356a95c08dbf073c5ffcf14a0bef718571c52839
[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 if (HardwareIDs)
1113 {
1114 for (DriverRank = 0, currentId = (LPCWSTR)HardwareIDs; !DriverAlreadyAdded && *currentId; currentId += strlenW(currentId) + 1, DriverRank++)
1115 {
1116 if (strcmpiW(DeviceId, currentId) == 0)
1117 {
1118 AddDriverToList(
1119 pDriverListHead,
1120 DriverType,
1121 &ClassGuid,
1122 ContextDevice,
1123 currentInfFileDetails,
1124 FullInfFileName,
1125 ProviderName,
1126 ManufacturerName,
1127 currentId,
1128 DriverDate, DriverVersion,
1129 DriverRank + (i == 2 ? 0 : 0x1000 + i - 3));
1130 DriverAlreadyAdded = TRUE;
1131 }
1132 }
1133 }
1134 if (CompatibleIDs)
1135 {
1136 for (DriverRank = 0, currentId = (LPCWSTR)CompatibleIDs; !DriverAlreadyAdded && *currentId; currentId += strlenW(currentId) + 1, DriverRank++)
1137 {
1138 if (strcmpiW(DeviceId, currentId) == 0)
1139 {
1140 AddDriverToList(
1141 pDriverListHead,
1142 DriverType,
1143 &ClassGuid,
1144 ContextDevice,
1145 currentInfFileDetails,
1146 FullInfFileName,
1147 ProviderName,
1148 ManufacturerName,
1149 currentId,
1150 DriverDate, DriverVersion,
1151 DriverRank + (i == 2 ? 0x2000 : 0x3000 + i - 3));
1152 DriverAlreadyAdded = TRUE;
1153 }
1154 }
1155 }
1156 HeapFree(GetProcessHeap(), 0, DeviceId);
1157 }
1158 }
1159 Result = SetupFindNextLine(&ContextDevice, &ContextDevice);
1160 }
1161
1162 HeapFree(GetProcessHeap(), 0, ManufacturerName);
1163 ManufacturerName = NULL;
1164 Result = SetupFindNextLine(&ContextManufacturer, &ContextManufacturer);
1165 }
1166
1167 ret = TRUE;
1168 next:
1169 HeapFree(GetProcessHeap(), 0, ProviderName);
1170 HeapFree(GetProcessHeap(), 0, ExcludeFromSelect);
1171 ProviderName = ExcludeFromSelect = NULL;
1172
1173 DereferenceInfFile(currentInfFileDetails);
1174 currentInfFileDetails = NULL;
1175 }
1176 ret = TRUE;
1177 }
1178 }
1179
1180 done:
1181 if (ret)
1182 {
1183 if (DeviceInfoData)
1184 {
1185 InstallParams.Flags |= DI_DIDCOMPAT;
1186 InstallParams.FlagsEx |= DI_FLAGSEX_DIDCOMPATINFO;
1187 }
1188 else
1189 {
1190 InstallParams.Flags |= DI_DIDCLASS;
1191 InstallParams.FlagsEx |= DI_FLAGSEX_DIDINFOLIST;
1192 }
1193 ret = SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
1194 }
1195
1196 HeapFree(GetProcessHeap(), 0, ProviderName);
1197 HeapFree(GetProcessHeap(), 0, ManufacturerName);
1198 MyFree(HardwareIDs);
1199 MyFree(CompatibleIDs);
1200 HeapFree(GetProcessHeap(), 0, FullInfFileName);
1201 HeapFree(GetProcessHeap(), 0, ExcludeFromSelect);
1202 if (currentInfFileDetails)
1203 DereferenceInfFile(currentInfFileDetails);
1204 HeapFree(GetProcessHeap(), 0, Buffer);
1205
1206 TRACE("Returning %d\n", ret);
1207 return ret;
1208 }
1209
1210 /***********************************************************************
1211 * SetupDiDestroyDriverInfoList (SETUPAPI.@)
1212 */
1213 BOOL WINAPI
1214 SetupDiDestroyDriverInfoList(
1215 IN HDEVINFO DeviceInfoSet,
1216 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
1217 IN DWORD DriverType)
1218 {
1219 struct DeviceInfoSet *list;
1220 BOOL ret = FALSE;
1221
1222 TRACE("%p %p 0x%lx\n", DeviceInfoSet, DeviceInfoData, DriverType);
1223
1224 if (!DeviceInfoSet)
1225 SetLastError(ERROR_INVALID_HANDLE);
1226 else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
1227 SetLastError(ERROR_INVALID_HANDLE);
1228 else if (DriverType != SPDIT_CLASSDRIVER && DriverType != SPDIT_COMPATDRIVER)
1229 SetLastError(ERROR_INVALID_PARAMETER);
1230 else if (DriverType == SPDIT_COMPATDRIVER && !DeviceInfoData)
1231 SetLastError(ERROR_INVALID_PARAMETER);
1232 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
1233 SetLastError(ERROR_INVALID_USER_BUFFER);
1234 else
1235 {
1236 PLIST_ENTRY ListEntry;
1237 struct DriverInfoElement *driverInfo;
1238 SP_DEVINSTALL_PARAMS_W InstallParams;
1239
1240 InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
1241 if (!SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams))
1242 goto done;
1243
1244 if (!DeviceInfoData)
1245 /* Fall back to destroying class driver list */
1246 DriverType = SPDIT_CLASSDRIVER;
1247
1248 if (DriverType == SPDIT_CLASSDRIVER)
1249 {
1250 while (!IsListEmpty(&list->DriverListHead))
1251 {
1252 ListEntry = RemoveHeadList(&list->DriverListHead);
1253 driverInfo = CONTAINING_RECORD(ListEntry, struct DriverInfoElement, ListEntry);
1254 DestroyDriverInfoElement(driverInfo);
1255 }
1256 InstallParams.Reserved = 0;
1257 InstallParams.Flags &= ~(DI_DIDCLASS | DI_MULTMFGS);
1258 InstallParams.FlagsEx &= ~DI_FLAGSEX_DIDINFOLIST;
1259 ret = SetupDiSetDeviceInstallParamsW(DeviceInfoSet, NULL, &InstallParams);
1260 }
1261 else
1262 {
1263 SP_DEVINSTALL_PARAMS_W InstallParamsSet;
1264 struct DeviceInfo *deviceInfo;
1265
1266 InstallParamsSet.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
1267 if (!SetupDiGetDeviceInstallParamsW(DeviceInfoSet, NULL, &InstallParamsSet))
1268 goto done;
1269 deviceInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
1270 while (!IsListEmpty(&deviceInfo->DriverListHead))
1271 {
1272 ListEntry = RemoveHeadList(&deviceInfo->DriverListHead);
1273 driverInfo = CONTAINING_RECORD(ListEntry, struct DriverInfoElement, ListEntry);
1274 if ((PVOID)InstallParamsSet.Reserved == driverInfo)
1275 {
1276 InstallParamsSet.Reserved = 0;
1277 SetupDiSetDeviceInstallParamsW(DeviceInfoSet, NULL, &InstallParamsSet);
1278 }
1279 DestroyDriverInfoElement(driverInfo);
1280 }
1281 InstallParams.Reserved = 0;
1282 InstallParams.Flags &= ~DI_DIDCOMPAT;
1283 InstallParams.FlagsEx &= ~DI_FLAGSEX_DIDCOMPATINFO;
1284 ret = SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
1285 }
1286 }
1287
1288 done:
1289 TRACE("Returning %d\n", ret);
1290 return ret;
1291 }
1292
1293 /***********************************************************************
1294 * SetupDiEnumDriverInfoA (SETUPAPI.@)
1295 */
1296 BOOL WINAPI
1297 SetupDiEnumDriverInfoA(
1298 IN HDEVINFO DeviceInfoSet,
1299 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
1300 IN DWORD DriverType,
1301 IN DWORD MemberIndex,
1302 OUT PSP_DRVINFO_DATA_A DriverInfoData)
1303 {
1304 SP_DRVINFO_DATA_V2_W driverInfoData2W;
1305 BOOL ret = FALSE;
1306
1307 TRACE("%p %p 0x%lx %ld %p\n", DeviceInfoSet, DeviceInfoData,
1308 DriverType, MemberIndex, DriverInfoData);
1309
1310 if (DriverInfoData == NULL)
1311 SetLastError(ERROR_INVALID_PARAMETER);
1312 else if (DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V1_A) && DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V2_A))
1313 SetLastError(ERROR_INVALID_USER_BUFFER);
1314 else
1315 {
1316 driverInfoData2W.cbSize = sizeof(SP_DRVINFO_DATA_V2_W);
1317 ret = SetupDiEnumDriverInfoW(DeviceInfoSet, DeviceInfoData,
1318 DriverType, MemberIndex, &driverInfoData2W);
1319
1320 if (ret)
1321 {
1322 /* Do W->A conversion */
1323 DriverInfoData->DriverType = driverInfoData2W.DriverType;
1324 DriverInfoData->Reserved = driverInfoData2W.Reserved;
1325 if (WideCharToMultiByte(CP_ACP, 0, driverInfoData2W.Description, -1,
1326 DriverInfoData->Description, LINE_LEN, NULL, NULL) == 0)
1327 {
1328 DriverInfoData->Description[0] = '\0';
1329 ret = FALSE;
1330 }
1331 if (WideCharToMultiByte(CP_ACP, 0, driverInfoData2W.MfgName, -1,
1332 DriverInfoData->MfgName, LINE_LEN, NULL, NULL) == 0)
1333 {
1334 DriverInfoData->MfgName[0] = '\0';
1335 ret = FALSE;
1336 }
1337 if (WideCharToMultiByte(CP_ACP, 0, driverInfoData2W.ProviderName, -1,
1338 DriverInfoData->ProviderName, LINE_LEN, NULL, NULL) == 0)
1339 {
1340 DriverInfoData->ProviderName[0] = '\0';
1341 ret = FALSE;
1342 }
1343 if (DriverInfoData->cbSize == sizeof(SP_DRVINFO_DATA_V2_A))
1344 {
1345 /* Copy more fields */
1346 DriverInfoData->DriverDate = driverInfoData2W.DriverDate;
1347 DriverInfoData->DriverVersion = driverInfoData2W.DriverVersion;
1348 }
1349 }
1350 }
1351
1352 TRACE("Returning %d\n", ret);
1353 return ret;
1354 }
1355
1356
1357 /***********************************************************************
1358 * SetupDiEnumDriverInfoW (SETUPAPI.@)
1359 */
1360 BOOL WINAPI
1361 SetupDiEnumDriverInfoW(
1362 IN HDEVINFO DeviceInfoSet,
1363 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
1364 IN DWORD DriverType,
1365 IN DWORD MemberIndex,
1366 OUT PSP_DRVINFO_DATA_W DriverInfoData)
1367 {
1368 PLIST_ENTRY ListHead;
1369 BOOL ret = FALSE;
1370
1371 TRACE("%p %p 0x%lx %ld %p\n", DeviceInfoSet, DeviceInfoData,
1372 DriverType, MemberIndex, DriverInfoData);
1373
1374 if (!DeviceInfoSet || !DriverInfoData)
1375 SetLastError(ERROR_INVALID_PARAMETER);
1376 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
1377 SetLastError(ERROR_INVALID_HANDLE);
1378 else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
1379 SetLastError(ERROR_INVALID_HANDLE);
1380 else if (DriverType != SPDIT_CLASSDRIVER && DriverType != SPDIT_COMPATDRIVER)
1381 SetLastError(ERROR_INVALID_PARAMETER);
1382 else if (DriverType == SPDIT_COMPATDRIVER && !DeviceInfoData)
1383 SetLastError(ERROR_INVALID_PARAMETER);
1384 else if (DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V1_W) && DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V2_W))
1385 SetLastError(ERROR_INVALID_USER_BUFFER);
1386 else
1387 {
1388 struct DeviceInfo *devInfo = NULL;
1389 PLIST_ENTRY ItemList;
1390 if (DeviceInfoData)
1391 devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
1392 if (!devInfo || (devInfo->CreationFlags & DICD_INHERIT_CLASSDRVS))
1393 {
1394 ListHead = &((struct DeviceInfoSet *)DeviceInfoSet)->DriverListHead;
1395 }
1396 else
1397 {
1398 ListHead = &devInfo->DriverListHead;
1399 }
1400
1401 ItemList = ListHead->Flink;
1402 while (ItemList != ListHead && MemberIndex-- > 0)
1403 ItemList = ItemList->Flink;
1404 if (ItemList == ListHead)
1405 SetLastError(ERROR_NO_MORE_ITEMS);
1406 else
1407 {
1408 struct DriverInfoElement *DrvInfo = CONTAINING_RECORD(ItemList, struct DriverInfoElement, ListEntry);
1409
1410 memcpy(
1411 &DriverInfoData->DriverType,
1412 &DrvInfo->Info.DriverType,
1413 DriverInfoData->cbSize - FIELD_OFFSET(SP_DRVINFO_DATA_W, DriverType));
1414 ret = TRUE;
1415 }
1416 }
1417
1418 TRACE("Returning %d\n", ret);
1419 return ret;
1420 }
1421
1422 /***********************************************************************
1423 * SetupDiGetSelectedDriverA (SETUPAPI.@)
1424 */
1425 BOOL WINAPI
1426 SetupDiGetSelectedDriverA(
1427 IN HDEVINFO DeviceInfoSet,
1428 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
1429 OUT PSP_DRVINFO_DATA_A DriverInfoData)
1430 {
1431 SP_DRVINFO_DATA_V2_W driverInfoData2W;
1432 BOOL ret = FALSE;
1433
1434 if (DriverInfoData == NULL)
1435 SetLastError(ERROR_INVALID_PARAMETER);
1436 else if (DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V1_A) && DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V2_A))
1437 SetLastError(ERROR_INVALID_USER_BUFFER);
1438 else
1439 {
1440 driverInfoData2W.cbSize = sizeof(SP_DRVINFO_DATA_V2_W);
1441
1442 ret = SetupDiGetSelectedDriverW(DeviceInfoSet,
1443 DeviceInfoData,
1444 &driverInfoData2W);
1445
1446 if (ret)
1447 {
1448 /* Do W->A conversion */
1449 DriverInfoData->DriverType = driverInfoData2W.DriverType;
1450 DriverInfoData->Reserved = driverInfoData2W.Reserved;
1451 if (WideCharToMultiByte(CP_ACP, 0, driverInfoData2W.Description, -1,
1452 DriverInfoData->Description, LINE_LEN, NULL, NULL) == 0)
1453 {
1454 DriverInfoData->Description[0] = '\0';
1455 ret = FALSE;
1456 }
1457 if (WideCharToMultiByte(CP_ACP, 0, driverInfoData2W.MfgName, -1,
1458 DriverInfoData->MfgName, LINE_LEN, NULL, NULL) == 0)
1459 {
1460 DriverInfoData->MfgName[0] = '\0';
1461 ret = FALSE;
1462 }
1463 if (WideCharToMultiByte(CP_ACP, 0, driverInfoData2W.ProviderName, -1,
1464 DriverInfoData->ProviderName, LINE_LEN, NULL, NULL) == 0)
1465 {
1466 DriverInfoData->ProviderName[0] = '\0';
1467 ret = FALSE;
1468 }
1469 if (DriverInfoData->cbSize == sizeof(SP_DRVINFO_DATA_V2_A))
1470 {
1471 /* Copy more fields */
1472 DriverInfoData->DriverDate = driverInfoData2W.DriverDate;
1473 DriverInfoData->DriverVersion = driverInfoData2W.DriverVersion;
1474 }
1475 }
1476 }
1477
1478 return ret;
1479 }
1480
1481 /***********************************************************************
1482 * SetupDiGetSelectedDriverW (SETUPAPI.@)
1483 */
1484 BOOL WINAPI
1485 SetupDiGetSelectedDriverW(
1486 IN HDEVINFO DeviceInfoSet,
1487 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
1488 OUT PSP_DRVINFO_DATA_W DriverInfoData)
1489 {
1490 BOOL ret = FALSE;
1491
1492 TRACE("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DriverInfoData);
1493
1494 if (!DeviceInfoSet || !DriverInfoData)
1495 SetLastError(ERROR_INVALID_PARAMETER);
1496 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
1497 SetLastError(ERROR_INVALID_HANDLE);
1498 else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
1499 SetLastError(ERROR_INVALID_HANDLE);
1500 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
1501 SetLastError(ERROR_INVALID_USER_BUFFER);
1502 else if (DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V1_W) && DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V2_W))
1503 SetLastError(ERROR_INVALID_USER_BUFFER);
1504 else
1505 {
1506 SP_DEVINSTALL_PARAMS InstallParams;
1507
1508 InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
1509 if (SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams))
1510 {
1511 struct DriverInfoElement *driverInfo;
1512 driverInfo = (struct DriverInfoElement *)InstallParams.Reserved;
1513 if (driverInfo == NULL)
1514 SetLastError(ERROR_NO_DRIVER_SELECTED);
1515 else
1516 {
1517 memcpy(
1518 &DriverInfoData->DriverType,
1519 &driverInfo->Info.DriverType,
1520 DriverInfoData->cbSize - FIELD_OFFSET(SP_DRVINFO_DATA_W, DriverType));
1521 ret = TRUE;
1522 }
1523 }
1524 }
1525
1526 TRACE("Returning %d\n", ret);
1527 return ret;
1528 }
1529
1530 /***********************************************************************
1531 * SetupDiSetSelectedDriverA (SETUPAPI.@)
1532 */
1533 BOOL WINAPI
1534 SetupDiSetSelectedDriverA(
1535 IN HDEVINFO DeviceInfoSet,
1536 IN OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
1537 IN OUT PSP_DRVINFO_DATA_A DriverInfoData OPTIONAL)
1538 {
1539 SP_DRVINFO_DATA_V1_W DriverInfoDataW;
1540 PSP_DRVINFO_DATA_W pDriverInfoDataW = NULL;
1541 BOOL ret = FALSE;
1542
1543 if (DriverInfoData != NULL)
1544 {
1545 if (DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V2_A) &&
1546 DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V1_A))
1547 {
1548 SetLastError(ERROR_INVALID_PARAMETER);
1549 return FALSE;
1550 }
1551
1552 DriverInfoDataW.cbSize = sizeof(SP_DRVINFO_DATA_V1_W);
1553 DriverInfoDataW.Reserved = DriverInfoData->Reserved;
1554
1555 if (DriverInfoDataW.Reserved == 0)
1556 {
1557 DriverInfoDataW.DriverType = DriverInfoData->DriverType;
1558
1559 /* convert the strings to unicode */
1560 if (!MultiByteToWideChar(CP_ACP,
1561 0,
1562 DriverInfoData->Description,
1563 LINE_LEN,
1564 DriverInfoDataW.Description,
1565 LINE_LEN) ||
1566 !MultiByteToWideChar(CP_ACP,
1567 0,
1568 DriverInfoData->ProviderName,
1569 LINE_LEN,
1570 DriverInfoDataW.ProviderName,
1571 LINE_LEN))
1572 {
1573 return FALSE;
1574 }
1575 }
1576
1577 pDriverInfoDataW = (PSP_DRVINFO_DATA_W)&DriverInfoDataW;
1578 }
1579
1580 ret = SetupDiSetSelectedDriverW(DeviceInfoSet,
1581 DeviceInfoData,
1582 pDriverInfoDataW);
1583
1584 if (ret && pDriverInfoDataW != NULL)
1585 {
1586 DriverInfoData->Reserved = DriverInfoDataW.Reserved;
1587 }
1588
1589 return ret;
1590 }
1591
1592 /***********************************************************************
1593 * SetupDiSetSelectedDriverW (SETUPAPI.@)
1594 */
1595 BOOL WINAPI
1596 SetupDiSetSelectedDriverW(
1597 IN HDEVINFO DeviceInfoSet,
1598 IN OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
1599 IN OUT PSP_DRVINFO_DATA_W DriverInfoData OPTIONAL)
1600 {
1601 BOOL ret = FALSE;
1602
1603 TRACE("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DriverInfoData);
1604
1605 if (!DeviceInfoSet)
1606 SetLastError(ERROR_INVALID_PARAMETER);
1607 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
1608 SetLastError(ERROR_INVALID_HANDLE);
1609 else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
1610 SetLastError(ERROR_INVALID_HANDLE);
1611 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
1612 SetLastError(ERROR_INVALID_USER_BUFFER);
1613 else if (DriverInfoData && DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V1_W) && DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V2_W))
1614 SetLastError(ERROR_INVALID_USER_BUFFER);
1615 else
1616 {
1617 struct DriverInfoElement **pDriverInfo;
1618 PLIST_ENTRY ListHead, ItemList;
1619
1620 if (DeviceInfoData)
1621 {
1622 pDriverInfo = (struct DriverInfoElement **)&((struct DeviceInfo *)DeviceInfoData->Reserved)->InstallParams.Reserved;
1623 ListHead = &((struct DeviceInfo *)DeviceInfoData->Reserved)->DriverListHead;
1624 }
1625 else
1626 {
1627 pDriverInfo = (struct DriverInfoElement **)&((struct DeviceInfoSet *)DeviceInfoSet)->InstallParams.Reserved;
1628 ListHead = &((struct DeviceInfoSet *)DeviceInfoSet)->DriverListHead;
1629 }
1630
1631 if (!DriverInfoData)
1632 {
1633 *pDriverInfo = NULL;
1634 ret = TRUE;
1635 }
1636 else
1637 {
1638 /* Search selected driver in list */
1639 ItemList = ListHead->Flink;
1640 while (ItemList != ListHead)
1641 {
1642 if (DriverInfoData->Reserved != 0)
1643 {
1644 if (DriverInfoData->Reserved == (ULONG_PTR)ItemList)
1645 break;
1646 }
1647 else
1648 {
1649 /* The caller wants to compare only DriverType, Description and ProviderName fields */
1650 struct DriverInfoElement *driverInfo = CONTAINING_RECORD(ItemList, struct DriverInfoElement, ListEntry);
1651 if (driverInfo->Info.DriverType == DriverInfoData->DriverType
1652 && strcmpW(driverInfo->Info.Description, DriverInfoData->Description) == 0
1653 && strcmpW(driverInfo->Info.ProviderName, DriverInfoData->ProviderName) == 0)
1654 {
1655 break;
1656 }
1657 }
1658 ItemList = ItemList->Flink;
1659 }
1660 if (ItemList == ListHead)
1661 SetLastError(ERROR_INVALID_PARAMETER);
1662 else
1663 {
1664 *pDriverInfo = CONTAINING_RECORD(ItemList, struct DriverInfoElement, ListEntry);
1665 DriverInfoData->Reserved = (ULONG_PTR)ItemList;
1666 ret = TRUE;
1667 TRACE("Choosing driver whose rank is 0x%lx\n",
1668 (*pDriverInfo)->Params.Rank);
1669 if (DeviceInfoData)
1670 memcpy(&DeviceInfoData->ClassGuid, &(*pDriverInfo)->ClassGuid, sizeof(GUID));
1671 }
1672 }
1673 }
1674
1675 TRACE("Returning %d\n", ret);
1676 return ret;
1677 }
1678
1679 /***********************************************************************
1680 * SetupDiGetDriverInfoDetailA (SETUPAPI.@)
1681 */
1682 BOOL WINAPI
1683 SetupDiGetDriverInfoDetailA(
1684 IN HDEVINFO DeviceInfoSet,
1685 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
1686 IN PSP_DRVINFO_DATA_A DriverInfoData,
1687 IN OUT PSP_DRVINFO_DETAIL_DATA_A DriverInfoDetailData OPTIONAL,
1688 IN DWORD DriverInfoDetailDataSize,
1689 OUT PDWORD RequiredSize OPTIONAL)
1690 {
1691 SP_DRVINFO_DATA_V2_W DriverInfoDataW;
1692 PSP_DRVINFO_DETAIL_DATA_W DriverInfoDetailDataW = NULL;
1693 DWORD BufSize = 0;
1694 DWORD HardwareIDLen = 0;
1695 BOOL ret = FALSE;
1696
1697 /* do some sanity checks, the unicode version might do more thorough checks */
1698 if (DriverInfoData == NULL ||
1699 (DriverInfoDetailData == NULL && DriverInfoDetailDataSize != 0) ||
1700 (DriverInfoDetailData != NULL &&
1701 (DriverInfoDetailDataSize < FIELD_OFFSET(SP_DRVINFO_DETAIL_DATA_A, HardwareID) + sizeof(CHAR) ||
1702 DriverInfoDetailData->cbSize != sizeof(SP_DRVINFO_DETAIL_DATA_A))))
1703 {
1704 SetLastError(ERROR_INVALID_PARAMETER);
1705 goto Cleanup;
1706 }
1707
1708 /* make sure we support both versions of the SP_DRVINFO_DATA structure */
1709 if (DriverInfoData->cbSize == sizeof(SP_DRVINFO_DATA_V1_A))
1710 {
1711 DriverInfoDataW.cbSize = sizeof(SP_DRVINFO_DATA_V1_W);
1712 }
1713 else if (DriverInfoData->cbSize == sizeof(SP_DRVINFO_DATA_V2_A))
1714 {
1715 DriverInfoDataW.cbSize = sizeof(SP_DRVINFO_DATA_V2_W);
1716 }
1717 else
1718 {
1719 SetLastError(ERROR_INVALID_PARAMETER);
1720 goto Cleanup;
1721 }
1722 DriverInfoDataW.DriverType = DriverInfoData->DriverType;
1723 DriverInfoDataW.Reserved = DriverInfoData->Reserved;
1724
1725 /* convert the strings to unicode */
1726 if (MultiByteToWideChar(CP_ACP,
1727 0,
1728 DriverInfoData->Description,
1729 LINE_LEN,
1730 DriverInfoDataW.Description,
1731 LINE_LEN) &&
1732 MultiByteToWideChar(CP_ACP,
1733 0,
1734 DriverInfoData->MfgName,
1735 LINE_LEN,
1736 DriverInfoDataW.MfgName,
1737 LINE_LEN) &&
1738 MultiByteToWideChar(CP_ACP,
1739 0,
1740 DriverInfoData->ProviderName,
1741 LINE_LEN,
1742 DriverInfoDataW.ProviderName,
1743 LINE_LEN))
1744 {
1745 if (DriverInfoDataW.cbSize == sizeof(SP_DRVINFO_DATA_V2_W))
1746 {
1747 DriverInfoDataW.DriverDate = ((PSP_DRVINFO_DATA_V2_A)DriverInfoData)->DriverDate;
1748 DriverInfoDataW.DriverVersion = ((PSP_DRVINFO_DATA_V2_A)DriverInfoData)->DriverVersion;
1749 }
1750
1751 if (DriverInfoDetailData != NULL)
1752 {
1753 /* calculate the unicode buffer size from the ansi buffer size */
1754 HardwareIDLen = DriverInfoDetailDataSize - FIELD_OFFSET(SP_DRVINFO_DETAIL_DATA_A, HardwareID);
1755 BufSize = FIELD_OFFSET(SP_DRVINFO_DETAIL_DATA_W, HardwareID) +
1756 (HardwareIDLen * sizeof(WCHAR));
1757
1758 DriverInfoDetailDataW = MyMalloc(BufSize);
1759 if (DriverInfoDetailDataW == NULL)
1760 {
1761 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1762 goto Cleanup;
1763 }
1764
1765 /* initialize the buffer */
1766 ZeroMemory(DriverInfoDetailDataW,
1767 BufSize);
1768 DriverInfoDetailDataW->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA_W);
1769 }
1770
1771 /* call the unicode version */
1772 ret = SetupDiGetDriverInfoDetailW(DeviceInfoSet,
1773 DeviceInfoData,
1774 &DriverInfoDataW,
1775 DriverInfoDetailDataW,
1776 BufSize,
1777 RequiredSize);
1778
1779 if (ret)
1780 {
1781 if (DriverInfoDetailDataW != NULL)
1782 {
1783 /* convert the SP_DRVINFO_DETAIL_DATA_W structure to ansi */
1784 DriverInfoDetailData->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA_A);
1785 DriverInfoDetailData->InfDate = DriverInfoDetailDataW->InfDate;
1786 DriverInfoDetailData->Reserved = DriverInfoDetailDataW->Reserved;
1787 if (WideCharToMultiByte(CP_ACP,
1788 0,
1789 DriverInfoDetailDataW->SectionName,
1790 LINE_LEN,
1791 DriverInfoDetailData->SectionName,
1792 LINE_LEN,
1793 NULL,
1794 NULL) &&
1795 WideCharToMultiByte(CP_ACP,
1796 0,
1797 DriverInfoDetailDataW->InfFileName,
1798 MAX_PATH,
1799 DriverInfoDetailData->InfFileName,
1800 MAX_PATH,
1801 NULL,
1802 NULL) &&
1803 WideCharToMultiByte(CP_ACP,
1804 0,
1805 DriverInfoDetailDataW->DrvDescription,
1806 LINE_LEN,
1807 DriverInfoDetailData->DrvDescription,
1808 LINE_LEN,
1809 NULL,
1810 NULL) &&
1811 WideCharToMultiByte(CP_ACP,
1812 0,
1813 DriverInfoDetailDataW->HardwareID,
1814 HardwareIDLen,
1815 DriverInfoDetailData->HardwareID,
1816 HardwareIDLen,
1817 NULL,
1818 NULL))
1819 {
1820 DWORD len, cnt = 0;
1821 DWORD hwidlen = HardwareIDLen;
1822 CHAR *s = DriverInfoDetailData->HardwareID;
1823
1824 /* count the strings in the list */
1825 while (*s != '\0')
1826 {
1827 len = lstrlenA(s) + 1;
1828 if (hwidlen > len)
1829 {
1830 cnt++;
1831 s += len;
1832 hwidlen -= len;
1833 }
1834 else
1835 {
1836 /* looks like the string list wasn't terminated... */
1837 SetLastError(ERROR_INVALID_USER_BUFFER);
1838 ret = FALSE;
1839 break;
1840 }
1841 }
1842
1843 /* make sure CompatIDsOffset points to the second string in the
1844 list, if present */
1845 if (cnt > 1)
1846 {
1847 DriverInfoDetailData->CompatIDsOffset = lstrlenA(DriverInfoDetailData->HardwareID) + 1;
1848 DriverInfoDetailData->CompatIDsLength = (DWORD)(s - DriverInfoDetailData->HardwareID) -
1849 DriverInfoDetailData->CompatIDsOffset + 1;
1850 }
1851 else
1852 {
1853 DriverInfoDetailData->CompatIDsOffset = 0;
1854 DriverInfoDetailData->CompatIDsLength = 0;
1855 }
1856 }
1857 else
1858 {
1859 ret = FALSE;
1860 }
1861 }
1862
1863 if (RequiredSize != NULL)
1864 {
1865 *RequiredSize = FIELD_OFFSET(SP_DRVINFO_DETAIL_DATA_A, HardwareID) +
1866 (((*RequiredSize) - FIELD_OFFSET(SP_DRVINFO_DETAIL_DATA_W, HardwareID)) / sizeof(WCHAR));
1867 }
1868 }
1869 }
1870
1871 Cleanup:
1872 if (DriverInfoDetailDataW != NULL)
1873 {
1874 MyFree(DriverInfoDetailDataW);
1875 }
1876
1877 return ret;
1878 }
1879
1880 /***********************************************************************
1881 * SetupDiGetDriverInfoDetailW (SETUPAPI.@)
1882 */
1883 BOOL WINAPI
1884 SetupDiGetDriverInfoDetailW(
1885 IN HDEVINFO DeviceInfoSet,
1886 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
1887 IN PSP_DRVINFO_DATA_W DriverInfoData,
1888 IN OUT PSP_DRVINFO_DETAIL_DATA_W DriverInfoDetailData OPTIONAL,
1889 IN DWORD DriverInfoDetailDataSize,
1890 OUT PDWORD RequiredSize OPTIONAL)
1891 {
1892 BOOL ret = FALSE;
1893
1894 TRACE("%p %p %p %p %lu %p\n", DeviceInfoSet, DeviceInfoData,
1895 DriverInfoData, DriverInfoDetailData,
1896 DriverInfoDetailDataSize, RequiredSize);
1897
1898 if (!DeviceInfoSet)
1899 SetLastError(ERROR_INVALID_PARAMETER);
1900 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
1901 SetLastError(ERROR_INVALID_HANDLE);
1902 else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
1903 SetLastError(ERROR_INVALID_HANDLE);
1904 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
1905 SetLastError(ERROR_INVALID_USER_BUFFER);
1906 else if (!DriverInfoData)
1907 SetLastError(ERROR_INVALID_PARAMETER);
1908 else if (!DriverInfoDetailData && DriverInfoDetailDataSize != 0)
1909 SetLastError(ERROR_INVALID_PARAMETER);
1910 else if (DriverInfoDetailData && DriverInfoDetailDataSize < sizeof(SP_DRVINFO_DETAIL_DATA_W))
1911 SetLastError(ERROR_INVALID_PARAMETER);
1912 else if (DriverInfoDetailData && DriverInfoDetailData->cbSize != sizeof(SP_DRVINFO_DETAIL_DATA_W))
1913 SetLastError(ERROR_INVALID_USER_BUFFER);
1914 else if (DriverInfoData->Reserved == 0)
1915 SetLastError(ERROR_NO_DRIVER_SELECTED);
1916 else
1917 {
1918 struct DriverInfoElement *driverInfoElement;
1919 LPWSTR HardwareIDs = NULL;
1920 LPWSTR CompatibleIDs = NULL;
1921 LPWSTR pBuffer = NULL;
1922 LPCWSTR DeviceID = NULL;
1923 ULONG HardwareIDsSize, CompatibleIDsSize;
1924 ULONG sizeNeeded, sizeLeft, size;
1925 BOOL Result;
1926
1927 driverInfoElement = (struct DriverInfoElement *)DriverInfoData->Reserved;
1928
1929 /* Get hardware and compatible IDs lists */
1930 Result = GetHardwareAndCompatibleIDsLists(
1931 DeviceInfoSet,
1932 DeviceInfoData,
1933 &HardwareIDs, &HardwareIDsSize,
1934 &CompatibleIDs, &CompatibleIDsSize);
1935 if (!Result)
1936 goto done;
1937
1938 sizeNeeded = FIELD_OFFSET(SP_DRVINFO_DETAIL_DATA_W, HardwareID)
1939 + HardwareIDsSize + CompatibleIDsSize;
1940 if (RequiredSize)
1941 *RequiredSize = sizeNeeded;
1942
1943 if (!DriverInfoDetailData)
1944 {
1945 ret = TRUE;
1946 goto done;
1947 }
1948
1949 memcpy(
1950 DriverInfoDetailData,
1951 &driverInfoElement->Details,
1952 driverInfoElement->Details.cbSize);
1953 DriverInfoDetailData->CompatIDsOffset = 0;
1954 DriverInfoDetailData->CompatIDsLength = 0;
1955
1956 sizeLeft = (DriverInfoDetailDataSize - FIELD_OFFSET(SP_DRVINFO_DETAIL_DATA_W, HardwareID)) / sizeof(WCHAR);
1957 pBuffer = DriverInfoDetailData->HardwareID;
1958 /* Add as many as possible HardwareIDs in the list */
1959 DeviceID = HardwareIDs;
1960 while (DeviceID && *DeviceID && (size = wcslen(DeviceID)) + 1 < sizeLeft)
1961 {
1962 TRACE("Adding %s to list\n", debugstr_w(DeviceID));
1963 wcscpy(pBuffer, DeviceID);
1964 DeviceID += size + 1;
1965 pBuffer += size + 1;
1966 sizeLeft -= size + 1;
1967 DriverInfoDetailData->CompatIDsOffset += size + 1;
1968 }
1969 if (sizeLeft > 0)
1970 {
1971 *pBuffer = UNICODE_NULL;
1972 sizeLeft--;
1973 DriverInfoDetailData->CompatIDsOffset++;
1974 }
1975 /* Add as many as possible CompatibleIDs in the list */
1976 DeviceID = CompatibleIDs;
1977 while (DeviceID && *DeviceID && (size = wcslen(DeviceID)) + 1 < sizeLeft)
1978 {
1979 TRACE("Adding %s to list\n", debugstr_w(DeviceID));
1980 wcscpy(pBuffer, DeviceID);
1981 DeviceID += size + 1;
1982 pBuffer += size + 1;
1983 sizeLeft -= size + 1;
1984 DriverInfoDetailData->CompatIDsLength += size + 1;
1985 }
1986 if (sizeLeft > 0)
1987 {
1988 *pBuffer = UNICODE_NULL;
1989 sizeLeft--;
1990 DriverInfoDetailData->CompatIDsLength++;
1991 }
1992
1993 if (sizeNeeded > DriverInfoDetailDataSize)
1994 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1995 else
1996 ret = TRUE;
1997
1998 done:
1999 MyFree(HardwareIDs);
2000 MyFree(CompatibleIDs);
2001 }
2002
2003 TRACE("Returning %d\n", ret);
2004 return ret;
2005 }
2006
2007 /***********************************************************************
2008 * SetupDiGetDriverInstallParamsW (SETUPAPI.@)
2009 */
2010 BOOL WINAPI
2011 SetupDiGetDriverInstallParamsW(
2012 IN HDEVINFO DeviceInfoSet,
2013 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
2014 IN PSP_DRVINFO_DATA_W DriverInfoData,
2015 OUT PSP_DRVINSTALL_PARAMS DriverInstallParams)
2016 {
2017 BOOL ret = FALSE;
2018
2019 TRACE("%p %p %p %p\n", DeviceInfoSet, DeviceInfoData, DriverInfoData, DriverInstallParams);
2020
2021 if (!DeviceInfoSet || !DriverInfoData || !DriverInstallParams)
2022 SetLastError(ERROR_INVALID_PARAMETER);
2023 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
2024 SetLastError(ERROR_INVALID_HANDLE);
2025 else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2026 SetLastError(ERROR_INVALID_HANDLE);
2027 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
2028 SetLastError(ERROR_INVALID_USER_BUFFER);
2029 else if (DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V1_W) && DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V2_W))
2030 SetLastError(ERROR_INVALID_USER_BUFFER);
2031 else if (DriverInstallParams->cbSize != sizeof(SP_DRVINSTALL_PARAMS))
2032 SetLastError(ERROR_INVALID_USER_BUFFER);
2033 else
2034 {
2035 SP_DEVINSTALL_PARAMS InstallParams;
2036
2037 InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
2038 if (SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams))
2039 {
2040 struct DriverInfoElement *driverInfo;
2041 driverInfo = (struct DriverInfoElement *)InstallParams.Reserved;
2042 if (driverInfo == NULL)
2043 SetLastError(ERROR_NO_DRIVER_SELECTED);
2044 else
2045 {
2046 memcpy(
2047 DriverInstallParams,
2048 &driverInfo->Params,
2049 DriverInstallParams->cbSize);
2050 ret = TRUE;
2051 }
2052 }
2053 }
2054
2055 TRACE("Returning %d\n", ret);
2056 return ret;
2057 }
2058
2059 /***********************************************************************
2060 * SetupDiSelectBestCompatDrv (SETUPAPI.@)
2061 */
2062 BOOL WINAPI
2063 SetupDiSelectBestCompatDrv(
2064 IN HDEVINFO DeviceInfoSet,
2065 IN OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
2066 {
2067 SP_DRVINFO_DATA_W drvInfoData;
2068 BOOL ret;
2069
2070 TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
2071
2072 /* Drivers are sorted by rank in the driver list, so
2073 * the first driver in the list is the best one.
2074 */
2075 drvInfoData.cbSize = sizeof(SP_DRVINFO_DATA_W);
2076 ret = SetupDiEnumDriverInfoW(
2077 DeviceInfoSet,
2078 DeviceInfoData,
2079 SPDIT_COMPATDRIVER,
2080 0, /* Member index */
2081 &drvInfoData);
2082
2083 if (ret)
2084 {
2085 ret = SetupDiSetSelectedDriverW(
2086 DeviceInfoSet,
2087 DeviceInfoData,
2088 &drvInfoData);
2089 }
2090
2091 TRACE("Returning %d\n", ret);
2092 return ret;
2093 }
2094
2095 /***********************************************************************
2096 * SetupDiInstallDriverFiles (SETUPAPI.@)
2097 */
2098 BOOL WINAPI
2099 SetupDiInstallDriverFiles(
2100 IN HDEVINFO DeviceInfoSet,
2101 IN PSP_DEVINFO_DATA DeviceInfoData)
2102 {
2103 BOOL ret = FALSE;
2104
2105 TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
2106
2107 if (!DeviceInfoSet)
2108 SetLastError(ERROR_INVALID_PARAMETER);
2109 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
2110 SetLastError(ERROR_INVALID_HANDLE);
2111 else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2112 SetLastError(ERROR_INVALID_HANDLE);
2113 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
2114 SetLastError(ERROR_INVALID_USER_BUFFER);
2115 else if (DeviceInfoData && ((struct DeviceInfo *)DeviceInfoData->Reserved)->InstallParams.Reserved == 0)
2116 SetLastError(ERROR_NO_DRIVER_SELECTED);
2117 else if (!DeviceInfoData && ((struct DeviceInfoSet *)DeviceInfoSet)->InstallParams.Reserved == 0)
2118 SetLastError(ERROR_NO_DRIVER_SELECTED);
2119 else
2120 {
2121 SP_DEVINSTALL_PARAMS_W InstallParams;
2122 struct DriverInfoElement *SelectedDriver;
2123 WCHAR SectionName[MAX_PATH];
2124 DWORD SectionNameLength = 0;
2125 PVOID InstallMsgHandler;
2126 PVOID InstallMsgHandlerContext;
2127 PVOID Context = NULL;
2128
2129 InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
2130 ret = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
2131 if (!ret)
2132 goto done;
2133
2134 SelectedDriver = (struct DriverInfoElement *)InstallParams.Reserved;
2135 if (!SelectedDriver)
2136 {
2137 SetLastError(ERROR_NO_DRIVER_SELECTED);
2138 goto done;
2139 }
2140
2141 ret = SetupDiGetActualSectionToInstallW(
2142 SelectedDriver->InfFileDetails->hInf,
2143 SelectedDriver->Details.SectionName,
2144 SectionName, MAX_PATH - strlenW(DotCoInstallers), &SectionNameLength, NULL);
2145 if (!ret)
2146 goto done;
2147
2148 if (InstallParams.InstallMsgHandler)
2149 {
2150 InstallMsgHandler = InstallParams.InstallMsgHandler;
2151 InstallMsgHandlerContext = InstallParams.InstallMsgHandlerContext;
2152 }
2153 else
2154 {
2155 Context = SetupInitDefaultQueueCallback(InstallParams.hwndParent);
2156 if (!Context)
2157 goto cleanup;
2158 InstallMsgHandler = SetupDefaultQueueCallbackW;
2159 InstallMsgHandlerContext = Context;
2160 }
2161 ret = SetupInstallFromInfSectionW(InstallParams.hwndParent,
2162 SelectedDriver->InfFileDetails->hInf, SectionName,
2163 SPINST_FILES, NULL, SelectedDriver->InfFileDetails->DirectoryName, SP_COPY_NEWER,
2164 InstallMsgHandler, InstallMsgHandlerContext,
2165 DeviceInfoSet, DeviceInfoData);
2166 if (!ret)
2167 goto done;
2168
2169 /* Install files from .CoInstallers section */
2170 lstrcatW(SectionName, DotCoInstallers);
2171 ret = SetupInstallFromInfSectionW(InstallParams.hwndParent,
2172 SelectedDriver->InfFileDetails->hInf, SectionName,
2173 SPINST_FILES, NULL, SelectedDriver->InfFileDetails->DirectoryName, SP_COPY_NEWER,
2174 InstallMsgHandler, InstallMsgHandlerContext,
2175 DeviceInfoSet, DeviceInfoData);
2176 if (!ret)
2177 goto done;
2178
2179 /* Set the DI_NOFILECOPY flag to prevent another
2180 * installation during SetupDiInstallDevice */
2181 InstallParams.Flags |= DI_NOFILECOPY;
2182 ret = SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
2183
2184 cleanup:
2185 if (Context)
2186 SetupTermDefaultQueueCallback(Context);
2187 }
2188
2189 done:
2190 TRACE("Returning %d\n", ret);
2191 return ret;
2192 }