说,如果我想从一个库存的Windows可执行文件中提取一个图标。我可以通过在Visual Studio中打开它来获取该图标ID:
然后我会对48x48大小的图标感兴趣:
所以我的假设是:
HICON hIcons[4];
::ExtractIconEx(L"mstsc.exe", -13011, hIcons, NULL, 4);
hIconLogo = hIcons[3];
但是当我运行它时,该方法只返回3个图标:
并且其中只有一个是我需要的32x32版本。
然后我找到了ExtractAssociatedIconEx API,我这样称呼它:
WORD wIcnId = -13011;
WORD wIcnInd = 3;
hIconLogo = ::ExtractAssociatedIconEx(hInst, L"mstsc.exe", &wIcnInd, &wIcnId);
但这也给了我一些我没想到的其他图标。
那么这两个API有什么区别?我做错了什么?
答案 0 :(得分:14)
ExtractIconEx
功能只能返回两种尺寸的图标:大图标和小图标。这些是相对大小,由环境定义。 A"大"图标通常是32x32像素,但在某些系统配置上可能会更大。 A"小"图标是典型的16x16像素,但同样的警告适用。唯一的保证是"小"图标是小于#34;大"图标。如果您想知道系统的实际尺寸,可以使用SM_CXICON
调用GetSystemMetrics
函数,使用SM_CYICON
调用"大"图标,或SM_CXSMICON
和SM_CYSMICON
用于"小"的图标。
操作系统使用" small"和"大"内部的图标;大多数API只涉及" small"和"大" (有时也被称为"大"图标)。例如,当您set an icon for a window设置为" small"图标或者"大"图标。这是你唯一的两个选择。
ExtractIconEx
函数将phIconLarge
参数设置为指向大图标句柄数组的指针。 phIconSmall
参数设置为指向小图标句柄数组的指针。由于您为NULL
参数传递了phIconSmall
,因此您没有获得任何小图标。 hIcons
填充了"大"的句柄。文件中的图标,在您的系统上,是32x32图标的不同位深度。
ExtractAssociatedIcon
功能(及其前兄弟)仅返回"大"图标。因此,当您调用它时,您应该获得与调用ExtractIconEx
的方式相同的结果。我不确定你是否说它会给你不同的结果。它可能与索引有关。否定指数对ExtractIconEx
具有特殊性,但我不确定它们是否对ExtractAssociatedIcon
有效。文档没有给出很多提示。
SHGetFileInfo
功能,虽然在许多方面功能更强大,包括从任何文件系统对象中提取图标的功能,但具有相同功能基本限制:它为您提供SHGFI_LARGEICON
和SHGFI_SMALLICON
的选择。
如果您需要提取自定义尺寸的图标(例如,系统"小""大"尺寸)以外的其他图标,那么您&# 39;我需要做更多的工作。基本上有两种选择:
调用 SHGetImageList
函数,该函数是另一个shell辅助函数,但是检索包含图标的shell映像列表。它为图标大小提供了更多选项:SHIL_SMALL
(通常为16x16),SHIL_LARGE
(通常为32x32),SHIL_EXTRALARGE
(通常为48x48)和SHIL_JUMBO
(通常为256x256-仅在Vista及更高版本上)。因此,如果您要求SHIL_EXTRALARGE
,您将获得您正在寻找的48x48图标。
此处仍然需要SHGetFileInfo
功能,但这次将检索shell图像列表中所需图标的索引。使用SHGFI_SYSICONINDEX
选项检索它。
完全未经测试的示例代码,从未被编译器触及:
HICON ExtractExtraLargeIcon(LPCTSTR pszPath)
{
// Determine the index of the desired icon
// in the system image list.
SHGETFILEINFO sfi;
SHGetFileInfo(pszPath, 0, &sfi, sizeof(sfi), SHGFI_SYSICONINDEX);
// Retrieve the system image list.
// (To get 48x48 icons, we use `SHIL_EXTRALARGE`.)
IImageList* piml;
if (SHGetImageList(SHIL_EXTRALARGE, IID_IImageList, (void**)&piml) == S_OK)
{
HICON hIcon;
if (piml->GetIcon(sfi.iIcon, ILD_TRANSPARENT, &hIcon) == S_OK)
{
return hIcon;
}
}
// Oops! We failed.
return NULL;
}
您的另一个选择是自己从文件中提取所需的大小图标。尽管图标资源格式已有详细记录,并且各种各样的人使用这些知识编写了一堆难看的提取代码并将其发布到Internet上,但有一种更简单的方法:SHDefExtractIcon
。
前段时间为Raymond Chen blogged about,如果SHDefExtractIcon
(上面的代码示例尝试使用的代码失败)失败,那么 IExtractIcon::Extract
就是更强大的后备。此函数的强大功能是其nIconSize
参数,该参数指定要提取的图标的实际大小。
改编Raymond的例子:
HICON ExtractArbitrarySizeIcon(LPCTSTR pszPath, int size)
{
HICON hIcon;
if (SHDefExtractIcon(pszPath, 1, 0, &hIcon, NULL, size) == S_OK)
{
return hIcon;
}
return NULL; // failure
}
无论您做什么,请记住每当API函数返回HICON时,它都会将该资源的所有权转让给您。这意味着,当您完成图标后,必须通过调用DestroyIcon
函数来销毁它,以避免泄漏。