2009-08-25 9 views
20

Momentan erhalte ich ein natives Icon, indem ich SHGetFileInfo aufruft. Dann wandle ich es unter Verwendung des folgenden Codes in eine Bitmap um. Die Bitmap wird schließlich im WPF-Formular angezeigt.Wie zeige ich ein Windows-Dateisymbol in WPF an?

Gibt es einen schnelleren Weg, um das Gleiche zu tun?

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

Antwort

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

ich es glauben, ist einfacher (mehr verwaltet) Weg, dies zu lösen, hier hilighted. http://www.pchenry.com/Home/tabid/36/EntryID/193/Default.aspx

Der Kern der Lösung ist hier.

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

Denken Sie daran, Ihre Ressourcen nach der Verwendung von ihnen zu entsorgen. In diesem Szenario ist Ihr Stream nicht geschlossen, denke ich. –

5

Thomas Code könnte noch mehr vereinfacht werden. Hier ist der vollständige Code mit zusätzlicher Fehlerprüfung:

  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; 

Der Unterschied ist:

  • keine Notwendigkeit Icon-Objekt erstellen
  • stellen Sie sicher, einen Fall zu behandeln, in denen iconHandle 0 (IntPtr.Zero) durch zB Rückkehr einige vordefinierte Imagesource Objekt
  • stellen Sie sicher, win32 api DestroyIcon(), wenn es darum geht, aus SHGetFileInfo()
+0

Können Sie bitte auch den Interop-Code angeben? Ich habe Probleme mit Ihrem Code mit der Funktionssignatur von SHGetFileInfo von der Windows API. Alle anderen Lösungen, die ich gefunden habe, verwenden System.Drawing, das zu 100% mit WPF unvereinbar zu sein scheint, also warum sollte man es benutzen? Das sieht am einfachsten aus. Wenn ich es zur Arbeit bringen könnte. – ygoe

+0

Interop-Klasse und andere kombiniert in [meine Antwort] (http://stackoverflow.com/questions/1325625/how-do-i-display-a-windows-file-icon-in-wpf#answer-29819585) unten (es ist zu lang für einen Kommentar) –

23

Wie wäre es so etwas wie zu verwenden:

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

Klar, Sie sind nicht genug verworren;) – ocodo

+6

@Slomojo mit System.Drawing und Bitmap map = Icon.ExtractAssociatedIcon (Dateiname). ToBitmap() funktioniert auch ... – msfanboy

+0

ToBitmap() verliert das Alpha Kanal – Prat

8

Kombination Krzysztof Kowalczyk answer mit einigen googeln, i aus diesen:

Methode:

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

und Interop-Klasse:

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

Kopieren/Einfügen-Lösung! ... +1. Nur ein kleiner Kommentar: Sie sollten bei "BitmapSource" Base statt "ImageSource" bleiben, da es nach der Promotion schwieriger ist, in die Basisklasse zurückzuspringen. Perfekte Antwort anders. Vielen Dank. – VeV

+0

Funktioniert perfekt.Eine Verbesserung: Da das Laden von Symbolen für eine Reihe von Dateien einen Moment dauern kann, möchten Sie es vielleicht in einem Arbeitsthread machen. Um ein solches Bild in der Benutzeroberfläche verwenden zu können, muss es eingefroren sein: 'img.Freeze();' Es wird sich sowieso nicht ändern. – ygoe

+0

Große Lösung. Ich habe es so erweitert, dass es auch Verzeichnisse unterstützt. Anstatt die magische Zahl 256 an SHGetFileInfo zu übergeben, übergebe ich 'FILE_ATTRIBUTE_DIRECTORY' (0x10), wenn ich das Ordnersymbol' FILE_ATTRIBUTE_NORMAL' (0x80) abrufen möchte. Ich habe diese beiden Werte als Konstanten innerhalb der Interop-Klasse hinzugefügt. Verwendete Informationen von [hier] (https://stackoverflow.com/questions/1599235/how-do-i-fetch-the-folder-icon-on-windows-7-using-shell32-shgetfileinfo) und [hier] (https://msdn.microsoft.com/en-us/library/windows/desktop/gg258117(v=vs.85).aspx). –

Verwandte Themen