Convierta System.Drawing.Icon a System.Media.ImageSource

Tengo un IntPtr marshaled a través de un límite no administrado / administrado que corresponde a un Icon Handle. Convertirlo en un icono es trivial a través del método FromHandle (), y esto fue satisfactorio hasta hace poco.

Básicamente, ya tengo suficiente rareza de hilos ahora que el baile de MTA / STA que he estado jugando para evitar que un WinForm alojado rompa la interfaz de usuario (WPF-tastic) principal de la aplicación es demasiado frágil como para seguirlo. Entonces WinForm tiene que irse.

Entonces, ¿cómo puedo obtener una versión de ImageSource de un ícono?

Tenga en cuenta que probé ImageSourceConverter en vano.

Por otro lado, puedo obtener el recurso subyacente para algunos, pero no para todos los icons involucrados, y generalmente existen fuera del ensamblaje de mi aplicación (de hecho, a menudo existen en dll no administrados).

Prueba esto:

Icon img; Bitmap bitmap = img.ToBitmap(); IntPtr hBitmap = bitmap.GetHbitmap(); ImageSource wpfBitmap = Imaging.CreateBitmapSourceFromHBitmap( hBitmap, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions()); 

ACTUALIZACIÓN : Incorporar la sugerencia de Alex y convertirla en un método de extensión:

 internal static class IconUtilities { [DllImport("gdi32.dll", SetLastError = true)] private static extern bool DeleteObject(IntPtr hObject); public static ImageSource ToImageSource(this Icon icon) { Bitmap bitmap = icon.ToBitmap(); IntPtr hBitmap = bitmap.GetHbitmap(); ImageSource wpfBitmap = Imaging.CreateBitmapSourceFromHBitmap( hBitmap, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions()); if (!DeleteObject(hBitmap)) { throw new Win32Exception(); } return wpfBitmap; } } 

Entonces puedes hacer:

 ImageSource wpfBitmap = img.ToImageSource(); 

Método de conversión simple sin crear ningún objeto adicional:

  public static ImageSource ToImageSource(this Icon icon) { ImageSource imageSource = Imaging.CreateBitmapSourceFromHIcon( icon.Handle, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions()); return imageSource; } 

Cuando se usan streams desechables, casi siempre se recomienda utilizar bloques ‘que usan’ para forzar la correcta liberación de recursos.

 using (MemoryStream iconStream = new MemoryStream()) { icon.Save(iconStream); iconStream.Seek(0, SeekOrigin.Begin); this.TargetWindow.Icon = System.Windows.Media.Imaging.BitmapFrame.Create(iconStream); } 

Donde icon es la fuente System.Drawing.Icon, y this.TargetWindow es el destino System.Windows.Window.

 MemoryStream iconStream = new MemoryStream(); myForm.Icon.Save(iconStream); iconStream.Seek(0, SeekOrigin.Begin); _wpfForm.Icon = System.Windows.Media.Imaging.BitmapFrame.Create(iconStream); 

Tomar de algunos encima esto ha creado la más alta calidad de icons para mí. Cargando los icons de una matriz de bytes. Utilizo la carga de la memoria caché porque si no lo hace obtendrá una excepción eliminada cuando deseche la secuencia de la memoria.

  internal static ImageSource ToImageSource(this byte[] iconBytes) { if (iconBytes == null) throw new ArgumentNullException(nameof(iconBytes)); using (var ms = new MemoryStream(iconBytes)) { return BitmapFrame.Create(ms, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad); } } 

De alguna manera, un ejemplo similar, solo sintonizado desde los casos de uso del desarrollador …

  [DllImport("shell32.dll")] public static extern IntPtr ExtractIcon(IntPtr hInst, string file, int nIconIndex); [DllImport("user32.dll", SetLastError = true)] static extern bool DestroyIcon(IntPtr hIcon); ///  /// Gets application icon from main .exe. ///  /// object to which to set up icon /// true if get it as "ImageSource" (xaml technology), false if get it as "Icon" (winforms technology) /// true if successful. public bool GetIcon(object setToObject, bool bAsImageSource) { String path = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location); path = Path.Combine(path, "yourmainexecutableName.exe"); int iIconIndex = 0; // If your application contains multiple icons, then // you could change iIconIndex here. object o2set = null; IntPtr hIcon = ExtractIcon(IntPtr.Zero, path, iIconIndex); if (hIcon == IntPtr.Zero) return false; Icon icon = (Icon)Icon.FromHandle(hIcon); if (bAsImageSource) { o2set = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap( icon.ToBitmap().GetHbitmap(), IntPtr.Zero, Int32Rect.Empty, System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions()); } else { icon = (Icon)icon.Clone(); } DestroyIcon(hIcon); setToObject.GetType().GetProperty("Icon").SetValue(setToObject, o2set); return true; } //GetIcon 

Hay una solución realmente simple para este problema.

Pasos:

(1) agregar imagen a los recursos en el explorador de soluciones -> resources.resx (2) editar las propiedades de la imagen dentro del directorio “Resources” en el explorador de soluciones y cambiar “Build action” a “Resource”

En xaml, agregue lo siguiente …

Icono = “recursos / nombre de la imagen” (donde “nombre de la imagen” es el nombre de la imagen que ha agregado a los recursos; consulte el punto (1).