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 .

Était-ce utile?

La solution

Aujourd'hui, j'ai créé une fonction très utile pour extraire les icônes 256 x 256 Bitmaps de Vista .

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 .

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top