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 HeapFree(GetProcessHeap(), 0, filenameW
);
245 if (ReturnBufferSize
)
247 SetLastError(ERROR_INVALID_PARAMETER
);
254 if (size
> ReturnBufferSize
)
256 HeapFree(GetProcessHeap(), 0, filenameW
);
257 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
261 WideCharToMultiByte(CP_ACP
, 0, filenameW
, -1, ReturnBuffer
, size
, NULL
, NULL
);
262 HeapFree(GetProcessHeap(), 0, filenameW
);
267 /***********************************************************************
268 * SetupQueryInfFileInformationW (SETUPAPI.@)
270 BOOL WINAPI
SetupQueryInfFileInformationW(PSP_INF_INFORMATION InfInformation
,
271 UINT InfIndex
, PWSTR ReturnBuffer
,
272 DWORD ReturnBufferSize
, PDWORD RequiredSize
)
277 TRACE("(%p, %u, %p, %d, %p) Stub!\n", InfInformation
, InfIndex
,
278 ReturnBuffer
, ReturnBufferSize
, RequiredSize
);
282 SetLastError(ERROR_INVALID_PARAMETER
);
287 FIXME("Appended INF files are not handled\n");
289 ptr
= (LPWSTR
)InfInformation
->VersionData
;
293 *RequiredSize
= len
+ 1;
298 if (ReturnBufferSize
< len
)
300 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
304 lstrcpyW(ReturnBuffer
, ptr
);
308 /***********************************************************************
309 * SetupGetSourceFileLocationA (SETUPAPI.@)
312 BOOL WINAPI
SetupGetSourceFileLocationA( HINF hinf
, PINFCONTEXT context
, PCSTR filename
,
313 PUINT source_id
, PSTR buffer
, DWORD buffer_size
,
314 PDWORD required_size
)
317 WCHAR
*filenameW
= NULL
, *bufferW
= NULL
;
321 TRACE("%p, %p, %s, %p, %p, 0x%08x, %p\n", hinf
, context
, debugstr_a(filename
), source_id
,
322 buffer
, buffer_size
, required_size
);
324 if (filename
&& *filename
&& !(filenameW
= strdupAtoW( filename
)))
327 if (!SetupGetSourceFileLocationW( hinf
, context
, filenameW
, source_id
, NULL
, 0, &required
))
330 if (!(bufferW
= HeapAlloc( GetProcessHeap(), 0, required
* sizeof(WCHAR
) )))
333 if (!SetupGetSourceFileLocationW( hinf
, context
, filenameW
, source_id
, bufferW
, required
, NULL
))
336 size
= WideCharToMultiByte( CP_ACP
, 0, bufferW
, -1, NULL
, 0, NULL
, NULL
);
337 if (required_size
) *required_size
= size
;
341 if (buffer_size
>= size
)
342 WideCharToMultiByte( CP_ACP
, 0, bufferW
, -1, buffer
, buffer_size
, NULL
, NULL
);
345 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
352 HeapFree( GetProcessHeap(), 0, filenameW
);
353 HeapFree( GetProcessHeap(), 0, bufferW
);
357 static LPWSTR
get_source_id( HINF hinf
, PINFCONTEXT context
, PCWSTR filename
)
362 if (!SetupFindFirstLineW( hinf
, source_disks_files_platform
, filename
, context
) &&
363 !SetupFindFirstLineW( hinf
, source_disks_files
, filename
, context
))
366 if (!SetupGetStringFieldW( context
, 1, NULL
, 0, &size
))
369 if (!(source_id
= HeapAlloc( GetProcessHeap(), 0, size
* sizeof(WCHAR
) )))
372 if (!SetupGetStringFieldW( context
, 1, source_id
, size
, NULL
))
374 HeapFree( GetProcessHeap(), 0, source_id
);
378 if (!SetupFindFirstLineW( hinf
, source_disks_names_platform
, source_id
, context
) &&
379 !SetupFindFirstLineW( hinf
, source_disks_names
, source_id
, context
))
381 HeapFree( GetProcessHeap(), 0, source_id
);
387 /***********************************************************************
388 * SetupGetSourceFileLocationW (SETUPAPI.@)
391 BOOL WINAPI
SetupGetSourceFileLocationW( HINF hinf
, PINFCONTEXT context
, PCWSTR filename
,
392 PUINT source_id
, PWSTR buffer
, DWORD buffer_size
,
393 PDWORD required_size
)
396 WCHAR
*end
, *source_id_str
;
398 TRACE("%p, %p, %s, %p, %p, 0x%08x, %p\n", hinf
, context
, debugstr_w(filename
), source_id
,
399 buffer
, buffer_size
, required_size
);
401 if (!context
) context
= &ctx
;
403 if (!(source_id_str
= get_source_id( hinf
, context
, filename
)))
406 *source_id
= strtolW( source_id_str
, &end
, 10 );
407 if (end
== source_id_str
|| *end
)
409 HeapFree( GetProcessHeap(), 0, source_id_str
);
412 HeapFree( GetProcessHeap(), 0, source_id_str
);
414 if (SetupGetStringFieldW( context
, 4, buffer
, buffer_size
, required_size
))
417 if (required_size
) *required_size
= 1;
420 if (buffer_size
>= 1) buffer
[0] = 0;
423 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
430 /***********************************************************************
431 * SetupGetSourceInfoA (SETUPAPI.@)
434 BOOL WINAPI
SetupGetSourceInfoA( HINF hinf
, UINT source_id
, UINT info
,
435 PSTR buffer
, DWORD buffer_size
, LPDWORD required_size
)
438 WCHAR
*bufferW
= NULL
;
442 TRACE("%p, %d, %d, %p, %d, %p\n", hinf
, source_id
, info
, buffer
, buffer_size
,
445 if (!SetupGetSourceInfoW( hinf
, source_id
, info
, NULL
, 0, &required
))
448 if (!(bufferW
= HeapAlloc( GetProcessHeap(), 0, required
* sizeof(WCHAR
) )))
451 if (!SetupGetSourceInfoW( hinf
, source_id
, info
, bufferW
, required
, NULL
))
454 size
= WideCharToMultiByte( CP_ACP
, 0, bufferW
, -1, NULL
, 0, NULL
, NULL
);
455 if (required_size
) *required_size
= size
;
459 if (buffer_size
>= size
)
460 WideCharToMultiByte( CP_ACP
, 0, bufferW
, -1, buffer
, buffer_size
, NULL
, NULL
);
463 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
470 HeapFree( GetProcessHeap(), 0, bufferW
);
474 /***********************************************************************
475 * SetupGetSourceInfoW (SETUPAPI.@)
478 BOOL WINAPI
SetupGetSourceInfoW( HINF hinf
, UINT source_id
, UINT info
,
479 PWSTR buffer
, DWORD buffer_size
, LPDWORD required_size
)
482 WCHAR source_id_str
[11];
483 static const WCHAR fmt
[] = {'%','d',0};
486 TRACE("%p, %d, %d, %p, %d, %p\n", hinf
, source_id
, info
, buffer
, buffer_size
,
489 sprintfW( source_id_str
, fmt
, source_id
);
491 if (!SetupFindFirstLineW( hinf
, source_disks_names_platform
, source_id_str
, &ctx
) &&
492 !SetupFindFirstLineW( hinf
, source_disks_names
, source_id_str
, &ctx
))
497 case SRCINFO_PATH
: index
= 4; break;
498 case SRCINFO_TAGFILE
: index
= 2; break;
499 case SRCINFO_DESCRIPTION
: index
= 1; break;
501 WARN("unknown info level: %d\n", info
);
505 if (SetupGetStringFieldW( &ctx
, index
, buffer
, buffer_size
, required_size
))
508 if (required_size
) *required_size
= 1;
511 if (buffer_size
>= 1) buffer
[0] = 0;
514 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
521 /***********************************************************************
522 * SetupGetTargetPathA (SETUPAPI.@)
525 BOOL WINAPI
SetupGetTargetPathA( HINF hinf
, PINFCONTEXT context
, PCSTR section
, PSTR buffer
,
526 DWORD buffer_size
, PDWORD required_size
)
529 WCHAR
*sectionW
= NULL
, *bufferW
= NULL
;
533 TRACE("%p, %p, %s, %p, 0x%08x, %p\n", hinf
, context
, debugstr_a(section
), buffer
,
534 buffer_size
, required_size
);
536 if (section
&& !(sectionW
= strdupAtoW( section
)))
539 if (!SetupGetTargetPathW( hinf
, context
, sectionW
, NULL
, 0, &required
))
542 if (!(bufferW
= HeapAlloc( GetProcessHeap(), 0, required
* sizeof(WCHAR
) )))
545 if (!SetupGetTargetPathW( hinf
, context
, sectionW
, bufferW
, required
, NULL
))
548 size
= WideCharToMultiByte( CP_ACP
, 0, bufferW
, -1, NULL
, 0, NULL
, NULL
);
549 if (required_size
) *required_size
= size
;
553 if (buffer_size
>= size
)
554 WideCharToMultiByte( CP_ACP
, 0, bufferW
, -1, buffer
, buffer_size
, NULL
, NULL
);
557 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
564 HeapFree( GetProcessHeap(), 0, sectionW
);
565 HeapFree( GetProcessHeap(), 0, bufferW
);
569 /***********************************************************************
570 * SetupGetTargetPathW (SETUPAPI.@)
573 BOOL WINAPI
SetupGetTargetPathW( HINF hinf
, PINFCONTEXT context
, PCWSTR section
, PWSTR buffer
,
574 DWORD buffer_size
, PDWORD required_size
)
576 static const WCHAR destination_dirs
[] =
577 {'D','e','s','t','i','n','a','t','i','o','n','D','i','r','s',0};
578 static const WCHAR default_dest_dir
[] =
579 {'D','e','f','a','u','l','t','D','e','s','t','D','i','r',0};
582 WCHAR
*dir
, systemdir
[MAX_PATH
];
586 TRACE("%p, %p, %s, %p, 0x%08x, %p\n", hinf
, context
, debugstr_w(section
), buffer
,
587 buffer_size
, required_size
);
589 if (context
) ret
= SetupFindFirstLineW( hinf
, destination_dirs
, NULL
, context
);
592 if (!(ret
= SetupFindFirstLineW( hinf
, destination_dirs
, section
, &ctx
)))
593 ret
= SetupFindFirstLineW( hinf
, destination_dirs
, default_dest_dir
, &ctx
);
595 if (!ret
|| !(dir
= PARSER_get_dest_dir( context
? context
: &ctx
)))
597 GetSystemDirectoryW( systemdir
, MAX_PATH
);
600 size
= strlenW( dir
) + 1;
601 if (required_size
) *required_size
= size
;
605 if (buffer_size
>= size
)
606 lstrcpyW( buffer
, dir
);
609 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
610 HeapFree( GetProcessHeap(), 0, dir
);
614 if (dir
!= systemdir
) HeapFree( GetProcessHeap(), 0, dir
);
618 /***********************************************************************
619 * SetupQueryInfOriginalFileInformationA (SETUPAPI.@)
621 BOOL WINAPI
SetupQueryInfOriginalFileInformationA(
622 PSP_INF_INFORMATION InfInformation
, UINT InfIndex
,
623 PSP_ALTPLATFORM_INFO AlternativePlatformInfo
,
624 PSP_ORIGINAL_FILE_INFO_A OriginalFileInfo
)
627 SP_ORIGINAL_FILE_INFO_W OriginalFileInfoW
;
629 TRACE("(%p, %d, %p, %p)\n", InfInformation
, InfIndex
,
630 AlternativePlatformInfo
, OriginalFileInfo
);
632 if (OriginalFileInfo
->cbSize
!= sizeof(*OriginalFileInfo
))
634 WARN("incorrect OriginalFileInfo->cbSize of %d\n", OriginalFileInfo
->cbSize
);
635 SetLastError( ERROR_INVALID_USER_BUFFER
);
639 OriginalFileInfoW
.cbSize
= sizeof(OriginalFileInfoW
);
640 ret
= SetupQueryInfOriginalFileInformationW(InfInformation
, InfIndex
,
641 AlternativePlatformInfo
, &OriginalFileInfoW
);
644 WideCharToMultiByte(CP_ACP
, 0, OriginalFileInfoW
.OriginalInfName
, -1,
645 OriginalFileInfo
->OriginalInfName
, MAX_PATH
, NULL
, NULL
);
646 WideCharToMultiByte(CP_ACP
, 0, OriginalFileInfoW
.OriginalCatalogName
, -1,
647 OriginalFileInfo
->OriginalCatalogName
, MAX_PATH
, NULL
, NULL
);
653 /***********************************************************************
654 * SetupQueryInfOriginalFileInformationW (SETUPAPI.@)
656 BOOL WINAPI
SetupQueryInfOriginalFileInformationW(
657 PSP_INF_INFORMATION InfInformation
, UINT InfIndex
,
658 PSP_ALTPLATFORM_INFO AlternativePlatformInfo
,
659 PSP_ORIGINAL_FILE_INFO_W OriginalFileInfo
)
664 static const WCHAR wszVersion
[] = { 'V','e','r','s','i','o','n',0 };
665 static const WCHAR wszCatalogFile
[] = { 'C','a','t','a','l','o','g','F','i','l','e',0 };
667 FIXME("(%p, %d, %p, %p): semi-stub\n", InfInformation
, InfIndex
,
668 AlternativePlatformInfo
, OriginalFileInfo
);
670 if (OriginalFileInfo
->cbSize
!= sizeof(*OriginalFileInfo
))
672 WARN("incorrect OriginalFileInfo->cbSize of %d\n", OriginalFileInfo
->cbSize
);
673 SetLastError(ERROR_INVALID_USER_BUFFER
);
677 inf_path
= (LPWSTR
)InfInformation
->VersionData
;
679 /* FIXME: we should get OriginalCatalogName from CatalogFile line in
680 * the original inf file and cache it, but that would require building a
682 hinf
= SetupOpenInfFileW(inf_path
, NULL
, INF_STYLE_WIN4
, NULL
);
683 if (hinf
== INVALID_HANDLE_VALUE
) return FALSE
;
685 if (!SetupGetLineTextW(NULL
, hinf
, wszVersion
, wszCatalogFile
,
686 OriginalFileInfo
->OriginalCatalogName
,
687 sizeof(OriginalFileInfo
->OriginalCatalogName
)/sizeof(OriginalFileInfo
->OriginalCatalogName
[0]),
690 OriginalFileInfo
->OriginalCatalogName
[0] = '\0';
692 SetupCloseInfFile(hinf
);
694 /* FIXME: not quite correct as we just return the same file name as
695 * destination (copied) inf file, not the source (original) inf file.
696 * to fix it properly would require building a .pnf file */
697 /* file name is stored in VersionData field of InfInformation */
698 inf_name
= strrchrW(inf_path
, '\\');
699 if (inf_name
) inf_name
++;
700 else inf_name
= inf_path
;
702 strcpyW(OriginalFileInfo
->OriginalInfName
, inf_name
);