ExtractIconEx:有效但偶尔会崩溃

ExtractIconEx: works but occasionally crashes

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

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]);
    }
}
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()

来自您链接到的文档:

Pointer to an array of icon handles that receives handles to the large icons extracted from the file. If this parameter is NULL, no large icons are extracted from the file.

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

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