mshtml: Added PutProperty implementation.
[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         return 0;
256     }
257     hRsrc = FindResourceW(hModule,
258                           MAKEINTRESOURCEW(VS_VERSION_INFO),
259                           MAKEINTRESOURCEW(VS_FILE_INFO));
260     if(!hRsrc)
261     {
262         WARN("Could not find VS_VERSION_INFO in %s\n", debugstr_w(filename));
263         FreeLibrary(hModule);
264         return 0xFFFFFFFF;
265     }
266     len = SizeofResource(hModule, hRsrc);
267     hMem = LoadResource(hModule, hRsrc);
268     if(!hMem)
269     {
270         WARN("Could not load VS_VERSION_INFO from %s\n", debugstr_w(filename));
271         FreeLibrary(hModule);
272         return 0xFFFFFFFF;
273     }
274     buf = LockResource(hMem);
275
276     vffi = (VS_FIXEDFILEINFO *)VersionInfo32_Value( (VS_VERSION_INFO_STRUCT32 *)buf );
277
278     if ( vffi->dwSignature != VS_FFI_SIGNATURE )
279     {
280         WARN("vffi->dwSignature is 0x%08x, but not 0x%08lx!\n",
281                    vffi->dwSignature, VS_FFI_SIGNATURE );
282         len = 0xFFFFFFFF;
283         goto END;
284     }
285
286     if ( TRACE_ON(ver) )
287         print_vffi_debug( vffi );
288
289     if(data)
290     {
291         if(datasize < len)
292             len = datasize; /* truncate data */
293         if(len)
294             memcpy(data, buf, len);
295         else
296             len = 0xFFFFFFFF;
297     }
298 END:
299     FreeResource(hMem);
300     FreeLibrary(hModule);
301
302     return len;
303 }
304
305 /***********************************************************************
306  *           VERSION_GetFileVersionInfo_16             [internal]
307  *
308  *    NOTE: returns size of the 16-bit VERSION resource or 0xFFFFFFFF
309  *    in the case the file exists, but VERSION_INFO not found.
310  */
311 static DWORD VERSION_GetFileVersionInfo_16( LPCSTR filename, DWORD datasize, LPVOID data )
312 {
313     const VS_FIXEDFILEINFO *vffi;
314     DWORD len, offset;
315     BYTE *buf;
316     HMODULE16 hModule;
317     HRSRC16 hRsrc;
318     HGLOBAL16 hMem;
319     char dllname[20], owner[20], *p;
320     const char *basename;
321     BOOL is_builtin = FALSE;
322
323     TRACE("%s\n", debugstr_a(filename));
324
325     /* strip path information */
326
327     basename = filename;
328     if (basename[0] && basename[1] == ':') basename += 2;  /* strip drive specification */
329     if ((p = strrchr( basename, '\\' ))) basename = p + 1;
330     if ((p = strrchr( basename, '/' ))) basename = p + 1;
331
332     if (strlen(basename) < sizeof(dllname)-4)
333     {
334         int file_exists;
335
336         strcpy( dllname, basename );
337         p = strrchr( dllname, '.' );
338         if (!p) strcat( dllname, ".dll" );
339         for (p = dllname; *p; p++) if (*p >= 'A' && *p <= 'Z') *p += 32;
340
341         if (wine_dll_get_owner( dllname, owner, sizeof(owner), &file_exists ) == 0)
342             is_builtin = TRUE;
343     }
344
345     /* first try without loading a 16-bit module */
346     if (is_builtin)
347         len = 0;
348     else
349         len = GetFileResourceSize16( filename,
350                                      MAKEINTRESOURCEA(VS_FILE_INFO),
351                                      MAKEINTRESOURCEA(VS_VERSION_INFO),
352                                      &offset );
353     if (len)
354     {
355         if (!data) return len;
356
357         len = GetFileResource16( filename,
358                                  MAKEINTRESOURCEA(VS_FILE_INFO),
359                                  MAKEINTRESOURCEA(VS_VERSION_INFO),
360                                  offset, datasize, data );
361         if (len)
362         {
363             vffi = (VS_FIXEDFILEINFO *)VersionInfo16_Value( (VS_VERSION_INFO_STRUCT16 *)data );
364
365             if ( vffi->dwSignature == VS_FFI_SIGNATURE )
366             {
367                 if ( ((VS_VERSION_INFO_STRUCT16 *)data)->wLength < len )
368                     len = ((VS_VERSION_INFO_STRUCT16 *)data)->wLength;
369
370                 if ( TRACE_ON(ver) )
371                     print_vffi_debug( vffi );
372
373                 return len;
374             }
375         }
376     }
377
378     /* this might be a builtin 16-bit module */
379     hModule = LoadLibrary16(filename);
380     if(hModule < 32)
381     {
382         WARN("Could not load %s\n", debugstr_a(filename));
383         return 0;
384     }
385     hRsrc = FindResource16(hModule,
386                           MAKEINTRESOURCEA(VS_VERSION_INFO),
387                           MAKEINTRESOURCEA(VS_FILE_INFO));
388     if(!hRsrc)
389     {
390         WARN("Could not find VS_VERSION_INFO in %s\n", debugstr_a(filename));
391         FreeLibrary16(hModule);
392         return 0xFFFFFFFF;
393     }
394     len = SizeofResource16(hModule, hRsrc);
395     hMem = LoadResource16(hModule, hRsrc);
396     if(!hMem)
397     {
398         WARN("Could not load VS_VERSION_INFO from %s\n", debugstr_a(filename));
399         FreeLibrary16(hModule);
400         return 0xFFFFFFFF;
401     }
402     buf = LockResource16(hMem);
403
404     if(!VersionInfoIs16(buf))
405     {
406         len = 0xFFFFFFFF;
407         goto END;
408     }
409
410     vffi = (VS_FIXEDFILEINFO *)VersionInfo16_Value( (VS_VERSION_INFO_STRUCT16 *)buf );
411
412     if ( vffi->dwSignature != VS_FFI_SIGNATURE )
413     {
414         WARN("vffi->dwSignature is 0x%08x, but not 0x%08lx!\n",
415                    vffi->dwSignature, VS_FFI_SIGNATURE );
416         len = 0xFFFFFFFF;
417         goto END;
418     }
419
420     if ( TRACE_ON(ver) )
421         print_vffi_debug( vffi );
422
423     if(data)
424     {
425         if(datasize < len)
426             len = datasize; /* truncate data */
427         if(len)
428             memcpy(data, buf, len);
429         else
430             len = 0xFFFFFFFF;
431     }
432 END:
433     FreeResource16(hMem);
434     FreeLibrary16(hModule);
435
436     return len;
437 }
438
439 /***********************************************************************
440  *           GetFileVersionInfoSizeW         [VERSION.@]
441  */
442 DWORD WINAPI GetFileVersionInfoSizeW( LPCWSTR filename, LPDWORD handle )
443 {
444     DWORD len;
445
446     TRACE("(%s,%p)\n", debugstr_w(filename), handle );
447
448     if (handle) *handle = 0;
449
450     if (!filename)
451     {
452         SetLastError(ERROR_INVALID_PARAMETER);
453         return 0;
454     }
455     if (!*filename)
456     {
457         SetLastError(ERROR_BAD_PATHNAME);
458         return 0;
459     }
460
461     len = VERSION_GetFileVersionInfo_PE(filename, 0, NULL);
462     /* 0xFFFFFFFF means: file is a PE module, but VERSION_INFO not found */
463     if(len == 0xFFFFFFFF)
464     {
465         SetLastError(ERROR_RESOURCE_DATA_NOT_FOUND);
466         return 0;
467     }
468
469     if (!len)
470     {
471         LPSTR filenameA;
472
473         len = WideCharToMultiByte( CP_ACP, 0, filename, -1, NULL, 0, NULL, NULL );
474         filenameA = HeapAlloc( GetProcessHeap(), 0, len );
475         WideCharToMultiByte( CP_ACP, 0, filename, -1, filenameA, len, NULL, NULL );
476
477         len = VERSION_GetFileVersionInfo_16(filenameA, 0, NULL);
478         HeapFree( GetProcessHeap(), 0, filenameA );
479         /* 0xFFFFFFFF means: file exists, but VERSION_INFO not found */
480         if (!len)
481         {
482             SetLastError(ERROR_FILE_NOT_FOUND);
483             return 0;
484         }
485         if (len == 0xFFFFFFFF)
486         {
487             SetLastError(ERROR_RESOURCE_DATA_NOT_FOUND);
488             return 0;
489         }
490
491         /* We have a 16bit resource.
492          *
493          * XP/W2K/W2K3 uses a buffer which is more than the actual needed space:
494          *
495          * (info->wLength - sizeof(VS_FIXEDFILEINFO)) * 4
496          *
497          * This extra buffer is used for ANSI to Unicode conversions in W-Calls.
498          * info->wLength should be the same as len. Currently it isn't but that
499          * doesn't seem to be a problem (len is bigger than info->wLength).
500          */
501          len = (len - sizeof(VS_FIXEDFILEINFO)) * 4;
502     }
503     else
504     {
505         /* We have a 32bit resource.
506          *
507          * XP/W2K/W2K3 uses a buffer which is 2 times the actual needed space + 4 bytes "FE2X"
508          * This extra buffer is used for Unicode to ANSI conversions in A-Calls
509          */
510          len = (len * 2) + 4;
511     }
512
513     SetLastError(0);
514     return len;
515 }
516
517 /***********************************************************************
518  *           GetFileVersionInfoSizeA         [VERSION.@]
519  */
520 DWORD WINAPI GetFileVersionInfoSizeA( LPCSTR filename, LPDWORD handle )
521 {
522     UNICODE_STRING filenameW;
523     DWORD retval;
524
525     TRACE("(%s,%p)\n", debugstr_a(filename), handle );
526
527     if(filename)
528         RtlCreateUnicodeStringFromAsciiz(&filenameW, filename);
529     else
530         filenameW.Buffer = NULL;
531
532     retval = GetFileVersionInfoSizeW(filenameW.Buffer, handle);
533
534     RtlFreeUnicodeString(&filenameW);
535
536     return retval;
537 }
538
539 /***********************************************************************
540  *           GetFileVersionInfoW             [VERSION.@]
541  */
542 BOOL WINAPI GetFileVersionInfoW( LPCWSTR filename, DWORD handle,
543                                     DWORD datasize, LPVOID data )
544 {
545     DWORD len;
546     VS_VERSION_INFO_STRUCT32* vvis = (VS_VERSION_INFO_STRUCT32*)data;
547
548     TRACE("(%s,%d,size=%d,data=%p)\n",
549                 debugstr_w(filename), handle, datasize, data );
550
551     if (!data)
552     {
553         SetLastError(ERROR_INVALID_DATA);
554         return FALSE;
555     }
556     len = VERSION_GetFileVersionInfo_PE(filename, datasize, data);
557     /* 0xFFFFFFFF means: file is a PE module, but VERSION_INFO not found */
558     if (len == 0xFFFFFFFF)
559     {
560         SetLastError(ERROR_RESOURCE_DATA_NOT_FOUND);
561         return FALSE;
562     }
563
564     if (!len)
565     {
566         LPSTR filenameA;
567
568         len = WideCharToMultiByte( CP_ACP, 0, filename, -1, NULL, 0, NULL, NULL );
569         filenameA = HeapAlloc( GetProcessHeap(), 0, len );
570         WideCharToMultiByte( CP_ACP, 0, filename, -1, filenameA, len, NULL, NULL );
571
572         len = VERSION_GetFileVersionInfo_16(filenameA, datasize, data);
573         HeapFree( GetProcessHeap(), 0, filenameA );
574         /* 0xFFFFFFFF means: file exists, but VERSION_INFO not found */
575         if (!len || len == 0xFFFFFFFF)
576         {
577             SetLastError(ERROR_RESOURCE_DATA_NOT_FOUND);
578             return FALSE;
579         }
580         /* We have a 16bit resource. */
581     }
582     else 
583     {
584         static const char signature[] = "FE2X";
585         DWORD bufsize = vvis->wLength + strlen(signature);
586         DWORD convbuf;
587  
588         /* We have a 32bit resource.
589          *
590          * XP/W2K/W2K3 uses a buffer which is 2 times the actual needed space + 4 bytes "FE2X"
591          * This extra buffer is used for Unicode to ANSI conversions in A-Calls
592          */
593
594         /* information is truncated to datasize bytes */
595         if (datasize >= bufsize)
596         {
597             convbuf = datasize - vvis->wLength;
598             memcpy( ((char*)(data))+vvis->wLength, signature, convbuf > 4 ? 4 : convbuf );
599         }
600     }
601
602     SetLastError(0);
603     return TRUE;
604 }
605
606 /***********************************************************************
607  *           GetFileVersionInfoA             [VERSION.@]
608  */
609 BOOL WINAPI GetFileVersionInfoA( LPCSTR filename, DWORD handle,
610                                     DWORD datasize, LPVOID data )
611 {
612     UNICODE_STRING filenameW;
613     BOOL retval;
614
615     TRACE("(%s,%d,size=%d,data=%p)\n",
616                 debugstr_a(filename), handle, datasize, data );
617
618     if(filename)
619         RtlCreateUnicodeStringFromAsciiz(&filenameW, filename);
620     else
621         filenameW.Buffer = NULL;
622
623     retval = GetFileVersionInfoW(filenameW.Buffer, handle, datasize, data);
624
625     RtlFreeUnicodeString(&filenameW);
626
627     return retval;
628 }
629
630 /***********************************************************************
631  *           VersionInfo16_FindChild             [internal]
632  */
633 static const VS_VERSION_INFO_STRUCT16 *VersionInfo16_FindChild( const VS_VERSION_INFO_STRUCT16 *info,
634                                             LPCSTR szKey, UINT cbKey )
635 {
636     const VS_VERSION_INFO_STRUCT16 *child = VersionInfo16_Children( info );
637
638     while ((char *)child < (char *)info + info->wLength )
639     {
640         if (!strncasecmp( child->szKey, szKey, cbKey ) && !child->szKey[cbKey])
641             return child;
642
643         if (!(child->wLength)) return NULL;
644         child = VersionInfo16_Next( child );
645     }
646
647     return NULL;
648 }
649
650 /***********************************************************************
651  *           VersionInfo32_FindChild             [internal]
652  */
653 static const VS_VERSION_INFO_STRUCT32 *VersionInfo32_FindChild( const VS_VERSION_INFO_STRUCT32 *info,
654                                             LPCWSTR szKey, UINT cbKey )
655 {
656     const VS_VERSION_INFO_STRUCT32 *child = VersionInfo32_Children( info );
657
658     while ((char *)child < (char *)info + info->wLength )
659     {
660         if (!strncmpiW( child->szKey, szKey, cbKey ) && !child->szKey[cbKey])
661             return child;
662
663         child = VersionInfo32_Next( child );
664     }
665
666     return NULL;
667 }
668
669 /***********************************************************************
670  *           VersionInfo16_QueryValue              [internal]
671  *
672  *    Gets a value from a 16-bit NE resource
673  */
674 static BOOL WINAPI VersionInfo16_QueryValue( const VS_VERSION_INFO_STRUCT16 *info, LPCSTR lpSubBlock,
675                                LPVOID *lplpBuffer, UINT *puLen )
676 {
677     while ( *lpSubBlock )
678     {
679         /* Find next path component */
680         LPCSTR lpNextSlash;
681         for ( lpNextSlash = lpSubBlock; *lpNextSlash; lpNextSlash++ )
682             if ( *lpNextSlash == '\\' )
683                 break;
684
685         /* Skip empty components */
686         if ( lpNextSlash == lpSubBlock )
687         {
688             lpSubBlock++;
689             continue;
690         }
691
692         /* We have a non-empty component: search info for key */
693         info = VersionInfo16_FindChild( info, lpSubBlock, lpNextSlash-lpSubBlock );
694         if ( !info )
695         {
696             if (puLen) *puLen = 0 ;
697             SetLastError( ERROR_RESOURCE_TYPE_NOT_FOUND );
698             return FALSE;
699         }
700
701         /* Skip path component */
702         lpSubBlock = lpNextSlash;
703     }
704
705     /* Return value */
706     *lplpBuffer = VersionInfo16_Value( info );
707     if (puLen)
708         *puLen = info->wValueLength;
709
710     return TRUE;
711 }
712
713 /***********************************************************************
714  *           VersionInfo32_QueryValue              [internal]
715  *
716  *    Gets a value from a 32-bit PE resource
717  */
718 static BOOL WINAPI VersionInfo32_QueryValue( const VS_VERSION_INFO_STRUCT32 *info, LPCWSTR lpSubBlock,
719                                LPVOID *lplpBuffer, UINT *puLen )
720 {
721     TRACE("lpSubBlock : (%s)\n", debugstr_w(lpSubBlock));
722
723     while ( *lpSubBlock )
724     {
725         /* Find next path component */
726         LPCWSTR lpNextSlash;
727         for ( lpNextSlash = lpSubBlock; *lpNextSlash; lpNextSlash++ )
728             if ( *lpNextSlash == '\\' )
729                 break;
730
731         /* Skip empty components */
732         if ( lpNextSlash == lpSubBlock )
733         {
734             lpSubBlock++;
735             continue;
736         }
737
738         /* We have a non-empty component: search info for key */
739         info = VersionInfo32_FindChild( info, lpSubBlock, lpNextSlash-lpSubBlock );
740         if ( !info )
741         {
742             if (puLen) *puLen = 0 ;
743             SetLastError( ERROR_RESOURCE_TYPE_NOT_FOUND );
744             return FALSE;
745         }
746
747         /* Skip path component */
748         lpSubBlock = lpNextSlash;
749     }
750
751     /* Return value */
752     *lplpBuffer = VersionInfo32_Value( info );
753     if (puLen)
754         *puLen = info->wValueLength;
755
756     return TRUE;
757 }
758
759 /***********************************************************************
760  *           VerQueryValueA              [VERSION.@]
761  */
762 BOOL WINAPI VerQueryValueA( LPCVOID pBlock, LPCSTR lpSubBlock,
763                                LPVOID *lplpBuffer, PUINT puLen )
764 {
765     static const char rootA[] = "\\";
766     static const char varfileinfoA[] = "\\VarFileInfo\\Translation";
767     const VS_VERSION_INFO_STRUCT16 *info = (const VS_VERSION_INFO_STRUCT16 *)pBlock;
768
769     TRACE("(%p,%s,%p,%p)\n",
770                 pBlock, debugstr_a(lpSubBlock), lplpBuffer, puLen );
771
772      if (!pBlock)
773         return FALSE;
774
775     if ( !VersionInfoIs16( info ) )
776     {
777         BOOL ret;
778         INT len;
779         LPWSTR lpSubBlockW;
780
781         len  = MultiByteToWideChar(CP_ACP, 0, lpSubBlock, -1, NULL, 0);
782         lpSubBlockW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
783
784         if (!lpSubBlockW)
785             return FALSE;
786
787         MultiByteToWideChar(CP_ACP, 0, lpSubBlock, -1, lpSubBlockW, len);
788
789         ret = VersionInfo32_QueryValue(pBlock, lpSubBlockW, lplpBuffer, puLen);
790
791         HeapFree(GetProcessHeap(), 0, lpSubBlockW);
792
793         if (ret && strcasecmp( lpSubBlock, rootA ) && strcasecmp( lpSubBlock, varfileinfoA ))
794         {
795             /* Set lpBuffer so it points to the 'empty' area where we store
796              * the converted strings
797              */
798             LPSTR lpBufferA = (LPSTR)pBlock + info->wLength + 4;
799             DWORD pos = (LPCSTR)*lplpBuffer - (LPCSTR)pBlock;
800
801             len = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)*lplpBuffer, -1,
802                                       lpBufferA + pos, info->wLength - pos, NULL, NULL);
803             *lplpBuffer = lpBufferA + pos;
804             *puLen = len;
805         }
806         return ret;
807     }
808
809     return VersionInfo16_QueryValue(info, lpSubBlock, lplpBuffer, puLen);
810 }
811
812 /***********************************************************************
813  *           VerQueryValueW              [VERSION.@]
814  */
815 BOOL WINAPI VerQueryValueW( LPCVOID pBlock, LPCWSTR lpSubBlock,
816                                LPVOID *lplpBuffer, PUINT puLen )
817 {
818     static const WCHAR rootW[] = { '\\', 0 };
819     static const WCHAR varfileinfoW[] = { '\\','V','a','r','F','i','l','e','I','n','f','o',
820                                           '\\','T','r','a','n','s','l','a','t','i','o','n', 0 };
821
822     const VS_VERSION_INFO_STRUCT32 *info = (const VS_VERSION_INFO_STRUCT32 *)pBlock;
823
824     TRACE("(%p,%s,%p,%p)\n",
825                 pBlock, debugstr_w(lpSubBlock), lplpBuffer, puLen );
826
827     if (!pBlock)
828         return FALSE;
829
830     if ( VersionInfoIs16( info ) )
831     {
832         BOOL ret;
833         int len;
834         LPSTR lpSubBlockA;
835
836         len = WideCharToMultiByte(CP_ACP, 0, lpSubBlock, -1, NULL, 0, NULL, NULL);
837         lpSubBlockA = HeapAlloc(GetProcessHeap(), 0, len * sizeof(char));
838
839         if (!lpSubBlockA)
840             return FALSE;
841
842         WideCharToMultiByte(CP_ACP, 0, lpSubBlock, -1, lpSubBlockA, len, NULL, NULL);
843
844         ret = VersionInfo16_QueryValue(pBlock, lpSubBlockA, lplpBuffer, puLen);
845
846         HeapFree(GetProcessHeap(), 0, lpSubBlockA);
847
848         if (ret && strcmpiW( lpSubBlock, rootW ) && strcmpiW( lpSubBlock, varfileinfoW ))
849         {
850             /* Set lpBuffer so it points to the 'empty' area where we store
851              * the converted strings
852              */
853             LPWSTR lpBufferW = (LPWSTR)((LPSTR)pBlock + info->wLength);
854             DWORD pos = (LPCSTR)*lplpBuffer - (LPCSTR)pBlock;
855             DWORD max = (info->wLength - sizeof(VS_FIXEDFILEINFO)) * 4 - info->wLength;
856
857             len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)*lplpBuffer, -1,
858                                       lpBufferW + pos, max/sizeof(WCHAR) - pos );
859             *lplpBuffer = lpBufferW + pos;
860             *puLen = len;
861         }
862         return ret;
863     }
864
865     return VersionInfo32_QueryValue(info, lpSubBlock, lplpBuffer, puLen);
866 }