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