ExtractIcon 和 ExtractAssociatedIcon 之间的区别?需要提取特定大小的图标
Difference between ExtractIcon and ExtractAssociatedIcon? Need to extract icon of specific size
比如说,如果我想从库存 Windows 可执行文件中提取图标。我可以通过在 Visual Studio:
中打开它来获取该图标 ID
那么我会对 48x48 大小的图标感兴趣:
所以我的假设是:
HICON hIcons[4];
::ExtractIconEx(L"mstsc.exe", -13011, hIcons, NULL, 4);
hIconLogo = hIcons[3];
但是当我运行它时,方法returns只有3个图标:
其中只有一个是我需要的 32x32 版本。
然后我发现 ExtractAssociatedIconEx API 我是这样调用的:
WORD wIcnId = -13011;
WORD wIcnInd = 3;
hIconLogo = ::ExtractAssociatedIconEx(hInst, L"mstsc.exe", &wIcnInd, &wIcnId);
但这也给了我一些我没想到的其他图标。
那么这两个 API 之间有什么区别?我做错了什么?
ExtractIconEx
function can return only two sizes of icons: large and small. Those are relative sizes, defined by the environment. A "large" icon is classically 32x32 pixels, but may be larger on certain system configurations. A "small" icon is classically 16x16 pixels, but the same caveat applies. The only guarantee is that a "small" icon is, well, smaller than a "large" icon. If you want to know the actual size on your system, you call the GetSystemMetrics
函数,SM_CXICON
和 SM_CYICON
用于“大”图标,或 SM_CXSMICON
和 SM_CYSMICON
用于“小”图标" 图标。
操作系统在内部到处使用“小”和“大”图标;大多数 API 仅处理“小”和“大”(有时也称为“大”图标)。例如,当您 set an icon for a window 时,您设置了“小”图标或“大”图标。这是你仅有的两个选择。
ExtractIconEx
函数将 phIconLarge
参数设置为指向大图标句柄数组的指针。 phIconSmall
参数设置为指向小图标句柄数组的指针。由于您为 phIconSmall
参数传递了 NULL
,因此您没有得到任何小图标。 hIcons
填充了文件中“大”图标的句柄,在您的系统上,这些图标是 32x32 图标的不同位深度。
ExtractAssociatedIcon
函数(及其 Ex 兄弟)returns 仅“大”图标。所以当你调用它时你应该得到与你调用 ExtractIconEx
的方式相同的结果。我不太确定您是说它是否给您 不同 结果。它可能与索引有关。负索引对 ExtractIconEx
有特殊意义,但我不确定它们是否对 ExtractAssociatedIcon
有效。文档没有给出太多提示。
SHGetFileInfo
函数,尽管在许多方面更强大,包括从 any 中提取图标的能力文件系统对象,具有相同的基本限制:它为您提供 SHGFI_LARGEICON
和 SHGFI_SMALLICON
.
的选择
如果您需要提取自定义尺寸的图标(即系统“小”和“大”尺寸以外的图标),那么您需要做更多的工作。 基本上有两个选项:
- 调用
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;
}
- 您的另一种选择是自己从文件中提取所需大小的图标。虽然图标资源格式有很好的文档记录,并且各种人利用这些知识写了一堆丑陋的提取代码并发布在互联网上,但有一个更简单的方法:
SHDefExtractIcon
.
与 Raymond Chen blogged about 前段时间一样,SHDefExtractIcon
如果 IExtractIcon::Extract
是你更强大的后备(这是上面的代码示例尝试的使用)失败。这个函数的强大之处在于它的 nIconSize
参数,它指定了你想要提取的图标的实际大小。
改编雷蒙德的例子:
HICON ExtractArbitrarySizeIcon(LPCTSTR pszPath, int size)
{
HICON hIcon;
if (SHDefExtractIcon(pszPath, 1, 0, &hIcon, NULL, size) == S_OK)
{
return hIcon;
}
return NULL; // failure
}
无论您做什么,请记住,每当 API 函数 returns HICON 时,它都会将该资源的所有权转让给您。这意味着,当您完成图标后,您必须通过调用 DestroyIcon
函数来销毁它以避免泄漏。
比如说,如果我想从库存 Windows 可执行文件中提取图标。我可以通过在 Visual Studio:
中打开它来获取该图标 ID那么我会对 48x48 大小的图标感兴趣:
所以我的假设是:
HICON hIcons[4];
::ExtractIconEx(L"mstsc.exe", -13011, hIcons, NULL, 4);
hIconLogo = hIcons[3];
但是当我运行它时,方法returns只有3个图标:
其中只有一个是我需要的 32x32 版本。
然后我发现 ExtractAssociatedIconEx API 我是这样调用的:
WORD wIcnId = -13011;
WORD wIcnInd = 3;
hIconLogo = ::ExtractAssociatedIconEx(hInst, L"mstsc.exe", &wIcnInd, &wIcnId);
但这也给了我一些我没想到的其他图标。
那么这两个 API 之间有什么区别?我做错了什么?
ExtractIconEx
function can return only two sizes of icons: large and small. Those are relative sizes, defined by the environment. A "large" icon is classically 32x32 pixels, but may be larger on certain system configurations. A "small" icon is classically 16x16 pixels, but the same caveat applies. The only guarantee is that a "small" icon is, well, smaller than a "large" icon. If you want to know the actual size on your system, you call the GetSystemMetrics
函数,SM_CXICON
和 SM_CYICON
用于“大”图标,或 SM_CXSMICON
和 SM_CYSMICON
用于“小”图标" 图标。
操作系统在内部到处使用“小”和“大”图标;大多数 API 仅处理“小”和“大”(有时也称为“大”图标)。例如,当您 set an icon for a window 时,您设置了“小”图标或“大”图标。这是你仅有的两个选择。
ExtractIconEx
函数将 phIconLarge
参数设置为指向大图标句柄数组的指针。 phIconSmall
参数设置为指向小图标句柄数组的指针。由于您为 phIconSmall
参数传递了 NULL
,因此您没有得到任何小图标。 hIcons
填充了文件中“大”图标的句柄,在您的系统上,这些图标是 32x32 图标的不同位深度。
ExtractAssociatedIcon
函数(及其 Ex 兄弟)returns 仅“大”图标。所以当你调用它时你应该得到与你调用 ExtractIconEx
的方式相同的结果。我不太确定您是说它是否给您 不同 结果。它可能与索引有关。负索引对 ExtractIconEx
有特殊意义,但我不确定它们是否对 ExtractAssociatedIcon
有效。文档没有给出太多提示。
SHGetFileInfo
函数,尽管在许多方面更强大,包括从 any 中提取图标的能力文件系统对象,具有相同的基本限制:它为您提供 SHGFI_LARGEICON
和 SHGFI_SMALLICON
.
如果您需要提取自定义尺寸的图标(即系统“小”和“大”尺寸以外的图标),那么您需要做更多的工作。 基本上有两个选项:
- 调用
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;
}
- 您的另一种选择是自己从文件中提取所需大小的图标。虽然图标资源格式有很好的文档记录,并且各种人利用这些知识写了一堆丑陋的提取代码并发布在互联网上,但有一个更简单的方法:
SHDefExtractIcon
.
与 Raymond Chen blogged about 前段时间一样,SHDefExtractIcon
如果 IExtractIcon::Extract
是你更强大的后备(这是上面的代码示例尝试的使用)失败。这个函数的强大之处在于它的 nIconSize
参数,它指定了你想要提取的图标的实际大小。
改编雷蒙德的例子:
HICON ExtractArbitrarySizeIcon(LPCTSTR pszPath, int size)
{
HICON hIcon;
if (SHDefExtractIcon(pszPath, 1, 0, &hIcon, NULL, size) == S_OK)
{
return hIcon;
}
return NULL; // failure
}
无论您做什么,请记住,每当 API 函数 returns HICON 时,它都会将该资源的所有权转让给您。这意味着,当您完成图标后,您必须通过调用 DestroyIcon
函数来销毁它以避免泄漏。