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