C# 如何在WPF中显示Windows文件图标?

C# 如何在WPF中显示Windows文件图标?,c#,wpf,icons,C#,Wpf,Icons,目前,我通过调用SHGetFileInfo获得了一个本机图标。然后,我将使用以下代码将其转换为位图。位图最终以WPF形式显示 有没有更快的方法来做同样的事情 try { using (Icon i = Icon.FromHandle(shinfo.hIcon)) { Bitmap bmp = i.ToBitmap(); MemoryStream strm = new M

目前,我通过调用SHGetFileInfo获得了一个本机图标。然后,我将使用以下代码将其转换为位图。位图最终以WPF形式显示

有没有更快的方法来做同样的事情

try
        {
            using (Icon i = Icon.FromHandle(shinfo.hIcon))
            {
                Bitmap bmp = i.ToBitmap();
                MemoryStream strm = new MemoryStream();
                bmp.Save(strm, System.Drawing.Imaging.ImageFormat.Png);
                BitmapImage bmpImage = new BitmapImage();
                bmpImage.BeginInit();
                strm.Seek(0, SeekOrigin.Begin);
                bmpImage.StreamSource = strm;
                bmpImage.EndInit();

                return bmpImage;
            }
        }
        finally
        {
            Win32.DestroyIcon(hImgLarge);
        }
我相信这里有更简单(更有管理)的方法来解决这个问题。

解决方案的关键在于这里

System.Drawing.Icon formIcon = IconsInWPF.Properties.Resources.Habs;
MemoryStream stream = new MemoryStream();
formIcon.Save(stream);
this.Icon = BitmapFrame.Create(stream);

托马斯的代码可以简化得更多。以下是带有附加错误检查的完整代码:

            Interop.SHGetFileInfo(path, isFile, ref pifFileInfo);
            IntPtr iconHandle = pifFileInfo.hIcon;
            if (IntPtr.Zero == iconHandle)
                return DefaultImgSrc;
            ImageSource img = Imaging.CreateBitmapSourceFromHIcon(
                        iconHandle,
                        Int32Rect.Empty,
                        BitmapSizeOptions.FromEmptyOptions());
            User32.DestroyIcon(iconHandle);
            return img;
