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
34 #include "wine/winuser16.h"
35 #include "wine/unicode.h"
37 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(ver
);
41 /******************************************************************************
43 * This function will print via standard TRACE, debug info regarding
44 * the file info structure vffi.
45 * 15-Feb-1998 Dimitrie Paun (dimi@cs.toronto.edu)
46 * Added this function to clean up the code.
48 *****************************************************************************/
49 static void print_vffi_debug(VS_FIXEDFILEINFO
*vffi
)
51 BOOL versioned_printer
= FALSE
;
53 if((vffi
->dwFileType
== VFT_DLL
) || (vffi
->dwFileType
== VFT_DRV
))
55 if(vffi
->dwFileSubtype
== VFT2_DRV_VERSIONED_PRINTER
)
56 /* this is documented for newer w2k Drivers and up */
57 versioned_printer
= TRUE
;
58 else if( (vffi
->dwFileSubtype
== VFT2_DRV_PRINTER
) &&
59 (vffi
->dwFileVersionMS
!= vffi
->dwProductVersionMS
) &&
60 (vffi
->dwFileVersionMS
> 0) &&
61 (vffi
->dwFileVersionMS
<= 3) )
62 /* found this on NT 3.51, NT4.0 and old w2k Drivers */
63 versioned_printer
= TRUE
;
66 TRACE("structversion=%u.%u, ",
67 HIWORD(vffi
->dwStrucVersion
),LOWORD(vffi
->dwStrucVersion
));
70 WORD mode
= LOWORD(vffi
->dwFileVersionMS
);
71 WORD ver_rev
= HIWORD(vffi
->dwFileVersionLS
);
72 TRACE("fileversion=%lu.%u.%u.%u (%s.major.minor.release), ",
73 (vffi
->dwFileVersionMS
),
74 HIBYTE(ver_rev
), LOBYTE(ver_rev
), LOWORD(vffi
->dwFileVersionLS
),
75 (mode
== 3) ? "Usermode" : ((mode
<= 2) ? "Kernelmode" : "?") );
79 TRACE("fileversion=%u.%u.%u.%u, ",
80 HIWORD(vffi
->dwFileVersionMS
),LOWORD(vffi
->dwFileVersionMS
),
81 HIWORD(vffi
->dwFileVersionLS
),LOWORD(vffi
->dwFileVersionLS
));
83 TRACE("productversion=%u.%u.%u.%u\n",
84 HIWORD(vffi
->dwProductVersionMS
),LOWORD(vffi
->dwProductVersionMS
),
85 HIWORD(vffi
->dwProductVersionLS
),LOWORD(vffi
->dwProductVersionLS
));
87 TRACE("flagmask=0x%lx, flags=0x%lx %s%s%s%s%s%s\n",
88 vffi
->dwFileFlagsMask
, vffi
->dwFileFlags
,
89 (vffi
->dwFileFlags
& VS_FF_DEBUG
) ? "DEBUG," : "",
90 (vffi
->dwFileFlags
& VS_FF_PRERELEASE
) ? "PRERELEASE," : "",
91 (vffi
->dwFileFlags
& VS_FF_PATCHED
) ? "PATCHED," : "",
92 (vffi
->dwFileFlags
& VS_FF_PRIVATEBUILD
) ? "PRIVATEBUILD," : "",
93 (vffi
->dwFileFlags
& VS_FF_INFOINFERRED
) ? "INFOINFERRED," : "",
94 (vffi
->dwFileFlags
& VS_FF_SPECIALBUILD
) ? "SPECIALBUILD," : "");
98 TRACE("OS=0x%x.0x%x ", HIWORD(vffi
->dwFileOS
), LOWORD(vffi
->dwFileOS
));
100 switch (vffi
->dwFileOS
&0xFFFF0000)
102 case VOS_DOS
:TRACE("DOS,");break;
103 case VOS_OS216
:TRACE("OS/2-16,");break;
104 case VOS_OS232
:TRACE("OS/2-32,");break;
105 case VOS_NT
:TRACE("NT,");break;
108 TRACE("UNKNOWN(0x%lx),",vffi
->dwFileOS
&0xFFFF0000);break;
111 switch (LOWORD(vffi
->dwFileOS
))
113 case VOS__BASE
:TRACE("BASE");break;
114 case VOS__WINDOWS16
:TRACE("WIN16");break;
115 case VOS__WINDOWS32
:TRACE("WIN32");break;
116 case VOS__PM16
:TRACE("PM16");break;
117 case VOS__PM32
:TRACE("PM32");break;
119 TRACE("UNKNOWN(0x%x)",LOWORD(vffi
->dwFileOS
));break;
124 switch (vffi
->dwFileType
)
126 case VFT_APP
:TRACE("filetype=APP");break;
128 TRACE("filetype=DLL");
129 if(vffi
->dwFileSubtype
!= 0)
131 if(versioned_printer
) /* NT3.x/NT4.0 or old w2k Driver */
133 TRACE(" (subtype=0x%lx)", vffi
->dwFileSubtype
);
137 TRACE("filetype=DRV,");
138 switch(vffi
->dwFileSubtype
)
140 case VFT2_DRV_PRINTER
:TRACE("PRINTER");break;
141 case VFT2_DRV_KEYBOARD
:TRACE("KEYBOARD");break;
142 case VFT2_DRV_LANGUAGE
:TRACE("LANGUAGE");break;
143 case VFT2_DRV_DISPLAY
:TRACE("DISPLAY");break;
144 case VFT2_DRV_MOUSE
:TRACE("MOUSE");break;
145 case VFT2_DRV_NETWORK
:TRACE("NETWORK");break;
146 case VFT2_DRV_SYSTEM
:TRACE("SYSTEM");break;
147 case VFT2_DRV_INSTALLABLE
:TRACE("INSTALLABLE");break;
148 case VFT2_DRV_SOUND
:TRACE("SOUND");break;
149 case VFT2_DRV_COMM
:TRACE("COMM");break;
150 case VFT2_DRV_INPUTMETHOD
:TRACE("INPUTMETHOD");break;
151 case VFT2_DRV_VERSIONED_PRINTER
:TRACE("VERSIONED_PRINTER");break;
154 TRACE("UNKNOWN(0x%lx)",vffi
->dwFileSubtype
);break;
158 TRACE("filetype=FONT,");
159 switch (vffi
->dwFileSubtype
)
161 case VFT2_FONT_RASTER
:TRACE("RASTER");break;
162 case VFT2_FONT_VECTOR
:TRACE("VECTOR");break;
163 case VFT2_FONT_TRUETYPE
:TRACE("TRUETYPE");break;
164 default:TRACE("UNKNOWN(0x%lx)",vffi
->dwFileSubtype
);break;
167 case VFT_VXD
:TRACE("filetype=VXD");break;
168 case VFT_STATIC_LIB
:TRACE("filetype=STATIC_LIB");break;
171 TRACE("filetype=Unknown(0x%lx)",vffi
->dwFileType
);break;
175 TRACE("filedate=0x%lx.0x%lx\n",vffi
->dwFileDateMS
,vffi
->dwFileDateLS
);
178 /***********************************************************************
179 * Version Info Structure
187 #if 0 /* variable length structure */
191 VS_VERSION_INFO_STRUCT16 Children
[];
193 } VS_VERSION_INFO_STRUCT16
;
201 #if 0 /* variable length structure */
205 VS_VERSION_INFO_STRUCT32 Children
[];
207 } VS_VERSION_INFO_STRUCT32
;
209 #define VersionInfoIs16( ver ) \
210 ( ((VS_VERSION_INFO_STRUCT16 *)ver)->szKey[0] >= ' ' )
212 #define DWORD_ALIGN( base, ptr ) \
213 ( (LPBYTE)(base) + ((((LPBYTE)(ptr) - (LPBYTE)(base)) + 3) & ~3) )
215 #define VersionInfo16_Value( ver ) \
216 DWORD_ALIGN( (ver), (ver)->szKey + strlen((ver)->szKey) + 1 )
217 #define VersionInfo32_Value( ver ) \
218 DWORD_ALIGN( (ver), (ver)->szKey + strlenW((ver)->szKey) + 1 )
220 #define VersionInfo16_Children( ver ) \
221 (VS_VERSION_INFO_STRUCT16 *)( VersionInfo16_Value( ver ) + \
222 ( ( (ver)->wValueLength + 3 ) & ~3 ) )
223 #define VersionInfo32_Children( ver ) \
224 (VS_VERSION_INFO_STRUCT32 *)( VersionInfo32_Value( ver ) + \
225 ( ( (ver)->wValueLength * \
226 ((ver)->wType? 2 : 1) + 3 ) & ~3 ) )
228 #define VersionInfo16_Next( ver ) \
229 (VS_VERSION_INFO_STRUCT16 *)( (LPBYTE)ver + (((ver)->wLength + 3) & ~3) )
230 #define VersionInfo32_Next( ver ) \
231 (VS_VERSION_INFO_STRUCT32 *)( (LPBYTE)ver + (((ver)->wLength + 3) & ~3) )
233 /***********************************************************************
234 * VERSION_GetFileVersionInfo_PE [internal]
236 * NOTE: returns size of the PE VERSION resource or 0xFFFFFFFF
237 * in the case the file is a PE module, but VERSION_INFO not found.
239 static DWORD
VERSION_GetFileVersionInfo_PE( LPCWSTR filename
, DWORD datasize
, LPVOID data
)
241 VS_FIXEDFILEINFO
*vffi
;
248 TRACE("%s\n", debugstr_w(filename
));
250 hModule
= GetModuleHandleW(filename
);
252 hModule
= LoadLibraryExW(filename
, 0, LOAD_LIBRARY_AS_DATAFILE
);
254 hModule
= LoadLibraryExW(filename
, 0, 0);
257 WARN("Could not load %s\n", debugstr_w(filename
));
260 hRsrc
= FindResourceW(hModule
,
261 MAKEINTRESOURCEW(VS_VERSION_INFO
),
262 MAKEINTRESOURCEW(VS_FILE_INFO
));
265 WARN("Could not find VS_VERSION_INFO in %s\n", debugstr_w(filename
));
266 FreeLibrary(hModule
);
269 len
= SizeofResource(hModule
, hRsrc
);
270 hMem
= LoadResource(hModule
, hRsrc
);
273 WARN("Could not load VS_VERSION_INFO from %s\n", debugstr_w(filename
));
274 FreeLibrary(hModule
);
277 buf
= LockResource(hMem
);
279 vffi
= (VS_FIXEDFILEINFO
*)VersionInfo32_Value( (VS_VERSION_INFO_STRUCT32
*)buf
);
281 if ( vffi
->dwSignature
!= VS_FFI_SIGNATURE
)
283 WARN("vffi->dwSignature is 0x%08lx, but not 0x%08lx!\n",
284 vffi
->dwSignature
, VS_FFI_SIGNATURE
);
290 print_vffi_debug( vffi
);
295 len
= datasize
; /* truncate data */
297 memcpy(data
, buf
, len
);
303 FreeLibrary(hModule
);
308 /***********************************************************************
309 * VERSION_GetFileVersionInfo_16 [internal]
311 * NOTE: returns size of the 16-bit VERSION resource or 0xFFFFFFFF
312 * in the case the file exists, but VERSION_INFO not found.
314 static DWORD
VERSION_GetFileVersionInfo_16( LPCSTR filename
, DWORD datasize
, LPVOID data
)
316 VS_FIXEDFILEINFO
*vffi
;
322 char dllname
[20], owner
[20], *p
;
323 const char *basename
;
324 BOOL is_builtin
= FALSE
;
326 TRACE("%s\n", debugstr_a(filename
));
328 /* strip path information */
331 if (basename
[0] && basename
[1] == ':') basename
+= 2; /* strip drive specification */
332 if ((p
= strrchr( basename
, '\\' ))) basename
= p
+ 1;
333 if ((p
= strrchr( basename
, '/' ))) basename
= p
+ 1;
335 if (strlen(basename
) < sizeof(dllname
)-4)
339 strcpy( dllname
, basename
);
340 p
= strrchr( dllname
, '.' );
341 if (!p
) strcat( dllname
, ".dll" );
342 for (p
= dllname
; *p
; p
++) if (*p
>= 'A' && *p
<= 'Z') *p
+= 32;
344 if (wine_dll_get_owner( dllname
, owner
, sizeof(owner
), &file_exists
) == 0)
348 /* first try without loading a 16-bit module */
352 len
= GetFileResourceSize16( filename
,
353 MAKEINTRESOURCEA(VS_FILE_INFO
),
354 MAKEINTRESOURCEA(VS_VERSION_INFO
),
358 if (!data
) return len
;
360 len
= GetFileResource16( filename
,
361 MAKEINTRESOURCEA(VS_FILE_INFO
),
362 MAKEINTRESOURCEA(VS_VERSION_INFO
),
363 offset
, datasize
, data
);
366 vffi
= (VS_FIXEDFILEINFO
*)VersionInfo16_Value( (VS_VERSION_INFO_STRUCT16
*)data
);
368 if ( vffi
->dwSignature
== VS_FFI_SIGNATURE
)
370 if ( ((VS_VERSION_INFO_STRUCT16
*)data
)->wLength
< len
)
371 len
= ((VS_VERSION_INFO_STRUCT16
*)data
)->wLength
;
374 print_vffi_debug( vffi
);
381 /* this might be a builtin 16-bit module */
382 hModule
= LoadLibrary16(filename
);
385 WARN("Could not load %s\n", debugstr_a(filename
));
388 hRsrc
= FindResource16(hModule
,
389 MAKEINTRESOURCEA(VS_VERSION_INFO
),
390 MAKEINTRESOURCEA(VS_FILE_INFO
));
393 WARN("Could not find VS_VERSION_INFO in %s\n", debugstr_a(filename
));
394 FreeLibrary16(hModule
);
397 len
= SizeofResource16(hModule
, hRsrc
);
398 hMem
= LoadResource16(hModule
, hRsrc
);
401 WARN("Could not load VS_VERSION_INFO from %s\n", debugstr_a(filename
));
402 FreeLibrary16(hModule
);
405 buf
= LockResource16(hMem
);
407 if(!VersionInfoIs16(buf
))
413 vffi
= (VS_FIXEDFILEINFO
*)VersionInfo16_Value( (VS_VERSION_INFO_STRUCT16
*)buf
);
415 if ( vffi
->dwSignature
!= VS_FFI_SIGNATURE
)
417 WARN("vffi->dwSignature is 0x%08lx, but not 0x%08lx!\n",
418 vffi
->dwSignature
, VS_FFI_SIGNATURE
);
424 print_vffi_debug( vffi
);
429 len
= datasize
; /* truncate data */
431 memcpy(data
, buf
, len
);
436 FreeResource16(hMem
);
437 FreeLibrary16(hModule
);
442 /***********************************************************************
443 * GetFileVersionInfoSizeW [VERSION.@]
445 DWORD WINAPI
GetFileVersionInfoSizeW( LPCWSTR filename
, LPDWORD handle
)
449 TRACE("(%s,%p)\n", debugstr_w(filename
), handle
);
451 if (handle
) *handle
= 0;
455 SetLastError(ERROR_INVALID_PARAMETER
);
460 SetLastError(ERROR_BAD_PATHNAME
);
464 len
= VERSION_GetFileVersionInfo_PE(filename
, 0, NULL
);
465 /* 0xFFFFFFFF means: file is a PE module, but VERSION_INFO not found */
466 if(len
== 0xFFFFFFFF)
468 SetLastError(ERROR_RESOURCE_DATA_NOT_FOUND
);
476 len
= WideCharToMultiByte( CP_ACP
, 0, filename
, -1, NULL
, 0, NULL
, NULL
);
477 filenameA
= HeapAlloc( GetProcessHeap(), 0, len
);
478 WideCharToMultiByte( CP_ACP
, 0, filename
, -1, filenameA
, len
, NULL
, NULL
);
480 len
= VERSION_GetFileVersionInfo_16(filenameA
, 0, NULL
);
481 HeapFree( GetProcessHeap(), 0, filenameA
);
482 /* 0xFFFFFFFF means: file exists, but VERSION_INFO not found */
485 SetLastError(ERROR_FILE_NOT_FOUND
);
488 if (len
== 0xFFFFFFFF)
490 SetLastError(ERROR_RESOURCE_DATA_NOT_FOUND
);
494 /* We have a 16bit resource.
496 * XP/W2K/W2K3 uses a buffer which is more than the actual needed space:
498 * (info->wLength - sizeof(VS_FIXEDFILEINFO)) * 4
500 * This extra buffer is used for ANSI to Unicode conversions in W-Calls.
501 * info->wLength should be the same as len. Currently it isn't but that
502 * doesn't seem to be a problem (len is bigger then info->wLength).
504 len
= (len
- sizeof(VS_FIXEDFILEINFO
)) * 4;
508 /* We have a 32bit resource.
510 * XP/W2K/W2K3 uses a buffer which is 2 times the actual needed space + 4 bytes "FE2X"
511 * This extra buffer is used for Unicode to ANSI conversions in A-Calls
520 /***********************************************************************
521 * GetFileVersionInfoSizeA [VERSION.@]
523 DWORD WINAPI
GetFileVersionInfoSizeA( LPCSTR filename
, LPDWORD handle
)
525 UNICODE_STRING filenameW
;
528 TRACE("(%s,%p)\n", debugstr_a(filename
), handle
);
531 RtlCreateUnicodeStringFromAsciiz(&filenameW
, filename
);
533 filenameW
.Buffer
= NULL
;
535 retval
= GetFileVersionInfoSizeW(filenameW
.Buffer
, handle
);
537 RtlFreeUnicodeString(&filenameW
);
542 /***********************************************************************
543 * GetFileVersionInfoW [VERSION.@]
545 BOOL WINAPI
GetFileVersionInfoW( LPCWSTR filename
, DWORD handle
,
546 DWORD datasize
, LPVOID data
)
549 VS_VERSION_INFO_STRUCT32
* vvis
= (VS_VERSION_INFO_STRUCT32
*)data
;
551 TRACE("(%s,%ld,size=%ld,data=%p)\n",
552 debugstr_w(filename
), handle
, datasize
, data
);
556 SetLastError(ERROR_INVALID_DATA
);
559 len
= VERSION_GetFileVersionInfo_PE(filename
, datasize
, data
);
560 /* 0xFFFFFFFF means: file is a PE module, but VERSION_INFO not found */
561 if (len
== 0xFFFFFFFF)
563 SetLastError(ERROR_RESOURCE_DATA_NOT_FOUND
);
571 len
= WideCharToMultiByte( CP_ACP
, 0, filename
, -1, NULL
, 0, NULL
, NULL
);
572 filenameA
= HeapAlloc( GetProcessHeap(), 0, len
);
573 WideCharToMultiByte( CP_ACP
, 0, filename
, -1, filenameA
, len
, NULL
, NULL
);
575 len
= VERSION_GetFileVersionInfo_16(filenameA
, datasize
, data
);
576 HeapFree( GetProcessHeap(), 0, filenameA
);
577 /* 0xFFFFFFFF means: file exists, but VERSION_INFO not found */
578 if (!len
|| len
== 0xFFFFFFFF)
580 SetLastError(ERROR_RESOURCE_DATA_NOT_FOUND
);
583 /* We have a 16bit resource. */
587 static const char signature
[] = "FE2X";
588 DWORD bufsize
= vvis
->wLength
+ strlen(signature
);
591 /* We have a 32bit resource.
593 * XP/W2K/W2K3 uses a buffer which is 2 times the actual needed space + 4 bytes "FE2X"
594 * This extra buffer is used for Unicode to ANSI conversions in A-Calls
597 /* information is truncated to datasize bytes */
598 if (datasize
>= bufsize
)
600 convbuf
= datasize
- vvis
->wLength
;
601 memcpy( ((char*)(data
))+vvis
->wLength
, signature
, convbuf
> 4 ? 4 : convbuf
);
609 /***********************************************************************
610 * GetFileVersionInfoA [VERSION.@]
612 BOOL WINAPI
GetFileVersionInfoA( LPCSTR filename
, DWORD handle
,
613 DWORD datasize
, LPVOID data
)
615 UNICODE_STRING filenameW
;
618 TRACE("(%s,%ld,size=%ld,data=%p)\n",
619 debugstr_a(filename
), handle
, datasize
, data
);
622 RtlCreateUnicodeStringFromAsciiz(&filenameW
, filename
);
624 filenameW
.Buffer
= NULL
;
626 retval
= GetFileVersionInfoW(filenameW
.Buffer
, handle
, datasize
, data
);
628 RtlFreeUnicodeString(&filenameW
);
633 /***********************************************************************
634 * VersionInfo16_FindChild [internal]
636 static VS_VERSION_INFO_STRUCT16
*VersionInfo16_FindChild( VS_VERSION_INFO_STRUCT16
*info
,
637 LPCSTR szKey
, UINT cbKey
)
639 VS_VERSION_INFO_STRUCT16
*child
= VersionInfo16_Children( info
);
641 while ((char *)child
< (char *)info
+ info
->wLength
)
643 if ( !strncasecmp( child
->szKey
, szKey
, cbKey
) )
646 if (!(child
->wLength
)) return NULL
;
647 child
= VersionInfo16_Next( child
);
653 /***********************************************************************
654 * VersionInfo32_FindChild [internal]
656 static VS_VERSION_INFO_STRUCT32
*VersionInfo32_FindChild( VS_VERSION_INFO_STRUCT32
*info
,
657 LPCWSTR szKey
, UINT cbKey
)
659 VS_VERSION_INFO_STRUCT32
*child
= VersionInfo32_Children( info
);
661 while ((char *)child
< (char *)info
+ info
->wLength
)
663 if ( !strncmpiW( child
->szKey
, szKey
, cbKey
) )
666 child
= VersionInfo32_Next( child
);
672 /***********************************************************************
673 * VersionInfo16_QueryValue [internal]
675 * Gets a value from a 16-bit NE resource
677 static BOOL WINAPI
VersionInfo16_QueryValue( VS_VERSION_INFO_STRUCT16
*info
, LPCSTR lpSubBlock
,
678 LPVOID
*lplpBuffer
, UINT
*puLen
)
680 while ( *lpSubBlock
)
682 /* Find next path component */
684 for ( lpNextSlash
= lpSubBlock
; *lpNextSlash
; lpNextSlash
++ )
685 if ( *lpNextSlash
== '\\' )
688 /* Skip empty components */
689 if ( lpNextSlash
== lpSubBlock
)
695 /* We have a non-empty component: search info for key */
696 info
= VersionInfo16_FindChild( info
, lpSubBlock
, lpNextSlash
-lpSubBlock
);
697 if ( !info
) return FALSE
;
699 /* Skip path component */
700 lpSubBlock
= lpNextSlash
;
704 *lplpBuffer
= VersionInfo16_Value( info
);
706 *puLen
= info
->wValueLength
;
711 /***********************************************************************
712 * VersionInfo32_QueryValue [internal]
714 * Gets a value from a 32-bit PE resource
716 static BOOL WINAPI
VersionInfo32_QueryValue( VS_VERSION_INFO_STRUCT32
*info
, LPCWSTR lpSubBlock
,
717 LPVOID
*lplpBuffer
, UINT
*puLen
)
719 TRACE("lpSubBlock : (%s)\n", debugstr_w(lpSubBlock
));
721 while ( *lpSubBlock
)
723 /* Find next path component */
725 for ( lpNextSlash
= lpSubBlock
; *lpNextSlash
; lpNextSlash
++ )
726 if ( *lpNextSlash
== '\\' )
729 /* Skip empty components */
730 if ( lpNextSlash
== lpSubBlock
)
736 /* We have a non-empty component: search info for key */
737 info
= VersionInfo32_FindChild( info
, lpSubBlock
, lpNextSlash
-lpSubBlock
);
738 if ( !info
) return FALSE
;
740 /* Skip path component */
741 lpSubBlock
= lpNextSlash
;
745 *lplpBuffer
= VersionInfo32_Value( info
);
747 *puLen
= info
->wValueLength
;
752 /***********************************************************************
753 * VerQueryValueA [VERSION.@]
755 BOOL WINAPI
VerQueryValueA( LPVOID pBlock
, LPSTR lpSubBlock
,
756 LPVOID
*lplpBuffer
, UINT
*puLen
)
758 static const char rootA
[] = "\\";
759 static const char varfileinfoA
[] = "\\VarFileInfo\\Translation";
760 VS_VERSION_INFO_STRUCT16
*info
= (VS_VERSION_INFO_STRUCT16
*)pBlock
;
762 TRACE("(%p,%s,%p,%p)\n",
763 pBlock
, debugstr_a(lpSubBlock
), lplpBuffer
, puLen
);
765 if ( !VersionInfoIs16( info
) )
771 len
= MultiByteToWideChar(CP_ACP
, 0, lpSubBlock
, -1, NULL
, 0);
772 lpSubBlockW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
777 MultiByteToWideChar(CP_ACP
, 0, lpSubBlock
, -1, lpSubBlockW
, len
);
779 ret
= VersionInfo32_QueryValue(pBlock
, lpSubBlockW
, lplpBuffer
, puLen
);
781 HeapFree(GetProcessHeap(), 0, lpSubBlockW
);
783 if (ret
&& strcasecmp( lpSubBlock
, rootA
) && strcasecmp( lpSubBlock
, varfileinfoA
))
785 LPSTR lpBufferA
= (LPSTR
)pBlock
+ info
->wLength
+ 4;
786 DWORD pos
= (LPSTR
)*lplpBuffer
- (LPSTR
)pBlock
;
788 len
= WideCharToMultiByte(CP_ACP
, 0, (LPCWSTR
)*lplpBuffer
, -1,
789 lpBufferA
+ pos
, info
->wLength
- pos
, NULL
, NULL
);
790 *lplpBuffer
= lpBufferA
+ pos
;
796 return VersionInfo16_QueryValue(info
, lpSubBlock
, lplpBuffer
, puLen
);
799 /***********************************************************************
800 * VerQueryValueW [VERSION.@]
802 BOOL WINAPI
VerQueryValueW( LPVOID pBlock
, LPWSTR lpSubBlock
,
803 LPVOID
*lplpBuffer
, UINT
*puLen
)
805 static const WCHAR rootW
[] = { '\\', 0 };
806 static const WCHAR varfileinfoW
[] = { '\\','V','a','r','F','i','l','e','I','n','f','o',
807 '\\','T','r','a','n','s','l','a','t','i','o','n', 0 };
809 VS_VERSION_INFO_STRUCT32
*info
= (VS_VERSION_INFO_STRUCT32
*)pBlock
;
811 TRACE("(%p,%s,%p,%p)\n",
812 pBlock
, debugstr_w(lpSubBlock
), lplpBuffer
, puLen
);
814 if ( VersionInfoIs16( info
) )
820 len
= WideCharToMultiByte(CP_ACP
, 0, lpSubBlock
, -1, NULL
, 0, NULL
, NULL
);
821 lpSubBlockA
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(char));
826 WideCharToMultiByte(CP_ACP
, 0, lpSubBlock
, -1, lpSubBlockA
, len
, NULL
, NULL
);
828 ret
= VersionInfo16_QueryValue(pBlock
, lpSubBlockA
, lplpBuffer
, puLen
);
830 HeapFree(GetProcessHeap(), 0, lpSubBlockA
);
832 if (ret
&& strcmpiW( lpSubBlock
, rootW
) && strcmpiW( lpSubBlock
, varfileinfoW
))
834 LPWSTR lpBufferW
= (LPWSTR
)((LPSTR
)pBlock
+ info
->wLength
);
835 DWORD pos
= (LPSTR
)*lplpBuffer
- (LPSTR
)pBlock
;
836 DWORD max
= (info
->wLength
- sizeof(VS_FIXEDFILEINFO
)) * 4 - info
->wLength
;
838 len
= MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)*lplpBuffer
, -1,
839 lpBufferW
+ pos
, max
/sizeof(WCHAR
) - pos
);
840 *lplpBuffer
= lpBufferW
+ pos
;
846 return VersionInfo32_QueryValue(info
, lpSubBlock
, lplpBuffer
, puLen
);