ExtractIcon和ExtractAssociatedIcon之间的区别? 需要提取特定大小的图标

说,如果我想从一个股票Windows可执行文件中提取一个图标。 我可以通过在Visual Studio中打开它来获取该图标ID:

在这里输入图像说明

然后我会对48×48大小的图标感兴趣:

在这里输入图像说明

所以我的假设是做:

HICON hIcons[4]; ::ExtractIconEx(L"mstsc.exe", -13011, hIcons, NULL, 4); hIconLogo = hIcons[3]; 

但是当我运行它时,该方法只返回3个图标:

在这里输入图像说明

只有其中一个是我需要的32×32版本。

然后我find了我调用的ExtractAssociatedIconEx API:

 WORD wIcnId = -13011; WORD wIcnInd = 3; hIconLogo = ::ExtractAssociatedIconEx(hInst, L"mstsc.exe", &wIcnInd, &wIcnId); 

但是这也给了我一些我没想到的图标。

那么这两个API之间有什么区别呢? 我做错了什么?

Solutions Collecting From Web of "ExtractIcon和ExtractAssociatedIcon之间的区别? 需要提取特定大小的图标"

ExtractIconEx函数只能返回两种尺寸的图标:大和小。 这些是由环境定义的相对大小。 “大”图标通常是32×32像素,但在某些系统配置中可能会更大。 一个“小”图标通常是16×16像素,但同样的警告适用。 唯一的保证是一个“小”图标,比“大”图标小。 如果您想了解系统上的实际大小,请调用GetSystemMetrics函数, SM_CXICONSM_CYICON用于“大”图标,或者SM_CXSMICONSM_CYSMICON用于“小”图标。

操作系统在内部使用“小”和“大”图标; 大部分API只处理“小”和“大”(偶尔也被称为“大”图标)。 例如, 为窗口设置图标时 ,可以设置“小”图标或“大”图标。 这是你唯一的两个选择。

ExtractIconEx函数将phIconLarge参数设置为指向大图标的句柄数组的指针。 phIconSmall参数被设置为一个指向小图标的句柄数组的指针。 由于您为phIconSmall参数传递了NULL ,因此您没有得到任何小图标。 hIcons充满了文件中“大”图标的句柄,在您的系统中,这些图标是32×32图标的不同位深度。

ExtractAssociatedIcon函数(和它的前兄弟)只返回“大”图标。 所以当你像调用ExtractIconEx那样调用它的时候,你应该得到相同的结果。 我不太确定你是否在说这是给你不同的结果。 这可能与索引有关。 负指数意味着ExtractIconEx特别的东西,但我不确定它们是否对ExtractAssociatedIcon有效。 文档没有提供太多的提示。

SHGetFileInfo函数尽管在许多方面更强大,包括从任何文件系统对象中提取图标的能力都具有相同的基本限制:它可以让您选择SHGFI_LARGEICONSHGFI_SMALLICON

如果您需要提取自定义大小的图标(即系统的“小”和“大”尺寸以外的其他图标),那么您需要做更多的工作。 基本上有两种选择:

  1. 调用SHGetImageList函数,这是另一个外壳帮助函数,但是它可以检索包含图标的外壳图像列表。 它为您提供了更多的图标大小选项: SHIL_SMALL (通常为16×16), SHIL_LARGE (通常为32×32), SHIL_EXTRALARGE (通常为48×48)和SHIL_JUMBO (通常在Vista及更高版本上为256×256)。 所以,如果你要求SHIL_EXTRALARGE ,你会得到你正在寻找的48×48图标。

    您仍然需要在这里使用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; } 
  2. 你的另一个选择是从你自己的文件中提取所需的大小图标。 虽然图标资源格式有很好的文档记录,不同的人已经使用这些知识来编写一堆难看的提取代码并将其发布到互联网上,但还有一种更简单的方法: SHDefExtractIcon

    正如Raymond Chen博客上一段时间的介绍,如果IExtractIcon::Extract (这是上面的代码示例试图使用的)失败, SHDefExtractIcon是更强大的后备。 这个函数的功能是它的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函数来销毁它,以避免泄漏。