由于需要用到EXE文件的OriginalFilename这个值,原本微软提供了API可以取得PE文件的版本信息,通过VerQueryValue可以查询到这个值。
标准的取法是:
- 通过
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/
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。