SHGetImageList - SHIL_JUMBO для маленьких значков (32,32) - PullRequest
17 голосов
/ 23 июня 2011

В моем коде я получаю список изображений через функцию 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 x 256).

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

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

Ответы [ 3 ]

2 голосов
/ 08 октября 2013

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

См. IShellItemImageFactory :: GetImage метод в MSDN для получения дополнительной информации.подробнее.

Существует библиотека для .NET, которая поддерживает следующие интерфейсы: Windows® API Code Pack для Microsoft® .NET Framework .


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

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

0 голосов
/ 05 сентября 2013

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

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 приведена ниже

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

0 голосов
/ 30 октября 2012

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

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-based . Чтобы установить эти типы с поддержкой dpi, вызовите SetProcessDPIAware. SHIL_JUMBO имеет фиксированное значение 256 пикселей независимо от настройки с поддержкой dpi.

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

...