ExtractIconEx:有效,但偶尔会崩溃

时间:2018-10-28 12:23:29

标签: c++ arrays winapi icons allocation

我正在从文件中提取图标并将其显示在对话框中

const LPCWSTR path = L"c:\path\to\file";
const UINT nIconsCheck = ExtractIconEx(path, -1, nullptr, nullptr, 0);
if(nIconsCheck > 0)
{
    HICON *iconHandles=new HICON;
    const UINT nIcons = ExtractIconEx(path, 0, iconHandles, nullptr, nIconsCheck);

    if(nIcons == nIconsCheck && nIcons != unsigned(-1))
    {

        IconSelect iconSelect(this); //dialog
        for(UINT i=0; i<nIcons; i++)
        {
            qDebug() << i;
            iconSelect.addIcon(QtWin::fromHICON(iconHandles[i])); //fromHICON returns QPixmap
            DestroyIcon(iconHandles[i]);
        }

        iconSelect.exec();
    }
}

在对话框中正确加载了图标,但有时会意外地导致应用程序崩溃。

知道发生了什么吗?

Documentation on ExtractIconEx

编辑:感谢您提供快速而有用的答案。以下是我正在使用atm的完整工作代码:

// In my case I have a QString `filePath`
// `QString::toWCharArray` retrieves a non-0-terminated string,
// so append a 0 to `path`
std::vector<WCHAR> path(unsigned(filePath.length())+1); 
filePath.toWCharArray(path.data());
path.at(path.size()-1) = 0;

// Get number of icons in selected file
UINT nIcons = ExtractIconEx(path.data(), -1, nullptr, nullptr, 0);

if(nIcons == 0)
{
    // Try to find associated file that contains icon(s)
    // If found, `path` is replaced with the new path
    WORD index=0;
    DestroyIcon(ExtractAssociatedIcon(GetModuleHandle(nullptr), path.data(), &index));
    // Get number of icons in associated file
    nIcons = ExtractIconEx(path.data(), -1, nullptr, nullptr, 0);
}

if(nIcons > 0)
{
    // Get array of HICONs
    std::vector<HICON> iconHandles(nIcons);
    nIcons = ExtractIconEx(path.data(), 0, iconHandles.data(), nullptr, nIcons);

    for(UINT i=0; i<nIcons; i++) // Using iconHandles.size() is possibly safer,
                                 // but AFAIK nIcons always carries the correct value
    {
        // Use iconHandles[i]
        // In Qt you can use QtWin::fromHICON(iconHandles[i]) to generate a QPixmap
        DestroyIcon(iconHandles[i]);
    }
}

2 个答案:

答案 0 :(得分:4)

HICON *iconHandles=new HICON;

在这里,您仅分配一个HICON对象。如果给定文件中有多个图标,则对ExtractIconEx()的下一次调用将通过写入分配的内存来创建缓冲区溢出。您已进入行为不确定的黑暗世界。

要解决此问题,您可以像这样使用std::vector

std::vector<HICON> iconHandles(nIconsCheck); 
const UINT nIcons = ExtractIconEx(path, 0, iconHandles.data(), nullptr, iconHandles.size());
iconHandles.resize(nIcons); // Resize to the actual number of icons.

// Instead of: if(nIcons == nIconsCheck && nIcons != unsigned(-1))
if(!iconHandles.empty())
{
    // Use icons
}

与手动分配相比,这具有优势,您无需delete分配的内存。范围结束时,vector析构函数将自动执行此操作。尽管您仍然必须为每个图标句柄调用DestroyIcon()

答案 1 :(得分:2)

从您链接到的文档中:

  

指向图标句柄数组的指针,该数组接收从文件中提取的大图标的句柄。如果此参数为NULL,则不会从文件中提取大图标。

您只给了它一个指向一个图标句柄的指针。

分配一个与函数预期大小一样大的数组;从外观上看,这意味着nIconsCheck个元素。正如zett42所说,向量对此很有用。