Add tests for VerQueryValue[AW].
[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
568     TRACE("(%s,%p)\n", debugstr_a(filename), handle );
569
570     if(filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename);
571     else filenameW.Buffer = NULL;
572     retval = GetFileVersionInfoSizeW(filenameW.Buffer, handle);
573     RtlFreeUnicodeString(&filenameW);
574     return retval;
575 }
576
577 /***********************************************************************
578  *           GetFileVersionInfoA             [VERSION.@]
579  */
580 BOOL WINAPI GetFileVersionInfoA( LPCSTR filename, DWORD handle,
581                                     DWORD datasize, LPVOID data )
582 {   UNICODE_STRING filenameW;
583     DWORD len;
584
585     TRACE("(%s,%ld,size=%ld,data=%p)\n",
586                 debugstr_a(filename), handle, datasize, data );
587
588     if (!data)
589     {
590         SetLastError(ERROR_INVALID_DATA);
591         return FALSE;
592     }
593     if(filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename);
594     else filenameW.Buffer = NULL;
595     len = VERSION_GetFileVersionInfo_PE(filenameW.Buffer, datasize, data);
596     /* 0xFFFFFFFF means: file is a PE module, but VERSION_INFO not found */
597     RtlFreeUnicodeString(&filenameW);
598     if (len == 0xFFFFFFFF)
599     {
600         SetLastError(ERROR_RESOURCE_DATA_NOT_FOUND);
601         return FALSE;
602     }
603
604     if (!len)
605     {
606         len = VERSION_GetFileVersionInfo_16(filename, datasize, data);
607         /* 0xFFFFFFFF means: file exists, but VERSION_INFO not found */
608         if (!len || len == 0xFFFFFFFF)
609         {
610             SetLastError(ERROR_RESOURCE_DATA_NOT_FOUND);
611             return FALSE;
612         }
613     }
614
615     /* Don't convert a possible win32 to a win16 stucture, Windows always uses win32
616      * for storing the structure on a unicode enabled system
617      */
618
619     SetLastError(0);
620     return TRUE;
621 }
622
623 /***********************************************************************
624  *           GetFileVersionInfoW             [VERSION.@]
625  */
626 BOOL WINAPI GetFileVersionInfoW( LPCWSTR filename, DWORD handle,
627                                     DWORD datasize, LPVOID data )
628 {
629     DWORD len;
630
631     TRACE("(%s,%ld,size=%ld,data=%p)\n",
632                 debugstr_w(filename), handle, datasize, data );
633
634     if (!data)
635     {
636         SetLastError(ERROR_INVALID_DATA);
637         return FALSE;
638     }
639     len = VERSION_GetFileVersionInfo_PE(filename, datasize, data);
640     /* 0xFFFFFFFF means: file is a PE module, but VERSION_INFO not found */
641     if (len == 0xFFFFFFFF)
642     {
643         SetLastError(ERROR_RESOURCE_DATA_NOT_FOUND);
644         return FALSE;
645     }
646
647     if (!len)
648     {
649         LPSTR filenameA;
650
651         len = WideCharToMultiByte( CP_ACP, 0, filename, -1, NULL, 0, NULL, NULL );
652         filenameA = HeapAlloc( GetProcessHeap(), 0, len );
653         WideCharToMultiByte( CP_ACP, 0, filename, -1, filenameA, len, NULL, NULL );
654
655         len = VERSION_GetFileVersionInfo_16(filenameA, datasize, data);
656         HeapFree( GetProcessHeap(), 0, filenameA );
657         /* 0xFFFFFFFF means: file exists, but VERSION_INFO not found */
658         if (!len || len == 0xFFFFFFFF)
659         {
660             SetLastError(ERROR_RESOURCE_DATA_NOT_FOUND);
661             return FALSE;
662         }
663     }
664
665     if ( datasize >= sizeof(VS_VERSION_INFO_STRUCT16) &&
666          datasize >= ((VS_VERSION_INFO_STRUCT16 *)data)->wLength &&
667          VersionInfoIs16( data ) )
668     {
669         ERR("Cannot access NE resource in %s\n", debugstr_w(filename) );
670         SetLastError(ERROR_RESOURCE_DATA_NOT_FOUND);
671         return  FALSE;
672     }
673
674     SetLastError(0);
675     return TRUE;
676 }
677
678
679 /***********************************************************************
680  *           VersionInfo16_FindChild             [internal]
681  */
682 static VS_VERSION_INFO_STRUCT16 *VersionInfo16_FindChild( VS_VERSION_INFO_STRUCT16 *info,
683                                             LPCSTR szKey, UINT cbKey )
684 {
685     VS_VERSION_INFO_STRUCT16 *child = VersionInfo16_Children( info );
686
687     while ( (DWORD)child < (DWORD)info + info->wLength )
688     {
689         if ( !strncasecmp( child->szKey, szKey, cbKey ) )
690             return child;
691
692         if (!(child->wLength)) return NULL;
693         child = VersionInfo16_Next( child );
694     }
695
696     return NULL;
697 }
698
699 /***********************************************************************
700  *           VersionInfo32_FindChild             [internal]
701  */
702 static VS_VERSION_INFO_STRUCT32 *VersionInfo32_FindChild( VS_VERSION_INFO_STRUCT32 *info,
703                                             LPCWSTR szKey, UINT cbKey )
704 {
705     VS_VERSION_INFO_STRUCT32 *child = VersionInfo32_Children( info );
706
707     while ( (DWORD)child < (DWORD)info + info->wLength )
708     {
709         if ( !strncmpiW( child->szKey, szKey, cbKey ) )
710             return child;
711
712         child = VersionInfo32_Next( child );
713     }
714
715     return NULL;
716 }
717
718 /***********************************************************************
719  *           VersionInfo16_QueryValue              [internal]
720  *
721  *    Gets a value from a 16-bit NE resource
722  */
723 DWORD WINAPI VersionInfo16_QueryValue( VS_VERSION_INFO_STRUCT16 *info, LPCSTR lpSubBlock,
724                                LPVOID *lplpBuffer, UINT *puLen )
725 {
726     while ( *lpSubBlock )
727     {
728         /* Find next path component */
729         LPCSTR lpNextSlash;
730         for ( lpNextSlash = lpSubBlock; *lpNextSlash; lpNextSlash++ )
731             if ( *lpNextSlash == '\\' )
732                 break;
733
734         /* Skip empty components */
735         if ( lpNextSlash == lpSubBlock )
736         {
737             lpSubBlock++;
738             continue;
739         }
740
741         /* We have a non-empty component: search info for key */
742         info = VersionInfo16_FindChild( info, lpSubBlock, lpNextSlash-lpSubBlock );
743         if ( !info ) return FALSE;
744
745         /* Skip path component */
746         lpSubBlock = lpNextSlash;
747     }
748
749     /* Return value */
750     *lplpBuffer = VersionInfo16_Value( info );
751     if (puLen)
752         *puLen = info->wValueLength;
753
754     return TRUE;
755 }
756
757 /***********************************************************************
758  *           VerQueryValueA              [VERSION.@]
759  */
760 DWORD WINAPI VerQueryValueA( LPVOID pBlock, LPCSTR lpSubBlock,
761                                LPVOID *lplpBuffer, UINT *puLen )
762 {
763     VS_VERSION_INFO_STRUCT16 *info = (VS_VERSION_INFO_STRUCT16 *)pBlock;
764
765     TRACE("(%p,%s,%p,%p)\n",
766                 pBlock, debugstr_a(lpSubBlock), lplpBuffer, puLen );
767
768     if ( !VersionInfoIs16( info ) )
769     {
770         /* FIXME : The conversion is maybe a bit overkill, we only need 1 value */
771
772         ConvertVersionInfo32To16( (VS_VERSION_INFO_STRUCT32 *)info,
773                                   (VS_VERSION_INFO_STRUCT16 *)info );
774     }
775
776     return VersionInfo16_QueryValue(info, lpSubBlock, lplpBuffer, puLen);
777 }
778
779 /***********************************************************************
780  *           VerQueryValueW              [VERSION.@]
781  */
782 DWORD WINAPI VerQueryValueW( LPVOID pBlock, LPCWSTR lpSubBlock,
783                                LPVOID *lplpBuffer, UINT *puLen )
784 {
785     VS_VERSION_INFO_STRUCT32 *info = (VS_VERSION_INFO_STRUCT32 *)pBlock;
786
787     TRACE("(%p,%s,%p,%p)\n",
788                 pBlock, debugstr_w(lpSubBlock), lplpBuffer, puLen );
789
790     if ( VersionInfoIs16( info ) )
791     {
792         DWORD ret;
793         int len = WideCharToMultiByte(CP_ACP, 0, lpSubBlock, -1, NULL, 0, NULL, NULL);
794         LPSTR lpSubBlockA = HeapAlloc(GetProcessHeap(), 0, len * sizeof(char));
795         if (!lpSubBlockA)
796             return FALSE;
797         WideCharToMultiByte(CP_ACP, 0, lpSubBlock, -1, lpSubBlockA, len, NULL, NULL);
798         ret = VersionInfo16_QueryValue(pBlock, lpSubBlockA, lplpBuffer, puLen);
799         HeapFree(GetProcessHeap(), 0, lpSubBlockA);
800         return ret;
801     }
802
803     while ( *lpSubBlock )
804     {
805         /* Find next path component */
806         LPCWSTR lpNextSlash;
807         for ( lpNextSlash = lpSubBlock; *lpNextSlash; lpNextSlash++ )
808             if ( *lpNextSlash == '\\' )
809                 break;
810
811         /* Skip empty components */
812         if ( lpNextSlash == lpSubBlock )
813         {
814             lpSubBlock++;
815             continue;
816         }
817
818         /* We have a non-empty component: search info for key */
819         info = VersionInfo32_FindChild( info, lpSubBlock, lpNextSlash-lpSubBlock );
820         if ( !info ) return FALSE;
821
822         /* Skip path component */
823         lpSubBlock = lpNextSlash;
824     }
825
826     /* Return value */
827     *lplpBuffer = VersionInfo32_Value( info );
828     if (puLen)
829         *puLen = info->wValueLength;
830
831     return TRUE;
832 }