ntdll: Fix compilation on systems that don't support nameless unions.
[wine] / dlls / setupapi / query.c
1 /*
2  * setupapi query functions
3  *
4  * Copyright 2006 James Hawkins
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include <stdarg.h>
22
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winuser.h"
26 #include "winreg.h"
27 #include "setupapi.h"
28 #include "advpub.h"
29 #include "winnls.h"
30 #include "wine/debug.h"
31 #include "wine/unicode.h"
32 #include "setupapi_private.h"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
35
36 #ifdef __i386__
37 static const WCHAR source_disks_names_platform[] =
38     {'S','o','u','r','c','e','D','i','s','k','s','N','a','m','e','s','.','x','8','6',0};
39 static const WCHAR source_disks_files_platform[] =
40     {'S','o','u','r','c','e','D','i','s','k','s','F','i','l','e','s','.','x','8','6',0};
41 #elif defined(__x86_64)
42 static const WCHAR source_disks_names_platform[] =
43     {'S','o','u','r','c','e','D','i','s','k','s','N','a','m','e','s','.','a','m','d','6','4',0};
44 static const WCHAR source_disks_files_platform[] =
45     {'S','o','u','r','c','e','D','i','s','k','s','F','i','l','e','s','.','a','m','d','6','4',0};
46 #else  /* FIXME: other platforms */
47 static const WCHAR source_disks_names_platform[] =
48     {'S','o','u','r','c','e','D','i','s','k','s','N','a','m','e','s',0};
49 static const WCHAR source_disks_files_platform[] =
50     {'S','o','u','r','c','e','D','i','s','k','s','F','i','l','e','s',0};
51 #endif
52 static const WCHAR source_disks_names[] =
53     {'S','o','u','r','c','e','D','i','s','k','s','N','a','m','e','s',0};
54 static const WCHAR source_disks_files[] =
55     {'S','o','u','r','c','e','D','i','s','k','s','F','i','l','e','s',0};
56
57 /* fills the PSP_INF_INFORMATION struct fill_info is TRUE
58  * always returns the required size of the information
59  */
60 static BOOL fill_inf_info(HINF inf, PSP_INF_INFORMATION buffer, DWORD size, DWORD *required)
61 {
62     LPCWSTR filename = PARSER_get_inf_filename(inf);
63     DWORD total_size = FIELD_OFFSET(SP_INF_INFORMATION, VersionData)
64                         + (lstrlenW(filename) + 1) * sizeof(WCHAR);
65
66     if (required) *required = total_size;
67
68     /* FIXME: we need to parse the INF file to find the correct version info */
69     if (buffer)
70     {
71         if (size < total_size)
72         {
73             SetLastError(ERROR_INSUFFICIENT_BUFFER);
74             return FALSE;
75         }
76         buffer->InfStyle = INF_STYLE_WIN4;
77         buffer->InfCount = 1;
78         /* put the filename in buffer->VersionData */
79         lstrcpyW((LPWSTR)&buffer->VersionData[0], filename);
80     }
81     return TRUE;
82 }
83
84 static HINF search_for_inf(LPCVOID InfSpec, DWORD SearchControl)
85 {
86     HINF hInf = INVALID_HANDLE_VALUE;
87     WCHAR inf_path[MAX_PATH];
88
89     static const WCHAR infW[] = {'\\','i','n','f','\\',0};
90     static const WCHAR system32W[] = {'\\','s','y','s','t','e','m','3','2','\\',0};
91
92     if (SearchControl == INFINFO_REVERSE_DEFAULT_SEARCH)
93     {
94         GetWindowsDirectoryW(inf_path, MAX_PATH);
95         lstrcatW(inf_path, system32W);
96         lstrcatW(inf_path, InfSpec);
97
98         hInf = SetupOpenInfFileW(inf_path, NULL,
99                                  INF_STYLE_OLDNT | INF_STYLE_WIN4, NULL);
100         if (hInf != INVALID_HANDLE_VALUE)
101             return hInf;
102
103         GetWindowsDirectoryW(inf_path, MAX_PATH);
104         lstrcpyW(inf_path, infW);
105         lstrcatW(inf_path, InfSpec);
106
107         return SetupOpenInfFileW(inf_path, NULL,
108                                  INF_STYLE_OLDNT | INF_STYLE_WIN4, NULL);
109     }
110
111     return INVALID_HANDLE_VALUE;
112 }
113
114 /***********************************************************************
115  *      SetupGetInfInformationA    (SETUPAPI.@)
116  *
117  */
118 BOOL WINAPI SetupGetInfInformationA(LPCVOID InfSpec, DWORD SearchControl,
119                                     PSP_INF_INFORMATION ReturnBuffer,
120                                     DWORD ReturnBufferSize, PDWORD RequiredSize)
121 {
122     LPWSTR inf = (LPWSTR)InfSpec;
123     DWORD len;
124     BOOL ret;
125
126     if (InfSpec && SearchControl >= INFINFO_INF_NAME_IS_ABSOLUTE)
127     {
128         len = lstrlenA(InfSpec) + 1;
129         inf = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
130         MultiByteToWideChar(CP_ACP, 0, InfSpec, -1, inf, len);
131     }
132
133     ret = SetupGetInfInformationW(inf, SearchControl, ReturnBuffer,
134                                   ReturnBufferSize, RequiredSize);
135
136     if (SearchControl >= INFINFO_INF_NAME_IS_ABSOLUTE)
137         HeapFree(GetProcessHeap(), 0, inf);
138
139     return ret;
140 }
141
142 /***********************************************************************
143  *      SetupGetInfInformationW    (SETUPAPI.@)
144  * 
145  * BUGS
146  *   Only handles the case when InfSpec is an INF handle.
147  */
148 BOOL WINAPI SetupGetInfInformationW(LPCVOID InfSpec, DWORD SearchControl,
149                                      PSP_INF_INFORMATION ReturnBuffer,
150                                      DWORD ReturnBufferSize, PDWORD RequiredSize)
151 {
152     HINF inf;
153     BOOL ret;
154     DWORD infSize;
155
156     TRACE("(%p, %d, %p, %d, %p)\n", InfSpec, SearchControl, ReturnBuffer,
157            ReturnBufferSize, RequiredSize);
158
159     if (!InfSpec)
160     {
161         if (SearchControl == INFINFO_INF_SPEC_IS_HINF)
162             SetLastError(ERROR_INVALID_HANDLE);
163         else
164             SetLastError(ERROR_INVALID_PARAMETER);
165
166         return FALSE;
167     }
168
169     switch (SearchControl)
170     {
171         case INFINFO_INF_SPEC_IS_HINF:
172             inf = (HINF)InfSpec;
173             break;
174         case INFINFO_INF_NAME_IS_ABSOLUTE:
175         case INFINFO_DEFAULT_SEARCH:
176             inf = SetupOpenInfFileW(InfSpec, NULL,
177                                     INF_STYLE_OLDNT | INF_STYLE_WIN4, NULL);
178             break;
179         case INFINFO_REVERSE_DEFAULT_SEARCH:
180             inf = search_for_inf(InfSpec, SearchControl);
181             break;
182         case INFINFO_INF_PATH_LIST_SEARCH:
183             FIXME("Unhandled search control: %d\n", SearchControl);
184
185             if (RequiredSize)
186                 *RequiredSize = 0;
187
188             return FALSE;
189         default:
190             SetLastError(ERROR_INVALID_PARAMETER);
191             return FALSE;
192     }
193
194     if (inf == INVALID_HANDLE_VALUE)
195     {
196         SetLastError(ERROR_FILE_NOT_FOUND);
197         return FALSE;
198     }
199
200     ret = fill_inf_info(inf, ReturnBuffer, ReturnBufferSize, &infSize);
201     if (!ReturnBuffer && (ReturnBufferSize >= infSize))
202     {
203         SetLastError(ERROR_INVALID_PARAMETER);
204         ret = FALSE;
205     }
206     if (RequiredSize) *RequiredSize = infSize;
207
208     if (SearchControl >= INFINFO_INF_NAME_IS_ABSOLUTE)
209         SetupCloseInfFile(inf);
210
211     return ret;
212 }
213
214 /***********************************************************************
215  *      SetupQueryInfFileInformationA    (SETUPAPI.@)
216  */
217 BOOL WINAPI SetupQueryInfFileInformationA(PSP_INF_INFORMATION InfInformation,
218                                           UINT InfIndex, PSTR ReturnBuffer,
219                                           DWORD ReturnBufferSize, PDWORD RequiredSize)
220 {
221     LPWSTR filenameW;
222     DWORD size;
223     BOOL ret;
224
225     ret = SetupQueryInfFileInformationW(InfInformation, InfIndex, NULL, 0, &size);
226     if (!ret)
227         return FALSE;
228
229     filenameW = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
230
231     ret = SetupQueryInfFileInformationW(InfInformation, InfIndex,
232                                         filenameW, size, &size);
233     if (!ret)
234     {
235         HeapFree(GetProcessHeap(), 0, filenameW);
236         return FALSE;
237     }
238
239     if (RequiredSize)
240         *RequiredSize = size;
241
242     if (!ReturnBuffer)
243     {
244         if (ReturnBufferSize)
245         {
246             SetLastError(ERROR_INVALID_PARAMETER);
247             return FALSE;
248         }
249
250         return TRUE;
251     }
252
253     if (size > ReturnBufferSize)
254     {
255         SetLastError(ERROR_INSUFFICIENT_BUFFER);
256         return FALSE;
257     }
258
259     WideCharToMultiByte(CP_ACP, 0, filenameW, -1, ReturnBuffer, size, NULL, NULL);
260     HeapFree(GetProcessHeap(), 0, filenameW);
261
262     return ret;
263 }
264
265 /***********************************************************************
266  *      SetupQueryInfFileInformationW    (SETUPAPI.@)
267  */
268 BOOL WINAPI SetupQueryInfFileInformationW(PSP_INF_INFORMATION InfInformation,
269                                           UINT InfIndex, PWSTR ReturnBuffer,
270                                           DWORD ReturnBufferSize, PDWORD RequiredSize) 
271 {
272     DWORD len;
273     LPWSTR ptr;
274
275     TRACE("(%p, %u, %p, %d, %p) Stub!\n", InfInformation, InfIndex,
276           ReturnBuffer, ReturnBufferSize, RequiredSize);
277
278     if (!InfInformation)
279     {
280         SetLastError(ERROR_INVALID_PARAMETER);
281         return FALSE;
282     }
283
284     if (InfIndex != 0)
285         FIXME("Appended INF files are not handled\n");
286
287     ptr = (LPWSTR)&InfInformation->VersionData[0];
288     len = lstrlenW(ptr);
289
290     if (RequiredSize)
291         *RequiredSize = len + 1;
292
293     if (!ReturnBuffer)
294         return TRUE;
295
296     if (ReturnBufferSize < len)
297     {
298         SetLastError(ERROR_INSUFFICIENT_BUFFER);
299         return FALSE;
300     }
301
302     lstrcpyW(ReturnBuffer, ptr);
303     return TRUE;
304 }
305
306 /***********************************************************************
307  *            SetupGetSourceFileLocationA   (SETUPAPI.@)
308  */
309
310 BOOL WINAPI SetupGetSourceFileLocationA( HINF hinf, PINFCONTEXT context, PCSTR filename,
311                                          PUINT source_id, PSTR buffer, DWORD buffer_size,
312                                          PDWORD required_size )
313 {
314     BOOL ret = FALSE;
315     WCHAR *filenameW = NULL, *bufferW = NULL;
316     DWORD required;
317     INT size;
318
319     TRACE("%p, %p, %s, %p, %p, 0x%08x, %p\n", hinf, context, debugstr_a(filename), source_id,
320           buffer, buffer_size, required_size);
321
322     if (filename && *filename && !(filenameW = strdupAtoW( filename )))
323         return FALSE;
324
325     if (!SetupGetSourceFileLocationW( hinf, context, filenameW, source_id, NULL, 0, &required ))
326         goto done;
327
328     if (!(bufferW = HeapAlloc( GetProcessHeap(), 0, required * sizeof(WCHAR) )))
329         goto done;
330
331     if (!SetupGetSourceFileLocationW( hinf, context, filenameW, source_id, bufferW, required, NULL ))
332         goto done;
333
334     size = WideCharToMultiByte( CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL );
335     if (required_size) *required_size = size;
336
337     if (buffer)
338     {
339         if (buffer_size >= size)
340             WideCharToMultiByte( CP_ACP, 0, bufferW, -1, buffer, buffer_size, NULL, NULL );
341         else
342         {
343             SetLastError( ERROR_INSUFFICIENT_BUFFER );
344             goto done;
345         }
346     }
347     ret = TRUE;
348
349  done:
350     HeapFree( GetProcessHeap(), 0, filenameW );
351     HeapFree( GetProcessHeap(), 0, bufferW );
352     return ret;
353 }
354
355 static LPWSTR get_source_id( HINF hinf, PINFCONTEXT context, PCWSTR filename )
356 {
357     DWORD size;
358     LPWSTR source_id;
359
360     if (!SetupFindFirstLineW( hinf, source_disks_files_platform, filename, context ) &&
361         !SetupFindFirstLineW( hinf, source_disks_files, filename, context ))
362         return NULL;
363
364     if (!SetupGetStringFieldW( context, 1, NULL, 0, &size ))
365         return NULL;
366
367     if (!(source_id = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) )))
368         return NULL;
369
370     if (!SetupGetStringFieldW( context, 1, source_id, size, NULL ))
371     {
372         HeapFree( GetProcessHeap(), 0, source_id );
373         return NULL;
374     }
375
376     if (!SetupFindFirstLineW( hinf, source_disks_names_platform, source_id, context ) &&
377         !SetupFindFirstLineW( hinf, source_disks_names, source_id, context ))
378     {
379         HeapFree( GetProcessHeap(), 0, source_id );
380         return NULL;
381     }
382     return source_id;
383 }
384
385 /***********************************************************************
386  *            SetupGetSourceFileLocationW   (SETUPAPI.@)
387  */
388
389 BOOL WINAPI SetupGetSourceFileLocationW( HINF hinf, PINFCONTEXT context, PCWSTR filename,
390                                          PUINT source_id, PWSTR buffer, DWORD buffer_size,
391                                          PDWORD required_size )
392 {
393     INFCONTEXT ctx;
394     WCHAR *end, *source_id_str;
395
396     TRACE("%p, %p, %s, %p, %p, 0x%08x, %p\n", hinf, context, debugstr_w(filename), source_id,
397           buffer, buffer_size, required_size);
398
399     if (!context) context = &ctx;
400
401     if (!(source_id_str = get_source_id( hinf, context, filename )))
402         return FALSE;
403
404     *source_id = strtolW( source_id_str, &end, 10 );
405     if (end == source_id_str || *end)
406     {
407         HeapFree( GetProcessHeap(), 0, source_id_str );
408         return FALSE;
409     }
410     HeapFree( GetProcessHeap(), 0, source_id_str );
411
412     if (SetupGetStringFieldW( context, 4, buffer, buffer_size, required_size ))
413         return TRUE;
414
415     if (required_size) *required_size = 1;
416     if (buffer)
417     {
418         if (buffer_size >= 1) buffer[0] = 0;
419         else
420         {
421             SetLastError( ERROR_INSUFFICIENT_BUFFER );
422             return FALSE;
423         }
424     }
425     return TRUE;
426 }
427
428 /***********************************************************************
429  *            SetupGetSourceInfoA  (SETUPAPI.@)
430  */
431
432 BOOL WINAPI SetupGetSourceInfoA( HINF hinf, UINT source_id, UINT info,
433                                  PSTR buffer, DWORD buffer_size, LPDWORD required_size )
434 {
435     BOOL ret = FALSE;
436     WCHAR *bufferW = NULL;
437     DWORD required;
438     INT size;
439
440     TRACE("%p, %d, %d, %p, %d, %p\n", hinf, source_id, info, buffer, buffer_size,
441           required_size);
442
443     if (!SetupGetSourceInfoW( hinf, source_id, info, NULL, 0, &required ))
444         return FALSE;
445
446     if (!(bufferW = HeapAlloc( GetProcessHeap(), 0, required * sizeof(WCHAR) )))
447         return FALSE;
448
449     if (!SetupGetSourceInfoW( hinf, source_id, info, bufferW, required, NULL ))
450         goto done;
451
452     size = WideCharToMultiByte( CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL );
453     if (required_size) *required_size = size;
454
455     if (buffer)
456     {
457         if (buffer_size >= size)
458             WideCharToMultiByte( CP_ACP, 0, bufferW, -1, buffer, buffer_size, NULL, NULL );
459         else
460         {
461             SetLastError( ERROR_INSUFFICIENT_BUFFER );
462             goto done;
463         }
464     }
465     ret = TRUE;
466
467  done:
468     HeapFree( GetProcessHeap(), 0, bufferW );
469     return ret;
470 }
471
472 /***********************************************************************
473  *            SetupGetSourceInfoW  (SETUPAPI.@)
474  */
475
476 BOOL WINAPI SetupGetSourceInfoW( HINF hinf, UINT source_id, UINT info,
477                                  PWSTR buffer, DWORD buffer_size, LPDWORD required_size )
478 {
479     INFCONTEXT ctx;
480     WCHAR source_id_str[11];
481     static const WCHAR fmt[] = {'%','d',0};
482     DWORD index;
483
484     TRACE("%p, %d, %d, %p, %d, %p\n", hinf, source_id, info, buffer, buffer_size,
485           required_size);
486
487     sprintfW( source_id_str, fmt, source_id );
488
489     if (!SetupFindFirstLineW( hinf, source_disks_names_platform, source_id_str, &ctx ) &&
490         !SetupFindFirstLineW( hinf, source_disks_names, source_id_str, &ctx ))
491         return FALSE;
492
493     switch (info)
494     {
495     case SRCINFO_PATH:          index = 4; break;
496     case SRCINFO_TAGFILE:       index = 2; break;
497     case SRCINFO_DESCRIPTION:   index = 1; break;
498     default:
499         WARN("unknown info level: %d\n", info);
500         return FALSE;
501     }
502
503     if (SetupGetStringFieldW( &ctx, index, buffer, buffer_size, required_size ))
504         return TRUE;
505
506     if (required_size) *required_size = 1;
507     if (buffer)
508     {
509         if (buffer_size >= 1) buffer[0] = 0;
510         else
511         {
512             SetLastError( ERROR_INSUFFICIENT_BUFFER );
513             return FALSE;
514         }
515     }
516     return TRUE;
517 }
518
519 /***********************************************************************
520  *            SetupGetTargetPathA   (SETUPAPI.@)
521  */
522
523 BOOL WINAPI SetupGetTargetPathA( HINF hinf, PINFCONTEXT context, PCSTR section, PSTR buffer,
524                                  DWORD buffer_size, PDWORD required_size )
525 {
526     BOOL ret = FALSE;
527     WCHAR *sectionW = NULL, *bufferW = NULL;
528     DWORD required;
529     INT size;
530
531     TRACE("%p, %p, %s, %p, 0x%08x, %p\n", hinf, context, debugstr_a(section), buffer,
532           buffer_size, required_size);
533
534     if (section && !(sectionW = strdupAtoW( section )))
535         return FALSE;
536
537     if (!SetupGetTargetPathW( hinf, context, sectionW, NULL, 0, &required ))
538         goto done;
539
540     if (!(bufferW = HeapAlloc( GetProcessHeap(), 0, required * sizeof(WCHAR) )))
541         goto done;
542
543     if (!SetupGetTargetPathW( hinf, context, sectionW, bufferW, required, NULL ))
544         goto done;
545
546     size = WideCharToMultiByte( CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL );
547     if (required_size) *required_size = size;
548
549     if (buffer)
550     {
551         if (buffer_size >= size)
552             WideCharToMultiByte( CP_ACP, 0, bufferW, -1, buffer, buffer_size, NULL, NULL );
553         else
554         {
555             SetLastError( ERROR_INSUFFICIENT_BUFFER );
556             goto done;
557         }
558     }
559     ret = TRUE;
560
561  done:
562     HeapFree( GetProcessHeap(), 0, sectionW );
563     HeapFree( GetProcessHeap(), 0, bufferW );
564     return ret;
565 }
566
567 /***********************************************************************
568  *            SetupGetTargetPathW   (SETUPAPI.@)
569  */
570
571 BOOL WINAPI SetupGetTargetPathW( HINF hinf, PINFCONTEXT context, PCWSTR section, PWSTR buffer,
572                                  DWORD buffer_size, PDWORD required_size )
573 {
574     static const WCHAR destination_dirs[] =
575         {'D','e','s','t','i','n','a','t','i','o','n','D','i','r','s',0};
576     static const WCHAR default_dest_dir[]  =
577         {'D','e','f','a','u','l','t','D','e','s','t','D','i','r',0};
578
579     INFCONTEXT ctx;
580     WCHAR *dir;
581     INT size;
582
583     TRACE("%p, %p, %s, %p, 0x%08x, %p\n", hinf, context, debugstr_w(section), buffer,
584           buffer_size, required_size);
585
586     if (context && !SetupFindFirstLineW( hinf, destination_dirs, NULL, context )) return FALSE;
587     else if (section && !SetupFindFirstLineW( hinf, section, NULL, &ctx )) return FALSE;
588     else if (!SetupFindFirstLineW( hinf, destination_dirs, default_dest_dir, &ctx )) return FALSE;
589
590     if (!(dir = PARSER_get_dest_dir( context ? context : &ctx ))) return FALSE;
591
592     size = lstrlenW( dir ) + 1;
593     if (required_size) *required_size = size;
594
595     if (buffer)
596     {
597         if (buffer_size >= size)
598             lstrcpyW( buffer, dir );
599         else
600         {
601             SetLastError( ERROR_INSUFFICIENT_BUFFER );
602             HeapFree( GetProcessHeap(), 0, dir );
603             return FALSE;
604         }
605     }
606     HeapFree( GetProcessHeap(), 0, dir );
607     return TRUE;
608 }
609
610 /***********************************************************************
611  *            SetupQueryInfOriginalFileInformationA   (SETUPAPI.@)
612  */
613 BOOL WINAPI SetupQueryInfOriginalFileInformationA(
614     PSP_INF_INFORMATION InfInformation, UINT InfIndex,
615     PSP_ALTPLATFORM_INFO AlternativePlatformInfo,
616     PSP_ORIGINAL_FILE_INFO_A OriginalFileInfo)
617 {
618     BOOL ret;
619     SP_ORIGINAL_FILE_INFO_W OriginalFileInfoW;
620
621     TRACE("(%p, %d, %p, %p)\n", InfInformation, InfIndex,
622         AlternativePlatformInfo, OriginalFileInfo);
623
624     if (OriginalFileInfo->cbSize != sizeof(*OriginalFileInfo))
625     {
626         ERR("incorrect OriginalFileInfo->cbSize of %d\n", OriginalFileInfo->cbSize);
627         SetLastError( ERROR_INVALID_USER_BUFFER );
628         return FALSE;
629     }
630
631     OriginalFileInfoW.cbSize = sizeof(OriginalFileInfoW);
632     ret = SetupQueryInfOriginalFileInformationW(InfInformation, InfIndex,
633         AlternativePlatformInfo, &OriginalFileInfoW);
634     if (ret)
635     {
636         WideCharToMultiByte(CP_ACP, 0, OriginalFileInfoW.OriginalInfName, MAX_PATH,
637             OriginalFileInfo->OriginalInfName, MAX_PATH, NULL, NULL);
638         WideCharToMultiByte(CP_ACP, 0, OriginalFileInfoW.OriginalCatalogName, MAX_PATH,
639             OriginalFileInfo->OriginalCatalogName, MAX_PATH, NULL, NULL);
640     }
641
642     return ret;
643 }
644
645 /***********************************************************************
646  *            SetupQueryInfOriginalFileInformationW   (SETUPAPI.@)
647  */
648 BOOL WINAPI SetupQueryInfOriginalFileInformationW(
649     PSP_INF_INFORMATION InfInformation, UINT InfIndex,
650     PSP_ALTPLATFORM_INFO AlternativePlatformInfo,
651     PSP_ORIGINAL_FILE_INFO_W OriginalFileInfo)
652 {
653     LPCWSTR inf_name;
654     LPCWSTR inf_path;
655     HINF hinf;
656     static const WCHAR wszVersion[] = { 'V','e','r','s','i','o','n',0 };
657     static const WCHAR wszCatalogFile[] = { 'C','a','t','a','l','o','g','F','i','l','e',0 };
658
659     FIXME("(%p, %d, %p, %p): semi-stub\n", InfInformation, InfIndex,
660         AlternativePlatformInfo, OriginalFileInfo);
661
662     if (OriginalFileInfo->cbSize != sizeof(*OriginalFileInfo))
663     {
664         ERR("incorrect OriginalFileInfo->cbSize of %d\n", OriginalFileInfo->cbSize);
665         return ERROR_INVALID_USER_BUFFER;
666     }
667
668     inf_path = (LPWSTR)&InfInformation->VersionData[0];
669
670     /* FIXME: we should get OriginalCatalogName from CatalogFile line in
671      * the original inf file and cache it, but that would require building a
672      * .pnf file. */
673     hinf = SetupOpenInfFileW(inf_path, NULL, INF_STYLE_WIN4, NULL);
674     if (hinf == INVALID_HANDLE_VALUE) return FALSE;
675
676     if (!SetupGetLineTextW(NULL, hinf, wszVersion, wszCatalogFile,
677                            OriginalFileInfo->OriginalCatalogName,
678                            sizeof(OriginalFileInfo->OriginalCatalogName)/sizeof(OriginalFileInfo->OriginalCatalogName[0]),
679                            NULL))
680     {
681         OriginalFileInfo->OriginalCatalogName[0] = '\0';
682     }
683     SetupCloseInfFile(hinf);
684
685     /* FIXME: not quite correct as we just return the same file name as
686      * destination (copied) inf file, not the source (original) inf file.
687      * to fix it properly would require building a .pnf file */
688     /* file name is stored in VersionData field of InfInformation */
689     inf_name = strrchrW(inf_path, '\\');
690     if (inf_name) inf_name++;
691     else inf_name = inf_path;
692
693     strcpyW(OriginalFileInfo->OriginalInfName, inf_name);
694
695     return TRUE;
696 }