Sync to trunk revision 63922.
[reactos.git] / dll / win32 / setupapi / driver.c
1 /*
2 * SetupAPI driver-related functions
3 *
4 * Copyright 2005-2006 Hervé Poussineau (hpoussin@reactos.org)
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 /* Unicode constants */
24 static const WCHAR BackSlash[] = {'\\',0};
25 static const WCHAR ClassGUID[] = {'C','l','a','s','s','G','U','I','D',0};
26 static const WCHAR DotCoInstallers[] = {'.','C','o','I','n','s','t','a','l','l','e','r','s',0};
27 static const WCHAR InfDirectory[] = {'i','n','f','\\',0};
28 static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
29
30 static const WCHAR INF_MANUFACTURER[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
31 static const WCHAR INF_PROVIDER[] = {'P','r','o','v','i','d','e','r',0};
32 static const WCHAR INF_DRIVER_VER[] = {'D','r','i','v','e','r','V','e','r',0};
33
34
35 /***********************************************************************
36 * struct InfFileDetails management
37 */
38 static VOID
39 ReferenceInfFile(struct InfFileDetails* infFile)
40 {
41 InterlockedIncrement(&infFile->References);
42 }
43
44 VOID
45 DereferenceInfFile(struct InfFileDetails* infFile)
46 {
47 if (InterlockedDecrement(&infFile->References) == 0)
48 {
49 SetupCloseInfFile(infFile->hInf);
50 HeapFree(GetProcessHeap(), 0, infFile);
51 }
52 }
53
54 struct InfFileDetails *
55 CreateInfFileDetails(
56 IN LPCWSTR FullInfFileName)
57 {
58 struct InfFileDetails *details;
59 PWCHAR last;
60 DWORD Needed;
61
62 Needed = FIELD_OFFSET(struct InfFileDetails, szData)
63 + strlenW(FullInfFileName) * sizeof(WCHAR) + sizeof(UNICODE_NULL);
64
65 details = HeapAlloc(GetProcessHeap(), 0, Needed);
66 if (!details)
67 {
68 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
69 return NULL;
70 }
71
72 memset(details, 0, Needed);
73 strcpyW(details->szData, FullInfFileName);
74 last = strrchrW(details->szData, '\\');
75 if (last)
76 {
77 details->DirectoryName = details->szData;
78 details->FileName = last + 1;
79 *last = '\0';
80 }
81 else
82 details->FileName = details->szData;
83 ReferenceInfFile(details);
84 details->hInf = SetupOpenInfFileW(FullInfFileName, NULL, INF_STYLE_WIN4, NULL);
85 if (details->hInf == INVALID_HANDLE_VALUE)
86 {
87 HeapFree(GetProcessHeap(), 0, details);
88 return NULL;
89 }
90 return details;
91 }
92
93 BOOL
94 DestroyDriverInfoElement(struct DriverInfoElement* driverInfo)
95 {
96 DereferenceInfFile(driverInfo->InfFileDetails);
97 HeapFree(GetProcessHeap(), 0, driverInfo->MatchingId);
98 HeapFree(GetProcessHeap(), 0, driverInfo);
99 return TRUE;
100 }
101
102 /***********************************************************************
103 * Helper functions for SetupDiBuildDriverInfoList
104 */
105 static BOOL
106 AddKnownDriverToList(
107 IN PLIST_ENTRY DriverListHead,
108 IN DWORD DriverType, /* SPDIT_CLASSDRIVER or SPDIT_COMPATDRIVER */
109 IN LPGUID ClassGuid,
110 IN struct InfFileDetails *InfFileDetails,
111 IN LPCWSTR InfFile,
112 IN LPCWSTR SectionName,
113 IN LPCWSTR DriverDescription,
114 IN LPCWSTR ProviderName,
115 IN LPCWSTR ManufacturerName,
116 IN LPCWSTR MatchingId,
117 IN FILETIME DriverDate,
118 IN DWORDLONG DriverVersion,
119 IN DWORD Rank)
120 {
121 struct DriverInfoElement *driverInfo = NULL;
122 HANDLE hFile = INVALID_HANDLE_VALUE;
123 BOOL Result = FALSE;
124 PLIST_ENTRY PreviousEntry;
125 BOOL ret = FALSE;
126
127 driverInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(struct DriverInfoElement));
128 if (!driverInfo)
129 {
130 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
131 goto cleanup;
132 }
133 memset(driverInfo, 0, sizeof(struct DriverInfoElement));
134
135 driverInfo->Params.cbSize = sizeof(SP_DRVINSTALL_PARAMS);
136 driverInfo->Params.Reserved = (ULONG_PTR)driverInfo;
137
138 driverInfo->Details.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA_W);
139 driverInfo->Details.Reserved = (ULONG_PTR)driverInfo;
140
141 /* Copy InfFileName field */
142 lstrcpynW(driverInfo->Details.InfFileName, InfFile, MAX_PATH - 1);
143 driverInfo->Details.InfFileName[MAX_PATH - 1] = '\0';
144
145 /* Fill InfDate field */
146 hFile = CreateFileW(
147 InfFile,
148 GENERIC_READ, FILE_SHARE_READ,
149 NULL, OPEN_EXISTING, 0, NULL);
150 if (hFile == INVALID_HANDLE_VALUE)
151 goto cleanup;
152 Result = GetFileTime(hFile, NULL, NULL, &driverInfo->Details.InfDate);
153 if (!Result)
154 goto cleanup;
155
156 /* Fill SectionName field */
157 lstrcpynW(driverInfo->Details.SectionName, SectionName, LINE_LEN);
158
159 /* Fill DrvDescription field */
160 lstrcpynW(driverInfo->Details.DrvDescription, DriverDescription, LINE_LEN);
161
162 /* Copy MatchingId information */
163 if (MatchingId)
164 {
165 driverInfo->MatchingId = HeapAlloc(GetProcessHeap(), 0, (strlenW(MatchingId) + 1) * sizeof(WCHAR));
166 if (!driverInfo->MatchingId)
167 {
168 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
169 goto cleanup;
170 }
171 RtlCopyMemory(driverInfo->MatchingId, MatchingId, (strlenW(MatchingId) + 1) * sizeof(WCHAR));
172 }
173 else
174 driverInfo->MatchingId = NULL;
175
176 TRACE("Adding driver '%s' [%s/%s] (Rank 0x%lx)\n",
177 debugstr_w(driverInfo->Details.DrvDescription), debugstr_w(InfFile),
178 debugstr_w(SectionName), Rank);
179
180 driverInfo->Params.Rank = Rank;
181 memcpy(&driverInfo->DriverDate, &DriverDate, sizeof(FILETIME));
182 memcpy(&driverInfo->ClassGuid, ClassGuid, sizeof(GUID));
183 driverInfo->Info.DriverType = DriverType;
184 driverInfo->Info.Reserved = (ULONG_PTR)driverInfo;
185 lstrcpynW(driverInfo->Info.Description, driverInfo->Details.DrvDescription, LINE_LEN - 1);
186 driverInfo->Info.Description[LINE_LEN - 1] = '\0';
187 lstrcpynW(driverInfo->Info.MfgName, ManufacturerName, LINE_LEN - 1);
188 driverInfo->Info.MfgName[LINE_LEN - 1] = '\0';
189 if (ProviderName)
190 {
191 lstrcpynW(driverInfo->Info.ProviderName, ProviderName, LINE_LEN - 1);
192 driverInfo->Info.ProviderName[LINE_LEN - 1] = '\0';
193 }
194 else
195 driverInfo->Info.ProviderName[0] = '\0';
196 driverInfo->Info.DriverDate = DriverDate;
197 driverInfo->Info.DriverVersion = DriverVersion;
198 ReferenceInfFile(InfFileDetails);
199 driverInfo->InfFileDetails = InfFileDetails;
200
201 /* Insert current driver in driver list, according to its rank */
202 PreviousEntry = DriverListHead->Flink;
203 while (PreviousEntry != DriverListHead)
204 {
205 struct DriverInfoElement *CurrentDriver;
206 CurrentDriver = CONTAINING_RECORD(PreviousEntry, struct DriverInfoElement, ListEntry);
207 if (CurrentDriver->Params.Rank > Rank ||
208 (CurrentDriver->Params.Rank == Rank && CurrentDriver->DriverDate.QuadPart < driverInfo->DriverDate.QuadPart))
209 {
210 /* Insert before the current item */
211 InsertHeadList(PreviousEntry->Blink, &driverInfo->ListEntry);
212 break;
213 }
214 PreviousEntry = PreviousEntry->Flink;
215 }
216 if (PreviousEntry == DriverListHead)
217 {
218 /* Insert at the end of the list */
219 InsertTailList(DriverListHead, &driverInfo->ListEntry);
220 }
221
222 ret = TRUE;
223
224 cleanup:
225 if (!ret)
226 {
227 if (driverInfo)
228 HeapFree(GetProcessHeap(), 0, driverInfo->MatchingId);
229 HeapFree(GetProcessHeap(), 0, driverInfo);
230 }
231 if (hFile != INVALID_HANDLE_VALUE)
232 CloseHandle(hFile);
233
234 return ret;
235 }
236
237 static BOOL
238 AddDriverToList(
239 IN PLIST_ENTRY DriverListHead,
240 IN DWORD DriverType, /* SPDIT_CLASSDRIVER or SPDIT_COMPATDRIVER */
241 IN LPGUID ClassGuid,
242 IN INFCONTEXT ContextDevice,
243 IN struct InfFileDetails *InfFileDetails,
244 IN LPCWSTR InfFile,
245 IN LPCWSTR ProviderName,
246 IN LPCWSTR ManufacturerName,
247 IN LPCWSTR MatchingId,
248 IN FILETIME DriverDate,
249 IN DWORDLONG DriverVersion,
250 IN DWORD Rank)
251 {
252 LPWSTR SectionName = NULL;
253 LPWSTR DriverDescription = NULL;
254 BOOL Result;
255 BOOL ret = FALSE;
256
257 /* Read SectionName */
258 SectionName = MyMalloc(LINE_LEN);
259 if (!SectionName)
260 {
261 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
262 goto cleanup;
263 }
264 ZeroMemory(SectionName, LINE_LEN);
265 Result = SetupGetStringFieldW(
266 &ContextDevice,
267 1,
268 SectionName,
269 LINE_LEN,
270 NULL);
271 if (!Result)
272 goto cleanup;
273
274 /* Read DriverDescription */
275 DriverDescription = MyMalloc(LINE_LEN);
276 if (!DriverDescription)
277 {
278 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
279 goto cleanup;
280 }
281 ZeroMemory(DriverDescription, LINE_LEN);
282 Result = SetupGetStringFieldW(
283 &ContextDevice,
284 0, /* Field index */
285 DriverDescription, LINE_LEN,
286 NULL);
287
288 ret = AddKnownDriverToList(
289 DriverListHead,
290 DriverType,
291 ClassGuid,
292 InfFileDetails,
293 InfFile,
294 SectionName,
295 DriverDescription,
296 ProviderName,
297 ManufacturerName,
298 MatchingId,
299 DriverDate,
300 DriverVersion,
301 Rank);
302
303 cleanup:
304 MyFree(SectionName);
305 MyFree(DriverDescription);
306
307 return ret;
308 }
309
310 static BOOL
311 GetVersionInformationFromInfFile(
312 IN HINF hInf,
313 OUT LPGUID ClassGuid,
314 OUT LPWSTR* pProviderName,
315 OUT FILETIME* DriverDate,
316 OUT DWORDLONG* DriverVersion)
317 {
318 DWORD RequiredSize;
319 WCHAR guidW[MAX_GUID_STRING_LEN + 1];
320 LPWSTR DriverVer = NULL;
321 LPWSTR ProviderName = NULL;
322 LPWSTR pComma; /* Points into DriverVer */
323 LPWSTR pVersion = NULL; /* Points into DriverVer */
324 SYSTEMTIME SystemTime;
325 BOOL Result;
326 BOOL ret = FALSE; /* Final result */
327
328 /* Get class Guid */
329 if (!SetupGetLineTextW(
330 NULL, /* Context */
331 hInf,
332 Version, ClassGUID,
333 guidW, sizeof(guidW),
334 NULL /* Required size */))
335 {
336 goto cleanup;
337 }
338 guidW[37] = '\0'; /* Replace the } by a NULL character */
339 if (UuidFromStringW(&guidW[1], ClassGuid) != RPC_S_OK)
340 {
341 SetLastError(ERROR_GEN_FAILURE);
342 goto cleanup;
343 }
344
345 /* Get provider name */
346 Result = SetupGetLineTextW(
347 NULL, /* Context */
348 hInf, Version, INF_PROVIDER,
349 NULL, 0,
350 &RequiredSize);
351 if (Result)
352 {
353 /* We know the needed buffer size */
354 ProviderName = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
355 if (!ProviderName)
356 {
357 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
358 goto cleanup;
359 }
360 Result = SetupGetLineTextW(
361 NULL, /* Context */
362 hInf, Version, INF_PROVIDER,
363 ProviderName, RequiredSize,
364 &RequiredSize);
365 }
366 if (!Result)
367 goto cleanup;
368 *pProviderName = ProviderName;
369
370 /* Read the "DriverVer" value */
371 Result = SetupGetLineTextW(
372 NULL, /* Context */
373 hInf, Version, INF_DRIVER_VER,
374 NULL, 0,
375 &RequiredSize);
376 if (Result)
377 {
378 /* We know know the needed buffer size */
379 DriverVer = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
380 if (!DriverVer)
381 {
382 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
383 goto cleanup;
384 }
385 Result = SetupGetLineTextW(
386 NULL, /* Context */
387 hInf, Version, INF_DRIVER_VER,
388 DriverVer, RequiredSize,
389 &RequiredSize);
390 }
391 else
392 {
393 /* windows sets default date of 00/00/0000 when this directive is missing*/
394 memset(DriverDate, 0, sizeof(FILETIME));
395 *DriverVersion = 0;
396 return TRUE;
397 }
398
399 /* Get driver date and driver version, by analyzing the "DriverVer" value */
400 pComma = strchrW(DriverVer, ',');
401 if (pComma != NULL)
402 {
403 *pComma = UNICODE_NULL;
404 pVersion = pComma + 1;
405 }
406 /* Get driver date version. Invalid date = 00/00/00 */
407 memset(DriverDate, 0, sizeof(FILETIME));
408 if (strlenW(DriverVer) == 10
409 && (DriverVer[2] == '-' || DriverVer[2] == '/')
410 && (DriverVer[5] == '-' || DriverVer[5] == '/'))
411 {
412 memset(&SystemTime, 0, sizeof(SYSTEMTIME));
413 DriverVer[2] = DriverVer[5] = UNICODE_NULL;
414 SystemTime.wMonth = ((DriverVer[0] - '0') * 10) + DriverVer[1] - '0';
415 SystemTime.wDay = ((DriverVer[3] - '0') * 10) + DriverVer[4] - '0';
416 SystemTime.wYear = ((DriverVer[6] - '0') * 1000) + ((DriverVer[7] - '0') * 100) + ((DriverVer[8] - '0') * 10) + DriverVer[9] - '0';
417 SystemTimeToFileTime(&SystemTime, DriverDate);
418 }
419 /* Get driver version. Invalid version = 0.0.0.0 */
420 *DriverVersion = 0;
421 if (pVersion)
422 {
423 WORD Major, Minor = 0, Revision = 0, Build = 0;
424 LPWSTR pMinor = NULL, pRevision = NULL, pBuild = NULL;
425 LARGE_INTEGER fullVersion;
426
427 pMinor = strchrW(pVersion, '.');
428 if (pMinor)
429 {
430 *pMinor = 0;
431 pRevision = strchrW(++pMinor, '.');
432 Minor = atoiW(pMinor);
433 }
434 if (pRevision)
435 {
436 *pRevision = 0;
437 pBuild = strchrW(++pRevision, '.');
438 Revision = atoiW(pRevision);
439 }
440 if (pBuild)
441 {
442 *pBuild = 0;
443 pBuild++;
444 Build = atoiW(pBuild);
445 }
446 Major = atoiW(pVersion);
447 fullVersion.u.HighPart = Major << 16 | Minor;
448 fullVersion.u.LowPart = Revision << 16 | Build;
449 memcpy(DriverVersion, &fullVersion, sizeof(LARGE_INTEGER));
450 }
451
452 ret = TRUE;
453
454 cleanup:
455 if (!ret)
456 {
457 HeapFree(GetProcessHeap(), 0, ProviderName);
458 *pProviderName = NULL;
459 }
460 HeapFree(GetProcessHeap(), 0, DriverVer);
461
462 return ret;
463 }
464
465 static BOOL
466 GetHardwareAndCompatibleIDsLists(
467 IN HDEVINFO DeviceInfoSet,
468 IN OUT PSP_DEVINFO_DATA DeviceInfoData,
469 OUT LPWSTR *pHardwareIDs OPTIONAL,
470 OUT LPDWORD pHardwareIDsRequiredSize OPTIONAL,
471 OUT LPWSTR *pCompatibleIDs OPTIONAL,
472 OUT LPDWORD pCompatibleIDsRequiredSize OPTIONAL)
473 {
474 LPWSTR HardwareIDs = NULL;
475 LPWSTR CompatibleIDs = NULL;
476 DWORD RequiredSize;
477 BOOL Result;
478
479 /* Get hardware IDs list */
480 Result = FALSE;
481 RequiredSize = 512; /* Initial buffer size */
482 SetLastError(ERROR_INSUFFICIENT_BUFFER);
483 while (!Result && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
484 {
485 MyFree(HardwareIDs);
486 HardwareIDs = MyMalloc(RequiredSize);
487 if (!HardwareIDs)
488 {
489 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
490 goto done;
491 }
492 Result = SetupDiGetDeviceRegistryPropertyW(
493 DeviceInfoSet,
494 DeviceInfoData,
495 SPDRP_HARDWAREID,
496 NULL,
497 (PBYTE)HardwareIDs,
498 RequiredSize,
499 &RequiredSize);
500 }
501 if (!Result)
502 {
503 if (GetLastError() == ERROR_FILE_NOT_FOUND)
504 {
505 /* No hardware ID for this device */
506 MyFree(HardwareIDs);
507 HardwareIDs = NULL;
508 RequiredSize = 0;
509 }
510 else
511 goto done;
512 }
513 if (pHardwareIDs)
514 *pHardwareIDs = HardwareIDs;
515 if (pHardwareIDsRequiredSize)
516 *pHardwareIDsRequiredSize = RequiredSize;
517
518 /* Get compatible IDs list */
519 Result = FALSE;
520 RequiredSize = 512; /* Initial buffer size */
521 SetLastError(ERROR_INSUFFICIENT_BUFFER);
522 while (!Result && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
523 {
524 MyFree(CompatibleIDs);
525 CompatibleIDs = MyMalloc(RequiredSize);
526 if (!CompatibleIDs)
527 {
528 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
529 goto done;
530 }
531 Result = SetupDiGetDeviceRegistryPropertyW(
532 DeviceInfoSet,
533 DeviceInfoData,
534 SPDRP_COMPATIBLEIDS,
535 NULL,
536 (PBYTE)CompatibleIDs,
537 RequiredSize,
538 &RequiredSize);
539 }
540 if (!Result)
541 {
542 if (GetLastError() == ERROR_FILE_NOT_FOUND)
543 {
544 /* No compatible ID for this device */
545 MyFree(CompatibleIDs);
546 CompatibleIDs = NULL;
547 RequiredSize = 0;
548 }
549 else
550 goto done;
551 }
552 if (pCompatibleIDs)
553 *pCompatibleIDs = CompatibleIDs;
554 if (pCompatibleIDsRequiredSize)
555 *pCompatibleIDsRequiredSize = RequiredSize;
556
557 Result = TRUE;
558
559 done:
560 if (!Result)
561 {
562 MyFree(HardwareIDs);
563 MyFree(CompatibleIDs);
564 }
565 return Result;
566 }
567
568 #if WIN32_WINNT < 0x0600
569 /* WARNING:
570 * This code has been copied from advapi32/reg/reg.c,
571 * so this dll can be tested as is on Windows XP
572 */
573
574 #define RRF_RT_REG_NONE (1 << 0)
575 #define RRF_RT_REG_SZ (1 << 1)
576 #define RRF_RT_REG_EXPAND_SZ (1 << 2)
577 #define RRF_RT_REG_BINARY (1 << 3)
578 #define RRF_RT_REG_DWORD (1 << 4)
579 #define RRF_RT_REG_MULTI_SZ (1 << 5)
580 #define RRF_RT_REG_QWORD (1 << 6)
581 #define RRF_RT_DWORD (RRF_RT_REG_BINARY | RRF_RT_REG_DWORD)
582 #define RRF_RT_QWORD (RRF_RT_REG_BINARY | RRF_RT_REG_QWORD)
583 #define RRF_NOEXPAND (1 << 28)
584 #define RRF_ZEROONFAILURE (1 << 29)
585
586 static VOID
587 RegpApplyRestrictions( DWORD dwFlags, DWORD dwType, DWORD cbData,
588 PLONG ret )
589 {
590 /* Check if the type is restricted by the passed flags */
591 if (*ret == ERROR_SUCCESS || *ret == ERROR_MORE_DATA)
592 {
593 DWORD dwMask = 0;
594
595 switch (dwType)
596 {
597 case REG_NONE: dwMask = RRF_RT_REG_NONE; break;
598 case REG_SZ: dwMask = RRF_RT_REG_SZ; break;
599 case REG_EXPAND_SZ: dwMask = RRF_RT_REG_EXPAND_SZ; break;
600 case REG_MULTI_SZ: dwMask = RRF_RT_REG_MULTI_SZ; break;
601 case REG_BINARY: dwMask = RRF_RT_REG_BINARY; break;
602 case REG_DWORD: dwMask = RRF_RT_REG_DWORD; break;
603 case REG_QWORD: dwMask = RRF_RT_REG_QWORD; break;
604 }
605
606 if (dwFlags & dwMask)
607 {
608 /* Type is not restricted, check for size mismatch */
609 if (dwType == REG_BINARY)
610 {
611 DWORD cbExpect = 0;
612
613 if ((dwFlags & RRF_RT_DWORD) == RRF_RT_DWORD)
614 cbExpect = 4;
615 else if ((dwFlags & RRF_RT_QWORD) == RRF_RT_QWORD)
616 cbExpect = 8;
617
618 if (cbExpect && cbData != cbExpect)
619 *ret = ERROR_DATATYPE_MISMATCH;
620 }
621 }
622 else *ret = ERROR_UNSUPPORTED_TYPE;
623 }
624 }
625
626 static LONG WINAPI
627 RegGetValueW( HKEY hKey, LPCWSTR pszSubKey, LPCWSTR pszValue,
628 DWORD dwFlags, LPDWORD pdwType, PVOID pvData,
629 LPDWORD pcbData )
630 {
631 DWORD dwType, cbData = pcbData ? *pcbData : 0;
632 PVOID pvBuf = NULL;
633 LONG ret;
634
635 TRACE("(%p,%s,%s,%ld,%p,%p,%p=%ld)\n",
636 hKey, debugstr_w(pszSubKey), debugstr_w(pszValue), dwFlags, pdwType,
637 pvData, pcbData, cbData);
638
639 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND))
640 return ERROR_INVALID_PARAMETER;
641
642 if (pszSubKey && pszSubKey[0])
643 {
644 ret = RegOpenKeyExW(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
645 if (ret != ERROR_SUCCESS) return ret;
646 }
647
648 ret = RegQueryValueExW(hKey, pszValue, NULL, &dwType, pvData, &cbData);
649
650 /* If we are going to expand we need to read in the whole the value even
651 * if the passed buffer was too small as the expanded string might be
652 * smaller than the unexpanded one and could fit into cbData bytes. */
653 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
654 (dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND)))
655 {
656 do {
657 if (pvBuf) HeapFree(GetProcessHeap(), 0, pvBuf);
658
659 pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
660 if (!pvBuf)
661 {
662 ret = ERROR_NOT_ENOUGH_MEMORY;
663 break;
664 }
665
666 if (ret == ERROR_MORE_DATA)
667 ret = RegQueryValueExW(hKey, pszValue, NULL,
668 &dwType, pvBuf, &cbData);
669 else
670 {
671 /* Even if cbData was large enough we have to copy the
672 * string since ExpandEnvironmentStrings can't handle
673 * overlapping buffers. */
674 CopyMemory(pvBuf, pvData, cbData);
675 }
676
677 /* Both the type or the value itself could have been modified in
678 * between so we have to keep retrying until the buffer is large
679 * enough or we no longer have to expand the value. */
680 } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
681
682 if (ret == ERROR_SUCCESS)
683 {
684 if (dwType == REG_EXPAND_SZ)
685 {
686 cbData = ExpandEnvironmentStringsW(pvBuf, pvData,
687 pcbData ? (*pcbData)/sizeof(WCHAR) : 0);
688 dwType = REG_SZ;
689 if(pcbData && cbData > ((*pcbData)/sizeof(WCHAR)))
690 ret = ERROR_MORE_DATA;
691 }
692 else if (pcbData)
693 CopyMemory(pvData, pvBuf, *pcbData);
694 }
695
696 if (pvBuf) HeapFree(GetProcessHeap(), 0, pvBuf);
697 }
698
699 if (pszSubKey && pszSubKey[0])
700 RegCloseKey(hKey);
701
702 RegpApplyRestrictions(dwFlags, dwType, cbData, &ret);
703
704 if (pcbData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
705 ZeroMemory(pvData, *pcbData);
706
707 if (pdwType) *pdwType = dwType;
708 if (pcbData) *pcbData = cbData;
709
710 return ret;
711 }
712 #endif /* End of code copied from advapi32/reg/reg.c */
713
714 /***********************************************************************
715 * SetupDiBuildDriverInfoList (SETUPAPI.@)
716 */
717 BOOL WINAPI
718 SetupDiBuildDriverInfoList(
719 IN HDEVINFO DeviceInfoSet,
720 IN OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
721 IN DWORD DriverType)
722 {
723 struct DeviceInfoSet *list;
724 SP_DEVINSTALL_PARAMS_W InstallParams;
725 PVOID Buffer = NULL;
726 struct InfFileDetails *currentInfFileDetails = NULL;
727 LPWSTR ProviderName = NULL;
728 LPWSTR ManufacturerName = NULL;
729 WCHAR ManufacturerSection[LINE_LEN + 1];
730 LPWSTR HardwareIDs = NULL;
731 LPWSTR CompatibleIDs = NULL;
732 LPWSTR FullInfFileName = NULL;
733 LPWSTR ExcludeFromSelect = NULL;
734 FILETIME DriverDate;
735 DWORDLONG DriverVersion = 0;
736 DWORD RequiredSize;
737 BOOL ret = FALSE;
738
739 TRACE("%p %p %ld\n", DeviceInfoSet, DeviceInfoData, DriverType);
740
741 if (!DeviceInfoSet)
742 SetLastError(ERROR_INVALID_HANDLE);
743 else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
744 SetLastError(ERROR_INVALID_HANDLE);
745 else if (list->HKLM != HKEY_LOCAL_MACHINE)
746 SetLastError(ERROR_INVALID_HANDLE);
747 else if (DriverType != SPDIT_CLASSDRIVER && DriverType != SPDIT_COMPATDRIVER)
748 SetLastError(ERROR_INVALID_PARAMETER);
749 else if (DriverType == SPDIT_COMPATDRIVER && !DeviceInfoData)
750 SetLastError(ERROR_INVALID_PARAMETER);
751 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
752 SetLastError(ERROR_INVALID_USER_BUFFER);
753 else
754 {
755 PLIST_ENTRY pDriverListHead = &list->DriverListHead;
756 BOOL Result;
757
758 InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
759 Result = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
760 if (!Result)
761 goto done;
762
763 if (DeviceInfoData)
764 {
765 struct DeviceInfo *devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
766 if (!(devInfo->CreationFlags & DICD_INHERIT_CLASSDRVS))
767 pDriverListHead = &devInfo->DriverListHead;
768 }
769
770 if (DriverType == SPDIT_COMPATDRIVER)
771 {
772 /* Get hardware and compatible IDs lists */
773 Result = GetHardwareAndCompatibleIDsLists(
774 DeviceInfoSet,
775 DeviceInfoData,
776 &HardwareIDs,
777 NULL,
778 &CompatibleIDs,
779 NULL);
780 if (!Result)
781 goto done;
782 if (!HardwareIDs && !CompatibleIDs)
783 {
784 SetLastError(ERROR_FILE_NOT_FOUND);
785 goto done;
786 }
787 }
788
789 if (InstallParams.FlagsEx & DI_FLAGSEX_INSTALLEDDRIVER)
790 {
791 HKEY hDriverKey;
792 WCHAR InfFileName[MAX_PATH];
793 WCHAR InfFileSection[MAX_PATH];
794 ULONG RequiredSize;
795 struct DeviceInfo *devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
796 struct InfFileDetails *infFileDetails = NULL;
797 FILETIME DriverDate;
798 LONG rc;
799 DWORD len;
800
801 /* Prepend inf directory name to file name */
802 len = sizeof(InfFileName) / sizeof(InfFileName[0]);
803 RequiredSize = GetSystemWindowsDirectoryW(InfFileName, len);
804 if (RequiredSize == 0 || RequiredSize >= len)
805 goto done;
806 if (*InfFileName && InfFileName[strlenW(InfFileName) - 1] != '\\')
807 strcatW(InfFileName, BackSlash);
808 strcatW(InfFileName, InfDirectory);
809
810 /* Read some information from registry, before creating the driver structure */
811 hDriverKey = SetupDiOpenDevRegKey(
812 DeviceInfoSet,
813 DeviceInfoData,
814 DICS_FLAG_GLOBAL,
815 0,
816 DIREG_DRV,
817 KEY_QUERY_VALUE);
818 if (hDriverKey == INVALID_HANDLE_VALUE)
819 goto done;
820 RequiredSize = (len - strlenW(InfFileName)) * sizeof(WCHAR);
821 rc = RegGetValueW(
822 hDriverKey,
823 NULL,
824 REGSTR_VAL_INFPATH,
825 RRF_RT_REG_SZ,
826 NULL,
827 &InfFileName[strlenW(InfFileName)],
828 &RequiredSize);
829 if (rc != ERROR_SUCCESS)
830 {
831 SetLastError(rc);
832 CloseHandle(hDriverKey);
833 goto done;
834 }
835 RequiredSize = sizeof(InfFileSection);
836 rc = RegGetValueW(
837 hDriverKey,
838 NULL,
839 REGSTR_VAL_INFSECTION,
840 RRF_RT_REG_SZ,
841 NULL,
842 InfFileSection,
843 &RequiredSize);
844 if (rc != ERROR_SUCCESS)
845 {
846 SetLastError(rc);
847 CloseHandle(hDriverKey);
848 goto done;
849 }
850 TRACE("Current driver in %s/%s\n", debugstr_w(InfFileName), debugstr_w(InfFileSection));
851 infFileDetails = CreateInfFileDetails(InfFileName);
852 if (!infFileDetails)
853 {
854 CloseHandle(hDriverKey);
855 goto done;
856 }
857 DriverDate.dwLowDateTime = DriverDate.dwHighDateTime = 0; /* FIXME */
858 CloseHandle(hDriverKey);
859 ret = AddKnownDriverToList(
860 pDriverListHead,
861 SPDIT_COMPATDRIVER,
862 &devInfo->ClassGuid,
863 infFileDetails,
864 InfFileName,
865 InfFileSection, /* Yes, we don't care of section extension */
866 L"DriverDescription", /* FIXME */
867 L"ProviderName", /* FIXME */
868 L"ManufacturerName", /* FIXME */
869 L"MatchingId", /* FIXME */
870 DriverDate,
871 0, /* FIXME: DriverVersion */
872 0);
873 if (!ret)
874 DereferenceInfFile(infFileDetails);
875 Result = FALSE;
876 }
877 else if (InstallParams.Flags & DI_ENUMSINGLEINF)
878 {
879 /* InstallParams.DriverPath contains the name of a .inf file */
880 RequiredSize = strlenW(InstallParams.DriverPath) + 2;
881 Buffer = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
882 if (!Buffer)
883 {
884 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
885 goto done;
886 }
887 strcpyW(Buffer, InstallParams.DriverPath);
888 ((LPWSTR)Buffer)[RequiredSize - 1] = 0;
889 Result = TRUE;
890 }
891 else
892 {
893 /* Enumerate .inf files */
894 Result = FALSE;
895 RequiredSize = 32768; /* Initial buffer size */
896 SetLastError(ERROR_INSUFFICIENT_BUFFER);
897 while (!Result && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
898 {
899 HeapFree(GetProcessHeap(), 0, Buffer);
900 Buffer = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
901 if (!Buffer)
902 {
903 Result = FALSE;
904 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
905 break;
906 }
907 Result = SetupGetInfFileListW(
908 *InstallParams.DriverPath ? InstallParams.DriverPath : NULL,
909 INF_STYLE_WIN4,
910 Buffer, RequiredSize,
911 &RequiredSize);
912 }
913 if (!Result && GetLastError() == ERROR_FILE_NOT_FOUND)
914 {
915 /* No .inf file in specified directory. So, we should
916 * success as we created an empty driver info list.
917 */
918 ret = TRUE;
919 goto done;
920 }
921 }
922 if (Result)
923 {
924 LPCWSTR filename;
925 LPWSTR pFullFilename;
926
927 if (InstallParams.Flags & DI_ENUMSINGLEINF)
928 {
929 /* Only a filename */
930 FullInfFileName = HeapAlloc(GetProcessHeap(), 0, MAX_PATH * sizeof(WCHAR));
931 if (!FullInfFileName)
932 goto done;
933 pFullFilename = &FullInfFileName[0];
934 }
935 else if (*InstallParams.DriverPath)
936 {
937 /* Directory name specified */
938 DWORD len;
939 len = GetFullPathNameW(InstallParams.DriverPath, 0, NULL, NULL);
940 if (len == 0)
941 goto done;
942 FullInfFileName = HeapAlloc(GetProcessHeap(), 0, (len + 1 + MAX_PATH) * sizeof(WCHAR));
943 if (!FullInfFileName)
944 goto done;
945 len = GetFullPathNameW(InstallParams.DriverPath, len, FullInfFileName, NULL);
946 if (len == 0)
947 goto done;
948 if (*FullInfFileName && FullInfFileName[strlenW(FullInfFileName) - 1] != '\\')
949 strcatW(FullInfFileName, BackSlash);
950 pFullFilename = &FullInfFileName[strlenW(FullInfFileName)];
951 }
952 else
953 {
954 /* Nothing specified ; need to get the %SYSTEMROOT%\ directory */
955 DWORD len;
956 len = GetSystemWindowsDirectoryW(NULL, 0);
957 if (len == 0)
958 goto done;
959 FullInfFileName = HeapAlloc(GetProcessHeap(), 0, (len + 1 + strlenW(InfDirectory) + MAX_PATH) * sizeof(WCHAR));
960 if (!FullInfFileName)
961 goto done;
962 len = GetSystemWindowsDirectoryW(FullInfFileName, len);
963 if (len == 0)
964 goto done;
965 if (*FullInfFileName && FullInfFileName[strlenW(FullInfFileName) - 1] != '\\')
966 strcatW(FullInfFileName, BackSlash);
967 strcatW(FullInfFileName, InfDirectory);
968 pFullFilename = &FullInfFileName[strlenW(FullInfFileName)];
969 }
970
971 for (filename = (LPCWSTR)Buffer; *filename; filename += strlenW(filename) + 1)
972 {
973 INFCONTEXT ContextManufacturer, ContextDevice;
974 GUID ClassGuid;
975
976 strcpyW(pFullFilename, filename);
977 TRACE("Opening file %s\n", debugstr_w(FullInfFileName));
978
979 currentInfFileDetails = CreateInfFileDetails(FullInfFileName);
980 if (!currentInfFileDetails)
981 continue;
982
983 if (!GetVersionInformationFromInfFile(
984 currentInfFileDetails->hInf,
985 &ClassGuid,
986 &ProviderName,
987 &DriverDate,
988 &DriverVersion))
989 {
990 DereferenceInfFile(currentInfFileDetails);
991 currentInfFileDetails = NULL;
992 continue;
993 }
994
995 if (DriverType == SPDIT_CLASSDRIVER)
996 {
997 /* Check if the ClassGuid in this .inf file is corresponding with our needs */
998 if (!IsEqualIID(&list->ClassGuid, &GUID_NULL) && !IsEqualIID(&list->ClassGuid, &ClassGuid))
999 {
1000 goto next;
1001 }
1002 }
1003
1004 if (InstallParams.FlagsEx & DI_FLAGSEX_ALLOWEXCLUDEDDRVS)
1005 {
1006 /* Read ExcludeFromSelect control flags */
1007 /* FIXME */
1008 }
1009 else
1010 FIXME("ExcludeFromSelect list ignored\n");
1011
1012 /* Get the manufacturers list */
1013 Result = SetupFindFirstLineW(currentInfFileDetails->hInf, INF_MANUFACTURER, NULL, &ContextManufacturer);
1014 while (Result)
1015 {
1016 Result = SetupGetStringFieldW(
1017 &ContextManufacturer,
1018 0, /* Field index */
1019 NULL, 0,
1020 &RequiredSize);
1021 if (Result)
1022 {
1023 /* We got the needed size for the buffer */
1024 ManufacturerName = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
1025 if (!ManufacturerName)
1026 {
1027 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1028 goto done;
1029 }
1030 Result = SetupGetStringFieldW(
1031 &ContextManufacturer,
1032 0, /* Field index */
1033 ManufacturerName, RequiredSize,
1034 &RequiredSize);
1035 }
1036 /* Get manufacturer section name */
1037 Result = SetupGetStringFieldW(
1038 &ContextManufacturer,
1039 1, /* Field index */
1040 ManufacturerSection, LINE_LEN,
1041 &RequiredSize);
1042 if (Result)
1043 {
1044 ManufacturerSection[RequiredSize] = 0; /* Final NULL char */
1045 /* Add (possible) extension to manufacturer section name */
1046 Result = SetupDiGetActualSectionToInstallW(
1047 currentInfFileDetails->hInf, ManufacturerSection, ManufacturerSection, LINE_LEN, NULL, NULL);
1048 if (Result)
1049 {
1050 TRACE("Enumerating devices in manufacturer %s\n", debugstr_w(ManufacturerSection));
1051 Result = SetupFindFirstLineW(currentInfFileDetails->hInf, ManufacturerSection, NULL, &ContextDevice);
1052 }
1053 }
1054 while (Result)
1055 {
1056 if (DriverType == SPDIT_CLASSDRIVER)
1057 {
1058 /* FIXME: Check ExcludeFromSelect list */
1059 if (!AddDriverToList(
1060 pDriverListHead,
1061 DriverType,
1062 &ClassGuid,
1063 ContextDevice,
1064 currentInfFileDetails,
1065 FullInfFileName,
1066 ProviderName,
1067 ManufacturerName,
1068 NULL,
1069 DriverDate, DriverVersion,
1070 0))
1071 {
1072 break;
1073 }
1074 }
1075 else /* DriverType = SPDIT_COMPATDRIVER */
1076 {
1077 /* 1. Get all fields */
1078 DWORD FieldCount = SetupGetFieldCount(&ContextDevice);
1079 DWORD DriverRank;
1080 DWORD i;
1081 LPCWSTR currentId;
1082 BOOL DriverAlreadyAdded;
1083
1084 for (i = 2; i <= FieldCount; i++)
1085 {
1086 LPWSTR DeviceId = NULL;
1087 Result = FALSE;
1088 RequiredSize = 128; /* Initial buffer size */
1089 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1090 while (!Result && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
1091 {
1092 HeapFree(GetProcessHeap(), 0, DeviceId);
1093 DeviceId = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
1094 if (!DeviceId)
1095 {
1096 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1097 goto done;
1098 }
1099 Result = SetupGetStringFieldW(
1100 &ContextDevice,
1101 i,
1102 DeviceId, RequiredSize,
1103 &RequiredSize);
1104 }
1105 if (!Result)
1106 {
1107 HeapFree(GetProcessHeap(), 0, DeviceId);
1108 goto done;
1109 }
1110 /* FIXME: Check ExcludeFromSelect list */
1111 DriverAlreadyAdded = FALSE;
1112 for (DriverRank = 0, currentId = (LPCWSTR)HardwareIDs; !DriverAlreadyAdded && *currentId; currentId += strlenW(currentId) + 1, DriverRank++)
1113 {
1114 if (strcmpiW(DeviceId, currentId) == 0)
1115 {
1116 AddDriverToList(
1117 pDriverListHead,
1118 DriverType,
1119 &ClassGuid,
1120 ContextDevice,
1121 currentInfFileDetails,
1122 FullInfFileName,
1123 ProviderName,
1124 ManufacturerName,
1125 currentId,
1126 DriverDate, DriverVersion,
1127 DriverRank + (i == 2 ? 0 : 0x1000 + i - 3));
1128 DriverAlreadyAdded = TRUE;
1129 }
1130 }
1131 if (CompatibleIDs)
1132 {
1133 for (DriverRank = 0, currentId = (LPCWSTR)CompatibleIDs; !DriverAlreadyAdded && *currentId; currentId += strlenW(currentId) + 1, DriverRank++)
1134 {
1135 if (strcmpiW(DeviceId, currentId) == 0)
1136 {
1137 AddDriverToList(
1138 pDriverListHead,
1139 DriverType,
1140 &ClassGuid,
1141 ContextDevice,
1142 currentInfFileDetails,
1143 FullInfFileName,
1144 ProviderName,
1145 ManufacturerName,
1146 currentId,
1147 DriverDate, DriverVersion,
1148 DriverRank + (i == 2 ? 0x2000 : 0x3000 + i - 3));
1149 DriverAlreadyAdded = TRUE;
1150 }
1151 }
1152 }
1153 HeapFree(GetProcessHeap(), 0, DeviceId);
1154 }
1155 }
1156 Result = SetupFindNextLine(&ContextDevice, &ContextDevice);
1157 }
1158
1159 HeapFree(GetProcessHeap(), 0, ManufacturerName);
1160 ManufacturerName = NULL;
1161 Result = SetupFindNextLine(&ContextManufacturer, &ContextManufacturer);
1162 }
1163
1164 ret = TRUE;
1165 next:
1166 HeapFree(GetProcessHeap(), 0, ProviderName);
1167 HeapFree(GetProcessHeap(), 0, ExcludeFromSelect);
1168 ProviderName = ExcludeFromSelect = NULL;
1169
1170 DereferenceInfFile(currentInfFileDetails);
1171 currentInfFileDetails = NULL;
1172 }
1173 ret = TRUE;
1174 }
1175 }
1176
1177 done:
1178 if (ret)
1179 {
1180 if (DeviceInfoData)
1181 {
1182 InstallParams.Flags |= DI_DIDCOMPAT;
1183 InstallParams.FlagsEx |= DI_FLAGSEX_DIDCOMPATINFO;
1184 }
1185 else
1186 {
1187 InstallParams.Flags |= DI_DIDCLASS;
1188 InstallParams.FlagsEx |= DI_FLAGSEX_DIDINFOLIST;
1189 }
1190 ret = SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
1191 }
1192
1193 HeapFree(GetProcessHeap(), 0, ProviderName);
1194 HeapFree(GetProcessHeap(), 0, ManufacturerName);
1195 MyFree(HardwareIDs);
1196 MyFree(CompatibleIDs);
1197 HeapFree(GetProcessHeap(), 0, FullInfFileName);
1198 HeapFree(GetProcessHeap(), 0, ExcludeFromSelect);
1199 if (currentInfFileDetails)
1200 DereferenceInfFile(currentInfFileDetails);
1201 HeapFree(GetProcessHeap(), 0, Buffer);
1202
1203 TRACE("Returning %d\n", ret);
1204 return ret;
1205 }
1206
1207 /***********************************************************************
1208 * SetupDiDestroyDriverInfoList (SETUPAPI.@)
1209 */
1210 BOOL WINAPI
1211 SetupDiDestroyDriverInfoList(
1212 IN HDEVINFO DeviceInfoSet,
1213 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
1214 IN DWORD DriverType)
1215 {
1216 struct DeviceInfoSet *list;
1217 BOOL ret = FALSE;
1218
1219 TRACE("%p %p 0x%lx\n", DeviceInfoSet, DeviceInfoData, DriverType);
1220
1221 if (!DeviceInfoSet)
1222 SetLastError(ERROR_INVALID_HANDLE);
1223 else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
1224 SetLastError(ERROR_INVALID_HANDLE);
1225 else if (DriverType != SPDIT_CLASSDRIVER && DriverType != SPDIT_COMPATDRIVER)
1226 SetLastError(ERROR_INVALID_PARAMETER);
1227 else if (DriverType == SPDIT_COMPATDRIVER && !DeviceInfoData)
1228 SetLastError(ERROR_INVALID_PARAMETER);
1229 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
1230 SetLastError(ERROR_INVALID_USER_BUFFER);
1231 else
1232 {
1233 PLIST_ENTRY ListEntry;
1234 struct DriverInfoElement *driverInfo;
1235 SP_DEVINSTALL_PARAMS_W InstallParams;
1236
1237 InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
1238 if (!SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams))
1239 goto done;
1240
1241 if (!DeviceInfoData)
1242 /* Fall back to destroying class driver list */
1243 DriverType = SPDIT_CLASSDRIVER;
1244
1245 if (DriverType == SPDIT_CLASSDRIVER)
1246 {
1247 while (!IsListEmpty(&list->DriverListHead))
1248 {
1249 ListEntry = RemoveHeadList(&list->DriverListHead);
1250 driverInfo = CONTAINING_RECORD(ListEntry, struct DriverInfoElement, ListEntry);
1251 DestroyDriverInfoElement(driverInfo);
1252 }
1253 InstallParams.Reserved = 0;
1254 InstallParams.Flags &= ~(DI_DIDCLASS | DI_MULTMFGS);
1255 InstallParams.FlagsEx &= ~DI_FLAGSEX_DIDINFOLIST;
1256 ret = SetupDiSetDeviceInstallParamsW(DeviceInfoSet, NULL, &InstallParams);
1257 }
1258 else
1259 {
1260 SP_DEVINSTALL_PARAMS_W InstallParamsSet;
1261 struct DeviceInfo *deviceInfo;
1262
1263 InstallParamsSet.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
1264 if (!SetupDiGetDeviceInstallParamsW(DeviceInfoSet, NULL, &InstallParamsSet))
1265 goto done;
1266 deviceInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
1267 while (!IsListEmpty(&deviceInfo->DriverListHead))
1268 {
1269 ListEntry = RemoveHeadList(&deviceInfo->DriverListHead);
1270 driverInfo = CONTAINING_RECORD(ListEntry, struct DriverInfoElement, ListEntry);
1271 if ((PVOID)InstallParamsSet.Reserved == driverInfo)
1272 {
1273 InstallParamsSet.Reserved = 0;
1274 SetupDiSetDeviceInstallParamsW(DeviceInfoSet, NULL, &InstallParamsSet);
1275 }
1276 DestroyDriverInfoElement(driverInfo);
1277 }
1278 InstallParams.Reserved = 0;
1279 InstallParams.Flags &= ~DI_DIDCOMPAT;
1280 InstallParams.FlagsEx &= ~DI_FLAGSEX_DIDCOMPATINFO;
1281 ret = SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
1282 }
1283 }
1284
1285 done:
1286 TRACE("Returning %d\n", ret);
1287 return ret;
1288 }
1289
1290 /***********************************************************************
1291 * SetupDiEnumDriverInfoA (SETUPAPI.@)
1292 */
1293 BOOL WINAPI
1294 SetupDiEnumDriverInfoA(
1295 IN HDEVINFO DeviceInfoSet,
1296 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
1297 IN DWORD DriverType,
1298 IN DWORD MemberIndex,
1299 OUT PSP_DRVINFO_DATA_A DriverInfoData)
1300 {
1301 SP_DRVINFO_DATA_V2_W driverInfoData2W;
1302 BOOL ret = FALSE;
1303
1304 TRACE("%p %p 0x%lx %ld %p\n", DeviceInfoSet, DeviceInfoData,
1305 DriverType, MemberIndex, DriverInfoData);
1306
1307 if (DriverInfoData == NULL)
1308 SetLastError(ERROR_INVALID_PARAMETER);
1309 else if (DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V1_A) && DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V2_A))
1310 SetLastError(ERROR_INVALID_USER_BUFFER);
1311 else
1312 {
1313 driverInfoData2W.cbSize = sizeof(SP_DRVINFO_DATA_V2_W);
1314 ret = SetupDiEnumDriverInfoW(DeviceInfoSet, DeviceInfoData,
1315 DriverType, MemberIndex, &driverInfoData2W);
1316
1317 if (ret)
1318 {
1319 /* Do W->A conversion */
1320 DriverInfoData->DriverType = driverInfoData2W.DriverType;
1321 DriverInfoData->Reserved = driverInfoData2W.Reserved;
1322 if (WideCharToMultiByte(CP_ACP, 0, driverInfoData2W.Description, -1,
1323 DriverInfoData->Description, LINE_LEN, NULL, NULL) == 0)
1324 {
1325 DriverInfoData->Description[0] = '\0';
1326 ret = FALSE;
1327 }
1328 if (WideCharToMultiByte(CP_ACP, 0, driverInfoData2W.MfgName, -1,
1329 DriverInfoData->MfgName, LINE_LEN, NULL, NULL) == 0)
1330 {
1331 DriverInfoData->MfgName[0] = '\0';
1332 ret = FALSE;
1333 }
1334 if (WideCharToMultiByte(CP_ACP, 0, driverInfoData2W.ProviderName, -1,
1335 DriverInfoData->ProviderName, LINE_LEN, NULL, NULL) == 0)
1336 {
1337 DriverInfoData->ProviderName[0] = '\0';
1338 ret = FALSE;
1339 }
1340 if (DriverInfoData->cbSize == sizeof(SP_DRVINFO_DATA_V2_A))
1341 {
1342 /* Copy more fields */
1343 DriverInfoData->DriverDate = driverInfoData2W.DriverDate;
1344 DriverInfoData->DriverVersion = driverInfoData2W.DriverVersion;
1345 }
1346 }
1347 }
1348
1349 TRACE("Returning %d\n", ret);
1350 return ret;
1351 }
1352
1353
1354 /***********************************************************************
1355 * SetupDiEnumDriverInfoW (SETUPAPI.@)
1356 */
1357 BOOL WINAPI
1358 SetupDiEnumDriverInfoW(
1359 IN HDEVINFO DeviceInfoSet,
1360 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
1361 IN DWORD DriverType,
1362 IN DWORD MemberIndex,
1363 OUT PSP_DRVINFO_DATA_W DriverInfoData)
1364 {
1365 PLIST_ENTRY ListHead;
1366 BOOL ret = FALSE;
1367
1368 TRACE("%p %p 0x%lx %ld %p\n", DeviceInfoSet, DeviceInfoData,
1369 DriverType, MemberIndex, DriverInfoData);
1370
1371 if (!DeviceInfoSet || !DriverInfoData)
1372 SetLastError(ERROR_INVALID_PARAMETER);
1373 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
1374 SetLastError(ERROR_INVALID_HANDLE);
1375 else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
1376 SetLastError(ERROR_INVALID_HANDLE);
1377 else if (DriverType != SPDIT_CLASSDRIVER && DriverType != SPDIT_COMPATDRIVER)
1378 SetLastError(ERROR_INVALID_PARAMETER);
1379 else if (DriverType == SPDIT_COMPATDRIVER && !DeviceInfoData)
1380 SetLastError(ERROR_INVALID_PARAMETER);
1381 else if (DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V1_W) && DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V2_W))
1382 SetLastError(ERROR_INVALID_USER_BUFFER);
1383 else
1384 {
1385 struct DeviceInfo *devInfo = NULL;
1386 PLIST_ENTRY ItemList;
1387 if (DeviceInfoData)
1388 devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
1389 if (!devInfo || (devInfo->CreationFlags & DICD_INHERIT_CLASSDRVS))
1390 {
1391 ListHead = &((struct DeviceInfoSet *)DeviceInfoSet)->DriverListHead;
1392 }
1393 else
1394 {
1395 ListHead = &devInfo->DriverListHead;
1396 }
1397
1398 ItemList = ListHead->Flink;
1399 while (ItemList != ListHead && MemberIndex-- > 0)
1400 ItemList = ItemList->Flink;
1401 if (ItemList == ListHead)
1402 SetLastError(ERROR_NO_MORE_ITEMS);
1403 else
1404 {
1405 struct DriverInfoElement *DrvInfo = CONTAINING_RECORD(ItemList, struct DriverInfoElement, ListEntry);
1406
1407 memcpy(
1408 &DriverInfoData->DriverType,
1409 &DrvInfo->Info.DriverType,
1410 DriverInfoData->cbSize - FIELD_OFFSET(SP_DRVINFO_DATA_W, DriverType));
1411 ret = TRUE;
1412 }
1413 }
1414
1415 TRACE("Returning %d\n", ret);
1416 return ret;
1417 }
1418
1419 /***********************************************************************
1420 * SetupDiGetSelectedDriverA (SETUPAPI.@)
1421 */
1422 BOOL WINAPI
1423 SetupDiGetSelectedDriverA(
1424 IN HDEVINFO DeviceInfoSet,
1425 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
1426 OUT PSP_DRVINFO_DATA_A DriverInfoData)
1427 {
1428 SP_DRVINFO_DATA_V2_W driverInfoData2W;
1429 BOOL ret = FALSE;
1430
1431 if (DriverInfoData == NULL)
1432 SetLastError(ERROR_INVALID_PARAMETER);
1433 else if (DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V1_A) && DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V2_A))
1434 SetLastError(ERROR_INVALID_USER_BUFFER);
1435 else
1436 {
1437 driverInfoData2W.cbSize = sizeof(SP_DRVINFO_DATA_V2_W);
1438
1439 ret = SetupDiGetSelectedDriverW(DeviceInfoSet,
1440 DeviceInfoData,
1441 &driverInfoData2W);
1442
1443 if (ret)
1444 {
1445 /* Do W->A conversion */
1446 DriverInfoData->DriverType = driverInfoData2W.DriverType;
1447 DriverInfoData->Reserved = driverInfoData2W.Reserved;
1448 if (WideCharToMultiByte(CP_ACP, 0, driverInfoData2W.Description, -1,
1449 DriverInfoData->Description, LINE_LEN, NULL, NULL) == 0)
1450 {
1451 DriverInfoData->Description[0] = '\0';
1452 ret = FALSE;
1453 }
1454 if (WideCharToMultiByte(CP_ACP, 0, driverInfoData2W.MfgName, -1,
1455 DriverInfoData->MfgName, LINE_LEN, NULL, NULL) == 0)
1456 {
1457 DriverInfoData->MfgName[0] = '\0';
1458 ret = FALSE;
1459 }
1460 if (WideCharToMultiByte(CP_ACP, 0, driverInfoData2W.ProviderName, -1,
1461 DriverInfoData->ProviderName, LINE_LEN, NULL, NULL) == 0)
1462 {
1463 DriverInfoData->ProviderName[0] = '\0';
1464 ret = FALSE;
1465 }
1466 if (DriverInfoData->cbSize == sizeof(SP_DRVINFO_DATA_V2_A))
1467 {
1468 /* Copy more fields */
1469 DriverInfoData->DriverDate = driverInfoData2W.DriverDate;
1470 DriverInfoData->DriverVersion = driverInfoData2W.DriverVersion;
1471 }
1472 }
1473 }
1474
1475 return ret;
1476 }
1477
1478 /***********************************************************************
1479 * SetupDiGetSelectedDriverW (SETUPAPI.@)
1480 */
1481 BOOL WINAPI
1482 SetupDiGetSelectedDriverW(
1483 IN HDEVINFO DeviceInfoSet,
1484 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
1485 OUT PSP_DRVINFO_DATA_W DriverInfoData)
1486 {
1487 BOOL ret = FALSE;
1488
1489 TRACE("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DriverInfoData);
1490
1491 if (!DeviceInfoSet || !DriverInfoData)
1492 SetLastError(ERROR_INVALID_PARAMETER);
1493 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
1494 SetLastError(ERROR_INVALID_HANDLE);
1495 else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
1496 SetLastError(ERROR_INVALID_HANDLE);
1497 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
1498 SetLastError(ERROR_INVALID_USER_BUFFER);
1499 else if (DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V1_W) && DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V2_W))
1500 SetLastError(ERROR_INVALID_USER_BUFFER);
1501 else
1502 {
1503 SP_DEVINSTALL_PARAMS InstallParams;
1504
1505 InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
1506 if (SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams))
1507 {
1508 struct DriverInfoElement *driverInfo;
1509 driverInfo = (struct DriverInfoElement *)InstallParams.Reserved;
1510 if (driverInfo == NULL)
1511 SetLastError(ERROR_NO_DRIVER_SELECTED);
1512 else
1513 {
1514 memcpy(
1515 &DriverInfoData->DriverType,
1516 &driverInfo->Info.DriverType,
1517 DriverInfoData->cbSize - FIELD_OFFSET(SP_DRVINFO_DATA_W, DriverType));
1518 ret = TRUE;
1519 }
1520 }
1521 }
1522
1523 TRACE("Returning %d\n", ret);
1524 return ret;
1525 }
1526
1527 /***********************************************************************
1528 * SetupDiSetSelectedDriverA (SETUPAPI.@)
1529 */
1530 BOOL WINAPI
1531 SetupDiSetSelectedDriverA(
1532 IN HDEVINFO DeviceInfoSet,
1533 IN OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
1534 IN OUT PSP_DRVINFO_DATA_A DriverInfoData OPTIONAL)
1535 {
1536 SP_DRVINFO_DATA_V1_W DriverInfoDataW;
1537 PSP_DRVINFO_DATA_W pDriverInfoDataW = NULL;
1538 BOOL ret = FALSE;
1539
1540 if (DriverInfoData != NULL)
1541 {
1542 if (DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V2_A) &&
1543 DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V1_A))
1544 {
1545 SetLastError(ERROR_INVALID_PARAMETER);
1546 return FALSE;
1547 }
1548
1549 DriverInfoDataW.cbSize = sizeof(SP_DRVINFO_DATA_V1_W);
1550 DriverInfoDataW.Reserved = DriverInfoData->Reserved;
1551
1552 if (DriverInfoDataW.Reserved == 0)
1553 {
1554 DriverInfoDataW.DriverType = DriverInfoData->DriverType;
1555
1556 /* convert the strings to unicode */
1557 if (!MultiByteToWideChar(CP_ACP,
1558 0,
1559 DriverInfoData->Description,
1560 LINE_LEN,
1561 DriverInfoDataW.Description,
1562 LINE_LEN) ||
1563 !MultiByteToWideChar(CP_ACP,
1564 0,
1565 DriverInfoData->ProviderName,
1566 LINE_LEN,
1567 DriverInfoDataW.ProviderName,
1568 LINE_LEN))
1569 {
1570 return FALSE;
1571 }
1572 }
1573
1574 pDriverInfoDataW = (PSP_DRVINFO_DATA_W)&DriverInfoDataW;
1575 }
1576
1577 ret = SetupDiSetSelectedDriverW(DeviceInfoSet,
1578 DeviceInfoData,
1579 pDriverInfoDataW);
1580
1581 if (ret && pDriverInfoDataW != NULL)
1582 {
1583 DriverInfoData->Reserved = DriverInfoDataW.Reserved;
1584 }
1585
1586 return ret;
1587 }
1588
1589 /***********************************************************************
1590 * SetupDiSetSelectedDriverW (SETUPAPI.@)
1591 */
1592 BOOL WINAPI
1593 SetupDiSetSelectedDriverW(
1594 IN HDEVINFO DeviceInfoSet,
1595 IN OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
1596 IN OUT PSP_DRVINFO_DATA_W DriverInfoData OPTIONAL)
1597 {
1598 BOOL ret = FALSE;
1599
1600 TRACE("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DriverInfoData);
1601
1602 if (!DeviceInfoSet)
1603 SetLastError(ERROR_INVALID_PARAMETER);
1604 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
1605 SetLastError(ERROR_INVALID_HANDLE);
1606 else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
1607 SetLastError(ERROR_INVALID_HANDLE);
1608 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
1609 SetLastError(ERROR_INVALID_USER_BUFFER);
1610 else if (DriverInfoData && DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V1_W) && DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V2_W))
1611 SetLastError(ERROR_INVALID_USER_BUFFER);
1612 else
1613 {
1614 struct DriverInfoElement **pDriverInfo;
1615 PLIST_ENTRY ListHead, ItemList;
1616
1617 if (DeviceInfoData)
1618 {
1619 pDriverInfo = (struct DriverInfoElement **)&((struct DeviceInfo *)DeviceInfoData->Reserved)->InstallParams.Reserved;
1620 ListHead = &((struct DeviceInfo *)DeviceInfoData->Reserved)->DriverListHead;
1621 }
1622 else
1623 {
1624 pDriverInfo = (struct DriverInfoElement **)&((struct DeviceInfoSet *)DeviceInfoSet)->InstallParams.Reserved;
1625 ListHead = &((struct DeviceInfoSet *)DeviceInfoSet)->DriverListHead;
1626 }
1627
1628 if (!DriverInfoData)
1629 {
1630 *pDriverInfo = NULL;
1631 ret = TRUE;
1632 }
1633 else
1634 {
1635 /* Search selected driver in list */
1636 ItemList = ListHead->Flink;
1637 while (ItemList != ListHead)
1638 {
1639 if (DriverInfoData->Reserved != 0)
1640 {
1641 if (DriverInfoData->Reserved == (ULONG_PTR)ItemList)
1642 break;
1643 }
1644 else
1645 {
1646 /* The caller wants to compare only DriverType, Description and ProviderName fields */
1647 struct DriverInfoElement *driverInfo = CONTAINING_RECORD(ItemList, struct DriverInfoElement, ListEntry);
1648 if (driverInfo->Info.DriverType == DriverInfoData->DriverType
1649 && strcmpW(driverInfo->Info.Description, DriverInfoData->Description) == 0
1650 && strcmpW(driverInfo->Info.ProviderName, DriverInfoData->ProviderName) == 0)
1651 {
1652 break;
1653 }
1654 }
1655 ItemList = ItemList->Flink;
1656 }
1657 if (ItemList == ListHead)
1658 SetLastError(ERROR_INVALID_PARAMETER);
1659 else
1660 {
1661 *pDriverInfo = CONTAINING_RECORD(ItemList, struct DriverInfoElement, ListEntry);
1662 DriverInfoData->Reserved = (ULONG_PTR)ItemList;
1663 ret = TRUE;
1664 TRACE("Choosing driver whose rank is 0x%lx\n",
1665 (*pDriverInfo)->Params.Rank);
1666 if (DeviceInfoData)
1667 memcpy(&DeviceInfoData->ClassGuid, &(*pDriverInfo)->ClassGuid, sizeof(GUID));
1668 }
1669 }
1670 }
1671
1672 TRACE("Returning %d\n", ret);
1673 return ret;
1674 }
1675
1676 /***********************************************************************
1677 * SetupDiGetDriverInfoDetailA (SETUPAPI.@)
1678 */
1679 BOOL WINAPI
1680 SetupDiGetDriverInfoDetailA(
1681 IN HDEVINFO DeviceInfoSet,
1682 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
1683 IN PSP_DRVINFO_DATA_A DriverInfoData,
1684 IN OUT PSP_DRVINFO_DETAIL_DATA_A DriverInfoDetailData OPTIONAL,
1685 IN DWORD DriverInfoDetailDataSize,
1686 OUT PDWORD RequiredSize OPTIONAL)
1687 {
1688 SP_DRVINFO_DATA_V2_W DriverInfoDataW;
1689 PSP_DRVINFO_DETAIL_DATA_W DriverInfoDetailDataW = NULL;
1690 DWORD BufSize = 0;
1691 DWORD HardwareIDLen = 0;
1692 BOOL ret = FALSE;
1693
1694 /* do some sanity checks, the unicode version might do more thorough checks */
1695 if (DriverInfoData == NULL ||
1696 (DriverInfoDetailData == NULL && DriverInfoDetailDataSize != 0) ||
1697 (DriverInfoDetailData != NULL &&
1698 (DriverInfoDetailDataSize < FIELD_OFFSET(SP_DRVINFO_DETAIL_DATA_A, HardwareID) + sizeof(CHAR) ||
1699 DriverInfoDetailData->cbSize != sizeof(SP_DRVINFO_DETAIL_DATA_A))))
1700 {
1701 SetLastError(ERROR_INVALID_PARAMETER);
1702 goto Cleanup;
1703 }
1704
1705 /* make sure we support both versions of the SP_DRVINFO_DATA structure */
1706 if (DriverInfoData->cbSize == sizeof(SP_DRVINFO_DATA_V1_A))
1707 {
1708 DriverInfoDataW.cbSize = sizeof(SP_DRVINFO_DATA_V1_W);
1709 }
1710 else if (DriverInfoData->cbSize == sizeof(SP_DRVINFO_DATA_V2_A))
1711 {
1712 DriverInfoDataW.cbSize = sizeof(SP_DRVINFO_DATA_V2_W);
1713 }
1714 else
1715 {
1716 SetLastError(ERROR_INVALID_PARAMETER);
1717 goto Cleanup;
1718 }
1719 DriverInfoDataW.DriverType = DriverInfoData->DriverType;
1720 DriverInfoDataW.Reserved = DriverInfoData->Reserved;
1721
1722 /* convert the strings to unicode */
1723 if (MultiByteToWideChar(CP_ACP,
1724 0,
1725 DriverInfoData->Description,
1726 LINE_LEN,
1727 DriverInfoDataW.Description,
1728 LINE_LEN) &&
1729 MultiByteToWideChar(CP_ACP,
1730 0,
1731 DriverInfoData->MfgName,
1732 LINE_LEN,
1733 DriverInfoDataW.MfgName,
1734 LINE_LEN) &&
1735 MultiByteToWideChar(CP_ACP,
1736 0,
1737 DriverInfoData->ProviderName,
1738 LINE_LEN,
1739 DriverInfoDataW.ProviderName,
1740 LINE_LEN))
1741 {
1742 if (DriverInfoDataW.cbSize == sizeof(SP_DRVINFO_DATA_V2_W))
1743 {
1744 DriverInfoDataW.DriverDate = ((PSP_DRVINFO_DATA_V2_A)DriverInfoData)->DriverDate;
1745 DriverInfoDataW.DriverVersion = ((PSP_DRVINFO_DATA_V2_A)DriverInfoData)->DriverVersion;
1746 }
1747
1748 if (DriverInfoDetailData != NULL)
1749 {
1750 /* calculate the unicode buffer size from the ansi buffer size */
1751 HardwareIDLen = DriverInfoDetailDataSize - FIELD_OFFSET(SP_DRVINFO_DETAIL_DATA_A, HardwareID);
1752 BufSize = FIELD_OFFSET(SP_DRVINFO_DETAIL_DATA_W, HardwareID) +
1753 (HardwareIDLen * sizeof(WCHAR));
1754
1755 DriverInfoDetailDataW = MyMalloc(BufSize);
1756 if (DriverInfoDetailDataW == NULL)
1757 {
1758 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1759 goto Cleanup;
1760 }
1761
1762 /* initialize the buffer */
1763 ZeroMemory(DriverInfoDetailDataW,
1764 BufSize);
1765 DriverInfoDetailDataW->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA_W);
1766 }
1767
1768 /* call the unicode version */
1769 ret = SetupDiGetDriverInfoDetailW(DeviceInfoSet,
1770 DeviceInfoData,
1771 &DriverInfoDataW,
1772 DriverInfoDetailDataW,
1773 BufSize,
1774 RequiredSize);
1775
1776 if (ret)
1777 {
1778 if (DriverInfoDetailDataW != NULL)
1779 {
1780 /* convert the SP_DRVINFO_DETAIL_DATA_W structure to ansi */
1781 DriverInfoDetailData->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA_A);
1782 DriverInfoDetailData->InfDate = DriverInfoDetailDataW->InfDate;
1783 DriverInfoDetailData->Reserved = DriverInfoDetailDataW->Reserved;
1784 if (WideCharToMultiByte(CP_ACP,
1785 0,
1786 DriverInfoDetailDataW->SectionName,
1787 LINE_LEN,
1788 DriverInfoDetailData->SectionName,
1789 LINE_LEN,
1790 NULL,
1791 NULL) &&
1792 WideCharToMultiByte(CP_ACP,
1793 0,
1794 DriverInfoDetailDataW->InfFileName,
1795 MAX_PATH,
1796 DriverInfoDetailData->InfFileName,
1797 MAX_PATH,
1798 NULL,
1799 NULL) &&
1800 WideCharToMultiByte(CP_ACP,
1801 0,
1802 DriverInfoDetailDataW->DrvDescription,
1803 LINE_LEN,
1804 DriverInfoDetailData->DrvDescription,
1805 LINE_LEN,
1806 NULL,
1807 NULL) &&
1808 WideCharToMultiByte(CP_ACP,
1809 0,
1810 DriverInfoDetailDataW->HardwareID,
1811 HardwareIDLen,
1812 DriverInfoDetailData->HardwareID,
1813 HardwareIDLen,
1814 NULL,
1815 NULL))
1816 {
1817 DWORD len, cnt = 0;
1818 DWORD hwidlen = HardwareIDLen;
1819 CHAR *s = DriverInfoDetailData->HardwareID;
1820
1821 /* count the strings in the list */
1822 while (*s != '\0')
1823 {
1824 len = lstrlenA(s) + 1;
1825 if (hwidlen > len)
1826 {
1827 cnt++;
1828 s += len;
1829 hwidlen -= len;
1830 }
1831 else
1832 {
1833 /* looks like the string list wasn't terminated... */
1834 SetLastError(ERROR_INVALID_USER_BUFFER);
1835 ret = FALSE;
1836 break;
1837 }
1838 }
1839
1840 /* make sure CompatIDsOffset points to the second string in the
1841 list, if present */
1842 if (cnt > 1)
1843 {
1844 DriverInfoDetailData->CompatIDsOffset = lstrlenA(DriverInfoDetailData->HardwareID) + 1;
1845 DriverInfoDetailData->CompatIDsLength = (DWORD)(s - DriverInfoDetailData->HardwareID) -
1846 DriverInfoDetailData->CompatIDsOffset + 1;
1847 }
1848 else
1849 {
1850 DriverInfoDetailData->CompatIDsOffset = 0;
1851 DriverInfoDetailData->CompatIDsLength = 0;
1852 }
1853 }
1854 else
1855 {
1856 ret = FALSE;
1857 }
1858 }
1859
1860 if (RequiredSize != NULL)
1861 {
1862 *RequiredSize = FIELD_OFFSET(SP_DRVINFO_DETAIL_DATA_A, HardwareID) +
1863 (((*RequiredSize) - FIELD_OFFSET(SP_DRVINFO_DETAIL_DATA_W, HardwareID)) / sizeof(WCHAR));
1864 }
1865 }
1866 }
1867
1868 Cleanup:
1869 if (DriverInfoDetailDataW != NULL)
1870 {
1871 MyFree(DriverInfoDetailDataW);
1872 }
1873
1874 return ret;
1875 }
1876
1877 /***********************************************************************
1878 * SetupDiGetDriverInfoDetailW (SETUPAPI.@)
1879 */
1880 BOOL WINAPI
1881 SetupDiGetDriverInfoDetailW(
1882 IN HDEVINFO DeviceInfoSet,
1883 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
1884 IN PSP_DRVINFO_DATA_W DriverInfoData,
1885 IN OUT PSP_DRVINFO_DETAIL_DATA_W DriverInfoDetailData OPTIONAL,
1886 IN DWORD DriverInfoDetailDataSize,
1887 OUT PDWORD RequiredSize OPTIONAL)
1888 {
1889 BOOL ret = FALSE;
1890
1891 TRACE("%p %p %p %p %lu %p\n", DeviceInfoSet, DeviceInfoData,
1892 DriverInfoData, DriverInfoDetailData,
1893 DriverInfoDetailDataSize, RequiredSize);
1894
1895 if (!DeviceInfoSet)
1896 SetLastError(ERROR_INVALID_PARAMETER);
1897 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
1898 SetLastError(ERROR_INVALID_HANDLE);
1899 else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
1900 SetLastError(ERROR_INVALID_HANDLE);
1901 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
1902 SetLastError(ERROR_INVALID_USER_BUFFER);
1903 else if (!DriverInfoData)
1904 SetLastError(ERROR_INVALID_PARAMETER);
1905 else if (!DriverInfoDetailData && DriverInfoDetailDataSize != 0)
1906 SetLastError(ERROR_INVALID_PARAMETER);
1907 else if (DriverInfoDetailData && DriverInfoDetailDataSize < sizeof(SP_DRVINFO_DETAIL_DATA_W))
1908 SetLastError(ERROR_INVALID_PARAMETER);
1909 else if (DriverInfoDetailData && DriverInfoDetailData->cbSize != sizeof(SP_DRVINFO_DETAIL_DATA_W))
1910 SetLastError(ERROR_INVALID_USER_BUFFER);
1911 else if (DriverInfoData->Reserved == 0)
1912 SetLastError(ERROR_NO_DRIVER_SELECTED);
1913 else
1914 {
1915 struct DriverInfoElement *driverInfoElement;
1916 LPWSTR HardwareIDs = NULL;
1917 LPWSTR CompatibleIDs = NULL;
1918 LPWSTR pBuffer = NULL;
1919 LPCWSTR DeviceID = NULL;
1920 ULONG HardwareIDsSize, CompatibleIDsSize;
1921 ULONG sizeNeeded, sizeLeft, size;
1922 BOOL Result;
1923
1924 driverInfoElement = (struct DriverInfoElement *)DriverInfoData->Reserved;
1925
1926 /* Get hardware and compatible IDs lists */
1927 Result = GetHardwareAndCompatibleIDsLists(
1928 DeviceInfoSet,
1929 DeviceInfoData,
1930 &HardwareIDs, &HardwareIDsSize,
1931 &CompatibleIDs, &CompatibleIDsSize);
1932 if (!Result)
1933 goto done;
1934
1935 sizeNeeded = FIELD_OFFSET(SP_DRVINFO_DETAIL_DATA_W, HardwareID)
1936 + HardwareIDsSize + CompatibleIDsSize;
1937 if (RequiredSize)
1938 *RequiredSize = sizeNeeded;
1939
1940 if (!DriverInfoDetailData)
1941 {
1942 ret = TRUE;
1943 goto done;
1944 }
1945
1946 memcpy(
1947 DriverInfoDetailData,
1948 &driverInfoElement->Details,
1949 driverInfoElement->Details.cbSize);
1950 DriverInfoDetailData->CompatIDsOffset = 0;
1951 DriverInfoDetailData->CompatIDsLength = 0;
1952
1953 sizeLeft = (DriverInfoDetailDataSize - FIELD_OFFSET(SP_DRVINFO_DETAIL_DATA_W, HardwareID)) / sizeof(WCHAR);
1954 pBuffer = DriverInfoDetailData->HardwareID;
1955 /* Add as many as possible HardwareIDs in the list */
1956 DeviceID = HardwareIDs;
1957 while (DeviceID && *DeviceID && (size = wcslen(DeviceID)) + 1 < sizeLeft)
1958 {
1959 TRACE("Adding %s to list\n", debugstr_w(DeviceID));
1960 wcscpy(pBuffer, DeviceID);
1961 DeviceID += size + 1;
1962 pBuffer += size + 1;
1963 sizeLeft -= size + 1;
1964 DriverInfoDetailData->CompatIDsOffset += size + 1;
1965 }
1966 if (sizeLeft > 0)
1967 {
1968 *pBuffer = UNICODE_NULL;
1969 sizeLeft--;
1970 DriverInfoDetailData->CompatIDsOffset++;
1971 }
1972 /* Add as many as possible CompatibleIDs in the list */
1973 DeviceID = CompatibleIDs;
1974 while (DeviceID && *DeviceID && (size = wcslen(DeviceID)) + 1 < sizeLeft)
1975 {
1976 TRACE("Adding %s to list\n", debugstr_w(DeviceID));
1977 wcscpy(pBuffer, DeviceID);
1978 DeviceID += size + 1;
1979 pBuffer += size + 1;
1980 sizeLeft -= size + 1;
1981 DriverInfoDetailData->CompatIDsLength += size + 1;
1982 }
1983 if (sizeLeft > 0)
1984 {
1985 *pBuffer = UNICODE_NULL;
1986 sizeLeft--;
1987 DriverInfoDetailData->CompatIDsLength++;
1988 }
1989
1990 if (sizeNeeded > DriverInfoDetailDataSize)
1991 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1992 else
1993 ret = TRUE;
1994
1995 done:
1996 MyFree(HardwareIDs);
1997 MyFree(CompatibleIDs);
1998 }
1999
2000 TRACE("Returning %d\n", ret);
2001 return ret;
2002 }
2003
2004 /***********************************************************************
2005 * SetupDiGetDriverInstallParamsW (SETUPAPI.@)
2006 */
2007 BOOL WINAPI
2008 SetupDiGetDriverInstallParamsW(
2009 IN HDEVINFO DeviceInfoSet,
2010 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
2011 IN PSP_DRVINFO_DATA_W DriverInfoData,
2012 OUT PSP_DRVINSTALL_PARAMS DriverInstallParams)
2013 {
2014 BOOL ret = FALSE;
2015
2016 TRACE("%p %p %p %p\n", DeviceInfoSet, DeviceInfoData, DriverInfoData, DriverInstallParams);
2017
2018 if (!DeviceInfoSet || !DriverInfoData || !DriverInstallParams)
2019 SetLastError(ERROR_INVALID_PARAMETER);
2020 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
2021 SetLastError(ERROR_INVALID_HANDLE);
2022 else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2023 SetLastError(ERROR_INVALID_HANDLE);
2024 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
2025 SetLastError(ERROR_INVALID_USER_BUFFER);
2026 else if (DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V1_W) && DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V2_W))
2027 SetLastError(ERROR_INVALID_USER_BUFFER);
2028 else if (DriverInstallParams->cbSize != sizeof(SP_DRVINSTALL_PARAMS))
2029 SetLastError(ERROR_INVALID_USER_BUFFER);
2030 else
2031 {
2032 SP_DEVINSTALL_PARAMS InstallParams;
2033
2034 InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
2035 if (SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams))
2036 {
2037 struct DriverInfoElement *driverInfo;
2038 driverInfo = (struct DriverInfoElement *)InstallParams.Reserved;
2039 if (driverInfo == NULL)
2040 SetLastError(ERROR_NO_DRIVER_SELECTED);
2041 else
2042 {
2043 memcpy(
2044 DriverInstallParams,
2045 &driverInfo->Params,
2046 DriverInstallParams->cbSize);
2047 ret = TRUE;
2048 }
2049 }
2050 }
2051
2052 TRACE("Returning %d\n", ret);
2053 return ret;
2054 }
2055
2056 /***********************************************************************
2057 * SetupDiSelectBestCompatDrv (SETUPAPI.@)
2058 */
2059 BOOL WINAPI
2060 SetupDiSelectBestCompatDrv(
2061 IN HDEVINFO DeviceInfoSet,
2062 IN OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
2063 {
2064 SP_DRVINFO_DATA_W drvInfoData;
2065 BOOL ret;
2066
2067 TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
2068
2069 /* Drivers are sorted by rank in the driver list, so
2070 * the first driver in the list is the best one.
2071 */
2072 drvInfoData.cbSize = sizeof(SP_DRVINFO_DATA_W);
2073 ret = SetupDiEnumDriverInfoW(
2074 DeviceInfoSet,
2075 DeviceInfoData,
2076 SPDIT_COMPATDRIVER,
2077 0, /* Member index */
2078 &drvInfoData);
2079
2080 if (ret)
2081 {
2082 ret = SetupDiSetSelectedDriverW(
2083 DeviceInfoSet,
2084 DeviceInfoData,
2085 &drvInfoData);
2086 }
2087
2088 TRACE("Returning %d\n", ret);
2089 return ret;
2090 }
2091
2092 /***********************************************************************
2093 * SetupDiInstallDriverFiles (SETUPAPI.@)
2094 */
2095 BOOL WINAPI
2096 SetupDiInstallDriverFiles(
2097 IN HDEVINFO DeviceInfoSet,
2098 IN PSP_DEVINFO_DATA DeviceInfoData)
2099 {
2100 BOOL ret = FALSE;
2101
2102 TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
2103
2104 if (!DeviceInfoSet)
2105 SetLastError(ERROR_INVALID_PARAMETER);
2106 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
2107 SetLastError(ERROR_INVALID_HANDLE);
2108 else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2109 SetLastError(ERROR_INVALID_HANDLE);
2110 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
2111 SetLastError(ERROR_INVALID_USER_BUFFER);
2112 else if (DeviceInfoData && ((struct DeviceInfo *)DeviceInfoData->Reserved)->InstallParams.Reserved == 0)
2113 SetLastError(ERROR_NO_DRIVER_SELECTED);
2114 else if (!DeviceInfoData && ((struct DeviceInfoSet *)DeviceInfoSet)->InstallParams.Reserved == 0)
2115 SetLastError(ERROR_NO_DRIVER_SELECTED);
2116 else
2117 {
2118 SP_DEVINSTALL_PARAMS_W InstallParams;
2119 struct DriverInfoElement *SelectedDriver;
2120 WCHAR SectionName[MAX_PATH];
2121 DWORD SectionNameLength = 0;
2122 PVOID InstallMsgHandler;
2123 PVOID InstallMsgHandlerContext;
2124 PVOID Context = NULL;
2125
2126 InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
2127 ret = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
2128 if (!ret)
2129 goto done;
2130
2131 SelectedDriver = (struct DriverInfoElement *)InstallParams.Reserved;
2132 if (!SelectedDriver)
2133 {
2134 SetLastError(ERROR_NO_DRIVER_SELECTED);
2135 goto done;
2136 }
2137
2138 ret = SetupDiGetActualSectionToInstallW(
2139 SelectedDriver->InfFileDetails->hInf,
2140 SelectedDriver->Details.SectionName,
2141 SectionName, MAX_PATH - strlenW(DotCoInstallers), &SectionNameLength, NULL);
2142 if (!ret)
2143 goto done;
2144
2145 if (InstallParams.InstallMsgHandler)
2146 {
2147 InstallMsgHandler = InstallParams.InstallMsgHandler;
2148 InstallMsgHandlerContext = InstallParams.InstallMsgHandlerContext;
2149 }
2150 else
2151 {
2152 Context = SetupInitDefaultQueueCallback(InstallParams.hwndParent);
2153 if (!Context)
2154 goto cleanup;
2155 InstallMsgHandler = SetupDefaultQueueCallbackW;
2156 InstallMsgHandlerContext = Context;
2157 }
2158 ret = SetupInstallFromInfSectionW(InstallParams.hwndParent,
2159 SelectedDriver->InfFileDetails->hInf, SectionName,
2160 SPINST_FILES, NULL, SelectedDriver->InfFileDetails->DirectoryName, SP_COPY_NEWER,
2161 InstallMsgHandler, InstallMsgHandlerContext,
2162 DeviceInfoSet, DeviceInfoData);
2163 if (!ret)
2164 goto done;
2165
2166 /* Install files from .CoInstallers section */
2167 lstrcatW(SectionName, DotCoInstallers);
2168 ret = SetupInstallFromInfSectionW(InstallParams.hwndParent,
2169 SelectedDriver->InfFileDetails->hInf, SectionName,
2170 SPINST_FILES, NULL, SelectedDriver->InfFileDetails->DirectoryName, SP_COPY_NEWER,
2171 InstallMsgHandler, InstallMsgHandlerContext,
2172 DeviceInfoSet, DeviceInfoData);
2173 if (!ret)
2174 goto done;
2175
2176 /* Set the DI_NOFILECOPY flag to prevent another
2177 * installation during SetupDiInstallDevice */
2178 InstallParams.Flags |= DI_NOFILECOPY;
2179 ret = SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
2180
2181 cleanup:
2182 if (Context)
2183 SetupTermDefaultQueueCallback(Context);
2184 }
2185
2186 done:
2187 TRACE("Returning %d\n", ret);
2188 return ret;
2189 }