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

标签 c++ windows winapi icons windows-shell

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

enter image description here

然后,我将对48x48大小的图标感兴趣:

enter image description here

所以我的假设是:

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

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

enter image description here

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

然后,我找到了被这样调用的ExtractAssociatedIconEx API:
WORD wIcnId = -13011;
WORD wIcnInd = 3;
hIconLogo = ::ExtractAssociatedIconEx(hInst, L"mstsc.exe", &wIcnInd, &wIcnId);

但这也给了我一些意料之外的图标。

那么这两个API有什么区别?我在做什么错呢?

最佳答案

ExtractIconEx 函数只能返回两种尺寸的图标:大和小。这些是相对大小,由环境定义。 “大”图标通常为32x32像素,但在某些系统配置上可能会更大。 “小”图标通常为16x16像素,但同样需要注意。唯一的保证是“小”图标比“大”图标小。如果您想知道系统的实际大小,则可以使用GetSystemMetricsSM_CXICON调用“大”图标,或者使用SM_CYICONSM_CXSMICON调用“小”图标的 SM_CYSMICON 函数。
操作系统内部使用“小”和“大”图标。大多数API仅处理“小”和“大”(有时也称为“大”图标)。例如,当您使用set an icon for a window时,您将设置“小”图标或“大”图标。这些是您仅有的两个选择。ExtractIconEx函数将phIconLarge参数设置为指向大图标的句柄数组的指针。 phIconSmall参数设置为指向小图标的句柄数组的指针。由于您为NULL参数传递了phIconSmall,因此您没有得到任何小图标。 hIcons充满了文件中“大”图标的句柄,在您的系统上,它们是32x32图标的不同位深。
ExtractAssociatedIcon 函数(及其前任兄弟)仅返回“大”图标。因此,在调用它时,应该获得与调用ExtractIconEx相同的结果。我不太确定您是说它给您带来不同的结果。它可能与索引有关。负索引意味着ExtractIconEx有一些特殊之处,但我不确定它们是否对ExtractAssociatedIcon有效。该文档没有太多提示。
SHGetFileInfo 函数尽管在许多方面都更加强大,包括从任何文件系统对象中提取图标的能力,但具有相同的基本限制:它为您提供了SHGFI_LARGEICONSHGFI_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;
        }
    
  • 您的另一个选择是自己从文件中提取所需的大小图标。尽管图标资源格式有充分的文档证明,并且各种人都使用此知识来编写一堆难看的提取代码并将其发布到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 函数来销毁它,以免泄漏。

    关于c++ - ExtractIcon和ExtractAssociatedIcon之间的区别?需要提取特定大小的图标,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37370241/

    相关文章:

    c++ - "call failed and did not execute"

    Windows系统编程

    linux - 使用 clock_gettime(CLOCK_MONOTONIC) 在 CPU 间移动线程

    c++ - 约束现有的 Boost.Spirit real_parser (使用策略)

    c++ - 为什么要使用虚函数?

    windows - Ansible 处理程序在播放结束时运行两次

    windows - SolidWorks 2011 SolidCAM崩溃

    c# - 如何隐藏控制台窗口?

    c++ - boost 1.58 未定义引用

    c++ - Windows上的大型连续虚拟内存分配