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

C# SHGetImageList-SHIL_JUMBO用于较小图标(32,32),c#,windows-vista,icons,C#,Windows Vista,Icons,在我的代码中,我通过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.Dr

在我的代码中,我通过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)都返回一个空结构


可以获取此图标较小的信息,我可以从其他来源获取图标。

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

var hres=SHGetImageList(SHIL_大,参考iidImageList,输出iml)

SHIL_LARGE适用于32x32

IImageList指针类型(如ppv参数中返回的指针类型)可以根据需要转换为HIMAGELIST;例如,在列表视图中使用。相反,HIMAGELIST可以转换为指向IImageList的指针。 从Windows Vista开始,如果进程标记为dpi aware,则使用每英寸点数(dpi)的SHIL_小、SHIL_大和SHIL_超大比例。要将这些类型设置为dpi感知,请调用SetProcessDPIAware。SHIL_JUMBO固定为256像素,与dpi感知设置无关


我使用

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);
            //...
        }
使用iImageList::GetItemFlags并检查下面的输出dwFlags参数的ILIF_LOWQUALITY,msdn quote,可以很容易地发现质量下降

Windows Vista及更高版本。指示imagelist中的项是通过StretchBlt函数生成的,因此图像质量可能会降低


看起来,自Vista以来,Microsoft希望开发人员依赖于
IShellItem
IShellItemImageFactory
接口。与系统映像列表的
IImageList
实现不同,
iImageFactory
生成的映像与资源管理器中显示的映像完全相同,系统映像列表的实现严重受损(大多数方法都会因
E_NOTIMPL
而失败,图标大小不会报告)。如果请求的小图标大小为“jumbo”,则它们将居中并由边框包围(至少在Windows 7上)。虽然它比
IImageList
效率更低,占用内存更多,但Explorer可能也使用它,所以这没什么大不了的

有关更多详细信息,请参阅MSDN上的

有一个支持以下接口的.NET库:


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


考虑到像这样的问题已经在很多地方发布,而且多年来都没有得到回答,恐怕只有通过反向工程Windows Shell,特别是标准/默认
IShellItemImageFactory::GetImage
实现才能获得更多信息。对壳牌公司进行了大量的逆向工程,所以也许值得试着问他……

我也遇到了同样的问题。快把我逼疯了。从另一个方向解决问题:有没有办法检测是否存在巨型图标?i的值是多少?你确定这不是因为它们只是叠加图像吗?这个答案为GetImage方法提供了一个很好的包装器:
int currentImageListIndex; //loop by noImages above
int idx0Based=0;
ppv.GetOverlayImage(currentImageListIndex+1, ref idx0Based);