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(const 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=%u.%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%x, flags=0x%x %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%x),",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%x)", 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%x)",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%x)",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%x)",vffi
->dwFileType
);break;
175 TRACE("filedate=0x%x.0x%x\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 ( ((const 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 (const VS_VERSION_INFO_STRUCT16 *)( VersionInfo16_Value( ver ) + \
222 ( ( (ver)->wValueLength + 3 ) & ~3 ) )
223 #define VersionInfo32_Children( ver ) \
224 (const 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 const VS_FIXEDFILEINFO
*vffi
;
248 TRACE("%s\n", debugstr_w(filename
));
250 if (!GetModuleHandleExW(0, filename
, &hModule
))
251 hModule
= LoadLibraryExW(filename
, 0, LOAD_LIBRARY_AS_DATAFILE
);
255 WARN("Could not load %s\n", debugstr_w(filename
));
259 hRsrc
= FindResourceW(hModule
,
260 MAKEINTRESOURCEW(VS_VERSION_INFO
),
261 MAKEINTRESOURCEW(VS_FILE_INFO
));
264 WARN("Could not find VS_VERSION_INFO in %s\n", debugstr_w(filename
));
265 FreeLibrary(hModule
);
268 len
= SizeofResource(hModule
, hRsrc
);
269 hMem
= LoadResource(hModule
, hRsrc
);
272 WARN("Could not load VS_VERSION_INFO from %s\n", debugstr_w(filename
));
273 FreeLibrary(hModule
);
276 buf
= LockResource(hMem
);
278 vffi
= (VS_FIXEDFILEINFO
*)VersionInfo32_Value( (VS_VERSION_INFO_STRUCT32
*)buf
);
280 if ( vffi
->dwSignature
!= VS_FFI_SIGNATURE
)
282 WARN("vffi->dwSignature is 0x%08x, but not 0x%08lx!\n",
283 vffi
->dwSignature
, VS_FFI_SIGNATURE
);
289 print_vffi_debug( vffi
);
294 len
= datasize
; /* truncate data */
296 memcpy(data
, buf
, len
);
302 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 const 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
));
386 if (hModule
== ERROR_BAD_FORMAT
)
391 hRsrc
= FindResource16(hModule
,
392 MAKEINTRESOURCEA(VS_VERSION_INFO
),
393 MAKEINTRESOURCEA(VS_FILE_INFO
));
396 WARN("Could not find VS_VERSION_INFO in %s\n", debugstr_a(filename
));
397 FreeLibrary16(hModule
);
400 len
= SizeofResource16(hModule
, hRsrc
);
401 hMem
= LoadResource16(hModule
, hRsrc
);
404 WARN("Could not load VS_VERSION_INFO from %s\n", debugstr_a(filename
));
405 FreeLibrary16(hModule
);
408 buf
= LockResource16(hMem
);
410 if(!VersionInfoIs16(buf
))
416 vffi
= (VS_FIXEDFILEINFO
*)VersionInfo16_Value( (VS_VERSION_INFO_STRUCT16
*)buf
);
418 if ( vffi
->dwSignature
!= VS_FFI_SIGNATURE
)
420 WARN("vffi->dwSignature is 0x%08x, but not 0x%08lx!\n",
421 vffi
->dwSignature
, VS_FFI_SIGNATURE
);
427 print_vffi_debug( vffi
);
432 len
= datasize
; /* truncate data */
434 memcpy(data
, buf
, len
);
439 FreeResource16(hMem
);
440 FreeLibrary16(hModule
);
444 #endif /* ! __REACTOS__ */
446 /***********************************************************************
447 * GetFileVersionInfoSizeW [VERSION.@]
449 DWORD WINAPI
GetFileVersionInfoSizeW( LPCWSTR filename
, LPDWORD handle
)
453 TRACE("(%s,%p)\n", debugstr_w(filename
), handle
);
455 if (handle
) *handle
= 0;
459 SetLastError(ERROR_INVALID_PARAMETER
);
464 SetLastError(ERROR_BAD_PATHNAME
);
468 len
= VERSION_GetFileVersionInfo_PE(filename
, 0, NULL
);
469 /* 0xFFFFFFFF means: file is a PE module, but VERSION_INFO not found */
470 if(len
== 0xFFFFFFFF)
472 SetLastError(ERROR_RESOURCE_DATA_NOT_FOUND
);
479 SetLastError(ERROR_FILE_NOT_FOUND
);
481 #else /* __REACTOS__ */
484 len
= WideCharToMultiByte( CP_ACP
, 0, filename
, -1, NULL
, 0, NULL
, NULL
);
485 filenameA
= HeapAlloc( GetProcessHeap(), 0, len
);
486 WideCharToMultiByte( CP_ACP
, 0, filename
, -1, filenameA
, len
, NULL
, NULL
);
488 len
= VERSION_GetFileVersionInfo_16(filenameA
, 0, NULL
);
489 HeapFree( GetProcessHeap(), 0, filenameA
);
490 /* 0xFFFFFFFF means: file exists, but VERSION_INFO not found */
493 SetLastError(ERROR_FILE_NOT_FOUND
);
496 if (len
== 0xFFFFFFFF)
498 SetLastError(ERROR_RESOURCE_DATA_NOT_FOUND
);
502 /* We have a 16bit resource.
504 * XP/W2K/W2K3 uses a buffer which is more than the actual needed space:
506 * (info->wLength - sizeof(VS_FIXEDFILEINFO)) * 4
508 * This extra buffer is used for ANSI to Unicode conversions in W-Calls.
509 * info->wLength should be the same as len. Currently it isn't but that
510 * doesn't seem to be a problem (len is bigger than info->wLength).
512 len
= (len
- sizeof(VS_FIXEDFILEINFO
)) * 4;
513 #endif /* ! __REACTOS__ */
517 /* We have a 32bit resource.
519 * XP/W2K/W2K3 uses a buffer which is 2 times the actual needed space + 4 bytes "FE2X"
520 * This extra buffer is used for Unicode to ANSI conversions in A-Calls
529 /***********************************************************************
530 * GetFileVersionInfoSizeA [VERSION.@]
532 DWORD WINAPI
GetFileVersionInfoSizeA( LPCSTR filename
, LPDWORD handle
)
534 UNICODE_STRING filenameW
;
537 TRACE("(%s,%p)\n", debugstr_a(filename
), handle
);
540 RtlCreateUnicodeStringFromAsciiz(&filenameW
, filename
);
542 filenameW
.Buffer
= NULL
;
544 retval
= GetFileVersionInfoSizeW(filenameW
.Buffer
, handle
);
546 RtlFreeUnicodeString(&filenameW
);
551 /***********************************************************************
552 * GetFileVersionInfoW [VERSION.@]
554 BOOL WINAPI
GetFileVersionInfoW( LPCWSTR filename
, DWORD handle
,
555 DWORD datasize
, LPVOID data
)
558 VS_VERSION_INFO_STRUCT32
* vvis
= data
;
560 TRACE("(%s,%d,size=%d,data=%p)\n",
561 debugstr_w(filename
), handle
, datasize
, data
);
565 SetLastError(ERROR_INVALID_DATA
);
568 len
= VERSION_GetFileVersionInfo_PE(filename
, datasize
, data
);
569 /* 0xFFFFFFFF means: file is a PE module, but VERSION_INFO not found */
570 if (len
== 0xFFFFFFFF)
572 SetLastError(ERROR_RESOURCE_DATA_NOT_FOUND
);
579 SetLastError(ERROR_RESOURCE_DATA_NOT_FOUND
);
581 #else /* __REACTOS__ */
584 len
= WideCharToMultiByte( CP_ACP
, 0, filename
, -1, NULL
, 0, NULL
, NULL
);
585 filenameA
= HeapAlloc( GetProcessHeap(), 0, len
);
586 WideCharToMultiByte( CP_ACP
, 0, filename
, -1, filenameA
, len
, NULL
, NULL
);
588 len
= VERSION_GetFileVersionInfo_16(filenameA
, datasize
, data
);
589 HeapFree( GetProcessHeap(), 0, filenameA
);
590 /* 0xFFFFFFFF means: file exists, but VERSION_INFO not found */
591 if (!len
|| len
== 0xFFFFFFFF)
593 SetLastError(ERROR_RESOURCE_DATA_NOT_FOUND
);
596 /* We have a 16bit resource. */
597 #endif /* ! __REACTOS__ */
601 static const char signature
[] = "FE2X";
602 DWORD bufsize
= vvis
->wLength
+ strlen(signature
);
605 /* We have a 32bit resource.
607 * XP/W2K/W2K3 uses a buffer which is 2 times the actual needed space + 4 bytes "FE2X"
608 * This extra buffer is used for Unicode to ANSI conversions in A-Calls
611 /* information is truncated to datasize bytes */
612 if (datasize
>= bufsize
)
614 convbuf
= datasize
- vvis
->wLength
;
615 memcpy( ((char*)(data
))+vvis
->wLength
, signature
, convbuf
> 4 ? 4 : convbuf
);
623 /***********************************************************************
624 * GetFileVersionInfoA [VERSION.@]
626 BOOL WINAPI
GetFileVersionInfoA( LPCSTR filename
, DWORD handle
,
627 DWORD datasize
, LPVOID data
)
629 UNICODE_STRING filenameW
;
632 TRACE("(%s,%d,size=%d,data=%p)\n",
633 debugstr_a(filename
), handle
, datasize
, data
);
636 RtlCreateUnicodeStringFromAsciiz(&filenameW
, filename
);
638 filenameW
.Buffer
= NULL
;
640 retval
= GetFileVersionInfoW(filenameW
.Buffer
, handle
, datasize
, data
);
642 RtlFreeUnicodeString(&filenameW
);
647 /***********************************************************************
648 * VersionInfo16_FindChild [internal]
650 static const VS_VERSION_INFO_STRUCT16
*VersionInfo16_FindChild( const VS_VERSION_INFO_STRUCT16
*info
,
651 LPCSTR szKey
, UINT cbKey
)
653 const VS_VERSION_INFO_STRUCT16
*child
= VersionInfo16_Children( info
);
655 while ((char *)child
< (char *)info
+ info
->wLength
)
657 if (!strncasecmp( child
->szKey
, szKey
, cbKey
) && !child
->szKey
[cbKey
])
660 if (!(child
->wLength
)) return NULL
;
661 child
= VersionInfo16_Next( child
);
667 /***********************************************************************
668 * VersionInfo32_FindChild [internal]
670 static const VS_VERSION_INFO_STRUCT32
*VersionInfo32_FindChild( const VS_VERSION_INFO_STRUCT32
*info
,
671 LPCWSTR szKey
, UINT cbKey
)
673 const VS_VERSION_INFO_STRUCT32
*child
= VersionInfo32_Children( info
);
675 while ((char *)child
< (char *)info
+ info
->wLength
)
677 if (!strncmpiW( child
->szKey
, szKey
, cbKey
) && !child
->szKey
[cbKey
])
680 if (!(child
->wLength
)) return NULL
;
681 child
= VersionInfo32_Next( child
);
687 /***********************************************************************
688 * VersionInfo16_QueryValue [internal]
690 * Gets a value from a 16-bit NE resource
692 static BOOL
VersionInfo16_QueryValue( const VS_VERSION_INFO_STRUCT16
*info
, LPCSTR lpSubBlock
,
693 LPVOID
*lplpBuffer
, UINT
*puLen
)
695 while ( *lpSubBlock
)
697 /* Find next path component */
699 for ( lpNextSlash
= lpSubBlock
; *lpNextSlash
; lpNextSlash
++ )
700 if ( *lpNextSlash
== '\\' )
703 /* Skip empty components */
704 if ( lpNextSlash
== lpSubBlock
)
710 /* We have a non-empty component: search info for key */
711 info
= VersionInfo16_FindChild( info
, lpSubBlock
, lpNextSlash
-lpSubBlock
);
714 if (puLen
) *puLen
= 0 ;
715 SetLastError( ERROR_RESOURCE_TYPE_NOT_FOUND
);
719 /* Skip path component */
720 lpSubBlock
= lpNextSlash
;
724 *lplpBuffer
= VersionInfo16_Value( info
);
726 *puLen
= info
->wValueLength
;
731 /***********************************************************************
732 * VersionInfo32_QueryValue [internal]
734 * Gets a value from a 32-bit PE resource
736 static BOOL
VersionInfo32_QueryValue( const VS_VERSION_INFO_STRUCT32
*info
, LPCWSTR lpSubBlock
,
737 LPVOID
*lplpBuffer
, UINT
*puLen
)
739 TRACE("lpSubBlock : (%s)\n", debugstr_w(lpSubBlock
));
741 while ( *lpSubBlock
)
743 /* Find next path component */
745 for ( lpNextSlash
= lpSubBlock
; *lpNextSlash
; lpNextSlash
++ )
746 if ( *lpNextSlash
== '\\' )
749 /* Skip empty components */
750 if ( lpNextSlash
== lpSubBlock
)
756 /* We have a non-empty component: search info for key */
757 info
= VersionInfo32_FindChild( info
, lpSubBlock
, lpNextSlash
-lpSubBlock
);
760 if (puLen
) *puLen
= 0 ;
761 SetLastError( ERROR_RESOURCE_TYPE_NOT_FOUND
);
765 /* Skip path component */
766 lpSubBlock
= lpNextSlash
;
770 *lplpBuffer
= VersionInfo32_Value( info
);
772 *puLen
= info
->wValueLength
;
777 /***********************************************************************
778 * VerQueryValueA [VERSION.@]
780 BOOL WINAPI
VerQueryValueA( LPCVOID pBlock
, LPCSTR lpSubBlock
,
781 LPVOID
*lplpBuffer
, PUINT puLen
)
783 static const char rootA
[] = "\\";
784 static const char varfileinfoA
[] = "\\VarFileInfo\\Translation";
785 const VS_VERSION_INFO_STRUCT16
*info
= pBlock
;
787 TRACE("(%p,%s,%p,%p)\n",
788 pBlock
, debugstr_a(lpSubBlock
), lplpBuffer
, puLen
);
793 if (lpSubBlock
== NULL
|| lpSubBlock
[0] == '\0')
796 if ( !VersionInfoIs16( info
) )
802 len
= MultiByteToWideChar(CP_ACP
, 0, lpSubBlock
, -1, NULL
, 0);
803 lpSubBlockW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
808 MultiByteToWideChar(CP_ACP
, 0, lpSubBlock
, -1, lpSubBlockW
, len
);
810 ret
= VersionInfo32_QueryValue(pBlock
, lpSubBlockW
, lplpBuffer
, puLen
);
812 HeapFree(GetProcessHeap(), 0, lpSubBlockW
);
814 if (ret
&& strcasecmp( lpSubBlock
, rootA
) && strcasecmp( lpSubBlock
, varfileinfoA
))
816 /* Set lpBuffer so it points to the 'empty' area where we store
817 * the converted strings
819 LPSTR lpBufferA
= (LPSTR
)pBlock
+ info
->wLength
+ 4;
820 DWORD pos
= (LPCSTR
)*lplpBuffer
- (LPCSTR
)pBlock
;
822 len
= WideCharToMultiByte(CP_ACP
, 0, *lplpBuffer
, -1,
823 lpBufferA
+ pos
, info
->wLength
- pos
, NULL
, NULL
);
824 *lplpBuffer
= lpBufferA
+ pos
;
830 return VersionInfo16_QueryValue(info
, lpSubBlock
, lplpBuffer
, puLen
);
833 /***********************************************************************
834 * VerQueryValueW [VERSION.@]
836 BOOL WINAPI
VerQueryValueW( LPCVOID pBlock
, LPCWSTR lpSubBlock
,
837 LPVOID
*lplpBuffer
, PUINT puLen
)
839 static const WCHAR nullW
[] = { 0 };
840 static const WCHAR rootW
[] = { '\\', 0 };
841 static const WCHAR varfileinfoW
[] = { '\\','V','a','r','F','i','l','e','I','n','f','o',
842 '\\','T','r','a','n','s','l','a','t','i','o','n', 0 };
844 const VS_VERSION_INFO_STRUCT32
*info
= pBlock
;
846 TRACE("(%p,%s,%p,%p)\n",
847 pBlock
, debugstr_w(lpSubBlock
), lplpBuffer
, puLen
);
852 if (lpSubBlock
== NULL
|| lpSubBlock
[0] == nullW
[0])
855 if ( VersionInfoIs16( info
) )
861 len
= WideCharToMultiByte(CP_ACP
, 0, lpSubBlock
, -1, NULL
, 0, NULL
, NULL
);
862 lpSubBlockA
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(char));
867 WideCharToMultiByte(CP_ACP
, 0, lpSubBlock
, -1, lpSubBlockA
, len
, NULL
, NULL
);
869 ret
= VersionInfo16_QueryValue(pBlock
, lpSubBlockA
, lplpBuffer
, puLen
);
871 HeapFree(GetProcessHeap(), 0, lpSubBlockA
);
873 if (ret
&& strcmpiW( lpSubBlock
, rootW
) && strcmpiW( lpSubBlock
, varfileinfoW
))
875 /* Set lpBuffer so it points to the 'empty' area where we store
876 * the converted strings
878 LPWSTR lpBufferW
= (LPWSTR
)((LPSTR
)pBlock
+ info
->wLength
);
879 DWORD pos
= (LPCSTR
)*lplpBuffer
- (LPCSTR
)pBlock
;
880 DWORD max
= (info
->wLength
- sizeof(VS_FIXEDFILEINFO
)) * 4 - info
->wLength
;
882 len
= MultiByteToWideChar(CP_ACP
, 0, *lplpBuffer
, -1,
883 lpBufferW
+ pos
, max
/sizeof(WCHAR
) - pos
);
884 *lplpBuffer
= lpBufferW
+ pos
;
890 return VersionInfo32_QueryValue(info
, lpSubBlock
, lplpBuffer
, puLen
);