我正在尝试使用以下代码从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上没有,则为here's the cop y),其字符串表编码为wLanguage
为0,wCodePage
为1200。 VerQueryValue
失败,错误代码为ERROR_RESOURCE_TYPE_NOT_FOUND
。但是我知道在文件浏览器中检查该文件时,该文件具有“文件描述”属性:
那么我上面的代码在做什么错了?
答案 0 :(得分:3)
使用Resource Hacker查看MSTTSEngine.dll,资源数据不一致。 VarFileInfo\Translation
定义的语言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 property API获取版本资源信息的方法。我给了example in this answer。在我的计算机上,它可以从MSTTSEngine.dll正确读取文件描述。