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