2009-08-25 2 views
20

В настоящее время я получаю собственный значок, вызывая SHGetFileInfo. Затем я конвертирую его в растровое изображение, используя следующий код. Растровое изображение в конечном итоге отображается в форме WPF.Как отобразить значок файла Windows в 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); 
     } 

ответ

19
using System.Windows.Interop; 

... 

using (Icon i = Icon.FromHandle(shinfo.hIcon)) 
{ 

    ImageSource img = Imaging.CreateBitmapSourceFromHIcon(
          i.Handle, 
          new Int32Rect(0,0,i.Width, i.Height), 
          BitmapSizeOptions.FromEmptyOptions()); 
} 
1

Я верю, что есть проще (более управляемый) способ решения этой hilighted здесь. 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); 
+2

Помните утилизировать свои ресурсы после их использования. В этом случае ваш поток не закрыт, я думаю. –

5

Код Томаса может быть упрощен даже больше. Вот полный код с дополнительной проверкой ошибок:

  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; 

Разница заключается в том:

  • нет необходимости создавать Icon объект
  • убедитесь обрабатывать случай, когда iconHandle является 0 (IntPtr.Zero) например, возвращая некоторый предопределенный объект ImageSource
  • убедитесь, что использовать Win32 API DestroyIcon(), если оно исходит от SHGetFileInfo()
+0

Можете ли вы также указать код Interop? У меня проблемы с вашим кодом с сигнатурой функции SHGetFileInfo из Windows API. Все остальные решения, которые я нашел, используют System.Drawing, которые кажутся 100% несовместимыми с WPF, поэтому зачем его использовать. Это выглядит наиболее прямолинейно. Если бы я мог заставить его работать. – ygoe

+0

Interop класс и другие объединенные в [мой ответ] (http://stackoverflow.com/questions/1325625/how-do-i-display-a-windows-file-icon-in-wpf#answer-29819585) ниже (его слишком долго для комментария) –

23

Как о чем-то вроде:

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

Очевидно, что вы недостаточно свернуты;) – ocodo

+6

@Slomojo с использованием System.Drawing и Bitmap map = Icon.ExtractAssociatedIcon (fileName) .ToBitmap() также работает ... – msfanboy

+0

ToBitmap() теряет альфу channel – Prat

8

Объединяя Krzysztof Kowalczyk answer с некоторыми Googling, я составил это:

Метод:

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

и 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); 
    } 

source

+1

Копирование/Вставить решение! ... +1. Просто небольшой комментарий, хотя: вы должны придерживаться базы «BitmapSource» вместо «ImageSource», как только это было продвинуто, сложнее вернуть обратно в базовый класс. Идеальный ответ в противном случае. Благодарю. – VeV

+0

Работает отлично.Одно улучшение: поскольку загрузка значков для нескольких файлов может занять некоторое время, вы можете сделать это в рабочем потоке. Чтобы иметь возможность использовать такое изображение в пользовательском интерфейсе, он должен быть заморожен: 'img.Freeze();' Он все равно не изменится. – ygoe

+0

Отличное решение. Я расширил его так, чтобы он также поддерживал каталоги. Вместо того, чтобы передавать магическое число 256 в SHGetFileInfo, я передаю 'FILE_ATTRIBUTE_DIRECTORY' (0x10), когда я хочу получить значок папки,' FILE_ATTRIBUTE_NORMAL' (0x80) в противном случае. Я добавил эти два значения в качестве констант внутри класса Interop. Использованная информация из [здесь] (https://stackoverflow.com/questions/1599235/how-do-i-fetch-the-folder-icon-on-windows-7-using-shell32-shgetfileinfo) и [здесь] (https://msdn.microsoft.com/en-us/library/windows/desktop/gg258117(v=vs.85).aspx). –

Смежные вопросы