gdiplus: Implemented GdipSetClipRegion with basic tests.
[wine] / dlls / version / info.c
CommitLineData
9a624916 1/*
ce821773 2 * Implementation of VERSION.DLL - Version Info access
9a624916 3 *
ce821773
UW
4 * Copyright 1996,1997 Marcus Meissner
5 * Copyright 1997 David Cuthbert
6 * Copyright 1999 Ulrich Weigand
5b2810bb 7 * Copyright 2005 Paul Vriens
0799c1a7
AJ
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
360a3f91 21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
b99ab2dd 22 *
ce821773
UW
23 */
24
e37c6e18 25#include <stdarg.h>
ce821773
UW
26#include <stdlib.h>
27#include <string.h>
28
e37c6e18
AJ
29#include "windef.h"
30#include "winbase.h"
317af320 31#include "winver.h"
1ce19853 32#include "winternl.h"
b85a6adc 33#include "wine/winuser16.h"
5ea22474 34#include "wine/unicode.h"
ce821773 35#include "winerror.h"
0799c1a7 36#include "wine/debug.h"
ce821773 37
0799c1a7 38WINE_DEFAULT_DEBUG_CHANNEL(ver);
b4b9fae6 39
ce821773
UW
40/******************************************************************************
41 *
c232ce43 42 * This function will print via standard TRACE, debug info regarding
ce821773
UW
43 * the file info structure vffi.
44 * 15-Feb-1998 Dimitrie Paun (dimi@cs.toronto.edu)
45 * Added this function to clean up the code.
46 *
47 *****************************************************************************/
b940df14 48static void print_vffi_debug(const VS_FIXEDFILEINFO *vffi)
ce821773 49{
2ee26f21
DR
50 BOOL versioned_printer = FALSE;
51
52 if((vffi->dwFileType == VFT_DLL) || (vffi->dwFileType == VFT_DRV))
53 {
54 if(vffi->dwFileSubtype == VFT2_DRV_VERSIONED_PRINTER)
55 /* this is documented for newer w2k Drivers and up */
56 versioned_printer = TRUE;
57 else if( (vffi->dwFileSubtype == VFT2_DRV_PRINTER) &&
58 (vffi->dwFileVersionMS != vffi->dwProductVersionMS) &&
59 (vffi->dwFileVersionMS > 0) &&
60 (vffi->dwFileVersionMS <= 3) )
61 /* found this on NT 3.51, NT4.0 and old w2k Drivers */
62 versioned_printer = TRUE;
63 }
64
65 TRACE("structversion=%u.%u, ",
66 HIWORD(vffi->dwStrucVersion),LOWORD(vffi->dwStrucVersion));
67 if(versioned_printer)
68 {
69 WORD mode = LOWORD(vffi->dwFileVersionMS);
70 WORD ver_rev = HIWORD(vffi->dwFileVersionLS);
54b1c5e0 71 TRACE("fileversion=%u.%u.%u.%u (%s.major.minor.release), ",
2ee26f21
DR
72 (vffi->dwFileVersionMS),
73 HIBYTE(ver_rev), LOBYTE(ver_rev), LOWORD(vffi->dwFileVersionLS),
74 (mode == 3) ? "Usermode" : ((mode <= 2) ? "Kernelmode" : "?") );
75 }
76 else
77 {
78 TRACE("fileversion=%u.%u.%u.%u, ",
79 HIWORD(vffi->dwFileVersionMS),LOWORD(vffi->dwFileVersionMS),
80 HIWORD(vffi->dwFileVersionLS),LOWORD(vffi->dwFileVersionLS));
81 }
82 TRACE("productversion=%u.%u.%u.%u\n",
c232ce43 83 HIWORD(vffi->dwProductVersionMS),LOWORD(vffi->dwProductVersionMS),
2ee26f21
DR
84 HIWORD(vffi->dwProductVersionLS),LOWORD(vffi->dwProductVersionLS));
85
54b1c5e0 86 TRACE("flagmask=0x%x, flags=0x%x %s%s%s%s%s%s\n",
2ee26f21 87 vffi->dwFileFlagsMask, vffi->dwFileFlags,
c232ce43
PV
88 (vffi->dwFileFlags & VS_FF_DEBUG) ? "DEBUG," : "",
89 (vffi->dwFileFlags & VS_FF_PRERELEASE) ? "PRERELEASE," : "",
90 (vffi->dwFileFlags & VS_FF_PATCHED) ? "PATCHED," : "",
91 (vffi->dwFileFlags & VS_FF_PRIVATEBUILD) ? "PRIVATEBUILD," : "",
92 (vffi->dwFileFlags & VS_FF_INFOINFERRED) ? "INFOINFERRED," : "",
93 (vffi->dwFileFlags & VS_FF_SPECIALBUILD) ? "SPECIALBUILD," : "");
ce821773 94
c232ce43 95 TRACE("(");
ce821773 96
c232ce43
PV
97 TRACE("OS=0x%x.0x%x ", HIWORD(vffi->dwFileOS), LOWORD(vffi->dwFileOS));
98
99 switch (vffi->dwFileOS&0xFFFF0000)
100 {
101 case VOS_DOS:TRACE("DOS,");break;
102 case VOS_OS216:TRACE("OS/2-16,");break;
103 case VOS_OS232:TRACE("OS/2-32,");break;
104 case VOS_NT:TRACE("NT,");break;
105 case VOS_UNKNOWN:
106 default:
54b1c5e0 107 TRACE("UNKNOWN(0x%x),",vffi->dwFileOS&0xFFFF0000);break;
c232ce43
PV
108 }
109
110 switch (LOWORD(vffi->dwFileOS))
111 {
112 case VOS__BASE:TRACE("BASE");break;
113 case VOS__WINDOWS16:TRACE("WIN16");break;
114 case VOS__WINDOWS32:TRACE("WIN32");break;
115 case VOS__PM16:TRACE("PM16");break;
116 case VOS__PM32:TRACE("PM32");break;
117 default:
118 TRACE("UNKNOWN(0x%x)",LOWORD(vffi->dwFileOS));break;
119 }
ce821773 120
c232ce43
PV
121 TRACE(")\n");
122
123 switch (vffi->dwFileType)
124 {
125 case VFT_APP:TRACE("filetype=APP");break;
2ee26f21
DR
126 case VFT_DLL:
127 TRACE("filetype=DLL");
128 if(vffi->dwFileSubtype != 0)
129 {
130 if(versioned_printer) /* NT3.x/NT4.0 or old w2k Driver */
131 TRACE(",PRINTER");
54b1c5e0 132 TRACE(" (subtype=0x%x)", vffi->dwFileSubtype);
2ee26f21
DR
133 }
134 break;
c232ce43
PV
135 case VFT_DRV:
136 TRACE("filetype=DRV,");
137 switch(vffi->dwFileSubtype)
138 {
139 case VFT2_DRV_PRINTER:TRACE("PRINTER");break;
140 case VFT2_DRV_KEYBOARD:TRACE("KEYBOARD");break;
141 case VFT2_DRV_LANGUAGE:TRACE("LANGUAGE");break;
142 case VFT2_DRV_DISPLAY:TRACE("DISPLAY");break;
143 case VFT2_DRV_MOUSE:TRACE("MOUSE");break;
144 case VFT2_DRV_NETWORK:TRACE("NETWORK");break;
145 case VFT2_DRV_SYSTEM:TRACE("SYSTEM");break;
146 case VFT2_DRV_INSTALLABLE:TRACE("INSTALLABLE");break;
147 case VFT2_DRV_SOUND:TRACE("SOUND");break;
148 case VFT2_DRV_COMM:TRACE("COMM");break;
149 case VFT2_DRV_INPUTMETHOD:TRACE("INPUTMETHOD");break;
2ee26f21 150 case VFT2_DRV_VERSIONED_PRINTER:TRACE("VERSIONED_PRINTER");break;
c232ce43
PV
151 case VFT2_UNKNOWN:
152 default:
54b1c5e0 153 TRACE("UNKNOWN(0x%x)",vffi->dwFileSubtype);break;
c232ce43
PV
154 }
155 break;
156 case VFT_FONT:
157 TRACE("filetype=FONT,");
158 switch (vffi->dwFileSubtype)
159 {
160 case VFT2_FONT_RASTER:TRACE("RASTER");break;
161 case VFT2_FONT_VECTOR:TRACE("VECTOR");break;
162 case VFT2_FONT_TRUETYPE:TRACE("TRUETYPE");break;
54b1c5e0 163 default:TRACE("UNKNOWN(0x%x)",vffi->dwFileSubtype);break;
c232ce43
PV
164 }
165 break;
166 case VFT_VXD:TRACE("filetype=VXD");break;
167 case VFT_STATIC_LIB:TRACE("filetype=STATIC_LIB");break;
168 case VFT_UNKNOWN:
169 default:
54b1c5e0 170 TRACE("filetype=Unknown(0x%x)",vffi->dwFileType);break;
c232ce43
PV
171 }
172
173 TRACE("\n");
54b1c5e0 174 TRACE("filedate=0x%x.0x%x\n",vffi->dwFileDateMS,vffi->dwFileDateLS);
c232ce43 175}
ce821773
UW
176
177/***********************************************************************
178 * Version Info Structure
179 */
180
181typedef struct
182{
183 WORD wLength;
184 WORD wValueLength;
185 CHAR szKey[1];
186#if 0 /* variable length structure */
187 /* DWORD aligned */
188 BYTE Value[];
189 /* DWORD aligned */
4ca9d755 190 VS_VERSION_INFO_STRUCT16 Children[];
ce821773 191#endif
4ca9d755 192} VS_VERSION_INFO_STRUCT16;
ce821773
UW
193
194typedef struct
195{
196 WORD wLength;
197 WORD wValueLength;
98e33334 198 WORD wType;
ce821773
UW
199 WCHAR szKey[1];
200#if 0 /* variable length structure */
201 /* DWORD aligned */
202 BYTE Value[];
203 /* DWORD aligned */
4ca9d755 204 VS_VERSION_INFO_STRUCT32 Children[];
ce821773 205#endif
4ca9d755 206} VS_VERSION_INFO_STRUCT32;
ce821773
UW
207
208#define VersionInfoIs16( ver ) \
ab91c216 209 ( ((const VS_VERSION_INFO_STRUCT16 *)ver)->szKey[0] >= ' ' )
ce821773 210
f030d752
UW
211#define DWORD_ALIGN( base, ptr ) \
212 ( (LPBYTE)(base) + ((((LPBYTE)(ptr) - (LPBYTE)(base)) + 3) & ~3) )
c9df14d8 213
ce821773 214#define VersionInfo16_Value( ver ) \
c7e7df8b 215 DWORD_ALIGN( (ver), (ver)->szKey + strlen((ver)->szKey) + 1 )
ce821773 216#define VersionInfo32_Value( ver ) \
c7e7df8b 217 DWORD_ALIGN( (ver), (ver)->szKey + strlenW((ver)->szKey) + 1 )
ce821773
UW
218
219#define VersionInfo16_Children( ver ) \
ab91c216 220 (const VS_VERSION_INFO_STRUCT16 *)( VersionInfo16_Value( ver ) + \
ce821773
UW
221 ( ( (ver)->wValueLength + 3 ) & ~3 ) )
222#define VersionInfo32_Children( ver ) \
ab91c216 223 (const VS_VERSION_INFO_STRUCT32 *)( VersionInfo32_Value( ver ) + \
ce821773 224 ( ( (ver)->wValueLength * \
98e33334 225 ((ver)->wType? 2 : 1) + 3 ) & ~3 ) )
ce821773
UW
226
227#define VersionInfo16_Next( ver ) \
4ca9d755 228 (VS_VERSION_INFO_STRUCT16 *)( (LPBYTE)ver + (((ver)->wLength + 3) & ~3) )
ce821773 229#define VersionInfo32_Next( ver ) \
4ca9d755 230 (VS_VERSION_INFO_STRUCT32 *)( (LPBYTE)ver + (((ver)->wLength + 3) & ~3) )
ce821773 231
8f73cd14
DT
232/***********************************************************************
233 * VERSION_GetFileVersionInfo_PE [internal]
234 *
4868e715 235 * NOTE: returns size of the PE VERSION resource or 0xFFFFFFFF
97551bce 236 * in the case the file is a PE module, but VERSION_INFO not found.
8f73cd14 237 */
97551bce 238static DWORD VERSION_GetFileVersionInfo_PE( LPCWSTR filename, DWORD datasize, LPVOID data )
8f73cd14 239{
96c84497 240 const VS_FIXEDFILEINFO *vffi;
8f73cd14
DT
241 DWORD len;
242 BYTE *buf;
243 HMODULE hModule;
244 HRSRC hRsrc;
245 HGLOBAL hMem;
8f73cd14 246
97551bce 247 TRACE("%s\n", debugstr_w(filename));
8f73cd14 248
09c3d32f 249 if (!GetModuleHandleExW(0, filename, &hModule))
1ce19853 250 hModule = LoadLibraryExW(filename, 0, LOAD_LIBRARY_AS_DATAFILE);
09c3d32f 251
8f73cd14
DT
252 if(!hModule)
253 {
1ce19853 254 WARN("Could not load %s\n", debugstr_w(filename));
972c61d3 255
8f73cd14
DT
256 return 0;
257 }
258 hRsrc = FindResourceW(hModule,
259 MAKEINTRESOURCEW(VS_VERSION_INFO),
260 MAKEINTRESOURCEW(VS_FILE_INFO));
261 if(!hRsrc)
262 {
1ce19853 263 WARN("Could not find VS_VERSION_INFO in %s\n", debugstr_w(filename));
0ca9bba6 264 FreeLibrary(hModule);
4868e715 265 return 0xFFFFFFFF;
8f73cd14
DT
266 }
267 len = SizeofResource(hModule, hRsrc);
268 hMem = LoadResource(hModule, hRsrc);
269 if(!hMem)
270 {
1ce19853 271 WARN("Could not load VS_VERSION_INFO from %s\n", debugstr_w(filename));
0ca9bba6 272 FreeLibrary(hModule);
4868e715 273 return 0xFFFFFFFF;
8f73cd14
DT
274 }
275 buf = LockResource(hMem);
276
277 vffi = (VS_FIXEDFILEINFO *)VersionInfo32_Value( (VS_VERSION_INFO_STRUCT32 *)buf );
278
279 if ( vffi->dwSignature != VS_FFI_SIGNATURE )
280 {
54b1c5e0 281 WARN("vffi->dwSignature is 0x%08x, but not 0x%08lx!\n",
8f73cd14 282 vffi->dwSignature, VS_FFI_SIGNATURE );
4868e715 283 len = 0xFFFFFFFF;
8f73cd14
DT
284 goto END;
285 }
286
287 if ( TRACE_ON(ver) )
288 print_vffi_debug( vffi );
289
290 if(data)
291 {
f7e7cd4a
DT
292 if(datasize < len)
293 len = datasize; /* truncate data */
294 if(len)
8f73cd14
DT
295 memcpy(data, buf, len);
296 else
4868e715 297 len = 0xFFFFFFFF;
8f73cd14
DT
298 }
299END:
300 FreeResource(hMem);
0ca9bba6 301 FreeLibrary(hModule);
8f73cd14
DT
302
303 return len;
304}
305
306/***********************************************************************
307 * VERSION_GetFileVersionInfo_16 [internal]
308 *
4868e715 309 * NOTE: returns size of the 16-bit VERSION resource or 0xFFFFFFFF
97551bce 310 * in the case the file exists, but VERSION_INFO not found.
8f73cd14 311 */
97551bce 312static DWORD VERSION_GetFileVersionInfo_16( LPCSTR filename, DWORD datasize, LPVOID data )
8f73cd14 313{
96c84497 314 const VS_FIXEDFILEINFO *vffi;
97551bce 315 DWORD len, offset;
8f73cd14
DT
316 BYTE *buf;
317 HMODULE16 hModule;
318 HRSRC16 hRsrc;
319 HGLOBAL16 hMem;
97551bce
DT
320 char dllname[20], owner[20], *p;
321 const char *basename;
322 BOOL is_builtin = FALSE;
323
324 TRACE("%s\n", debugstr_a(filename));
8f73cd14 325
97551bce 326 /* strip path information */
8f73cd14 327
97551bce
DT
328 basename = filename;
329 if (basename[0] && basename[1] == ':') basename += 2; /* strip drive specification */
330 if ((p = strrchr( basename, '\\' ))) basename = p + 1;
331 if ((p = strrchr( basename, '/' ))) basename = p + 1;
332
333 if (strlen(basename) < sizeof(dllname)-4)
334 {
335 int file_exists;
336
337 strcpy( dllname, basename );
338 p = strrchr( dllname, '.' );
339 if (!p) strcat( dllname, ".dll" );
340 for (p = dllname; *p; p++) if (*p >= 'A' && *p <= 'Z') *p += 32;
341
342 if (wine_dll_get_owner( dllname, owner, sizeof(owner), &file_exists ) == 0)
343 is_builtin = TRUE;
344 }
345
346 /* first try without loading a 16-bit module */
347 if (is_builtin)
348 len = 0;
349 else
350 len = GetFileResourceSize16( filename,
351 MAKEINTRESOURCEA(VS_FILE_INFO),
352 MAKEINTRESOURCEA(VS_VERSION_INFO),
353 &offset );
354 if (len)
355 {
356 if (!data) return len;
357
358 len = GetFileResource16( filename,
359 MAKEINTRESOURCEA(VS_FILE_INFO),
360 MAKEINTRESOURCEA(VS_VERSION_INFO),
361 offset, datasize, data );
362 if (len)
363 {
e5503f96 364 vffi = (VS_FIXEDFILEINFO *)VersionInfo16_Value( (VS_VERSION_INFO_STRUCT16 *)data );
97551bce
DT
365
366 if ( vffi->dwSignature == VS_FFI_SIGNATURE )
367 {
368 if ( ((VS_VERSION_INFO_STRUCT16 *)data)->wLength < len )
369 len = ((VS_VERSION_INFO_STRUCT16 *)data)->wLength;
370
371 if ( TRACE_ON(ver) )
372 print_vffi_debug( vffi );
373
97551bce
DT
374 return len;
375 }
376 }
377 }
378
379 /* this might be a builtin 16-bit module */
0ca9bba6 380 hModule = LoadLibrary16(filename);
8f73cd14
DT
381 if(hModule < 32)
382 {
383 WARN("Could not load %s\n", debugstr_a(filename));
1a328d91
AS
384 if (hModule == ERROR_BAD_FORMAT)
385 return 0xFFFFFFFF;
386 else
387 return 0x0;
8f73cd14
DT
388 }
389 hRsrc = FindResource16(hModule,
390 MAKEINTRESOURCEA(VS_VERSION_INFO),
391 MAKEINTRESOURCEA(VS_FILE_INFO));
392 if(!hRsrc)
393 {
394 WARN("Could not find VS_VERSION_INFO in %s\n", debugstr_a(filename));
0ca9bba6 395 FreeLibrary16(hModule);
4868e715 396 return 0xFFFFFFFF;
8f73cd14
DT
397 }
398 len = SizeofResource16(hModule, hRsrc);
399 hMem = LoadResource16(hModule, hRsrc);
400 if(!hMem)
401 {
402 WARN("Could not load VS_VERSION_INFO from %s\n", debugstr_a(filename));
0ca9bba6 403 FreeLibrary16(hModule);
4868e715 404 return 0xFFFFFFFF;
8f73cd14
DT
405 }
406 buf = LockResource16(hMem);
407
408 if(!VersionInfoIs16(buf))
97551bce
DT
409 {
410 len = 0xFFFFFFFF;
8f73cd14 411 goto END;
97551bce 412 }
8f73cd14
DT
413
414 vffi = (VS_FIXEDFILEINFO *)VersionInfo16_Value( (VS_VERSION_INFO_STRUCT16 *)buf );
415
416 if ( vffi->dwSignature != VS_FFI_SIGNATURE )
417 {
54b1c5e0 418 WARN("vffi->dwSignature is 0x%08x, but not 0x%08lx!\n",
8f73cd14 419 vffi->dwSignature, VS_FFI_SIGNATURE );
4868e715 420 len = 0xFFFFFFFF;
8f73cd14
DT
421 goto END;
422 }
423
424 if ( TRACE_ON(ver) )
425 print_vffi_debug( vffi );
426
427 if(data)
428 {
f7e7cd4a
DT
429 if(datasize < len)
430 len = datasize; /* truncate data */
431 if(len)
8f73cd14
DT
432 memcpy(data, buf, len);
433 else
4868e715 434 len = 0xFFFFFFFF;
8f73cd14
DT
435 }
436END:
437 FreeResource16(hMem);
0ca9bba6 438 FreeLibrary16(hModule);
8f73cd14
DT
439
440 return len;
441}
ce821773
UW
442
443/***********************************************************************
1ce19853 444 * GetFileVersionInfoSizeW [VERSION.@]
ce821773 445 */
1ce19853 446DWORD WINAPI GetFileVersionInfoSizeW( LPCWSTR filename, LPDWORD handle )
ce821773 447{
97551bce 448 DWORD len;
ce821773 449
1ce19853
SL
450 TRACE("(%s,%p)\n", debugstr_w(filename), handle );
451
97551bce 452 if (handle) *handle = 0;
ce821773 453
55cc226d
DT
454 if (!filename)
455 {
456 SetLastError(ERROR_INVALID_PARAMETER);
457 return 0;
458 }
459 if (!*filename)
460 {
461 SetLastError(ERROR_BAD_PATHNAME);
462 return 0;
463 }
464
97551bce
DT
465 len = VERSION_GetFileVersionInfo_PE(filename, 0, NULL);
466 /* 0xFFFFFFFF means: file is a PE module, but VERSION_INFO not found */
1dc62b7e
FG
467 if(len == 0xFFFFFFFF)
468 {
469 SetLastError(ERROR_RESOURCE_DATA_NOT_FOUND);
97551bce 470 return 0;
1ce19853 471 }
1ce19853 472
97551bce 473 if (!len)
1dc62b7e 474 {
97551bce 475 LPSTR filenameA;
ce821773 476
97551bce
DT
477 len = WideCharToMultiByte( CP_ACP, 0, filename, -1, NULL, 0, NULL, NULL );
478 filenameA = HeapAlloc( GetProcessHeap(), 0, len );
479 WideCharToMultiByte( CP_ACP, 0, filename, -1, filenameA, len, NULL, NULL );
ce821773 480
97551bce
DT
481 len = VERSION_GetFileVersionInfo_16(filenameA, 0, NULL);
482 HeapFree( GetProcessHeap(), 0, filenameA );
483 /* 0xFFFFFFFF means: file exists, but VERSION_INFO not found */
55cc226d
DT
484 if (!len)
485 {
486 SetLastError(ERROR_FILE_NOT_FOUND);
487 return 0;
488 }
489 if (len == 0xFFFFFFFF)
97551bce
DT
490 {
491 SetLastError(ERROR_RESOURCE_DATA_NOT_FOUND);
492 return 0;
493 }
31d0e742
PV
494
495 /* We have a 16bit resource.
496 *
497 * XP/W2K/W2K3 uses a buffer which is more than the actual needed space:
498 *
499 * (info->wLength - sizeof(VS_FIXEDFILEINFO)) * 4
500 *
501 * This extra buffer is used for ANSI to Unicode conversions in W-Calls.
502 * info->wLength should be the same as len. Currently it isn't but that
96c337f0 503 * doesn't seem to be a problem (len is bigger than info->wLength).
31d0e742
PV
504 */
505 len = (len - sizeof(VS_FIXEDFILEINFO)) * 4;
506 }
507 else
508 {
509 /* We have a 32bit resource.
510 *
511 * XP/W2K/W2K3 uses a buffer which is 2 times the actual needed space + 4 bytes "FE2X"
512 * This extra buffer is used for Unicode to ANSI conversions in A-Calls
513 */
514 len = (len * 2) + 4;
ce821773
UW
515 }
516
97551bce 517 SetLastError(0);
ce821773
UW
518 return len;
519}
520
521/***********************************************************************
1ce19853 522 * GetFileVersionInfoSizeA [VERSION.@]
ce821773 523 */
1ce19853 524DWORD WINAPI GetFileVersionInfoSizeA( LPCSTR filename, LPDWORD handle )
b296b042
PV
525{
526 UNICODE_STRING filenameW;
1ce19853 527 DWORD retval;
8e541c8a
PV
528
529 TRACE("(%s,%p)\n", debugstr_a(filename), handle );
530
b296b042
PV
531 if(filename)
532 RtlCreateUnicodeStringFromAsciiz(&filenameW, filename);
533 else
534 filenameW.Buffer = NULL;
4868e715 535
b296b042 536 retval = GetFileVersionInfoSizeW(filenameW.Buffer, handle);
ce821773 537
1ce19853 538 RtlFreeUnicodeString(&filenameW);
97551bce 539
b296b042 540 return retval;
ce821773
UW
541}
542
543/***********************************************************************
8b216b3d 544 * GetFileVersionInfoW [VERSION.@]
ce821773 545 */
07b6e6e6 546BOOL WINAPI GetFileVersionInfoW( LPCWSTR filename, DWORD handle,
ce821773
UW
547 DWORD datasize, LPVOID data )
548{
97551bce 549 DWORD len;
31d0e742 550 VS_VERSION_INFO_STRUCT32* vvis = (VS_VERSION_INFO_STRUCT32*)data;
0e44f63c 551
54b1c5e0 552 TRACE("(%s,%d,size=%d,data=%p)\n",
0e44f63c 553 debugstr_w(filename), handle, datasize, data );
ce821773 554
18a1a6e1
RR
555 if (!data)
556 {
557 SetLastError(ERROR_INVALID_DATA);
558 return FALSE;
559 }
97551bce
DT
560 len = VERSION_GetFileVersionInfo_PE(filename, datasize, data);
561 /* 0xFFFFFFFF means: file is a PE module, but VERSION_INFO not found */
562 if (len == 0xFFFFFFFF)
563 {
564 SetLastError(ERROR_RESOURCE_DATA_NOT_FOUND);
565 return FALSE;
566 }
8f73cd14 567
97551bce
DT
568 if (!len)
569 {
570 LPSTR filenameA;
ce821773 571
97551bce
DT
572 len = WideCharToMultiByte( CP_ACP, 0, filename, -1, NULL, 0, NULL, NULL );
573 filenameA = HeapAlloc( GetProcessHeap(), 0, len );
574 WideCharToMultiByte( CP_ACP, 0, filename, -1, filenameA, len, NULL, NULL );
575
576 len = VERSION_GetFileVersionInfo_16(filenameA, datasize, data);
577 HeapFree( GetProcessHeap(), 0, filenameA );
578 /* 0xFFFFFFFF means: file exists, but VERSION_INFO not found */
579 if (!len || len == 0xFFFFFFFF)
580 {
581 SetLastError(ERROR_RESOURCE_DATA_NOT_FOUND);
582 return FALSE;
583 }
31d0e742
PV
584 /* We have a 16bit resource. */
585 }
586 else
587 {
0eddf434
JH
588 static const char signature[] = "FE2X";
589 DWORD bufsize = vvis->wLength + strlen(signature);
31d0e742
PV
590 DWORD convbuf;
591
592 /* We have a 32bit resource.
593 *
594 * XP/W2K/W2K3 uses a buffer which is 2 times the actual needed space + 4 bytes "FE2X"
595 * This extra buffer is used for Unicode to ANSI conversions in A-Calls
596 */
597
0eddf434
JH
598 /* information is truncated to datasize bytes */
599 if (datasize >= bufsize)
600 {
601 convbuf = datasize - vvis->wLength;
602 memcpy( ((char*)(data))+vvis->wLength, signature, convbuf > 4 ? 4 : convbuf );
603 }
97551bce 604 }
97551bce
DT
605
606 SetLastError(0);
607 return TRUE;
ce821773
UW
608}
609
b296b042
PV
610/***********************************************************************
611 * GetFileVersionInfoA [VERSION.@]
612 */
613BOOL WINAPI GetFileVersionInfoA( LPCSTR filename, DWORD handle,
614 DWORD datasize, LPVOID data )
615{
616 UNICODE_STRING filenameW;
617 BOOL retval;
111a913d 618
54b1c5e0 619 TRACE("(%s,%d,size=%d,data=%p)\n",
b296b042 620 debugstr_a(filename), handle, datasize, data );
111a913d 621
b296b042
PV
622 if(filename)
623 RtlCreateUnicodeStringFromAsciiz(&filenameW, filename);
624 else
625 filenameW.Buffer = NULL;
111a913d 626
b296b042 627 retval = GetFileVersionInfoW(filenameW.Buffer, handle, datasize, data);
111a913d 628
5b2810bb
PV
629 RtlFreeUnicodeString(&filenameW);
630
b296b042
PV
631 return retval;
632}
ce821773
UW
633
634/***********************************************************************
635 * VersionInfo16_FindChild [internal]
636 */
ab91c216 637static const VS_VERSION_INFO_STRUCT16 *VersionInfo16_FindChild( const VS_VERSION_INFO_STRUCT16 *info,
a3960292 638 LPCSTR szKey, UINT cbKey )
ce821773 639{
ab91c216 640 const VS_VERSION_INFO_STRUCT16 *child = VersionInfo16_Children( info );
ce821773 641
261e3764 642 while ((char *)child < (char *)info + info->wLength )
ce821773 643 {
31368dec 644 if (!strncasecmp( child->szKey, szKey, cbKey ) && !child->szKey[cbKey])
ce821773
UW
645 return child;
646
17d0d4e8 647 if (!(child->wLength)) return NULL;
ce821773
UW
648 child = VersionInfo16_Next( child );
649 }
650
651 return NULL;
652}
653
654/***********************************************************************
655 * VersionInfo32_FindChild [internal]
656 */
ab91c216 657static const VS_VERSION_INFO_STRUCT32 *VersionInfo32_FindChild( const VS_VERSION_INFO_STRUCT32 *info,
a3960292 658 LPCWSTR szKey, UINT cbKey )
ce821773 659{
ab91c216 660 const VS_VERSION_INFO_STRUCT32 *child = VersionInfo32_Children( info );
ce821773 661
261e3764 662 while ((char *)child < (char *)info + info->wLength )
ce821773 663 {
31368dec 664 if (!strncmpiW( child->szKey, szKey, cbKey ) && !child->szKey[cbKey])
ce821773
UW
665 return child;
666
667 child = VersionInfo32_Next( child );
668 }
669
670 return NULL;
671}
672
673/***********************************************************************
bcc80032
RS
674 * VersionInfo16_QueryValue [internal]
675 *
676 * Gets a value from a 16-bit NE resource
ce821773 677 */
ab91c216 678static BOOL WINAPI VersionInfo16_QueryValue( const VS_VERSION_INFO_STRUCT16 *info, LPCSTR lpSubBlock,
a3960292 679 LPVOID *lplpBuffer, UINT *puLen )
ce821773 680{
ce821773
UW
681 while ( *lpSubBlock )
682 {
683 /* Find next path component */
684 LPCSTR lpNextSlash;
685 for ( lpNextSlash = lpSubBlock; *lpNextSlash; lpNextSlash++ )
686 if ( *lpNextSlash == '\\' )
687 break;
688
689 /* Skip empty components */
690 if ( lpNextSlash == lpSubBlock )
691 {
692 lpSubBlock++;
693 continue;
694 }
695
696 /* We have a non-empty component: search info for key */
697 info = VersionInfo16_FindChild( info, lpSubBlock, lpNextSlash-lpSubBlock );
31368dec
DT
698 if ( !info )
699 {
700 if (puLen) *puLen = 0 ;
701 SetLastError( ERROR_RESOURCE_TYPE_NOT_FOUND );
702 return FALSE;
703 }
ce821773
UW
704
705 /* Skip path component */
706 lpSubBlock = lpNextSlash;
707 }
708
709 /* Return value */
710 *lplpBuffer = VersionInfo16_Value( info );
18a1a6e1
RR
711 if (puLen)
712 *puLen = info->wValueLength;
ce821773
UW
713
714 return TRUE;
715}
716
00d81121
PV
717/***********************************************************************
718 * VersionInfo32_QueryValue [internal]
719 *
720 * Gets a value from a 32-bit PE resource
721 */
ab91c216 722static BOOL WINAPI VersionInfo32_QueryValue( const VS_VERSION_INFO_STRUCT32 *info, LPCWSTR lpSubBlock,
00d81121
PV
723 LPVOID *lplpBuffer, UINT *puLen )
724{
725 TRACE("lpSubBlock : (%s)\n", debugstr_w(lpSubBlock));
726
727 while ( *lpSubBlock )
728 {
729 /* Find next path component */
730 LPCWSTR lpNextSlash;
731 for ( lpNextSlash = lpSubBlock; *lpNextSlash; lpNextSlash++ )
732 if ( *lpNextSlash == '\\' )
733 break;
734
735 /* Skip empty components */
736 if ( lpNextSlash == lpSubBlock )
737 {
738 lpSubBlock++;
739 continue;
740 }
741
742 /* We have a non-empty component: search info for key */
743 info = VersionInfo32_FindChild( info, lpSubBlock, lpNextSlash-lpSubBlock );
31368dec
DT
744 if ( !info )
745 {
746 if (puLen) *puLen = 0 ;
747 SetLastError( ERROR_RESOURCE_TYPE_NOT_FOUND );
748 return FALSE;
749 }
00d81121
PV
750
751 /* Skip path component */
752 lpSubBlock = lpNextSlash;
753 }
754
755 /* Return value */
756 *lplpBuffer = VersionInfo32_Value( info );
757 if (puLen)
758 *puLen = info->wValueLength;
759
760 return TRUE;
761}
762
bcc80032
RS
763/***********************************************************************
764 * VerQueryValueA [VERSION.@]
765 */
ab91c216 766BOOL WINAPI VerQueryValueA( LPCVOID pBlock, LPCSTR lpSubBlock,
015dc79c 767 LPVOID *lplpBuffer, PUINT puLen )
bcc80032 768{
111a913d
PV
769 static const char rootA[] = "\\";
770 static const char varfileinfoA[] = "\\VarFileInfo\\Translation";
ab91c216 771 const VS_VERSION_INFO_STRUCT16 *info = (const VS_VERSION_INFO_STRUCT16 *)pBlock;
bcc80032
RS
772
773 TRACE("(%p,%s,%p,%p)\n",
774 pBlock, debugstr_a(lpSubBlock), lplpBuffer, puLen );
775
e1347ecd
SE
776 if (!pBlock)
777 return FALSE;
778
bcc80032
RS
779 if ( !VersionInfoIs16( info ) )
780 {
111a913d
PV
781 BOOL ret;
782 INT len;
783 LPWSTR lpSubBlockW;
784
785 len = MultiByteToWideChar(CP_ACP, 0, lpSubBlock, -1, NULL, 0);
786 lpSubBlockW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
787
788 if (!lpSubBlockW)
789 return FALSE;
790
791 MultiByteToWideChar(CP_ACP, 0, lpSubBlock, -1, lpSubBlockW, len);
792
793 ret = VersionInfo32_QueryValue(pBlock, lpSubBlockW, lplpBuffer, puLen);
794
795 HeapFree(GetProcessHeap(), 0, lpSubBlockW);
796
2bacc463 797 if (ret && strcasecmp( lpSubBlock, rootA ) && strcasecmp( lpSubBlock, varfileinfoA ))
111a913d 798 {
ab91c216
FG
799 /* Set lpBuffer so it points to the 'empty' area where we store
800 * the converted strings
801 */
37871ce3 802 LPSTR lpBufferA = (LPSTR)pBlock + info->wLength + 4;
ab91c216 803 DWORD pos = (LPCSTR)*lplpBuffer - (LPCSTR)pBlock;
111a913d 804
37871ce3
AJ
805 len = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)*lplpBuffer, -1,
806 lpBufferA + pos, info->wLength - pos, NULL, NULL);
807 *lplpBuffer = lpBufferA + pos;
111a913d 808 *puLen = len;
111a913d 809 }
2bacc463 810 return ret;
bcc80032
RS
811 }
812
813 return VersionInfo16_QueryValue(info, lpSubBlock, lplpBuffer, puLen);
814}
815
ce821773 816/***********************************************************************
8b216b3d 817 * VerQueryValueW [VERSION.@]
ce821773 818 */
ab91c216 819BOOL WINAPI VerQueryValueW( LPCVOID pBlock, LPCWSTR lpSubBlock,
015dc79c 820 LPVOID *lplpBuffer, PUINT puLen )
ce821773 821{
111a913d
PV
822 static const WCHAR rootW[] = { '\\', 0 };
823 static const WCHAR varfileinfoW[] = { '\\','V','a','r','F','i','l','e','I','n','f','o',
824 '\\','T','r','a','n','s','l','a','t','i','o','n', 0 };
825
ab91c216 826 const VS_VERSION_INFO_STRUCT32 *info = (const VS_VERSION_INFO_STRUCT32 *)pBlock;
ce821773 827
9fe7a254 828 TRACE("(%p,%s,%p,%p)\n",
ce821773
UW
829 pBlock, debugstr_w(lpSubBlock), lplpBuffer, puLen );
830
e1347ecd
SE
831 if (!pBlock)
832 return FALSE;
833
bcc80032
RS
834 if ( VersionInfoIs16( info ) )
835 {
72fba73a 836 BOOL ret;
111a913d
PV
837 int len;
838 LPSTR lpSubBlockA;
839
840 len = WideCharToMultiByte(CP_ACP, 0, lpSubBlock, -1, NULL, 0, NULL, NULL);
841 lpSubBlockA = HeapAlloc(GetProcessHeap(), 0, len * sizeof(char));
842
bcc80032
RS
843 if (!lpSubBlockA)
844 return FALSE;
111a913d 845
bcc80032 846 WideCharToMultiByte(CP_ACP, 0, lpSubBlock, -1, lpSubBlockA, len, NULL, NULL);
111a913d 847
bcc80032 848 ret = VersionInfo16_QueryValue(pBlock, lpSubBlockA, lplpBuffer, puLen);
111a913d 849
bcc80032 850 HeapFree(GetProcessHeap(), 0, lpSubBlockA);
111a913d 851
2bacc463 852 if (ret && strcmpiW( lpSubBlock, rootW ) && strcmpiW( lpSubBlock, varfileinfoW ))
111a913d 853 {
ab91c216
FG
854 /* Set lpBuffer so it points to the 'empty' area where we store
855 * the converted strings
856 */
37871ce3 857 LPWSTR lpBufferW = (LPWSTR)((LPSTR)pBlock + info->wLength);
ab91c216 858 DWORD pos = (LPCSTR)*lplpBuffer - (LPCSTR)pBlock;
37871ce3 859 DWORD max = (info->wLength - sizeof(VS_FIXEDFILEINFO)) * 4 - info->wLength;
111a913d 860
37871ce3
AJ
861 len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)*lplpBuffer, -1,
862 lpBufferW + pos, max/sizeof(WCHAR) - pos );
863 *lplpBuffer = lpBufferW + pos;
111a913d 864 *puLen = len;
111a913d 865 }
2bacc463 866 return ret;
bcc80032
RS
867 }
868
00d81121 869 return VersionInfo32_QueryValue(info, lpSubBlock, lplpBuffer, puLen);
ce821773 870}