代码之家  ›  专栏  ›  技术社区  ›  tronda Bahribayli

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

  •  18
  • tronda Bahribayli  · 技术社区  · 16 年前

    我有以下代码,适用于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中获取文件夹图标时,会得到以下结果:

    alt text

    alt text

    2 回复  |  直到 8 年前
        1
  •  21
  •   JPW    16 年前

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

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

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

    但是,如果你想要一个驱动器或文件夹的图标,这是行不通的。

    http://mwinapi.sourceforge.net ).

    如果你想坚持手工制作的解决方案,这对我来说是可行的(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);
                }
            }
        }
    }
    
        2
  •  9
  •   shelleybutterfly Justin Dearing    11 年前

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

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

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

    SHGetFileInfo("AnyNonEmptyStringWillDo", FILE_ATTRIBUTE_DIRECTORY, sfi,
          SizeOf(sfi), SHGFI_USEFILEATTRIBUTES or SHGFI_SYSICONINDEX)
    
    推荐文章