在我的代码中,我通过函数 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)对于此大小都会返回一个空结构。
可以得到这个图标较小的信息,我可以从其他来源获取图标。
看起来,从 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 逆向工程,所以也许值得尝试问他......
您可以执行一些代码来识别图像指标,并在需要时使用以下内容:
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
我已经使用
运行了你的示例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 函数生成的,因此图像质量可能会下降