J'ai un IntPtr marshalé à travers une frontière non gérée/gérée qui correspond à une poignée d'icône. Le convertir en icône est trivial via la méthode FromHandle (), et c'était satisfaisant jusqu'à récemment.
Fondamentalement, j'ai assez de bizarreries de threads maintenant que la danse MTA/STA que j'ai jouée pour empêcher un WinForm hébergé de casser l'interface utilisateur principale (WPF-tastic) de l'application est trop fragile pour rester. Le WinForm doit donc partir.
Alors, comment puis-je obtenir une version ImageSource d'une icône?
Remarque, j'ai essayé ImageSourceConverter en vain.
En passant, je peux obtenir la ressource sous-jacente pour certains mais pas toutes les icônes impliquées et elles existent généralement en dehors de l'assembly de mon application (en fait, elles existent souvent dans des DLL non gérées).
Essaye ça:
Icon img;
Bitmap bitmap = img.ToBitmap();
IntPtr hBitmap = bitmap.GetHbitmap();
ImageSource wpfBitmap =
Imaging.CreateBitmapSourceFromHBitmap(
hBitmap, IntPtr.Zero, Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());
UPDATE : Incorporer la suggestion d'Alex et en faire une méthode d'extension:
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;
}
}
Ensuite, vous pouvez faire:
ImageSource wpfBitmap = img.ToImageSource();
Méthode de conversion simple sans créer d'objets supplémentaires:
public static ImageSource ToImageSource(this Icon icon)
{
ImageSource imageSource = Imaging.CreateBitmapSourceFromHIcon(
icon.Handle,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());
return imageSource;
}
Lors de l'utilisation de flux jetables, il est presque toujours recommandé d'utiliser des blocs "à l'aide" pour forcer la libération correcte des ressources.
using (MemoryStream iconStream = new MemoryStream())
{
icon.Save(iconStream);
iconStream.Seek(0, SeekOrigin.Begin);
this.TargetWindow.Icon = System.Windows.Media.Imaging.BitmapFrame.Create(iconStream);
}
Où icon
est le System.Drawing.Icon source et this.TargetWindow
est le System.Windows.Window cible.
MemoryStream iconStream = new MemoryStream();
myForm.Icon.Save(iconStream);
iconStream.Seek(0, SeekOrigin.Begin);
_wpfForm.Icon = System.Windows.Media.Imaging.BitmapFrame.Create(iconStream);
Prenant de certains ci-dessus, cela a créé la plus haute qualité d'icônes pour moi-même. Chargement des icônes à partir d'un tableau d'octets. J'utilise le cache onload car si vous ne le faites pas, vous obtiendrez une exception supprimée lorsque vous supprimez le flux de mémoire.
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);
}
}
Exemple quelque peu similaire, uniquement à partir des cas d'utilisation du développeur ...
[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);
/// <summary>
/// Gets application icon from main .exe.
/// </summary>
/// <param name="setToObject">object to which to set up icon</param>
/// <param name="bAsImageSource">true if get it as "ImageSource" (xaml technology), false if get it as "Icon" (winforms technology)</param>
/// <returns>true if successful.</returns>
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