2009-08-25 11 views
20

Actualmente recibo un ícono nativo al llamar a SHGetFileInfo. Entonces, lo estoy convirtiendo a un mapa de bits usando el siguiente código. El mapa de bits finalmente se muestra en el formulario WPF.¿Cómo se muestra un ícono de archivo de Windows en WPF?

¿Hay una forma más rápida de hacer lo mismo?

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

Respuesta

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

Me creer que hay más simple (más gestionado) forma de resolver este hilighted aquí. http://www.pchenry.com/Home/tabid/36/EntryID/193/Default.aspx

El quid de la solución está aquí.

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

olvide depositar sus recursos después de usarlos. En este escenario, tu transmisión no está cerrada, creo. –

5

El código de Thomas se podría simplificar aún más. Aquí está el código completo con la comprobación de error adicional:

  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; 

La diferencia es:

  • hay necesidad de crear objeto Icon
  • asegurarse de manejar un caso en iconHandle es 0 (IntPtr.Zero) por ejemplo devolver un objeto predefinido ImageSource
  • asegúrese de utilizar DestroyIcon Win32 API() si se trata de SHGetFileInfo()
+0

¿Puede proporcionar el código de Interop también? Tengo problemas para hacer coincidir tu código con la firma de función de SHGetFileInfo de la API de Windows. Todas las demás soluciones que he encontrado usan System.Drawing, que parece 100% incompatible con WPF, así que ¿para qué molestarse en usarlo? Esto parece el más directo. Si pudiera hacerlo funcionar. – ygoe

+0

Interop class & other combinado en [mi respuesta] (http://stackoverflow.com/questions/1325625/how-do-i-display-a-windows-file-icon-in-wpf#answer-29819585) a continuación (es demasiado tiempo para comentar) –

23

¿Qué tal algo como:

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

Claramente no estás siendo lo suficientemente intrincado;) – ocodo

+6

@Slomojo usando System.Drawing y Bitmap map = Icon.ExtractAssociatedIcon (fileName) .ToBitmap() también funciona ... – msfanboy

+0

ToBitmap() pierde el alfa canal – Prat

8

Combinando Krzysztof Kowalczyk answer con algunas google, hice esto:

Método:

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

y la clase de interoperabilidad:

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

¡Copiar/Pegar solución! ... +1. Sin embargo, solo un pequeño comentario: debe quedarse con la base de "BitmapSource" en lugar de "ImageSource", ya que una vez promocionada, es más difícil volver a la clase base. Respuesta perfecta de lo contrario. Gracias. – VeV

+0

Funciona perfectamente.Una mejora: dado que cargar iconos para varios archivos puede tomar un momento, es posible que desee hacerlo en un hilo de trabajo. Para poder utilizar dicha imagen en la interfaz de usuario, debe estar congelada: 'img.Freeze();' No cambiará de todos modos. – ygoe

+0

Gran solución. Lo extendí para que también sea compatible con directorios. En lugar de pasar el número mágico 256 a SHGetFileInfo, paso 'FILE_ATTRIBUTE_DIRECTORY' (0x10) cuando quiero recuperar el icono de carpeta,' FILE_ATTRIBUTE_NORMAL' (0x80) de lo contrario. Agregué estos dos valores como constantes dentro de la clase Interop. Se utilizó información de [aquí] (https://stackoverflow.com/questions/1599235/how-do-i-fetch-the-folder-icon-on-windows-7-using-shell32-shgetfileinfo) y [aquí] (https://msdn.microsoft.com/en-us/library/windows/desktop/gg258117(v=vs.85).aspx). –

Cuestiones relacionadas