程序开头加上如下引用,不然编译不过。
#pragma comment(lib, "Version.lib")
结构定义:
struct LANGANDCODEPAGE
{
WORD wLanguage;
WORD wCodePage;
};
struct VS_VERSIONINFO
{
WORD wLength;
WORD wValueLength;
WORD wType;
WCHAR szKey[1];
WORD wPadding1[1]; //以零填充szKey以对齐数据为32位(4个字节)
VS_FIXEDFILEINFO Value;
WORD wPadding2[1];
WORD wChildren[1];
};
struct KEYSTRING
{
WORD wLength;
WORD wValueLength;
WORD wType;
WCHAR szKey[1];
WORD Padding[1];
WORD Value[1];
};
struct STRINGTABLE
{
WORD wLength;
WORD wValueLength;
WORD wType;
WCHAR szKey[1];
WORD Padding[1];
KEYSTRING Children[1];
};
struct STRINGFILEINFO
{
WORD wLength;
WORD wValueLength;
WORD wType;
WCHAR szKey[1];
WORD Padding[1];
STRINGTABLE Children[1];
};
VS_VERSIONINFO及相关的结构是个相当复杂的结构,主要是因为他它里面的szKey及 诸如Children等成员的大小并不确定,所以在定义这些结构时都是以1为单位,在实际应用时才确定其具体地址。
定义两个字符串于存储字段名及字段值:
CHAR szKey[MAX_PATH]={0}, szValue[MAX_PATH]={0};
因为各字符串都是以宽字符形式存储的,所以要进行转换,相关函数:
//*****************************************************************************
// 宽字符串转为标准字符串
// swSource:宽字符串 szDescription=保存标准字符串的缓冲区 nSize = 缓冲区大小
//*****************************************************************************
BOOL TransformStringWideToAnsi(LPCWSTR swSource, LPSTR szDescription, UINT nSize)
{
UINT nLength = WideCharToMultiByte(CP_ACP, NULL, swSource, -1, NULL, 0, NULL, NULL);
if((nLength<=0)||(nSize<nLength)) return FALSE;
WideCharToMultiByte(CP_ACP, NULL, swSource, -1, szDescription, nLength, NULL, NULL);
szDescription[nLength-1]=0;
return TRUE;
}
//*****************************************************************************
// 列举文件描述信息
// lpszAppFile=文件名
//*****************************************************************************
BOOL ListAppDescription(LPCSTR lpszAppFile)
{
BOOL fgRet = FALSE;
DWORD dwHandle, dwSize;
LPSTR lpFileName = (LPSTR)lpszAppFile;
//获取版本信息区大小
dwSize = ::GetFileVersionInfoSize(lpFileName, &dwHandle);
if(dwSize == 0) return FALSE;
//建立缓冲区,
LPBYTE lpBuffer = new BYTE[dwSize];
ZeroMemory(lpBuffer, dwSize);
do
{
//读取版本信息
if(!::GetFileVersionInfo(lpFileName, 0, dwSize, lpBuffer)) break;
//获取语言代码
UINT nSize;
LANGANDCODEPAGE *lpTranslate = NULL;
if(!::VerQueryValue(lpBuffer, _T("\\VarFileInfo\\Translation"), (LPVOID *)(&lpTranslate), &nSize)) break;
//定位VS_VERSIONINFO结构体
VS_VERSIONINFO *pVerInfo;
pVerInfo = (VS_VERSIONINFO *)lpBuffer;
if(pVerInfo->wValueLength == 0) break;
if(!wcscmp(pVerInfo->szKey, (WCHAR *)"VS_VERSION_INFO")) break;
//定位VS_FIXEDFILEINFO结构体
VS_FIXEDFILEINFO *pFixedInfo;
nSize = wcslen(pVerInfo->szKey);
LPBYTE pOffsetBytes = (BYTE *)pVerInfo->szKey + ((nSize+1)*sizeof(WCHAR)); //跳过szkey
pFixedInfo = (VS_FIXEDFILEINFO *)(pOffsetBytes+(nSize*sizeof(WCHAR))%4); //修正偏移地址
if(pFixedInfo->dwSignature != 0xfeef04bd) break; //检查标记
//定位STRINGFILEINFO结构体
STRINGFILEINFO *pStringFileInfo;
pOffsetBytes = (BYTE *)pFixedInfo + sizeof(VS_FIXEDFILEINFO); //跳过VS_FIXEDFILEINFO即为STRINGFILEINFO
pStringFileInfo = (STRINGFILEINFO *)pOffsetBytes;
//定位STRINGTABLE结构体
STRINGTABLE *pStringTable;
nSize = wcslen(pStringFileInfo->szKey);
pOffsetBytes = (BYTE *)pStringFileInfo->szKey + ((nSize+1)*sizeof(WCHAR));
pStringTable = (STRINGTABLE *)(pOffsetBytes+(nSize*sizeof(WCHAR))%4);
//定位KEYSTRING结构体
KEYSTRING *pKeyString;
nSize = wcslen(pStringTable->szKey);
pOffsetBytes = (BYTE *)pStringTable->szKey + ((nSize+1)*sizeof(WCHAR)); //跳过块头(中文(080404b0))
pOffsetBytes += (nSize*sizeof(WCHAR))%4;
WCHAR *pwString=NULL, swKeyName[MAX_PATH];
TransformStringAnsiToWide(lpszKeyName, swKeyName, MAX_PATH);
while((pOffsetBytes-(BYTE *)pStringTable)<pStringTable->wLength)
{
pKeyString = (KEYSTRING *)pOffsetBytes; //KEYSTRING结构体
nSize = wcslen(pKeyString->szKey); //跳过KEY_NAME
pwString = pKeyString->szKey+nSize+1; //算上结束字符
pwString += (nSize%4)/sizeof(WCHAR); //对齐32位,得到KEY_VALUE地址
//转换为标准字符串
TransformStringWideToAnsi(pKeyString->szKey, szKey, MAX_PATH);
if(pKeyString->wValueLength) TransformStringWideToAnsi(pwString, szValue, MAX_PATH);
//显示部分略
//strcat(szKey, "=");
//strcat(szKey, szValue);
//ShowMessage(szKey);
//计算下一项地址
pOffsetBytes += pKeyString->wLength;
pOffsetBytes += pKeyString->wLength%4; //对齐32位
}
}while(FALSE);
delete []lpBuffer;
return fgRet;
}