SHGetImageList - SHIL_JUMBO 用于较小的图标 (32,32)

问题描述 投票:0回答:3

在我的代码中,我通过函数 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)对于此大小都会返回一个空结构。

可以得到这个图标较小的信息,我可以从其他来源获取图标。

c# windows-vista icons
3个回答
4
投票

看起来,从 Vista 开始,微软希望开发者依赖

IShellItem
IShellItemImageFactory
界面。与系统图像列表的
IImageList
实现不同,该实现严重损坏(大多数方法因
E_NOTIMPL
失败,未报告图标大小),
IShellItemImageFactory
生成的图像与资源管理器中显示的图像完全相同。如果需要“巨型”尺寸的小图标,它们会居中并被边框包围(至少在 Windows 7 上)。虽然它的使用效率比
IImageList
低且消耗更多内存,但 Explorer 可能也会使用它,所以这没什么大不了的。

有关更多详细信息,请参阅 Microsoft 文档中的 IShellItemImageFactory::GetImage 方法

有一个支持这些接口的 .NET 库:适用于 Microsoft® .NET Framework 的 Windows® API 代码包


虽然这并不能完全回答你的问题(仍然没有可靠的方法来确定图标的大小),但我认为将小 32x32 图标调整为 256x256 是一个坏主意,而资源管理器方式(仅调整大小到 48x48,然后居中)应该是首选。这也将提供一致的行为,这是一个好主意。

考虑到类似的问题已经在很多地方发布,而且多年来都没有得到解答,恐怕只能通过逆向工程 Windows Shell 来获得更多信息,特别是标准/默认

IShellItemImageFactory::GetImage
实现。 Geoff Chappell 做了相当多的 shell 逆向工程,所以也许值得尝试问他......


0
投票

您可以执行一些代码来识别图像指标,并在需要时使用以下内容:

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 scale 具有每英寸点数 (dpi) 如果进程标记为 dpi 感知。要将这些类型设置为 dpi 感知,请调用 SetProcessDPIAware。无论 dpi 感知设置如何,SHIL_JUMBO 都固定为 256 像素。

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


-1
投票

我已经使用

运行了你的示例
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 的尺寸时

对于每种图像列表类型,都有固定数量的图像,因此巨型设置不会缺少图标。

我保留了所有找到的所有分辨率的图标(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 函数生成的,因此图像质量可能会下降

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.