Использование значка 256 x 256 Windows Vista в приложении

У меня есть приложение, которое я сделал значок 256 x 256 для Windows Vista для.

Мне было интересно, как я смогу использовать файл PNG 256x256 в файле ico, который используется в качестве значка приложения, и показать его в окне изображения в форме.

Я использую VB.NET, но ответы на С# в порядке. Я думаю, мне, возможно, придется использовать отражение.

Я не уверен, что это возможно даже в Windows XP и может потребоваться Windows API-интерфейсы Vista​​p >

Ответ 1

Сегодня я сделал очень приятную функцию для извлечения 256x256 растровых изображений из значков Vista​​strong > .

Как и вы, Натан W, я использую его для отображения большого значка в виде растрового изображения в поле "О программе". Например, этот код получает значок Vista как изображение PNG и отображает его в 256x256 PictureBox:

picboxAppLogo.Image = ExtractVistaIcon(myIcon);

Эта функция принимает объект Icon как параметр. Таким образом, вы можете использовать его с любыми значками - из ресурсов, из файлов, из потоков и т.д. (Читайте ниже об извлечении значка EXE).

Он работает на любой ОС, потому что он не использует любой Win32 API, он 100% управляемый код: -)

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

ВАЖНО! Если вы хотите загрузить этот значок непосредственно из EXE файла, то вы НЕ МОЖЕТ использовать Icon.ExtractAssociatedIcon(Application.ExecutablePath) в качестве параметра, потому что Функция .NET ExtractAssociatedIcon() настолько глупа, что извлекает ТОЛЬКО 32x32 значок!

Вместо этого лучше использовать весь класс IconExtractor, созданный Tsuda Kageyu (http://www.codeproject.com/KB/cs/IconExtractor.aspx). Вы можете немного упростить этот класс, чтобы уменьшить его. Используйте IconExtractor следующим образом:

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

Примечание. Я все еще использую функцию ExtractVistaIcon() здесь, потому что мне не нравится, как IconExtractor обрабатывает это задание - во-первых, он извлекает все форматы значков с помощью IconExtractor.SplitIcon(icoAppIcon), а затем вам нужно знать точный индекс значков 256x256, чтобы получить нужный значок vista. Итак, использование моего ExtractVistaIcon() здесь намного быстрее и проще:)

Ответ 2

Найдено здесь. Чтобы получить большой значок Vista, вам необходимо использовать метод Shell32 SHGetFileInfo. Я скопировал соответствующий текст ниже, конечно, вы захотите заменить переменную filename на "Assembly.GetExecutingAssembly(). Location".

using System.Runtime.InteropServices;

Буква констант, которые мы будем использовать в вызове SHGetFileInfo(), чтобы указать размер значка, который мы хотим получить:

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

Структура SHFILEINFO очень важна, так как это будет наша ручка для различной информации о файлах, среди которых графический значок.

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

Окончательная подготовка неуправляемого кода - это определить подпись SHGetFileInfo, которая находится внутри популярного файла 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);

Теперь, когда у нас все готово, пришло время сделать вызов функции и отобразить значок, который мы получили. Объект, который будет извлечен, это тип значка (System.Drawing.Icon), но мы хотим отобразить его в PictureBox, чтобы мы преобразовали значок в растровое изображение с помощью метода ToBitmap().

Но прежде всего есть три элемента управления, которые нужно добавить к форме: кнопка btnExtract, которая имеет "Экстракт извлечения" для свойства Text, picIconSmall, который является PictureBox и picIconLarge, который также является PictureBox. Это потому, что мы получим два размера значков. Теперь дважды щелкните btnExtract в представлении Visual Studio Design, и вы попадете на его событие Click. Внутри остальная часть кода:

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: найдено еще больше информации здесь.

Ответ 3

Ни один из вышеперечисленных ответов не обрабатывает Vista Icons - только небольшие (32x32) и большие (48x48)

Существует библиотека, которая обрабатывает значки Vista здесь

... он выглядит довольно сложным из-за формата альфа-канала с двумя PNG.

Я попытаюсь сделать краткий ответ в vb.net, но это может занять некоторое время.

Ответ 4

Имея ту же проблему с отображением 256 * 256 * 32 изображений из ICO файла в окне изображения, я нашел решение от SAL80 наиболее эффективным (и почти работает). Однако исходный код не поддерживает изображения, сохраненные как BMP (большой значок обычно PNG, но не всегда...).

Вот моя версия для будущих ссылок. Код для создания растрового изображения также немного проще:

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

Ответ 5

Посмотрите доступные функции , которые доступны. Также существует обзор, в котором упоминается запрос на различные размеры значков. Там Dream.In.Code поток форума для использования API в С#, а также ссылка Pinvoke.net.