VerQueryValue是常用的用于查询/获取PE文件信息的API。
但对于某些exe或dll文件,却出现了问题。
一般的做法,首先通过如下代码,获取文件的语言代码和代码页信息:
typedef struct _LANGANDCODEPAGE
{
WORD wLanguage;
WORD wCodePage;
}LANGANDCODEPAGE;
LANGANDCODEPAGE* m_lpTransTable = nullptr;
::VerQueryValue(lpVersionData,
_T("\\VarFileInfo\\Translation"),
(void **)&m_lpTransTable,
&nQuerySize);
第二部,通过如下代码进行各类信息的查询:
CString strBlockName;
strBlockName.Format(_T("\\StringFileInfo\\%04x%04x\\%s"),
m_lpTransTable[0].wLanguage,
m_lpTransTable[0].wCodePage,
lpszValueName);
::VerQueryValue((void **)m_lpVersionData,
strBlockName,
&lpData, &nQuerySize);
然而,在对以上代码进行测试时发现,对某些exe,VerQueryValue始终返回FALSE,通过GetLastError获取错误代码为1813,也就是ERROR_RESOURCE_TYPE_NOT_FOUND。
但是奇怪的是,通过右键菜单查看属性的”详细信息“,可以看到各类文件信息。
经过一番研究,终于弄清楚原委:
直接原因是是第二部中m_lpTransTable[0].wLanguage的问题。
实际上,这个WORD类型的wLanguage就是CLID(详细可参考我的这篇文章《操作系统的语言ID(LCID)》)
我们获取到的exe文件的CLID是0x0000,也就是语言中性的(Language-Neutral)。也就是说,使用这个CLID在这个exe文件中是查不到任何信息的,那么换成其他的CLID取值呢?
我这里用0904进行了替换,再运行,OK了。
这个问题存在于很多Windows自带的文件中,这就像个脑经急转弯,弄清楚了也就那么回事,但一开始却不容易想到。
只是不知道微软为什么要这么做,是无意的,还是想对开发人员隐藏一些信息呢。