xref: /reactos/dll/win32/setupapi/driver.c (revision ba3f0743)
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 }
2193