dbghelp: Simplify the resort operation (module address table) by using binary inserti...
[wine] / dlls / version / info.c
1 /*
2  * Implementation of VERSION.DLL - Version Info access
3  *
4  * Copyright 1996,1997 Marcus Meissner
5  * Copyright 1997 David Cuthbert
6  * Copyright 1999 Ulrich Weigand
7  * Copyright 2005 Paul Vriens
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
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22  *
23  */
24
25 #include <stdarg.h>
26 #include <stdlib.h>
27 #include <string.h>
28
29 #include "windef.h"
30 #include "winbase.h"
31 #include "winver.h"
32 #include "winternl.h"
33 #include "wine/winuser16.h"
34 #include "wine/unicode.h"
35 #include "winerror.h"
36 #include "wine/debug.h"
37
38 WINE_DEFAULT_DEBUG_CHANNEL(ver);
39
40 /******************************************************************************
41  *
42  *   This function will print via standard TRACE, debug info regarding
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  *****************************************************************************/
48 static void print_vffi_debug(const VS_FIXEDFILEINFO *vffi)
49 {
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);
71         TRACE("fileversion=%u.%u.%u.%u (%s.major.minor.release), ",
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",
83           HIWORD(vffi->dwProductVersionMS),LOWORD(vffi->dwProductVersionMS),
84           HIWORD(vffi->dwProductVersionLS),LOWORD(vffi->dwProductVersionLS));
85
86     TRACE("flagmask=0x%x, flags=0x%x %s%s%s%s%s%s\n",
87           vffi->dwFileFlagsMask, vffi->dwFileFlags,
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," : "");
94
95     TRACE("(");
96
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:
107         TRACE("UNKNOWN(0x%x),",vffi->dwFileOS&0xFFFF0000);break;
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     }
120
121     TRACE(")\n");
122
123     switch (vffi->dwFileType)
124     {
125     case VFT_APP:TRACE("filetype=APP");break;
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");
132             TRACE(" (subtype=0x%x)", vffi->dwFileSubtype);
133         }
134         break;
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;
150         case VFT2_DRV_VERSIONED_PRINTER:TRACE("VERSIONED_PRINTER");break;
151         case VFT2_UNKNOWN:
152         default:
153             TRACE("UNKNOWN(0x%x)",vffi->dwFileSubtype);break;
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;
163         default:TRACE("UNKNOWN(0x%x)",vffi->dwFileSubtype);break;
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:
170         TRACE("filetype=Unknown(0x%x)",vffi->dwFileType);break;
171     }
172
173     TRACE("\n");
174     TRACE("filedate=0x%x.0x%x\n",vffi->dwFileDateMS,vffi->dwFileDateLS);
175 }
176
177 /***********************************************************************
178  * Version Info Structure
179  */
180
181 typedef 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 */
190     VS_VERSION_INFO_STRUCT16 Children[];
191 #endif
192 } VS_VERSION_INFO_STRUCT16;
193
194 typedef struct
195 {
196     WORD  wLength;
197     WORD  wValueLength;
198     WORD  wType;
199     WCHAR szKey[1];
200 #if 0   /* variable length structure */
201     /* DWORD aligned */
202     BYTE  Value[];
203     /* DWORD aligned */
204     VS_VERSION_INFO_STRUCT32 Children[];
205 #endif
206 } VS_VERSION_INFO_STRUCT32;
207
208 #define VersionInfoIs16( ver ) \
209     ( ((const VS_VERSION_INFO_STRUCT16 *)ver)->szKey[0] >= ' ' )
210
211 #define DWORD_ALIGN( base, ptr ) \
212     ( (LPBYTE)(base) + ((((LPBYTE)(ptr) - (LPBYTE)(base)) + 3) & ~3) )
213
214 #define VersionInfo16_Value( ver )  \
215     DWORD_ALIGN( (ver), (ver)->szKey + strlen((ver)->szKey) + 1 )
216 #define VersionInfo32_Value( ver )  \
217     DWORD_ALIGN( (ver), (ver)->szKey + strlenW((ver)->szKey) + 1 )
218
219 #define VersionInfo16_Children( ver )  \
220     (const VS_VERSION_INFO_STRUCT16 *)( VersionInfo16_Value( ver ) + \
221                            ( ( (ver)->wValueLength + 3 ) & ~3 ) )
222 #define VersionInfo32_Children( ver )  \
223     (const VS_VERSION_INFO_STRUCT32 *)( VersionInfo32_Value( ver ) + \
224                            ( ( (ver)->wValueLength * \
225                                ((ver)->wType? 2 : 1) + 3 ) & ~3 ) )
226
227 #define VersionInfo16_Next( ver ) \
228     (VS_VERSION_INFO_STRUCT16 *)( (LPBYTE)ver + (((ver)->wLength + 3) & ~3) )
229 #define VersionInfo32_Next( ver ) \
230     (VS_VERSION_INFO_STRUCT32 *)( (LPBYTE)ver + (((ver)->wLength + 3) & ~3) )
231
232 /***********************************************************************
233  *           VERSION_GetFileVersionInfo_PE             [internal]
234  *
235  *    NOTE: returns size of the PE VERSION resource or 0xFFFFFFFF
236  *    in the case the file is a PE module, but VERSION_INFO not found.
237  */
238 static DWORD VERSION_GetFileVersionInfo_PE( LPCWSTR filename, DWORD datasize, LPVOID data )
239 {
240     const VS_FIXEDFILEINFO *vffi;
241     DWORD len;
242     BYTE *buf;
243     HMODULE hModule;
244     HRSRC hRsrc;
245     HGLOBAL hMem;
246
247     TRACE("%s\n", debugstr_w(filename));
248
249     if (!GetModuleHandleExW(0, filename, &hModule))
250         hModule = LoadLibraryExW(filename, 0, LOAD_LIBRARY_AS_DATAFILE);
251
252     if(!hModule)
253     {
254         WARN("Could not load %s\n", debugstr_w(filename));
255
256         return 0;
257     }
258     hRsrc = FindResourceW(hModule,
259                           MAKEINTRESOURCEW(VS_VERSION_INFO),
260                           MAKEINTRESOURCEW(VS_FILE_INFO));
261     if(!hRsrc)
262     {
263         WARN("Could not find VS_VERSION_INFO in %s\n", debugstr_w(filename));
264         FreeLibrary(hModule);
265         return 0xFFFFFFFF;
266     }
267     len = SizeofResource(hModule, hRsrc);
268     hMem = LoadResource(hModule, hRsrc);
269     if(!hMem)
270     {
271         WARN("Could not load VS_VERSION_INFO from %s\n", debugstr_w(filename));
272         FreeLibrary(hModule);
273         return 0xFFFFFFFF;
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     {
281         WARN("vffi->dwSignature is 0x%08x, but not 0x%08lx!\n",
282                    vffi->dwSignature, VS_FFI_SIGNATURE );
283         len = 0xFFFFFFFF;
284         goto END;
285     }
286
287     if ( TRACE_ON(ver) )
288         print_vffi_debug( vffi );
289
290     if(data)
291     {
292         if(datasize < len)
293             len = datasize; /* truncate data */
294         if(len)
295             memcpy(data, buf, len);
296         else
297             len = 0xFFFFFFFF;
298     }
299 END:
300     FreeResource(hMem);
301     FreeLibrary(hModule);
302
303     return len;
304 }
305
306 /***********************************************************************
307  *           VERSION_GetFileVersionInfo_16             [internal]
308  *
309  *    NOTE: returns size of the 16-bit VERSION resource or 0xFFFFFFFF
310  *    in the case the file exists, but VERSION_INFO not found.
311  */
312 static DWORD VERSION_GetFileVersionInfo_16( LPCSTR filename, DWORD datasize, LPVOID data )
313 {
314     const VS_FIXEDFILEINFO *vffi;
315     DWORD len, offset;
316     BYTE *buf;
317     HMODULE16 hModule;
318     HRSRC16 hRsrc;
319     HGLOBAL16 hMem;
320     char dllname[20], owner[20], *p;
321     const char *basename;
322     BOOL is_builtin = FALSE;
323
324     TRACE("%s\n", debugstr_a(filename));
325
326     /* strip path information */
327
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         {
364             vffi = (VS_FIXEDFILEINFO *)VersionInfo16_Value( (VS_VERSION_INFO_STRUCT16 *)data );
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
374                 return len;
375             }
376         }
377     }
378
379     /* this might be a builtin 16-bit module */
380     hModule = LoadLibrary16(filename);
381     if(hModule < 32)
382     {
383         WARN("Could not load %s\n", debugstr_a(filename));
384         if (hModule == ERROR_BAD_FORMAT)
385                 return 0xFFFFFFFF;
386         else
387                 return 0x0;
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));
395         FreeLibrary16(hModule);
396         return 0xFFFFFFFF;
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));
403         FreeLibrary16(hModule);
404         return 0xFFFFFFFF;
405     }
406     buf = LockResource16(hMem);
407
408     if(!VersionInfoIs16(buf))
409     {
410         len = 0xFFFFFFFF;
411         goto END;
412     }
413
414     vffi = (VS_FIXEDFILEINFO *)VersionInfo16_Value( (VS_VERSION_INFO_STRUCT16 *)buf );
415
416     if ( vffi->dwSignature != VS_FFI_SIGNATURE )
417     {
418         WARN("vffi->dwSignature is 0x%08x, but not 0x%08lx!\n",
419                    vffi->dwSignature, VS_FFI_SIGNATURE );
420         len = 0xFFFFFFFF;
421         goto END;
422     }
423
424     if ( TRACE_ON(ver) )
425         print_vffi_debug( vffi );
426
427     if(data)
428     {
429         if(datasize < len)
430             len = datasize; /* truncate data */
431         if(len)
432             memcpy(data, buf, len);
433         else
434             len = 0xFFFFFFFF;
435     }
436 END:
437     FreeResource16(hMem);
438     FreeLibrary16(hModule);
439
440     return len;
441 }
442
443 /***********************************************************************
444  *           GetFileVersionInfoSizeW         [VERSION.@]
445  */
446 DWORD WINAPI GetFileVersionInfoSizeW( LPCWSTR filename, LPDWORD handle )
447 {
448     DWORD len;
449
450     TRACE("(%s,%p)\n", debugstr_w(filename), handle );
451
452     if (handle) *handle = 0;
453
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
465     len = VERSION_GetFileVersionInfo_PE(filename, 0, NULL);
466     /* 0xFFFFFFFF means: file is a PE module, but VERSION_INFO not found */
467     if(len == 0xFFFFFFFF)
468     {
469         SetLastError(ERROR_RESOURCE_DATA_NOT_FOUND);
470         return 0;
471     }
472
473     if (!len)
474     {
475         LPSTR filenameA;
476
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 );
480
481         len = VERSION_GetFileVersionInfo_16(filenameA, 0, NULL);
482         HeapFree( GetProcessHeap(), 0, filenameA );
483         /* 0xFFFFFFFF means: file exists, but VERSION_INFO not found */
484         if (!len)
485         {
486             SetLastError(ERROR_FILE_NOT_FOUND);
487             return 0;
488         }
489         if (len == 0xFFFFFFFF)
490         {
491             SetLastError(ERROR_RESOURCE_DATA_NOT_FOUND);
492             return 0;
493         }
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
503          * doesn't seem to be a problem (len is bigger than info->wLength).
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;
515     }
516
517     SetLastError(0);
518     return len;
519 }
520
521 /***********************************************************************
522  *           GetFileVersionInfoSizeA         [VERSION.@]
523  */
524 DWORD WINAPI GetFileVersionInfoSizeA( LPCSTR filename, LPDWORD handle )
525 {
526     UNICODE_STRING filenameW;
527     DWORD retval;
528
529     TRACE("(%s,%p)\n", debugstr_a(filename), handle );
530
531     if(filename)
532         RtlCreateUnicodeStringFromAsciiz(&filenameW, filename);
533     else
534         filenameW.Buffer = NULL;
535
536     retval = GetFileVersionInfoSizeW(filenameW.Buffer, handle);
537
538     RtlFreeUnicodeString(&filenameW);
539
540     return retval;
541 }
542
543 /***********************************************************************
544  *           GetFileVersionInfoW             [VERSION.@]
545  */
546 BOOL WINAPI GetFileVersionInfoW( LPCWSTR filename, DWORD handle,
547                                     DWORD datasize, LPVOID data )
548 {
549     DWORD len;
550     VS_VERSION_INFO_STRUCT32* vvis = data;
551
552     TRACE("(%s,%d,size=%d,data=%p)\n",
553                 debugstr_w(filename), handle, datasize, data );
554
555     if (!data)
556     {
557         SetLastError(ERROR_INVALID_DATA);
558         return FALSE;
559     }
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     }
567
568     if (!len)
569     {
570         LPSTR filenameA;
571
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         }
584         /* We have a 16bit resource. */
585     }
586     else 
587     {
588         static const char signature[] = "FE2X";
589         DWORD bufsize = vvis->wLength + strlen(signature);
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
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         }
604     }
605
606     SetLastError(0);
607     return TRUE;
608 }
609
610 /***********************************************************************
611  *           GetFileVersionInfoA             [VERSION.@]
612  */
613 BOOL WINAPI GetFileVersionInfoA( LPCSTR filename, DWORD handle,
614                                     DWORD datasize, LPVOID data )
615 {
616     UNICODE_STRING filenameW;
617     BOOL retval;
618
619     TRACE("(%s,%d,size=%d,data=%p)\n",
620                 debugstr_a(filename), handle, datasize, data );
621
622     if(filename)
623         RtlCreateUnicodeStringFromAsciiz(&filenameW, filename);
624     else
625         filenameW.Buffer = NULL;
626
627     retval = GetFileVersionInfoW(filenameW.Buffer, handle, datasize, data);
628
629     RtlFreeUnicodeString(&filenameW);
630
631     return retval;
632 }
633
634 /***********************************************************************
635  *           VersionInfo16_FindChild             [internal]
636  */
637 static const VS_VERSION_INFO_STRUCT16 *VersionInfo16_FindChild( const VS_VERSION_INFO_STRUCT16 *info,
638                                             LPCSTR szKey, UINT cbKey )
639 {
640     const VS_VERSION_INFO_STRUCT16 *child = VersionInfo16_Children( info );
641
642     while ((char *)child < (char *)info + info->wLength )
643     {
644         if (!strncasecmp( child->szKey, szKey, cbKey ) && !child->szKey[cbKey])
645             return child;
646
647         if (!(child->wLength)) return NULL;
648         child = VersionInfo16_Next( child );
649     }
650
651     return NULL;
652 }
653
654 /***********************************************************************
655  *           VersionInfo32_FindChild             [internal]
656  */
657 static const VS_VERSION_INFO_STRUCT32 *VersionInfo32_FindChild( const VS_VERSION_INFO_STRUCT32 *info,
658                                             LPCWSTR szKey, UINT cbKey )
659 {
660     const VS_VERSION_INFO_STRUCT32 *child = VersionInfo32_Children( info );
661
662     while ((char *)child < (char *)info + info->wLength )
663     {
664         if (!strncmpiW( child->szKey, szKey, cbKey ) && !child->szKey[cbKey])
665             return child;
666
667         if (!(child->wLength)) return NULL;
668         child = VersionInfo32_Next( child );
669     }
670
671     return NULL;
672 }
673
674 /***********************************************************************
675  *           VersionInfo16_QueryValue              [internal]
676  *
677  *    Gets a value from a 16-bit NE resource
678  */
679 static BOOL VersionInfo16_QueryValue( const VS_VERSION_INFO_STRUCT16 *info, LPCSTR lpSubBlock,
680                                LPVOID *lplpBuffer, UINT *puLen )
681 {
682     while ( *lpSubBlock )
683     {
684         /* Find next path component */
685         LPCSTR lpNextSlash;
686         for ( lpNextSlash = lpSubBlock; *lpNextSlash; lpNextSlash++ )
687             if ( *lpNextSlash == '\\' )
688                 break;
689
690         /* Skip empty components */
691         if ( lpNextSlash == lpSubBlock )
692         {
693             lpSubBlock++;
694             continue;
695         }
696
697         /* We have a non-empty component: search info for key */
698         info = VersionInfo16_FindChild( info, lpSubBlock, lpNextSlash-lpSubBlock );
699         if ( !info )
700         {
701             if (puLen) *puLen = 0 ;
702             SetLastError( ERROR_RESOURCE_TYPE_NOT_FOUND );
703             return FALSE;
704         }
705
706         /* Skip path component */
707         lpSubBlock = lpNextSlash;
708     }
709
710     /* Return value */
711     *lplpBuffer = VersionInfo16_Value( info );
712     if (puLen)
713         *puLen = info->wValueLength;
714
715     return TRUE;
716 }
717
718 /***********************************************************************
719  *           VersionInfo32_QueryValue              [internal]
720  *
721  *    Gets a value from a 32-bit PE resource
722  */
723 static BOOL VersionInfo32_QueryValue( const VS_VERSION_INFO_STRUCT32 *info, LPCWSTR lpSubBlock,
724                                LPVOID *lplpBuffer, UINT *puLen )
725 {
726     TRACE("lpSubBlock : (%s)\n", debugstr_w(lpSubBlock));
727
728     while ( *lpSubBlock )
729     {
730         /* Find next path component */
731         LPCWSTR lpNextSlash;
732         for ( lpNextSlash = lpSubBlock; *lpNextSlash; lpNextSlash++ )
733             if ( *lpNextSlash == '\\' )
734                 break;
735
736         /* Skip empty components */
737         if ( lpNextSlash == lpSubBlock )
738         {
739             lpSubBlock++;
740             continue;
741         }
742
743         /* We have a non-empty component: search info for key */
744         info = VersionInfo32_FindChild( info, lpSubBlock, lpNextSlash-lpSubBlock );
745         if ( !info )
746         {
747             if (puLen) *puLen = 0 ;
748             SetLastError( ERROR_RESOURCE_TYPE_NOT_FOUND );
749             return FALSE;
750         }
751
752         /* Skip path component */
753         lpSubBlock = lpNextSlash;
754     }
755
756     /* Return value */
757     *lplpBuffer = VersionInfo32_Value( info );
758     if (puLen)
759         *puLen = info->wValueLength;
760
761     return TRUE;
762 }
763
764 /***********************************************************************
765  *           VerQueryValueA              [VERSION.@]
766  */
767 BOOL WINAPI VerQueryValueA( LPCVOID pBlock, LPCSTR lpSubBlock,
768                                LPVOID *lplpBuffer, PUINT puLen )
769 {
770     static const char rootA[] = "\\";
771     static const char varfileinfoA[] = "\\VarFileInfo\\Translation";
772     const VS_VERSION_INFO_STRUCT16 *info = pBlock;
773
774     TRACE("(%p,%s,%p,%p)\n",
775                 pBlock, debugstr_a(lpSubBlock), lplpBuffer, puLen );
776
777      if (!pBlock)
778         return FALSE;
779
780     if (lpSubBlock == NULL || lpSubBlock[0] == '\0')
781         lpSubBlock = rootA;
782
783     if ( !VersionInfoIs16( info ) )
784     {
785         BOOL ret;
786         INT len;
787         LPWSTR lpSubBlockW;
788
789         len  = MultiByteToWideChar(CP_ACP, 0, lpSubBlock, -1, NULL, 0);
790         lpSubBlockW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
791
792         if (!lpSubBlockW)
793             return FALSE;
794
795         MultiByteToWideChar(CP_ACP, 0, lpSubBlock, -1, lpSubBlockW, len);
796
797         ret = VersionInfo32_QueryValue(pBlock, lpSubBlockW, lplpBuffer, puLen);
798
799         HeapFree(GetProcessHeap(), 0, lpSubBlockW);
800
801         if (ret && strcasecmp( lpSubBlock, rootA ) && strcasecmp( lpSubBlock, varfileinfoA ))
802         {
803             /* Set lpBuffer so it points to the 'empty' area where we store
804              * the converted strings
805              */
806             LPSTR lpBufferA = (LPSTR)pBlock + info->wLength + 4;
807             DWORD pos = (LPCSTR)*lplpBuffer - (LPCSTR)pBlock;
808
809             len = WideCharToMultiByte(CP_ACP, 0, *lplpBuffer, -1,
810                                       lpBufferA + pos, info->wLength - pos, NULL, NULL);
811             *lplpBuffer = lpBufferA + pos;
812             *puLen = len;
813         }
814         return ret;
815     }
816
817     return VersionInfo16_QueryValue(info, lpSubBlock, lplpBuffer, puLen);
818 }
819
820 /***********************************************************************
821  *           VerQueryValueW              [VERSION.@]
822  */
823 BOOL WINAPI VerQueryValueW( LPCVOID pBlock, LPCWSTR lpSubBlock,
824                                LPVOID *lplpBuffer, PUINT puLen )
825 {
826     static const WCHAR nullW[] = { 0 };
827     static const WCHAR rootW[] = { '\\', 0 };
828     static const WCHAR varfileinfoW[] = { '\\','V','a','r','F','i','l','e','I','n','f','o',
829                                           '\\','T','r','a','n','s','l','a','t','i','o','n', 0 };
830
831     const VS_VERSION_INFO_STRUCT32 *info = pBlock;
832
833     TRACE("(%p,%s,%p,%p)\n",
834                 pBlock, debugstr_w(lpSubBlock), lplpBuffer, puLen );
835
836     if (!pBlock)
837         return FALSE;
838
839     if (lpSubBlock == NULL || lpSubBlock[0] == nullW[0])
840         lpSubBlock = rootW;
841
842     if ( VersionInfoIs16( info ) )
843     {
844         BOOL ret;
845         int len;
846         LPSTR lpSubBlockA;
847
848         len = WideCharToMultiByte(CP_ACP, 0, lpSubBlock, -1, NULL, 0, NULL, NULL);
849         lpSubBlockA = HeapAlloc(GetProcessHeap(), 0, len * sizeof(char));
850
851         if (!lpSubBlockA)
852             return FALSE;
853
854         WideCharToMultiByte(CP_ACP, 0, lpSubBlock, -1, lpSubBlockA, len, NULL, NULL);
855
856         ret = VersionInfo16_QueryValue(pBlock, lpSubBlockA, lplpBuffer, puLen);
857
858         HeapFree(GetProcessHeap(), 0, lpSubBlockA);
859
860         if (ret && strcmpiW( lpSubBlock, rootW ) && strcmpiW( lpSubBlock, varfileinfoW ))
861         {
862             /* Set lpBuffer so it points to the 'empty' area where we store
863              * the converted strings
864              */
865             LPWSTR lpBufferW = (LPWSTR)((LPSTR)pBlock + info->wLength);
866             DWORD pos = (LPCSTR)*lplpBuffer - (LPCSTR)pBlock;
867             DWORD max = (info->wLength - sizeof(VS_FIXEDFILEINFO)) * 4 - info->wLength;
868
869             len = MultiByteToWideChar(CP_ACP, 0, *lplpBuffer, -1,
870                                       lpBufferW + pos, max/sizeof(WCHAR) - pos );
871             *lplpBuffer = lpBufferW + pos;
872             *puLen = len;
873         }
874         return ret;
875     }
876
877     return VersionInfo32_QueryValue(info, lpSubBlock, lplpBuffer, puLen);
878 }