如何使用Shell32.SHGetFileInfo在Windows 7上获取文件夹图标

我有以下代码适用于Windows XP和Vista – 32位和64位:

public static Icon GetFolderIcon(IconSize size, FolderType folderType) { // Need to add size check, although errors generated at present! uint flags = Shell32.SHGFI_ICON | Shell32.SHGFI_USEFILEATTRIBUTES; if (FolderType.Open == folderType) { flags += Shell32.SHGFI_OPENICON; } if (IconSize.Small == size) { flags += Shell32.SHGFI_SMALLICON; } else { flags += Shell32.SHGFI_LARGEICON; } // Get the folder icon var shfi = new Shell32.SHFILEINFO(); Shell32.SHGetFileInfo( null, Shell32.FILE_ATTRIBUTE_DIRECTORY, ref shfi, (uint) Marshal.SizeOf(shfi), flags ); Icon.FromHandle(shfi.hIcon); // Load the icon from an HICON handle // Now clone the icon, so that it can be successfully stored in an ImageList var icon = (Icon)Icon.FromHandle(shfi.hIcon).Clone(); User32Dll.DestroyIcon( shfi.hIcon ); // Cleanup return icon; } 

常量按以下方式定义:

 public const uint SHGFI_ICON = 0x000000100; public const uint SHGFI_USEFILEATTRIBUTES = 0x000000010; public const uint SHGFI_OPENICON = 0x000000002; public const uint SHGFI_SMALLICON = 0x000000001; public const uint SHGFI_LARGEICON = 0x000000000; public const uint FILE_ATTRIBUTE_DIRECTORY = 0x00000010; 

这在获取文件夹图标时在Windows 7中提供以下结果:

替代文字

在Vista中 – 使用相同的方法导致以下文件夹图标:

替代文字

我想要Windows 7的“正确”Windows文件夹图标 – 而不是用于指示安装Windows的驱动器的图标。

我不知道win32 API,我的非托管编程在Windows平台上几乎没有。

您不应将null指定为SHGeFileInfo的第一个参数。 请改用文件夹的路径(请注意,某些文件夹具有不同的(非标准)图标)。 例如,您可以使用临时文件夹或应用程序的根文件夹。

最佳做法是为每个文件夹获取正确的图标(换句话说:将GetFolderIcon的签名更改为public static Icon GetFolderIcon(string folderPath, IconSize size, FolderType folderType)并为您显示的每个文件夹调用它)。

似乎有一个开源库已经有一个托管文件夹图标的托管包装器。 在PInvoke.net上找到(SHGetFileInfo的条目):

但是,如果您需要驱动器或文件夹的图标,则不起作用。

在这种情况下,您可以使用ManagedWindowsApi项目( http://mwinapi.sourceforge.net )提供的ExtendedFileInfo类。

如果你想坚持手工制作的解决方案,这对我有用(Win7 x64 RTM,.NET 3.5 SP1):

 using System; using System.Drawing; using System.Runtime.InteropServices; using System.Windows.Forms; namespace IconExtractor { [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; }; public enum FolderType { Closed, Open } public enum IconSize { Large, Small } public partial class Form1 : Form { [DllImport("shell32.dll", CharSet = CharSet.Auto)] public static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, out SHFILEINFO psfi, uint cbFileInfo, uint uFlags); [DllImport("user32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] static extern bool DestroyIcon(IntPtr hIcon); public const uint SHGFI_ICON = 0x000000100; public const uint SHGFI_USEFILEATTRIBUTES = 0x000000010; public const uint SHGFI_OPENICON = 0x000000002; public const uint SHGFI_SMALLICON = 0x000000001; public const uint SHGFI_LARGEICON = 0x000000000; public const uint FILE_ATTRIBUTE_DIRECTORY = 0x00000010; public static Icon GetFolderIcon(IconSize size, FolderType folderType) { // Need to add size check, although errors generated at present! uint flags = SHGFI_ICON | SHGFI_USEFILEATTRIBUTES; if (FolderType.Open == folderType) { flags += SHGFI_OPENICON; } if (IconSize.Small == size) { flags += SHGFI_SMALLICON; } else { flags += SHGFI_LARGEICON; } // Get the folder icon var shfi = new SHFILEINFO(); var res = SHGetFileInfo(@"C:\Windows", FILE_ATTRIBUTE_DIRECTORY, out shfi, (uint) Marshal.SizeOf(shfi), flags ); if (res == IntPtr.Zero) throw Marshal.GetExceptionForHR(Marshal.GetHRForLastWin32Error()); // Load the icon from an HICON handle Icon.FromHandle(shfi.hIcon); // Now clone the icon, so that it can be successfully stored in an ImageList var icon = (Icon)Icon.FromHandle(shfi.hIcon).Clone(); DestroyIcon( shfi.hIcon ); // Cleanup return icon;} public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { try { Icon icon = GetFolderIcon(IconSize.Large, FolderType.Open); pictureBox1.Image = icon.ToBitmap(); // Note: The image actually should be disposed somewhere } catch (Exception ex) { MessageBox.Show(ex.Message); } } } } 

您不应将null指定为SHGeFileInfo的第一个参数。

那就对了。

请改用文件夹的路径(请注意,某些文件夹具有不同的(非标准)图标)。 例如,您可以使用临时文件夹或应用程序的根文件夹。

它不需要是真实的(现有的)文件夹路径。 任何非空字符串都可以。 例如:

 SHGetFileInfo("AnyNonEmptyStringWillDo", FILE_ATTRIBUTE_DIRECTORY, sfi, SizeOf(sfi), SHGFI_USEFILEATTRIBUTES or SHGFI_SYSICONINDEX)