SHGetImageList - SHIL_JUMBO для небольших значков (32,32)

В моем коде я получаю список изображений через функцию SHGETImageList с размером SHIL_JUMBO.

 IImageList iml;
 var hres = SHGetImageList(SHIL_JUMBO, ref iidImageList, out  iml);
 IntPtr hIcon = IntPtr.Zero;
 iml.GetIcon(i, ILD_TRANSPARENT |  ILD_IMAGE, ref hIcon);

 Icon ico =  (Icon)System.Drawing.Icon.FromHandle(hIcon).Clone();
 ShellAPI.DestroyIcon(hIcon);

Все в порядке, но когда ему нужно получить меньшие значки (когда у них нет размера для 256x256), функция GetIcon возвращает мне значок размером 256x256, но с иконкой размером 32x32 в верхнем левом углу, Я хочу изменить размер этого значка на новый размер (256 х 256).

У меня нет информации о том, как изменить размер моего значка на 256 х 256. Каждая функция в iml (например GetImageInfo, GetImageRect) для этого размера возвращает пустую структуру.

Возможно получить информацию о том, что этот значок меньше, и я могу получить значок из другого источника.

Ответы

Ответ 1

Похоже, с Vista Microsoft ожидает, что разработчики будут полагаться на интерфейсы IShellItem и IShellItemImageFactory. В отличие от IImageList реализации списков системных образов, которые сильно нарушены (большинство методов терпят неудачу с E_NOTIMPL, размеры значков не сообщаются), IShellItemImageFactory создает изображения точно так, как они отображаются в проводнике. В случае небольших значков, запрошенных в "гигантском" размере, они центрированы и окружены границей (по крайней мере, на Windows 7). Хотя он менее эффективен и потребляет больше памяти, чем IImageList, Explorer, вероятно, тоже использует его, поэтому это не имеет большого значения.

Подробнее см. IShellItemImageFactory:: Метод GetImage в MSDN.

Там есть библиотека для .NET, которая поддерживает эти интерфейсы: Код кода Windows® для Microsoft®.NET Framework.


Хотя это точно не отвечает на ваш вопрос (по-прежнему нет надежного способа определить размер значков), я думаю, что изменение размера маленькой 32x32-значка до 256x256 - это плохая идея, и путь проводника (изменение размера только до 48x48, затем центрирование). Это также обеспечит согласованное поведение, которое является хорошей идеей.

Рассмотрение таких вопросов было опубликовано во многих местах, и ни один из них не ответил в течение многих лет, я боюсь, что больше информации может получить только обратная инженерия Windows Shell и, в частности, стандартная/стандартная реализация IShellItemImageFactory::GetImage. Джефф Чаппелл сделал совсем немного обратной разработки оболочки, поэтому, возможно, стоит попробовать спросить его...

Ответ 2

Вы можете выполнить некоторый код для идентификации показателей изображения и при необходимости использовать следующее:

var hres = SHGetImageList(SHIL_LARGE, ref iidImageList, out iml);

SHIL_LARGE для 32x32.

Тип указателя IImageList, например, возвращаемый параметром ppv, может быть отброшен как HIMAGELIST по мере необходимости; например, для использования в виде списка. И наоборот, HIMAGELIST может быть отброшен как указатель на IImageList. Начиная с Windows Vista, SHIL_SMALL, SHIL_LARGE и SHIL_EXTRALARGE шкала с точками на дюйм (dpi), если процесс отмечен как dpi. Чтобы установить эти типы в формате dpi, вызовите SetProcessDPIAware. SHIL_JUMBO фиксируется на 256 пикселей независимо от настройки, поддерживающей dpi.

http://msdn.microsoft.com/en-us/library/windows/desktop/bb762185(v=vs.85).aspx

Ответ 3

Я запустил ваш пример, используя

const string IID_IImageList = "46EB5926-582E-4017-9FDF-E8998DAA0950";
const string IID_IImageList2 = "192B9D83-50FC-457B-90A0-2B82A8B5DAE1";

определенный в CommonControls.h При запуске:

        IEnumerable<int> shils =  new int[]{ 
            ShellAPI.SHIL_EXTRALARGE, 
            ShellAPI.SHIL_JUMBO, 
            ShellAPI.SHIL_SYSSMALL,
            ShellAPI.SHIL_LARGE, 
            ShellAPI.SHIL_SMALL,
            ShellAPI.SHIL_LAST
        };
        ShellAPI.IImageList ppv = null;
        Guid guil = new Guid(IID_IImageList2);//or IID_IImageList
        foreach (int iil in shils)
        {
            ShellAPI.SHGetImageList(iil, ref guil, ref ppv);
            int noImages = 0;
            ppv.GetImageCount(ref noImages);
            //...
        }

количество изображений остается постоянным. Поэтому я не согласен с

когда они не имеют размера для 256x256

Для каждого типа списка изображений есть постоянное количество изображений, поэтому для jumbo-установки нет значков.

Я сохранил все найденные значки со всеми разрешениями (16x16,32x32,48x48,256x256). Соотношение сторон идентично всем различным размерам одного и того же значка (тот же самый индекс списка изображений/различное разрешение). Соотношение сторон означает, что версия 256x256 - это не версия 48x48, вставленная в угол, а остальная часть черного фона.

Кроме того, все

значки размером 256x256, но с иконкой размером 32x32 в верхнем левом углу на самом деле являются наложенными изображениями, как можно проверить:

int currentImageListIndex; //loop by noImages above
int idx0Based=0;
ppv.GetOverlayImage(currentImageListIndex+1, ref idx0Based);

Дефекты качества можно легко обнаружить с помощью IImageAList:: GetItemFlags и проверки выходного параметра dwFlags для ILIF_LOWQUALITY, msdn quote ниже

Windows Vista и более поздние версии. Указывает, что элемент в imagelist был создан с помощью функции StretchBlt, следовательно, качество изображения может ухудшиться