2 * setupapi query functions
4 * Copyright 2006 James Hawkins
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.
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.
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
30 #include "wine/debug.h"
31 #include "wine/unicode.h"
32 #include "setupapi_private.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
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};
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};
57 /* fills the PSP_INF_INFORMATION struct fill_info is TRUE
58 * always returns the required size of the information
60 static BOOL fill_inf_info(HINF inf, PSP_INF_INFORMATION buffer, DWORD size, DWORD *required)
62 LPCWSTR filename = PARSER_get_inf_filename(inf);
63 DWORD total_size = FIELD_OFFSET(SP_INF_INFORMATION, VersionData)
64 + (lstrlenW(filename) + 1) * sizeof(WCHAR);
66 if (required) *required = total_size;
68 /* FIXME: we need to parse the INF file to find the correct version info */
71 if (size < total_size)
73 SetLastError(ERROR_INSUFFICIENT_BUFFER);
76 buffer->InfStyle = INF_STYLE_WIN4;
78 /* put the filename in buffer->VersionData */
79 lstrcpyW((LPWSTR)&buffer->VersionData[0], filename);
84 static HINF search_for_inf(LPCVOID InfSpec, DWORD SearchControl)
86 HINF hInf = INVALID_HANDLE_VALUE;
87 WCHAR inf_path[MAX_PATH];
89 static const WCHAR infW[] = {'\\','i','n','f','\\',0};
90 static const WCHAR system32W[] = {'\\','s','y','s','t','e','m','3','2','\\',0};
92 if (SearchControl == INFINFO_REVERSE_DEFAULT_SEARCH)
94 GetWindowsDirectoryW(inf_path, MAX_PATH);
95 lstrcatW(inf_path, system32W);
96 lstrcatW(inf_path, InfSpec);
98 hInf = SetupOpenInfFileW(inf_path, NULL,
99 INF_STYLE_OLDNT | INF_STYLE_WIN4, NULL);
100 if (hInf != INVALID_HANDLE_VALUE)
103 GetWindowsDirectoryW(inf_path, MAX_PATH);
104 lstrcpyW(inf_path, infW);
105 lstrcatW(inf_path, InfSpec);
107 return SetupOpenInfFileW(inf_path, NULL,
108 INF_STYLE_OLDNT | INF_STYLE_WIN4, NULL);
111 return INVALID_HANDLE_VALUE;
114 /***********************************************************************
115 * SetupGetInfInformationA (SETUPAPI.@)
118 BOOL WINAPI SetupGetInfInformationA(LPCVOID InfSpec, DWORD SearchControl,
119 PSP_INF_INFORMATION ReturnBuffer,
120 DWORD ReturnBufferSize, PDWORD RequiredSize)
122 LPWSTR inf = (LPWSTR)InfSpec;
126 if (InfSpec && SearchControl >= INFINFO_INF_NAME_IS_ABSOLUTE)
128 len = lstrlenA(InfSpec) + 1;
129 inf = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
130 MultiByteToWideChar(CP_ACP, 0, InfSpec, -1, inf, len);
133 ret = SetupGetInfInformationW(inf, SearchControl, ReturnBuffer,
134 ReturnBufferSize, RequiredSize);
136 if (SearchControl >= INFINFO_INF_NAME_IS_ABSOLUTE)
137 HeapFree(GetProcessHeap(), 0, inf);
142 /***********************************************************************
143 * SetupGetInfInformationW (SETUPAPI.@)
146 * Only handles the case when InfSpec is an INF handle.
148 BOOL WINAPI SetupGetInfInformationW(LPCVOID InfSpec, DWORD SearchControl,
149 PSP_INF_INFORMATION ReturnBuffer,
150 DWORD ReturnBufferSize, PDWORD RequiredSize)
156 TRACE("(%p, %d, %p, %d, %p)\n", InfSpec, SearchControl, ReturnBuffer,
157 ReturnBufferSize, RequiredSize);
161 if (SearchControl == INFINFO_INF_SPEC_IS_HINF)
162 SetLastError(ERROR_INVALID_HANDLE);
164 SetLastError(ERROR_INVALID_PARAMETER);
169 switch (SearchControl)
171 case INFINFO_INF_SPEC_IS_HINF:
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);
179 case INFINFO_REVERSE_DEFAULT_SEARCH:
180 inf = search_for_inf(InfSpec, SearchControl);
182 case INFINFO_INF_PATH_LIST_SEARCH:
183 FIXME("Unhandled search control: %d\n", SearchControl);
190 SetLastError(ERROR_INVALID_PARAMETER);
194 if (inf == INVALID_HANDLE_VALUE)
196 SetLastError(ERROR_FILE_NOT_FOUND);
200 ret = fill_inf_info(inf, ReturnBuffer, ReturnBufferSize, &infSize);
201 if (!ReturnBuffer && (ReturnBufferSize >= infSize))
203 SetLastError(ERROR_INVALID_PARAMETER);
206 if (RequiredSize) *RequiredSize = infSize;
208 if (SearchControl >= INFINFO_INF_NAME_IS_ABSOLUTE)
209 SetupCloseInfFile(inf);
214 /***********************************************************************
215 * SetupQueryInfFileInformationA (SETUPAPI.@)
217 BOOL WINAPI SetupQueryInfFileInformationA(PSP_INF_INFORMATION InfInformation,
218 UINT InfIndex, PSTR ReturnBuffer,
219 DWORD ReturnBufferSize, PDWORD RequiredSize)
225 ret = SetupQueryInfFileInformationW(InfInformation, InfIndex, NULL, 0, &size);
229 filenameW = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
231 ret = SetupQueryInfFileInformationW(InfInformation, InfIndex,
232 filenameW, size, &size);
235 HeapFree(GetProcessHeap(), 0, filenameW);
240 *RequiredSize = size;
244 if (ReturnBufferSize)
246 SetLastError(ERROR_INVALID_PARAMETER);
253 if (size > ReturnBufferSize)
255 SetLastError(ERROR_INSUFFICIENT_BUFFER);
259 WideCharToMultiByte(CP_ACP, 0, filenameW, -1, ReturnBuffer, size, NULL, NULL);
260 HeapFree(GetProcessHeap(), 0, filenameW);
265 /***********************************************************************
266 * SetupQueryInfFileInformationW (SETUPAPI.@)
268 BOOL WINAPI SetupQueryInfFileInformationW(PSP_INF_INFORMATION InfInformation,
269 UINT InfIndex, PWSTR ReturnBuffer,
270 DWORD ReturnBufferSize, PDWORD RequiredSize)
275 TRACE("(%p, %u, %p, %d, %p) Stub!\n", InfInformation, InfIndex,
276 ReturnBuffer, ReturnBufferSize, RequiredSize);
280 SetLastError(ERROR_INVALID_PARAMETER);
285 FIXME("Appended INF files are not handled\n");
287 ptr = (LPWSTR)&InfInformation->VersionData[0];
291 *RequiredSize = len + 1;
296 if (ReturnBufferSize < len)
298 SetLastError(ERROR_INSUFFICIENT_BUFFER);
302 lstrcpyW(ReturnBuffer, ptr);
306 /***********************************************************************
307 * SetupGetSourceFileLocationA (SETUPAPI.@)
310 BOOL WINAPI SetupGetSourceFileLocationA( HINF hinf, PINFCONTEXT context, PCSTR filename,
311 PUINT source_id, PSTR buffer, DWORD buffer_size,
312 PDWORD required_size )
315 WCHAR *filenameW = NULL, *bufferW = NULL;
319 TRACE("%p, %p, %s, %p, %p, 0x%08x, %p\n", hinf, context, debugstr_a(filename), source_id,
320 buffer, buffer_size, required_size);
322 if (filename && *filename && !(filenameW = strdupAtoW( filename )))
325 if (!SetupGetSourceFileLocationW( hinf, context, filenameW, source_id, NULL, 0, &required ))
328 if (!(bufferW = HeapAlloc( GetProcessHeap(), 0, required * sizeof(WCHAR) )))
331 if (!SetupGetSourceFileLocationW( hinf, context, filenameW, source_id, bufferW, required, NULL ))
334 size = WideCharToMultiByte( CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL );
335 if (required_size) *required_size = size;
339 if (buffer_size >= size)
340 WideCharToMultiByte( CP_ACP, 0, bufferW, -1, buffer, buffer_size, NULL, NULL );
343 SetLastError( ERROR_INSUFFICIENT_BUFFER );
350 HeapFree( GetProcessHeap(), 0, filenameW );
351 HeapFree( GetProcessHeap(), 0, bufferW );
355 static LPWSTR get_source_id( HINF hinf, PINFCONTEXT context, PCWSTR filename )
360 if (!SetupFindFirstLineW( hinf, source_disks_files_platform, filename, context ) &&
361 !SetupFindFirstLineW( hinf, source_disks_files, filename, context ))
364 if (!SetupGetStringFieldW( context, 1, NULL, 0, &size ))
367 if (!(source_id = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) )))
370 if (!SetupGetStringFieldW( context, 1, source_id, size, NULL ))
372 HeapFree( GetProcessHeap(), 0, source_id );
376 if (!SetupFindFirstLineW( hinf, source_disks_names_platform, source_id, context ) &&
377 !SetupFindFirstLineW( hinf, source_disks_names, source_id, context ))
379 HeapFree( GetProcessHeap(), 0, source_id );
385 /***********************************************************************
386 * SetupGetSourceFileLocationW (SETUPAPI.@)
389 BOOL WINAPI SetupGetSourceFileLocationW( HINF hinf, PINFCONTEXT context, PCWSTR filename,
390 PUINT source_id, PWSTR buffer, DWORD buffer_size,
391 PDWORD required_size )
394 WCHAR *end, *source_id_str;
396 TRACE("%p, %p, %s, %p, %p, 0x%08x, %p\n", hinf, context, debugstr_w(filename), source_id,
397 buffer, buffer_size, required_size);
399 if (!context) context = &ctx;
401 if (!(source_id_str = get_source_id( hinf, context, filename )))
404 *source_id = strtolW( source_id_str, &end, 10 );
405 if (end == source_id_str || *end)
407 HeapFree( GetProcessHeap(), 0, source_id_str );
410 HeapFree( GetProcessHeap(), 0, source_id_str );
412 if (SetupGetStringFieldW( context, 4, buffer, buffer_size, required_size ))
415 if (required_size) *required_size = 1;
418 if (buffer_size >= 1) buffer[0] = 0;
421 SetLastError( ERROR_INSUFFICIENT_BUFFER );
428 /***********************************************************************
429 * SetupGetSourceInfoA (SETUPAPI.@)
432 BOOL WINAPI SetupGetSourceInfoA( HINF hinf, UINT source_id, UINT info,
433 PSTR buffer, DWORD buffer_size, LPDWORD required_size )
436 WCHAR *bufferW = NULL;
440 TRACE("%p, %d, %d, %p, %d, %p\n", hinf, source_id, info, buffer, buffer_size,
443 if (!SetupGetSourceInfoW( hinf, source_id, info, NULL, 0, &required ))
446 if (!(bufferW = HeapAlloc( GetProcessHeap(), 0, required * sizeof(WCHAR) )))
449 if (!SetupGetSourceInfoW( hinf, source_id, info, bufferW, required, NULL ))
452 size = WideCharToMultiByte( CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL );
453 if (required_size) *required_size = size;
457 if (buffer_size >= size)
458 WideCharToMultiByte( CP_ACP, 0, bufferW, -1, buffer, buffer_size, NULL, NULL );
461 SetLastError( ERROR_INSUFFICIENT_BUFFER );
468 HeapFree( GetProcessHeap(), 0, bufferW );
472 /***********************************************************************
473 * SetupGetSourceInfoW (SETUPAPI.@)
476 BOOL WINAPI SetupGetSourceInfoW( HINF hinf, UINT source_id, UINT info,
477 PWSTR buffer, DWORD buffer_size, LPDWORD required_size )
480 WCHAR source_id_str[11];
481 static const WCHAR fmt[] = {'%','d',0};
484 TRACE("%p, %d, %d, %p, %d, %p\n", hinf, source_id, info, buffer, buffer_size,
487 sprintfW( source_id_str, fmt, source_id );
489 if (!SetupFindFirstLineW( hinf, source_disks_names_platform, source_id_str, &ctx ) &&
490 !SetupFindFirstLineW( hinf, source_disks_names, source_id_str, &ctx ))
495 case SRCINFO_PATH: index = 4; break;
496 case SRCINFO_TAGFILE: index = 2; break;
497 case SRCINFO_DESCRIPTION: index = 1; break;
499 WARN("unknown info level: %d\n", info);
503 if (SetupGetStringFieldW( &ctx, index, buffer, buffer_size, required_size ))
506 if (required_size) *required_size = 1;
509 if (buffer_size >= 1) buffer[0] = 0;
512 SetLastError( ERROR_INSUFFICIENT_BUFFER );
519 /***********************************************************************
520 * SetupGetTargetPathA (SETUPAPI.@)
523 BOOL WINAPI SetupGetTargetPathA( HINF hinf, PINFCONTEXT context, PCSTR section, PSTR buffer,
524 DWORD buffer_size, PDWORD required_size )
527 WCHAR *sectionW = NULL, *bufferW = NULL;
531 TRACE("%p, %p, %s, %p, 0x%08x, %p\n", hinf, context, debugstr_a(section), buffer,
532 buffer_size, required_size);
534 if (section && !(sectionW = strdupAtoW( section )))
537 if (!SetupGetTargetPathW( hinf, context, sectionW, NULL, 0, &required ))
540 if (!(bufferW = HeapAlloc( GetProcessHeap(), 0, required * sizeof(WCHAR) )))
543 if (!SetupGetTargetPathW( hinf, context, sectionW, bufferW, required, NULL ))
546 size = WideCharToMultiByte( CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL );
547 if (required_size) *required_size = size;
551 if (buffer_size >= size)
552 WideCharToMultiByte( CP_ACP, 0, bufferW, -1, buffer, buffer_size, NULL, NULL );
555 SetLastError( ERROR_INSUFFICIENT_BUFFER );
562 HeapFree( GetProcessHeap(), 0, sectionW );
563 HeapFree( GetProcessHeap(), 0, bufferW );
567 /***********************************************************************
568 * SetupGetTargetPathW (SETUPAPI.@)
571 BOOL WINAPI SetupGetTargetPathW( HINF hinf, PINFCONTEXT context, PCWSTR section, PWSTR buffer,
572 DWORD buffer_size, PDWORD required_size )
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};
583 TRACE("%p, %p, %s, %p, 0x%08x, %p\n", hinf, context, debugstr_w(section), buffer,
584 buffer_size, required_size);
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;
590 if (!(dir = PARSER_get_dest_dir( context ? context : &ctx ))) return FALSE;
592 size = lstrlenW( dir ) + 1;
593 if (required_size) *required_size = size;
597 if (buffer_size >= size)
598 lstrcpyW( buffer, dir );
601 SetLastError( ERROR_INSUFFICIENT_BUFFER );
602 HeapFree( GetProcessHeap(), 0, dir );
606 HeapFree( GetProcessHeap(), 0, dir );
610 /***********************************************************************
611 * SetupQueryInfOriginalFileInformationA (SETUPAPI.@)
613 BOOL WINAPI SetupQueryInfOriginalFileInformationA(
614 PSP_INF_INFORMATION InfInformation, UINT InfIndex,
615 PSP_ALTPLATFORM_INFO AlternativePlatformInfo,
616 PSP_ORIGINAL_FILE_INFO_A OriginalFileInfo)
619 SP_ORIGINAL_FILE_INFO_W OriginalFileInfoW;
621 TRACE("(%p, %d, %p, %p)\n", InfInformation, InfIndex,
622 AlternativePlatformInfo, OriginalFileInfo);
624 if (OriginalFileInfo->cbSize != sizeof(*OriginalFileInfo))
626 ERR("incorrect OriginalFileInfo->cbSize of %d\n", OriginalFileInfo->cbSize);
627 SetLastError( ERROR_INVALID_USER_BUFFER );
631 OriginalFileInfoW.cbSize = sizeof(OriginalFileInfoW);
632 ret = SetupQueryInfOriginalFileInformationW(InfInformation, InfIndex,
633 AlternativePlatformInfo, &OriginalFileInfoW);
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);
645 /***********************************************************************
646 * SetupQueryInfOriginalFileInformationW (SETUPAPI.@)
648 BOOL WINAPI SetupQueryInfOriginalFileInformationW(
649 PSP_INF_INFORMATION InfInformation, UINT InfIndex,
650 PSP_ALTPLATFORM_INFO AlternativePlatformInfo,
651 PSP_ORIGINAL_FILE_INFO_W OriginalFileInfo)
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 };
659 FIXME("(%p, %d, %p, %p): semi-stub\n", InfInformation, InfIndex,
660 AlternativePlatformInfo, OriginalFileInfo);
662 if (OriginalFileInfo->cbSize != sizeof(*OriginalFileInfo))
664 ERR("incorrect OriginalFileInfo->cbSize of %d\n", OriginalFileInfo->cbSize);
665 return ERROR_INVALID_USER_BUFFER;
668 inf_path = (LPWSTR)&InfInformation->VersionData[0];
670 /* FIXME: we should get OriginalCatalogName from CatalogFile line in
671 * the original inf file and cache it, but that would require building a
673 hinf = SetupOpenInfFileW(inf_path, NULL, INF_STYLE_WIN4, NULL);
674 if (hinf == INVALID_HANDLE_VALUE) return FALSE;
676 if (!SetupGetLineTextW(NULL, hinf, wszVersion, wszCatalogFile,
677 OriginalFileInfo->OriginalCatalogName,
678 sizeof(OriginalFileInfo->OriginalCatalogName)/sizeof(OriginalFileInfo->OriginalCatalogName[0]),
681 OriginalFileInfo->OriginalCatalogName[0] = '\0';
683 SetupCloseInfFile(hinf);
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;
693 strcpyW(OriginalFileInfo->OriginalInfName, inf_name);