Utilisation d'une icône Windows Vista 256 x 256 dans une application
Question
J'ai une application pour laquelle j'ai créé une icône Windows & Vista de Windows 256 x 256.
Je me demandais comment utiliser un fichier PNG 256x256 dans le fichier ico utilisé comme icône de l'application et l'afficher dans une zone d'image d'un formulaire.
J'utilise VB.NET, mais les réponses en C # suffisent. Je pense que je devrai peut-être utiliser la réflexion.
Je ne sais pas si cela est possible dans Windows XP et j'ai peut-être besoin des API Windows Vista ??p>.
La solution
Aujourd'hui, j'ai créé une fonction très utile pour extraire les icônes 256 x 256 Bitmaps de Vista ??strong>.
Comme vous, Nathan W, je l’utilise pour afficher la grande icône sous forme de bitmap dans "À propos de". boîte. Par exemple, ce code obtient l’icône Vista sous forme d’image PNG et l’affiche dans un PictureBox 256x256:
picboxAppLogo.Image = ExtractVistaIcon(myIcon);
Cette fonction prend l’objet Icon en paramètre. Vous pouvez donc l'utiliser avec toutes les icônes - à partir de ressources , à partir de fichiers, de flux, etc. (Lisez ci-dessous comment extraire l'icône EXE.)
Il fonctionne sur n'importe quel système d'exploitation , car il n'utilise pas les API Win32, il s'agit du code 100% géré : -)
// Based on: http://www.codeproject.com/KB/cs/IconExtractor.aspx
// And a hint from: http://www.codeproject.com/KB/cs/IconLib.aspx
Bitmap ExtractVistaIcon(Icon icoIcon)
{
Bitmap bmpPngExtracted = null;
try
{
byte[] srcBuf = null;
using (System.IO.MemoryStream stream = new System.IO.MemoryStream())
{ icoIcon.Save(stream); srcBuf = stream.ToArray(); }
const int SizeICONDIR = 6;
const int SizeICONDIRENTRY = 16;
int iCount = BitConverter.ToInt16(srcBuf, 4);
for (int iIndex=0; iIndex<iCount; iIndex++)
{
int iWidth = srcBuf[SizeICONDIR + SizeICONDIRENTRY * iIndex];
int iHeight = srcBuf[SizeICONDIR + SizeICONDIRENTRY * iIndex + 1];
int iBitCount = BitConverter.ToInt16(srcBuf, SizeICONDIR + SizeICONDIRENTRY * iIndex + 6);
if (iWidth == 0 && iHeight == 0 && iBitCount == 32)
{
int iImageSize = BitConverter.ToInt32(srcBuf, SizeICONDIR + SizeICONDIRENTRY * iIndex + 8);
int iImageOffset = BitConverter.ToInt32(srcBuf, SizeICONDIR + SizeICONDIRENTRY * iIndex + 12);
System.IO.MemoryStream destStream = new System.IO.MemoryStream();
System.IO.BinaryWriter writer = new System.IO.BinaryWriter(destStream);
writer.Write(srcBuf, iImageOffset, iImageSize);
destStream.Seek(0, System.IO.SeekOrigin.Begin);
bmpPngExtracted = new Bitmap(destStream); // This is PNG! :)
break;
}
}
}
catch { return null; }
return bmpPngExtracted;
}
IMPORTANT! Si vous souhaitez charger cette icône directement à partir d'un fichier EXE, vous ne pouvez pas utiliser Icon.ExtractAssociatedIcon (Application.ExecutablePath) en tant que paramètre, car la fonction .NET ExtractAssociatedIcon () est tellement stupide qu’elle extrait SEULEMENT l’icône 32x32!
Utilisez plutôt la classe entière IconExtractor , créée par Tsuda Kageyu ( http://www.codeproject.com/KB/cs/IconExtractor.aspx ). Vous pouvez légèrement simplifier cette classe, pour la rendre plus petite. Utilisez IconExtractor de cette manière:
// Getting FILL icon set from EXE, and extracting 256x256 version for logo...
using (TKageyu.Utils.IconExtractor IconEx = new TKageyu.Utils.IconExtractor(Application.ExecutablePath))
{
Icon icoAppIcon = IconEx.GetIcon(0); // Because standard System.Drawing.Icon.ExtractAssociatedIcon() returns ONLY 32x32.
picboxAppLogo.Image = ExtractVistaIcon(icoAppIcon);
}
Remarque: j'utilise toujours ma fonction ExtractVistaIcon () ici, car je n'aime pas la façon dont IconExtractor gère ce travail. Tout d'abord, il extrait tous les formats d'icônes à l'aide de IconExtractor.SplitIcon (icoAppIcon ), puis vous devez connaître l’index exact de l’icône 256x256 pour obtenir l’icône vista souhaitée. Donc, utiliser ma fonction ExtractVistaIcon () ici est beaucoup plus rapide et simple:)
Autres conseils
Informations trouvées ici . Pour obtenir la grande icône Vista, vous devez utiliser la méthode SHGetFileInfo de Shell32. J'ai copié le texte pertinent ci-dessous, mais vous voudrez bien sûr remplacer la variable "filename" par "Assembly.GetExecutingAssembly (). Location".
using System.Runtime.InteropServices;
Un groupe de constantes que nous allons utiliser dans l'appel à SHGetFileInfo () pour spécifier la taille de l'icône que nous souhaitons récupérer:
// Constants that we need in the function call
private const int SHGFI_ICON = 0x100;
private const int SHGFI_SMALLICON = 0x1;
private const int SHGFI_LARGEICON = 0x0;
La structure SHFILEINFO est très importante car elle gérera diverses informations sur les fichiers, notamment l’icône graphique.
// This structure will contain information about the file
public struct SHFILEINFO
{
// Handle to the icon representing the file
public IntPtr hIcon;
// Index of the icon within the image list
public int iIcon;
// Various attributes of the file
public uint dwAttributes;
// Path to the file
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string szDisplayName;
// File type
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
public string szTypeName;
};
La dernière préparation du code non managé consiste à définir la signature de SHGetFileInfo, située à l'intérieur du fichier shell32 populaire:
// The signature of SHGetFileInfo (located in Shell32.dll)
[DllImport("Shell32.dll")]
public static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, int cbFileInfo, uint uFlags);
Maintenant que tout est prêt, il est temps d'appeler la fonction et d'afficher l'icône que nous avons récupérée. L'objet qui sera récupéré est un type Icon (System.Drawing.Icon) mais nous souhaitons l'afficher dans un PictureBox afin que nous convertissions l'icône en Bitmap à l'aide de la méthode ToBitmap ().
Mais tout d’abord, vous devez ajouter au formulaire 3 contrôles, un bouton btnExtract qui contient " Extract Icon " pour sa propriété Text, picIconSmall qui est un PictureBox et un picIconLarge qui est également un PictureBox. C'est parce que nous aurons deux tailles d'icônes. Maintenant, double-cliquez sur btnExtract dans la vue Conception de Visual Studio et vous obtiendrez son événement Click. À l'intérieur se trouve le reste du code:
private void btnExtract_Click(object sender, EventArgs e)
{
// Will store a handle to the small icon
IntPtr hImgSmall;
// Will store a handle to the large icon
IntPtr hImgLarge;
SHFILEINFO shinfo = new SHFILEINFO();
// Open the file that we wish to extract the icon from
if(openFile.ShowDialog() == DialogResult.OK)
{
// Store the file name
string FileName = openFile.FileName;
// Sore the icon in this myIcon object
System.Drawing.Icon myIcon;
// Get a handle to the small icon
hImgSmall = SHGetFileInfo(FileName, 0, ref shinfo, Marshal.SizeOf(shinfo), SHGFI_ICON | SHGFI_SMALLICON);
// Get the small icon from the handle
myIcon = System.Drawing.Icon.FromHandle(shinfo.hIcon);
// Display the small icon
picIconSmall.Image = myIcon.ToBitmap();
// Get a handle to the large icon
hImgLarge = SHGetFileInfo(FileName, 0, ref shinfo, Marshal.SizeOf(shinfo), SHGFI_ICON | SHGFI_LARGEICON);
// Get the large icon from the handle
myIcon = System.Drawing.Icon.FromHandle(shinfo.hIcon);
// Display the large icon
picIconLarge.Image = myIcon.ToBitmap();
}
}
UPDATE: retrouvé encore plus d'informations ici .
Aucune des réponses ci-dessus ne gère les icônes Vista - uniquement les petites (32x32) et les grandes (48x48)
Il existe une bibliothèque qui gère les icônes Vista ici
.... cela semble assez compliqué à cause du format de canal alpha dual-png.
Je vais essayer de donner une réponse concise en vb .net mais cela peut prendre un certain temps.
Ayant le même problème d'affichage de l'image 256 * 256 * 32 d'un fichier ICO dans un bloc d'image, j'ai trouvé la solution de SAL80 la plus efficace (et fonctionnant presque). Toutefois, le code d'origine ne prend pas en charge les images stockées au format BMP (la grande icône est généralement le format PNG, mais pas toujours ...).
Voici ma version pour les références futures. Le code pour créer le bitmap est aussi un peu plus simple:
/// <summary>
/// Extracts the large Vista icon from a ICO file
/// </summary>
/// <param name="srcBuf">Bytes of the ICO file</param>
/// <returns>The large icon or null if not found</returns>
private static Bitmap ExtractVistaIcon(byte[] srcBuf)
{
const int SizeIcondir = 6;
const int SizeIcondirentry = 16;
// Read image count from ICO header
int iCount = BitConverter.ToInt16(srcBuf, 4);
// Search for a large icon
for (int iIndex = 0; iIndex < iCount; iIndex++)
{
// Read image information from image directory entry
int iWidth = srcBuf[SizeIcondir + SizeIcondirentry * iIndex];
int iHeight = srcBuf[SizeIcondir + SizeIcondirentry * iIndex + 1];
int iBitCount = BitConverter.ToInt16(srcBuf, SizeIcondir + SizeIcondirentry * iIndex + 6);
// If Vista icon
if (iWidth == 0 && iHeight == 0 && iBitCount == 32)
{
// Get image data position and length from directory
int iImageSize = BitConverter.ToInt32(srcBuf, SizeIcondir + SizeIcondirentry * iIndex + 8);
int iImageOffset = BitConverter.ToInt32(srcBuf, SizeIcondir + SizeIcondirentry * iIndex + 12);
// Check if the image has a PNG signature
if (srcBuf[iImageOffset] == 0x89 && srcBuf[iImageOffset+1] == 0x50 && srcBuf[iImageOffset+2] == 0x4E && srcBuf[iImageOffset+3] == 0x47)
{
// the PNG data is stored directly in the file
var x = new MemoryStream(srcBuf, iImageOffset, iImageSize, false, false);
return new Bitmap(x);
}
// Else it's bitmap data with a partial bitmap header
// Read size from partial header
int w = BitConverter.ToInt32(srcBuf, iImageOffset + 4);
// Create a full header
var b = new Bitmap(w, w, PixelFormat.Format32bppArgb);
// Copy bits into bitmap
BitmapData bmpData = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), ImageLockMode.WriteOnly, b.PixelFormat);
Marshal.Copy(srcBuf, iImageOffset + Marshal.SizeOf(typeof(Bitmapinfoheader)), bmpData.Scan0, b.Width*b.Height*4);
b.UnlockBits(bmpData);
return b;
}
}
return null;
}
Consultez les fonctions de l'icône qui sont disponibles. Il existe également un présentation qui mentionne l'interrogation de différents tailles d'icônes. Un fil de forum Dream.In.Code permet d'utiliser les API en C #, ainsi que une une référence à Pinvoke.net .