区别在于:

  • 无需创建图标对象
  • 确保处理iconHandle为0(IntPtr.Zero)的情况,例如返回一些预定义的ImageSource对象
  • 如果win32 api DestroyIcon()来自SHGetFileInfo(),请确保使用它

    • 像这样的东西怎么样:

      var icon = System.Drawing.Icon.ExtractAssociatedIcon(fileName);
      var bmp = icon.ToBitmap()
      
      结合谷歌搜索,我编造了以下内容:

      方法:

      /*
      using System;
      using System.Runtime.InteropServices;
      using System.Windows;
      using System.Windows.Interop;
      using System.Windows.Media;
      using System.Windows.Media.Imaging;
      */
      
           public static ImageSource GetIcon(string strPath, bool bSmall)
              {
                Interop.SHFILEINFO info = new Interop.SHFILEINFO(true);
                int cbFileInfo = Marshal.SizeOf(info);
                Interop.SHGFI flags;
                if (bSmall)
                  flags = Interop.SHGFI.Icon | Interop.SHGFI.SmallIcon | Interop.SHGFI.UseFileAttributes;
                else
                  flags = Interop.SHGFI.Icon | Interop.SHGFI.LargeIcon | Interop.SHGFI.UseFileAttributes;
      
                Interop.SHGetFileInfo(strPath, 256, out info, (uint)cbFileInfo, flags);
      
                IntPtr iconHandle = info.hIcon;
                //if (IntPtr.Zero == iconHandle) // not needed, always return icon (blank)
                //  return DefaultImgSrc;
                ImageSource img = Imaging.CreateBitmapSourceFromHIcon(
                            iconHandle,
                            Int32Rect.Empty,
                            BitmapSizeOptions.FromEmptyOptions());
                Interop.DestroyIcon(iconHandle);
                return img;
              }
      
      和互操作类:

      using System;
      using System.Runtime.InteropServices;
      public static class Interop
        {
          /// <summary>Maximal Length of unmanaged Windows-Path-strings</summary>
          private const int MAX_PATH = 260;
          /// <summary>Maximal Length of unmanaged Typename</summary>
          private const int MAX_TYPE = 80;
      
      
          [Flags]
          public enum SHGFI : int
          {
            /// <summary>get icon</summary>
            Icon = 0x000000100,
            /// <summary>get display name</summary>
            DisplayName = 0x000000200,
            /// <summary>get type name</summary>
            TypeName = 0x000000400,
            /// <summary>get attributes</summary>
            Attributes = 0x000000800,
            /// <summary>get icon location</summary>
            IconLocation = 0x000001000,
            /// <summary>return exe type</summary>
            ExeType = 0x000002000,
            /// <summary>get system icon index</summary>
            SysIconIndex = 0x000004000,
            /// <summary>put a link overlay on icon</summary>
            LinkOverlay = 0x000008000,
            /// <summary>show icon in selected state</summary>
            Selected = 0x000010000,
            /// <summary>get only specified attributes</summary>
            Attr_Specified = 0x000020000,
            /// <summary>get large icon</summary>
            LargeIcon = 0x000000000,
            /// <summary>get small icon</summary>
            SmallIcon = 0x000000001,
            /// <summary>get open icon</summary>
            OpenIcon = 0x000000002,
            /// <summary>get shell size icon</summary>
            ShellIconSize = 0x000000004,
            /// <summary>pszPath is a pidl</summary>
            PIDL = 0x000000008,
            /// <summary>use passed dwFileAttribute</summary>
            UseFileAttributes = 0x000000010,
            /// <summary>apply the appropriate overlays</summary>
            AddOverlays = 0x000000020,
            /// <summary>Get the index of the overlay in the upper 8 bits of the iIcon</summary>
            OverlayIndex = 0x000000040,
          }
      
          [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
          public struct SHFILEINFO
          {
            public SHFILEINFO(bool b)
            {
              hIcon = IntPtr.Zero;
              iIcon = 0;
              dwAttributes = 0;
              szDisplayName = "";
              szTypeName = "";
            }
            public IntPtr hIcon;
            public int iIcon;
            public uint dwAttributes;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH)]
            public string szDisplayName;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_TYPE)]
            public string szTypeName;
          };
      
          [DllImport("shell32.dll", CharSet = CharSet.Auto)]
          public static extern int SHGetFileInfo(
            string pszPath,
            int dwFileAttributes,
            out    SHFILEINFO psfi,
            uint cbfileInfo,
            SHGFI uFlags);
      
          [DllImport("user32.dll", SetLastError = true)]
          public static extern bool DestroyIcon(IntPtr hIcon);
        }
      
      使用系统;
      使用System.Runtime.InteropServices;
      公共静态类互操作
      {
      ///非托管Windows路径字符串的最大长度
      私有常量int MAX_PATH=260;
      ///非托管Typename的最大长度
      私有常量int MAX_TYPE=80;
      [旗帜]
      公共枚举SHGFI:int
      {
      ///获取图标
      图标=0x000000100,
      ///获取显示名称
      DisplayName=0x000000200,
      ///获取类型名
      TypeName=0x000000400,
      ///获取属性
      属性=0x000000800,
      ///获取图标位置
      IconLocation=0x000001000,
      ///返回exe类型
      ExeType=0x000002000,
      ///获取系统图标索引
      SysIconIndex=0x000004000,
      ///在图标上放置一个链接覆盖
      LinkOverlay=0x00008000,
      ///在选定状态下显示图标
      所选=0x000010000,
      ///仅获取指定的属性
      指定的属性=0x000020000,
      ///获取大图标
      LargeIcon=0x000000000,
      ///获取小图标
      SmallIcon=0x000000001,
      ///打开图标
      OpenIcon=0x000000002,
      ///获取外壳大小图标
      ShellIconSize=0x000000004,
      ///pszPath是一个pidl
      PIDL=0x000000008,
      ///使用传递的dwFileAttribute
      UseFileAttributes=0x000000010,
      ///应用适当的覆盖层
      AddOverlays=0x000000020,
      ///获取iIcon上8位的覆盖索引
      OverlayIndex=0x000000040,
      }
      [StructLayout(LayoutKind.Sequential,CharSet=CharSet.Auto)]
      公共结构SHFILEINFO
      {
      公共SHFILEINFO(布尔b)
      {
      hIcon=IntPtr.Zero;
      iIcon=0;
      dwAttributes=0;
      szDisplayName=“”;
      szTypeName=“”;
      }
      公共IntPtr hIcon;
      公共国际会议;
      公共单位属性;
      [Marshallas(UnmanagedType.ByValTStr,SizeConst=MAX\u PATH)]
      公共字符串名称;
      [Marshallas(UnmanagedType.ByValTStr,SizeConst=MAX\u TYPE)]
      公共字符串类型名;
      };
      [DllImport(“shell32.dll”,CharSet=CharSet.Auto)]
      公共静态外部int SHGetFileInfo(
      字符串pszPath,
      int dwFileAttributes,
      输出SHFILEINFO psfi,
      uint cbfileInfo,
      SHGFI uFlags);
      [DllImport(“user32.dll”,SetLastError=true)]
      公共静态外部布尔销毁图标(IntPtr hIcon);
      }
      

      很明显,您的问题还不够复杂;)@Slomojo使用System.Drawing and Bitmap=Icon.ExtractAssociatedIcon(文件名)。ToBitmap()也可以工作…ToBitmap()丢失alpha通道这只提取分辨率为32x32的图标。您可以直接将图标转换为图像源,而不是使用
      Icon.ToBitmap(),使用
      图标。句柄
      属性和Thomas或Krysztof答案。或者您可以提供互操作代码吗?我在将您的代码与Windows API中SHGetFileInfo的函数签名匹配时遇到问题。我发现的所有其他解决方案都使用System.Drawing,它似乎与WPF 100%不兼容,所以为什么还要麻烦使用它呢。这看起来最直截了当。如果我能让它工作。Interop类和其他组合在下面(太长了,无法评论)复制/粘贴解决方案+1.只是一个小小的注释:您应该坚持使用“BitmapSource”基类而不是“ImageSource”,因为一旦升级,就很难回溯到基类。否则,答案是完美的。谢谢,很好用。一个改进:由于加载多个文件的图标可能需要一段时间,因此您可能希望在工作线程中执行此操作。要在UI中使用这样的图像,必须将其冻结:
      img.Freeze()它无论如何都不会改变。很好的解决方案。我扩展了它,这样它也支持目录。当我想要检索文件夹图标时,我会传递
      FILE\u ATTRIBUTE\u DIRECTORY
      (0x10),否则传递
      FILE\u ATTRIBUTE\u NORMAL
      (0x80),而不是将幻数256传递给SHGetFileInfo。我将这两个值作为常量添加到Interop类中。已使用和中的信息。请记住在使用资源后处置它们。在这个场景中,我认为您的流没有关闭。
      using System;
      using System.Runtime.InteropServices;
      public static class Interop
        {
          /// <summary>Maximal Length of unmanaged Windows-Path-strings</summary>
          private const int MAX_PATH = 260;
          /// <summary>Maximal Length of unmanaged Typename</summary>
          private const int MAX_TYPE = 80;
      
      
          [Flags]
          public enum SHGFI : int
          {
            /// <summary>get icon</summary>
            Icon = 0x000000100,
            /// <summary>get display name</summary>
            DisplayName = 0x000000200,
            /// <summary>get type name</summary>
            TypeName = 0x000000400,
            /// <summary>get attributes</summary>
            Attributes = 0x000000800,
            /// <summary>get icon location</summary>
            IconLocation = 0x000001000,
            /// <summary>return exe type</summary>
            ExeType = 0x000002000,
            /// <summary>get system icon index</summary>
            SysIconIndex = 0x000004000,
            /// <summary>put a link overlay on icon</summary>
            LinkOverlay = 0x000008000,
            /// <summary>show icon in selected state</summary>
            Selected = 0x000010000,
            /// <summary>get only specified attributes</summary>
            Attr_Specified = 0x000020000,
            /// <summary>get large icon</summary>
            LargeIcon = 0x000000000,
            /// <summary>get small icon</summary>
            SmallIcon = 0x000000001,
            /// <summary>get open icon</summary>
            OpenIcon = 0x000000002,
            /// <summary>get shell size icon</summary>
            ShellIconSize = 0x000000004,
            /// <summary>pszPath is a pidl</summary>
            PIDL = 0x000000008,
            /// <summary>use passed dwFileAttribute</summary>
            UseFileAttributes = 0x000000010,
            /// <summary>apply the appropriate overlays</summary>
            AddOverlays = 0x000000020,
            /// <summary>Get the index of the overlay in the upper 8 bits of the iIcon</summary>
            OverlayIndex = 0x000000040,
          }
      
          [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
          public struct SHFILEINFO
          {
            public SHFILEINFO(bool b)
            {
              hIcon = IntPtr.Zero;
              iIcon = 0;
              dwAttributes = 0;
              szDisplayName = "";
              szTypeName = "";
            }
            public IntPtr hIcon;
            public int iIcon;
            public uint dwAttributes;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH)]
            public string szDisplayName;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_TYPE)]
            public string szTypeName;
          };
      
          [DllImport("shell32.dll", CharSet = CharSet.Auto)]
          public static extern int SHGetFileInfo(
            string pszPath,
            int dwFileAttributes,
            out    SHFILEINFO psfi,
            uint cbfileInfo,
            SHGFI uFlags);
      
          [DllImport("user32.dll", SetLastError = true)]
          public static extern bool DestroyIcon(IntPtr hIcon);
        }