crypt32/tests: Fix a test failure on older crypt32.
[wine/hramrach.git] / dlls / version / info.c
blobde6dd4ba52ec512286e56911f135e3c3029bfa69
1 /*
2 * Implementation of VERSION.DLL - Version Info access
4 * Copyright 1996,1997 Marcus Meissner
5 * Copyright 1997 David Cuthbert
6 * Copyright 1999 Ulrich Weigand
7 * Copyright 2005 Paul Vriens
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.
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.
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
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include <stdarg.h>
26 #include <stdlib.h>
27 #include <string.h>
29 #include "windef.h"
30 #include "winbase.h"
31 #include "winver.h"
32 #include "winternl.h"
33 #include "lzexpand.h"
34 #include "wine/winuser16.h"
35 #include "wine/unicode.h"
36 #include "winerror.h"
37 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(ver);
41 extern DWORD find_version_resource( HFILE lzfd, DWORD *reslen, DWORD *offset );
43 /******************************************************************************
45 * This function will print via standard TRACE, debug info regarding
46 * the file info structure vffi.
47 * 15-Feb-1998 Dimitrie Paun (dimi@cs.toronto.edu)
48 * Added this function to clean up the code.
50 *****************************************************************************/
51 static void print_vffi_debug(const VS_FIXEDFILEINFO *vffi)
53 BOOL versioned_printer = FALSE;
55 if((vffi->dwFileType == VFT_DLL) || (vffi->dwFileType == VFT_DRV))
57 if(vffi->dwFileSubtype == VFT2_DRV_VERSIONED_PRINTER)
58 /* this is documented for newer w2k Drivers and up */
59 versioned_printer = TRUE;
60 else if( (vffi->dwFileSubtype == VFT2_DRV_PRINTER) &&
61 (vffi->dwFileVersionMS != vffi->dwProductVersionMS) &&
62 (vffi->dwFileVersionMS > 0) &&
63 (vffi->dwFileVersionMS <= 3) )
64 /* found this on NT 3.51, NT4.0 and old w2k Drivers */
65 versioned_printer = TRUE;
68 TRACE("structversion=%u.%u, ",
69 HIWORD(vffi->dwStrucVersion),LOWORD(vffi->dwStrucVersion));
70 if(versioned_printer)
72 WORD mode = LOWORD(vffi->dwFileVersionMS);
73 WORD ver_rev = HIWORD(vffi->dwFileVersionLS);
74 TRACE("fileversion=%u.%u.%u.%u (%s.major.minor.release), ",
75 (vffi->dwFileVersionMS),
76 HIBYTE(ver_rev), LOBYTE(ver_rev), LOWORD(vffi->dwFileVersionLS),
77 (mode == 3) ? "Usermode" : ((mode <= 2) ? "Kernelmode" : "?") );
79 else
81 TRACE("fileversion=%u.%u.%u.%u, ",
82 HIWORD(vffi->dwFileVersionMS),LOWORD(vffi->dwFileVersionMS),
83 HIWORD(vffi->dwFileVersionLS),LOWORD(vffi->dwFileVersionLS));
85 TRACE("productversion=%u.%u.%u.%u\n",
86 HIWORD(vffi->dwProductVersionMS),LOWORD(vffi->dwProductVersionMS),
87 HIWORD(vffi->dwProductVersionLS),LOWORD(vffi->dwProductVersionLS));
89 TRACE("flagmask=0x%x, flags=0x%x %s%s%s%s%s%s\n",
90 vffi->dwFileFlagsMask, vffi->dwFileFlags,
91 (vffi->dwFileFlags & VS_FF_DEBUG) ? "DEBUG," : "",
92 (vffi->dwFileFlags & VS_FF_PRERELEASE) ? "PRERELEASE," : "",
93 (vffi->dwFileFlags & VS_FF_PATCHED) ? "PATCHED," : "",
94 (vffi->dwFileFlags & VS_FF_PRIVATEBUILD) ? "PRIVATEBUILD," : "",
95 (vffi->dwFileFlags & VS_FF_INFOINFERRED) ? "INFOINFERRED," : "",
96 (vffi->dwFileFlags & VS_FF_SPECIALBUILD) ? "SPECIALBUILD," : "");
98 TRACE("(");
100 TRACE("OS=0x%x.0x%x ", HIWORD(vffi->dwFileOS), LOWORD(vffi->dwFileOS));
102 switch (vffi->dwFileOS&0xFFFF0000)
104 case VOS_DOS:TRACE("DOS,");break;
105 case VOS_OS216:TRACE("OS/2-16,");break;
106 case VOS_OS232:TRACE("OS/2-32,");break;
107 case VOS_NT:TRACE("NT,");break;
108 case VOS_UNKNOWN:
109 default:
110 TRACE("UNKNOWN(0x%x),",vffi->dwFileOS&0xFFFF0000);break;
113 switch (LOWORD(vffi->dwFileOS))
115 case VOS__BASE:TRACE("BASE");break;
116 case VOS__WINDOWS16:TRACE("WIN16");break;
117 case VOS__WINDOWS32:TRACE("WIN32");break;
118 case VOS__PM16:TRACE("PM16");break;
119 case VOS__PM32:TRACE("PM32");break;
120 default:
121 TRACE("UNKNOWN(0x%x)",LOWORD(vffi->dwFileOS));break;
124 TRACE(")\n");
126 switch (vffi->dwFileType)
128 case VFT_APP:TRACE("filetype=APP");break;
129 case VFT_DLL:
130 TRACE("filetype=DLL");
131 if(vffi->dwFileSubtype != 0)
133 if(versioned_printer) /* NT3.x/NT4.0 or old w2k Driver */
134 TRACE(",PRINTER");
135 TRACE(" (subtype=0x%x)", vffi->dwFileSubtype);
137 break;
138 case VFT_DRV:
139 TRACE("filetype=DRV,");
140 switch(vffi->dwFileSubtype)
142 case VFT2_DRV_PRINTER:TRACE("PRINTER");break;
143 case VFT2_DRV_KEYBOARD:TRACE("KEYBOARD");break;
144 case VFT2_DRV_LANGUAGE:TRACE("LANGUAGE");break;
145 case VFT2_DRV_DISPLAY:TRACE("DISPLAY");break;
146 case VFT2_DRV_MOUSE:TRACE("MOUSE");break;
147 case VFT2_DRV_NETWORK:TRACE("NETWORK");break;
148 case VFT2_DRV_SYSTEM:TRACE("SYSTEM");break;
149 case VFT2_DRV_INSTALLABLE:TRACE("INSTALLABLE");break;
150 case VFT2_DRV_SOUND:TRACE("SOUND");break;
151 case VFT2_DRV_COMM:TRACE("COMM");break;
152 case VFT2_DRV_INPUTMETHOD:TRACE("INPUTMETHOD");break;
153 case VFT2_DRV_VERSIONED_PRINTER:TRACE("VERSIONED_PRINTER");break;
154 case VFT2_UNKNOWN:
155 default:
156 TRACE("UNKNOWN(0x%x)",vffi->dwFileSubtype);break;
158 break;
159 case VFT_FONT:
160 TRACE("filetype=FONT,");
161 switch (vffi->dwFileSubtype)
163 case VFT2_FONT_RASTER:TRACE("RASTER");break;
164 case VFT2_FONT_VECTOR:TRACE("VECTOR");break;
165 case VFT2_FONT_TRUETYPE:TRACE("TRUETYPE");break;
166 default:TRACE("UNKNOWN(0x%x)",vffi->dwFileSubtype);break;
168 break;
169 case VFT_VXD:TRACE("filetype=VXD");break;
170 case VFT_STATIC_LIB:TRACE("filetype=STATIC_LIB");break;
171 case VFT_UNKNOWN:
172 default:
173 TRACE("filetype=Unknown(0x%x)",vffi->dwFileType);break;
176 TRACE("\n");
177 TRACE("filedate=0x%x.0x%x\n",vffi->dwFileDateMS,vffi->dwFileDateLS);
180 /***********************************************************************
181 * Version Info Structure
184 typedef struct
186 WORD wLength;
187 WORD wValueLength;
188 CHAR szKey[1];
189 #if 0 /* variable length structure */
190 /* DWORD aligned */
191 BYTE Value[];
192 /* DWORD aligned */
193 VS_VERSION_INFO_STRUCT16 Children[];
194 #endif
195 } VS_VERSION_INFO_STRUCT16;
197 typedef struct
199 WORD wLength;
200 WORD wValueLength;
201 WORD wType;
202 WCHAR szKey[1];
203 #if 0 /* variable length structure */
204 /* DWORD aligned */
205 BYTE Value[];
206 /* DWORD aligned */
207 VS_VERSION_INFO_STRUCT32 Children[];
208 #endif
209 } VS_VERSION_INFO_STRUCT32;
211 #define VersionInfoIs16( ver ) \
212 ( ((const VS_VERSION_INFO_STRUCT16 *)ver)->szKey[0] >= ' ' )
214 #define DWORD_ALIGN( base, ptr ) \
215 ( (LPBYTE)(base) + ((((LPBYTE)(ptr) - (LPBYTE)(base)) + 3) & ~3) )
217 #define VersionInfo16_Value( ver ) \
218 DWORD_ALIGN( (ver), (ver)->szKey + strlen((ver)->szKey) + 1 )
219 #define VersionInfo32_Value( ver ) \
220 DWORD_ALIGN( (ver), (ver)->szKey + strlenW((ver)->szKey) + 1 )
222 #define VersionInfo16_Children( ver ) \
223 (const VS_VERSION_INFO_STRUCT16 *)( VersionInfo16_Value( ver ) + \
224 ( ( (ver)->wValueLength + 3 ) & ~3 ) )
225 #define VersionInfo32_Children( ver ) \
226 (const VS_VERSION_INFO_STRUCT32 *)( VersionInfo32_Value( ver ) + \
227 ( ( (ver)->wValueLength * \
228 ((ver)->wType? 2 : 1) + 3 ) & ~3 ) )
230 #define VersionInfo16_Next( ver ) \
231 (VS_VERSION_INFO_STRUCT16 *)( (LPBYTE)ver + (((ver)->wLength + 3) & ~3) )
232 #define VersionInfo32_Next( ver ) \
233 (VS_VERSION_INFO_STRUCT32 *)( (LPBYTE)ver + (((ver)->wLength + 3) & ~3) )
235 /***********************************************************************
236 * VERSION_GetFileVersionInfo_PE [internal]
238 * NOTE: returns size of the PE VERSION resource or 0xFFFFFFFF
239 * in the case the file is a PE module, but VERSION_INFO not found.
241 static DWORD VERSION_GetFileVersionInfo_PE( LPCWSTR filename, DWORD datasize, LPVOID data )
243 const VS_FIXEDFILEINFO *vffi;
244 DWORD len;
245 BYTE *buf;
246 HMODULE hModule;
247 HRSRC hRsrc;
248 HGLOBAL hMem;
250 TRACE("%s\n", debugstr_w(filename));
252 if (!GetModuleHandleExW(0, filename, &hModule))
253 hModule = LoadLibraryExW(filename, 0, LOAD_LIBRARY_AS_DATAFILE);
255 if(!hModule)
257 WARN("Could not load %s\n", debugstr_w(filename));
259 return 0;
261 hRsrc = FindResourceW(hModule,
262 MAKEINTRESOURCEW(VS_VERSION_INFO),
263 MAKEINTRESOURCEW(VS_FILE_INFO));
264 if(!hRsrc)
266 WARN("Could not find VS_VERSION_INFO in %s\n", debugstr_w(filename));
267 FreeLibrary(hModule);
268 return 0xFFFFFFFF;
270 len = SizeofResource(hModule, hRsrc);
271 hMem = LoadResource(hModule, hRsrc);
272 if(!hMem)
274 WARN("Could not load VS_VERSION_INFO from %s\n", debugstr_w(filename));
275 FreeLibrary(hModule);
276 return 0xFFFFFFFF;
278 buf = LockResource(hMem);
280 vffi = (VS_FIXEDFILEINFO *)VersionInfo32_Value( (VS_VERSION_INFO_STRUCT32 *)buf );
282 if ( vffi->dwSignature != VS_FFI_SIGNATURE )
284 WARN("vffi->dwSignature is 0x%08x, but not 0x%08lx!\n",
285 vffi->dwSignature, VS_FFI_SIGNATURE );
286 len = 0xFFFFFFFF;
287 goto END;
290 if ( TRACE_ON(ver) )
291 print_vffi_debug( vffi );
293 if(data)
295 if(datasize < len)
296 len = datasize; /* truncate data */
297 if(len)
298 memcpy(data, buf, len);
299 else
300 len = 0xFFFFFFFF;
302 END:
303 FreeResource(hMem);
304 FreeLibrary(hModule);
306 return len;
309 /***********************************************************************
310 * VERSION_GetFileVersionInfo_16 [internal]
312 * NOTE: returns size of the 16-bit VERSION resource or 0xFFFFFFFF
313 * in the case the file exists, but VERSION_INFO not found.
315 static DWORD VERSION_GetFileVersionInfo_16( LPCSTR filename, DWORD datasize, LPVOID data )
317 const VS_FIXEDFILEINFO *vffi;
318 DWORD len, offset;
319 BYTE *buf;
320 HMODULE16 hModule;
321 HRSRC16 hRsrc;
322 HGLOBAL16 hMem;
323 char dllname[20], owner[20], *p;
324 const char *basename;
325 BOOL is_builtin = FALSE;
327 TRACE("%s\n", debugstr_a(filename));
329 /* strip path information */
331 basename = filename;
332 if (basename[0] && basename[1] == ':') basename += 2; /* strip drive specification */
333 if ((p = strrchr( basename, '\\' ))) basename = p + 1;
334 if ((p = strrchr( basename, '/' ))) basename = p + 1;
336 if (strlen(basename) < sizeof(dllname)-4)
338 int file_exists;
340 strcpy( dllname, basename );
341 p = strrchr( dllname, '.' );
342 if (!p) strcat( dllname, ".dll" );
343 for (p = dllname; *p; p++) if (*p >= 'A' && *p <= 'Z') *p += 32;
345 if (wine_dll_get_owner( dllname, owner, sizeof(owner), &file_exists ) == 0)
346 is_builtin = TRUE;
349 /* first try without loading a 16-bit module */
350 len = 0;
351 if (!is_builtin)
353 OFSTRUCT ofs;
354 HFILE lzfd = LZOpenFileA( (LPSTR)filename, &ofs, OF_READ );
356 if (lzfd >= 0)
358 if (find_version_resource( lzfd, &len, &offset ))
360 if (data)
362 LZSeek( lzfd, offset, 0 /* SEEK_SET */ );
363 len = LZRead( lzfd, data, min( len, datasize ) );
366 LZClose( lzfd );
369 if (len)
371 if (!data) return len;
373 vffi = (VS_FIXEDFILEINFO *)VersionInfo16_Value( (VS_VERSION_INFO_STRUCT16 *)data );
375 if ( vffi->dwSignature == VS_FFI_SIGNATURE )
377 if ( ((VS_VERSION_INFO_STRUCT16 *)data)->wLength < len )
378 len = ((VS_VERSION_INFO_STRUCT16 *)data)->wLength;
380 if ( TRACE_ON(ver) )
381 print_vffi_debug( vffi );
383 return len;
388 /* this might be a builtin 16-bit module */
389 hModule = LoadLibrary16(filename);
390 if(hModule < 32)
392 WARN("Could not load %s\n", debugstr_a(filename));
393 if (hModule == ERROR_BAD_FORMAT)
394 return 0xFFFFFFFF;
395 else
396 return 0x0;
398 hRsrc = FindResource16(hModule,
399 MAKEINTRESOURCEA(VS_VERSION_INFO),
400 MAKEINTRESOURCEA(VS_FILE_INFO));
401 if(!hRsrc)
403 WARN("Could not find VS_VERSION_INFO in %s\n", debugstr_a(filename));
404 FreeLibrary16(hModule);
405 return 0xFFFFFFFF;
407 len = SizeofResource16(hModule, hRsrc);
408 hMem = LoadResource16(hModule, hRsrc);
409 if(!hMem)
411 WARN("Could not load VS_VERSION_INFO from %s\n", debugstr_a(filename));
412 FreeLibrary16(hModule);
413 return 0xFFFFFFFF;
415 buf = LockResource16(hMem);
417 if(!VersionInfoIs16(buf))
419 len = 0xFFFFFFFF;
420 goto END;
423 vffi = (VS_FIXEDFILEINFO *)VersionInfo16_Value( (VS_VERSION_INFO_STRUCT16 *)buf );
425 if ( vffi->dwSignature != VS_FFI_SIGNATURE )
427 WARN("vffi->dwSignature is 0x%08x, but not 0x%08lx!\n",
428 vffi->dwSignature, VS_FFI_SIGNATURE );
429 len = 0xFFFFFFFF;
430 goto END;
433 if ( TRACE_ON(ver) )
434 print_vffi_debug( vffi );
436 if(data)
438 if(datasize < len)
439 len = datasize; /* truncate data */
440 if(len)
441 memcpy(data, buf, len);
442 else
443 len = 0xFFFFFFFF;
445 END:
446 FreeResource16(hMem);
447 FreeLibrary16(hModule);
449 return len;
452 /***********************************************************************
453 * GetFileVersionInfoSizeW [VERSION.@]
455 DWORD WINAPI GetFileVersionInfoSizeW( LPCWSTR filename, LPDWORD handle )
457 DWORD len;
459 TRACE("(%s,%p)\n", debugstr_w(filename), handle );
461 if (handle) *handle = 0;
463 if (!filename)
465 SetLastError(ERROR_INVALID_PARAMETER);
466 return 0;
468 if (!*filename)
470 SetLastError(ERROR_BAD_PATHNAME);
471 return 0;
474 len = VERSION_GetFileVersionInfo_PE(filename, 0, NULL);
475 /* 0xFFFFFFFF means: file is a PE module, but VERSION_INFO not found */
476 if(len == 0xFFFFFFFF)
478 SetLastError(ERROR_RESOURCE_DATA_NOT_FOUND);
479 return 0;
482 if (!len)
484 LPSTR filenameA;
486 len = WideCharToMultiByte( CP_ACP, 0, filename, -1, NULL, 0, NULL, NULL );
487 filenameA = HeapAlloc( GetProcessHeap(), 0, len );
488 WideCharToMultiByte( CP_ACP, 0, filename, -1, filenameA, len, NULL, NULL );
490 len = VERSION_GetFileVersionInfo_16(filenameA, 0, NULL);
491 HeapFree( GetProcessHeap(), 0, filenameA );
492 /* 0xFFFFFFFF means: file exists, but VERSION_INFO not found */
493 if (!len)
495 SetLastError(ERROR_FILE_NOT_FOUND);
496 return 0;
498 if (len == 0xFFFFFFFF)
500 SetLastError(ERROR_RESOURCE_DATA_NOT_FOUND);
501 return 0;
504 /* We have a 16bit resource.
506 * XP/W2K/W2K3 uses a buffer which is more than the actual needed space:
508 * (info->wLength - sizeof(VS_FIXEDFILEINFO)) * 4
510 * This extra buffer is used for ANSI to Unicode conversions in W-Calls.
511 * info->wLength should be the same as len. Currently it isn't but that
512 * doesn't seem to be a problem (len is bigger than info->wLength).
514 len = (len - sizeof(VS_FIXEDFILEINFO)) * 4;
516 else
518 /* We have a 32bit resource.
520 * XP/W2K/W2K3 uses a buffer which is 2 times the actual needed space + 4 bytes "FE2X"
521 * This extra buffer is used for Unicode to ANSI conversions in A-Calls
523 len = (len * 2) + 4;
526 SetLastError(0);
527 return len;
530 /***********************************************************************
531 * GetFileVersionInfoSizeA [VERSION.@]
533 DWORD WINAPI GetFileVersionInfoSizeA( LPCSTR filename, LPDWORD handle )
535 UNICODE_STRING filenameW;
536 DWORD retval;
538 TRACE("(%s,%p)\n", debugstr_a(filename), handle );
540 if(filename)
541 RtlCreateUnicodeStringFromAsciiz(&filenameW, filename);
542 else
543 filenameW.Buffer = NULL;
545 retval = GetFileVersionInfoSizeW(filenameW.Buffer, handle);
547 RtlFreeUnicodeString(&filenameW);
549 return retval;
552 /***********************************************************************
553 * GetFileVersionInfoW [VERSION.@]
555 BOOL WINAPI GetFileVersionInfoW( LPCWSTR filename, DWORD handle,
556 DWORD datasize, LPVOID data )
558 DWORD len;
559 VS_VERSION_INFO_STRUCT32* vvis = data;
561 TRACE("(%s,%d,size=%d,data=%p)\n",
562 debugstr_w(filename), handle, datasize, data );
564 if (!data)
566 SetLastError(ERROR_INVALID_DATA);
567 return FALSE;
569 len = VERSION_GetFileVersionInfo_PE(filename, datasize, data);
570 /* 0xFFFFFFFF means: file is a PE module, but VERSION_INFO not found */
571 if (len == 0xFFFFFFFF)
573 SetLastError(ERROR_RESOURCE_DATA_NOT_FOUND);
574 return FALSE;
577 if (!len)
579 LPSTR filenameA;
581 len = WideCharToMultiByte( CP_ACP, 0, filename, -1, NULL, 0, NULL, NULL );
582 filenameA = HeapAlloc( GetProcessHeap(), 0, len );
583 WideCharToMultiByte( CP_ACP, 0, filename, -1, filenameA, len, NULL, NULL );
585 len = VERSION_GetFileVersionInfo_16(filenameA, datasize, data);
586 HeapFree( GetProcessHeap(), 0, filenameA );
587 /* 0xFFFFFFFF means: file exists, but VERSION_INFO not found */
588 if (!len || len == 0xFFFFFFFF)
590 SetLastError(ERROR_RESOURCE_DATA_NOT_FOUND);
591 return FALSE;
593 /* We have a 16bit resource. */
595 else
597 static const char signature[] = "FE2X";
598 DWORD bufsize = vvis->wLength + strlen(signature);
599 DWORD convbuf;
601 /* We have a 32bit resource.
603 * XP/W2K/W2K3 uses a buffer which is 2 times the actual needed space + 4 bytes "FE2X"
604 * This extra buffer is used for Unicode to ANSI conversions in A-Calls
607 /* information is truncated to datasize bytes */
608 if (datasize >= bufsize)
610 convbuf = datasize - vvis->wLength;
611 memcpy( ((char*)(data))+vvis->wLength, signature, convbuf > 4 ? 4 : convbuf );
615 SetLastError(0);
616 return TRUE;
619 /***********************************************************************
620 * GetFileVersionInfoA [VERSION.@]
622 BOOL WINAPI GetFileVersionInfoA( LPCSTR filename, DWORD handle,
623 DWORD datasize, LPVOID data )
625 UNICODE_STRING filenameW;
626 BOOL retval;
628 TRACE("(%s,%d,size=%d,data=%p)\n",
629 debugstr_a(filename), handle, datasize, data );
631 if(filename)
632 RtlCreateUnicodeStringFromAsciiz(&filenameW, filename);
633 else
634 filenameW.Buffer = NULL;
636 retval = GetFileVersionInfoW(filenameW.Buffer, handle, datasize, data);
638 RtlFreeUnicodeString(&filenameW);
640 return retval;
643 /***********************************************************************
644 * VersionInfo16_FindChild [internal]
646 static const VS_VERSION_INFO_STRUCT16 *VersionInfo16_FindChild( const VS_VERSION_INFO_STRUCT16 *info,
647 LPCSTR szKey, UINT cbKey )
649 const VS_VERSION_INFO_STRUCT16 *child = VersionInfo16_Children( info );
651 while ((char *)child < (char *)info + info->wLength )
653 if (!strncasecmp( child->szKey, szKey, cbKey ) && !child->szKey[cbKey])
654 return child;
656 if (!(child->wLength)) return NULL;
657 child = VersionInfo16_Next( child );
660 return NULL;
663 /***********************************************************************
664 * VersionInfo32_FindChild [internal]
666 static const VS_VERSION_INFO_STRUCT32 *VersionInfo32_FindChild( const VS_VERSION_INFO_STRUCT32 *info,
667 LPCWSTR szKey, UINT cbKey )
669 const VS_VERSION_INFO_STRUCT32 *child = VersionInfo32_Children( info );
671 while ((char *)child < (char *)info + info->wLength )
673 if (!strncmpiW( child->szKey, szKey, cbKey ) && !child->szKey[cbKey])
674 return child;
676 if (!(child->wLength)) return NULL;
677 child = VersionInfo32_Next( child );
680 return NULL;
683 /***********************************************************************
684 * VersionInfo16_QueryValue [internal]
686 * Gets a value from a 16-bit NE resource
688 static BOOL VersionInfo16_QueryValue( const VS_VERSION_INFO_STRUCT16 *info, LPCSTR lpSubBlock,
689 LPVOID *lplpBuffer, UINT *puLen )
691 while ( *lpSubBlock )
693 /* Find next path component */
694 LPCSTR lpNextSlash;
695 for ( lpNextSlash = lpSubBlock; *lpNextSlash; lpNextSlash++ )
696 if ( *lpNextSlash == '\\' )
697 break;
699 /* Skip empty components */
700 if ( lpNextSlash == lpSubBlock )
702 lpSubBlock++;
703 continue;
706 /* We have a non-empty component: search info for key */
707 info = VersionInfo16_FindChild( info, lpSubBlock, lpNextSlash-lpSubBlock );
708 if ( !info )
710 if (puLen) *puLen = 0 ;
711 SetLastError( ERROR_RESOURCE_TYPE_NOT_FOUND );
712 return FALSE;
715 /* Skip path component */
716 lpSubBlock = lpNextSlash;
719 /* Return value */
720 *lplpBuffer = VersionInfo16_Value( info );
721 if (puLen)
722 *puLen = info->wValueLength;
724 return TRUE;
727 /***********************************************************************
728 * VersionInfo32_QueryValue [internal]
730 * Gets a value from a 32-bit PE resource
732 static BOOL VersionInfo32_QueryValue( const VS_VERSION_INFO_STRUCT32 *info, LPCWSTR lpSubBlock,
733 LPVOID *lplpBuffer, UINT *puLen )
735 TRACE("lpSubBlock : (%s)\n", debugstr_w(lpSubBlock));
737 while ( *lpSubBlock )
739 /* Find next path component */
740 LPCWSTR lpNextSlash;
741 for ( lpNextSlash = lpSubBlock; *lpNextSlash; lpNextSlash++ )
742 if ( *lpNextSlash == '\\' )
743 break;
745 /* Skip empty components */
746 if ( lpNextSlash == lpSubBlock )
748 lpSubBlock++;
749 continue;
752 /* We have a non-empty component: search info for key */
753 info = VersionInfo32_FindChild( info, lpSubBlock, lpNextSlash-lpSubBlock );
754 if ( !info )
756 if (puLen) *puLen = 0 ;
757 SetLastError( ERROR_RESOURCE_TYPE_NOT_FOUND );
758 return FALSE;
761 /* Skip path component */
762 lpSubBlock = lpNextSlash;
765 /* Return value */
766 *lplpBuffer = VersionInfo32_Value( info );
767 if (puLen)
768 *puLen = info->wValueLength;
770 return TRUE;
773 /***********************************************************************
774 * VerQueryValueA [VERSION.@]
776 BOOL WINAPI VerQueryValueA( LPCVOID pBlock, LPCSTR lpSubBlock,
777 LPVOID *lplpBuffer, PUINT puLen )
779 static const char rootA[] = "\\";
780 static const char varfileinfoA[] = "\\VarFileInfo\\Translation";
781 const VS_VERSION_INFO_STRUCT16 *info = pBlock;
783 TRACE("(%p,%s,%p,%p)\n",
784 pBlock, debugstr_a(lpSubBlock), lplpBuffer, puLen );
786 if (!pBlock)
787 return FALSE;
789 if (lpSubBlock == NULL || lpSubBlock[0] == '\0')
790 lpSubBlock = rootA;
792 if ( !VersionInfoIs16( info ) )
794 BOOL ret;
795 INT len;
796 LPWSTR lpSubBlockW;
798 len = MultiByteToWideChar(CP_ACP, 0, lpSubBlock, -1, NULL, 0);
799 lpSubBlockW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
801 if (!lpSubBlockW)
802 return FALSE;
804 MultiByteToWideChar(CP_ACP, 0, lpSubBlock, -1, lpSubBlockW, len);
806 ret = VersionInfo32_QueryValue(pBlock, lpSubBlockW, lplpBuffer, puLen);
808 HeapFree(GetProcessHeap(), 0, lpSubBlockW);
810 if (ret && strcasecmp( lpSubBlock, rootA ) && strcasecmp( lpSubBlock, varfileinfoA ))
812 /* Set lpBuffer so it points to the 'empty' area where we store
813 * the converted strings
815 LPSTR lpBufferA = (LPSTR)pBlock + info->wLength + 4;
816 DWORD pos = (LPCSTR)*lplpBuffer - (LPCSTR)pBlock;
818 len = WideCharToMultiByte(CP_ACP, 0, *lplpBuffer, -1,
819 lpBufferA + pos, info->wLength - pos, NULL, NULL);
820 *lplpBuffer = lpBufferA + pos;
821 *puLen = len;
823 return ret;
826 return VersionInfo16_QueryValue(info, lpSubBlock, lplpBuffer, puLen);
829 /***********************************************************************
830 * VerQueryValueW [VERSION.@]
832 BOOL WINAPI VerQueryValueW( LPCVOID pBlock, LPCWSTR lpSubBlock,
833 LPVOID *lplpBuffer, PUINT puLen )
835 static const WCHAR nullW[] = { 0 };
836 static const WCHAR rootW[] = { '\\', 0 };
837 static const WCHAR varfileinfoW[] = { '\\','V','a','r','F','i','l','e','I','n','f','o',
838 '\\','T','r','a','n','s','l','a','t','i','o','n', 0 };
840 const VS_VERSION_INFO_STRUCT32 *info = pBlock;
842 TRACE("(%p,%s,%p,%p)\n",
843 pBlock, debugstr_w(lpSubBlock), lplpBuffer, puLen );
845 if (!pBlock)
846 return FALSE;
848 if (lpSubBlock == NULL || lpSubBlock[0] == nullW[0])
849 lpSubBlock = rootW;
851 if ( VersionInfoIs16( info ) )
853 BOOL ret;
854 int len;
855 LPSTR lpSubBlockA;
857 len = WideCharToMultiByte(CP_ACP, 0, lpSubBlock, -1, NULL, 0, NULL, NULL);
858 lpSubBlockA = HeapAlloc(GetProcessHeap(), 0, len * sizeof(char));
860 if (!lpSubBlockA)
861 return FALSE;
863 WideCharToMultiByte(CP_ACP, 0, lpSubBlock, -1, lpSubBlockA, len, NULL, NULL);
865 ret = VersionInfo16_QueryValue(pBlock, lpSubBlockA, lplpBuffer, puLen);
867 HeapFree(GetProcessHeap(), 0, lpSubBlockA);
869 if (ret && strcmpiW( lpSubBlock, rootW ) && strcmpiW( lpSubBlock, varfileinfoW ))
871 /* Set lpBuffer so it points to the 'empty' area where we store
872 * the converted strings
874 LPWSTR lpBufferW = (LPWSTR)((LPSTR)pBlock + info->wLength);
875 DWORD pos = (LPCSTR)*lplpBuffer - (LPCSTR)pBlock;
876 DWORD max = (info->wLength - sizeof(VS_FIXEDFILEINFO)) * 4 - info->wLength;
878 len = MultiByteToWideChar(CP_ACP, 0, *lplpBuffer, -1,
879 lpBufferW + pos, max/sizeof(WCHAR) - pos );
880 *lplpBuffer = lpBufferW + pos;
881 *puLen = len;
883 return ret;
886 return VersionInfo32_QueryValue(info, lpSubBlock, lplpBuffer, puLen);