Pregunta

Tengo una aplicación para la que he creado un ícono de Vista para Windows de 256 x 256 & nbsp;

Me preguntaba cómo podría utilizar un archivo PNG de 256x256 en el archivo ico utilizado como icono de la aplicación y mostrarlo en un cuadro de imagen en un formulario.

Estoy usando VB.NET, pero las respuestas en C # están bien. Estoy pensando que puedo tener que usar la reflexión.

No estoy seguro de si esto es posible en Windows & nbsp; XP y puede necesitar las API de Windows & nbsp; Vista

¿Fue útil?

Solución

Hoy, hice una muy buena función para extraer los mapas de bits de 256x256 de los íconos de Vista .

Al igual que usted, Nathan W, lo uso para mostrar el icono grande como un mapa de bits en " Acerca de " caja. Por ejemplo, este código obtiene el icono de Vista como imagen PNG y lo muestra en un PictureBox de 256x256:

picboxAppLogo.Image = ExtractVistaIcon(myIcon);

Esta función toma el objeto Icon como parámetro. Por lo tanto, puede usarlo con cualquier ícono, desde recursos , desde archivos, desde secuencias, etc. (Lea a continuación sobre la extracción del icono EXE).

Se ejecuta en cualquier sistema operativo , porque no usa ninguna API Win32, es código 100% administrado : -)

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

IMPORTANTE! Si desea cargar este ícono directamente desde el archivo EXE, NO PUEDE usar Icon.ExtractAssociatedIcon (Application.ExecutablePath) como parámetro, porque la función .NET ExtractAssociatedIcon () es tan estúpida que extrae SOLAMENTE el icono 32x32!

En su lugar, es mejor utilizar toda la clase IconExtractor , creada por Tsuda Kageyu ( http://www.codeproject.com/KB/cs/IconExtractor.aspx ). Puede simplificar ligeramente esta clase para hacerla más pequeña. Use IconExtractor de esta manera:

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

Nota: Sigo usando mi función ExtractVistaIcon () aquí, porque no me gusta cómo IconExtractor maneja este trabajo: primero, extrae todos los formatos de iconos usando IconExtractor.SplitIcon (icoAppIcon ), y luego debe conocer el índice exacto del icono de 256x256 para obtener el icono de vista deseado. Entonces, usar mi ExtractVistaIcon () aquí es una forma mucho más rápida y sencilla :)

Otros consejos

Se encontró información aquí . Para obtener el ícono grande de Vista, debe usar el método SHGetFileInfo de Shell32. He copiado el texto relevante a continuación, por supuesto, querrás reemplazar la variable de nombre de archivo con " Assembly.GetExecutingAssembly (). Location " ;.

using System.Runtime.InteropServices;

Un grupo de constantes que utilizaremos en la llamada a SHGetFileInfo () para especificar el tamaño del icono que deseamos recuperar:

// 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 estructura de SHFILEINFO es muy importante ya que será nuestro control de la información de varios archivos, entre los que se encuentra el icono gráfico.

// 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 preparación final para el código no administrado es definir la firma de SHGetFileInfo, que se encuentra dentro del popular Shell32.dll:

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

Ahora que tenemos todo preparado, es hora de hacer la llamada a la función y mostrar el icono que recuperamos. El objeto que se recuperará es un tipo de icono (System.Drawing.Icon) pero queremos mostrarlo en un PictureBox, por lo que convertiremos el icono en un mapa de bits utilizando el método ToBitmap ().

Pero antes de nada, hay 3 controles que debe agregar al formulario, un btnExtract de botón que tiene " Icono Extraer " para su propiedad Text, picIconSmall que es un PictureBox y un picIconLarge que también es un PictureBox. Eso es porque obtendremos dos tamaños de iconos. Ahora haga doble clic en btnExtract en la vista Diseño de Visual Studio y accederá a su evento Click. Dentro está el resto del código:

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

    }
}

ACTUALIZACIÓN: encontré aún más información aquí .

Ninguna de las respuestas anteriores maneja los íconos de Vista, solo pequeños (32x32) y grandes (48x48)

Hay una biblioteca que maneja los iconos de Vista aquí

... parece bastante complicado debido al formato de canal alfa dual-png.

Intentaré dar una respuesta concisa en vb .net, pero puede llevar algún tiempo.

Al tener el mismo problema de mostrar la imagen 256 * 256 * 32 de un archivo ICO en un cuadro de imagen, encontré que la solución de SAL80 es la más eficiente (y casi funciona). Sin embargo, el código original no admite imágenes almacenadas como BMP (el ícono grande suele ser PNG, pero no siempre ...).

Aquí está mi versión para futuras referencias. El código para crear el mapa de bits también es un poco más 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;
    }

Eche un vistazo a Windows funciones del icono que están disponibles. También hay una descripción general que menciona la consulta de diferentes tamaños de íconos. Hay un hilo de foro Dream.In.Code para usar las API en C #, así como una referencia de Pinvoke.net .

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top