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, следовательно, качество изображения может ухудшиться