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
30 #include "wine/test.h"
32 #define MY_LAST_ERROR ((DWORD)-1)
33 #define EXPECT_BAD_PATH__NOT_FOUND \
34 ok( (ERROR_PATH_NOT_FOUND == GetLastError()) || \
35 (ERROR_RESOURCE_DATA_NOT_FOUND == GetLastError()) || \
36 (ERROR_FILE_NOT_FOUND == GetLastError()) || \
37 (ERROR_BAD_PATHNAME == GetLastError()) || \
38 (ERROR_SUCCESS == GetLastError()), \
39 "Last error wrong! ERROR_RESOURCE_DATA_NOT_FOUND/ERROR_BAD_PATHNAME (98)/" \
40 "ERROR_PATH_NOT_FOUND (NT4)/ERROR_FILE_NOT_FOUND (2k3) " \
41 "ERROR_SUCCESS (2k) expected, got %u\n", GetLastError());
42 #define EXPECT_INVALID__NOT_FOUND \
43 ok( (ERROR_PATH_NOT_FOUND == GetLastError()) || \
44 (ERROR_RESOURCE_DATA_NOT_FOUND == GetLastError()) || \
45 (ERROR_FILE_NOT_FOUND == GetLastError()) || \
46 (ERROR_INVALID_PARAMETER == GetLastError()) || \
47 (ERROR_SUCCESS == GetLastError()), \
48 "Last error wrong! ERROR_RESOURCE_DATA_NOT_FOUND/ERROR_INVALID_PARAMETER (98)/" \
49 "ERROR_PATH_NOT_FOUND (NT4)/ERROR_FILE_NOT_FOUND (2k3) " \
50 "ERROR_SUCCESS (2k) expected, got %u\n", GetLastError());
52 static void create_file(const CHAR
*name
)
57 file
= CreateFileA(name
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, NULL
);
58 ok(file
!= INVALID_HANDLE_VALUE
, "Failure to open file %s\n", name
);
59 WriteFile(file
, name
, strlen(name
), &written
, NULL
);
60 WriteFile(file
, "\n", strlen("\n"), &written
, NULL
);
64 static void test_info_size(void)
66 char mypath
[MAX_PATH
] = "";
68 SetLastError(MY_LAST_ERROR
);
69 retval
= GetFileVersionInfoSizeA( NULL
, NULL
);
71 "GetFileVersionInfoSizeA result wrong! 0L expected, got 0x%08x\n",
73 EXPECT_INVALID__NOT_FOUND
;
76 SetLastError(MY_LAST_ERROR
);
77 retval
= GetFileVersionInfoSizeA( NULL
, &hdl
);
79 "GetFileVersionInfoSizeA result wrong! 0L expected, got 0x%08x\n",
81 EXPECT_INVALID__NOT_FOUND
;
83 "Handle wrong! 0L expected, got 0x%08x\n", hdl
);
85 SetLastError(MY_LAST_ERROR
);
86 retval
= GetFileVersionInfoSizeA( "", NULL
);
88 "GetFileVersionInfoSizeA result wrong! 0L expected, got 0x%08x\n",
90 EXPECT_BAD_PATH__NOT_FOUND
;
93 SetLastError(MY_LAST_ERROR
);
94 retval
= GetFileVersionInfoSizeA( "", &hdl
);
96 "GetFileVersionInfoSizeA result wrong! 0L expected, got 0x%08x\n",
98 EXPECT_BAD_PATH__NOT_FOUND
;
100 "Handle wrong! 0L expected, got 0x%08x\n", hdl
);
102 SetLastError(MY_LAST_ERROR
);
103 retval
= GetFileVersionInfoSizeA( "kernel32.dll", NULL
);
105 "GetFileVersionInfoSizeA result wrong! <> 0L expected, got 0x%08x\n",
107 ok((NO_ERROR
== GetLastError()) || (MY_LAST_ERROR
== GetLastError()),
108 "Last error wrong! NO_ERROR/0x%08x (NT4) expected, got %u\n",
109 MY_LAST_ERROR
, GetLastError());
112 SetLastError(MY_LAST_ERROR
);
113 retval
= GetFileVersionInfoSizeA( "kernel32.dll", &hdl
);
115 "GetFileVersionInfoSizeA result wrong! <> 0L expected, got 0x%08x\n",
117 ok((NO_ERROR
== GetLastError()) || (MY_LAST_ERROR
== GetLastError()),
118 "Last error wrong! NO_ERROR/0x%08x (NT4) expected, got %u\n",
119 MY_LAST_ERROR
, GetLastError());
121 "Handle wrong! 0L expected, got 0x%08x\n", hdl
);
123 SetLastError(MY_LAST_ERROR
);
124 retval
= GetFileVersionInfoSizeA( "notexist.dll", NULL
);
126 "GetFileVersionInfoSizeA result wrong! 0L expected, got 0x%08x\n",
128 ok( (ERROR_FILE_NOT_FOUND
== GetLastError()) ||
129 (ERROR_RESOURCE_DATA_NOT_FOUND
== GetLastError()) ||
130 (MY_LAST_ERROR
== GetLastError()) ||
131 (ERROR_SUCCESS
== GetLastError()), /* win2k */
132 "Last error wrong! ERROR_FILE_NOT_FOUND/ERROR_RESOURCE_DATA_NOT_FOUND "
133 "(XP)/0x%08x (NT4) expected, got %u\n", MY_LAST_ERROR
, GetLastError());
135 /* test a currently loaded executable */
136 if(GetModuleFileNameA(NULL
, mypath
, MAX_PATH
)) {
138 SetLastError(MY_LAST_ERROR
);
139 retval
= GetFileVersionInfoSizeA( mypath
, &hdl
);
141 "GetFileVersionInfoSizeA result wrong! <> 0L expected, got 0x%08x\n",
143 ok((NO_ERROR
== GetLastError()) || (MY_LAST_ERROR
== GetLastError()),
144 "Last error wrong! NO_ERROR/0x%08x (NT4) expected, got %u\n",
145 MY_LAST_ERROR
, GetLastError());
147 "Handle wrong! 0L expected, got 0x%08x\n", hdl
);
150 trace("skipping GetModuleFileNameA(NULL,..) failed\n");
152 /* test a not loaded executable */
153 if(GetSystemDirectoryA(mypath
, MAX_PATH
)) {
154 lstrcatA(mypath
, "\\regsvr32.exe");
156 if(INVALID_FILE_ATTRIBUTES
== GetFileAttributesA(mypath
))
157 trace("GetFileAttributesA(%s) failed\n", mypath
);
160 SetLastError(MY_LAST_ERROR
);
161 retval
= GetFileVersionInfoSizeA( mypath
, &hdl
);
163 "GetFileVersionInfoSizeA result wrong! <> 0L expected, got 0x%08x\n",
165 ok((NO_ERROR
== GetLastError()) || (MY_LAST_ERROR
== GetLastError()),
166 "Last error wrong! NO_ERROR/0x%08x (NT4) expected, got %u\n",
167 MY_LAST_ERROR
, GetLastError());
169 "Handle wrong! 0L expected, got 0x%08x\n", hdl
);
173 trace("skipping GetSystemDirectoryA(mypath,..) failed\n");
175 create_file("test.txt");
177 /* no version info */
178 SetLastError(0xdeadbeef);
180 retval
= GetFileVersionInfoSizeA("test.txt", &hdl
);
181 ok(retval
== 0, "Expected 0, got %d\n", retval
);
182 ok(hdl
== 0, "Expected 0, got %d\n", hdl
);
183 ok(GetLastError() == ERROR_RESOURCE_DATA_NOT_FOUND
||
184 GetLastError() == ERROR_SUCCESS
, /* win2k */
185 "Expected ERROR_RESOURCE_DATA_NOT_FOUND, got %d\n", GetLastError());
187 DeleteFileA("test.txt");
190 static void VersionDwordLong2String(DWORDLONG Version
, LPSTR lpszVerString
)
194 a
= (WORD
)(Version
>> 48);
195 b
= (WORD
)((Version
>> 32) & 0xffff);
196 c
= (WORD
)((Version
>> 16) & 0xffff);
197 d
= (WORD
)(Version
& 0xffff);
199 sprintf(lpszVerString
, "%d.%d.%d.%d", a
, b
, c
, d
);
202 static void test_info(void)
205 PVOID pVersionInfo
= NULL
;
207 VS_FIXEDFILEINFO
*pFixedVersionInfo
;
209 char VersionString
[MAX_PATH
];
210 static const char backslash
[] = "\\";
211 DWORDLONG dwlVersion
;
214 SetLastError(MY_LAST_ERROR
);
215 retval
= GetFileVersionInfoSizeA( "kernel32.dll", &hdl
);
217 "GetFileVersionInfoSizeA result wrong! <> 0L expected, got 0x%08x\n",
219 ok((NO_ERROR
== GetLastError()) || (MY_LAST_ERROR
== GetLastError()),
220 "Last error wrong! NO_ERROR/0x%08x (NT4) expected, got %u\n",
221 MY_LAST_ERROR
, GetLastError());
223 "Handle wrong! 0L expected, got 0x%08x\n", hdl
);
225 if ( retval
== 0 || hdl
!= 0)
228 pVersionInfo
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, retval
);
229 ok(pVersionInfo
!= 0, "HeapAlloc failed\n" );
230 if (pVersionInfo
== 0)
235 /* this test crashes on WinNT4
237 boolret
= GetFileVersionInfoA( "kernel32.dll", 0, retval
, 0);
238 ok (!boolret
, "GetFileVersionInfoA should have failed: GetLastError = %u\n", GetLastError());
239 ok ((GetLastError() == ERROR_INVALID_DATA
) || (GetLastError() == ERROR_BAD_PATHNAME
) ||
240 (GetLastError() == NO_ERROR
),
241 "Last error wrong! ERROR_INVALID_DATA/ERROR_BAD_PATHNAME (ME)/"
242 "NO_ERROR (95) expected, got %u\n",
246 boolret
= GetFileVersionInfoA( "kernel32.dll", 0, retval
, pVersionInfo
);
247 ok (boolret
, "GetFileVersionInfoA failed: GetLastError = %u\n", GetLastError());
251 boolret
= VerQueryValueA( pVersionInfo
, NULL
, (LPVOID
*)&pFixedVersionInfo
, &uiLength
);
252 ok (boolret
|| GetLastError() == NO_ERROR
/* Win98 */,
253 "VerQueryValueA failed: GetLastError = %u\n", GetLastError());
255 boolret
= VerQueryValueA( pVersionInfo
, "", (LPVOID
*)&pFixedVersionInfo
, &uiLength
);
256 ok (boolret
, "VerQueryValueA failed: GetLastError = %u\n", GetLastError());
258 boolret
= VerQueryValueA( pVersionInfo
, backslash
, (LPVOID
*)&pFixedVersionInfo
, &uiLength
);
259 ok (boolret
, "VerQueryValueA failed: GetLastError = %u\n", GetLastError());
263 dwlVersion
= (((DWORDLONG
)pFixedVersionInfo
->dwFileVersionMS
) << 32) +
264 pFixedVersionInfo
->dwFileVersionLS
;
266 VersionDwordLong2String(dwlVersion
, VersionString
);
268 trace("kernel32.dll version: %s\n", VersionString
);
272 /* this test crashes on WinNT4
274 boolret
= VerQueryValueA( pVersionInfo
, backslash
, (LPVOID
*)&pFixedVersionInfo
, 0);
275 ok (boolret
, "VerQueryValue failed: GetLastError = %u\n", GetLastError());
279 HeapFree( GetProcessHeap(), 0, pVersionInfo
);
282 static void test_32bit_win(void)
285 DWORD hdlW
, retvalW
= 0;
287 PVOID pVersionInfoA
= NULL
;
288 PVOID pVersionInfoW
= NULL
;
291 UINT uiLengthA
, uiLengthW
;
292 char mypathA
[MAX_PATH
];
293 WCHAR mypathW
[MAX_PATH
];
295 WCHAR rootW
[] = { '\\', 0 };
296 WCHAR emptyW
[] = { 0 };
297 char varfileinfoA
[] = "\\VarFileInfo\\Translation";
298 WCHAR varfileinfoW
[] = { '\\','V','a','r','F','i','l','e','I','n','f','o',
299 '\\','T','r','a','n','s','l','a','t','i','o','n', 0 };
300 char WineVarFileInfoA
[] = { 0x09, 0x04, 0xE4, 0x04 };
301 char FileDescriptionA
[] = "\\StringFileInfo\\040904E4\\FileDescription";
302 WCHAR FileDescriptionW
[] = { '\\','S','t','r','i','n','g','F','i','l','e','I','n','f','o',
303 '\\','0','4','0','9','0','4','E','4',
304 '\\','F','i','l','e','D','e','s','c','r','i','p','t','i','o','n', 0 };
305 char WineFileDescriptionA
[] = "FileDescription";
306 WCHAR WineFileDescriptionW
[] = { 'F','i','l','e','D','e','s','c','r','i','p','t','i','o','n', 0 };
307 BOOL is_unicode_enabled
= TRUE
;
309 /* A copy from dlls/version/info.c */
316 #if 0 /* variable length structure */
320 VS_VERSION_INFO_STRUCT32 Children
[];
322 } VS_VERSION_INFO_STRUCT32
;
324 /* If we call GetFileVersionInfoA on a system that supports Unicode, NT/W2K/XP/W2K3 (by default) and Wine,
325 * the versioninfo will contain Unicode strings.
326 * Part of the test is to call both the A and W versions, which should have the same Version Information
327 * for some requests, on systems that support both calls.
330 /* First get the versioninfo via the W versions */
331 SetLastError(0xdeadbeef);
332 GetModuleFileNameW(NULL
, mypathW
, MAX_PATH
);
333 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
335 win_skip("GetModuleFileNameW not existing on this platform, skipping comparison between A- and W-calls\n");
336 is_unicode_enabled
= FALSE
;
339 if (is_unicode_enabled
)
341 retvalW
= GetFileVersionInfoSizeW( mypathW
, &hdlW
);
342 pVersionInfoW
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, retvalW
);
343 retW
= GetFileVersionInfoW( mypathW
, 0, retvalW
, pVersionInfoW
);
344 ok(retW
, "GetFileVersionInfo failed: GetLastError = %u\n", GetLastError());
347 GetModuleFileNameA(NULL
, mypathA
, MAX_PATH
);
348 retvalA
= GetFileVersionInfoSizeA( mypathA
, &hdlA
);
349 pVersionInfoA
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, retvalA
);
350 retA
= GetFileVersionInfoA( mypathA
, 0, retvalA
, pVersionInfoA
);
351 ok(retA
, "GetFileVersionInfo failed: GetLastError = %u\n", GetLastError());
353 if (is_unicode_enabled
)
355 ok( retvalA
== retvalW
, "The size of the struct should be the same for both A/W calls, it is (%d) vs. (%d)\n",
357 ok( !memcmp(pVersionInfoA
, pVersionInfoW
, retvalA
), "Both structs should be the same, they aren't\n");
360 /* The structs on Windows are bigger than just the struct for the basic information. The total struct
361 * contains also an empty part, which is used for converted strings. The converted strings are a result
362 * of calling VerQueryValueA on a 32bit resource and calling VerQueryValueW on a 16bit resource.
363 * The first WORD of the structure (wLength) shows the size of the base struct. The total struct size depends
364 * on the Windows version:
366 * 16bits resource (numbers are from a sample app):
368 * Windows Version Retrieved with A/W wLength StructSize
369 * ====================================================================================
370 * Win98 A 0x01B4 (436) 436
371 * NT4 A/W 0x01B4 (436) 2048 ???
372 * W2K/XP/W2K3 A/W 0x01B4 (436) 1536 which is (436 - sizeof(VS_FIXEDFILEINFO)) * 4
374 * 32bits resource (numbers are from this test executable version_crosstest.exe):
375 * Windows Version Retrieved with A/W wLength StructSize
376 * =============================================================
377 * Win98 A 0x01E0 (480) 848 (structure data doesn't seem correct)
378 * NT4 A/W 0x0350 (848) 1272 (848 * 1.5)
379 * W2K/XP/W2K3 A/W 0x0350 (848) 1700 which is (848 * 2) + 4
381 * Wine will follow the implementation (eventually) of W2K/XP/W2K3
384 /* Now some tests for the above (only if we are unicode enabled) */
386 if (is_unicode_enabled
)
388 VS_VERSION_INFO_STRUCT32
*vvis
= pVersionInfoW
;
389 ok ( retvalW
== ((vvis
->wLength
* 2) + 4) || retvalW
== (vvis
->wLength
* 1.5),
390 "Structure is not of the correct size\n");
393 /* Although the 32bit resource structures contain Unicode strings, VerQueryValueA will always return normal strings,
394 * VerQueryValueW will always return Unicode ones. (That means everything returned for StringFileInfo requests).
397 /* Get the VS_FIXEDFILEINFO information, this must be the same for both A- and W-Calls */
399 retA
= VerQueryValueA( pVersionInfoA
, rootA
, (LPVOID
*)&pBufA
, &uiLengthA
);
400 ok (retA
, "VerQueryValueA failed: GetLastError = %u\n", GetLastError());
401 ok ( uiLengthA
== sizeof(VS_FIXEDFILEINFO
), "Size (%d) doesn't match the size of the VS_FIXEDFILEINFO struct\n", uiLengthA
);
403 if (is_unicode_enabled
)
406 { /* This causes Vista and w2k8 to crash */
407 retW
= VerQueryValueW( pVersionInfoW
, NULL
, (LPVOID
*)&pBufW
, &uiLengthW
);
408 ok (retW
, "VerQueryValueW failed: GetLastError = %u\n", GetLastError());
411 retW
= VerQueryValueW( pVersionInfoW
, emptyW
, (LPVOID
*)&pBufW
, &uiLengthW
);
412 ok (retW
, "VerQueryValueW failed: GetLastError = %u\n", GetLastError());
414 retW
= VerQueryValueW( pVersionInfoW
, rootW
, (LPVOID
*)&pBufW
, &uiLengthW
);
415 ok (retW
, "VerQueryValueW failed: GetLastError = %u\n", GetLastError());
416 ok ( uiLengthW
== sizeof(VS_FIXEDFILEINFO
), "Size (%d) doesn't match the size of the VS_FIXEDFILEINFO struct\n", uiLengthW
);
418 ok( uiLengthA
== uiLengthW
, "The size of VS_FIXEDFILEINFO should be the same for both A/W calls, it is (%d) vs. (%d)\n",
419 uiLengthA
, uiLengthW
);
420 ok( !memcmp(pBufA
, pBufW
, uiLengthA
), "Both values should be the same, they aren't\n");
423 /* Get some VarFileInfo information, this must be the same for both A- and W-Calls */
425 retA
= VerQueryValueA( pVersionInfoA
, varfileinfoA
, (LPVOID
*)&pBufA
, &uiLengthA
);
426 ok (retA
, "VerQueryValueA failed: GetLastError = %u\n", GetLastError());
427 ok( !memcmp(pBufA
, WineVarFileInfoA
, uiLengthA
), "The VarFileInfo should have matched 0904e404 (non case sensitive)\n");
429 if (is_unicode_enabled
)
431 retW
= VerQueryValueW( pVersionInfoW
, varfileinfoW
, (LPVOID
*)&pBufW
, &uiLengthW
);
432 ok (retW
, "VerQueryValueW failed: GetLastError = %u\n", GetLastError());
433 ok( uiLengthA
== uiLengthW
, "The size of the VarFileInfo information should be the same for both A/W calls, it is (%d) vs. (%d)\n",
434 uiLengthA
, uiLengthW
);
435 ok( !memcmp(pBufA
, pBufW
, uiLengthA
), "Both values should be the same, they aren't\n");
438 /* Get some StringFileInfo information, this will be ANSI for A-Calls and Unicode for W-Calls */
440 retA
= VerQueryValueA( pVersionInfoA
, FileDescriptionA
, (LPVOID
*)&pBufA
, &uiLengthA
);
441 ok (retA
, "VerQueryValueA failed: GetLastError = %u\n", GetLastError());
442 ok( !lstrcmpA(WineFileDescriptionA
, pBufA
), "expected '%s' got '%s'\n",
443 WineFileDescriptionA
, pBufA
);
445 /* Test a second time */
446 retA
= VerQueryValueA( pVersionInfoA
, FileDescriptionA
, (LPVOID
*)&pBufA
, &uiLengthA
);
447 ok (retA
, "VerQueryValueA failed: GetLastError = %u\n", GetLastError());
448 ok( !lstrcmpA(WineFileDescriptionA
, pBufA
), "expected '%s' got '%s'\n",
449 WineFileDescriptionA
, pBufA
);
451 if (is_unicode_enabled
)
453 retW
= VerQueryValueW( pVersionInfoW
, FileDescriptionW
, (LPVOID
*)&pBufW
, &uiLengthW
);
454 ok (retW
, "VerQueryValueW failed: GetLastError = %u\n", GetLastError());
455 ok( !lstrcmpW(WineFileDescriptionW
, pBufW
), "FileDescription should have been '%s'\n", WineFileDescriptionA
);
458 HeapFree( GetProcessHeap(), 0, pVersionInfoA
);
459 if (is_unicode_enabled
)
460 HeapFree( GetProcessHeap(), 0, pVersionInfoW
);
463 static void test_VerQueryValueA(void)
465 static const char * const value_name
[] = {
466 "Product", "CompanyName", "FileDescription", "Internal",
467 "ProductVersion", "InternalName", "File", "LegalCopyright",
468 "FileVersion", "Legal", "OriginalFilename", "ProductName",
469 "Company", "Original" };
471 UINT len
, ret
, translation
, i
;
474 ret
= GetModuleFileNameA(NULL
, buf
, sizeof(buf
));
477 SetLastError(0xdeadbeef);
478 len
= GetFileVersionInfoSizeA(buf
, NULL
);
479 ok(len
, "GetFileVersionInfoSizeA(%s) error %u\n", buf
, GetLastError());
481 ver
= HeapAlloc(GetProcessHeap(), 0, len
);
484 SetLastError(0xdeadbeef);
485 ret
= GetFileVersionInfoA(buf
, 0, len
, ver
);
486 ok(ret
, "GetFileVersionInfoA error %u\n", GetLastError());
488 p
= (char *)0xdeadbeef;
490 SetLastError(0xdeadbeef);
491 ret
= VerQueryValueA(ver
, "\\VarFileInfo\\Translation", (LPVOID
*)&p
, &len
);
492 ok(ret
, "VerQueryValue error %u\n", GetLastError());
493 ok(len
== 4, "VerQueryValue returned %u, expected 4\n", len
);
495 translation
= *(UINT
*)p
;
496 translation
= MAKELONG(HIWORD(translation
), LOWORD(translation
));
498 p
= (char *)0xdeadbeef;
500 SetLastError(0xdeadbeef);
501 ret
= VerQueryValueA(ver
, "String", (LPVOID
*)&p
, &len
);
502 ok(!ret
, "VerQueryValue should fail\n");
503 ok(GetLastError() == ERROR_RESOURCE_TYPE_NOT_FOUND
||
504 GetLastError() == 0xdeadbeef /* NT4, W2K */,
505 "VerQueryValue returned %u\n", GetLastError());
506 ok(p
== (char *)0xdeadbeef, "expected 0xdeadbeef got %p\n", p
);
507 ok(len
== 0, "expected 0 got %x\n", len
);
509 p
= (char *)0xdeadbeef;
511 SetLastError(0xdeadbeef);
512 ret
= VerQueryValueA(ver
, "StringFileInfo", (LPVOID
*)&p
, &len
);
513 ok(ret
, "VerQueryValue error %u\n", GetLastError());
514 ok(len
== 0, "VerQueryValue returned %u, expected 0\n", len
);
515 ok(p
!= (char *)0xdeadbeef, "not expected 0xdeadbeef\n");
517 p
= (char *)0xdeadbeef;
519 SetLastError(0xdeadbeef);
520 ret
= VerQueryValueA(ver
, "\\StringFileInfo", (LPVOID
*)&p
, &len
);
521 ok(ret
, "VerQueryValue error %u\n", GetLastError());
522 ok(len
== 0, "VerQueryValue returned %u, expected 0\n", len
);
523 ok(p
!= (char *)0xdeadbeef, "not expected 0xdeadbeef\n");
525 p
= (char *)0xdeadbeef;
527 SetLastError(0xdeadbeef);
528 ret
= VerQueryValueA(ver
, "\\\\StringFileInfo", (LPVOID
*)&p
, &len
);
529 ok(ret
, "VerQueryValue error %u\n", GetLastError());
530 ok(len
== 0, "VerQueryValue returned %u, expected 0\n", len
);
531 ok(p
!= (char *)0xdeadbeef, "not expected 0xdeadbeef\n");
533 p
= (char *)0xdeadbeef;
535 SetLastError(0xdeadbeef);
536 ret
= VerQueryValueA(ver
, "\\StringFileInfo\\\\", (LPVOID
*)&p
, &len
);
537 ok(ret
, "VerQueryValue error %u\n", GetLastError());
538 ok(len
== 0, "VerQueryValue returned %u, expected 0\n", len
);
539 ok(p
!= (char *)0xdeadbeef, "not expected 0xdeadbeef\n");
541 sprintf(buf
, "\\StringFileInfo\\%08x", translation
);
542 p
= (char *)0xdeadbeef;
544 SetLastError(0xdeadbeef);
545 ret
= VerQueryValueA(ver
, buf
, (LPVOID
*)&p
, &len
);
546 ok(ret
, "VerQueryValue error %u\n", GetLastError());
547 ok(len
== 0, "VerQueryValue returned %u, expected 0\n", len
);
548 ok(p
!= (char *)0xdeadbeef, "not expected 0xdeadbeef\n");
550 for (i
= 0; i
< sizeof(value_name
)/sizeof(value_name
[0]); i
++)
552 sprintf(buf
, "\\StringFileInfo\\%08x\\%s", translation
, value_name
[i
]);
553 p
= (char *)0xdeadbeef;
555 SetLastError(0xdeadbeef);
556 ret
= VerQueryValueA(ver
, buf
, (LPVOID
*)&p
, &len
);
557 ok(ret
, "VerQueryValueA(%s) error %u\n", buf
, GetLastError());
558 ok(len
== strlen(value_name
[i
]) + 1, "VerQueryValue returned %u\n", len
);
559 ok(!strcmp(value_name
[i
], p
), "expected \"%s\", got \"%s\"\n",
562 /* test partial value names */
565 p
= (char *)0xdeadbeef;
567 SetLastError(0xdeadbeef);
568 ret
= VerQueryValueA(ver
, buf
, (LPVOID
*)&p
, &len
);
569 ok(!ret
, "VerQueryValueA(%s) succeeded\n", buf
);
570 ok(GetLastError() == ERROR_RESOURCE_TYPE_NOT_FOUND
||
571 GetLastError() == 0xdeadbeef /* NT4, W2K */,
572 "VerQueryValue returned %u\n", GetLastError());
573 ok(p
== (char *)0xdeadbeef, "expected 0xdeadbeef got %p\n", p
);
574 ok(len
== 0, "expected 0 or 0xbeef, got %x\n", len
);
577 HeapFree(GetProcessHeap(), 0, ver
);
580 static void test_VerQueryValue_InvalidLength(void)
582 /* this buffer is created with the reactos resource compiler from this resource:
585 VS_VERSION_INFO VERSIONINFO
587 PRODUCTVERSION 1,0,0,0
592 FILESUBTYPE VFT2_UNKNOWN
594 BLOCK "StringFileInfo"
599 char preparedbuffer
[] = {
600 /* VS_VERSION_INFO_STRUCT32 */
601 0x80, 0x00, /* wLength */
602 0x34, 0x00, /* wValueLength */
603 0x00, 0x00, /* wType */
604 /* L"VS_VERSION_INFO" + DWORD alignment */
605 0x56, 0x00, 0x53, 0x00, 0x5f, 0x00, 0x56, 0x00, 0x45, 0x00, 0x52, 0x00, 0x53, 0x00, 0x49, 0x00, 0x4f,
606 0x00, 0x4e, 0x00, 0x5f, 0x00, 0x49, 0x00, 0x4e, 0x00, 0x46, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x00,
608 /* VS_FIXEDFILEINFO */
609 0xbd, 0x04, 0xef, 0xfe, /* dwSignature */
610 0x00, 0x00, 0x01, 0x00, /* dwStrucVersion */
611 0x00, 0x00, 0x01, 0x00, /* dwFileVersionMS */
612 0x00, 0x00, 0x00, 0x00, /* dwFileVersionLS */
613 0x00, 0x00, 0x01, 0x00, /* dwProductVersionMS */
614 0x00, 0x00, 0x00, 0x00, /* dwProductVersionLS */
615 0x3f, 0x00, 0x00, 0x00, /* dwFileFlagsMask */
616 0x00, 0x00, 0x00, 0x00, /* dwFileFlags */
617 0x00, 0x00, 0x00, 0x00, /* dwFileOS */
618 0x01, 0x00, 0x00, 0x00, /* dwFileType */
619 0x00, 0x00, 0x00, 0x00, /* dwFileSubtype */
620 0x00, 0x00, 0x00, 0x00, /* dwFileDateMS */
621 0x00, 0x00, 0x00, 0x00, /* dwFileDateLS */
624 0x24, 0x00, /* wLength */
625 0x00, 0x00, /* wValueLength */
626 0x01, 0x00, /* wType */
627 /* L"StringFileInfo" + DWORD alignment */
628 0x53, 0x00, 0x74, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x67, 0x00, 0x46, 0x00, 0x69, 0x00,
629 0x6c, 0x00, 0x65, 0x00, 0x49, 0x00, 0x6e, 0x00, 0x66, 0x00, 0x6f, 0x00, 0x00, 0x00,
631 0x46, 0x45, 0x32, 0x58,
633 /* Extra bytes allocated for W->A conversions. */
634 0x0d, 0xf0, 0xad, 0xba, 0x0d, 0xf0, 0xad, 0xba, 0x0d, 0xf0, 0xad, 0xba, 0x0d, 0xf0, 0xad, 0xba,
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,
645 WCHAR FileDescriptionW
[] = { '\\', '\\', 'S', 't', 'r', 'i', 'n', 'g', 'F', 'i', 'l', 'e', 'I', 'n', 'f', 'o', 0 };
647 p
= (char *)0xdeadbeef;
649 SetLastError(0xdeadbeef);
650 ret
= VerQueryValueA(preparedbuffer
, "StringFileInfo", (LPVOID
*)&p
, &len
);
651 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());
663 ok(len
== 0, "VerQueryValueA returned %u, expected 0\n", len
);
665 ok(p
== preparedbuffer
+ 0x7e, "p was %p, expected %p\n", p
, preparedbuffer
+ 0x7e);
667 p
= (char *)0xdeadbeef;
669 SetLastError(0xdeadbeef);
670 ret
= VerQueryValueA(preparedbuffer
, "\\\\StringFileInfo", (LPVOID
*)&p
, &len
);
671 ok(ret
, "VerQueryValueA error %u\n", GetLastError());
673 ok(len
== 0, "VerQueryValueA returned %u, expected 0\n", len
);
675 ok(p
== preparedbuffer
+ 0x7e, "p was %p, expected %p\n", p
, preparedbuffer
+ 0x7e);
677 /* also test the W versions. */
678 p
= (char *)0xdeadbeef;
680 SetLastError(0xdeadbeef);
681 ret
= VerQueryValueW(preparedbuffer
, FileDescriptionW
+ 2, (LPVOID
*)&p
, &len
);
682 ok(ret
, "VerQueryValueW error %u\n", GetLastError());
683 ok(len
== 0, "VerQueryValueW returned %u, expected 0\n", len
);
685 ok(p
== preparedbuffer
+ 0x7e, "p was %p, expected %p\n", p
, preparedbuffer
+ 0x7e);
687 p
= (char *)0xdeadbeef;
689 SetLastError(0xdeadbeef);
690 ret
= VerQueryValueW(preparedbuffer
, FileDescriptionW
+ 1, (LPVOID
*)&p
, &len
);
691 ok(ret
, "VerQueryValueW error %u\n", GetLastError());
692 ok(len
== 0, "VerQueryValueW returned %u, expected 0\n", len
);
694 ok(p
== preparedbuffer
+ 0x7e, "p was %p, expected %p\n", p
, preparedbuffer
+ 0x7e);
696 p
= (char *)0xdeadbeef;
698 SetLastError(0xdeadbeef);
699 ret
= VerQueryValueW(preparedbuffer
, FileDescriptionW
, (LPVOID
*)&p
, &len
);
700 ok(ret
, "VerQueryValueW error %u\n", GetLastError());
701 ok(len
== 0, "VerQueryValueW returned %u, expected 0\n", len
);
703 ok(p
== preparedbuffer
+ 0x7e, "p was %p, expected %p\n", p
, preparedbuffer
+ 0x7e);
706 static void test_extra_block(void)
708 WORD extra_block
[] = {
709 72, 0, 0, 'W', 'i', 'n', 'e', 'T', 'e', 's', 't', '\0',
710 24, 4, 0, 'B', 'i', 'n', 'a', 'r', 'y', '\0', 0xbeef, 0xdead,
711 24, 4, 1, 'T', 'e', 'x', 't', '\0', 'B', '-', ')', '\0',
719 ret
= GetModuleFileNameA(NULL
, buf
, sizeof(buf
));
720 ok(ret
, "GetModuleFileNameA failed\n");
722 len
= GetFileVersionInfoSizeA(buf
, NULL
);
723 ok(len
, "GetFileVersionInfoSizeA(%s) error %u\n", buf
, GetLastError());
725 ver
= HeapAlloc(GetProcessHeap(), 0, len
+ sizeof(extra_block
) * 2);
726 ok(ver
!= NULL
, "Can't allocate memory\n");
728 ret
= GetFileVersionInfoA(buf
, 0, len
, ver
);
729 ok(ret
, "GetFileVersionInfoA error %u\n", GetLastError());
731 /* forge the string table, as windres dislike an extra block */
732 length
= (WORD
*)ver
; /* see VS_VERSION_INFO_STRUCT32 for details */
733 memcpy(ver
+ *length
, extra_block
, sizeof(extra_block
));
734 *length
+= sizeof(extra_block
);
736 p
= (char *)0xdeadbeef;
739 ret
= VerQueryValueA(ver
, "WineTest\\Binary", (LPVOID
*)&p
, &len
);
740 ok(ret
, "VerQueryValue error %u\n", GetLastError());
741 ok(len
== 4, "VerQueryValue returned %u, expected 4\n", len
);
742 ok(p
!= (char *)0xdeadbeef, "not expected 0xdeadbeef\n");
743 ok(memcmp(p
, &w
, sizeof(w
)) == 0, "got 0x%08x, expected 0x%08x\n", *(PULONG
)p
, w
);
745 p
= (char *)0xdeadbeef;
747 ret
= VerQueryValueA(ver
, "WineTest\\Text", (LPVOID
*)&p
, &len
);
748 ok(ret
, "VerQueryValue error %u\n", GetLastError());
749 ok(len
== 4, "VerQueryValue returned %u, expected 4\n", len
);
750 ok(p
!= (char *)0xdeadbeef, "not expected 0xdeadbeef\n");
751 ok(strcmp(p
, "B-)") == 0, "got '%s', expected '%s'\n", p
, "B-)");
753 HeapFree(GetProcessHeap(), 0, ver
);
756 static void test_GetFileVersionInfoEx(void)
760 UINT size
, translation
, i
;
762 BOOL (WINAPI
*pGetFileVersionInfoExW
)(DWORD
, LPCWSTR
, DWORD
, DWORD
, LPVOID
);
763 DWORD (WINAPI
*pGetFileVersionInfoSizeExW
)(DWORD
, LPCWSTR
, LPDWORD
);
764 const LANGID lang
= GetUserDefaultUILanguage();
765 const LANGID english
= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
);
766 const WORD unicode
= 1200; /* = UNICODE */
767 const WCHAR kernel32W
[] = {'k','e','r','n','e','l','3','2','.','d','l','l',0};
768 const DWORD test_flags
[] = {
769 0, FILE_VER_GET_LOCALISED
, FILE_VER_GET_NEUTRAL
,
770 FILE_VER_GET_LOCALISED
| FILE_VER_GET_NEUTRAL
,
771 0xdeadbeef, /* invalid value (ignored) */
775 size
= GetFileVersionInfoSizeW(kernel32W
, NULL
);
776 ok(size
, "GetFileVersionInfoSize(kernel32) error %u\n", GetLastError());
778 ver
= HeapAlloc(GetProcessHeap(), 0, size
);
781 ret
= GetFileVersionInfoW(kernel32W
, 0, size
, ver
);
782 ok(ret
, "GetFileVersionInfo error %u\n", GetLastError());
784 ret
= VerQueryValueA(ver
, "\\VarFileInfo\\Translation", (void **)&p
, &size
);
785 translation
= *(UINT
*)p
;
786 ok(ret
, "VerQueryValue error %u\n", GetLastError());
787 ok(size
== 4, "VerQueryValue returned %u, expected 4\n", size
);
789 /* test default version resource */
790 todo_wine_if(lang
!= english
)
791 ok(LOWORD(translation
) == lang
, "got %u, expected lang is %u\n",
792 LOWORD(translation
), lang
);
794 ok(HIWORD(translation
) == unicode
, "got %u, expected codepage is %u\n",
795 HIWORD(translation
), unicode
);
797 HeapFree(GetProcessHeap(), 0, ver
);
799 mod
= GetModuleHandleA("version.dll");
802 /* prefer W-version as A-version is not available on Windows 7 */
803 pGetFileVersionInfoExW
= (void *)GetProcAddress(mod
, "GetFileVersionInfoExW");
804 pGetFileVersionInfoSizeExW
= (void *)GetProcAddress(mod
, "GetFileVersionInfoSizeExW");
805 if (!pGetFileVersionInfoExW
&& !pGetFileVersionInfoSizeExW
)
807 win_skip("GetFileVersionInfoEx family is not available\n");
811 for (i
= 0; i
< sizeof(test_flags
)/sizeof(test_flags
[0]); i
++)
813 size
= pGetFileVersionInfoSizeExW(test_flags
[i
], kernel32W
, NULL
);
814 ok(size
, "[%u] GetFileVersionInfoSizeEx(kernel32) error %u\n", i
, GetLastError());
816 ver
= HeapAlloc(GetProcessHeap(), 0, size
);
819 ret
= pGetFileVersionInfoExW(test_flags
[i
], kernel32W
, 0, size
, ver
);
820 ok(ret
, "[%u] GetFileVersionInfoEx error %u\n", i
, GetLastError());
822 ret
= VerQueryValueA(ver
, "\\VarFileInfo\\Translation", (void **)&p
, &size
);
823 ok(ret
, "[%u] VerQueryValue error %u\n", i
, GetLastError());
824 ok(size
== 4, "[%u] VerQueryValue returned %u, expected 4\n", i
, size
);
825 translation
= *(UINT
*)p
;
827 /* test MUI version resource */
828 todo_wine_if((test_flags
[i
] & FILE_VER_GET_LOCALISED
) && lang
!= english
)
829 if (test_flags
[i
] & FILE_VER_GET_LOCALISED
)
830 ok(LOWORD(translation
) == lang
, "[%u] got %u, expected lang is %u\n",
831 i
, LOWORD(translation
), lang
);
833 ok(LOWORD(translation
) == english
, "[%u] got %u, expected lang is %u\n",
834 i
, LOWORD(translation
), english
);
836 ok(HIWORD(translation
) == unicode
, "[%u] got %u, expected codepage is %u\n",
837 i
, HIWORD(translation
), unicode
);
839 /* test string info using translation info */
841 sprintf(desc
, "\\StringFileInfo\\%04x%04x\\FileDescription",
842 LOWORD(translation
), HIWORD(translation
));
843 ret
= VerQueryValueA(ver
, desc
, (void **)&p
, &size
);
844 ok(ret
, "[%u] VerQueryValue error %u\n", i
, GetLastError());
845 ok(size
== strlen(p
) + 1, "[%u] VerQueryValue returned %u\n", i
, size
);
847 HeapFree(GetProcessHeap(), 0, ver
);
858 test_VerQueryValueA();
859 test_VerQueryValue_InvalidLength();
861 test_GetFileVersionInfoEx();