由于需要用到EXE文件的OriginalFilename这个值,原本微软提供了API可以取得PE文件的版本信息,通过VerQueryValue可以查询到这个值。
标准的取法是:
- 通过
1 BOOL GetOriginalFilename(LPCTSTR pszPath, CString& rOriginalFilename)
2 {
3 if (NULL==pszPath)
4 {
5 return FALSE;
6 }
7
8 /// Get the length for version information
9
10 DWORD dwVersion = 0;
11 DWORD dwHandle = 0;
12 dwVersion = GetFileVersionInfoSize(pszPath, &dwHandle);
13 if (!dwVersion)
14 {
15 return FALSE;
16 }
17
18 /// Alloc the buffer for version information
19
20 std::auto_ptr<BYTE> pbBuffer(new BYTE[dwVersion]);
21 PVOID pBlock = pbBuffer.get();
22 ZeroMemory(pBlock, dwVersion);
23
24 if (!GetFileVersionInfo(pszPath, dwHandle, dwVersion, pBlock))
25 {
26 return FALSE;
27 }
28
29 /// Structure used to store enumerated languages and code pages.
30
31 struct LANGANDCODEPAGE
32 {
33 WORD wLanguage;
34 WORD wCodePage;
35 } *lpTranslate;
36
37 UINT cbTranslate = 0;
38
39 /// Read the list of languages and code pages.
40
41 VerQueryValue(pBlock,
42 TEXT("\\VarFileInfo\\Translation"),
43 (LPVOID*)&lpTranslate,
44 &cbTranslate);
45 if (NULL==lpTranslate)
46 {
47 return FALSE;
48 }
49
50 /// Read the Original filename for 1st language and code page.
51
52 TCHAR SubBlock[50] = {0};
53 StringCchPrintf(SubBlock, 50,
54 TEXT("\\StringFileInfo\\%04x%04x\\OriginalFilename"),
55 lpTranslate[0].wLanguage,
56 lpTranslate[0].wCodePage);
57
58 /// Retrieve file description for language and code page "i".
59
60 BOOL bResult = FALSE;
61 UINT dwBytes = 0;
62 LPTSTR pszFileName = NULL;
63 if (VerQueryValue(pBlock,
64 SubBlock,
65 (LPVOID*)&pszFileName,
66 &dwBytes))
67 {
68 rOriginalFilename = pszFileName;
69 bResult = TRUE;
70 }
71
72 return bResult;
73 }
通过上面代码就可以取得EXE文件的OriginalFilename值。但是有时候EXE文件资源信息中没有对应的Translation值或者Translation的值不匹配,但是有对应的OriginalFilename,这时候通过标准的方法就取不到了,怎么办呢?
如这是WinRAR的版本信息,对应的就不对。
Length Of Struc: 02ACh
Length Of Value: 0034h
Type Of Struc: 0000h
Info: VS_VERSION_INFO
Signature: FEEF04BDh
Struc Version: 1.0
File Version: 3.90.5.0
Product Version: 3.90.5.0
File Flags Mask: 0.0
File Flags:
File OS: WINDOWS32
File Type: APP
File SubType: UNKNOWN
File Date: 00:00:00 00/00/0000
Struc has Child(ren). Size: 592 bytes.
Child Type: StringFileInfo
Language/Code Page: 1033/1252
ProductName: WinRAR
CompanyName: Alexander Roshal
FileDescription: WinRAR archiver
FileVersion: 3.90.5
InternalName: WinRAR
LegalCopyright: Copyright ? Alexander Roshal 1993-2009
OriginalFilename: WinRAR.exe
Child Type: VarFileInfo
Translation: 0/0
这时通过之前的方法就不行了,只好自己解析了。下面代码参考了网上的VerInfoLib的代码,有兴趣的可以去下完整的代码http://packcab.googlecode.com/svn/trunk/VerInfoLib/
1 struct VarBlock
2 {
3 WORD wLength;
4 WORD wValueLength;
5 WORD wType;
6 WCHAR szKey[ANYSIZE_ARRAY];
7 WORD Padding[ANYSIZE_ARRAY];
8 };
9
10 struct VarString:
11 public VarBlock
12 {
13 WORD Value[ANYSIZE_ARRAY];
14 };
15
16 struct VarStringTable:
17 public VarBlock
18 {
19 VarString Children[ANYSIZE_ARRAY];
20 };
21
22 struct VarStringFileInfo:
23 public VarBlock
24 {
25 VarStringTable Children[ANYSIZE_ARRAY];
26 };
27
28 #define DWORDUP(x) (((DWORD)(LPBYTE)(x)+3)&~03)
29
30 BOOL GetOriginalFilename1(LPCTSTR pszPath, CString& rOriginalFilename)
31 {
32 if (NULL==pszPath)
33 {
34 return FALSE;
35 }
36
37 /// Get the length for version information
38
39 DWORD dwVersion = 0;
40 DWORD dwHandle = 0;
41 dwVersion = GetFileVersionInfoSize(pszPath, &dwHandle);
42 if (!dwVersion)
43 {
44 return FALSE;
45 }
46
47 /// Alloc the buffer for version information
48
49 std::auto_ptr<BYTE> pbBuffer(new BYTE[dwVersion]);
50 PVOID pBlock = pbBuffer.get();
51 ZeroMemory(pBlock, dwVersion);
52
53 if (!GetFileVersionInfo(pszPath, dwHandle, dwVersion, pBlock))
54 {
55 return FALSE;
56 }
57
58 /// Get StringFleInfo list in version information
59
60 LPVOID* pbStringFileInfo = NULL;
61 UINT cbStringFileInfo = 0;
62 VerQueryValue(pBlock,TEXT("\\StringFileInfo"),
63 (LPVOID*)&pbStringFileInfo,&cbStringFileInfo);
64
65 if (NULL==pbStringFileInfo)
66 {
67 return FALSE;
68 }
69
70 VarStringTable* pbStringTable = (VarStringTable*)DWORDUP(pbStringFileInfo);
71
72 BOOL bResult = FALSE;
73 VarString* pbString = (VarString*)DWORDUP(pbStringTable->szKey + lstrlenW(pbStringTable->szKey) + 1);
74 while ((DWORD_PTR)pbString < (DWORD_PTR)pbStringTable + pbStringTable->wLength)
75 {
76 if (lstrcmpiW(pbString->szKey, L"OriginalFilename")==0)
77 {
78 rOriginalFilename = (WCHAR*)DWORDUP(pbString->szKey + lstrlenW(pbString->szKey) + 1);
79 bResult = TRUE;
80 break;
81 }
82
83 pbString = (VarString*)DWORDUP((DWORD_PTR)pbString + pbString->wLength);
84 }
85
86 return bResult;
87 }
上面代码取出第一个StringTable值,并从中解析出OriginalFilename。具体参考MSDN中的Version Information。