[VERSION_WINETEST]
[reactos.git] / rostests / winetests / version / info.c
1 /*
2 * Copyright (C) 2004 Stefan Leichter
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17 */
18
19 #include <stdarg.h>
20 #include <stdio.h>
21 #include <assert.h>
22
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winerror.h"
26 #include "winver.h"
27 #include "wine/test.h"
28
29 #define MY_LAST_ERROR ((DWORD)-1)
30 #define EXPECT_BAD_PATH__NOT_FOUND \
31 ok( (ERROR_PATH_NOT_FOUND == GetLastError()) || \
32 (ERROR_RESOURCE_DATA_NOT_FOUND == GetLastError()) || \
33 (ERROR_FILE_NOT_FOUND == GetLastError()) || \
34 (ERROR_BAD_PATHNAME == GetLastError()) || \
35 (ERROR_SUCCESS == GetLastError()), \
36 "Last error wrong! ERROR_RESOURCE_DATA_NOT_FOUND/ERROR_BAD_PATHNAME (98)/" \
37 "ERROR_PATH_NOT_FOUND (NT4)/ERROR_FILE_NOT_FOUND (2k3) " \
38 "ERROR_SUCCESS (2k) expected, got %u\n", GetLastError());
39 #define EXPECT_INVALID__NOT_FOUND \
40 ok( (ERROR_PATH_NOT_FOUND == GetLastError()) || \
41 (ERROR_RESOURCE_DATA_NOT_FOUND == GetLastError()) || \
42 (ERROR_FILE_NOT_FOUND == GetLastError()) || \
43 (ERROR_INVALID_PARAMETER == GetLastError()) || \
44 (ERROR_SUCCESS == GetLastError()), \
45 "Last error wrong! ERROR_RESOURCE_DATA_NOT_FOUND/ERROR_INVALID_PARAMETER (98)/" \
46 "ERROR_PATH_NOT_FOUND (NT4)/ERROR_FILE_NOT_FOUND (2k3) " \
47 "ERROR_SUCCESS (2k) expected, got %u\n", GetLastError());
48
49 static void create_file(const CHAR *name)
50 {
51 HANDLE file;
52 DWORD written;
53
54 file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
55 ok(file != INVALID_HANDLE_VALUE, "Failure to open file %s\n", name);
56 WriteFile(file, name, strlen(name), &written, NULL);
57 WriteFile(file, "\n", strlen("\n"), &written, NULL);
58 CloseHandle(file);
59 }
60
61 static void test_info_size(void)
62 { DWORD hdl, retval;
63 char mypath[MAX_PATH] = "";
64
65 SetLastError(MY_LAST_ERROR);
66 retval = GetFileVersionInfoSizeA( NULL, NULL);
67 ok( !retval,
68 "GetFileVersionInfoSizeA result wrong! 0L expected, got 0x%08x\n",
69 retval);
70 EXPECT_INVALID__NOT_FOUND;
71
72 hdl = 0x55555555;
73 SetLastError(MY_LAST_ERROR);
74 retval = GetFileVersionInfoSizeA( NULL, &hdl);
75 ok( !retval,
76 "GetFileVersionInfoSizeA result wrong! 0L expected, got 0x%08x\n",
77 retval);
78 EXPECT_INVALID__NOT_FOUND;
79 ok( hdl == 0L,
80 "Handle wrong! 0L expected, got 0x%08x\n", hdl);
81
82 SetLastError(MY_LAST_ERROR);
83 retval = GetFileVersionInfoSizeA( "", NULL);
84 ok( !retval,
85 "GetFileVersionInfoSizeA result wrong! 0L expected, got 0x%08x\n",
86 retval);
87 EXPECT_BAD_PATH__NOT_FOUND;
88
89 hdl = 0x55555555;
90 SetLastError(MY_LAST_ERROR);
91 retval = GetFileVersionInfoSizeA( "", &hdl);
92 ok( !retval,
93 "GetFileVersionInfoSizeA result wrong! 0L expected, got 0x%08x\n",
94 retval);
95 EXPECT_BAD_PATH__NOT_FOUND;
96 ok( hdl == 0L,
97 "Handle wrong! 0L expected, got 0x%08x\n", hdl);
98
99 SetLastError(MY_LAST_ERROR);
100 retval = GetFileVersionInfoSizeA( "kernel32.dll", NULL);
101 ok( retval,
102 "GetFileVersionInfoSizeA result wrong! <> 0L expected, got 0x%08x\n",
103 retval);
104 ok((NO_ERROR == GetLastError()) || (MY_LAST_ERROR == GetLastError()),
105 "Last error wrong! NO_ERROR/0x%08x (NT4) expected, got %u\n",
106 MY_LAST_ERROR, GetLastError());
107
108 hdl = 0x55555555;
109 SetLastError(MY_LAST_ERROR);
110 retval = GetFileVersionInfoSizeA( "kernel32.dll", &hdl);
111 ok( retval,
112 "GetFileVersionInfoSizeA result wrong! <> 0L expected, got 0x%08x\n",
113 retval);
114 ok((NO_ERROR == GetLastError()) || (MY_LAST_ERROR == GetLastError()),
115 "Last error wrong! NO_ERROR/0x%08x (NT4) expected, got %u\n",
116 MY_LAST_ERROR, GetLastError());
117 ok( hdl == 0L,
118 "Handle wrong! 0L expected, got 0x%08x\n", hdl);
119
120 SetLastError(MY_LAST_ERROR);
121 retval = GetFileVersionInfoSizeA( "notexist.dll", NULL);
122 ok( !retval,
123 "GetFileVersionInfoSizeA result wrong! 0L expected, got 0x%08x\n",
124 retval);
125 ok( (ERROR_FILE_NOT_FOUND == GetLastError()) ||
126 (ERROR_RESOURCE_DATA_NOT_FOUND == GetLastError()) ||
127 (MY_LAST_ERROR == GetLastError()) ||
128 (ERROR_SUCCESS == GetLastError()), /* win2k */
129 "Last error wrong! ERROR_FILE_NOT_FOUND/ERROR_RESOURCE_DATA_NOT_FOUND "
130 "(XP)/0x%08x (NT4) expected, got %u\n", MY_LAST_ERROR, GetLastError());
131
132 /* test a currently loaded executable */
133 if(GetModuleFileNameA(NULL, mypath, MAX_PATH)) {
134 hdl = 0x55555555;
135 SetLastError(MY_LAST_ERROR);
136 retval = GetFileVersionInfoSizeA( mypath, &hdl);
137 ok( retval,
138 "GetFileVersionInfoSizeA result wrong! <> 0L expected, got 0x%08x\n",
139 retval);
140 ok((NO_ERROR == GetLastError()) || (MY_LAST_ERROR == GetLastError()),
141 "Last error wrong! NO_ERROR/0x%08x (NT4) expected, got %u\n",
142 MY_LAST_ERROR, GetLastError());
143 ok( hdl == 0L,
144 "Handle wrong! 0L expected, got 0x%08x\n", hdl);
145 }
146 else
147 trace("skipping GetModuleFileNameA(NULL,..) failed\n");
148
149 /* test a not loaded executable */
150 if(GetSystemDirectoryA(mypath, MAX_PATH)) {
151 lstrcatA(mypath, "\\regsvr32.exe");
152
153 if(INVALID_FILE_ATTRIBUTES == GetFileAttributesA(mypath))
154 trace("GetFileAttributesA(%s) failed\n", mypath);
155 else {
156 hdl = 0x55555555;
157 SetLastError(MY_LAST_ERROR);
158 retval = GetFileVersionInfoSizeA( mypath, &hdl);
159 ok( retval,
160 "GetFileVersionInfoSizeA result wrong! <> 0L expected, got 0x%08x\n",
161 retval);
162 ok((NO_ERROR == GetLastError()) || (MY_LAST_ERROR == GetLastError()),
163 "Last error wrong! NO_ERROR/0x%08x (NT4) expected, got %u\n",
164 MY_LAST_ERROR, GetLastError());
165 ok( hdl == 0L,
166 "Handle wrong! 0L expected, got 0x%08x\n", hdl);
167 }
168 }
169 else
170 trace("skipping GetSystemDirectoryA(mypath,..) failed\n");
171
172 create_file("test.txt");
173
174 /* no version info */
175 SetLastError(0xdeadbeef);
176 hdl = 0xcafe;
177 retval = GetFileVersionInfoSizeA("test.txt", &hdl);
178 ok(retval == 0, "Expected 0, got %d\n", retval);
179 ok(hdl == 0, "Expected 0, got %d\n", hdl);
180 ok(GetLastError() == ERROR_RESOURCE_DATA_NOT_FOUND ||
181 GetLastError() == ERROR_SUCCESS, /* win2k */
182 "Expected ERROR_RESOURCE_DATA_NOT_FOUND, got %d\n", GetLastError());
183
184 DeleteFileA("test.txt");
185 }
186
187 static void VersionDwordLong2String(DWORDLONG Version, LPSTR lpszVerString)
188 {
189 WORD a, b, c, d;
190
191 a = (WORD)(Version >> 48);
192 b = (WORD)((Version >> 32) & 0xffff);
193 c = (WORD)((Version >> 16) & 0xffff);
194 d = (WORD)(Version & 0xffff);
195
196 sprintf(lpszVerString, "%d.%d.%d.%d", a, b, c, d);
197 }
198
199 static void test_info(void)
200 {
201 DWORD hdl, retval;
202 PVOID pVersionInfo = NULL;
203 BOOL boolret;
204 VS_FIXEDFILEINFO *pFixedVersionInfo;
205 UINT uiLength;
206 char VersionString[MAX_PATH];
207 static const char backslash[] = "\\";
208 DWORDLONG dwlVersion;
209
210 hdl = 0x55555555;
211 SetLastError(MY_LAST_ERROR);
212 retval = GetFileVersionInfoSizeA( "kernel32.dll", &hdl);
213 ok( retval,
214 "GetFileVersionInfoSizeA result wrong! <> 0L expected, got 0x%08x\n",
215 retval);
216 ok((NO_ERROR == GetLastError()) || (MY_LAST_ERROR == GetLastError()),
217 "Last error wrong! NO_ERROR/0x%08x (NT4) expected, got %u\n",
218 MY_LAST_ERROR, GetLastError());
219 ok( hdl == 0L,
220 "Handle wrong! 0L expected, got 0x%08x\n", hdl);
221
222 if ( retval == 0 || hdl != 0)
223 return;
224
225 pVersionInfo = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, retval );
226 ok(pVersionInfo != 0, "HeapAlloc failed\n" );
227 if (pVersionInfo == 0)
228 return;
229
230 if (0)
231 {
232 /* this test crashes on WinNT4
233 */
234 boolret = GetFileVersionInfoA( "kernel32.dll", 0, retval, 0);
235 ok (!boolret, "GetFileVersionInfoA should have failed: GetLastError = %u\n", GetLastError());
236 ok ((GetLastError() == ERROR_INVALID_DATA) || (GetLastError() == ERROR_BAD_PATHNAME) ||
237 (GetLastError() == NO_ERROR),
238 "Last error wrong! ERROR_INVALID_DATA/ERROR_BAD_PATHNAME (ME)/"
239 "NO_ERROR (95) expected, got %u\n",
240 GetLastError());
241 }
242
243 boolret = GetFileVersionInfoA( "kernel32.dll", 0, retval, pVersionInfo );
244 ok (boolret, "GetFileVersionInfoA failed: GetLastError = %u\n", GetLastError());
245 if (!boolret)
246 goto cleanup;
247
248 boolret = VerQueryValueA( pVersionInfo, NULL, (LPVOID *)&pFixedVersionInfo, &uiLength );
249 ok (boolret || GetLastError() == NO_ERROR /* Win98 */,
250 "VerQueryValueA failed: GetLastError = %u\n", GetLastError());
251
252 boolret = VerQueryValueA( pVersionInfo, "", (LPVOID *)&pFixedVersionInfo, &uiLength );
253 ok (boolret, "VerQueryValueA failed: GetLastError = %u\n", GetLastError());
254
255 boolret = VerQueryValueA( pVersionInfo, backslash, (LPVOID *)&pFixedVersionInfo, &uiLength );
256 ok (boolret, "VerQueryValueA failed: GetLastError = %u\n", GetLastError());
257 if (!boolret)
258 goto cleanup;
259
260 dwlVersion = (((DWORDLONG)pFixedVersionInfo->dwFileVersionMS) << 32) +
261 pFixedVersionInfo->dwFileVersionLS;
262
263 VersionDwordLong2String(dwlVersion, VersionString);
264
265 trace("kernel32.dll version: %s\n", VersionString);
266
267 if (0)
268 {
269 /* this test crashes on WinNT4
270 */
271 boolret = VerQueryValueA( pVersionInfo, backslash, (LPVOID *)&pFixedVersionInfo, 0);
272 ok (boolret, "VerQueryValue failed: GetLastError = %u\n", GetLastError());
273 }
274
275 cleanup:
276 HeapFree( GetProcessHeap(), 0, pVersionInfo);
277 }
278
279 static void test_32bit_win(void)
280 {
281 DWORD hdlA, retvalA;
282 DWORD hdlW, retvalW = 0;
283 BOOL retA,retW;
284 PVOID pVersionInfoA = NULL;
285 PVOID pVersionInfoW = NULL;
286 char *pBufA;
287 WCHAR *pBufW;
288 UINT uiLengthA, uiLengthW;
289 char mypathA[MAX_PATH];
290 WCHAR mypathW[MAX_PATH];
291 char rootA[] = "\\";
292 WCHAR rootW[] = { '\\', 0 };
293 WCHAR emptyW[] = { 0 };
294 char varfileinfoA[] = "\\VarFileInfo\\Translation";
295 WCHAR varfileinfoW[] = { '\\','V','a','r','F','i','l','e','I','n','f','o',
296 '\\','T','r','a','n','s','l','a','t','i','o','n', 0 };
297 char WineVarFileInfoA[] = { 0x09, 0x04, 0xE4, 0x04 };
298 char FileDescriptionA[] = "\\StringFileInfo\\040904E4\\FileDescription";
299 WCHAR FileDescriptionW[] = { '\\','S','t','r','i','n','g','F','i','l','e','I','n','f','o',
300 '\\','0','4','0','9','0','4','E','4',
301 '\\','F','i','l','e','D','e','s','c','r','i','p','t','i','o','n', 0 };
302 char WineFileDescriptionA[] = "FileDescription";
303 WCHAR WineFileDescriptionW[] = { 'F','i','l','e','D','e','s','c','r','i','p','t','i','o','n', 0 };
304 BOOL is_unicode_enabled = TRUE;
305
306 /* A copy from dlls/version/info.c */
307 typedef struct
308 {
309 WORD wLength;
310 WORD wValueLength;
311 WORD wType;
312 WCHAR szKey[1];
313 #if 0 /* variable length structure */
314 /* DWORD aligned */
315 BYTE Value[];
316 /* DWORD aligned */
317 VS_VERSION_INFO_STRUCT32 Children[];
318 #endif
319 } VS_VERSION_INFO_STRUCT32;
320
321 /* If we call GetFileVersionInfoA on a system that supports Unicode, NT/W2K/XP/W2K3 (by default) and Wine,
322 * the versioninfo will contain Unicode strings.
323 * Part of the test is to call both the A and W versions, which should have the same Version Information
324 * for some requests, on systems that support both calls.
325 */
326
327 /* First get the versioninfo via the W versions */
328 SetLastError(0xdeadbeef);
329 GetModuleFileNameW(NULL, mypathW, MAX_PATH);
330 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
331 {
332 win_skip("GetModuleFileNameW not existing on this platform, skipping comparison between A- and W-calls\n");
333 is_unicode_enabled = FALSE;
334 }
335
336 if (is_unicode_enabled)
337 {
338 retvalW = GetFileVersionInfoSizeW( mypathW, &hdlW);
339 pVersionInfoW = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, retvalW );
340 retW = GetFileVersionInfoW( mypathW, 0, retvalW, pVersionInfoW );
341 ok(retW, "GetFileVersionInfo failed: GetLastError = %u\n", GetLastError());
342 }
343
344 GetModuleFileNameA(NULL, mypathA, MAX_PATH);
345 retvalA = GetFileVersionInfoSizeA( mypathA, &hdlA);
346 pVersionInfoA = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, retvalA );
347 retA = GetFileVersionInfoA( mypathA, 0, retvalA, pVersionInfoA );
348 ok(retA, "GetFileVersionInfo failed: GetLastError = %u\n", GetLastError());
349
350 if (is_unicode_enabled)
351 {
352 ok( retvalA == retvalW, "The size of the struct should be the same for both A/W calls, it is (%d) vs. (%d)\n",
353 retvalA, retvalW);
354 ok( !memcmp(pVersionInfoA, pVersionInfoW, retvalA), "Both structs should be the same, they aren't\n");
355 }
356
357 /* The structs on Windows are bigger than just the struct for the basic information. The total struct
358 * contains also an empty part, which is used for converted strings. The converted strings are a result
359 * of calling VerQueryValueA on a 32bit resource and calling VerQueryValueW on a 16bit resource.
360 * The first WORD of the structure (wLength) shows the size of the base struct. The total struct size depends
361 * on the Windows version:
362 *
363 * 16bits resource (numbers are from a sample app):
364 *
365 * Windows Version Retrieved with A/W wLength StructSize
366 * ====================================================================================
367 * Win98 A 0x01B4 (436) 436
368 * NT4 A/W 0x01B4 (436) 2048 ???
369 * W2K/XP/W2K3 A/W 0x01B4 (436) 1536 which is (436 - sizeof(VS_FIXEDFILEINFO)) * 4
370 *
371 * 32bits resource (numbers are from this test executable version_crosstest.exe):
372 * Windows Version Retrieved with A/W wLength StructSize
373 * =============================================================
374 * Win98 A 0x01E0 (480) 848 (structure data doesn't seem correct)
375 * NT4 A/W 0x0350 (848) 1272 (848 * 1.5)
376 * W2K/XP/W2K3 A/W 0x0350 (848) 1700 which is (848 * 2) + 4
377 *
378 * Wine will follow the implementation (eventually) of W2K/XP/W2K3
379 */
380
381 /* Now some tests for the above (only if we are unicode enabled) */
382
383 if (is_unicode_enabled)
384 {
385 VS_VERSION_INFO_STRUCT32 *vvis = pVersionInfoW;
386 ok ( retvalW == ((vvis->wLength * 2) + 4) || retvalW == (vvis->wLength * 1.5),
387 "Structure is not of the correct size\n");
388 }
389
390 /* Although the 32bit resource structures contain Unicode strings, VerQueryValueA will always return normal strings,
391 * VerQueryValueW will always return Unicode ones. (That means everything returned for StringFileInfo requests).
392 */
393
394 /* Get the VS_FIXEDFILEINFO information, this must be the same for both A- and W-Calls */
395
396 retA = VerQueryValueA( pVersionInfoA, rootA, (LPVOID *)&pBufA, &uiLengthA );
397 ok (retA, "VerQueryValueA failed: GetLastError = %u\n", GetLastError());
398 ok ( uiLengthA == sizeof(VS_FIXEDFILEINFO), "Size (%d) doesn't match the size of the VS_FIXEDFILEINFO struct\n", uiLengthA);
399
400 if (is_unicode_enabled)
401 {
402 if(0)
403 { /* This causes Vista and w2k8 to crash */
404 retW = VerQueryValueW( pVersionInfoW, NULL, (LPVOID *)&pBufW, &uiLengthW );
405 ok (retW, "VerQueryValueW failed: GetLastError = %u\n", GetLastError());
406 }
407
408 retW = VerQueryValueW( pVersionInfoW, emptyW, (LPVOID *)&pBufW, &uiLengthW );
409 ok (retW, "VerQueryValueW failed: GetLastError = %u\n", GetLastError());
410
411 retW = VerQueryValueW( pVersionInfoW, rootW, (LPVOID *)&pBufW, &uiLengthW );
412 ok (retW, "VerQueryValueW failed: GetLastError = %u\n", GetLastError());
413 ok ( uiLengthW == sizeof(VS_FIXEDFILEINFO), "Size (%d) doesn't match the size of the VS_FIXEDFILEINFO struct\n", uiLengthW );
414
415 ok( uiLengthA == uiLengthW, "The size of VS_FIXEDFILEINFO should be the same for both A/W calls, it is (%d) vs. (%d)\n",
416 uiLengthA, uiLengthW);
417 ok( !memcmp(pBufA, pBufW, uiLengthA), "Both values should be the same, they aren't\n");
418 }
419
420 /* Get some VarFileInfo information, this must be the same for both A- and W-Calls */
421
422 retA = VerQueryValueA( pVersionInfoA, varfileinfoA, (LPVOID *)&pBufA, &uiLengthA );
423 ok (retA, "VerQueryValueA failed: GetLastError = %u\n", GetLastError());
424 ok( !memcmp(pBufA, WineVarFileInfoA, uiLengthA), "The VarFileInfo should have matched 0904e404 (non case sensitive)\n");
425
426 if (is_unicode_enabled)
427 {
428 retW = VerQueryValueW( pVersionInfoW, varfileinfoW, (LPVOID *)&pBufW, &uiLengthW );
429 ok (retW, "VerQueryValueW failed: GetLastError = %u\n", GetLastError());
430 ok( uiLengthA == uiLengthW, "The size of the VarFileInfo information should be the same for both A/W calls, it is (%d) vs. (%d)\n",
431 uiLengthA, uiLengthW);
432 ok( !memcmp(pBufA, pBufW, uiLengthA), "Both values should be the same, they aren't\n");
433 }
434
435 /* Get some StringFileInfo information, this will be ANSI for A-Calls and Unicode for W-Calls */
436
437 retA = VerQueryValueA( pVersionInfoA, FileDescriptionA, (LPVOID *)&pBufA, &uiLengthA );
438 ok (retA, "VerQueryValueA failed: GetLastError = %u\n", GetLastError());
439 ok( !lstrcmpA(WineFileDescriptionA, pBufA), "expected '%s' got '%s'\n",
440 WineFileDescriptionA, pBufA);
441
442 /* Test a second time */
443 retA = VerQueryValueA( pVersionInfoA, FileDescriptionA, (LPVOID *)&pBufA, &uiLengthA );
444 ok (retA, "VerQueryValueA failed: GetLastError = %u\n", GetLastError());
445 ok( !lstrcmpA(WineFileDescriptionA, pBufA), "expected '%s' got '%s'\n",
446 WineFileDescriptionA, pBufA);
447
448 if (is_unicode_enabled)
449 {
450 retW = VerQueryValueW( pVersionInfoW, FileDescriptionW, (LPVOID *)&pBufW, &uiLengthW );
451 ok (retW, "VerQueryValueW failed: GetLastError = %u\n", GetLastError());
452 ok( !lstrcmpW(WineFileDescriptionW, pBufW), "FileDescription should have been '%s'\n", WineFileDescriptionA);
453 }
454
455 HeapFree( GetProcessHeap(), 0, pVersionInfoA);
456 if (is_unicode_enabled)
457 HeapFree( GetProcessHeap(), 0, pVersionInfoW);
458 }
459
460 static void test_VerQueryValueA(void)
461 {
462 static const char * const value_name[] = {
463 "Product", "CompanyName", "FileDescription", "Internal",
464 "ProductVersion", "InternalName", "File", "LegalCopyright",
465 "FileVersion", "Legal", "OriginalFilename", "ProductName",
466 "Company", "Original" };
467 char *ver, *p;
468 UINT len, ret, translation, i;
469 char buf[MAX_PATH];
470
471 ret = GetModuleFileNameA(NULL, buf, sizeof(buf));
472 assert(ret);
473
474 SetLastError(0xdeadbeef);
475 len = GetFileVersionInfoSizeA(buf, NULL);
476 ok(len, "GetFileVersionInfoSizeA(%s) error %u\n", buf, GetLastError());
477
478 ver = HeapAlloc(GetProcessHeap(), 0, len);
479 assert(ver);
480
481 SetLastError(0xdeadbeef);
482 ret = GetFileVersionInfoA(buf, 0, len, ver);
483 ok(ret, "GetFileVersionInfoA error %u\n", GetLastError());
484
485 p = (char *)0xdeadbeef;
486 len = 0xdeadbeef;
487 SetLastError(0xdeadbeef);
488 ret = VerQueryValueA(ver, "\\VarFileInfo\\Translation", (LPVOID*)&p, &len);
489 ok(ret, "VerQueryValue error %u\n", GetLastError());
490 ok(len == 4, "VerQueryValue returned %u, expected 4\n", len);
491
492 translation = *(UINT *)p;
493 translation = MAKELONG(HIWORD(translation), LOWORD(translation));
494
495 p = (char *)0xdeadbeef;
496 len = 0xdeadbeef;
497 SetLastError(0xdeadbeef);
498 ret = VerQueryValueA(ver, "String", (LPVOID*)&p, &len);
499 ok(!ret, "VerQueryValue should fail\n");
500 ok(GetLastError() == ERROR_RESOURCE_TYPE_NOT_FOUND ||
501 GetLastError() == 0xdeadbeef /* NT4, W2K */,
502 "VerQueryValue returned %u\n", GetLastError());
503 ok(p == (char *)0xdeadbeef, "expected 0xdeadbeef got %p\n", p);
504 ok(len == 0, "expected 0 got %x\n", len);
505
506 p = (char *)0xdeadbeef;
507 len = 0xdeadbeef;
508 SetLastError(0xdeadbeef);
509 ret = VerQueryValueA(ver, "StringFileInfo", (LPVOID*)&p, &len);
510 ok(ret, "VerQueryValue error %u\n", GetLastError());
511 ok(len == 0, "VerQueryValue returned %u, expected 0\n", len);
512 ok(p != (char *)0xdeadbeef, "not expected 0xdeadbeef\n");
513
514 p = (char *)0xdeadbeef;
515 len = 0xdeadbeef;
516 SetLastError(0xdeadbeef);
517 ret = VerQueryValueA(ver, "\\StringFileInfo", (LPVOID*)&p, &len);
518 ok(ret, "VerQueryValue error %u\n", GetLastError());
519 ok(len == 0, "VerQueryValue returned %u, expected 0\n", len);
520 ok(p != (char *)0xdeadbeef, "not expected 0xdeadbeef\n");
521
522 p = (char *)0xdeadbeef;
523 len = 0xdeadbeef;
524 SetLastError(0xdeadbeef);
525 ret = VerQueryValueA(ver, "\\\\StringFileInfo", (LPVOID*)&p, &len);
526 ok(ret, "VerQueryValue error %u\n", GetLastError());
527 ok(len == 0, "VerQueryValue returned %u, expected 0\n", len);
528 ok(p != (char *)0xdeadbeef, "not expected 0xdeadbeef\n");
529
530 p = (char *)0xdeadbeef;
531 len = 0xdeadbeef;
532 SetLastError(0xdeadbeef);
533 ret = VerQueryValueA(ver, "\\StringFileInfo\\\\", (LPVOID*)&p, &len);
534 ok(ret, "VerQueryValue error %u\n", GetLastError());
535 ok(len == 0, "VerQueryValue returned %u, expected 0\n", len);
536 ok(p != (char *)0xdeadbeef, "not expected 0xdeadbeef\n");
537
538 sprintf(buf, "\\StringFileInfo\\%08x", translation);
539 p = (char *)0xdeadbeef;
540 len = 0xdeadbeef;
541 SetLastError(0xdeadbeef);
542 ret = VerQueryValueA(ver, buf, (LPVOID*)&p, &len);
543 ok(ret, "VerQueryValue error %u\n", GetLastError());
544 ok(len == 0, "VerQueryValue returned %u, expected 0\n", len);
545 ok(p != (char *)0xdeadbeef, "not expected 0xdeadbeef\n");
546
547 for (i = 0; i < sizeof(value_name)/sizeof(value_name[0]); i++)
548 {
549 sprintf(buf, "\\StringFileInfo\\%08x\\%s", translation, value_name[i]);
550 p = (char *)0xdeadbeef;
551 len = 0xdeadbeef;
552 SetLastError(0xdeadbeef);
553 ret = VerQueryValueA(ver, buf, (LPVOID*)&p, &len);
554 ok(ret, "VerQueryValueA(%s) error %u\n", buf, GetLastError());
555 ok(len == strlen(value_name[i]) + 1, "VerQueryValue returned %u\n", len);
556 ok(!strcmp(value_name[i], p), "expected \"%s\", got \"%s\"\n",
557 value_name[i], p);
558
559 /* test partial value names */
560 len = lstrlenA(buf);
561 buf[len - 2] = 0;
562 p = (char *)0xdeadbeef;
563 len = 0xdeadbeef;
564 SetLastError(0xdeadbeef);
565 ret = VerQueryValueA(ver, buf, (LPVOID*)&p, &len);
566 ok(!ret, "VerQueryValueA(%s) succeeded\n", buf);
567 ok(GetLastError() == ERROR_RESOURCE_TYPE_NOT_FOUND ||
568 GetLastError() == 0xdeadbeef /* NT4, W2K */,
569 "VerQueryValue returned %u\n", GetLastError());
570 ok(p == (char *)0xdeadbeef, "expected 0xdeadbeef got %p\n", p);
571 ok(len == 0, "expected 0 or 0xbeef, got %x\n", len);
572 }
573
574 HeapFree(GetProcessHeap(), 0, ver);
575 }
576
577 static void test_extra_block(void)
578 {
579 WORD extra_block[] = {
580 72, 0, 0, 'W', 'i', 'n', 'e', 'T', 'e', 's', 't', '\0',
581 24, 4, 0, 'B', 'i', 'n', 'a', 'r', 'y', '\0', 0xbeef, 0xdead,
582 24, 4, 1, 'T', 'e', 'x', 't', '\0', 'B', '-', ')', '\0',
583 };
584 char buf[MAX_PATH];
585 UINT len, ret;
586 ULONG w;
587 char *ver, *p;
588 WORD *length;
589
590 ret = GetModuleFileNameA(NULL, buf, sizeof(buf));
591 ok(ret, "GetModuleFileNameA failed\n");
592
593 len = GetFileVersionInfoSizeA(buf, NULL);
594 ok(len, "GetFileVersionInfoSizeA(%s) error %u\n", buf, GetLastError());
595
596 ver = HeapAlloc(GetProcessHeap(), 0, len + sizeof(extra_block) * 2);
597 ok(ver != NULL, "Can't allocate memory\n");
598
599 ret = GetFileVersionInfoA(buf, 0, len, ver);
600 ok(ret, "GetFileVersionInfoA error %u\n", GetLastError());
601
602 /* forge the string table, as windres dislike an extra block */
603 length = (WORD *)ver; /* see VS_VERSION_INFO_STRUCT32 for details */
604 memcpy(ver + *length, extra_block, sizeof(extra_block));
605 *length += sizeof(extra_block);
606
607 p = (char *)0xdeadbeef;
608 len = 0xdeadbeef;
609 w = 0xdeadbeef;
610 ret = VerQueryValueA(ver, "WineTest\\Binary", (LPVOID*)&p, &len);
611 ok(ret, "VerQueryValue error %u\n", GetLastError());
612 ok(len == 4, "VerQueryValue returned %u, expected 4\n", len);
613 ok(p != (char *)0xdeadbeef, "not expected 0xdeadbeef\n");
614 ok(memcmp(p, &w, sizeof(w)) == 0, "got 0x%08x, expected 0x%08x\n", *(PULONG)p, w);
615
616 p = (char *)0xdeadbeef;
617 len = 0xdeadbeef;
618 ret = VerQueryValueA(ver, "WineTest\\Text", (LPVOID*)&p, &len);
619 ok(ret, "VerQueryValue error %u\n", GetLastError());
620 ok(len == 4, "VerQueryValue returned %u, expected 4\n", len);
621 ok(p != (char *)0xdeadbeef, "not expected 0xdeadbeef\n");
622 ok(strcmp(p, "B-)") == 0, "got '%s', expected '%s'\n", p, "B-)");
623
624 HeapFree(GetProcessHeap(), 0, ver);
625 }
626
627 START_TEST(info)
628 {
629 test_info_size();
630 test_info();
631 test_32bit_win();
632 test_VerQueryValueA();
633 test_extra_block();
634 }