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
];
295 const char varfileinfoA
[] = "\\VarFileInfo\\Translation";
296 const WCHAR varfileinfoW
[] = L
"\\VarFileInfo\\Translation";
297 const char WineVarFileInfoA
[] = { 0x09, 0x04, 0xE4, 0x04 };
298 const char FileDescriptionA
[] = "\\StringFileInfo\\040904E4\\FileDescription";
299 const WCHAR FileDescriptionW
[] = L
"\\StringFileInfo\\040904E4\\FileDescription";
300 const char WineFileDescriptionA
[] = "FileDescription";
301 const WCHAR WineFileDescriptionW
[] = L
"FileDescription";
302 BOOL is_unicode_enabled
= TRUE
;
304 /* A copy from dlls/version/info.c */
311 #if 0 /* variable length structure */
315 VS_VERSION_INFO_STRUCT32 Children
[];
317 } VS_VERSION_INFO_STRUCT32
;
319 /* If we call GetFileVersionInfoA on a system that supports Unicode, NT/W2K/XP/W2K3 (by default) and Wine,
320 * the versioninfo will contain Unicode strings.
321 * Part of the test is to call both the A and W versions, which should have the same Version Information
322 * for some requests, on systems that support both calls.
325 /* First get the versioninfo via the W versions */
326 SetLastError(0xdeadbeef);
327 GetModuleFileNameW(NULL
, mypathW
, MAX_PATH
);
328 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
330 win_skip("GetModuleFileNameW not existing on this platform, skipping comparison between A- and W-calls\n");
331 is_unicode_enabled
= FALSE
;
334 if (is_unicode_enabled
)
336 retvalW
= GetFileVersionInfoSizeW( mypathW
, &hdlW
);
337 pVersionInfoW
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, retvalW
);
338 retW
= GetFileVersionInfoW( mypathW
, 0, retvalW
, pVersionInfoW
);
339 ok(retW
, "GetFileVersionInfo failed: GetLastError = %u\n", GetLastError());
342 GetModuleFileNameA(NULL
, mypathA
, MAX_PATH
);
343 retvalA
= GetFileVersionInfoSizeA( mypathA
, &hdlA
);
344 pVersionInfoA
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, retvalA
);
345 retA
= GetFileVersionInfoA( mypathA
, 0, retvalA
, pVersionInfoA
);
346 ok(retA
, "GetFileVersionInfo failed: GetLastError = %u\n", GetLastError());
348 if (is_unicode_enabled
)
350 ok( retvalA
== retvalW
, "The size of the struct should be the same for both A/W calls, it is (%d) vs. (%d)\n",
352 ok( !memcmp(pVersionInfoA
, pVersionInfoW
, retvalA
), "Both structs should be the same, they aren't\n");
355 /* The structs on Windows are bigger than just the struct for the basic information. The total struct
356 * contains also an empty part, which is used for converted strings. The converted strings are a result
357 * of calling VerQueryValueA on a 32bit resource and calling VerQueryValueW on a 16bit resource.
358 * The first WORD of the structure (wLength) shows the size of the base struct. The total struct size depends
359 * on the Windows version:
361 * 16bits resource (numbers are from a sample app):
363 * Windows Version Retrieved with A/W wLength StructSize
364 * ====================================================================================
365 * Win98 A 0x01B4 (436) 436
366 * NT4 A/W 0x01B4 (436) 2048 ???
367 * W2K/XP/W2K3 A/W 0x01B4 (436) 1536 which is (436 - sizeof(VS_FIXEDFILEINFO)) * 4
369 * 32bits resource (numbers are from this test executable version_crosstest.exe):
370 * Windows Version Retrieved with A/W wLength StructSize
371 * =============================================================
372 * Win98 A 0x01E0 (480) 848 (structure data doesn't seem correct)
373 * NT4 A/W 0x0350 (848) 1272 (848 * 1.5)
374 * W2K/XP/W2K3 A/W 0x0350 (848) 1700 which is (848 * 2) + 4
376 * Wine will follow the implementation (eventually) of W2K/XP/W2K3
379 /* Now some tests for the above (only if we are unicode enabled) */
381 if (is_unicode_enabled
)
383 VS_VERSION_INFO_STRUCT32
*vvis
= pVersionInfoW
;
384 ok ( retvalW
== ((vvis
->wLength
* 2) + 4) || retvalW
== (vvis
->wLength
* 1.5),
385 "Structure is not of the correct size\n");
388 /* Although the 32bit resource structures contain Unicode strings, VerQueryValueA will always return normal strings,
389 * VerQueryValueW will always return Unicode ones. (That means everything returned for StringFileInfo requests).
392 /* Get the VS_FIXEDFILEINFO information, this must be the same for both A- and W-Calls */
394 retA
= VerQueryValueA( pVersionInfoA
, "\\", (void **)&pBufA
, &uiLengthA
);
395 ok (retA
, "VerQueryValueA failed: GetLastError = %u\n", GetLastError());
396 ok ( uiLengthA
== sizeof(VS_FIXEDFILEINFO
), "Size (%d) doesn't match the size of the VS_FIXEDFILEINFO struct\n", uiLengthA
);
398 if (is_unicode_enabled
)
401 { /* This causes Vista and w2k8 to crash */
402 retW
= VerQueryValueW( pVersionInfoW
, NULL
, (LPVOID
*)&pBufW
, &uiLengthW
);
403 ok (retW
, "VerQueryValueW failed: GetLastError = %u\n", GetLastError());
406 retW
= VerQueryValueW( pVersionInfoW
, L
"", (void **)&pBufW
, &uiLengthW
);
407 ok (retW
, "VerQueryValueW failed: GetLastError = %u\n", GetLastError());
409 retW
= VerQueryValueW( pVersionInfoW
, L
"\\", (void **)&pBufW
, &uiLengthW
);
410 ok (retW
, "VerQueryValueW failed: GetLastError = %u\n", GetLastError());
411 ok ( uiLengthW
== sizeof(VS_FIXEDFILEINFO
), "Size (%d) doesn't match the size of the VS_FIXEDFILEINFO struct\n", uiLengthW
);
413 ok( uiLengthA
== uiLengthW
, "The size of VS_FIXEDFILEINFO should be the same for both A/W calls, it is (%d) vs. (%d)\n",
414 uiLengthA
, uiLengthW
);
415 ok( !memcmp(pBufA
, pBufW
, uiLengthA
), "Both values should be the same, they aren't\n");
418 /* Get some VarFileInfo information, this must be the same for both A- and W-Calls */
420 retA
= VerQueryValueA( pVersionInfoA
, varfileinfoA
, (LPVOID
*)&pBufA
, &uiLengthA
);
421 ok (retA
, "VerQueryValueA failed: GetLastError = %u\n", GetLastError());
422 ok( !memcmp(pBufA
, WineVarFileInfoA
, uiLengthA
), "The VarFileInfo should have matched 0904e404 (non case sensitive)\n");
424 if (is_unicode_enabled
)
426 retW
= VerQueryValueW( pVersionInfoW
, varfileinfoW
, (LPVOID
*)&pBufW
, &uiLengthW
);
427 ok (retW
, "VerQueryValueW failed: GetLastError = %u\n", GetLastError());
428 ok( uiLengthA
== uiLengthW
, "The size of the VarFileInfo information should be the same for both A/W calls, it is (%d) vs. (%d)\n",
429 uiLengthA
, uiLengthW
);
430 ok( !memcmp(pBufA
, pBufW
, uiLengthA
), "Both values should be the same, they aren't\n");
433 /* Get some StringFileInfo information, this will be ANSI for A-Calls and Unicode for W-Calls */
435 retA
= VerQueryValueA( pVersionInfoA
, FileDescriptionA
, (LPVOID
*)&pBufA
, &uiLengthA
);
436 ok (retA
, "VerQueryValueA failed: GetLastError = %u\n", GetLastError());
437 ok( !lstrcmpA(WineFileDescriptionA
, pBufA
), "expected '%s' got '%s'\n",
438 WineFileDescriptionA
, pBufA
);
440 /* Test a second time */
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 if (is_unicode_enabled
)
448 retW
= VerQueryValueW( pVersionInfoW
, FileDescriptionW
, (LPVOID
*)&pBufW
, &uiLengthW
);
449 ok (retW
, "VerQueryValueW failed: GetLastError = %u\n", GetLastError());
450 ok( !lstrcmpW(WineFileDescriptionW
, pBufW
), "FileDescription should have been '%s'\n", WineFileDescriptionA
);
453 HeapFree( GetProcessHeap(), 0, pVersionInfoA
);
454 if (is_unicode_enabled
)
455 HeapFree( GetProcessHeap(), 0, pVersionInfoW
);
458 static void test_VerQueryValueA(void)
460 static const char * const value_name
[] = {
461 "Product", "CompanyName", "FileDescription", "Internal",
462 "ProductVersion", "InternalName", "File", "LegalCopyright",
463 "FileVersion", "Legal", "OriginalFilename", "ProductName",
464 "Company", "Original" };
466 UINT len
, ret
, translation
, i
;
469 ret
= GetModuleFileNameA(NULL
, buf
, sizeof(buf
));
472 SetLastError(0xdeadbeef);
473 len
= GetFileVersionInfoSizeA(buf
, NULL
);
474 ok(len
, "GetFileVersionInfoSizeA(%s) error %u\n", buf
, GetLastError());
476 ver
= HeapAlloc(GetProcessHeap(), 0, len
);
479 SetLastError(0xdeadbeef);
480 ret
= GetFileVersionInfoA(buf
, 0, len
, ver
);
481 ok(ret
, "GetFileVersionInfoA error %u\n", GetLastError());
483 p
= (char *)0xdeadbeef;
485 SetLastError(0xdeadbeef);
486 ret
= VerQueryValueA(ver
, "\\VarFileInfo\\Translation", (LPVOID
*)&p
, &len
);
487 ok(ret
, "VerQueryValue error %u\n", GetLastError());
488 ok(len
== 4, "VerQueryValue returned %u, expected 4\n", len
);
490 translation
= *(UINT
*)p
;
491 translation
= MAKELONG(HIWORD(translation
), LOWORD(translation
));
493 p
= (char *)0xdeadbeef;
495 SetLastError(0xdeadbeef);
496 ret
= VerQueryValueA(ver
, "String", (LPVOID
*)&p
, &len
);
497 ok(!ret
, "VerQueryValue should fail\n");
498 ok(GetLastError() == ERROR_RESOURCE_TYPE_NOT_FOUND
||
499 GetLastError() == 0xdeadbeef /* NT4, W2K */,
500 "VerQueryValue returned %u\n", GetLastError());
501 ok(p
== (char *)0xdeadbeef, "expected 0xdeadbeef got %p\n", p
);
502 ok(len
== 0, "expected 0 got %x\n", len
);
504 p
= (char *)0xdeadbeef;
506 SetLastError(0xdeadbeef);
507 ret
= VerQueryValueA(ver
, "StringFileInfo", (LPVOID
*)&p
, &len
);
508 ok(ret
, "VerQueryValue error %u\n", GetLastError());
509 ok(len
== 0, "VerQueryValue returned %u, expected 0\n", len
);
510 ok(p
!= (char *)0xdeadbeef, "not expected 0xdeadbeef\n");
512 p
= (char *)0xdeadbeef;
514 SetLastError(0xdeadbeef);
515 ret
= VerQueryValueA(ver
, "\\StringFileInfo", (LPVOID
*)&p
, &len
);
516 ok(ret
, "VerQueryValue error %u\n", GetLastError());
517 ok(len
== 0, "VerQueryValue returned %u, expected 0\n", len
);
518 ok(p
!= (char *)0xdeadbeef, "not expected 0xdeadbeef\n");
520 p
= (char *)0xdeadbeef;
522 SetLastError(0xdeadbeef);
523 ret
= VerQueryValueA(ver
, "\\\\StringFileInfo", (LPVOID
*)&p
, &len
);
524 ok(ret
, "VerQueryValue error %u\n", GetLastError());
525 ok(len
== 0, "VerQueryValue returned %u, expected 0\n", len
);
526 ok(p
!= (char *)0xdeadbeef, "not expected 0xdeadbeef\n");
528 p
= (char *)0xdeadbeef;
530 SetLastError(0xdeadbeef);
531 ret
= VerQueryValueA(ver
, "\\StringFileInfo\\\\", (LPVOID
*)&p
, &len
);
532 ok(ret
, "VerQueryValue error %u\n", GetLastError());
533 ok(len
== 0, "VerQueryValue returned %u, expected 0\n", len
);
534 ok(p
!= (char *)0xdeadbeef, "not expected 0xdeadbeef\n");
536 sprintf(buf
, "\\StringFileInfo\\%08x", translation
);
537 p
= (char *)0xdeadbeef;
539 SetLastError(0xdeadbeef);
540 ret
= VerQueryValueA(ver
, buf
, (LPVOID
*)&p
, &len
);
541 ok(ret
, "VerQueryValue error %u\n", GetLastError());
542 ok(len
== 0, "VerQueryValue returned %u, expected 0\n", len
);
543 ok(p
!= (char *)0xdeadbeef, "not expected 0xdeadbeef\n");
545 for (i
= 0; i
< ARRAY_SIZE(value_name
); i
++)
547 sprintf(buf
, "\\StringFileInfo\\%08x\\%s", translation
, value_name
[i
]);
548 p
= (char *)0xdeadbeef;
550 SetLastError(0xdeadbeef);
551 ret
= VerQueryValueA(ver
, buf
, (LPVOID
*)&p
, &len
);
552 ok(ret
, "VerQueryValueA(%s) error %u\n", buf
, GetLastError());
553 ok(len
== strlen(value_name
[i
]) + 1, "VerQueryValue returned %u\n", len
);
554 ok(!strcmp(value_name
[i
], p
), "expected \"%s\", got \"%s\"\n",
557 /* test partial value names */
560 p
= (char *)0xdeadbeef;
562 SetLastError(0xdeadbeef);
563 ret
= VerQueryValueA(ver
, buf
, (LPVOID
*)&p
, &len
);
564 ok(!ret
, "VerQueryValueA(%s) succeeded\n", buf
);
565 ok(GetLastError() == ERROR_RESOURCE_TYPE_NOT_FOUND
||
566 GetLastError() == 0xdeadbeef /* NT4, W2K */,
567 "VerQueryValue returned %u\n", GetLastError());
568 ok(p
== (char *)0xdeadbeef, "expected 0xdeadbeef got %p\n", p
);
569 ok(len
== 0, "expected 0 or 0xbeef, got %x\n", len
);
572 HeapFree(GetProcessHeap(), 0, ver
);
575 static void test_extra_block(void)
577 WORD extra_block
[] = {
578 72, 0, 0, 'W', 'i', 'n', 'e', 'T', 'e', 's', 't', '\0',
579 24, 4, 0, 'B', 'i', 'n', 'a', 'r', 'y', '\0', 0xbeef, 0xdead,
580 24, 4, 1, 'T', 'e', 'x', 't', '\0', 'B', '-', ')', '\0',
588 ret
= GetModuleFileNameA(NULL
, buf
, sizeof(buf
));
589 ok(ret
, "GetModuleFileNameA failed\n");
591 len
= GetFileVersionInfoSizeA(buf
, NULL
);
592 ok(len
, "GetFileVersionInfoSizeA(%s) error %u\n", buf
, GetLastError());
594 ver
= HeapAlloc(GetProcessHeap(), 0, len
+ sizeof(extra_block
) * 2);
595 ok(ver
!= NULL
, "Can't allocate memory\n");
597 ret
= GetFileVersionInfoA(buf
, 0, len
, ver
);
598 ok(ret
, "GetFileVersionInfoA error %u\n", GetLastError());
600 /* forge the string table, as windres dislike an extra block */
601 length
= (WORD
*)ver
; /* see VS_VERSION_INFO_STRUCT32 for details */
602 memcpy(ver
+ *length
, extra_block
, sizeof(extra_block
));
603 *length
+= sizeof(extra_block
);
605 p
= (char *)0xdeadbeef;
608 ret
= VerQueryValueA(ver
, "WineTest\\Binary", (LPVOID
*)&p
, &len
);
609 ok(ret
, "VerQueryValue error %u\n", GetLastError());
610 ok(len
== 4, "VerQueryValue returned %u, expected 4\n", len
);
611 ok(p
!= (char *)0xdeadbeef, "not expected 0xdeadbeef\n");
612 ok(memcmp(p
, &w
, sizeof(w
)) == 0, "got 0x%08x, expected 0x%08x\n", *(PULONG
)p
, w
);
614 p
= (char *)0xdeadbeef;
616 ret
= VerQueryValueA(ver
, "WineTest\\Text", (LPVOID
*)&p
, &len
);
617 ok(ret
, "VerQueryValue error %u\n", GetLastError());
618 ok(len
== 4, "VerQueryValue returned %u, expected 4\n", len
);
619 ok(p
!= (char *)0xdeadbeef, "not expected 0xdeadbeef\n");
620 ok(strcmp(p
, "B-)") == 0, "got '%s', expected '%s'\n", p
, "B-)");
622 HeapFree(GetProcessHeap(), 0, ver
);
625 static void test_GetFileVersionInfoEx(void)
629 UINT size
, translation
, i
;
631 BOOL (WINAPI
*pGetFileVersionInfoExW
)(DWORD
, LPCWSTR
, DWORD
, DWORD
, LPVOID
);
632 DWORD (WINAPI
*pGetFileVersionInfoSizeExW
)(DWORD
, LPCWSTR
, LPDWORD
);
633 const LANGID lang
= GetUserDefaultUILanguage();
634 const LANGID english
= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
);
635 const WORD unicode
= 1200; /* = UNICODE */
636 const DWORD test_flags
[] = {
637 0, FILE_VER_GET_LOCALISED
, FILE_VER_GET_NEUTRAL
,
638 FILE_VER_GET_LOCALISED
| FILE_VER_GET_NEUTRAL
,
639 0xdeadbeef, /* invalid value (ignored) */
643 mod
= GetModuleHandleA("kernel32.dll");
646 if (!FindResourceExA(mod
, (LPCSTR
)RT_VERSION
, (LPCSTR
)VS_VERSION_INFO
, lang
) &&
647 !FindResourceExA(mod
, (LPCSTR
)RT_VERSION
, (LPCSTR
)VS_VERSION_INFO
,
648 MAKELANGID(PRIMARYLANGID(lang
),SUBLANG_NEUTRAL
)))
650 skip("Translation is not available\n");
654 size
= GetFileVersionInfoSizeW(L
"kernel32.dll", NULL
);
655 ok(size
, "GetFileVersionInfoSize(kernel32) error %u\n", GetLastError());
657 ver
= HeapAlloc(GetProcessHeap(), 0, size
);
660 ret
= GetFileVersionInfoW(L
"kernel32.dll", 0, size
, ver
);
661 ok(ret
, "GetFileVersionInfo error %u\n", GetLastError());
663 ret
= VerQueryValueA(ver
, "\\VarFileInfo\\Translation", (void **)&p
, &size
);
664 translation
= *(UINT
*)p
;
665 ok(ret
, "VerQueryValue error %u\n", GetLastError());
666 ok(size
== 4, "VerQueryValue returned %u, expected 4\n", size
);
668 /* test default version resource */
669 ok(LOWORD(translation
) == lang
, "got %u, expected lang is %u\n",
670 LOWORD(translation
), lang
);
671 ok(HIWORD(translation
) == unicode
, "got %u, expected codepage is %u\n",
672 HIWORD(translation
), unicode
);
674 HeapFree(GetProcessHeap(), 0, ver
);
676 mod
= GetModuleHandleA("version.dll");
679 /* prefer W-version as A-version is not available on Windows 7 */
680 pGetFileVersionInfoExW
= (void *)GetProcAddress(mod
, "GetFileVersionInfoExW");
681 pGetFileVersionInfoSizeExW
= (void *)GetProcAddress(mod
, "GetFileVersionInfoSizeExW");
682 if (!pGetFileVersionInfoExW
&& !pGetFileVersionInfoSizeExW
)
684 win_skip("GetFileVersionInfoEx family is not available\n");
688 for (i
= 0; i
< ARRAY_SIZE(test_flags
); i
++)
690 size
= pGetFileVersionInfoSizeExW(test_flags
[i
], L
"kernel32.dll", NULL
);
691 ok(size
, "[%u] GetFileVersionInfoSizeEx(kernel32) error %u\n", i
, GetLastError());
693 ver
= HeapAlloc(GetProcessHeap(), 0, size
);
696 ret
= pGetFileVersionInfoExW(test_flags
[i
], L
"kernel32.dll", 0, size
, ver
);
697 ok(ret
, "[%u] GetFileVersionInfoEx error %u\n", i
, GetLastError());
699 ret
= VerQueryValueA(ver
, "\\VarFileInfo\\Translation", (void **)&p
, &size
);
700 ok(ret
, "[%u] VerQueryValue error %u\n", i
, GetLastError());
701 ok(size
== 4, "[%u] VerQueryValue returned %u, expected 4\n", i
, size
);
702 translation
= *(UINT
*)p
;
704 /* test MUI version resource */
705 if (test_flags
[i
] & FILE_VER_GET_LOCALISED
)
706 ok(LOWORD(translation
) == lang
, "[%u] got %u, expected lang is %u\n",
707 i
, LOWORD(translation
), lang
);
709 ok(LOWORD(translation
) == english
, "[%u] got %u, expected lang is %u\n",
710 i
, LOWORD(translation
), english
);
711 ok(HIWORD(translation
) == unicode
, "[%u] got %u, expected codepage is %u\n",
712 i
, HIWORD(translation
), unicode
);
714 /* test string info using translation info */
716 sprintf(desc
, "\\StringFileInfo\\%04x%04x\\FileDescription",
717 LOWORD(translation
), HIWORD(translation
));
718 ret
= VerQueryValueA(ver
, desc
, (void **)&p
, &size
);
719 ok(ret
, "[%u] VerQueryValue error %u\n", i
, GetLastError());
720 ok(size
== strlen(p
) + 1, "[%u] VerQueryValue returned %u\n", i
, size
);
722 HeapFree(GetProcessHeap(), 0, ver
);
733 test_VerQueryValueA();
735 test_GetFileVersionInfoEx();