New function VersionInfo32_QueryValue.
[wine/multimedia.git] / dlls / version / info.c
blob8d7fabf51ee00b646308306547990c335a813c3f
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
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 * TODO
23 * o Verify VerQueryValue()
26 #include <stdarg.h>
27 #include <stdlib.h>
28 #include <string.h>
30 #include "windef.h"
31 #include "winbase.h"
32 #include "winreg.h"
33 #include "winver.h"
34 #include "winternl.h"
35 #include "wine/winuser16.h"
36 #include "wine/unicode.h"
37 #include "winerror.h"
38 #include "wine/debug.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(ver);
42 /******************************************************************************
44 * This function will print via standard TRACE, debug info regarding
45 * the file info structure vffi.
46 * 15-Feb-1998 Dimitrie Paun (dimi@cs.toronto.edu)
47 * Added this function to clean up the code.
49 *****************************************************************************/
50 static void print_vffi_debug(VS_FIXEDFILEINFO *vffi)
52 TRACE("structversion=%u.%u, fileversion=%u.%u.%u.%u, productversion=%u.%u.%u.%u, flagmask=0x%lx, flags=%s%s%s%s%s%s\n",
53 HIWORD(vffi->dwStrucVersion),LOWORD(vffi->dwStrucVersion),
54 HIWORD(vffi->dwFileVersionMS),LOWORD(vffi->dwFileVersionMS),
55 HIWORD(vffi->dwFileVersionLS),LOWORD(vffi->dwFileVersionLS),
56 HIWORD(vffi->dwProductVersionMS),LOWORD(vffi->dwProductVersionMS),
57 HIWORD(vffi->dwProductVersionLS),LOWORD(vffi->dwProductVersionLS),
58 vffi->dwFileFlagsMask,
59 (vffi->dwFileFlags & VS_FF_DEBUG) ? "DEBUG," : "",
60 (vffi->dwFileFlags & VS_FF_PRERELEASE) ? "PRERELEASE," : "",
61 (vffi->dwFileFlags & VS_FF_PATCHED) ? "PATCHED," : "",
62 (vffi->dwFileFlags & VS_FF_PRIVATEBUILD) ? "PRIVATEBUILD," : "",
63 (vffi->dwFileFlags & VS_FF_INFOINFERRED) ? "INFOINFERRED," : "",
64 (vffi->dwFileFlags & VS_FF_SPECIALBUILD) ? "SPECIALBUILD," : "");
66 TRACE("(");
68 TRACE("OS=0x%x.0x%x ", HIWORD(vffi->dwFileOS), LOWORD(vffi->dwFileOS));
70 switch (vffi->dwFileOS&0xFFFF0000)
72 case VOS_DOS:TRACE("DOS,");break;
73 case VOS_OS216:TRACE("OS/2-16,");break;
74 case VOS_OS232:TRACE("OS/2-32,");break;
75 case VOS_NT:TRACE("NT,");break;
76 case VOS_UNKNOWN:
77 default:
78 TRACE("UNKNOWN(0x%lx),",vffi->dwFileOS&0xFFFF0000);break;
81 switch (LOWORD(vffi->dwFileOS))
83 case VOS__BASE:TRACE("BASE");break;
84 case VOS__WINDOWS16:TRACE("WIN16");break;
85 case VOS__WINDOWS32:TRACE("WIN32");break;
86 case VOS__PM16:TRACE("PM16");break;
87 case VOS__PM32:TRACE("PM32");break;
88 default:
89 TRACE("UNKNOWN(0x%x)",LOWORD(vffi->dwFileOS));break;
92 TRACE(")\n");
94 switch (vffi->dwFileType)
96 case VFT_APP:TRACE("filetype=APP");break;
97 case VFT_DLL:TRACE("filetype=DLL");break;
98 case VFT_DRV:
99 TRACE("filetype=DRV,");
100 switch(vffi->dwFileSubtype)
102 case VFT2_DRV_PRINTER:TRACE("PRINTER");break;
103 case VFT2_DRV_KEYBOARD:TRACE("KEYBOARD");break;
104 case VFT2_DRV_LANGUAGE:TRACE("LANGUAGE");break;
105 case VFT2_DRV_DISPLAY:TRACE("DISPLAY");break;
106 case VFT2_DRV_MOUSE:TRACE("MOUSE");break;
107 case VFT2_DRV_NETWORK:TRACE("NETWORK");break;
108 case VFT2_DRV_SYSTEM:TRACE("SYSTEM");break;
109 case VFT2_DRV_INSTALLABLE:TRACE("INSTALLABLE");break;
110 case VFT2_DRV_SOUND:TRACE("SOUND");break;
111 case VFT2_DRV_COMM:TRACE("COMM");break;
112 case VFT2_DRV_INPUTMETHOD:TRACE("INPUTMETHOD");break;
113 case VFT2_UNKNOWN:
114 default:
115 TRACE("UNKNOWN(0x%lx)",vffi->dwFileSubtype);break;
117 break;
118 case VFT_FONT:
119 TRACE("filetype=FONT,");
120 switch (vffi->dwFileSubtype)
122 case VFT2_FONT_RASTER:TRACE("RASTER");break;
123 case VFT2_FONT_VECTOR:TRACE("VECTOR");break;
124 case VFT2_FONT_TRUETYPE:TRACE("TRUETYPE");break;
125 default:TRACE("UNKNOWN(0x%lx)",vffi->dwFileSubtype);break;
127 break;
128 case VFT_VXD:TRACE("filetype=VXD");break;
129 case VFT_STATIC_LIB:TRACE("filetype=STATIC_LIB");break;
130 case VFT_UNKNOWN:
131 default:
132 TRACE("filetype=Unknown(0x%lx)",vffi->dwFileType);break;
135 TRACE("\n");
136 TRACE("filedate=0x%lx.0x%lx\n",vffi->dwFileDateMS,vffi->dwFileDateLS);
139 /***********************************************************************
140 * Version Info Structure
143 typedef struct
145 WORD wLength;
146 WORD wValueLength;
147 CHAR szKey[1];
148 #if 0 /* variable length structure */
149 /* DWORD aligned */
150 BYTE Value[];
151 /* DWORD aligned */
152 VS_VERSION_INFO_STRUCT16 Children[];
153 #endif
154 } VS_VERSION_INFO_STRUCT16;
156 typedef struct
158 WORD wLength;
159 WORD wValueLength;
160 WORD wType;
161 WCHAR szKey[1];
162 #if 0 /* variable length structure */
163 /* DWORD aligned */
164 BYTE Value[];
165 /* DWORD aligned */
166 VS_VERSION_INFO_STRUCT32 Children[];
167 #endif
168 } VS_VERSION_INFO_STRUCT32;
170 #define VersionInfoIs16( ver ) \
171 ( ((VS_VERSION_INFO_STRUCT16 *)ver)->szKey[0] >= ' ' )
173 #define DWORD_ALIGN( base, ptr ) \
174 ( (LPBYTE)(base) + ((((LPBYTE)(ptr) - (LPBYTE)(base)) + 3) & ~3) )
176 #define VersionInfo16_Value( ver ) \
177 DWORD_ALIGN( (ver), (ver)->szKey + strlen((ver)->szKey) + 1 )
178 #define VersionInfo32_Value( ver ) \
179 DWORD_ALIGN( (ver), (ver)->szKey + strlenW((ver)->szKey) + 1 )
181 #define VersionInfo16_Children( ver ) \
182 (VS_VERSION_INFO_STRUCT16 *)( VersionInfo16_Value( ver ) + \
183 ( ( (ver)->wValueLength + 3 ) & ~3 ) )
184 #define VersionInfo32_Children( ver ) \
185 (VS_VERSION_INFO_STRUCT32 *)( VersionInfo32_Value( ver ) + \
186 ( ( (ver)->wValueLength * \
187 ((ver)->wType? 2 : 1) + 3 ) & ~3 ) )
189 #define VersionInfo16_Next( ver ) \
190 (VS_VERSION_INFO_STRUCT16 *)( (LPBYTE)ver + (((ver)->wLength + 3) & ~3) )
191 #define VersionInfo32_Next( ver ) \
192 (VS_VERSION_INFO_STRUCT32 *)( (LPBYTE)ver + (((ver)->wLength + 3) & ~3) )
194 /***********************************************************************
195 * ConvertVersionInfo32To16 [internal]
197 static void ConvertVersionInfo32To16( VS_VERSION_INFO_STRUCT32 *info32,
198 VS_VERSION_INFO_STRUCT16 *info16 )
200 /* Copy data onto local stack to prevent overwrites */
201 WORD wLength = info32->wLength;
202 WORD wValueLength = info32->wValueLength;
203 WORD wType = info32->wType;
204 LPBYTE lpValue = VersionInfo32_Value( info32 );
205 VS_VERSION_INFO_STRUCT32 *child32 = VersionInfo32_Children( info32 );
206 VS_VERSION_INFO_STRUCT16 *child16;
208 TRACE("Converting %p to %p\n", info32, info16 );
209 TRACE("wLength %d, wValueLength %d, wType %d, value %p, child %p\n",
210 wLength, wValueLength, wType, lpValue, child32 );
212 /* Convert key */
213 WideCharToMultiByte( CP_ACP, 0, info32->szKey, -1, info16->szKey, 0x7fffffff, NULL, NULL );
215 TRACE("Copied key from %p to %p: %s\n", info32->szKey, info16->szKey,
216 debugstr_a(info16->szKey) );
218 /* Convert value */
219 if ( wValueLength == 0 )
221 info16->wValueLength = 0;
222 TRACE("No value present\n" );
224 else if ( wType )
226 info16->wValueLength = WideCharToMultiByte( CP_ACP, 0, (LPCWSTR)lpValue, -1, NULL, 0, NULL, NULL );
227 WideCharToMultiByte( CP_ACP, 0, (LPCWSTR)lpValue, -1,
228 VersionInfo16_Value( info16 ), info16->wValueLength, NULL, NULL );
230 TRACE("Copied value from %p to %p: %s\n", lpValue,
231 VersionInfo16_Value( info16 ),
232 debugstr_a(VersionInfo16_Value( info16 )) );
234 else
236 info16->wValueLength = wValueLength;
237 memmove( VersionInfo16_Value( info16 ), lpValue, wValueLength );
239 TRACE("Copied value from %p to %p: %d bytes\n", lpValue,
240 VersionInfo16_Value( info16 ), wValueLength );
243 /* Convert children */
244 child16 = VersionInfo16_Children( info16 );
245 while ( (DWORD)child32 < (DWORD)info32 + wLength && child32->wLength != 0 )
247 VS_VERSION_INFO_STRUCT32 *nextChild = VersionInfo32_Next( child32 );
249 ConvertVersionInfo32To16( child32, child16 );
251 child16 = VersionInfo16_Next( child16 );
252 child32 = nextChild;
255 /* Fixup length */
256 info16->wLength = (DWORD)child16 - (DWORD)info16;
258 TRACE("Finished, length is %d (%p - %p)\n",
259 info16->wLength, info16, child16 );
262 /***********************************************************************
263 * VERSION_GetFileVersionInfo_PE [internal]
265 * NOTE: returns size of the PE VERSION resource or 0xFFFFFFFF
266 * in the case the file is a PE module, but VERSION_INFO not found.
268 static DWORD VERSION_GetFileVersionInfo_PE( LPCWSTR filename, DWORD datasize, LPVOID data )
270 VS_FIXEDFILEINFO *vffi;
271 DWORD len;
272 BYTE *buf;
273 HMODULE hModule;
274 HRSRC hRsrc;
275 HGLOBAL hMem;
277 TRACE("%s\n", debugstr_w(filename));
279 hModule = GetModuleHandleW(filename);
280 if(!hModule)
281 hModule = LoadLibraryExW(filename, 0, LOAD_LIBRARY_AS_DATAFILE);
282 else
283 hModule = LoadLibraryExW(filename, 0, 0);
284 if(!hModule)
286 WARN("Could not load %s\n", debugstr_w(filename));
287 return 0;
289 hRsrc = FindResourceW(hModule,
290 MAKEINTRESOURCEW(VS_VERSION_INFO),
291 MAKEINTRESOURCEW(VS_FILE_INFO));
292 if(!hRsrc)
294 WARN("Could not find VS_VERSION_INFO in %s\n", debugstr_w(filename));
295 FreeLibrary(hModule);
296 return 0xFFFFFFFF;
298 len = SizeofResource(hModule, hRsrc);
299 hMem = LoadResource(hModule, hRsrc);
300 if(!hMem)
302 WARN("Could not load VS_VERSION_INFO from %s\n", debugstr_w(filename));
303 FreeLibrary(hModule);
304 return 0xFFFFFFFF;
306 buf = LockResource(hMem);
308 vffi = (VS_FIXEDFILEINFO *)VersionInfo32_Value( (VS_VERSION_INFO_STRUCT32 *)buf );
310 if ( vffi->dwSignature != VS_FFI_SIGNATURE )
312 WARN("vffi->dwSignature is 0x%08lx, but not 0x%08lx!\n",
313 vffi->dwSignature, VS_FFI_SIGNATURE );
314 len = 0xFFFFFFFF;
315 goto END;
318 if ( TRACE_ON(ver) )
319 print_vffi_debug( vffi );
321 if(data)
323 if(datasize < len)
324 len = datasize; /* truncate data */
325 if(len)
326 memcpy(data, buf, len);
327 else
328 len = 0xFFFFFFFF;
330 END:
331 FreeResource(hMem);
332 FreeLibrary(hModule);
334 return len;
337 /***********************************************************************
338 * VERSION_GetFileVersionInfo_16 [internal]
340 * NOTE: returns size of the 16-bit VERSION resource or 0xFFFFFFFF
341 * in the case the file exists, but VERSION_INFO not found.
343 static DWORD VERSION_GetFileVersionInfo_16( LPCSTR filename, DWORD datasize, LPVOID data )
345 VS_FIXEDFILEINFO *vffi;
346 DWORD len, offset;
347 BYTE *buf;
348 HMODULE16 hModule;
349 HRSRC16 hRsrc;
350 HGLOBAL16 hMem;
351 char dllname[20], owner[20], *p;
352 const char *basename;
353 BOOL is_builtin = FALSE;
355 TRACE("%s\n", debugstr_a(filename));
357 /* strip path information */
359 basename = filename;
360 if (basename[0] && basename[1] == ':') basename += 2; /* strip drive specification */
361 if ((p = strrchr( basename, '\\' ))) basename = p + 1;
362 if ((p = strrchr( basename, '/' ))) basename = p + 1;
364 if (strlen(basename) < sizeof(dllname)-4)
366 int file_exists;
368 strcpy( dllname, basename );
369 p = strrchr( dllname, '.' );
370 if (!p) strcat( dllname, ".dll" );
371 for (p = dllname; *p; p++) if (*p >= 'A' && *p <= 'Z') *p += 32;
373 if (wine_dll_get_owner( dllname, owner, sizeof(owner), &file_exists ) == 0)
374 is_builtin = TRUE;
377 /* first try without loading a 16-bit module */
378 if (is_builtin)
379 len = 0;
380 else
381 len = GetFileResourceSize16( filename,
382 MAKEINTRESOURCEA(VS_FILE_INFO),
383 MAKEINTRESOURCEA(VS_VERSION_INFO),
384 &offset );
385 if (len)
387 if (!data) return len;
389 len = GetFileResource16( filename,
390 MAKEINTRESOURCEA(VS_FILE_INFO),
391 MAKEINTRESOURCEA(VS_VERSION_INFO),
392 offset, datasize, data );
393 if (len)
395 vffi = (VS_FIXEDFILEINFO *)VersionInfo16_Value( (VS_VERSION_INFO_STRUCT16 *)data );
397 if ( vffi->dwSignature == VS_FFI_SIGNATURE )
399 if ( ((VS_VERSION_INFO_STRUCT16 *)data)->wLength < len )
400 len = ((VS_VERSION_INFO_STRUCT16 *)data)->wLength;
402 if ( TRACE_ON(ver) )
403 print_vffi_debug( vffi );
405 return len;
410 /* this might be a builtin 16-bit module */
411 hModule = LoadLibrary16(filename);
412 if(hModule < 32)
414 WARN("Could not load %s\n", debugstr_a(filename));
415 return 0;
417 hRsrc = FindResource16(hModule,
418 MAKEINTRESOURCEA(VS_VERSION_INFO),
419 MAKEINTRESOURCEA(VS_FILE_INFO));
420 if(!hRsrc)
422 WARN("Could not find VS_VERSION_INFO in %s\n", debugstr_a(filename));
423 FreeLibrary16(hModule);
424 return 0xFFFFFFFF;
426 len = SizeofResource16(hModule, hRsrc);
427 hMem = LoadResource16(hModule, hRsrc);
428 if(!hMem)
430 WARN("Could not load VS_VERSION_INFO from %s\n", debugstr_a(filename));
431 FreeLibrary16(hModule);
432 return 0xFFFFFFFF;
434 buf = LockResource16(hMem);
436 if(!VersionInfoIs16(buf))
438 len = 0xFFFFFFFF;
439 goto END;
442 vffi = (VS_FIXEDFILEINFO *)VersionInfo16_Value( (VS_VERSION_INFO_STRUCT16 *)buf );
444 if ( vffi->dwSignature != VS_FFI_SIGNATURE )
446 WARN("vffi->dwSignature is 0x%08lx, but not 0x%08lx!\n",
447 vffi->dwSignature, VS_FFI_SIGNATURE );
448 len = 0xFFFFFFFF;
449 goto END;
452 if ( TRACE_ON(ver) )
453 print_vffi_debug( vffi );
455 if(data)
457 if(datasize < len)
458 len = datasize; /* truncate data */
459 if(len)
460 memcpy(data, buf, len);
461 else
462 len = 0xFFFFFFFF;
464 END:
465 FreeResource16(hMem);
466 FreeLibrary16(hModule);
468 return len;
471 /***********************************************************************
472 * GetFileVersionInfoSizeW [VERSION.@]
474 DWORD WINAPI GetFileVersionInfoSizeW( LPCWSTR filename, LPDWORD handle )
476 DWORD len;
478 TRACE("(%s,%p)\n", debugstr_w(filename), handle );
480 if (handle) *handle = 0;
482 if (!filename)
484 SetLastError(ERROR_INVALID_PARAMETER);
485 return 0;
487 if (!*filename)
489 SetLastError(ERROR_BAD_PATHNAME);
490 return 0;
493 len = VERSION_GetFileVersionInfo_PE(filename, 0, NULL);
494 /* 0xFFFFFFFF means: file is a PE module, but VERSION_INFO not found */
495 if(len == 0xFFFFFFFF)
497 SetLastError(ERROR_RESOURCE_DATA_NOT_FOUND);
498 return 0;
501 if (!len)
503 LPSTR filenameA;
505 len = WideCharToMultiByte( CP_ACP, 0, filename, -1, NULL, 0, NULL, NULL );
506 filenameA = HeapAlloc( GetProcessHeap(), 0, len );
507 WideCharToMultiByte( CP_ACP, 0, filename, -1, filenameA, len, NULL, NULL );
509 len = VERSION_GetFileVersionInfo_16(filenameA, 0, NULL);
510 HeapFree( GetProcessHeap(), 0, filenameA );
511 /* 0xFFFFFFFF means: file exists, but VERSION_INFO not found */
512 if (!len)
514 SetLastError(ERROR_FILE_NOT_FOUND);
515 return 0;
517 if (len == 0xFFFFFFFF)
519 SetLastError(ERROR_RESOURCE_DATA_NOT_FOUND);
520 return 0;
524 SetLastError(0);
525 return len;
528 /***********************************************************************
529 * GetFileVersionInfoSizeA [VERSION.@]
531 DWORD WINAPI GetFileVersionInfoSizeA( LPCSTR filename, LPDWORD handle )
533 UNICODE_STRING filenameW;
534 DWORD retval;
536 TRACE("(%s,%p)\n", debugstr_a(filename), handle );
538 if(filename)
539 RtlCreateUnicodeStringFromAsciiz(&filenameW, filename);
540 else
541 filenameW.Buffer = NULL;
543 retval = GetFileVersionInfoSizeW(filenameW.Buffer, handle);
545 RtlFreeUnicodeString(&filenameW);
547 return retval;
550 /***********************************************************************
551 * GetFileVersionInfoW [VERSION.@]
553 BOOL WINAPI GetFileVersionInfoW( LPCWSTR filename, DWORD handle,
554 DWORD datasize, LPVOID data )
556 DWORD len;
558 TRACE("(%s,%ld,size=%ld,data=%p)\n",
559 debugstr_w(filename), handle, datasize, data );
561 if (!data)
563 SetLastError(ERROR_INVALID_DATA);
564 return FALSE;
566 len = VERSION_GetFileVersionInfo_PE(filename, datasize, data);
567 /* 0xFFFFFFFF means: file is a PE module, but VERSION_INFO not found */
568 if (len == 0xFFFFFFFF)
570 SetLastError(ERROR_RESOURCE_DATA_NOT_FOUND);
571 return FALSE;
574 if (!len)
576 LPSTR filenameA;
578 len = WideCharToMultiByte( CP_ACP, 0, filename, -1, NULL, 0, NULL, NULL );
579 filenameA = HeapAlloc( GetProcessHeap(), 0, len );
580 WideCharToMultiByte( CP_ACP, 0, filename, -1, filenameA, len, NULL, NULL );
582 len = VERSION_GetFileVersionInfo_16(filenameA, datasize, data);
583 HeapFree( GetProcessHeap(), 0, filenameA );
584 /* 0xFFFFFFFF means: file exists, but VERSION_INFO not found */
585 if (!len || len == 0xFFFFFFFF)
587 SetLastError(ERROR_RESOURCE_DATA_NOT_FOUND);
588 return FALSE;
592 /* If we end up here we have found either 16bit or 32bit
593 * version information
596 SetLastError(0);
597 return TRUE;
600 /***********************************************************************
601 * GetFileVersionInfoA [VERSION.@]
603 BOOL WINAPI GetFileVersionInfoA( LPCSTR filename, DWORD handle,
604 DWORD datasize, LPVOID data )
606 UNICODE_STRING filenameW;
607 BOOL retval;
609 TRACE("(%s,%ld,size=%ld,data=%p)\n",
610 debugstr_a(filename), handle, datasize, data );
612 if(filename)
613 RtlCreateUnicodeStringFromAsciiz(&filenameW, filename);
614 else
615 filenameW.Buffer = NULL;
617 retval = GetFileVersionInfoW(filenameW.Buffer, handle, datasize, data);
619 return retval;
622 /***********************************************************************
623 * VersionInfo16_FindChild [internal]
625 static VS_VERSION_INFO_STRUCT16 *VersionInfo16_FindChild( VS_VERSION_INFO_STRUCT16 *info,
626 LPCSTR szKey, UINT cbKey )
628 VS_VERSION_INFO_STRUCT16 *child = VersionInfo16_Children( info );
630 while ( (DWORD)child < (DWORD)info + info->wLength )
632 if ( !strncasecmp( child->szKey, szKey, cbKey ) )
633 return child;
635 if (!(child->wLength)) return NULL;
636 child = VersionInfo16_Next( child );
639 return NULL;
642 /***********************************************************************
643 * VersionInfo32_FindChild [internal]
645 static VS_VERSION_INFO_STRUCT32 *VersionInfo32_FindChild( VS_VERSION_INFO_STRUCT32 *info,
646 LPCWSTR szKey, UINT cbKey )
648 VS_VERSION_INFO_STRUCT32 *child = VersionInfo32_Children( info );
650 while ( (DWORD)child < (DWORD)info + info->wLength )
652 if ( !strncmpiW( child->szKey, szKey, cbKey ) )
653 return child;
655 child = VersionInfo32_Next( child );
658 return NULL;
661 /***********************************************************************
662 * VersionInfo16_QueryValue [internal]
664 * Gets a value from a 16-bit NE resource
666 static BOOL WINAPI VersionInfo16_QueryValue( VS_VERSION_INFO_STRUCT16 *info, LPCSTR lpSubBlock,
667 LPVOID *lplpBuffer, UINT *puLen )
669 while ( *lpSubBlock )
671 /* Find next path component */
672 LPCSTR lpNextSlash;
673 for ( lpNextSlash = lpSubBlock; *lpNextSlash; lpNextSlash++ )
674 if ( *lpNextSlash == '\\' )
675 break;
677 /* Skip empty components */
678 if ( lpNextSlash == lpSubBlock )
680 lpSubBlock++;
681 continue;
684 /* We have a non-empty component: search info for key */
685 info = VersionInfo16_FindChild( info, lpSubBlock, lpNextSlash-lpSubBlock );
686 if ( !info ) return FALSE;
688 /* Skip path component */
689 lpSubBlock = lpNextSlash;
692 /* Return value */
693 *lplpBuffer = VersionInfo16_Value( info );
694 if (puLen)
695 *puLen = info->wValueLength;
697 return TRUE;
700 /***********************************************************************
701 * VersionInfo32_QueryValue [internal]
703 * Gets a value from a 32-bit PE resource
705 static BOOL WINAPI VersionInfo32_QueryValue( VS_VERSION_INFO_STRUCT32 *info, LPCWSTR lpSubBlock,
706 LPVOID *lplpBuffer, UINT *puLen )
708 TRACE("lpSubBlock : (%s)\n", debugstr_w(lpSubBlock));
710 while ( *lpSubBlock )
712 /* Find next path component */
713 LPCWSTR lpNextSlash;
714 for ( lpNextSlash = lpSubBlock; *lpNextSlash; lpNextSlash++ )
715 if ( *lpNextSlash == '\\' )
716 break;
718 /* Skip empty components */
719 if ( lpNextSlash == lpSubBlock )
721 lpSubBlock++;
722 continue;
725 /* We have a non-empty component: search info for key */
726 info = VersionInfo32_FindChild( info, lpSubBlock, lpNextSlash-lpSubBlock );
727 if ( !info ) return FALSE;
729 /* Skip path component */
730 lpSubBlock = lpNextSlash;
733 /* Return value */
734 *lplpBuffer = VersionInfo32_Value( info );
735 if (puLen)
736 *puLen = info->wValueLength;
738 return TRUE;
741 /***********************************************************************
742 * VerQueryValueA [VERSION.@]
744 BOOL WINAPI VerQueryValueA( LPVOID pBlock, LPCSTR lpSubBlock,
745 LPVOID *lplpBuffer, UINT *puLen )
747 VS_VERSION_INFO_STRUCT16 *info = (VS_VERSION_INFO_STRUCT16 *)pBlock;
749 TRACE("(%p,%s,%p,%p)\n",
750 pBlock, debugstr_a(lpSubBlock), lplpBuffer, puLen );
752 if ( !VersionInfoIs16( info ) )
754 /* FIXME : The conversion is maybe a bit overkill, we only need 1 value */
756 ConvertVersionInfo32To16( (VS_VERSION_INFO_STRUCT32 *)info,
757 (VS_VERSION_INFO_STRUCT16 *)info );
760 return VersionInfo16_QueryValue(info, lpSubBlock, lplpBuffer, puLen);
763 /***********************************************************************
764 * VerQueryValueW [VERSION.@]
766 BOOL WINAPI VerQueryValueW( LPVOID pBlock, LPCWSTR lpSubBlock,
767 LPVOID *lplpBuffer, UINT *puLen )
769 VS_VERSION_INFO_STRUCT32 *info = (VS_VERSION_INFO_STRUCT32 *)pBlock;
771 TRACE("(%p,%s,%p,%p)\n",
772 pBlock, debugstr_w(lpSubBlock), lplpBuffer, puLen );
774 if ( VersionInfoIs16( info ) )
776 BOOL ret;
777 int len = WideCharToMultiByte(CP_ACP, 0, lpSubBlock, -1, NULL, 0, NULL, NULL);
778 LPSTR lpSubBlockA = HeapAlloc(GetProcessHeap(), 0, len * sizeof(char));
779 if (!lpSubBlockA)
780 return FALSE;
781 WideCharToMultiByte(CP_ACP, 0, lpSubBlock, -1, lpSubBlockA, len, NULL, NULL);
782 ret = VersionInfo16_QueryValue(pBlock, lpSubBlockA, lplpBuffer, puLen);
783 HeapFree(GetProcessHeap(), 0, lpSubBlockA);
784 return ret;
787 return VersionInfo32_QueryValue(info, lpSubBlock, lplpBuffer, puLen);