2 * Copyright (C) 2004 Stefan Leichter
3 * Copyright (C) 2017 Akihiro Sagawa
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
31 #include "wine/test.h"
33 #define MY_LAST_ERROR ((DWORD)-1)
34 #define EXPECT_BAD_PATH__NOT_FOUND \
35 ok( (ERROR_PATH_NOT_FOUND == GetLastError()) || \
36 (ERROR_RESOURCE_DATA_NOT_FOUND == GetLastError()) || \
37 (ERROR_FILE_NOT_FOUND == GetLastError()) || \
38 (ERROR_BAD_PATHNAME == GetLastError()) || \
39 (ERROR_SUCCESS == GetLastError()), \
40 "Last error wrong! ERROR_RESOURCE_DATA_NOT_FOUND/ERROR_BAD_PATHNAME (98)/" \
41 "ERROR_PATH_NOT_FOUND (NT4)/ERROR_FILE_NOT_FOUND (2k3) " \
42 "ERROR_SUCCESS (2k) expected, got %u\n", GetLastError());
43 #define EXPECT_INVALID__NOT_FOUND \
44 ok( (ERROR_PATH_NOT_FOUND == GetLastError()) || \
45 (ERROR_RESOURCE_DATA_NOT_FOUND == GetLastError()) || \
46 (ERROR_FILE_NOT_FOUND == GetLastError()) || \
47 (ERROR_INVALID_PARAMETER == GetLastError()) || \
48 (ERROR_SUCCESS == GetLastError()), \
49 "Last error wrong! ERROR_RESOURCE_DATA_NOT_FOUND/ERROR_INVALID_PARAMETER (98)/" \
50 "ERROR_PATH_NOT_FOUND (NT4)/ERROR_FILE_NOT_FOUND (2k3) " \
51 "ERROR_SUCCESS (2k) expected, got %u\n", GetLastError());
53 static void create_file(const CHAR
*name
)
58 file
= CreateFileA(name
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, NULL
);
59 ok(file
!= INVALID_HANDLE_VALUE
, "Failure to open file %s\n", name
);
60 WriteFile(file
, name
, strlen(name
), &written
, NULL
);
61 WriteFile(file
, "\n", strlen("\n"), &written
, NULL
);
65 static void test_info_size(void)
67 char mypath
[MAX_PATH
] = "";
69 SetLastError(MY_LAST_ERROR
);
70 retval
= GetFileVersionInfoSizeA( NULL
, NULL
);
72 "GetFileVersionInfoSizeA result wrong! 0L expected, got 0x%08x\n",
74 EXPECT_INVALID__NOT_FOUND
;
77 SetLastError(MY_LAST_ERROR
);
78 retval
= GetFileVersionInfoSizeA( NULL
, &hdl
);
80 "GetFileVersionInfoSizeA result wrong! 0L expected, got 0x%08x\n",
82 EXPECT_INVALID__NOT_FOUND
;
84 "Handle wrong! 0L expected, got 0x%08x\n", hdl
);
86 SetLastError(MY_LAST_ERROR
);
87 retval
= GetFileVersionInfoSizeA( "", NULL
);
89 "GetFileVersionInfoSizeA result wrong! 0L expected, got 0x%08x\n",
91 EXPECT_BAD_PATH__NOT_FOUND
;
94 SetLastError(MY_LAST_ERROR
);
95 retval
= GetFileVersionInfoSizeA( "", &hdl
);
97 "GetFileVersionInfoSizeA result wrong! 0L expected, got 0x%08x\n",
99 EXPECT_BAD_PATH__NOT_FOUND
;
101 "Handle wrong! 0L expected, got 0x%08x\n", hdl
);
103 SetLastError(MY_LAST_ERROR
);
104 retval
= GetFileVersionInfoSizeA( "kernel32.dll", NULL
);
106 "GetFileVersionInfoSizeA result wrong! <> 0L expected, got 0x%08x\n",
108 ok((NO_ERROR
== GetLastError()) || (MY_LAST_ERROR
== GetLastError()),
109 "Last error wrong! NO_ERROR/0x%08x (NT4) expected, got %u\n",
110 MY_LAST_ERROR
, GetLastError());
113 SetLastError(MY_LAST_ERROR
);
114 retval
= GetFileVersionInfoSizeA( "kernel32.dll", &hdl
);
116 "GetFileVersionInfoSizeA result wrong! <> 0L expected, got 0x%08x\n",
118 ok((NO_ERROR
== GetLastError()) || (MY_LAST_ERROR
== GetLastError()),
119 "Last error wrong! NO_ERROR/0x%08x (NT4) expected, got %u\n",
120 MY_LAST_ERROR
, GetLastError());
122 "Handle wrong! 0L expected, got 0x%08x\n", hdl
);
124 SetLastError(MY_LAST_ERROR
);
125 retval
= GetFileVersionInfoSizeA( "notexist.dll", NULL
);
127 "GetFileVersionInfoSizeA result wrong! 0L expected, got 0x%08x\n",
129 ok( (ERROR_FILE_NOT_FOUND
== GetLastError()) ||
130 (ERROR_RESOURCE_DATA_NOT_FOUND
== GetLastError()) ||
131 (MY_LAST_ERROR
== GetLastError()) ||
132 (ERROR_SUCCESS
== GetLastError()), /* win2k */
133 "Last error wrong! ERROR_FILE_NOT_FOUND/ERROR_RESOURCE_DATA_NOT_FOUND "
134 "(XP)/0x%08x (NT4) expected, got %u\n", MY_LAST_ERROR
, GetLastError());
136 /* test a currently loaded executable */
137 if(GetModuleFileNameA(NULL
, mypath
, MAX_PATH
)) {
139 SetLastError(MY_LAST_ERROR
);
140 retval
= GetFileVersionInfoSizeA( mypath
, &hdl
);
142 "GetFileVersionInfoSizeA result wrong! <> 0L expected, got 0x%08x\n",
144 ok((NO_ERROR
== GetLastError()) || (MY_LAST_ERROR
== GetLastError()),
145 "Last error wrong! NO_ERROR/0x%08x (NT4) expected, got %u\n",
146 MY_LAST_ERROR
, GetLastError());
148 "Handle wrong! 0L expected, got 0x%08x\n", hdl
);
151 trace("skipping GetModuleFileNameA(NULL,..) failed\n");
153 /* test a not loaded executable */
154 if(GetSystemDirectoryA(mypath
, MAX_PATH
)) {
155 lstrcatA(mypath
, "\\regsvr32.exe");
157 if(INVALID_FILE_ATTRIBUTES
== GetFileAttributesA(mypath
))
158 trace("GetFileAttributesA(%s) failed\n", mypath
);
161 SetLastError(MY_LAST_ERROR
);
162 retval
= GetFileVersionInfoSizeA( mypath
, &hdl
);
164 "GetFileVersionInfoSizeA result wrong! <> 0L expected, got 0x%08x\n",
166 ok((NO_ERROR
== GetLastError()) || (MY_LAST_ERROR
== GetLastError()),
167 "Last error wrong! NO_ERROR/0x%08x (NT4) expected, got %u\n",
168 MY_LAST_ERROR
, GetLastError());
170 "Handle wrong! 0L expected, got 0x%08x\n", hdl
);
174 trace("skipping GetSystemDirectoryA(mypath,..) failed\n");
176 create_file("test.txt");
178 /* no version info */
179 SetLastError(0xdeadbeef);
181 retval
= GetFileVersionInfoSizeA("test.txt", &hdl
);
182 ok(retval
== 0, "Expected 0, got %d\n", retval
);
183 ok(hdl
== 0, "Expected 0, got %d\n", hdl
);
184 ok(GetLastError() == ERROR_RESOURCE_DATA_NOT_FOUND
||
185 GetLastError() == ERROR_SUCCESS
, /* win2k */
186 "Expected ERROR_RESOURCE_DATA_NOT_FOUND, got %d\n", GetLastError());
188 DeleteFileA("test.txt");
191 static void VersionDwordLong2String(DWORDLONG Version
, LPSTR lpszVerString
)
195 a
= (WORD
)(Version
>> 48);
196 b
= (WORD
)((Version
>> 32) & 0xffff);
197 c
= (WORD
)((Version
>> 16) & 0xffff);
198 d
= (WORD
)(Version
& 0xffff);
200 sprintf(lpszVerString
, "%d.%d.%d.%d", a
, b
, c
, d
);
203 static void test_info(void)
206 PVOID pVersionInfo
= NULL
;
208 VS_FIXEDFILEINFO
*pFixedVersionInfo
;
210 char VersionString
[MAX_PATH
];
211 static const char backslash
[] = "\\";
212 DWORDLONG dwlVersion
;
215 SetLastError(MY_LAST_ERROR
);
216 retval
= GetFileVersionInfoSizeA( "kernel32.dll", &hdl
);
218 "GetFileVersionInfoSizeA result wrong! <> 0L expected, got 0x%08x\n",
220 ok((NO_ERROR
== GetLastError()) || (MY_LAST_ERROR
== GetLastError()),
221 "Last error wrong! NO_ERROR/0x%08x (NT4) expected, got %u\n",
222 MY_LAST_ERROR
, GetLastError());
224 "Handle wrong! 0L expected, got 0x%08x\n", hdl
);
226 if ( retval
== 0 || hdl
!= 0)
229 pVersionInfo
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, retval
);
230 ok(pVersionInfo
!= 0, "HeapAlloc failed\n" );
231 if (pVersionInfo
== 0)
236 /* this test crashes on WinNT4
238 boolret
= GetFileVersionInfoA( "kernel32.dll", 0, retval
, 0);
239 ok (!boolret
, "GetFileVersionInfoA should have failed: GetLastError = %u\n", GetLastError());
240 ok ((GetLastError() == ERROR_INVALID_DATA
) || (GetLastError() == ERROR_BAD_PATHNAME
) ||
241 (GetLastError() == NO_ERROR
),
242 "Last error wrong! ERROR_INVALID_DATA/ERROR_BAD_PATHNAME (ME)/"
243 "NO_ERROR (95) expected, got %u\n",
247 boolret
= GetFileVersionInfoA( "kernel32.dll", 0, retval
, pVersionInfo
);
248 ok (boolret
, "GetFileVersionInfoA failed: GetLastError = %u\n", GetLastError());
252 boolret
= VerQueryValueA( pVersionInfo
, NULL
, (LPVOID
*)&pFixedVersionInfo
, &uiLength
);
253 ok (boolret
|| GetLastError() == NO_ERROR
/* Win98 */,
254 "VerQueryValueA failed: GetLastError = %u\n", GetLastError());
256 boolret
= VerQueryValueA( pVersionInfo
, "", (LPVOID
*)&pFixedVersionInfo
, &uiLength
);
257 ok (boolret
, "VerQueryValueA failed: GetLastError = %u\n", GetLastError());
259 boolret
= VerQueryValueA( pVersionInfo
, backslash
, (LPVOID
*)&pFixedVersionInfo
, &uiLength
);
260 ok (boolret
, "VerQueryValueA failed: GetLastError = %u\n", GetLastError());
264 dwlVersion
= (((DWORDLONG
)pFixedVersionInfo
->dwFileVersionMS
) << 32) +
265 pFixedVersionInfo
->dwFileVersionLS
;
267 VersionDwordLong2String(dwlVersion
, VersionString
);
269 trace("kernel32.dll version: %s\n", VersionString
);
273 /* this test crashes on WinNT4
275 boolret
= VerQueryValueA( pVersionInfo
, backslash
, (LPVOID
*)&pFixedVersionInfo
, 0);
276 ok (boolret
, "VerQueryValue failed: GetLastError = %u\n", GetLastError());
280 HeapFree( GetProcessHeap(), 0, pVersionInfo
);
283 static void test_32bit_win(void)
286 DWORD hdlW
, retvalW
= 0;
288 PVOID pVersionInfoA
= NULL
;
289 PVOID pVersionInfoW
= NULL
;
292 UINT uiLengthA
, uiLengthW
;
293 char mypathA
[MAX_PATH
];
294 WCHAR mypathW
[MAX_PATH
];
296 WCHAR rootW
[] = { '\\', 0 };
297 WCHAR emptyW
[] = { 0 };
298 char varfileinfoA
[] = "\\VarFileInfo\\Translation";
299 WCHAR varfileinfoW
[] = { '\\','V','a','r','F','i','l','e','I','n','f','o',
300 '\\','T','r','a','n','s','l','a','t','i','o','n', 0 };
301 char WineVarFileInfoA
[] = { 0x09, 0x04, 0xE4, 0x04 };
302 char FileDescriptionA
[] = "\\StringFileInfo\\040904E4\\FileDescription";
303 WCHAR FileDescriptionW
[] = { '\\','S','t','r','i','n','g','F','i','l','e','I','n','f','o',
304 '\\','0','4','0','9','0','4','E','4',
305 '\\','F','i','l','e','D','e','s','c','r','i','p','t','i','o','n', 0 };
306 char WineFileDescriptionA
[] = "FileDescription";
307 WCHAR WineFileDescriptionW
[] = { 'F','i','l','e','D','e','s','c','r','i','p','t','i','o','n', 0 };
308 BOOL is_unicode_enabled
= TRUE
;
310 /* A copy from dlls/version/info.c */
317 #if 0 /* variable length structure */
321 VS_VERSION_INFO_STRUCT32 Children
[];
323 } VS_VERSION_INFO_STRUCT32
;
325 /* If we call GetFileVersionInfoA on a system that supports Unicode, NT/W2K/XP/W2K3 (by default) and Wine,
326 * the versioninfo will contain Unicode strings.
327 * Part of the test is to call both the A and W versions, which should have the same Version Information
328 * for some requests, on systems that support both calls.
331 /* First get the versioninfo via the W versions */
332 SetLastError(0xdeadbeef);
333 GetModuleFileNameW(NULL
, mypathW
, MAX_PATH
);
334 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
336 win_skip("GetModuleFileNameW not existing on this platform, skipping comparison between A- and W-calls\n");
337 is_unicode_enabled
= FALSE
;
340 if (is_unicode_enabled
)
342 retvalW
= GetFileVersionInfoSizeW( mypathW
, &hdlW
);
343 pVersionInfoW
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, retvalW
);
344 retW
= GetFileVersionInfoW( mypathW
, 0, retvalW
, pVersionInfoW
);
345 ok(retW
, "GetFileVersionInfo failed: GetLastError = %u\n", GetLastError());
348 GetModuleFileNameA(NULL
, mypathA
, MAX_PATH
);
349 retvalA
= GetFileVersionInfoSizeA( mypathA
, &hdlA
);
350 pVersionInfoA
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, retvalA
);
351 retA
= GetFileVersionInfoA( mypathA
, 0, retvalA
, pVersionInfoA
);
352 ok(retA
, "GetFileVersionInfo failed: GetLastError = %u\n", GetLastError());
354 if (is_unicode_enabled
)
356 ok( retvalA
== retvalW
, "The size of the struct should be the same for both A/W calls, it is (%d) vs. (%d)\n",
358 ok( !memcmp(pVersionInfoA
, pVersionInfoW
, retvalA
), "Both structs should be the same, they aren't\n");
361 /* The structs on Windows are bigger than just the struct for the basic information. The total struct
362 * contains also an empty part, which is used for converted strings. The converted strings are a result
363 * of calling VerQueryValueA on a 32bit resource and calling VerQueryValueW on a 16bit resource.
364 * The first WORD of the structure (wLength) shows the size of the base struct. The total struct size depends
365 * on the Windows version:
367 * 16bits resource (numbers are from a sample app):
369 * Windows Version Retrieved with A/W wLength StructSize
370 * ====================================================================================
371 * Win98 A 0x01B4 (436) 436
372 * NT4 A/W 0x01B4 (436) 2048 ???
373 * W2K/XP/W2K3 A/W 0x01B4 (436) 1536 which is (436 - sizeof(VS_FIXEDFILEINFO)) * 4
375 * 32bits resource (numbers are from this test executable version_crosstest.exe):
376 * Windows Version Retrieved with A/W wLength StructSize
377 * =============================================================
378 * Win98 A 0x01E0 (480) 848 (structure data doesn't seem correct)
379 * NT4 A/W 0x0350 (848) 1272 (848 * 1.5)
380 * W2K/XP/W2K3 A/W 0x0350 (848) 1700 which is (848 * 2) + 4
382 * Wine will follow the implementation (eventually) of W2K/XP/W2K3
385 /* Now some tests for the above (only if we are unicode enabled) */
387 if (is_unicode_enabled
)
389 VS_VERSION_INFO_STRUCT32
*vvis
= pVersionInfoW
;
390 ok ( retvalW
== ((vvis
->wLength
* 2) + 4) || retvalW
== (vvis
->wLength
* 1.5),
391 "Structure is not of the correct size\n");
394 /* Although the 32bit resource structures contain Unicode strings, VerQueryValueA will always return normal strings,
395 * VerQueryValueW will always return Unicode ones. (That means everything returned for StringFileInfo requests).
398 /* Get the VS_FIXEDFILEINFO information, this must be the same for both A- and W-Calls */
400 retA
= VerQueryValueA( pVersionInfoA
, rootA
, (LPVOID
*)&pBufA
, &uiLengthA
);
401 ok (retA
, "VerQueryValueA failed: GetLastError = %u\n", GetLastError());
402 ok ( uiLengthA
== sizeof(VS_FIXEDFILEINFO
), "Size (%d) doesn't match the size of the VS_FIXEDFILEINFO struct\n", uiLengthA
);
404 if (is_unicode_enabled
)
407 { /* This causes Vista and w2k8 to crash */
408 retW
= VerQueryValueW( pVersionInfoW
, NULL
, (LPVOID
*)&pBufW
, &uiLengthW
);
409 ok (retW
, "VerQueryValueW failed: GetLastError = %u\n", GetLastError());
412 retW
= VerQueryValueW( pVersionInfoW
, emptyW
, (LPVOID
*)&pBufW
, &uiLengthW
);
413 ok (retW
, "VerQueryValueW failed: GetLastError = %u\n", GetLastError());
415 retW
= VerQueryValueW( pVersionInfoW
, rootW
, (LPVOID
*)&pBufW
, &uiLengthW
);
416 ok (retW
, "VerQueryValueW failed: GetLastError = %u\n", GetLastError());
417 ok ( uiLengthW
== sizeof(VS_FIXEDFILEINFO
), "Size (%d) doesn't match the size of the VS_FIXEDFILEINFO struct\n", uiLengthW
);
419 ok( uiLengthA
== uiLengthW
, "The size of VS_FIXEDFILEINFO should be the same for both A/W calls, it is (%d) vs. (%d)\n",
420 uiLengthA
, uiLengthW
);
421 ok( !memcmp(pBufA
, pBufW
, uiLengthA
), "Both values should be the same, they aren't\n");
424 /* Get some VarFileInfo information, this must be the same for both A- and W-Calls */
426 retA
= VerQueryValueA( pVersionInfoA
, varfileinfoA
, (LPVOID
*)&pBufA
, &uiLengthA
);
427 ok (retA
, "VerQueryValueA failed: GetLastError = %u\n", GetLastError());
428 ok( !memcmp(pBufA
, WineVarFileInfoA
, uiLengthA
), "The VarFileInfo should have matched 0904e404 (non case sensitive)\n");
430 if (is_unicode_enabled
)
432 retW
= VerQueryValueW( pVersionInfoW
, varfileinfoW
, (LPVOID
*)&pBufW
, &uiLengthW
);
433 ok (retW
, "VerQueryValueW failed: GetLastError = %u\n", GetLastError());
434 ok( uiLengthA
== uiLengthW
, "The size of the VarFileInfo information should be the same for both A/W calls, it is (%d) vs. (%d)\n",
435 uiLengthA
, uiLengthW
);
436 ok( !memcmp(pBufA
, pBufW
, uiLengthA
), "Both values should be the same, they aren't\n");
439 /* Get some StringFileInfo information, this will be ANSI for A-Calls and Unicode for W-Calls */
441 retA
= VerQueryValueA( pVersionInfoA
, FileDescriptionA
, (LPVOID
*)&pBufA
, &uiLengthA
);
442 ok (retA
, "VerQueryValueA failed: GetLastError = %u\n", GetLastError());
443 ok( !lstrcmpA(WineFileDescriptionA
, pBufA
), "expected '%s' got '%s'\n",
444 WineFileDescriptionA
, pBufA
);
446 /* Test a second time */
447 retA
= VerQueryValueA( pVersionInfoA
, FileDescriptionA
, (LPVOID
*)&pBufA
, &uiLengthA
);
448 ok (retA
, "VerQueryValueA failed: GetLastError = %u\n", GetLastError());
449 ok( !lstrcmpA(WineFileDescriptionA
, pBufA
), "expected '%s' got '%s'\n",
450 WineFileDescriptionA
, pBufA
);
452 if (is_unicode_enabled
)
454 retW
= VerQueryValueW( pVersionInfoW
, FileDescriptionW
, (LPVOID
*)&pBufW
, &uiLengthW
);
455 ok (retW
, "VerQueryValueW failed: GetLastError = %u\n", GetLastError());
456 ok( !lstrcmpW(WineFileDescriptionW
, pBufW
), "FileDescription should have been '%s'\n", WineFileDescriptionA
);
459 HeapFree( GetProcessHeap(), 0, pVersionInfoA
);
460 if (is_unicode_enabled
)
461 HeapFree( GetProcessHeap(), 0, pVersionInfoW
);
464 static void test_VerQueryValueA(void)
466 static const char * const value_name
[] = {
467 "Product", "CompanyName", "FileDescription", "Internal",
468 "ProductVersion", "InternalName", "File", "LegalCopyright",
469 "FileVersion", "Legal", "OriginalFilename", "ProductName",
470 "Company", "Original" };
472 UINT len
, ret
, translation
, i
;
475 ret
= GetModuleFileNameA(NULL
, buf
, sizeof(buf
));
478 SetLastError(0xdeadbeef);
479 len
= GetFileVersionInfoSizeA(buf
, NULL
);
480 ok(len
, "GetFileVersionInfoSizeA(%s) error %u\n", buf
, GetLastError());
482 ver
= HeapAlloc(GetProcessHeap(), 0, len
);
485 SetLastError(0xdeadbeef);
486 ret
= GetFileVersionInfoA(buf
, 0, len
, ver
);
487 ok(ret
, "GetFileVersionInfoA error %u\n", GetLastError());
489 p
= (char *)0xdeadbeef;
491 SetLastError(0xdeadbeef);
492 ret
= VerQueryValueA(ver
, "\\VarFileInfo\\Translation", (LPVOID
*)&p
, &len
);
493 ok(ret
, "VerQueryValue error %u\n", GetLastError());
494 ok(len
== 4, "VerQueryValue returned %u, expected 4\n", len
);
496 translation
= *(UINT
*)p
;
497 translation
= MAKELONG(HIWORD(translation
), LOWORD(translation
));
499 p
= (char *)0xdeadbeef;
501 SetLastError(0xdeadbeef);
502 ret
= VerQueryValueA(ver
, "String", (LPVOID
*)&p
, &len
);
503 ok(!ret
, "VerQueryValue should fail\n");
504 ok(GetLastError() == ERROR_RESOURCE_TYPE_NOT_FOUND
||
505 GetLastError() == 0xdeadbeef /* NT4, W2K */,
506 "VerQueryValue returned %u\n", GetLastError());
507 ok(p
== (char *)0xdeadbeef, "expected 0xdeadbeef got %p\n", p
);
508 ok(len
== 0, "expected 0 got %x\n", len
);
510 p
= (char *)0xdeadbeef;
512 SetLastError(0xdeadbeef);
513 ret
= VerQueryValueA(ver
, "StringFileInfo", (LPVOID
*)&p
, &len
);
514 ok(ret
, "VerQueryValue error %u\n", GetLastError());
515 ok(len
== 0, "VerQueryValue returned %u, expected 0\n", len
);
516 ok(p
!= (char *)0xdeadbeef, "not expected 0xdeadbeef\n");
518 p
= (char *)0xdeadbeef;
520 SetLastError(0xdeadbeef);
521 ret
= VerQueryValueA(ver
, "\\StringFileInfo", (LPVOID
*)&p
, &len
);
522 ok(ret
, "VerQueryValue error %u\n", GetLastError());
523 ok(len
== 0, "VerQueryValue returned %u, expected 0\n", len
);
524 ok(p
!= (char *)0xdeadbeef, "not expected 0xdeadbeef\n");
526 p
= (char *)0xdeadbeef;
528 SetLastError(0xdeadbeef);
529 ret
= VerQueryValueA(ver
, "\\\\StringFileInfo", (LPVOID
*)&p
, &len
);
530 ok(ret
, "VerQueryValue error %u\n", GetLastError());
531 ok(len
== 0, "VerQueryValue returned %u, expected 0\n", len
);
532 ok(p
!= (char *)0xdeadbeef, "not expected 0xdeadbeef\n");
534 p
= (char *)0xdeadbeef;
536 SetLastError(0xdeadbeef);
537 ret
= VerQueryValueA(ver
, "\\StringFileInfo\\\\", (LPVOID
*)&p
, &len
);
538 ok(ret
, "VerQueryValue error %u\n", GetLastError());
539 ok(len
== 0, "VerQueryValue returned %u, expected 0\n", len
);
540 ok(p
!= (char *)0xdeadbeef, "not expected 0xdeadbeef\n");
542 sprintf(buf
, "\\StringFileInfo\\%08x", translation
);
543 p
= (char *)0xdeadbeef;
545 SetLastError(0xdeadbeef);
546 ret
= VerQueryValueA(ver
, buf
, (LPVOID
*)&p
, &len
);
547 ok(ret
, "VerQueryValue error %u\n", GetLastError());
548 ok(len
== 0, "VerQueryValue returned %u, expected 0\n", len
);
549 ok(p
!= (char *)0xdeadbeef, "not expected 0xdeadbeef\n");
551 for (i
= 0; i
< sizeof(value_name
)/sizeof(value_name
[0]); i
++)
553 sprintf(buf
, "\\StringFileInfo\\%08x\\%s", translation
, value_name
[i
]);
554 p
= (char *)0xdeadbeef;
556 SetLastError(0xdeadbeef);
557 ret
= VerQueryValueA(ver
, buf
, (LPVOID
*)&p
, &len
);
558 ok(ret
, "VerQueryValueA(%s) error %u\n", buf
, GetLastError());
559 ok(len
== strlen(value_name
[i
]) + 1, "VerQueryValue returned %u\n", len
);
560 ok(!strcmp(value_name
[i
], p
), "expected \"%s\", got \"%s\"\n",
563 /* test partial value names */
566 p
= (char *)0xdeadbeef;
568 SetLastError(0xdeadbeef);
569 ret
= VerQueryValueA(ver
, buf
, (LPVOID
*)&p
, &len
);
570 ok(!ret
, "VerQueryValueA(%s) succeeded\n", buf
);
571 ok(GetLastError() == ERROR_RESOURCE_TYPE_NOT_FOUND
||
572 GetLastError() == 0xdeadbeef /* NT4, W2K */,
573 "VerQueryValue returned %u\n", GetLastError());
574 ok(p
== (char *)0xdeadbeef, "expected 0xdeadbeef got %p\n", p
);
575 ok(len
== 0, "expected 0 or 0xbeef, got %x\n", len
);
578 HeapFree(GetProcessHeap(), 0, ver
);
581 static void test_VerQueryValue_InvalidLength(void)
583 /* this buffer is created with the reactos resource compiler from this resource:
586 VS_VERSION_INFO VERSIONINFO
588 PRODUCTVERSION 1,0,0,0
593 FILESUBTYPE VFT2_UNKNOWN
595 BLOCK "StringFileInfo"
600 char preparedbuffer
[] = {
601 /* VS_VERSION_INFO_STRUCT32 */
602 0x80, 0x00, /* wLength */
603 0x34, 0x00, /* wValueLength */
604 0x00, 0x00, /* wType */
605 /* L"VS_VERSION_INFO" + DWORD alignment */
606 0x56, 0x00, 0x53, 0x00, 0x5f, 0x00, 0x56, 0x00, 0x45, 0x00, 0x52, 0x00, 0x53, 0x00, 0x49, 0x00, 0x4f,
607 0x00, 0x4e, 0x00, 0x5f, 0x00, 0x49, 0x00, 0x4e, 0x00, 0x46, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x00,
609 /* VS_FIXEDFILEINFO */
610 0xbd, 0x04, 0xef, 0xfe, /* dwSignature */
611 0x00, 0x00, 0x01, 0x00, /* dwStrucVersion */
612 0x00, 0x00, 0x01, 0x00, /* dwFileVersionMS */
613 0x00, 0x00, 0x00, 0x00, /* dwFileVersionLS */
614 0x00, 0x00, 0x01, 0x00, /* dwProductVersionMS */
615 0x00, 0x00, 0x00, 0x00, /* dwProductVersionLS */
616 0x3f, 0x00, 0x00, 0x00, /* dwFileFlagsMask */
617 0x00, 0x00, 0x00, 0x00, /* dwFileFlags */
618 0x00, 0x00, 0x00, 0x00, /* dwFileOS */
619 0x01, 0x00, 0x00, 0x00, /* dwFileType */
620 0x00, 0x00, 0x00, 0x00, /* dwFileSubtype */
621 0x00, 0x00, 0x00, 0x00, /* dwFileDateMS */
622 0x00, 0x00, 0x00, 0x00, /* dwFileDateLS */
625 0x24, 0x00, /* wLength */
626 0x00, 0x00, /* wValueLength */
627 0x01, 0x00, /* wType */
628 /* L"StringFileInfo" + DWORD alignment */
629 0x53, 0x00, 0x74, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x67, 0x00, 0x46, 0x00, 0x69, 0x00,
630 0x6c, 0x00, 0x65, 0x00, 0x49, 0x00, 0x6e, 0x00, 0x66, 0x00, 0x6f, 0x00, 0x00, 0x00,
632 0x46, 0x45, 0x32, 0x58,
634 /* Extra bytes allocated for W->A conversions. */
635 0x0d, 0xf0, 0xad, 0xba, 0x0d, 0xf0, 0xad, 0xba, 0x0d, 0xf0, 0xad, 0xba, 0x0d, 0xf0, 0xad, 0xba,
636 0x0d, 0xf0, 0xad, 0xba, 0x0d, 0xf0, 0xad, 0xba, 0x0d, 0xf0, 0xad, 0xba, 0x0d, 0xf0, 0xad, 0xba,
637 0x0d, 0xf0, 0xad, 0xba, 0x0d, 0xf0, 0xad, 0xba, 0x0d, 0xf0, 0xad, 0xba, 0x0d, 0xf0, 0xad, 0xba,
638 0x0d, 0xf0, 0xad, 0xba, 0x0d, 0xf0, 0xad, 0xba, 0x0d, 0xf0, 0xad, 0xba, 0x0d, 0xf0, 0xad, 0xba,
639 0x0d, 0xf0, 0xad, 0xba, 0x0d, 0xf0, 0xad, 0xba, 0x0d, 0xf0, 0xad, 0xba, 0x0d, 0xf0, 0xad, 0xba,
640 0x0d, 0xf0, 0xad, 0xba, 0x0d, 0xf0, 0xad, 0xba, 0x0d, 0xf0, 0xad, 0xba, 0x0d, 0xf0, 0xad, 0xba,
641 0x0d, 0xf0, 0xad, 0xba, 0x0d, 0xf0, 0xad, 0xba, 0x0d, 0xf0, 0xad, 0xba, 0x0d, 0xf0, 0xad, 0xba,
642 0x0d, 0xf0, 0xad, 0xba, 0x0d, 0xf0, 0xad, 0xba, 0x0d, 0xf0, 0xad, 0xba, 0x0d, 0xf0, 0xad, 0xba,
646 WCHAR FileDescriptionW
[] = { '\\', '\\', 'S', 't', 'r', 'i', 'n', 'g', 'F', 'i', 'l', 'e', 'I', 'n', 'f', 'o', 0 };
648 p
= (char *)0xdeadbeef;
650 SetLastError(0xdeadbeef);
651 ret
= VerQueryValueA(preparedbuffer
, "StringFileInfo", (LPVOID
*)&p
, &len
);
652 ok(ret
, "VerQueryValueA error %u\n", GetLastError());
653 ok(len
== 0, "VerQueryValueA returned %u, expected 0\n", len
);
655 ok(p
== preparedbuffer
+ 0x7e, "p was %p, expected %p\n", p
, preparedbuffer
+ 0x7e);
657 p
= (char *)0xdeadbeef;
659 SetLastError(0xdeadbeef);
660 ret
= VerQueryValueA(preparedbuffer
, "\\StringFileInfo", (LPVOID
*)&p
, &len
);
661 ok(ret
, "VerQueryValueA error %u\n", GetLastError());
662 ok(len
== 0, "VerQueryValueA returned %u, expected 0\n", len
);
664 ok(p
== preparedbuffer
+ 0x7e, "p was %p, expected %p\n", p
, preparedbuffer
+ 0x7e);
666 p
= (char *)0xdeadbeef;
668 SetLastError(0xdeadbeef);
669 ret
= VerQueryValueA(preparedbuffer
, "\\\\StringFileInfo", (LPVOID
*)&p
, &len
);
670 ok(ret
, "VerQueryValueA error %u\n", GetLastError());
671 ok(len
== 0, "VerQueryValueA returned %u, expected 0\n", len
);
673 ok(p
== preparedbuffer
+ 0x7e, "p was %p, expected %p\n", p
, preparedbuffer
+ 0x7e);
675 /* also test the W versions. */
676 p
= (char *)0xdeadbeef;
678 SetLastError(0xdeadbeef);
679 ret
= VerQueryValueW(preparedbuffer
, FileDescriptionW
+ 2, (LPVOID
*)&p
, &len
);
680 ok(ret
, "VerQueryValueW error %u\n", GetLastError());
681 ok(len
== 0, "VerQueryValueW returned %u, expected 0\n", len
);
683 ok(p
== preparedbuffer
+ 0x7e, "p was %p, expected %p\n", p
, preparedbuffer
+ 0x7e);
685 p
= (char *)0xdeadbeef;
687 SetLastError(0xdeadbeef);
688 ret
= VerQueryValueW(preparedbuffer
, FileDescriptionW
+ 1, (LPVOID
*)&p
, &len
);
689 ok(ret
, "VerQueryValueW error %u\n", GetLastError());
690 ok(len
== 0, "VerQueryValueW returned %u, expected 0\n", len
);
692 ok(p
== preparedbuffer
+ 0x7e, "p was %p, expected %p\n", p
, preparedbuffer
+ 0x7e);
694 p
= (char *)0xdeadbeef;
696 SetLastError(0xdeadbeef);
697 ret
= VerQueryValueW(preparedbuffer
, FileDescriptionW
, (LPVOID
*)&p
, &len
);
698 ok(ret
, "VerQueryValueW error %u\n", GetLastError());
699 ok(len
== 0, "VerQueryValueW returned %u, expected 0\n", len
);
701 ok(p
== preparedbuffer
+ 0x7e, "p was %p, expected %p\n", p
, preparedbuffer
+ 0x7e);
704 static void test_extra_block(void)
706 WORD extra_block
[] = {
707 72, 0, 0, 'W', 'i', 'n', 'e', 'T', 'e', 's', 't', '\0',
708 24, 4, 0, 'B', 'i', 'n', 'a', 'r', 'y', '\0', 0xbeef, 0xdead,
709 24, 4, 1, 'T', 'e', 'x', 't', '\0', 'B', '-', ')', '\0',
717 ret
= GetModuleFileNameA(NULL
, buf
, sizeof(buf
));
718 ok(ret
, "GetModuleFileNameA failed\n");
720 len
= GetFileVersionInfoSizeA(buf
, NULL
);
721 ok(len
, "GetFileVersionInfoSizeA(%s) error %u\n", buf
, GetLastError());
723 ver
= HeapAlloc(GetProcessHeap(), 0, len
+ sizeof(extra_block
) * 2);
724 ok(ver
!= NULL
, "Can't allocate memory\n");
726 ret
= GetFileVersionInfoA(buf
, 0, len
, ver
);
727 ok(ret
, "GetFileVersionInfoA error %u\n", GetLastError());
729 /* forge the string table, as windres dislike an extra block */
730 length
= (WORD
*)ver
; /* see VS_VERSION_INFO_STRUCT32 for details */
731 memcpy(ver
+ *length
, extra_block
, sizeof(extra_block
));
732 *length
+= sizeof(extra_block
);
734 p
= (char *)0xdeadbeef;
737 ret
= VerQueryValueA(ver
, "WineTest\\Binary", (LPVOID
*)&p
, &len
);
738 ok(ret
, "VerQueryValue error %u\n", GetLastError());
739 ok(len
== 4, "VerQueryValue returned %u, expected 4\n", len
);
740 ok(p
!= (char *)0xdeadbeef, "not expected 0xdeadbeef\n");
741 ok(memcmp(p
, &w
, sizeof(w
)) == 0, "got 0x%08x, expected 0x%08x\n", *(PULONG
)p
, w
);
743 p
= (char *)0xdeadbeef;
745 ret
= VerQueryValueA(ver
, "WineTest\\Text", (LPVOID
*)&p
, &len
);
746 ok(ret
, "VerQueryValue error %u\n", GetLastError());
747 ok(len
== 4, "VerQueryValue returned %u, expected 4\n", len
);
748 ok(p
!= (char *)0xdeadbeef, "not expected 0xdeadbeef\n");
749 ok(strcmp(p
, "B-)") == 0, "got '%s', expected '%s'\n", p
, "B-)");
751 HeapFree(GetProcessHeap(), 0, ver
);
754 static void test_GetFileVersionInfoEx(void)
758 UINT size
, translation
, i
;
760 BOOL (WINAPI
*pGetFileVersionInfoExW
)(DWORD
, LPCWSTR
, DWORD
, DWORD
, LPVOID
);
761 DWORD (WINAPI
*pGetFileVersionInfoSizeExW
)(DWORD
, LPCWSTR
, LPDWORD
);
762 const LANGID lang
= GetUserDefaultUILanguage();
763 const LANGID english
= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
);
764 const WORD unicode
= 1200; /* = UNICODE */
765 const WCHAR kernel32W
[] = {'k','e','r','n','e','l','3','2','.','d','l','l',0};
766 const DWORD test_flags
[] = {
767 0, FILE_VER_GET_LOCALISED
, FILE_VER_GET_NEUTRAL
,
768 FILE_VER_GET_LOCALISED
| FILE_VER_GET_NEUTRAL
,
769 0xdeadbeef, /* invalid value (ignored) */
773 mod
= GetModuleHandleA("kernel32.dll");
776 if (!FindResourceExA(mod
, (LPCSTR
)RT_VERSION
, (LPCSTR
)VS_VERSION_INFO
, lang
) &&
777 !FindResourceExA(mod
, (LPCSTR
)RT_VERSION
, (LPCSTR
)VS_VERSION_INFO
,
778 MAKELANGID(PRIMARYLANGID(lang
),SUBLANG_NEUTRAL
)))
780 skip("Translation is not available\n");
784 size
= GetFileVersionInfoSizeW(kernel32W
, NULL
);
785 ok(size
, "GetFileVersionInfoSize(kernel32) error %u\n", GetLastError());
787 ver
= HeapAlloc(GetProcessHeap(), 0, size
);
790 ret
= GetFileVersionInfoW(kernel32W
, 0, size
, ver
);
791 ok(ret
, "GetFileVersionInfo error %u\n", GetLastError());
793 ret
= VerQueryValueA(ver
, "\\VarFileInfo\\Translation", (void **)&p
, &size
);
794 translation
= *(UINT
*)p
;
795 ok(ret
, "VerQueryValue error %u\n", GetLastError());
796 ok(size
== 4, "VerQueryValue returned %u, expected 4\n", size
);
798 /* test default version resource */
799 ok(LOWORD(translation
) == lang
, "got %u, expected lang is %u\n",
800 LOWORD(translation
), lang
);
801 ok(HIWORD(translation
) == unicode
, "got %u, expected codepage is %u\n",
802 HIWORD(translation
), unicode
);
804 HeapFree(GetProcessHeap(), 0, ver
);
806 mod
= GetModuleHandleA("version.dll");
809 /* prefer W-version as A-version is not available on Windows 7 */
810 pGetFileVersionInfoExW
= (void *)GetProcAddress(mod
, "GetFileVersionInfoExW");
811 pGetFileVersionInfoSizeExW
= (void *)GetProcAddress(mod
, "GetFileVersionInfoSizeExW");
812 if (!pGetFileVersionInfoExW
&& !pGetFileVersionInfoSizeExW
)
814 win_skip("GetFileVersionInfoEx family is not available\n");
818 for (i
= 0; i
< sizeof(test_flags
)/sizeof(test_flags
[0]); i
++)
820 size
= pGetFileVersionInfoSizeExW(test_flags
[i
], kernel32W
, NULL
);
821 ok(size
, "[%u] GetFileVersionInfoSizeEx(kernel32) error %u\n", i
, GetLastError());
823 ver
= HeapAlloc(GetProcessHeap(), 0, size
);
826 ret
= pGetFileVersionInfoExW(test_flags
[i
], kernel32W
, 0, size
, ver
);
827 ok(ret
, "[%u] GetFileVersionInfoEx error %u\n", i
, GetLastError());
829 ret
= VerQueryValueA(ver
, "\\VarFileInfo\\Translation", (void **)&p
, &size
);
830 ok(ret
, "[%u] VerQueryValue error %u\n", i
, GetLastError());
831 ok(size
== 4, "[%u] VerQueryValue returned %u, expected 4\n", i
, size
);
832 translation
= *(UINT
*)p
;
834 /* test MUI version resource */
835 if (test_flags
[i
] & FILE_VER_GET_LOCALISED
)
836 ok(LOWORD(translation
) == lang
, "[%u] got %u, expected lang is %u\n",
837 i
, LOWORD(translation
), lang
);
839 ok(LOWORD(translation
) == english
, "[%u] got %u, expected lang is %u\n",
840 i
, LOWORD(translation
), english
);
841 ok(HIWORD(translation
) == unicode
, "[%u] got %u, expected codepage is %u\n",
842 i
, HIWORD(translation
), unicode
);
844 /* test string info using translation info */
846 sprintf(desc
, "\\StringFileInfo\\%04x%04x\\FileDescription",
847 LOWORD(translation
), HIWORD(translation
));
848 ret
= VerQueryValueA(ver
, desc
, (void **)&p
, &size
);
849 ok(ret
, "[%u] VerQueryValue error %u\n", i
, GetLastError());
850 ok(size
== strlen(p
) + 1, "[%u] VerQueryValue returned %u\n", i
, size
);
852 HeapFree(GetProcessHeap(), 0, ver
);
863 test_VerQueryValueA();
864 test_VerQueryValue_InvalidLength();
866 test_GetFileVersionInfoEx();