Implemented NtCreatelFile using the new symlink scheme.
[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 END:
355     FreeResource(hMem);
356     FreeLibrary(hModule);
357
358     return len;
359 }
360
361 /***********************************************************************
362  *           VERSION_GetFileVersionInfo_16             [internal]
363  *
364  *    NOTE: returns size of the 16-bit VERSION resource or 0xFFFFFFFF
365  *    in the case if file exists, but VERSION_INFO not found.
366  *    FIXME: handle is not used.
367  */
368 static DWORD VERSION_GetFileVersionInfo_16( LPCSTR filename, LPDWORD handle,
369                                     DWORD datasize, LPVOID data )
370 {
371     VS_FIXEDFILEINFO *vffi;
372     DWORD len;
373     BYTE *buf;
374     HMODULE16 hModule;
375     HRSRC16 hRsrc;
376     HGLOBAL16 hMem;
377
378     TRACE("(%s,%p)\n", debugstr_a(filename), handle );
379
380     hModule = LoadLibrary16(filename);
381     if(hModule < 32)
382     {
383         WARN("Could not load %s\n", debugstr_a(filename));
384         return 0;
385     }
386     hRsrc = FindResource16(hModule,
387                           MAKEINTRESOURCEA(VS_VERSION_INFO),
388                           MAKEINTRESOURCEA(VS_FILE_INFO));
389     if(!hRsrc)
390     {
391         WARN("Could not find VS_VERSION_INFO in %s\n", debugstr_a(filename));
392         FreeLibrary16(hModule);
393         return 0xFFFFFFFF;
394     }
395     len = SizeofResource16(hModule, hRsrc);
396     hMem = LoadResource16(hModule, hRsrc);
397     if(!hMem)
398     {
399         WARN("Could not load VS_VERSION_INFO from %s\n", debugstr_a(filename));
400         FreeLibrary16(hModule);
401         return 0xFFFFFFFF;
402     }
403     buf = LockResource16(hMem);
404
405     if(!VersionInfoIs16(buf))
406         goto END;
407
408     vffi = (VS_FIXEDFILEINFO *)VersionInfo16_Value( (VS_VERSION_INFO_STRUCT16 *)buf );
409
410     if ( vffi->dwSignature != VS_FFI_SIGNATURE )
411     {
412         WARN("vffi->dwSignature is 0x%08lx, but not 0x%08lx!\n",
413                    vffi->dwSignature, VS_FFI_SIGNATURE );
414         len = 0xFFFFFFFF;
415         goto END;
416     }
417
418     if ( TRACE_ON(ver) )
419         print_vffi_debug( vffi );
420
421     if(data)
422     {
423         if(datasize < len)
424             len = datasize; /* truncate data */
425         if(len)
426             memcpy(data, buf, len);
427         else
428             len = 0xFFFFFFFF;
429     }
430 END:
431     FreeResource16(hMem);
432     FreeLibrary16(hModule);
433
434     return len;
435 }
436
437 /***********************************************************************
438  *           GetFileVersionInfoSizeW         [VERSION.@]
439  */
440 DWORD WINAPI GetFileVersionInfoSizeW( LPCWSTR filename, LPDWORD handle )
441 {
442     DWORD ret, offset, len = (filename && strlenW(filename)) ? strlenW(filename) + 1: MAX_PATH;
443     DWORD nSize = len;
444     LPSTR filenameA = NULL;
445     LPWSTR filenameW;
446     VS_FIXEDFILEINFO *vffi;
447     BYTE buf[144];
448
449     TRACE("(%s,%p)\n", debugstr_w(filename), handle );
450
451     filenameW = HeapAlloc( GetProcessHeap(), 0, sizeof(WCHAR) * len );
452     if (filename && strlenW(filename))
453         strcpyW(filenameW, filename);
454     else {
455         nSize = GetModuleFileNameW(NULL, filenameW, nSize);
456         if((nSize +1) >= len)
457             FIXME("buffer may be too small\n");
458     }
459
460     len = VERSION_GetFileVersionInfo_PE(filenameW, handle, 0, NULL);
461     /* 0xFFFFFFFF means: file exists, but VERSION_INFO not found */
462     if(len == 0xFFFFFFFF)
463     {
464         if ( handle ) *handle = 0L;
465         SetLastError(ERROR_RESOURCE_DATA_NOT_FOUND);
466         len = 0;
467         goto End;
468     }
469     if(len) {
470         if ( handle ) *handle = 0L;
471         goto End;
472     }
473
474     /* FIXME: handle not set correctly after this point
475      */
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, handle, 0, NULL);
482     /* 0xFFFFFFFF means: file exists, but VERSION_INFO not found */
483     if(len == 0xFFFFFFFF)
484     {
485         SetLastError(ERROR_RESOURCE_DATA_NOT_FOUND);
486         len = 0;
487         goto End;
488     }
489     if(len) goto End;
490
491     /* FIXME: last error not handled after this point
492      */
493     len = GetFileResourceSize16( filenameA,
494                                  MAKEINTRESOURCEA(VS_FILE_INFO),
495                                  MAKEINTRESOURCEA(VS_VERSION_INFO),
496                                  &offset );
497     if (!len) goto End;
498
499     ret = GetFileResource16( filenameA,
500                              MAKEINTRESOURCEA(VS_FILE_INFO),
501                              MAKEINTRESOURCEA(VS_VERSION_INFO),
502                              offset, sizeof( buf ), buf );
503     if (!ret) goto End;
504
505     if ( handle ) *handle = offset;
506
507     if ( VersionInfoIs16( buf ) )
508         vffi = (VS_FIXEDFILEINFO *)VersionInfo16_Value( (VS_VERSION_INFO_STRUCT16 *)buf );
509     else
510         vffi = (VS_FIXEDFILEINFO *)VersionInfo32_Value( (VS_VERSION_INFO_STRUCT32 *)buf );
511
512     if ( vffi->dwSignature != VS_FFI_SIGNATURE )
513     {
514         WARN("vffi->dwSignature is 0x%08lx, but not 0x%08lx!\n",
515                    vffi->dwSignature, VS_FFI_SIGNATURE );
516         len = 0;
517         goto End;
518     }
519
520     if ( ((VS_VERSION_INFO_STRUCT16 *)buf)->wLength < len )
521         len = ((VS_VERSION_INFO_STRUCT16 *)buf)->wLength;
522
523     if ( TRACE_ON(ver) )
524         print_vffi_debug( vffi );
525 End:
526     HeapFree( GetProcessHeap(), 0, filenameW);
527     if (filenameA)
528         HeapFree( GetProcessHeap(), 0, filenameA);
529     return len;
530 }
531
532 /***********************************************************************
533  *           GetFileVersionInfoSizeA         [VERSION.@]
534  */
535 DWORD WINAPI GetFileVersionInfoSizeA( LPCSTR filename, LPDWORD handle )
536 {   UNICODE_STRING filenameW;
537     DWORD retval;
538     if(filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename);
539     else filenameW.Buffer = NULL;
540     retval = GetFileVersionInfoSizeW(filenameW.Buffer, handle);
541     RtlFreeUnicodeString(&filenameW);
542     return retval;
543 }
544
545 /***********************************************************************
546  *           GetFileVersionInfoA             [VERSION.@]
547  */
548 BOOL WINAPI GetFileVersionInfoA( LPCSTR filename, DWORD handle,
549                                     DWORD datasize, LPVOID data )
550 {   UNICODE_STRING filenameW;
551     DWORD len;
552
553     TRACE("(%s,%ld,size=%ld,data=%p)\n",
554                 debugstr_a(filename), handle, datasize, data );
555
556     if(filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename);
557     else filenameW.Buffer = NULL;
558     len = VERSION_GetFileVersionInfo_PE(filenameW.Buffer, &handle, datasize, data);
559     /* 0xFFFFFFFF means: file exists, but VERSION_INFO not found */
560     RtlFreeUnicodeString(&filenameW);
561     if(len == 0xFFFFFFFF) return FALSE;
562     if(len)
563         goto DO_CONVERT;
564     len = VERSION_GetFileVersionInfo_16(filename, &handle, datasize, data);
565     /* 0xFFFFFFFF means: file exists, but VERSION_INFO not found */
566     if(len == 0xFFFFFFFF) return FALSE;
567     if(len)
568         goto DO_CONVERT;
569
570     if ( !GetFileResource16( filename, MAKEINTRESOURCEA(VS_FILE_INFO),
571                                        MAKEINTRESOURCEA(VS_VERSION_INFO),
572                                        handle, datasize, data ) )
573         return FALSE;
574 DO_CONVERT:
575     if (    datasize >= sizeof(VS_VERSION_INFO_STRUCT16)
576          && datasize >= ((VS_VERSION_INFO_STRUCT16 *)data)->wLength
577          && !VersionInfoIs16( data ) )
578     {
579         /* convert resource from PE format to NE format */
580         ConvertVersionInfo32To16( (VS_VERSION_INFO_STRUCT32 *)data,
581                                   (VS_VERSION_INFO_STRUCT16 *)data );
582     }
583
584     return TRUE;
585 }
586
587 /***********************************************************************
588  *           GetFileVersionInfoW             [VERSION.@]
589  */
590 BOOL WINAPI GetFileVersionInfoW( LPCWSTR filename, DWORD handle,
591                                     DWORD datasize, LPVOID data )
592 {
593     DWORD len = WideCharToMultiByte( CP_ACP, 0, filename, -1, NULL, 0, NULL, NULL );
594     LPSTR fn = HeapAlloc( GetProcessHeap(), 0, len );
595     DWORD retv = TRUE;
596
597     WideCharToMultiByte( CP_ACP, 0, filename, -1, fn, len, NULL, NULL );
598
599     TRACE("(%s,%ld,size=%ld,data=%p)\n",
600                 debugstr_w(filename), handle, datasize, data );
601
602     if(VERSION_GetFileVersionInfo_PE(filename, &handle, datasize, data))
603         goto END;
604     if(VERSION_GetFileVersionInfo_16(fn, &handle, datasize, data))
605         goto END;
606
607     if ( !GetFileResource16( fn, MAKEINTRESOURCEA(VS_FILE_INFO),
608                                  MAKEINTRESOURCEA(VS_VERSION_INFO),
609                                  handle, datasize, data ) )
610         retv = FALSE;
611
612     else if (    datasize >= sizeof(VS_VERSION_INFO_STRUCT16)
613               && datasize >= ((VS_VERSION_INFO_STRUCT16 *)data)->wLength
614               && VersionInfoIs16( data ) )
615     {
616         ERR("Cannot access NE resource in %s\n", debugstr_a(fn) );
617         retv =  FALSE;
618     }
619 END:
620     HeapFree( GetProcessHeap(), 0, fn );
621     return retv;
622 }
623
624
625 /***********************************************************************
626  *           VersionInfo16_FindChild             [internal]
627  */
628 static VS_VERSION_INFO_STRUCT16 *VersionInfo16_FindChild( VS_VERSION_INFO_STRUCT16 *info,
629                                             LPCSTR szKey, UINT cbKey )
630 {
631     VS_VERSION_INFO_STRUCT16 *child = VersionInfo16_Children( info );
632
633     while ( (DWORD)child < (DWORD)info + info->wLength )
634     {
635         if ( !strncasecmp( child->szKey, szKey, cbKey ) )
636             return child;
637
638         if (!(child->wLength)) return NULL;
639         child = VersionInfo16_Next( child );
640     }
641
642     return NULL;
643 }
644
645 /***********************************************************************
646  *           VersionInfo32_FindChild             [internal]
647  */
648 static VS_VERSION_INFO_STRUCT32 *VersionInfo32_FindChild( VS_VERSION_INFO_STRUCT32 *info,
649                                             LPCWSTR szKey, UINT cbKey )
650 {
651     VS_VERSION_INFO_STRUCT32 *child = VersionInfo32_Children( info );
652
653     while ( (DWORD)child < (DWORD)info + info->wLength )
654     {
655         if ( !strncmpiW( child->szKey, szKey, cbKey ) )
656             return child;
657
658         child = VersionInfo32_Next( child );
659     }
660
661     return NULL;
662 }
663
664 /***********************************************************************
665  *           VersionInfo16_QueryValue              [internal]
666  *
667  *    Gets a value from a 16-bit NE resource
668  */
669 DWORD WINAPI VersionInfo16_QueryValue( VS_VERSION_INFO_STRUCT16 *info, LPCSTR lpSubBlock,
670                                LPVOID *lplpBuffer, UINT *puLen )
671 {
672     while ( *lpSubBlock )
673     {
674         /* Find next path component */
675         LPCSTR lpNextSlash;
676         for ( lpNextSlash = lpSubBlock; *lpNextSlash; lpNextSlash++ )
677             if ( *lpNextSlash == '\\' )
678                 break;
679
680         /* Skip empty components */
681         if ( lpNextSlash == lpSubBlock )
682         {
683             lpSubBlock++;
684             continue;
685         }
686
687         /* We have a non-empty component: search info for key */
688         info = VersionInfo16_FindChild( info, lpSubBlock, lpNextSlash-lpSubBlock );
689         if ( !info ) return FALSE;
690
691         /* Skip path component */
692         lpSubBlock = lpNextSlash;
693     }
694
695     /* Return value */
696     *lplpBuffer = VersionInfo16_Value( info );
697     *puLen = info->wValueLength;
698
699     return TRUE;
700 }
701
702 /***********************************************************************
703  *           VerQueryValueA              [VERSION.@]
704  */
705 DWORD WINAPI VerQueryValueA( LPVOID pBlock, LPCSTR lpSubBlock,
706                                LPVOID *lplpBuffer, UINT *puLen )
707 {
708     VS_VERSION_INFO_STRUCT16 *info = (VS_VERSION_INFO_STRUCT16 *)pBlock;
709
710     TRACE("(%p,%s,%p,%p)\n",
711                 pBlock, debugstr_a(lpSubBlock), lplpBuffer, puLen );
712
713     if ( !VersionInfoIs16( info ) )
714     {
715         INT len;
716         LPWSTR wide_str;
717         DWORD give;
718
719         /* <lawson_whitney@juno.com> Feb 2001 */
720         /* AOL 5.0 does this, expecting to get this: */
721         len = MultiByteToWideChar(CP_ACP, 0, lpSubBlock, -1, NULL, 0);
722         wide_str = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
723         MultiByteToWideChar(CP_ACP, 0, lpSubBlock, -1, wide_str, len);
724
725         give = VerQueryValueW(pBlock, wide_str, lplpBuffer, puLen);
726         HeapFree(GetProcessHeap(), 0, wide_str);
727         return give;
728     }
729
730     return VersionInfo16_QueryValue(info, lpSubBlock, lplpBuffer, puLen);
731 }
732
733 /***********************************************************************
734  *           VerQueryValueW              [VERSION.@]
735  */
736 DWORD WINAPI VerQueryValueW( LPVOID pBlock, LPCWSTR lpSubBlock,
737                                LPVOID *lplpBuffer, UINT *puLen )
738 {
739     VS_VERSION_INFO_STRUCT32 *info = (VS_VERSION_INFO_STRUCT32 *)pBlock;
740
741     TRACE("(%p,%s,%p,%p)\n",
742                 pBlock, debugstr_w(lpSubBlock), lplpBuffer, puLen );
743
744     if ( VersionInfoIs16( info ) )
745     {
746         DWORD ret;
747         int len = WideCharToMultiByte(CP_ACP, 0, lpSubBlock, -1, NULL, 0, NULL, NULL);
748         LPSTR lpSubBlockA = HeapAlloc(GetProcessHeap(), 0, len * sizeof(char));
749         if (!lpSubBlockA)
750             return FALSE;
751         WideCharToMultiByte(CP_ACP, 0, lpSubBlock, -1, lpSubBlockA, len, NULL, NULL);
752         ret = VersionInfo16_QueryValue(pBlock, lpSubBlockA, lplpBuffer, puLen);
753         HeapFree(GetProcessHeap(), 0, lpSubBlockA);
754         return ret;
755     }
756
757     while ( *lpSubBlock )
758     {
759         /* Find next path component */
760         LPCWSTR lpNextSlash;
761         for ( lpNextSlash = lpSubBlock; *lpNextSlash; lpNextSlash++ )
762             if ( *lpNextSlash == '\\' )
763                 break;
764
765         /* Skip empty components */
766         if ( lpNextSlash == lpSubBlock )
767         {
768             lpSubBlock++;
769             continue;
770         }
771
772         /* We have a non-empty component: search info for key */
773         info = VersionInfo32_FindChild( info, lpSubBlock, lpNextSlash-lpSubBlock );
774         if ( !info ) return FALSE;
775
776         /* Skip path component */
777         lpSubBlock = lpNextSlash;
778     }
779
780     /* Return value */
781     *lplpBuffer = VersionInfo32_Value( info );
782     *puLen = info->wValueLength;
783
784     return TRUE;
785 }