【问题标题】:How do I display a Windows file icon in WPF?如何在 WPF 中显示 Windows 文件图标?
【发布时间】:2010-11-22 11:24:55
【问题描述】:

目前我通过调用 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);
        }

【问题讨论】:

    标签: c# wpf icons


    【解决方案1】:
    using System.Windows.Interop;
    
    ...
    
    ImageSource img = Imaging.CreateBitmapSourceFromHIcon(
        shinfo.hIcon,
        new Int32Rect(0,0,i.Width, i.Height),
        BitmapSizeOptions.FromEmptyOptions());
    

    【讨论】:

      【解决方案2】:

      结合Krzysztof Kowalczyk answer 和一些谷歌搜索,我做了这个:

      方法:

      /*
      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);
        }
      

      source

      【讨论】:

      • 复制/粘贴解决方案!... +1。不过,只是一个小评论:您应该坚持使用“BitmapSource”基类而不是“ImageSource”,因为一旦提升,就很难再转换回基类。否则完美答案。谢谢。
      • 完美运行。一项改进:由于为多个文件加载图标可能需要一些时间,因此您可能希望在工作线程中执行此操作。为了能够在 UI 中使用这样的图像,它必须被冻结:img.Freeze(); 它无论如何都不会改变。
      • 很好的解决方案。我对其进行了扩展,因此它也支持目录。当我想检索文件夹图标时,我没有将幻数 256 传递给 SHGetFileInfo,而是传递 FILE_ATTRIBUTE_DIRECTORY ( 0x10 ),否则传递 FILE_ATTRIBUTE_NORMAL ( 0x80 )。我在 Interop 类中添加了这两个值作为常量。使用来自herehere 的信息。
      【解决方案3】:

      我相信这里有更简单(更易于管理)的方法来解决这个问题。 http://www.pchenry.com/Home/tabid/36/EntryID/193/Default.aspx

      解决办法的关键就在这里。

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

      【讨论】:

      • 记得在使用完资源后将其丢弃。在这种情况下,我认为您的流没有关闭。
      【解决方案4】:

      怎么样:

      var icon = System.Drawing.Icon.ExtractAssociatedIcon(fileName);
      var bmp = icon.ToBitmap()
      

      【讨论】:

      • 显然你还不够复杂 ;)
      • @Slomojo 使用 System.Drawing 和 Bitmap map = Icon.ExtractAssociatedIcon(fileName).ToBitmap() 也有效...
      • ToBitmap() 丢失 alpha 通道
      • 这只会提取 32x32 分辨率的图标。
      • 您可以使用icon.Handle 属性和Thomas 或Krysztof 答案将图标直接转换为ImageSource,而不是使用icon.ToBitmap()。或this
      【解决方案5】:

      Thomas 的代码可以进一步简化。这是带有额外错误检查的完整代码:

                  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 对象
      • 如果来自 SHGetFileInfo(),请确保使用 win32 api DestroyIcon()

      【讨论】:

      • 能否请您也提供互操作代码?我在将您的代码与来自 Windows API 的 SHGetFileInfo 的函数签名匹配时遇到问题。我发现的所有其他解决方案都使用 System.Drawing,它似乎 100% 与 WPF 不兼容,所以为什么还要使用它。这看起来最直接。如果我能让它工作。
      • Interop 类和其他组合在下面的my answer 中(评论太长了)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-04-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多