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