首页 > 解决方案 > 带有 Unicode UTF-16 (1200) 代码页字符串表的 VerQueryValue 失败

问题描述

我正在尝试使用以下代码从 PE 文件中检索文件描述:

//This code was simplified &
//most error checks were removed for brevity

BYTE* pData = new BYTE[4096];
LPCTSTR path = L"C:\\Windows\\system32\\Speech\\Engines\\TTS\\MSTTSEngine.dll";
if(::GetFileVersionInfo(path, NULL, 4096, pData))
{
    struct LANGANDCODEPAGE
    {
        WORD wLanguage;
        WORD wCodePage;
    } *lpTranslate = NULL;

    UINT cbTranslate;
    if(VerQueryValue(pData,  L"\\VarFileInfo\\Translation", (LPVOID*)&lpTranslate, &cbTranslate))
    {
        CString strBlock;
        strBlock.Format(L"\\StringFileInfo\\%04x%04x\\FileDescription", 
            lpTranslate[0].wLanguage,
            lpTranslate[0].wCodePage
            );

        UINT dwProdLn = 0;
        VOID* lpBufferName = NULL;
        if(VerQueryValue(pData, strBlock, &lpBufferName, &dwProdLn))
        {
            TRACE(L"Description: %s", lpBufferName);
        }
        else
        {
            TRACE(L"Error=%d", ::GetLastError());
        }
    }

    delete[] pData;
}

该特定文件(如果您的 Windows 10 上没有它,这里是副本wLanguage)具有编码为 0 和wCodePage1200 的字符串表。在这种情况下VerQueryValue失败并显示错误代码ERROR_RESOURCE_TYPE_NOT_FOUND。但是当我在文件资源管理器中检查该文件时,我知道该文件具有“文件描述”属性:

在此处输入图像描述

那么我在上面的代码中做错了什么?

标签: c++winapimfcfileversioninfo

解决方案


使用 Resource Hacker 查看 MSTTSEngine.dll,资源数据存在不一致。VarFileInfo\Translation由is定义的语言 ID 0x0000,而StringFileInfo定义0x0409。只有 CodePage 值匹配。

BLOCK "StringFileInfo"
{
    BLOCK "040904b0"
    //     ^^^^ -> Problem
    {
        VALUE "CompanyName", "Microsoft Corporation"
        VALUE "FileDescription", "Microsoft TTS Engine (Desktop)"
        // [...]
    }
}

BLOCK "VarFileInfo"
{
    VALUE "Translation", 0x0000 0x04B0
    //                     ^^^^ -> Problem
}

因此,您的代码尝试读取StringFileInfo\000004B0不存在的。不幸的是,这种破坏版本资源的情况并没有得到很好的处理VerQueryValue,因为没有办法StringFileInfo独立于VarFileInfo.

解决方案

有另一种方法可以使用shell 属性 API获取版本资源信息。我在这个答案中给出了一个例子。在我的机器上,它正确地从 MSTTSEngine.dll 读取文件描述。


推荐阅读