Assorted spelling fixes.
[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  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  * TODO
23  *   o Verify VerQueryValue()
24  */
25
26 #include <stdarg.h>
27 #include <stdlib.h>
28 #include <string.h>
29
30 #include "windef.h"
31 #include "winbase.h"
32 #include "winreg.h"
33 #include "winver.h"
34 #include "winternl.h"
35 #include "wine/winuser16.h"
36 #include "wine/unicode.h"
37 #include "winerror.h"
38 #include "wine/debug.h"
39
40 WINE_DEFAULT_DEBUG_CHANNEL(ver);
41
42
43 /******************************************************************************
44  *
45  *   This function will print via dprintf[_]ver to stddeb debug info regarding
46  *   the file info structure vffi.
47  *      15-Feb-1998 Dimitrie Paun (dimi@cs.toronto.edu)
48  *      Added this function to clean up the code.
49  *
50  *****************************************************************************/
51 static void print_vffi_debug(VS_FIXEDFILEINFO *vffi)
52 {
53         TRACE(" structversion=%u.%u, fileversion=%u.%u.%u.%u, productversion=%u.%u.%u.%u, flagmask=0x%lx, flags=%s%s%s%s%s%s\n",
54                     HIWORD(vffi->dwStrucVersion),LOWORD(vffi->dwStrucVersion),
55                     HIWORD(vffi->dwFileVersionMS),LOWORD(vffi->dwFileVersionMS),
56                     HIWORD(vffi->dwFileVersionLS),LOWORD(vffi->dwFileVersionLS),
57                     HIWORD(vffi->dwProductVersionMS),LOWORD(vffi->dwProductVersionMS),
58                     HIWORD(vffi->dwProductVersionLS),LOWORD(vffi->dwProductVersionLS),
59                     vffi->dwFileFlagsMask,
60                     (vffi->dwFileFlags & VS_FF_DEBUG) ? "DEBUG," : "",
61                     (vffi->dwFileFlags & VS_FF_PRERELEASE) ? "PRERELEASE," : "",
62                     (vffi->dwFileFlags & VS_FF_PATCHED) ? "PATCHED," : "",
63                     (vffi->dwFileFlags & VS_FF_PRIVATEBUILD) ? "PRIVATEBUILD," : "",
64                     (vffi->dwFileFlags & VS_FF_INFOINFERRED) ? "INFOINFERRED," : "",
65                     (vffi->dwFileFlags & VS_FF_SPECIALBUILD) ? "SPECIALBUILD," : ""
66                     );
67
68         TRACE("(");
69         TRACE(" OS=0x%x.0x%x ",
70                 HIWORD(vffi->dwFileOS),
71                 LOWORD(vffi->dwFileOS)
72         );
73         switch (vffi->dwFileOS&0xFFFF0000) {
74         case VOS_DOS:TRACE("DOS,");break;
75         case VOS_OS216:TRACE("OS/2-16,");break;
76         case VOS_OS232:TRACE("OS/2-32,");break;
77         case VOS_NT:TRACE("NT,");break;
78         case VOS_UNKNOWN:
79         default:
80                 TRACE("UNKNOWN(0x%lx),",vffi->dwFileOS&0xFFFF0000);break;
81         }
82         switch (LOWORD(vffi->dwFileOS)) {
83         case VOS__BASE:TRACE("BASE");break;
84         case VOS__WINDOWS16:TRACE("WIN16");break;
85         case VOS__WINDOWS32:TRACE("WIN32");break;
86         case VOS__PM16:TRACE("PM16");break;
87         case VOS__PM32:TRACE("PM32");break;
88         default:TRACE("UNKNOWN(0x%x)",LOWORD(vffi->dwFileOS));break;
89         }
90         TRACE(")\n");
91
92         switch (vffi->dwFileType) {
93         default:
94         case VFT_UNKNOWN:
95                 TRACE("filetype=Unknown(0x%lx)",vffi->dwFileType);
96                 break;
97         case VFT_APP:TRACE("filetype=APP,");break;
98         case VFT_DLL:TRACE("filetype=DLL,");break;
99         case VFT_DRV:
100                 TRACE("filetype=DRV,");
101                 switch(vffi->dwFileSubtype) {
102                 default:
103                 case VFT2_UNKNOWN:
104                         TRACE("UNKNOWN(0x%lx)",vffi->dwFileSubtype);
105                         break;
106                 case VFT2_DRV_PRINTER:
107                         TRACE("PRINTER");
108                         break;
109                 case VFT2_DRV_KEYBOARD:
110                         TRACE("KEYBOARD");
111                         break;
112                 case VFT2_DRV_LANGUAGE:
113                         TRACE("LANGUAGE");
114                         break;
115                 case VFT2_DRV_DISPLAY:
116                         TRACE("DISPLAY");
117                         break;
118                 case VFT2_DRV_MOUSE:
119                         TRACE("MOUSE");
120                         break;
121                 case VFT2_DRV_NETWORK:
122                         TRACE("NETWORK");
123                         break;
124                 case VFT2_DRV_SYSTEM:
125                         TRACE("SYSTEM");
126                         break;
127                 case VFT2_DRV_INSTALLABLE:
128                         TRACE("INSTALLABLE");
129                         break;
130                 case VFT2_DRV_SOUND:
131                         TRACE("SOUND");
132                         break;
133                 case VFT2_DRV_COMM:
134                         TRACE("COMM");
135                         break;
136                 case VFT2_DRV_INPUTMETHOD:
137                         TRACE("INPUTMETHOD");
138                         break;
139                 }
140                 break;
141         case VFT_FONT:
142                 TRACE("filetype=FONT.");
143                 switch (vffi->dwFileSubtype) {
144                 default:
145                         TRACE("UNKNOWN(0x%lx)",vffi->dwFileSubtype);
146                         break;
147                 case VFT2_FONT_RASTER:TRACE("RASTER");break;
148                 case VFT2_FONT_VECTOR:TRACE("VECTOR");break;
149                 case VFT2_FONT_TRUETYPE:TRACE("TRUETYPE");break;
150                 }
151                 break;
152         case VFT_VXD:TRACE("filetype=VXD");break;
153         case VFT_STATIC_LIB:TRACE("filetype=STATIC_LIB");break;
154         }
155         TRACE("\n");
156         TRACE("  filedata=0x%lx.0x%lx\n",
157                     vffi->dwFileDateMS,vffi->dwFileDateLS);
158 }
159
160
161 /***********************************************************************
162  * Version Info Structure
163  */
164
165 typedef struct
166 {
167     WORD  wLength;
168     WORD  wValueLength;
169     CHAR  szKey[1];
170 #if 0   /* variable length structure */
171     /* DWORD aligned */
172     BYTE  Value[];
173     /* DWORD aligned */
174     VS_VERSION_INFO_STRUCT16 Children[];
175 #endif
176 } VS_VERSION_INFO_STRUCT16;
177
178 typedef struct
179 {
180     WORD  wLength;
181     WORD  wValueLength;
182     WORD  bText;
183     WCHAR szKey[1];
184 #if 0   /* variable length structure */
185     /* DWORD aligned */
186     BYTE  Value[];
187     /* DWORD aligned */
188     VS_VERSION_INFO_STRUCT32 Children[];
189 #endif
190 } VS_VERSION_INFO_STRUCT32;
191
192 #define VersionInfoIs16( ver ) \
193     ( ((VS_VERSION_INFO_STRUCT16 *)ver)->szKey[0] >= ' ' )
194
195 #define DWORD_ALIGN( base, ptr ) \
196     ( (LPBYTE)(base) + ((((LPBYTE)(ptr) - (LPBYTE)(base)) + 3) & ~3) )
197
198 #define VersionInfo16_Value( ver )  \
199     DWORD_ALIGN( (ver), (ver)->szKey + strlen((ver)->szKey) + 1 )
200 #define VersionInfo32_Value( ver )  \
201     DWORD_ALIGN( (ver), (ver)->szKey + strlenW((ver)->szKey) + 1 )
202
203 #define VersionInfo16_Children( ver )  \
204     (VS_VERSION_INFO_STRUCT16 *)( VersionInfo16_Value( ver ) + \
205                            ( ( (ver)->wValueLength + 3 ) & ~3 ) )
206 #define VersionInfo32_Children( ver )  \
207     (VS_VERSION_INFO_STRUCT32 *)( VersionInfo32_Value( ver ) + \
208                            ( ( (ver)->wValueLength * \
209                                ((ver)->bText? 2 : 1) + 3 ) & ~3 ) )
210
211 #define VersionInfo16_Next( ver ) \
212     (VS_VERSION_INFO_STRUCT16 *)( (LPBYTE)ver + (((ver)->wLength + 3) & ~3) )
213 #define VersionInfo32_Next( ver ) \
214     (VS_VERSION_INFO_STRUCT32 *)( (LPBYTE)ver + (((ver)->wLength + 3) & ~3) )
215
216 /***********************************************************************
217  *           ConvertVersionInfo32To16        [internal]
218  */
219 void ConvertVersionInfo32To16( VS_VERSION_INFO_STRUCT32 *info32,
220                                VS_VERSION_INFO_STRUCT16 *info16 )
221 {
222     /* Copy data onto local stack to prevent overwrites */
223     WORD wLength = info32->wLength;
224     WORD wValueLength = info32->wValueLength;
225     WORD bText = info32->bText;
226     LPBYTE lpValue = VersionInfo32_Value( info32 );
227     VS_VERSION_INFO_STRUCT32 *child32 = VersionInfo32_Children( info32 );
228     VS_VERSION_INFO_STRUCT16 *child16;
229
230     TRACE("Converting %p to %p\n", info32, info16 );
231     TRACE("wLength %d, wValueLength %d, bText %d, value %p, child %p\n",
232                 wLength, wValueLength, bText, lpValue, child32 );
233
234     /* Convert key */
235     WideCharToMultiByte( CP_ACP, 0, info32->szKey, -1, info16->szKey, 0x7fffffff, NULL, NULL );
236
237     TRACE("Copied key from %p to %p: %s\n", info32->szKey, info16->szKey,
238                 debugstr_a(info16->szKey) );
239
240     /* Convert value */
241     if ( wValueLength == 0 )
242     {
243         info16->wValueLength = 0;
244         TRACE("No value present\n" );
245     }
246     else if ( bText )
247     {
248         info16->wValueLength = WideCharToMultiByte( CP_ACP, 0, (LPCWSTR)lpValue, -1, NULL, 0, NULL, NULL );
249         WideCharToMultiByte( CP_ACP, 0, (LPCWSTR)lpValue, -1,
250                              VersionInfo16_Value( info16 ), info16->wValueLength, NULL, NULL );
251
252         TRACE("Copied value from %p to %p: %s\n", lpValue,
253                     VersionInfo16_Value( info16 ),
254                     debugstr_a(VersionInfo16_Value( info16 )) );
255     }
256     else
257     {
258         info16->wValueLength = wValueLength;
259         memmove( VersionInfo16_Value( info16 ), lpValue, wValueLength );
260
261         TRACE("Copied value from %p to %p: %d bytes\n", lpValue,
262                      VersionInfo16_Value( info16 ), wValueLength );
263     }
264
265     /* Convert children */
266     child16 = VersionInfo16_Children( info16 );
267     while ( (DWORD)child32 < (DWORD)info32 + wLength && child32->wLength != 0 )
268     {
269         VS_VERSION_INFO_STRUCT32 *nextChild = VersionInfo32_Next( child32 );
270
271         ConvertVersionInfo32To16( child32, child16 );
272
273         child16 = VersionInfo16_Next( child16 );
274         child32 = nextChild;
275     }
276
277     /* Fixup length */
278     info16->wLength = (DWORD)child16 - (DWORD)info16;
279
280     TRACE("Finished, length is %d (%p - %p)\n",
281                 info16->wLength, info16, child16 );
282 }
283
284 /***********************************************************************
285  *           VERSION_GetFileVersionInfo_PE             [internal]
286  *
287  *    NOTE: returns size of the PE VERSION resource or 0xFFFFFFFF
288  *    in the case if file exists, but VERSION_INFO not found.
289  *    FIXME: handle is not used.
290  */
291 static DWORD VERSION_GetFileVersionInfo_PE( LPCWSTR filename, LPDWORD handle,
292                                     DWORD datasize, LPVOID data )
293 {
294     VS_FIXEDFILEINFO *vffi;
295     DWORD len;
296     BYTE *buf;
297     HMODULE hModule;
298     HRSRC hRsrc;
299     HGLOBAL hMem;
300
301     TRACE("(%s,%p)\n", debugstr_w(filename), handle );
302
303     hModule = GetModuleHandleW(filename);
304     if(!hModule)
305         hModule = LoadLibraryExW(filename, 0, LOAD_LIBRARY_AS_DATAFILE);
306     else
307         hModule = LoadLibraryExW(filename, 0, 0);
308     if(!hModule)
309     {
310         WARN("Could not load %s\n", debugstr_w(filename));
311         return 0;
312     }
313     hRsrc = FindResourceW(hModule,
314                           MAKEINTRESOURCEW(VS_VERSION_INFO),
315                           MAKEINTRESOURCEW(VS_FILE_INFO));
316     if(!hRsrc)
317     {
318         WARN("Could not find VS_VERSION_INFO in %s\n", debugstr_w(filename));
319         FreeLibrary(hModule);
320         return 0xFFFFFFFF;
321     }
322     len = SizeofResource(hModule, hRsrc);
323     hMem = LoadResource(hModule, hRsrc);
324     if(!hMem)
325     {
326         WARN("Could not load VS_VERSION_INFO from %s\n", debugstr_w(filename));
327         FreeLibrary(hModule);
328         return 0xFFFFFFFF;
329     }
330     buf = LockResource(hMem);
331
332     vffi = (VS_FIXEDFILEINFO *)VersionInfo32_Value( (VS_VERSION_INFO_STRUCT32 *)buf );
333
334     if ( vffi->dwSignature != VS_FFI_SIGNATURE )
335     {
336         WARN("vffi->dwSignature is 0x%08lx, but not 0x%08lx!\n",
337                    vffi->dwSignature, VS_FFI_SIGNATURE );
338         len = 0xFFFFFFFF;
339         goto END;
340     }
341
342     if ( TRACE_ON(ver) )
343         print_vffi_debug( vffi );
344
345     if(data)
346     {
347         if(datasize < len)
348             len = datasize; /* truncate data */
349         if(len)
350             memcpy(data, buf, len);
351         else
352             len = 0xFFFFFFFF;
353     }
354     SetLastError(0);
355 END:
356     FreeResource(hMem);
357     FreeLibrary(hModule);
358
359     return len;
360 }
361
362 /***********************************************************************
363  *           VERSION_GetFileVersionInfo_16             [internal]
364  *
365  *    NOTE: returns size of the 16-bit VERSION resource or 0xFFFFFFFF
366  *    in the case if file exists, but VERSION_INFO not found.
367  *    FIXME: handle is not used.
368  */
369 static DWORD VERSION_GetFileVersionInfo_16( LPCSTR filename, LPDWORD handle,
370                                     DWORD datasize, LPVOID data )
371 {
372     VS_FIXEDFILEINFO *vffi;
373     DWORD len;
374     BYTE *buf;
375     HMODULE16 hModule;
376     HRSRC16 hRsrc;
377     HGLOBAL16 hMem;
378
379     TRACE("(%s,%p)\n", debugstr_a(filename), handle );
380
381     hModule = LoadLibrary16(filename);
382     if(hModule < 32)
383     {
384         WARN("Could not load %s\n", debugstr_a(filename));
385         return 0;
386     }
387     hRsrc = FindResource16(hModule,
388                           MAKEINTRESOURCEA(VS_VERSION_INFO),
389                           MAKEINTRESOURCEA(VS_FILE_INFO));
390     if(!hRsrc)
391     {
392         WARN("Could not find VS_VERSION_INFO in %s\n", debugstr_a(filename));
393         FreeLibrary16(hModule);
394         return 0xFFFFFFFF;
395     }
396     len = SizeofResource16(hModule, hRsrc);
397     hMem = LoadResource16(hModule, hRsrc);
398     if(!hMem)
399     {
400         WARN("Could not load VS_VERSION_INFO from %s\n", debugstr_a(filename));
401         FreeLibrary16(hModule);
402         return 0xFFFFFFFF;
403     }
404     buf = LockResource16(hMem);
405
406     if(!VersionInfoIs16(buf))
407         goto END;
408
409     vffi = (VS_FIXEDFILEINFO *)VersionInfo16_Value( (VS_VERSION_INFO_STRUCT16 *)buf );
410
411     if ( vffi->dwSignature != VS_FFI_SIGNATURE )
412     {
413         WARN("vffi->dwSignature is 0x%08lx, but not 0x%08lx!\n",
414                    vffi->dwSignature, VS_FFI_SIGNATURE );
415         len = 0xFFFFFFFF;
416         goto END;
417     }
418
419     if ( TRACE_ON(ver) )
420         print_vffi_debug( vffi );
421
422     if(data)
423     {
424         if(datasize < len)
425             len = datasize; /* truncate data */
426         if(len)
427             memcpy(data, buf, len);
428         else
429             len = 0xFFFFFFFF;
430     }
431 END:
432     FreeResource16(hMem);
433     FreeLibrary16(hModule);
434
435     return len;
436 }
437
438 /***********************************************************************
439  *           GetFileVersionInfoSizeW         [VERSION.@]
440  */
441 DWORD WINAPI GetFileVersionInfoSizeW( LPCWSTR filename, LPDWORD handle )
442 {
443     DWORD ret, offset, len = (filename && strlenW(filename)) ? strlenW(filename) + 1: MAX_PATH;
444     DWORD nSize = len;
445     LPSTR filenameA = NULL;
446     LPWSTR filenameW;
447     VS_FIXEDFILEINFO *vffi;
448     BYTE buf[144];
449
450     TRACE("(%s,%p)\n", debugstr_w(filename), handle );
451
452     filenameW = HeapAlloc( GetProcessHeap(), 0, sizeof(WCHAR) * len );
453     if (filename && strlenW(filename))
454         strcpyW(filenameW, filename);
455     else {
456         nSize = GetModuleFileNameW(NULL, filenameW, nSize);
457         if((nSize +1) >= len)
458             FIXME("buffer may be too small\n");
459     }
460
461     len = VERSION_GetFileVersionInfo_PE(filenameW, handle, 0, NULL);
462     /* 0xFFFFFFFF means: file exists, but VERSION_INFO not found */
463     if(len == 0xFFFFFFFF)
464     {
465         if ( handle ) *handle = 0L;
466         SetLastError(ERROR_RESOURCE_DATA_NOT_FOUND);
467         len = 0;
468         goto End;
469     }
470     if(len) {
471         if ( handle ) *handle = 0L;
472         goto End;
473     }
474
475     /* FIXME: handle not set correctly after this point
476      */
477
478     len = WideCharToMultiByte( CP_ACP, 0, filename, -1, NULL, 0, NULL, NULL );
479     filenameA = HeapAlloc( GetProcessHeap(), 0, len );
480     WideCharToMultiByte( CP_ACP, 0, filename, -1, filenameA, len, NULL, NULL );
481
482     len = VERSION_GetFileVersionInfo_16(filenameA, handle, 0, NULL);
483     /* 0xFFFFFFFF means: file exists, but VERSION_INFO not found */
484     if(len == 0xFFFFFFFF)
485     {
486         SetLastError(ERROR_RESOURCE_DATA_NOT_FOUND);
487         len = 0;
488         goto End;
489     }
490     if(len) goto End;
491
492     /* FIXME: last error not handled after this point
493      */
494     len = GetFileResourceSize16( filenameA,
495                                  MAKEINTRESOURCEA(VS_FILE_INFO),
496                                  MAKEINTRESOURCEA(VS_VERSION_INFO),
497                                  &offset );
498     if (!len) goto End;
499
500     ret = GetFileResource16( filenameA,
501                              MAKEINTRESOURCEA(VS_FILE_INFO),
502                              MAKEINTRESOURCEA(VS_VERSION_INFO),
503                              offset, sizeof( buf ), buf );
504     if (!ret) goto End;
505
506     if ( handle ) *handle = offset;
507
508     if ( VersionInfoIs16( buf ) )
509         vffi = (VS_FIXEDFILEINFO *)VersionInfo16_Value( (VS_VERSION_INFO_STRUCT16 *)buf );
510     else
511         vffi = (VS_FIXEDFILEINFO *)VersionInfo32_Value( (VS_VERSION_INFO_STRUCT32 *)buf );
512
513     if ( vffi->dwSignature != VS_FFI_SIGNATURE )
514     {
515         WARN("vffi->dwSignature is 0x%08lx, but not 0x%08lx!\n",
516                    vffi->dwSignature, VS_FFI_SIGNATURE );
517         len = 0;
518         goto End;
519     }
520
521     if ( ((VS_VERSION_INFO_STRUCT16 *)buf)->wLength < len )
522         len = ((VS_VERSION_INFO_STRUCT16 *)buf)->wLength;
523
524     if ( TRACE_ON(ver) )
525         print_vffi_debug( vffi );
526 End:
527     HeapFree( GetProcessHeap(), 0, filenameW);
528     if (filenameA)
529         HeapFree( GetProcessHeap(), 0, filenameA);
530     return len;
531 }
532
533 /***********************************************************************
534  *           GetFileVersionInfoSizeA         [VERSION.@]
535  */
536 DWORD WINAPI GetFileVersionInfoSizeA( LPCSTR filename, LPDWORD handle )
537 {   UNICODE_STRING filenameW;
538     DWORD retval;
539     if(filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename);
540     else filenameW.Buffer = NULL;
541     retval = GetFileVersionInfoSizeW(filenameW.Buffer, handle);
542     RtlFreeUnicodeString(&filenameW);
543     return retval;
544 }
545
546 /***********************************************************************
547  *           GetFileVersionInfoA             [VERSION.@]
548  */
549 BOOL WINAPI GetFileVersionInfoA( LPCSTR filename, DWORD handle,
550                                     DWORD datasize, LPVOID data )
551 {   UNICODE_STRING filenameW;
552     DWORD len;
553
554     TRACE("(%s,%ld,size=%ld,data=%p)\n",
555                 debugstr_a(filename), handle, datasize, data );
556
557     if(filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename);
558     else filenameW.Buffer = NULL;
559     len = VERSION_GetFileVersionInfo_PE(filenameW.Buffer, &handle, datasize, data);
560     /* 0xFFFFFFFF means: file exists, but VERSION_INFO not found */
561     RtlFreeUnicodeString(&filenameW);
562     if(len == 0xFFFFFFFF) return FALSE;
563     if(len)
564         goto DO_CONVERT;
565     len = VERSION_GetFileVersionInfo_16(filename, &handle, datasize, data);
566     /* 0xFFFFFFFF means: file exists, but VERSION_INFO not found */
567     if(len == 0xFFFFFFFF) return FALSE;
568     if(len)
569         goto DO_CONVERT;
570
571     if ( !GetFileResource16( filename, MAKEINTRESOURCEA(VS_FILE_INFO),
572                                        MAKEINTRESOURCEA(VS_VERSION_INFO),
573                                        handle, datasize, data ) )
574         return FALSE;
575 DO_CONVERT:
576     if (    datasize >= sizeof(VS_VERSION_INFO_STRUCT16)
577          && datasize >= ((VS_VERSION_INFO_STRUCT16 *)data)->wLength
578          && !VersionInfoIs16( data ) )
579     {
580         /* convert resource from PE format to NE format */
581         ConvertVersionInfo32To16( (VS_VERSION_INFO_STRUCT32 *)data,
582                                   (VS_VERSION_INFO_STRUCT16 *)data );
583     }
584
585     return TRUE;
586 }
587
588 /***********************************************************************
589  *           GetFileVersionInfoW             [VERSION.@]
590  */
591 BOOL WINAPI GetFileVersionInfoW( LPCWSTR filename, DWORD handle,
592                                     DWORD datasize, LPVOID data )
593 {
594     DWORD len = WideCharToMultiByte( CP_ACP, 0, filename, -1, NULL, 0, NULL, NULL );
595     LPSTR fn = HeapAlloc( GetProcessHeap(), 0, len );
596     DWORD retv = TRUE;
597
598     WideCharToMultiByte( CP_ACP, 0, filename, -1, fn, len, NULL, NULL );
599
600     TRACE("(%s,%ld,size=%ld,data=%p)\n",
601                 debugstr_w(filename), handle, datasize, data );
602
603     if(VERSION_GetFileVersionInfo_PE(filename, &handle, datasize, data))
604         goto END;
605     if(VERSION_GetFileVersionInfo_16(fn, &handle, datasize, data))
606         goto END;
607
608     if ( !GetFileResource16( fn, MAKEINTRESOURCEA(VS_FILE_INFO),
609                                  MAKEINTRESOURCEA(VS_VERSION_INFO),
610                                  handle, datasize, data ) )
611         retv = FALSE;
612
613     else if (    datasize >= sizeof(VS_VERSION_INFO_STRUCT16)
614               && datasize >= ((VS_VERSION_INFO_STRUCT16 *)data)->wLength
615               && VersionInfoIs16( data ) )
616     {
617         ERR("Cannot access NE resource in %s\n", debugstr_a(fn) );
618         retv =  FALSE;
619     }
620 END:
621     HeapFree( GetProcessHeap(), 0, fn );
622     return retv;
623 }
624
625
626 /***********************************************************************
627  *           VersionInfo16_FindChild             [internal]
628  */
629 static VS_VERSION_INFO_STRUCT16 *VersionInfo16_FindChild( VS_VERSION_INFO_STRUCT16 *info,
630                                             LPCSTR szKey, UINT cbKey )
631 {
632     VS_VERSION_INFO_STRUCT16 *child = VersionInfo16_Children( info );
633
634     while ( (DWORD)child < (DWORD)info + info->wLength )
635     {
636         if ( !strncasecmp( child->szKey, szKey, cbKey ) )
637             return child;
638
639         if (!(child->wLength)) return NULL;
640         child = VersionInfo16_Next( child );
641     }
642
643     return NULL;
644 }
645
646 /***********************************************************************
647  *           VersionInfo32_FindChild             [internal]
648  */
649 static VS_VERSION_INFO_STRUCT32 *VersionInfo32_FindChild( VS_VERSION_INFO_STRUCT32 *info,
650                                             LPCWSTR szKey, UINT cbKey )
651 {
652     VS_VERSION_INFO_STRUCT32 *child = VersionInfo32_Children( info );
653
654     while ( (DWORD)child < (DWORD)info + info->wLength )
655     {
656         if ( !strncmpiW( child->szKey, szKey, cbKey ) )
657             return child;
658
659         child = VersionInfo32_Next( child );
660     }
661
662     return NULL;
663 }
664
665 /***********************************************************************
666  *           VersionInfo16_QueryValue              [internal]
667  *
668  *    Gets a value from a 16-bit NE resource
669  */
670 DWORD WINAPI VersionInfo16_QueryValue( VS_VERSION_INFO_STRUCT16 *info, LPCSTR lpSubBlock,
671                                LPVOID *lplpBuffer, UINT *puLen )
672 {
673     while ( *lpSubBlock )
674     {
675         /* Find next path component */
676         LPCSTR lpNextSlash;
677         for ( lpNextSlash = lpSubBlock; *lpNextSlash; lpNextSlash++ )
678             if ( *lpNextSlash == '\\' )
679                 break;
680
681         /* Skip empty components */
682         if ( lpNextSlash == lpSubBlock )
683         {
684             lpSubBlock++;
685             continue;
686         }
687
688         /* We have a non-empty component: search info for key */
689         info = VersionInfo16_FindChild( info, lpSubBlock, lpNextSlash-lpSubBlock );
690         if ( !info ) return FALSE;
691
692         /* Skip path component */
693         lpSubBlock = lpNextSlash;
694     }
695
696     /* Return value */
697     *lplpBuffer = VersionInfo16_Value( info );
698     *puLen = info->wValueLength;
699
700     return TRUE;
701 }
702
703 /***********************************************************************
704  *           VerQueryValueA              [VERSION.@]
705  */
706 DWORD WINAPI VerQueryValueA( LPVOID pBlock, LPCSTR lpSubBlock,
707                                LPVOID *lplpBuffer, UINT *puLen )
708 {
709     VS_VERSION_INFO_STRUCT16 *info = (VS_VERSION_INFO_STRUCT16 *)pBlock;
710
711     TRACE("(%p,%s,%p,%p)\n",
712                 pBlock, debugstr_a(lpSubBlock), lplpBuffer, puLen );
713
714     if ( !VersionInfoIs16( info ) )
715     {
716         INT len;
717         LPWSTR wide_str;
718         DWORD give;
719
720         /* <lawson_whitney@juno.com> Feb 2001 */
721         /* AOL 5.0 does this, expecting to get this: */
722         len = MultiByteToWideChar(CP_ACP, 0, lpSubBlock, -1, NULL, 0);
723         wide_str = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
724         MultiByteToWideChar(CP_ACP, 0, lpSubBlock, -1, wide_str, len);
725
726         give = VerQueryValueW(pBlock, wide_str, lplpBuffer, puLen);
727         HeapFree(GetProcessHeap(), 0, wide_str);
728         return give;
729     }
730
731     return VersionInfo16_QueryValue(info, lpSubBlock, lplpBuffer, puLen);
732 }
733
734 /***********************************************************************
735  *           VerQueryValueW              [VERSION.@]
736  */
737 DWORD WINAPI VerQueryValueW( LPVOID pBlock, LPCWSTR lpSubBlock,
738                                LPVOID *lplpBuffer, UINT *puLen )
739 {
740     VS_VERSION_INFO_STRUCT32 *info = (VS_VERSION_INFO_STRUCT32 *)pBlock;
741
742     TRACE("(%p,%s,%p,%p)\n",
743                 pBlock, debugstr_w(lpSubBlock), lplpBuffer, puLen );
744
745     if ( VersionInfoIs16( info ) )
746     {
747         DWORD ret;
748         int len = WideCharToMultiByte(CP_ACP, 0, lpSubBlock, -1, NULL, 0, NULL, NULL);
749         LPSTR lpSubBlockA = HeapAlloc(GetProcessHeap(), 0, len * sizeof(char));
750         if (!lpSubBlockA)
751             return FALSE;
752         WideCharToMultiByte(CP_ACP, 0, lpSubBlock, -1, lpSubBlockA, len, NULL, NULL);
753         ret = VersionInfo16_QueryValue(pBlock, lpSubBlockA, lplpBuffer, puLen);
754         HeapFree(GetProcessHeap(), 0, lpSubBlockA);
755         return ret;
756     }
757
758     while ( *lpSubBlock )
759     {
760         /* Find next path component */
761         LPCWSTR lpNextSlash;
762         for ( lpNextSlash = lpSubBlock; *lpNextSlash; lpNextSlash++ )
763             if ( *lpNextSlash == '\\' )
764                 break;
765
766         /* Skip empty components */
767         if ( lpNextSlash == lpSubBlock )
768         {
769             lpSubBlock++;
770             continue;
771         }
772
773         /* We have a non-empty component: search info for key */
774         info = VersionInfo32_FindChild( info, lpSubBlock, lpNextSlash-lpSubBlock );
775         if ( !info ) return FALSE;
776
777         /* Skip path component */
778         lpSubBlock = lpNextSlash;
779     }
780
781     /* Return value */
782     *lplpBuffer = VersionInfo32_Value( info );
783     *puLen = info->wValueLength;
784
785     return TRUE;
786 }