首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

C# 呼叫 Shell API 取得檔案圖示:SHGetFileInfo 完整實作

     編輯:關於C#

在 Windows Forms 或 WPF 應用程式中顯示檔案系統圖示,需呼叫 Shell API SHGetFileInfo。本文提供完整的 P/Invoke 定義、旗標列舉與封裝方法,可直接取得大/小圖示 Icon 物件。

P/Invoke 簽名與結構定義


using System;
using System.Runtime.InteropServices;
using System.Drawing;

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct SHFILEINFO
{
    public IntPtr hIcon;
    public int iIcon;
    public uint dwAttributes;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
    public string szDisplayName;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
    public string szTypeName;
}

[Flags]
public enum SHGFI : uint
{
    ICON = 0x000000100,
    DISPLAYNAME = 0x000000200,
    TYPENAME = 0x000000400,
    ATTRIBUTES = 0x000000800,
    ICONLOCATION = 0x000001000,
    EXETYPE = 0x000002000,
    SYSICONINDEX = 0x000004000,
    LINKOVERLAY = 0x000008000,
    SELECTED = 0x000010000,
    ATTR_SPECIFIED = 0x000020000,
    LARGEICON = 0x000000000,
    SMALLICON = 0x000000001,
    OPENICON = 0x000000002,
    SHELLICONSIZE = 0x000000004,
    PIDL = 0x000000008,
    USEFILEATTRIBUTES = 0x000000010,
    ADDOVERLAYS = 0x000000020,
    OVERLAYINDEX = 0x000000040,
}

[Flags]
public enum FILE_ATTRIBUTE : uint
{
    READONLY = 0x00000001,
    HIDDEN = 0x00000002,
    SYSTEM = 0x00000004,
    DIRECTORY = 0x00000010,
    ARCHIVE = 0x00000020,
    DEVICE = 0x00000040,
    NORMAL = 0x00000080,
    TEMPORARY = 0x00000100,
    SPARSE_FILE = 0x00000200,
    REPARSE_POINT = 0x00000400,
    COMPRESSED = 0x00000800,
    OFFLINE = 0x00001000,
    NOT_CONTENT_INDEXED = 0x00002000,
    ENCRYPTED = 0x00004000,
}

public static class ShellApi
{
    [DllImport("shell32.dll", CharSet = CharSet.Auto, EntryPoint = "SHGetFileInfo")]
    public static extern IntPtr SHGetFileInfo(
        string pszPath,
        uint dwFileAttributes,
        ref SHFILEINFO psfi,
        uint cbFileInfo,
        uint uFlags);
}

封裝取得圖示方法


public static class FileIconHelper
{
    public static Icon GetLargeIcon(string filePath)
    {
        SHFILEINFO info = new SHFILEINFO();
        ShellApi.SHGetFileInfo(filePath, 0, ref info, (uint)Marshal.SizeOf(info),
            (uint)(SHGFI.ICON | SHGFI.LARGEICON));
        
        try
        {
            return (info.hIcon != IntPtr.Zero) ? Icon.FromHandle(info.hIcon) : null;
        }
        catch
        {
            return null;
        }
    }

    public static Icon GetSmallIcon(string filePath)
    {
        SHFILEINFO info = new SHFILEINFO();
        ShellApi.SHGetFileInfo(filePath, 0, ref info, (uint)Marshal.SizeOf(info),
            (uint)(SHGFI.ICON | SHGFI.SMALLICON));
        
        try
        {
            return (info.hIcon != IntPtr.Zero) ? Icon.FromHandle(info.hIcon) : null;
        }
        catch
        {
            return null;
        }
    }

    // 進階:依副檔名取得圖示(檔案不需實際存在)
    public static Icon GetIconByExtension(string extension, bool largeIcon)
    {
        SHFILEINFO info = new SHFILEINFO();
        uint flags = (uint)(SHGFI.ICON | SHGFI.USEFILEATTRIBUTES | 
            (largeIcon ? SHGFI.LARGEICON : SHGFI.SMALLICON));
        
        ShellApi.SHGetFileInfo(extension, (uint)FILE_ATTRIBUTE.NORMAL, 
            ref info, (uint)Marshal.SizeOf(info), flags);
        
        return (info.hIcon != IntPtr.Zero) ? Icon.FromHandle(info.hIcon) : null;
    }
}

使用範例


// 取得實體檔案圖示
Icon large = FileIconHelper.GetLargeIcon(@"C:\Windows\notepad.exe");
Icon small = FileIconHelper.GetSmallIcon(@"C:\Windows\notepad.exe");

// 顯示於 PictureBox 或 TreeView
pictureBox1.Image = large?.ToBitmap();

// 僅依副檔名取得圖示(較快,不需檔案存在)
Icon docIcon = FileIconHelper.GetIconByExtension(".docx", true);

常見問題與優化

  • TreeView/ListView 顯示模糊:Icon.FromHandle 回傳的圖示在縮放時可能失真。建議使用 ImageList 搭配 SHGetFileInfo 取得系統影像清單索引(SHGFI.SYSICONINDEX),直接指派 ImageList 給控制項。
  • 記憶體洩漏:Icon.FromHandle 建立的圖示需手動 DestroyIcon(P/Invoke user32.dll)釋放非受控資源,長期運行應用程式必須處理。
  • 效能:重複取得同樣圖示時,應快取 Icon 或影像清單索引。
  • 高 DPI:Windows 10+ 建議使用 SHGetImageList 取得高解析度系統影像清單。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved