xref: /reactos/dll/win32/setupapi/devinst.c (revision 171a9206)
1 /*
2  * SetupAPI device installer
3  *
4  * Copyright 2000 Andreas Mohr for CodeWeavers
5  *           2005-2006 Herv� Poussineau (hpoussin@reactos.org)
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21 
22 #include "setupapi_private.h"
23 
24 #include <pseh/pseh2.h>
25 
26 /* Unicode constants */
27 static const WCHAR BackSlash[] = {'\\',0};
28 static const WCHAR DateFormat[]  = {'%','u','-','%','u','-','%','u',0};
29 static const WCHAR DotCoInstallers[]  = {'.','C','o','I','n','s','t','a','l','l','e','r','s',0};
30 static const WCHAR DotHW[]  = {'.','H','W',0};
31 static const WCHAR DotServices[]  = {'.','S','e','r','v','i','c','e','s',0};
32 static const WCHAR InfDirectory[] = {'i','n','f','\\',0};
33 static const WCHAR InstanceKeyFormat[] = {'%','0','4','l','u',0};
34 static const WCHAR Version[]  = {'V','e','r','s','i','o','n',0};
35 static const WCHAR VersionFormat[] = {'%','u','.','%','u','.','%','u','.','%','u',0};
36 
37 static const WCHAR REGSTR_DRIVER_DATE[]  = {'D','r','i','v','e','r','D','a','t','e',0};
38 static const WCHAR REGSTR_DRIVER_DATE_DATA[]  = {'D','r','i','v','e','r','D','a','t','e','D','a','t','a',0};
39 static const WCHAR REGSTR_DRIVER_VERSION[]  = {'D','r','i','v','e','r','V','e','r','s','i','o','n',0};
40 static const WCHAR REGSTR_SECURITY[]  = {'S','e','c','u','r','i','t','y',0};
41 static const WCHAR REGSTR_UI_NUMBER_DESC_FORMAT[]  = {'U','I','N','u','m','b','e','r','D','e','s','c','F','o','r','m','a','t',0};
42 
43 typedef DWORD
44 (CALLBACK* CLASS_INSTALL_PROC) (
45     IN DI_FUNCTION InstallFunction,
46     IN HDEVINFO DeviceInfoSet,
47     IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL);
48 typedef BOOL
49 (WINAPI* DEFAULT_CLASS_INSTALL_PROC) (
50     IN HDEVINFO DeviceInfoSet,
51     IN OUT PSP_DEVINFO_DATA DeviceInfoData);
52 typedef DWORD
53 (CALLBACK* COINSTALLER_PROC) (
54     IN DI_FUNCTION InstallFunction,
55     IN HDEVINFO DeviceInfoSet,
56     IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
57     IN OUT PCOINSTALLER_CONTEXT_DATA Context);
58 
59 struct CoInstallerElement
60 {
61     LIST_ENTRY ListEntry;
62 
63     HMODULE Module;
64     COINSTALLER_PROC Function;
65     BOOL DoPostProcessing;
66     PVOID PrivateData;
67 };
68 
69 struct GetSectionCallbackInfo
70 {
71     PSP_ALTPLATFORM_INFO PlatformInfo;
72     BYTE ProductType;
73     WORD SuiteMask;
74     DWORD PrefixLength;
75     WCHAR BestSection[LINE_LEN + 1];
76     DWORD BestScore1, BestScore2, BestScore3, BestScore4, BestScore5;
77 };
78 
79 
80 
81 static void SETUPDI_GuidToString(const GUID *guid, LPWSTR guidStr)
82 {
83     static const WCHAR fmt[] = {'{','%','0','8','X','-','%','0','4','X','-',
84         '%','0','4','X','-','%','0','2','X','%','0','2','X','-','%','0','2',
85         'X','%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X','%',
86         '0','2','X','}',0};
87 
88     sprintfW(guidStr, fmt, guid->Data1, guid->Data2, guid->Data3,
89         guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
90         guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
91 }
92 
93 DWORD
94 GetErrorCodeFromCrCode(const IN CONFIGRET cr)
95 {
96   switch (cr)
97   {
98     case CR_ACCESS_DENIED:        return ERROR_ACCESS_DENIED;
99     case CR_BUFFER_SMALL:         return ERROR_INSUFFICIENT_BUFFER;
100     case CR_CALL_NOT_IMPLEMENTED: return ERROR_CALL_NOT_IMPLEMENTED;
101     case CR_FAILURE:              return ERROR_GEN_FAILURE;
102     case CR_INVALID_DATA:         return ERROR_INVALID_USER_BUFFER;
103     case CR_INVALID_DEVICE_ID:    return ERROR_INVALID_PARAMETER;
104     case CR_INVALID_MACHINENAME:  return ERROR_INVALID_COMPUTERNAME;
105     case CR_INVALID_DEVNODE:      return ERROR_INVALID_PARAMETER;
106     case CR_INVALID_FLAG:         return ERROR_INVALID_FLAGS;
107     case CR_INVALID_POINTER:      return ERROR_INVALID_PARAMETER;
108     case CR_INVALID_PROPERTY:     return ERROR_INVALID_PARAMETER;
109     case CR_NO_SUCH_DEVNODE:      return ERROR_FILE_NOT_FOUND;
110     case CR_NO_SUCH_REGISTRY_KEY: return ERROR_FILE_NOT_FOUND;
111     case CR_NO_SUCH_VALUE:        return ERROR_FILE_NOT_FOUND;
112     case CR_OUT_OF_MEMORY:        return ERROR_NOT_ENOUGH_MEMORY;
113     case CR_REGISTRY_ERROR:       return ERROR_GEN_FAILURE;
114     case CR_ALREADY_SUCH_DEVINST: return ERROR_DEVINST_ALREADY_EXISTS;
115     case CR_SUCCESS:              return ERROR_SUCCESS;
116     default:                      return ERROR_GEN_FAILURE;
117   }
118 
119   /* Does not happen */
120 }
121 
122 /* Lower scores are best ones */
123 static BOOL
124 CheckSectionValid(
125     IN LPCWSTR SectionName,
126     IN PSP_ALTPLATFORM_INFO PlatformInfo,
127     IN BYTE ProductType,
128     IN WORD SuiteMask,
129     OUT PDWORD ScorePlatform,
130     OUT PDWORD ScoreMajorVersion,
131     OUT PDWORD ScoreMinorVersion,
132     OUT PDWORD ScoreProductType,
133     OUT PDWORD ScoreSuiteMask)
134 {
135     LPWSTR Section = NULL;
136     //LPCWSTR pExtensionPlatform;
137     LPCWSTR pExtensionArchitecture;
138     LPWSTR Fields[6];
139     DWORD i;
140     BOOL ret = FALSE;
141 
142     //static const WCHAR ExtensionPlatformNone[]  = {'.',0};
143     static const WCHAR ExtensionPlatformNT[]  = {'.','N','T',0};
144     static const WCHAR ExtensionPlatformWindows[]  = {'.','W','i','n',0};
145 
146     static const WCHAR ExtensionArchitectureNone[]  = {0};
147     static const WCHAR ExtensionArchitecturealpha[]  = {'a','l','p','h','a',0};
148     static const WCHAR ExtensionArchitectureamd64[]  = {'A','M','D','6','4',0};
149     static const WCHAR ExtensionArchitectureia64[]  = {'I','A','6','4',0};
150     static const WCHAR ExtensionArchitecturemips[]  = {'m','i','p','s',0};
151     static const WCHAR ExtensionArchitectureppc[]  = {'p','p','c',0};
152     static const WCHAR ExtensionArchitecturex86[]  = {'x','8','6',0};
153 
154     TRACE("%s(%s %p 0x%x 0x%x)\n",
155         __FUNCTION__, debugstr_w(SectionName), PlatformInfo, ProductType, SuiteMask);
156 
157     *ScorePlatform = *ScoreMajorVersion = *ScoreMinorVersion = *ScoreProductType = *ScoreSuiteMask = 0;
158 
159     Section = pSetupDuplicateString(SectionName);
160     if (!Section)
161     {
162         TRACE("pSetupDuplicateString() failed\n");
163         goto cleanup;
164     }
165 
166     /* Set various extensions values */
167     switch (PlatformInfo->Platform)
168     {
169         case VER_PLATFORM_WIN32_WINDOWS:
170             //pExtensionPlatform = ExtensionPlatformWindows;
171             break;
172         case VER_PLATFORM_WIN32_NT:
173             //pExtensionPlatform = ExtensionPlatformNT;
174             break;
175         default:
176             ERR("Unknown platform 0x%lx\n", PlatformInfo->Platform);
177             //pExtensionPlatform = ExtensionPlatformNone;
178             break;
179     }
180     switch (PlatformInfo->ProcessorArchitecture)
181     {
182         case PROCESSOR_ARCHITECTURE_ALPHA:
183             pExtensionArchitecture = ExtensionArchitecturealpha;
184             break;
185         case PROCESSOR_ARCHITECTURE_AMD64:
186             pExtensionArchitecture = ExtensionArchitectureamd64;
187             break;
188         case PROCESSOR_ARCHITECTURE_IA64:
189             pExtensionArchitecture = ExtensionArchitectureia64;
190             break;
191         case PROCESSOR_ARCHITECTURE_INTEL:
192             pExtensionArchitecture = ExtensionArchitecturex86;
193             break;
194         case PROCESSOR_ARCHITECTURE_MIPS:
195             pExtensionArchitecture = ExtensionArchitecturemips;
196             break;
197         case PROCESSOR_ARCHITECTURE_PPC:
198             pExtensionArchitecture = ExtensionArchitectureppc;
199             break;
200         default:
201             ERR("Unknown processor architecture 0x%x\n", PlatformInfo->ProcessorArchitecture);
202         case PROCESSOR_ARCHITECTURE_UNKNOWN:
203             pExtensionArchitecture = ExtensionArchitectureNone;
204             break;
205     }
206 
207     /*
208      * Field[0] Platform
209      * Field[1] Architecture
210      * Field[2] Major version
211      * Field[3] Minor version
212      * Field[4] Product type
213      * Field[5] Suite mask
214      * Remark: these fields may be NULL if the information is not provided
215      */
216     Fields[0] = Section;
217     if (Fields[0] == NULL)
218     {
219         TRACE("No extension found\n");
220         *ScorePlatform = *ScoreMajorVersion = *ScoreMinorVersion = *ScoreProductType = *ScoreSuiteMask = ULONG_MAX;
221         ret = TRUE;
222         goto cleanup;
223     }
224     Fields[1] = Fields[0] + 1;
225     Fields[2] = Fields[3] = Fields[4] = Fields[5] = NULL;
226     for (i = 2; Fields[i - 1] != NULL && i < 6; i++)
227     {
228         Fields[i] = wcschr(Fields[i - 1], '.');
229         if (Fields[i])
230         {
231             Fields[i]++;
232             *(Fields[i] - 1) = UNICODE_NULL;
233         }
234     }
235     /* Take care of first 2 fields */
236     if (strncmpiW(Fields[0], ExtensionPlatformWindows, strlenW(ExtensionPlatformWindows)) == 0)
237     {
238         if (PlatformInfo->Platform != VER_PLATFORM_WIN32_WINDOWS)
239         {
240             TRACE("Mismatch on platform field\n");
241             goto cleanup;
242         }
243         Fields[1] += wcslen(ExtensionPlatformWindows) - 1;
244     }
245     else if (strncmpiW(Fields[0], ExtensionPlatformNT, strlenW(ExtensionPlatformNT)) == 0)
246     {
247         if (PlatformInfo->Platform != VER_PLATFORM_WIN32_NT)
248         {
249             TRACE("Mismatch on platform field\n");
250             goto cleanup;
251         }
252         Fields[1] += wcslen(ExtensionPlatformNT) - 1;
253     }
254     else
255     {
256         /* No platform specified */
257         *ScorePlatform |= 0x02;
258     }
259     if (strcmpiW(Fields[1], ExtensionArchitectureNone) == 0)
260     {
261         /* No architecture specified */
262         *ScorePlatform |= 0x01;
263     }
264     else if (strcmpiW(Fields[1], pExtensionArchitecture) != 0)
265     {
266         TRACE("Mismatch on architecture field ('%s' and '%s')\n",
267             debugstr_w(Fields[1]), debugstr_w(pExtensionArchitecture));
268         goto cleanup;
269     }
270 
271     /* Check if informations are matching */
272     if (Fields[2] && *Fields[2])
273     {
274         DWORD MajorVersion, MinorVersion = 0;
275         MajorVersion = strtoulW(Fields[2], NULL, 0);
276         if ((MajorVersion == 0 || MajorVersion == ULONG_MAX) &&
277             (errno == ERANGE || errno == EINVAL))
278         {
279             TRACE("Wrong MajorVersion ('%s')\n", debugstr_w(Fields[2]));
280             goto cleanup;
281         }
282         if (Fields[3] && *Fields[3])
283         {
284             MinorVersion = strtoulW(Fields[3], NULL, 0);
285             if ((MinorVersion == 0 || MinorVersion == ULONG_MAX) &&
286                 (errno == ERANGE || errno == EINVAL))
287             {
288                 TRACE("Wrong MinorVersion ('%s')\n", debugstr_w(Fields[3]));
289                 goto cleanup;
290             }
291         }
292         if (PlatformInfo->MajorVersion < MajorVersion ||
293             (PlatformInfo->MajorVersion == MajorVersion && PlatformInfo->MinorVersion < MinorVersion))
294         {
295             TRACE("Mismatch on version field (%lu.%lu and %lu.%lu)\n",
296                 MajorVersion, MinorVersion, PlatformInfo->MajorVersion, PlatformInfo->MinorVersion);
297             goto cleanup;
298         }
299         *ScoreMajorVersion = MajorVersion - PlatformInfo->MajorVersion;
300         if (MajorVersion == PlatformInfo->MajorVersion)
301             *ScoreMinorVersion = MinorVersion - PlatformInfo->MinorVersion;
302         else
303             *ScoreMinorVersion = MinorVersion;
304     }
305     else if (Fields[3] && *Fields[3])
306     {
307         TRACE("Minor version found without major version\n");
308         goto cleanup;
309     }
310     else
311     {
312         *ScoreMajorVersion = PlatformInfo->MajorVersion;
313         *ScoreMinorVersion = PlatformInfo->MinorVersion;
314     }
315 
316     if (Fields[4] && *Fields[4])
317     {
318         DWORD CurrentProductType;
319         CurrentProductType = strtoulW(Fields[4], NULL, 0);
320         if ((CurrentProductType == 0 || CurrentProductType == ULONG_MAX) &&
321             (errno == ERANGE || errno == EINVAL))
322         {
323             TRACE("Wrong Product type ('%s')\n", debugstr_w(Fields[4]));
324             goto cleanup;
325         }
326         if (CurrentProductType != ProductType)
327         {
328             TRACE("Mismatch on product type (0x%08lx and 0x%08x)\n",
329                 CurrentProductType, ProductType);
330             goto cleanup;
331         }
332     }
333     else
334         *ScoreProductType = 1;
335 
336     if (Fields[5] && *Fields[5])
337     {
338         DWORD CurrentSuiteMask;
339         CurrentSuiteMask = strtoulW(Fields[5], NULL, 0);
340         if ((CurrentSuiteMask == 0 || CurrentSuiteMask == ULONG_MAX) &&
341             (errno == ERANGE || errno == EINVAL))
342         {
343             TRACE("Wrong Suite mask ('%s')\n", debugstr_w(Fields[5]));
344             goto cleanup;
345         }
346         if ((CurrentSuiteMask & ~SuiteMask) != 0)
347         {
348             TRACE("Mismatch on suite mask (0x%08lx and 0x%08x)\n",
349                 CurrentSuiteMask, SuiteMask);
350             goto cleanup;
351         }
352         *ScoreSuiteMask = SuiteMask & ~CurrentSuiteMask;
353     }
354     else
355         *ScoreSuiteMask = SuiteMask;
356 
357     ret = TRUE;
358 
359 cleanup:
360     MyFree(Section);
361     return ret;
362 }
363 
364 static BOOL
365 GetSectionCallback(
366     IN LPCWSTR SectionName,
367     IN PVOID Context)
368 {
369     struct GetSectionCallbackInfo *info = Context;
370     DWORD Score1, Score2, Score3, Score4, Score5;
371     BOOL ret;
372 
373     if (SectionName[info->PrefixLength] != '.')
374         return TRUE;
375 
376     ret = CheckSectionValid(
377         &SectionName[info->PrefixLength],
378         info->PlatformInfo,
379         info->ProductType,
380         info->SuiteMask,
381         &Score1, &Score2, &Score3, &Score4, &Score5);
382     if (!ret)
383     {
384         TRACE("Section %s not compatible\n", debugstr_w(SectionName));
385         return TRUE;
386     }
387     if (Score1 > info->BestScore1) goto done;
388     if (Score1 < info->BestScore1) goto bettersection;
389     if (Score2 > info->BestScore2) goto done;
390     if (Score2 < info->BestScore2) goto bettersection;
391     if (Score3 > info->BestScore3) goto done;
392     if (Score3 < info->BestScore3) goto bettersection;
393     if (Score4 > info->BestScore4) goto done;
394     if (Score4 < info->BestScore4) goto bettersection;
395     if (Score5 > info->BestScore5) goto done;
396     if (Score5 < info->BestScore5) goto bettersection;
397     goto done;
398 
399 bettersection:
400     strcpyW(info->BestSection, SectionName);
401     info->BestScore1 = Score1;
402     info->BestScore2 = Score2;
403     info->BestScore3 = Score3;
404     info->BestScore4 = Score4;
405     info->BestScore5 = Score5;
406 
407 done:
408     return TRUE;
409 }
410 
411 /***********************************************************************
412  *		SetupDiGetActualSectionToInstallExW (SETUPAPI.@)
413  */
414 BOOL WINAPI
415 SetupDiGetActualSectionToInstallExW(
416     IN HINF InfHandle,
417     IN PCWSTR InfSectionName,
418     IN PSP_ALTPLATFORM_INFO AlternatePlatformInfo OPTIONAL,
419     OUT PWSTR InfSectionWithExt OPTIONAL,
420     IN DWORD InfSectionWithExtSize,
421     OUT PDWORD RequiredSize OPTIONAL,
422     OUT PWSTR* Extension OPTIONAL,
423     IN PVOID Reserved)
424 {
425     BOOL ret = FALSE;
426 
427     TRACE("%s(%p %s %p %p %lu %p %p %p)\n", __FUNCTION__, InfHandle, debugstr_w(InfSectionName),
428         AlternatePlatformInfo, InfSectionWithExt, InfSectionWithExtSize,
429         RequiredSize, Extension, Reserved);
430 
431     if (!InfHandle || InfHandle == (HINF)INVALID_HANDLE_VALUE)
432         SetLastError(ERROR_INVALID_HANDLE);
433     else if (!InfSectionName)
434         SetLastError(ERROR_INVALID_PARAMETER);
435     else if (AlternatePlatformInfo && AlternatePlatformInfo->cbSize != sizeof(SP_ALTPLATFORM_INFO))
436         SetLastError(ERROR_INVALID_USER_BUFFER);
437     else if (Reserved != NULL)
438         SetLastError(ERROR_INVALID_PARAMETER);
439     else
440     {
441         static SP_ALTPLATFORM_INFO CurrentPlatform = { 0, };
442         static BYTE CurrentProductType = 0;
443         static WORD CurrentSuiteMask = 0;
444         PSP_ALTPLATFORM_INFO pPlatformInfo = &CurrentPlatform;
445         struct GetSectionCallbackInfo CallbackInfo;
446         DWORD dwFullLength;
447         BYTE ProductType;
448         WORD SuiteMask;
449 
450         /* Fill platform info if needed */
451         if (AlternatePlatformInfo)
452         {
453             pPlatformInfo = AlternatePlatformInfo;
454             ProductType = 0;
455             SuiteMask = 0;
456         }
457         else
458         {
459             if (CurrentPlatform.cbSize != sizeof(SP_ALTPLATFORM_INFO))
460             {
461                 /* That's the first time we go here. We need to fill in the structure */
462                 SYSTEM_INFO SystemInfo;
463                 GetSystemInfo(&SystemInfo);
464                 CurrentPlatform.cbSize = sizeof(SP_ALTPLATFORM_INFO);
465                 CurrentPlatform.Platform = OsVersionInfo.dwPlatformId;
466                 CurrentPlatform.MajorVersion = OsVersionInfo.dwMajorVersion;
467                 CurrentPlatform.MinorVersion = OsVersionInfo.dwMinorVersion;
468                 CurrentPlatform.ProcessorArchitecture = SystemInfo.wProcessorArchitecture;
469                 CurrentPlatform.Reserved = 0;
470                 CurrentProductType = OsVersionInfo.wProductType;
471                 CurrentSuiteMask = OsVersionInfo.wSuiteMask;
472             }
473             ProductType = CurrentProductType;
474             SuiteMask = CurrentSuiteMask;
475         }
476 
477         CallbackInfo.PlatformInfo = pPlatformInfo;
478         CallbackInfo.ProductType = ProductType;
479         CallbackInfo.SuiteMask = SuiteMask;
480         CallbackInfo.PrefixLength = strlenW(InfSectionName);
481         CallbackInfo.BestScore1 = ULONG_MAX;
482         CallbackInfo.BestScore2 = ULONG_MAX;
483         CallbackInfo.BestScore3 = ULONG_MAX;
484         CallbackInfo.BestScore4 = ULONG_MAX;
485         CallbackInfo.BestScore5 = ULONG_MAX;
486         strcpyW(CallbackInfo.BestSection, InfSectionName);
487         TRACE("EnumerateSectionsStartingWith(InfSectionName = %S)\n", InfSectionName);
488         if (!EnumerateSectionsStartingWith(
489             InfHandle,
490             InfSectionName,
491             GetSectionCallback,
492             &CallbackInfo))
493         {
494             SetLastError(ERROR_GEN_FAILURE);
495             goto done;
496         }
497         TRACE("CallbackInfo.BestSection = %S\n", CallbackInfo.BestSection);
498 
499         dwFullLength = lstrlenW(CallbackInfo.BestSection);
500         if (RequiredSize != NULL)
501             *RequiredSize = dwFullLength + 1;
502 
503         if (InfSectionWithExtSize > 0)
504         {
505             if (InfSectionWithExtSize < dwFullLength + 1)
506             {
507                 SetLastError(ERROR_INSUFFICIENT_BUFFER);
508                 goto done;
509             }
510             strcpyW(InfSectionWithExt, CallbackInfo.BestSection);
511             if (Extension)
512             {
513                 DWORD dwLength = lstrlenW(InfSectionName);
514                 *Extension = (dwLength == dwFullLength) ? NULL : &InfSectionWithExt[dwLength];
515             }
516         }
517 
518         ret = TRUE;
519     }
520 
521 done:
522     TRACE("Returning %d\n", ret);
523     return ret;
524 }
525 
526 
527 BOOL
528 CreateDeviceInfo(
529     IN struct DeviceInfoSet *list,
530     IN LPCWSTR InstancePath,
531     IN LPCGUID pClassGuid,
532     OUT struct DeviceInfo **pDeviceInfo)
533 {
534     DWORD size;
535     CONFIGRET cr;
536     struct DeviceInfo *deviceInfo;
537 
538     *pDeviceInfo = NULL;
539 
540     size = FIELD_OFFSET(struct DeviceInfo, Data) + (strlenW(InstancePath) + 1) * sizeof(WCHAR);
541     deviceInfo = HeapAlloc(GetProcessHeap(), 0, size);
542     if (!deviceInfo)
543     {
544         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
545         return FALSE;
546     }
547     ZeroMemory(deviceInfo, size);
548 
549     cr = CM_Locate_DevNode_ExW(&deviceInfo->dnDevInst, (DEVINSTID_W)InstancePath, CM_LOCATE_DEVNODE_PHANTOM, list->hMachine);
550     if (cr != CR_SUCCESS)
551     {
552         SetLastError(GetErrorCodeFromCrCode(cr));
553         return FALSE;
554     }
555 
556     deviceInfo->set = list;
557     deviceInfo->InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
558     strcpyW(deviceInfo->Data, InstancePath);
559     deviceInfo->instanceId = deviceInfo->Data;
560     deviceInfo->UniqueId = strrchrW(deviceInfo->Data, '\\');
561     deviceInfo->DeviceDescription = NULL;
562     memcpy(&deviceInfo->ClassGuid, pClassGuid, sizeof(GUID));
563     deviceInfo->CreationFlags = 0;
564     InitializeListHead(&deviceInfo->DriverListHead);
565     InitializeListHead(&deviceInfo->InterfaceListHead);
566 
567     *pDeviceInfo = deviceInfo;
568     return TRUE;
569 }
570 
571 
572 static BOOL
573 DestroyClassInstallParams(struct ClassInstallParams* installParams)
574 {
575     HeapFree(GetProcessHeap(), 0, installParams->PropChangeParams);
576     HeapFree(GetProcessHeap(), 0, installParams->AddPropertyPageData);
577     return TRUE;
578 }
579 
580 static BOOL
581 DestroyDeviceInfo(struct DeviceInfo *deviceInfo)
582 {
583     PLIST_ENTRY ListEntry;
584     struct DriverInfoElement *driverInfo;
585     struct DeviceInterface *deviceInterface;
586 
587     while (!IsListEmpty(&deviceInfo->DriverListHead))
588     {
589         ListEntry = RemoveHeadList(&deviceInfo->DriverListHead);
590         driverInfo = CONTAINING_RECORD(ListEntry, struct DriverInfoElement, ListEntry);
591         if (!DestroyDriverInfoElement(driverInfo))
592             return FALSE;
593     }
594     while (!IsListEmpty(&deviceInfo->InterfaceListHead))
595     {
596         ListEntry = RemoveHeadList(&deviceInfo->InterfaceListHead);
597         deviceInterface = CONTAINING_RECORD(ListEntry, struct DeviceInterface, ListEntry);
598         if (!DestroyDeviceInterface(deviceInterface))
599             return FALSE;
600     }
601     DestroyClassInstallParams(&deviceInfo->ClassInstallParams);
602     if (deviceInfo->hmodDevicePropPageProvider)
603         FreeLibrary(deviceInfo->hmodDevicePropPageProvider);
604     return HeapFree(GetProcessHeap(), 0, deviceInfo);
605 }
606 
607 static BOOL
608 DestroyDeviceInfoSet(struct DeviceInfoSet* list)
609 {
610     PLIST_ENTRY ListEntry;
611     struct DeviceInfo *deviceInfo;
612 
613     while (!IsListEmpty(&list->ListHead))
614     {
615         ListEntry = RemoveHeadList(&list->ListHead);
616         deviceInfo = CONTAINING_RECORD(ListEntry, struct DeviceInfo, ListEntry);
617         if (!DestroyDeviceInfo(deviceInfo))
618             return FALSE;
619     }
620     if (list->HKLM != HKEY_LOCAL_MACHINE)
621         RegCloseKey(list->HKLM);
622     CM_Disconnect_Machine(list->hMachine);
623     DestroyClassInstallParams(&list->ClassInstallParams);
624     if (list->hmodClassPropPageProvider)
625         FreeLibrary(list->hmodClassPropPageProvider);
626     return HeapFree(GetProcessHeap(), 0, list);
627 }
628 
629 /***********************************************************************
630  *              SetupDiBuildClassInfoList  (SETUPAPI.@)
631  *
632  * Returns a list of setup class GUIDs that identify the classes
633  * that are installed on a local machine.
634  *
635  * PARAMS
636  *   Flags [I] control exclusion of classes from the list.
637  *   ClassGuidList [O] pointer to a GUID-typed array that receives a list of setup class GUIDs.
638  *   ClassGuidListSize [I] The number of GUIDs in the array (ClassGuidList).
639  *   RequiredSize [O] pointer, which receives the number of GUIDs that are returned.
640  *
641  * RETURNS
642  *   Success: TRUE.
643  *   Failure: FALSE.
644  */
645 BOOL WINAPI SetupDiBuildClassInfoList(
646         DWORD Flags,
647         LPGUID ClassGuidList,
648         DWORD ClassGuidListSize,
649         PDWORD RequiredSize)
650 {
651     TRACE("\n");
652     return SetupDiBuildClassInfoListExW(Flags, ClassGuidList,
653                                         ClassGuidListSize, RequiredSize,
654                                         NULL, NULL);
655 }
656 
657 /***********************************************************************
658  *              SetupDiBuildClassInfoListExA  (SETUPAPI.@)
659  *
660  * Returns a list of setup class GUIDs that identify the classes
661  * that are installed on a local or remote machine.
662  *
663  * PARAMS
664  *   Flags [I] control exclusion of classes from the list.
665  *   ClassGuidList [O] pointer to a GUID-typed array that receives a list of setup class GUIDs.
666  *   ClassGuidListSize [I] The number of GUIDs in the array (ClassGuidList).
667  *   RequiredSize [O] pointer, which receives the number of GUIDs that are returned.
668  *   MachineName [I] name of a remote machine.
669  *   Reserved [I] must be NULL.
670  *
671  * RETURNS
672  *   Success: TRUE.
673  *   Failure: FALSE.
674  */
675 BOOL WINAPI SetupDiBuildClassInfoListExA(
676         DWORD Flags,
677         LPGUID ClassGuidList,
678         DWORD ClassGuidListSize,
679         PDWORD RequiredSize,
680         LPCSTR MachineName,
681         PVOID Reserved)
682 {
683     LPWSTR MachineNameW = NULL;
684     BOOL bResult;
685 
686     TRACE("%s(0x%lx %p %lu %p %s %p)\n", __FUNCTION__, Flags, ClassGuidList,
687         ClassGuidListSize, RequiredSize, debugstr_a(MachineName), Reserved);
688 
689     if (MachineName)
690     {
691         MachineNameW = pSetupMultiByteToUnicode(MachineName, CP_ACP);
692         if (MachineNameW == NULL) return FALSE;
693     }
694 
695     bResult = SetupDiBuildClassInfoListExW(Flags, ClassGuidList,
696                                            ClassGuidListSize, RequiredSize,
697                                            MachineNameW, Reserved);
698 
699     MyFree(MachineNameW);
700 
701     return bResult;
702 }
703 
704 /***********************************************************************
705  *              SetupDiBuildClassInfoListExW  (SETUPAPI.@)
706  *
707  * Returns a list of setup class GUIDs that identify the classes
708  * that are installed on a local or remote machine.
709  *
710  * PARAMS
711  *   Flags [I] control exclusion of classes from the list.
712  *   ClassGuidList [O] pointer to a GUID-typed array that receives a list of setup class GUIDs.
713  *   ClassGuidListSize [I] The number of GUIDs in the array (ClassGuidList).
714  *   RequiredSize [O] pointer, which receives the number of GUIDs that are returned.
715  *   MachineName [I] name of a remote machine.
716  *   Reserved [I] must be NULL.
717  *
718  * RETURNS
719  *   Success: TRUE.
720  *   Failure: FALSE.
721  */
722 BOOL WINAPI SetupDiBuildClassInfoListExW(
723         DWORD Flags,
724         LPGUID ClassGuidList,
725         DWORD ClassGuidListSize,
726         PDWORD RequiredSize,
727         LPCWSTR MachineName,
728         PVOID Reserved)
729 {
730     GUID CurrentClassGuid;
731     HKEY hClassKey;
732     DWORD dwIndex;
733     DWORD dwGuidListIndex = 0;
734     HMACHINE hMachine = NULL;
735     CONFIGRET cr;
736 
737     TRACE("%s(0x%lx %p %lu %p %s %p)\n", __FUNCTION__, Flags, ClassGuidList,
738         ClassGuidListSize, RequiredSize, debugstr_w(MachineName), Reserved);
739 
740     if (!RequiredSize)
741     {
742         SetLastError(ERROR_INVALID_PARAMETER);
743         return FALSE;
744     }
745     else if (!ClassGuidList && ClassGuidListSize > 0)
746     {
747         SetLastError(ERROR_INVALID_PARAMETER);
748         return FALSE;
749     }
750 
751     if (MachineName)
752     {
753         cr = CM_Connect_MachineW(MachineName, &hMachine);
754         if (cr != CR_SUCCESS)
755         {
756             SetLastError(GetErrorCodeFromCrCode(cr));
757             return FALSE;
758         }
759     }
760 
761     for (dwIndex = 0; ; dwIndex++)
762     {
763         cr = CM_Enumerate_Classes_Ex(dwIndex,
764                                      &CurrentClassGuid,
765                                      0,
766                                      hMachine);
767         if (cr == CR_SUCCESS)
768         {
769             TRACE("Guid: %s\n", debugstr_guid(&CurrentClassGuid));
770             if (CM_Open_Class_Key_ExW(&CurrentClassGuid,
771                                        NULL,
772                                        KEY_QUERY_VALUE,
773                                        RegDisposition_OpenExisting,
774                                        &hClassKey,
775                                        CM_OPEN_CLASS_KEY_INSTALLER,
776                                        hMachine) != CR_SUCCESS)
777             {
778                 SetLastError(GetErrorCodeFromCrCode(cr));
779                 if (hMachine)
780                     CM_Disconnect_Machine(hMachine);
781                 return FALSE;
782             }
783 
784             if (!RegQueryValueExW(hClassKey,
785                                   REGSTR_VAL_NOUSECLASS,
786                                   NULL,
787                                   NULL,
788                                   NULL,
789                                   NULL))
790             {
791                 TRACE("'NoUseClass' value found!\n");
792                 RegCloseKey(hClassKey);
793                 continue;
794             }
795 
796             if ((Flags & DIBCI_NOINSTALLCLASS) &&
797                 (!RegQueryValueExW(hClassKey,
798                                    REGSTR_VAL_NOINSTALLCLASS,
799                                    NULL,
800                                    NULL,
801                                    NULL,
802                                    NULL)))
803             {
804                 TRACE("'NoInstallClass' value found!\n");
805                 RegCloseKey(hClassKey);
806                 continue;
807             }
808 
809             if ((Flags & DIBCI_NODISPLAYCLASS) &&
810                 (!RegQueryValueExW(hClassKey,
811                                    REGSTR_VAL_NODISPLAYCLASS,
812                                    NULL,
813                                    NULL,
814                                    NULL,
815                                    NULL)))
816             {
817                 TRACE("'NoDisplayClass' value found!\n");
818                 RegCloseKey(hClassKey);
819                 continue;
820             }
821 
822             RegCloseKey(hClassKey);
823 
824             if (dwGuidListIndex < ClassGuidListSize)
825             {
826                 ClassGuidList[dwGuidListIndex] = CurrentClassGuid;
827             }
828 
829             dwGuidListIndex++;
830         }
831 
832         if (cr != ERROR_SUCCESS)
833             break;
834     }
835 
836     if (hMachine)
837         CM_Disconnect_Machine(hMachine);
838 
839     if (RequiredSize != NULL)
840         *RequiredSize = dwGuidListIndex;
841 
842     if (ClassGuidListSize < dwGuidListIndex)
843     {
844         SetLastError(ERROR_INSUFFICIENT_BUFFER);
845         return FALSE;
846     }
847 
848     return TRUE;
849 }
850 
851 /***********************************************************************
852  *		SetupDiClassGuidsFromNameA  (SETUPAPI.@)
853  */
854 BOOL WINAPI SetupDiClassGuidsFromNameA(
855         LPCSTR ClassName,
856         LPGUID ClassGuidList,
857         DWORD ClassGuidListSize,
858         PDWORD RequiredSize)
859 {
860     return SetupDiClassGuidsFromNameExA(ClassName, ClassGuidList,
861                                         ClassGuidListSize, RequiredSize,
862                                         NULL, NULL);
863 }
864 
865 /***********************************************************************
866  *		SetupDiClassGuidsFromNameW  (SETUPAPI.@)
867  */
868 BOOL WINAPI SetupDiClassGuidsFromNameW(
869         LPCWSTR ClassName,
870         LPGUID ClassGuidList,
871         DWORD ClassGuidListSize,
872         PDWORD RequiredSize)
873 {
874     return SetupDiClassGuidsFromNameExW(ClassName, ClassGuidList,
875                                         ClassGuidListSize, RequiredSize,
876                                         NULL, NULL);
877 }
878 
879 /***********************************************************************
880  *		SetupDiClassGuidsFromNameExA  (SETUPAPI.@)
881  */
882 BOOL WINAPI SetupDiClassGuidsFromNameExA(
883         LPCSTR ClassName,
884         LPGUID ClassGuidList,
885         DWORD ClassGuidListSize,
886         PDWORD RequiredSize,
887         LPCSTR MachineName,
888         PVOID Reserved)
889 {
890     LPWSTR ClassNameW = NULL;
891     LPWSTR MachineNameW = NULL;
892     BOOL bResult;
893 
894     TRACE("%s(%s %p %lu %p %s %p)\n", __FUNCTION__, debugstr_a(ClassName), ClassGuidList,
895         ClassGuidListSize, RequiredSize, debugstr_a(MachineName), Reserved);
896 
897     if (!ClassName)
898     {
899         SetLastError(ERROR_INVALID_PARAMETER);
900         return FALSE;
901     }
902 
903     ClassNameW = pSetupMultiByteToUnicode(ClassName, CP_ACP);
904     if (ClassNameW == NULL)
905         return FALSE;
906 
907     if (MachineName)
908     {
909         MachineNameW = pSetupMultiByteToUnicode(MachineName, CP_ACP);
910         if (MachineNameW == NULL)
911         {
912             MyFree(ClassNameW);
913             return FALSE;
914         }
915     }
916 
917     bResult = SetupDiClassGuidsFromNameExW(ClassNameW, ClassGuidList,
918                                            ClassGuidListSize, RequiredSize,
919                                            MachineNameW, Reserved);
920 
921     MyFree(MachineNameW);
922     MyFree(ClassNameW);
923 
924     return bResult;
925 }
926 
927 /***********************************************************************
928  *		SetupDiClassGuidsFromNameExW  (SETUPAPI.@)
929  */
930 BOOL WINAPI SetupDiClassGuidsFromNameExW(
931         LPCWSTR ClassName,
932         LPGUID ClassGuidList,
933         DWORD ClassGuidListSize,
934         PDWORD RequiredSize,
935         LPCWSTR MachineName,
936         PVOID Reserved)
937 {
938     WCHAR szKeyName[40];
939     WCHAR szClassName[MAX_CLASS_NAME_LEN];
940     HKEY hClassesKey;
941     HKEY hClassKey;
942     DWORD dwLength;
943     DWORD dwIndex;
944     LONG lError;
945     DWORD dwGuidListIndex = 0;
946 
947     TRACE("%s(%s %p %lu %p %s %p)\n", __FUNCTION__, debugstr_w(ClassName), ClassGuidList,
948         ClassGuidListSize, RequiredSize, debugstr_w(MachineName), Reserved);
949 
950     if (!ClassName || !RequiredSize)
951     {
952         SetLastError(ERROR_INVALID_PARAMETER);
953         return FALSE;
954     }
955     if (!ClassGuidList && ClassGuidListSize > 0)
956     {
957         SetLastError(ERROR_INVALID_PARAMETER);
958         return FALSE;
959     }
960     *RequiredSize = 0;
961 
962     hClassesKey = SetupDiOpenClassRegKeyExW(NULL,
963                                             KEY_ENUMERATE_SUB_KEYS,
964                                             DIOCR_INSTALLER,
965                                             MachineName,
966                                             Reserved);
967     if (hClassesKey == INVALID_HANDLE_VALUE)
968     {
969         return FALSE;
970     }
971 
972     for (dwIndex = 0; ; dwIndex++)
973     {
974         dwLength = 40;
975         lError = RegEnumKeyExW(hClassesKey,
976                                dwIndex,
977                                szKeyName,
978                                &dwLength,
979                                NULL,
980                                NULL,
981                                NULL,
982                                NULL);
983         TRACE("RegEnumKeyExW() returns %d\n", lError);
984         if (lError == ERROR_SUCCESS || lError == ERROR_MORE_DATA)
985         {
986             TRACE("Key name: %p\n", szKeyName);
987 
988             if (RegOpenKeyExW(hClassesKey,
989                               szKeyName,
990                               0,
991                               KEY_QUERY_VALUE,
992                               &hClassKey))
993             {
994                 RegCloseKey(hClassesKey);
995                 return FALSE;
996             }
997 
998             dwLength = MAX_CLASS_NAME_LEN * sizeof(WCHAR);
999             if (!RegQueryValueExW(hClassKey,
1000                                   REGSTR_VAL_CLASS,
1001                                   NULL,
1002                                   NULL,
1003                                   (LPBYTE)szClassName,
1004                                   &dwLength))
1005             {
1006                 TRACE("Class name: %p\n", szClassName);
1007 
1008                 if (strcmpiW(szClassName, ClassName) == 0)
1009                 {
1010                     TRACE("Found matching class name\n");
1011 
1012                     TRACE("Guid: %p\n", szKeyName);
1013                     if (dwGuidListIndex < ClassGuidListSize)
1014                     {
1015                         if (szKeyName[0] == '{' && szKeyName[37] == '}')
1016                         {
1017                             szKeyName[37] = 0;
1018                         }
1019                         TRACE("Guid: %p\n", &szKeyName[1]);
1020 
1021                         UuidFromStringW(&szKeyName[1],
1022                                         &ClassGuidList[dwGuidListIndex]);
1023                     }
1024 
1025                     dwGuidListIndex++;
1026                 }
1027             }
1028 
1029             RegCloseKey(hClassKey);
1030         }
1031 
1032         if (lError != ERROR_SUCCESS)
1033             break;
1034     }
1035 
1036     RegCloseKey(hClassesKey);
1037 
1038     if (RequiredSize != NULL)
1039         *RequiredSize = dwGuidListIndex;
1040 
1041     if (ClassGuidListSize < dwGuidListIndex)
1042     {
1043         SetLastError(ERROR_INSUFFICIENT_BUFFER);
1044         return FALSE;
1045     }
1046 
1047     return TRUE;
1048 }
1049 
1050 /***********************************************************************
1051  *              SetupDiClassNameFromGuidA  (SETUPAPI.@)
1052  */
1053 BOOL WINAPI SetupDiClassNameFromGuidA(
1054         const GUID* ClassGuid,
1055         PSTR ClassName,
1056         DWORD ClassNameSize,
1057         PDWORD RequiredSize)
1058 {
1059     return SetupDiClassNameFromGuidExA(ClassGuid, ClassName,
1060                                        ClassNameSize, RequiredSize,
1061                                        NULL, NULL);
1062 }
1063 
1064 /***********************************************************************
1065  *              SetupDiClassNameFromGuidW  (SETUPAPI.@)
1066  */
1067 BOOL WINAPI SetupDiClassNameFromGuidW(
1068         const GUID* ClassGuid,
1069         PWSTR ClassName,
1070         DWORD ClassNameSize,
1071         PDWORD RequiredSize)
1072 {
1073     return SetupDiClassNameFromGuidExW(ClassGuid, ClassName,
1074                                        ClassNameSize, RequiredSize,
1075                                        NULL, NULL);
1076 }
1077 
1078 /***********************************************************************
1079  *              SetupDiClassNameFromGuidExA  (SETUPAPI.@)
1080  */
1081 BOOL WINAPI SetupDiClassNameFromGuidExA(
1082         const GUID* ClassGuid,
1083         PSTR ClassName,
1084         DWORD ClassNameSize,
1085         PDWORD RequiredSize,
1086         PCSTR MachineName,
1087         PVOID Reserved)
1088 {
1089     WCHAR ClassNameW[MAX_CLASS_NAME_LEN];
1090     LPWSTR MachineNameW = NULL;
1091     BOOL ret;
1092 
1093     if (MachineName)
1094         MachineNameW = pSetupMultiByteToUnicode(MachineName, CP_ACP);
1095     ret = SetupDiClassNameFromGuidExW(ClassGuid, ClassNameW, MAX_CLASS_NAME_LEN,
1096                                       RequiredSize, MachineNameW, Reserved);
1097     if (ret)
1098     {
1099         int len = WideCharToMultiByte(CP_ACP, 0, ClassNameW, -1, ClassName,
1100                                       ClassNameSize, NULL, NULL);
1101         if (len == 0 || len > ClassNameSize)
1102         {
1103             SetLastError(ERROR_INSUFFICIENT_BUFFER);
1104             ret = FALSE;
1105         }
1106     }
1107     MyFree(MachineNameW);
1108     return ret;
1109 }
1110 
1111 /***********************************************************************
1112  *		SetupDiClassNameFromGuidExW  (SETUPAPI.@)
1113  */
1114 BOOL WINAPI SetupDiClassNameFromGuidExW(
1115         const GUID* ClassGuid,
1116         PWSTR ClassName,
1117         DWORD ClassNameSize,
1118         PDWORD RequiredSize,
1119         PCWSTR MachineName,
1120         PVOID Reserved)
1121 {
1122     HKEY hKey;
1123     DWORD dwLength;
1124     DWORD dwRegType;
1125     LONG rc;
1126     PWSTR Buffer;
1127 
1128     TRACE("%s(%s %p %lu %p %s %p)\n", __FUNCTION__, debugstr_guid(ClassGuid), ClassName,
1129         ClassNameSize, RequiredSize, debugstr_w(MachineName), Reserved);
1130 
1131     /* Make sure there's a GUID */
1132     if (ClassGuid == NULL)
1133     {
1134         SetLastError(ERROR_INVALID_CLASS);  /* On Vista: ERROR_INVALID_USER_BUFFER */
1135         return FALSE;
1136     }
1137 
1138     /* Make sure there's a real buffer when there's a size */
1139     if ((ClassNameSize > 0) && (ClassName == NULL))
1140     {
1141         SetLastError(ERROR_INVALID_PARAMETER);  /* On Vista: ERROR_INVALID_USER_BUFFER */
1142         return FALSE;
1143     }
1144 
1145     /* Open the key for the GUID */
1146     hKey = SetupDiOpenClassRegKeyExW(ClassGuid, KEY_QUERY_VALUE, DIOCR_INSTALLER, MachineName, Reserved);
1147 
1148     if (hKey == INVALID_HANDLE_VALUE)
1149         return FALSE;
1150 
1151     /* Retrieve the class name data and close the key */
1152     rc = QueryRegistryValue(hKey, REGSTR_VAL_CLASS, (LPBYTE *) &Buffer, &dwRegType, &dwLength);
1153     RegCloseKey(hKey);
1154 
1155     /* Make sure we got the data */
1156     if (rc != ERROR_SUCCESS)
1157     {
1158         SetLastError(rc);
1159         return FALSE;
1160     }
1161 
1162     /* Make sure the data is a string */
1163     if (dwRegType != REG_SZ)
1164     {
1165         MyFree(Buffer);
1166         SetLastError(ERROR_GEN_FAILURE);
1167         return FALSE;
1168     }
1169 
1170     /* Determine the length of the class name */
1171     dwLength /= sizeof(WCHAR);
1172 
1173     if ((dwLength == 0) || (Buffer[dwLength - 1] != UNICODE_NULL))
1174         /* Count the null-terminator */
1175         dwLength++;
1176 
1177     /* Inform the caller about the class name */
1178     if ((ClassName != NULL) && (dwLength <= ClassNameSize))
1179     {
1180         memcpy(ClassName, Buffer, (dwLength - 1) * sizeof(WCHAR));
1181         ClassName[dwLength - 1] = UNICODE_NULL;
1182     }
1183 
1184     /* Inform the caller about the required size */
1185     if (RequiredSize != NULL)
1186         *RequiredSize = dwLength;
1187 
1188     /* Clean up the buffer */
1189     MyFree(Buffer);
1190 
1191     /* Make sure the buffer was large enough */
1192     if ((ClassName == NULL) || (dwLength > ClassNameSize))
1193     {
1194         SetLastError(ERROR_INSUFFICIENT_BUFFER);
1195         return FALSE;
1196     }
1197 
1198     return TRUE;
1199 }
1200 
1201 /***********************************************************************
1202  *		SetupDiCreateDeviceInfoList (SETUPAPI.@)
1203  */
1204 HDEVINFO WINAPI
1205 SetupDiCreateDeviceInfoList(const GUID *ClassGuid,
1206         HWND hwndParent)
1207 {
1208     return SetupDiCreateDeviceInfoListExW(ClassGuid, hwndParent, NULL, NULL);
1209 }
1210 
1211 /***********************************************************************
1212  *		SetupDiCreateDeviceInfoListExA (SETUPAPI.@)
1213  */
1214 HDEVINFO WINAPI
1215 SetupDiCreateDeviceInfoListExA(const GUID *ClassGuid,
1216         HWND hwndParent,
1217         PCSTR MachineName,
1218         PVOID Reserved)
1219 {
1220     LPWSTR MachineNameW = NULL;
1221     HDEVINFO hDevInfo;
1222 
1223     TRACE("%s(%s %p %s %p)\n", __FUNCTION__, debugstr_guid(ClassGuid), hwndParent,
1224       debugstr_a(MachineName), Reserved);
1225 
1226     if (MachineName)
1227     {
1228         MachineNameW = pSetupMultiByteToUnicode(MachineName, CP_ACP);
1229         if (MachineNameW == NULL)
1230             return INVALID_HANDLE_VALUE;
1231     }
1232 
1233     hDevInfo = SetupDiCreateDeviceInfoListExW(ClassGuid, hwndParent,
1234                                               MachineNameW, Reserved);
1235 
1236     MyFree(MachineNameW);
1237 
1238     return hDevInfo;
1239 }
1240 
1241 /***********************************************************************
1242  *		SetupDiCreateDeviceInfoListExW (SETUPAPI.@)
1243  *
1244  * Create an empty DeviceInfoSet list.
1245  *
1246  * PARAMS
1247  *   ClassGuid [I] if not NULL only devices with GUID ClassGuid are associated
1248  *                 with this list.
1249  *   hwndParent [I] hwnd needed for interface related actions.
1250  *   MachineName [I] name of machine to create emtpy DeviceInfoSet list, if NULL
1251  *                   local registry will be used.
1252  *   Reserved [I] must be NULL
1253  *
1254  * RETURNS
1255  *   Success: empty list.
1256  *   Failure: INVALID_HANDLE_VALUE.
1257  */
1258 HDEVINFO WINAPI
1259 SetupDiCreateDeviceInfoListExW(const GUID *ClassGuid,
1260         HWND hwndParent,
1261         PCWSTR MachineName,
1262         PVOID Reserved)
1263 {
1264     struct DeviceInfoSet *list = NULL;
1265     DWORD size = FIELD_OFFSET(struct DeviceInfoSet, szData);
1266     DWORD rc;
1267     CONFIGRET cr;
1268     HDEVINFO ret = INVALID_HANDLE_VALUE;
1269 
1270     TRACE("%s(%s %p %s %p)\n", __FUNCTION__, debugstr_guid(ClassGuid), hwndParent,
1271       debugstr_w(MachineName), Reserved);
1272 
1273     if (MachineName != NULL)
1274     {
1275         SIZE_T len = strlenW(MachineName);
1276         if (len >= SP_MAX_MACHINENAME_LENGTH - 4)
1277         {
1278             SetLastError(ERROR_INVALID_MACHINENAME);
1279             goto cleanup;
1280         }
1281         if(len > 0)
1282             size += (len + 3) * sizeof(WCHAR);
1283         else
1284             MachineName = NULL;
1285     }
1286 
1287     if (Reserved != NULL)
1288     {
1289         SetLastError(ERROR_INVALID_PARAMETER);
1290         return INVALID_HANDLE_VALUE;
1291     }
1292 
1293     list = MyMalloc(size);
1294     if (!list)
1295     {
1296         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1297         return INVALID_HANDLE_VALUE;
1298     }
1299     ZeroMemory(list, FIELD_OFFSET(struct DeviceInfoSet, szData));
1300 
1301     list->magic = SETUP_DEVICE_INFO_SET_MAGIC;
1302     memcpy(&list->ClassGuid,
1303             ClassGuid ? ClassGuid : &GUID_NULL,
1304             sizeof(list->ClassGuid));
1305     list->InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
1306     list->InstallParams.Flags |= DI_CLASSINSTALLPARAMS;
1307     list->InstallParams.hwndParent = hwndParent;
1308     if (MachineName)
1309     {
1310         rc = RegConnectRegistryW(MachineName, HKEY_LOCAL_MACHINE, &list->HKLM);
1311         if (rc != ERROR_SUCCESS)
1312         {
1313             SetLastError(ERROR_INVALID_MACHINENAME);
1314             goto cleanup;
1315         }
1316 
1317         list->szData[0] = list->szData[1] = '\\';
1318         strcpyW(list->szData + 2, MachineName);
1319         list->MachineName = list->szData;
1320     }
1321     else
1322     {
1323         list->HKLM = HKEY_LOCAL_MACHINE;
1324         list->MachineName = NULL;
1325     }
1326     cr = CM_Connect_MachineW(list->MachineName, &list->hMachine);
1327     if (cr != CR_SUCCESS)
1328     {
1329         SetLastError(GetErrorCodeFromCrCode(cr));
1330         goto cleanup;
1331     }
1332     InitializeListHead(&list->DriverListHead);
1333     InitializeListHead(&list->ListHead);
1334 
1335     return (HDEVINFO)list;
1336 
1337 cleanup:
1338     if (ret == INVALID_HANDLE_VALUE)
1339     {
1340         if (list)
1341         {
1342             if (list->HKLM != NULL && list->HKLM != HKEY_LOCAL_MACHINE)
1343                 RegCloseKey(list->HKLM);
1344             MyFree(list);
1345         }
1346     }
1347     return ret;
1348 }
1349 
1350 /***********************************************************************
1351  *              SetupDiCreateDevRegKeyA (SETUPAPI.@)
1352  */
1353 HKEY WINAPI SetupDiCreateDevRegKeyA(
1354         HDEVINFO DeviceInfoSet,
1355         PSP_DEVINFO_DATA DeviceInfoData,
1356         DWORD Scope,
1357         DWORD HwProfile,
1358         DWORD KeyType,
1359         HINF InfHandle,
1360         PCSTR InfSectionName)
1361 {
1362     PWSTR InfSectionNameW = NULL;
1363     HKEY key;
1364 
1365     TRACE("%s(%p %p %d %d %d %p %s)\n", __FUNCTION__, DeviceInfoSet, DeviceInfoData, Scope,
1366             HwProfile, KeyType, InfHandle, debugstr_a(InfSectionName));
1367 
1368     if (InfHandle)
1369     {
1370         if (!InfSectionName)
1371         {
1372             SetLastError(ERROR_INVALID_PARAMETER);
1373             return INVALID_HANDLE_VALUE;
1374         }
1375         else
1376         {
1377             InfSectionNameW = pSetupMultiByteToUnicode(InfSectionName, CP_ACP);
1378             if (InfSectionNameW == NULL) return INVALID_HANDLE_VALUE;
1379         }
1380     }
1381     key = SetupDiCreateDevRegKeyW(DeviceInfoSet, DeviceInfoData, Scope,
1382             HwProfile, KeyType, InfHandle, InfSectionNameW);
1383     MyFree(InfSectionNameW);
1384     return key;
1385 }
1386 
1387 static HKEY
1388 OpenHardwareProfileKey(
1389     IN HKEY HKLM,
1390     IN DWORD HwProfile,
1391     IN DWORD samDesired);
1392 
1393 /***********************************************************************
1394  *              SetupDiCreateDevRegKeyW (SETUPAPI.@)
1395  */
1396 HKEY WINAPI SetupDiCreateDevRegKeyW(
1397         HDEVINFO DeviceInfoSet,
1398         PSP_DEVINFO_DATA DeviceInfoData,
1399         DWORD Scope,
1400         DWORD HwProfile,
1401         DWORD KeyType,
1402         HINF InfHandle,
1403         PCWSTR InfSectionName)
1404 {
1405     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
1406     struct DeviceInfo *deviceInfo;
1407     HKEY key = INVALID_HANDLE_VALUE;
1408     DWORD rc;
1409     HKEY hHWProfileKey = INVALID_HANDLE_VALUE;
1410     HKEY hKey = NULL;
1411     HKEY RootKey;
1412 
1413     TRACE("%s(%p %p %lu %lu %lu %p %s)\n", __FUNCTION__, DeviceInfoSet, DeviceInfoData, Scope,
1414             HwProfile, KeyType, InfHandle, debugstr_w(InfSectionName));
1415 
1416     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
1417     {
1418         SetLastError(ERROR_INVALID_HANDLE);
1419         return INVALID_HANDLE_VALUE;
1420     }
1421     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
1422     {
1423         SetLastError(ERROR_INVALID_HANDLE);
1424         return INVALID_HANDLE_VALUE;
1425     }
1426     if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
1427             || !DeviceInfoData->Reserved)
1428     {
1429         SetLastError(ERROR_INVALID_PARAMETER);
1430         return INVALID_HANDLE_VALUE;
1431     }
1432     if (Scope != DICS_FLAG_GLOBAL && Scope != DICS_FLAG_CONFIGSPECIFIC)
1433     {
1434         SetLastError(ERROR_INVALID_FLAGS);
1435         return INVALID_HANDLE_VALUE;
1436     }
1437     if (KeyType != DIREG_DEV && KeyType != DIREG_DRV)
1438     {
1439         SetLastError(ERROR_INVALID_FLAGS);
1440         return INVALID_HANDLE_VALUE;
1441     }
1442     if (InfHandle && !InfSectionName)
1443     {
1444         SetLastError(ERROR_INVALID_PARAMETER);
1445         return INVALID_HANDLE_VALUE;
1446     }
1447     if (!InfHandle && InfSectionName)
1448     {
1449         SetLastError(ERROR_INVALID_PARAMETER);
1450         return INVALID_HANDLE_VALUE;
1451     }
1452 
1453     deviceInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
1454 
1455         if (Scope == DICS_FLAG_GLOBAL)
1456             RootKey = set->HKLM;
1457         else /* Scope == DICS_FLAG_CONFIGSPECIFIC */
1458         {
1459             hHWProfileKey = OpenHardwareProfileKey(set->HKLM, HwProfile, KEY_CREATE_SUB_KEY);
1460             if (hHWProfileKey == INVALID_HANDLE_VALUE)
1461                 goto cleanup;
1462             RootKey = hHWProfileKey;
1463         }
1464 
1465         if (KeyType == DIREG_DEV)
1466         {
1467 #if _WIN32_WINNT >= 0x502
1468             hKey = SETUPDI_CreateDevKey(RootKey, deviceInfo, KEY_READ | KEY_WRITE);
1469 #else
1470             hKey = SETUPDI_CreateDevKey(RootKey, deviceInfo, KEY_ALL_ACCESS);
1471 #endif
1472             if (hKey == INVALID_HANDLE_VALUE)
1473                 goto cleanup;
1474 
1475             if (Scope == DICS_FLAG_GLOBAL)
1476             {
1477                 HKEY hTempKey = hKey;
1478 
1479                 rc = RegCreateKeyExW(hTempKey,
1480                                      L"Device Parameters",
1481                                      0,
1482                                      NULL,
1483                                      REG_OPTION_NON_VOLATILE,
1484 #if _WIN32_WINNT >= 0x502
1485                                      KEY_READ | KEY_WRITE,
1486 #else
1487                                      KEY_ALL_ACCESS,
1488 #endif
1489                                      NULL,
1490                                      &hKey,
1491                                      NULL);
1492                 if (rc == ERROR_SUCCESS)
1493                     RegCloseKey(hTempKey);
1494             }
1495         }
1496         else /* KeyType == DIREG_DRV */
1497         {
1498 #if _WIN32_WINNT >= 0x502
1499             hKey = SETUPDI_CreateDrvKey(RootKey, deviceInfo, (UUID*)&DeviceInfoData->ClassGuid, KEY_READ | KEY_WRITE);
1500 #else
1501             hKey = SETUPDI_CreateDrvKey(RootKey, deviceInfo, (UUID*)&DeviceInfoData->ClassGuid, KEY_ALL_ACCESS);
1502 #endif
1503             if (hKey == INVALID_HANDLE_VALUE)
1504                 goto cleanup;
1505         }
1506 
1507         /* Do installation of the specified section */
1508         if (InfHandle)
1509         {
1510             FIXME("Need to install section %s in file %p\n",
1511                 debugstr_w(InfSectionName), InfHandle);
1512         }
1513         key = hKey;
1514 
1515 cleanup:
1516         if (hHWProfileKey != INVALID_HANDLE_VALUE)
1517             RegCloseKey(hHWProfileKey);
1518         if (hKey != NULL && hKey != key)
1519             RegCloseKey(hKey);
1520 
1521     TRACE("Returning 0x%p\n", key);
1522     return key;
1523 }
1524 
1525 /***********************************************************************
1526  *              SetupDiCreateDeviceInfoA (SETUPAPI.@)
1527  */
1528 BOOL WINAPI SetupDiCreateDeviceInfoA(
1529         HDEVINFO DeviceInfoSet,
1530         PCSTR DeviceName,
1531         CONST GUID *ClassGuid,
1532         PCSTR DeviceDescription,
1533         HWND hwndParent,
1534         DWORD CreationFlags,
1535         PSP_DEVINFO_DATA DeviceInfoData)
1536 {
1537     BOOL ret;
1538     LPWSTR DeviceNameW = NULL;
1539     LPWSTR DeviceDescriptionW = NULL;
1540 
1541     TRACE("\n");
1542 
1543     if (DeviceName)
1544     {
1545         DeviceNameW = pSetupMultiByteToUnicode(DeviceName, CP_ACP);
1546         if (DeviceNameW == NULL) return FALSE;
1547     }
1548     if (DeviceDescription)
1549     {
1550         DeviceDescriptionW = pSetupMultiByteToUnicode(DeviceDescription, CP_ACP);
1551         if (DeviceDescriptionW == NULL)
1552         {
1553             MyFree(DeviceNameW);
1554             return FALSE;
1555         }
1556     }
1557 
1558     ret = SetupDiCreateDeviceInfoW(DeviceInfoSet, DeviceNameW, ClassGuid, DeviceDescriptionW,
1559             hwndParent, CreationFlags, DeviceInfoData);
1560 
1561     MyFree(DeviceNameW);
1562     MyFree(DeviceDescriptionW);
1563 
1564     return ret;
1565 }
1566 
1567 /***********************************************************************
1568  *              SetupDiCreateDeviceInfoW (SETUPAPI.@)
1569  */
1570 BOOL WINAPI SetupDiCreateDeviceInfoW(
1571         HDEVINFO DeviceInfoSet,
1572         PCWSTR DeviceName,
1573         CONST GUID *ClassGuid,
1574         PCWSTR DeviceDescription,
1575         HWND hwndParent,
1576         DWORD CreationFlags,
1577         PSP_DEVINFO_DATA DeviceInfoData)
1578 {
1579     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
1580     struct DeviceInfo *deviceInfo = NULL;
1581     BOOL ret = FALSE;
1582     CONFIGRET cr;
1583     DEVINST RootDevInst;
1584     DEVINST DevInst;
1585     WCHAR GenInstanceId[MAX_DEVICE_ID_LEN];
1586 
1587     TRACE("%s(%p %s %s %s %p %x %p)\n", __FUNCTION__, DeviceInfoSet, debugstr_w(DeviceName),
1588         debugstr_guid(ClassGuid), debugstr_w(DeviceDescription),
1589         hwndParent, CreationFlags, DeviceInfoData);
1590 
1591     if (!DeviceName)
1592     {
1593         SetLastError(ERROR_INVALID_DEVINST_NAME);
1594         return FALSE;
1595     }
1596     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
1597     {
1598         SetLastError(ERROR_INVALID_HANDLE);
1599         return FALSE;
1600     }
1601     if (!ClassGuid)
1602     {
1603         SetLastError(ERROR_INVALID_PARAMETER);
1604         return FALSE;
1605     }
1606     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
1607     {
1608         SetLastError(ERROR_INVALID_HANDLE);
1609         return FALSE;
1610     }
1611     if (!IsEqualGUID(&set->ClassGuid, &GUID_NULL) &&
1612         !IsEqualGUID(ClassGuid, &set->ClassGuid))
1613     {
1614         SetLastError(ERROR_CLASS_MISMATCH);
1615         return FALSE;
1616     }
1617     if (CreationFlags & ~(DICD_GENERATE_ID | DICD_INHERIT_CLASSDRVS))
1618     {
1619         TRACE("Unknown flags: 0x%08lx\n", CreationFlags & ~(DICD_GENERATE_ID | DICD_INHERIT_CLASSDRVS));
1620         SetLastError(ERROR_INVALID_FLAGS);
1621         return FALSE;
1622     }
1623 
1624     /* Get the root device instance */
1625     cr = CM_Locate_DevInst_ExW(&RootDevInst,
1626                                NULL,
1627                                CM_LOCATE_DEVINST_NORMAL,
1628                                set->hMachine);
1629     if (cr != CR_SUCCESS)
1630     {
1631         SetLastError(ERROR_INVALID_DATA);
1632         return FALSE;
1633     }
1634 
1635     /* Create the new device instance */
1636     cr = CM_Create_DevInst_ExW(&DevInst,
1637                                (DEVINSTID)DeviceName,
1638                                RootDevInst,
1639                                (CreationFlags & DICD_GENERATE_ID) ?
1640                                      CM_CREATE_DEVINST_GENERATE_ID : 0,
1641                                set->hMachine);
1642     if (cr != CR_SUCCESS)
1643     {
1644         SetLastError(GetErrorCodeFromCrCode(cr));
1645         return FALSE;
1646     }
1647 
1648     if (CreationFlags & DICD_GENERATE_ID)
1649     {
1650         /* Grab the actual instance ID that was created */
1651         cr = CM_Get_Device_ID_Ex(DevInst,
1652                                  GenInstanceId,
1653                                  MAX_DEVICE_ID_LEN,
1654                                  0,
1655                                  set->hMachine);
1656         if (cr != CR_SUCCESS)
1657         {
1658             SetLastError(GetErrorCodeFromCrCode(cr));
1659             return FALSE;
1660         }
1661 
1662         DeviceName = GenInstanceId;
1663         TRACE("Using generated instance ID: %s\n", debugstr_w(DeviceName));
1664     }
1665 
1666     if (CreateDeviceInfo(set, DeviceName, ClassGuid, &deviceInfo))
1667     {
1668         InsertTailList(&set->ListHead, &deviceInfo->ListEntry);
1669 
1670         if (!DeviceInfoData)
1671             ret = TRUE;
1672         else
1673         {
1674             if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
1675             {
1676                 SetLastError(ERROR_INVALID_USER_BUFFER);
1677             }
1678             else
1679             {
1680                 memcpy(&DeviceInfoData->ClassGuid, ClassGuid, sizeof(GUID));
1681                 DeviceInfoData->DevInst = deviceInfo->dnDevInst;
1682                 DeviceInfoData->Reserved = (ULONG_PTR)deviceInfo;
1683                 ret = TRUE;
1684             }
1685         }
1686     }
1687 
1688     if (ret == FALSE)
1689     {
1690         if (deviceInfo != NULL)
1691         {
1692             /* Remove deviceInfo from List */
1693             RemoveEntryList(&deviceInfo->ListEntry);
1694 
1695             /* Destroy deviceInfo */
1696             DestroyDeviceInfo(deviceInfo);
1697         }
1698     }
1699 
1700     TRACE("Returning %d\n", ret);
1701     return ret;
1702 }
1703 
1704 /***********************************************************************
1705  *		SetupDiRegisterDeviceInfo (SETUPAPI.@)
1706  */
1707 BOOL WINAPI SetupDiRegisterDeviceInfo(
1708         HDEVINFO DeviceInfoSet,
1709         PSP_DEVINFO_DATA DeviceInfoData,
1710         DWORD Flags,
1711         PSP_DETSIG_CMPPROC CompareProc,
1712         PVOID CompareContext,
1713         PSP_DEVINFO_DATA DupDeviceInfoData)
1714 {
1715     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
1716     WCHAR DevInstId[MAX_DEVICE_ID_LEN];
1717     DEVINST ParentDevInst;
1718     CONFIGRET cr;
1719     DWORD dwError = ERROR_SUCCESS;
1720 
1721     TRACE("%s(%p %p %08x %p %p %p)\n", __FUNCTION__, DeviceInfoSet, DeviceInfoData, Flags,
1722             CompareProc, CompareContext, DupDeviceInfoData);
1723 
1724     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
1725     {
1726         SetLastError(ERROR_INVALID_HANDLE);
1727         return FALSE;
1728     }
1729     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
1730     {
1731         SetLastError(ERROR_INVALID_HANDLE);
1732         return FALSE;
1733     }
1734     if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
1735             || !DeviceInfoData->Reserved)
1736     {
1737         SetLastError(ERROR_INVALID_PARAMETER);
1738         return FALSE;
1739     }
1740 
1741     if (Flags & ~SPRDI_FIND_DUPS)
1742     {
1743         TRACE("Unknown flags: 0x%08lx\n", Flags & ~SPRDI_FIND_DUPS);
1744         SetLastError(ERROR_INVALID_FLAGS);
1745         return FALSE;
1746     }
1747 
1748     if (Flags & SPRDI_FIND_DUPS)
1749     {
1750         FIXME("Unimplemented codepath!\n");
1751     }
1752 
1753     CM_Get_Device_ID_Ex(DeviceInfoData->DevInst,
1754                         DevInstId,
1755                         MAX_DEVICE_ID_LEN,
1756                         0,
1757                         set->hMachine);
1758 
1759     CM_Get_Parent_Ex(&ParentDevInst,
1760                      DeviceInfoData->DevInst,
1761                      0,
1762                      set->hMachine);
1763 
1764     cr = CM_Create_DevInst_Ex(&DeviceInfoData->DevInst,
1765                               DevInstId,
1766                               ParentDevInst,
1767                               CM_CREATE_DEVINST_NORMAL | CM_CREATE_DEVINST_DO_NOT_INSTALL,
1768                               set->hMachine);
1769     if (cr != CR_SUCCESS &&
1770         cr != CR_ALREADY_SUCH_DEVINST)
1771     {
1772         dwError = ERROR_NO_SUCH_DEVINST;
1773     }
1774 
1775     SetLastError(dwError);
1776 
1777     return (dwError == ERROR_SUCCESS);
1778 }
1779 
1780 /***********************************************************************
1781  *		SetupDiEnumDeviceInfo (SETUPAPI.@)
1782  */
1783 BOOL WINAPI SetupDiEnumDeviceInfo(
1784         HDEVINFO  devinfo,
1785         DWORD  index,
1786         PSP_DEVINFO_DATA info)
1787 {
1788     BOOL ret = FALSE;
1789 
1790     TRACE("%s(%p %d %p)\n", __FUNCTION__, devinfo, index, info);
1791 
1792     if(info==NULL)
1793     {
1794         SetLastError(ERROR_INVALID_PARAMETER);
1795         return FALSE;
1796     }
1797     if (devinfo && devinfo != INVALID_HANDLE_VALUE)
1798     {
1799         struct DeviceInfoSet *list = (struct DeviceInfoSet *)devinfo;
1800         if (list->magic == SETUP_DEVICE_INFO_SET_MAGIC)
1801         {
1802             if (info->cbSize != sizeof(SP_DEVINFO_DATA))
1803                 SetLastError(ERROR_INVALID_USER_BUFFER);
1804             else
1805             {
1806                 PLIST_ENTRY ItemList = list->ListHead.Flink;
1807                 while (ItemList != &list->ListHead && index-- > 0)
1808                     ItemList = ItemList->Flink;
1809                 if (ItemList == &list->ListHead)
1810                     SetLastError(ERROR_NO_MORE_ITEMS);
1811                 else
1812                 {
1813                     struct DeviceInfo *DevInfo = CONTAINING_RECORD(ItemList, struct DeviceInfo, ListEntry);
1814                     memcpy(&info->ClassGuid,
1815                         &DevInfo->ClassGuid,
1816                         sizeof(GUID));
1817                     info->DevInst = DevInfo->dnDevInst;
1818                     info->Reserved = (ULONG_PTR)DevInfo;
1819                     ret = TRUE;
1820                 }
1821             }
1822         }
1823         else
1824             SetLastError(ERROR_INVALID_HANDLE);
1825     }
1826     else
1827         SetLastError(ERROR_INVALID_HANDLE);
1828     return ret;
1829 }
1830 
1831 /***********************************************************************
1832  *		SetupDiGetDeviceInstanceIdA (SETUPAPI.@)
1833  */
1834 BOOL WINAPI SetupDiGetDeviceInstanceIdA(
1835         HDEVINFO DeviceInfoSet,
1836         PSP_DEVINFO_DATA DeviceInfoData,
1837         PSTR DeviceInstanceId,
1838         DWORD DeviceInstanceIdSize,
1839         PDWORD RequiredSize)
1840 {
1841     BOOL ret = FALSE;
1842     DWORD size;
1843     PWSTR instanceId;
1844 
1845     TRACE("%s(%p %p %p %d %p)\n", __FUNCTION__, DeviceInfoSet, DeviceInfoData, DeviceInstanceId,
1846             DeviceInstanceIdSize, RequiredSize);
1847 
1848     if (!DeviceInstanceId && DeviceInstanceIdSize > 0)
1849     {
1850         SetLastError(ERROR_INVALID_PARAMETER);
1851         return FALSE;
1852     }
1853 
1854     ret = SetupDiGetDeviceInstanceIdW(DeviceInfoSet,
1855                                 DeviceInfoData,
1856                                 NULL,
1857                                 0,
1858                                 &size);
1859     if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
1860         return FALSE;
1861     instanceId = MyMalloc(size * sizeof(WCHAR));
1862     if (instanceId)
1863     {
1864         ret = SetupDiGetDeviceInstanceIdW(DeviceInfoSet,
1865                                           DeviceInfoData,
1866                                           instanceId,
1867                                           size,
1868                                           &size);
1869         if (ret)
1870         {
1871             int len = WideCharToMultiByte(CP_ACP, 0, instanceId, -1,
1872                                           DeviceInstanceId,
1873                                           DeviceInstanceIdSize, NULL, NULL);
1874 
1875             if (!len)
1876                 ret = FALSE;
1877             else
1878             {
1879                 if (len > DeviceInstanceIdSize)
1880                 {
1881                     SetLastError(ERROR_INSUFFICIENT_BUFFER);
1882                     ret = FALSE;
1883                 }
1884                 if (RequiredSize)
1885                     *RequiredSize = len;
1886             }
1887         }
1888         MyFree(instanceId);
1889     }
1890     else
1891     {
1892         if (RequiredSize)
1893             *RequiredSize = size;
1894         SetLastError(ERROR_INSUFFICIENT_BUFFER);
1895         ret = FALSE;
1896     }
1897     return ret;
1898 }
1899 
1900 /***********************************************************************
1901  *		SetupDiGetDeviceInstanceIdW (SETUPAPI.@)
1902  */
1903 BOOL WINAPI SetupDiGetDeviceInstanceIdW(
1904         HDEVINFO DeviceInfoSet,
1905         PSP_DEVINFO_DATA DeviceInfoData,
1906         PWSTR DeviceInstanceId,
1907         DWORD DeviceInstanceIdSize,
1908         PDWORD RequiredSize)
1909 {
1910     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
1911     struct DeviceInfo *devInfo;
1912 
1913     TRACE("%s(%p %p %p %d %p)\n", __FUNCTION__, DeviceInfoSet, DeviceInfoData, DeviceInstanceId,
1914             DeviceInstanceIdSize, RequiredSize);
1915 
1916     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
1917     {
1918         SetLastError(ERROR_INVALID_HANDLE);
1919         return FALSE;
1920     }
1921     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
1922     {
1923         SetLastError(ERROR_INVALID_HANDLE);
1924         return FALSE;
1925     }
1926     if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
1927             || !DeviceInfoData->Reserved)
1928     {
1929         SetLastError(ERROR_INVALID_PARAMETER);
1930         return FALSE;
1931     }
1932     devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
1933     if (!DeviceInstanceId && DeviceInstanceIdSize > 0)
1934     {
1935         SetLastError(ERROR_INVALID_PARAMETER);
1936         return FALSE;
1937     }
1938     if (DeviceInstanceId && DeviceInstanceIdSize == 0)
1939     {
1940         SetLastError(ERROR_INVALID_PARAMETER);
1941         return FALSE;
1942     }
1943     TRACE("instance ID: %s\n", debugstr_w(devInfo->instanceId));
1944     if (DeviceInstanceIdSize < lstrlenW(devInfo->instanceId) + 1)
1945     {
1946         SetLastError(ERROR_INSUFFICIENT_BUFFER);
1947         if (RequiredSize)
1948             *RequiredSize = lstrlenW(devInfo->instanceId) + 1;
1949         return FALSE;
1950     }
1951     lstrcpyW(DeviceInstanceId, devInfo->instanceId);
1952     if (RequiredSize)
1953         *RequiredSize = lstrlenW(devInfo->instanceId) + 1;
1954     return TRUE;
1955 }
1956 
1957 /***********************************************************************
1958  *		SetupDiGetActualSectionToInstallA (SETUPAPI.@)
1959  */
1960 BOOL WINAPI SetupDiGetActualSectionToInstallA(
1961         HINF InfHandle,
1962         PCSTR InfSectionName,
1963         PSTR InfSectionWithExt,
1964         DWORD InfSectionWithExtSize,
1965         PDWORD RequiredSize,
1966         PSTR *Extension)
1967 {
1968     return SetupDiGetActualSectionToInstallExA(InfHandle, InfSectionName,
1969         NULL, InfSectionWithExt, InfSectionWithExtSize, RequiredSize,
1970         Extension, NULL);
1971 }
1972 
1973 /***********************************************************************
1974  *		SetupDiGetActualSectionToInstallW (SETUPAPI.@)
1975  */
1976 BOOL WINAPI SetupDiGetActualSectionToInstallW(
1977         HINF InfHandle,
1978         PCWSTR InfSectionName,
1979         PWSTR InfSectionWithExt,
1980         DWORD InfSectionWithExtSize,
1981         PDWORD RequiredSize,
1982         PWSTR *Extension)
1983 {
1984     return SetupDiGetActualSectionToInstallExW(InfHandle, InfSectionName,
1985         NULL, InfSectionWithExt, InfSectionWithExtSize, RequiredSize,
1986         Extension, NULL);
1987 }
1988 
1989 /***********************************************************************
1990  *		SetupDiGetActualSectionToInstallExA  (SETUPAPI.@)
1991  */
1992 BOOL WINAPI
1993 SetupDiGetActualSectionToInstallExA(
1994         IN HINF InfHandle,
1995         IN PCSTR InfSectionName,
1996         IN PSP_ALTPLATFORM_INFO AlternatePlatformInfo OPTIONAL,
1997         OUT PSTR InfSectionWithExt OPTIONAL,
1998         IN DWORD InfSectionWithExtSize,
1999         OUT PDWORD RequiredSize OPTIONAL,
2000         OUT PSTR* Extension OPTIONAL,
2001         IN PVOID Reserved)
2002 {
2003     LPWSTR InfSectionNameW = NULL;
2004     LPWSTR InfSectionWithExtW = NULL;
2005     PWSTR ExtensionW;
2006     BOOL bResult = FALSE;
2007 
2008     TRACE("%s()\n", __FUNCTION__);
2009 
2010     if (InfSectionName)
2011     {
2012         InfSectionNameW = pSetupMultiByteToUnicode(InfSectionName, CP_ACP);
2013         if (InfSectionNameW == NULL)
2014             goto cleanup;
2015     }
2016     if (InfSectionWithExt)
2017     {
2018         InfSectionWithExtW = MyMalloc(InfSectionWithExtSize * sizeof(WCHAR));
2019         if (InfSectionWithExtW == NULL)
2020             goto cleanup;
2021     }
2022 
2023     bResult = SetupDiGetActualSectionToInstallExW(
2024         InfHandle, InfSectionNameW, AlternatePlatformInfo,
2025         InfSectionWithExt ? InfSectionWithExtW : NULL,
2026         InfSectionWithExtSize,
2027         RequiredSize,
2028         Extension ? &ExtensionW : NULL,
2029         Reserved);
2030 
2031     if (bResult && InfSectionWithExt)
2032     {
2033          bResult = WideCharToMultiByte(CP_ACP, 0, InfSectionWithExtW, -1, InfSectionWithExt,
2034              InfSectionWithExtSize, NULL, NULL) != 0;
2035     }
2036     if (bResult && Extension)
2037     {
2038         if (ExtensionW == NULL)
2039             *Extension = NULL;
2040          else
2041             *Extension = &InfSectionWithExt[ExtensionW - InfSectionWithExtW];
2042     }
2043 
2044 cleanup:
2045     MyFree(InfSectionNameW);
2046     MyFree(InfSectionWithExtW);
2047 
2048     return bResult;
2049 }
2050 
2051 /***********************************************************************
2052  *		SetupDiGetClassDescriptionA  (SETUPAPI.@)
2053  */
2054 BOOL WINAPI SetupDiGetClassDescriptionA(
2055         const GUID* ClassGuid,
2056         PSTR ClassDescription,
2057         DWORD ClassDescriptionSize,
2058         PDWORD RequiredSize)
2059 {
2060     return SetupDiGetClassDescriptionExA(ClassGuid, ClassDescription,
2061                                          ClassDescriptionSize,
2062                                          RequiredSize, NULL, NULL);
2063 }
2064 
2065 /***********************************************************************
2066  *		SetupDiGetClassDescriptionW  (SETUPAPI.@)
2067  */
2068 BOOL WINAPI SetupDiGetClassDescriptionW(
2069         const GUID* ClassGuid,
2070         PWSTR ClassDescription,
2071         DWORD ClassDescriptionSize,
2072         PDWORD RequiredSize)
2073 {
2074     return SetupDiGetClassDescriptionExW(ClassGuid, ClassDescription,
2075                                          ClassDescriptionSize,
2076                                          RequiredSize, NULL, NULL);
2077 }
2078 
2079 /***********************************************************************
2080  *		SetupDiGetClassDescriptionExA  (SETUPAPI.@)
2081  */
2082 BOOL WINAPI SetupDiGetClassDescriptionExA(
2083         const GUID* ClassGuid,
2084         PSTR ClassDescription,
2085         DWORD ClassDescriptionSize,
2086         PDWORD RequiredSize,
2087         PCSTR MachineName,
2088         PVOID Reserved)
2089 {
2090     PWCHAR ClassDescriptionW = NULL;
2091     LPWSTR MachineNameW = NULL;
2092     BOOL ret = FALSE;
2093 
2094     TRACE("%s(%s %p %lu %p %s %p)\n", __FUNCTION__, debugstr_guid(ClassGuid), ClassDescription,
2095         ClassDescriptionSize, RequiredSize, debugstr_a(MachineName), Reserved);
2096 
2097     if (ClassDescriptionSize > 0)
2098     {
2099         ClassDescriptionW = MyMalloc(ClassDescriptionSize * sizeof(WCHAR));
2100         if (!ClassDescriptionW)
2101         {
2102             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2103             goto cleanup;
2104         }
2105     }
2106 
2107     if (MachineName)
2108     {
2109         MachineNameW = pSetupMultiByteToUnicode(MachineName, CP_ACP);
2110         if (!MachineNameW)
2111         {
2112             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2113             goto cleanup;
2114         }
2115     }
2116 
2117     ret = SetupDiGetClassDescriptionExW(ClassGuid, ClassDescriptionW,
2118         ClassDescriptionSize * sizeof(WCHAR), RequiredSize, MachineNameW, Reserved);
2119     if (ret)
2120     {
2121         DWORD len = (DWORD)WideCharToMultiByte(CP_ACP, 0, ClassDescriptionW, -1, ClassDescription,
2122             ClassDescriptionSize, NULL, NULL);
2123         if (len == 0 || len > ClassDescriptionSize)
2124         {
2125             SetLastError(ERROR_INSUFFICIENT_BUFFER);
2126             ret = FALSE;
2127         }
2128     }
2129 
2130 cleanup:
2131     MyFree(ClassDescriptionW);
2132     MyFree(MachineNameW);
2133     return ret;
2134 }
2135 
2136 /***********************************************************************
2137  *		SetupDiGetClassDescriptionExW  (SETUPAPI.@)
2138  */
2139 BOOL WINAPI SetupDiGetClassDescriptionExW(
2140         const GUID* ClassGuid,
2141         PWSTR ClassDescription,
2142         DWORD ClassDescriptionSize,
2143         PDWORD RequiredSize,
2144         PCWSTR MachineName,
2145         PVOID Reserved)
2146 {
2147     HKEY hKey;
2148     DWORD dwLength;
2149     DWORD dwRegType;
2150     LONG rc;
2151     PWSTR Buffer;
2152 
2153     TRACE("%s(%s %p %lu %p %s %p)\n", __FUNCTION__, debugstr_guid(ClassGuid), ClassDescription,
2154         ClassDescriptionSize, RequiredSize, debugstr_w(MachineName), Reserved);
2155 
2156     /* Make sure there's a GUID */
2157     if (!ClassGuid)
2158     {
2159         SetLastError(ERROR_INVALID_PARAMETER);
2160         return FALSE;
2161     }
2162 
2163     /* Make sure there's a real buffer when there's a size */
2164     if (!ClassDescription && ClassDescriptionSize > 0)
2165     {
2166         SetLastError(ERROR_INVALID_PARAMETER);
2167         return FALSE;
2168     }
2169 
2170     /* Open the key for the GUID */
2171     hKey = SetupDiOpenClassRegKeyExW(ClassGuid,
2172                                      KEY_QUERY_VALUE,
2173                                      DIOCR_INSTALLER,
2174                                      MachineName,
2175                                      Reserved);
2176     if (hKey == INVALID_HANDLE_VALUE)
2177         return FALSE;
2178 
2179     /* Retrieve the class description data and close the key */
2180     rc = QueryRegistryValue(hKey, NULL, (LPBYTE *) &Buffer, &dwRegType, &dwLength);
2181     RegCloseKey(hKey);
2182 
2183     /* Make sure we got the data */
2184     if (rc != ERROR_SUCCESS)
2185     {
2186         SetLastError(rc);
2187         return FALSE;
2188     }
2189 
2190     /* Make sure the data is a string */
2191     if (dwRegType != REG_SZ)
2192     {
2193         MyFree(Buffer);
2194         SetLastError(ERROR_GEN_FAILURE);
2195         return FALSE;
2196     }
2197 
2198     /* Determine the length of the class description */
2199     dwLength /= sizeof(WCHAR);
2200 
2201     /* Count the null-terminator if none is present */
2202     if ((dwLength == 0) || (Buffer[dwLength - 1] != UNICODE_NULL))
2203         dwLength++;
2204 
2205     /* Inform the caller about the class description */
2206     if ((ClassDescription != NULL) && (dwLength <= ClassDescriptionSize))
2207     {
2208         memcpy(ClassDescription, Buffer, (dwLength - 1) * sizeof(WCHAR));
2209         ClassDescription[dwLength - 1] = UNICODE_NULL;
2210     }
2211 
2212     /* Inform the caller about the required size */
2213     if (RequiredSize != NULL)
2214         *RequiredSize = dwLength;
2215 
2216     /* Clean up the buffer */
2217     MyFree(Buffer);
2218 
2219     /* Make sure the buffer was large enough */
2220     if ((ClassDescription == NULL) || (dwLength > ClassDescriptionSize))
2221     {
2222         SetLastError(ERROR_INSUFFICIENT_BUFFER);
2223         return FALSE;
2224     }
2225 
2226     return TRUE;
2227 }
2228 
2229 /***********************************************************************
2230  *		SetupDiGetClassDevsA (SETUPAPI.@)
2231  */
2232 HDEVINFO WINAPI SetupDiGetClassDevsA(
2233         CONST GUID *class,
2234         LPCSTR enumstr,
2235         HWND parent,
2236         DWORD flags)
2237 {
2238     return SetupDiGetClassDevsExA(class, enumstr, parent,
2239                                   flags, NULL, NULL, NULL);
2240 }
2241 
2242 /***********************************************************************
2243  *		  SetupDiGetClassDevsExA (SETUPAPI.@)
2244  */
2245 HDEVINFO WINAPI SetupDiGetClassDevsExA(
2246         const GUID *class,
2247         PCSTR enumstr,
2248         HWND parent,
2249         DWORD flags,
2250         HDEVINFO deviceset,
2251         PCSTR machine,
2252         PVOID reserved)
2253 {
2254     HDEVINFO ret;
2255     LPWSTR enumstrW = NULL, machineW = NULL;
2256 
2257     if (enumstr)
2258     {
2259         enumstrW = pSetupMultiByteToUnicode(enumstr, CP_ACP);
2260         if (!enumstrW)
2261         {
2262             ret = INVALID_HANDLE_VALUE;
2263             goto end;
2264         }
2265     }
2266     if (machine)
2267     {
2268         machineW = pSetupMultiByteToUnicode(machine, CP_ACP);
2269         if (!machineW)
2270         {
2271             MyFree(enumstrW);
2272             ret = INVALID_HANDLE_VALUE;
2273             goto end;
2274         }
2275     }
2276     ret = SetupDiGetClassDevsExW(class, enumstrW, parent, flags, deviceset,
2277             machineW, reserved);
2278     MyFree(enumstrW);
2279     MyFree(machineW);
2280 
2281 end:
2282     return ret;
2283 }
2284 
2285 /***********************************************************************
2286  *		SetupDiGetClassDevsW (SETUPAPI.@)
2287  */
2288 HDEVINFO WINAPI SetupDiGetClassDevsW(
2289         CONST GUID *class,
2290         LPCWSTR enumstr,
2291         HWND parent,
2292         DWORD flags)
2293 {
2294     return SetupDiGetClassDevsExW(class, enumstr, parent, flags, NULL, NULL,
2295             NULL);
2296 }
2297 
2298 /***********************************************************************
2299  *              SetupDiGetClassDevsExW (SETUPAPI.@)
2300  */
2301 HDEVINFO WINAPI SetupDiGetClassDevsExW(
2302         CONST GUID *class,
2303         PCWSTR enumstr,
2304         HWND parent,
2305         DWORD flags,
2306         HDEVINFO deviceset,
2307         PCWSTR machine,
2308         PVOID reserved)
2309 {
2310     HDEVINFO hDeviceInfo = INVALID_HANDLE_VALUE;
2311     struct DeviceInfoSet *list;
2312     CONST GUID *pClassGuid;
2313     LONG rc;
2314     HDEVINFO set = INVALID_HANDLE_VALUE;
2315 
2316     TRACE("%s(%s %s %p 0x%08x %p %s %p)\n", __FUNCTION__, debugstr_guid(class),
2317             debugstr_w(enumstr), parent, flags, deviceset, debugstr_w(machine),
2318             reserved);
2319 
2320     if (!(flags & DIGCF_ALLCLASSES) && !class)
2321     {
2322         SetLastError(ERROR_INVALID_PARAMETER);
2323         return INVALID_HANDLE_VALUE;
2324     }
2325 
2326     /* Create the deviceset if not set */
2327     if (deviceset)
2328     {
2329         list = (struct DeviceInfoSet *)deviceset;
2330         if (list->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2331         {
2332             SetLastError(ERROR_INVALID_HANDLE);
2333             goto cleanup;
2334         }
2335         hDeviceInfo = deviceset;
2336     }
2337     else
2338     {
2339          hDeviceInfo = SetupDiCreateDeviceInfoListExW(
2340              flags & (DIGCF_DEVICEINTERFACE | DIGCF_ALLCLASSES) ? NULL : class,
2341              NULL, machine, NULL);
2342          if (hDeviceInfo == INVALID_HANDLE_VALUE)
2343              goto cleanup;
2344          list = (struct DeviceInfoSet *)hDeviceInfo;
2345     }
2346 
2347     if (flags & DIGCF_PROFILE)
2348         FIXME(": flag DIGCF_PROFILE ignored\n");
2349 
2350     if (flags & DIGCF_DEVICEINTERFACE)
2351     {
2352         if (!class)
2353         {
2354             SetLastError(ERROR_INVALID_PARAMETER);
2355             goto cleanup;
2356         }
2357         rc = SETUP_CreateInterfaceList(list, machine, class, enumstr, flags & DIGCF_PRESENT);
2358     }
2359     else
2360     {
2361         /* Determine which class(es) should be included in the deviceset */
2362         if (flags & DIGCF_ALLCLASSES)
2363         {
2364             /* The caller wants all classes. Check if
2365              * the deviceset limits us to one class */
2366             if (IsEqualIID(&list->ClassGuid, &GUID_NULL))
2367                 pClassGuid = NULL;
2368             else
2369                 pClassGuid = &list->ClassGuid;
2370         }
2371         else if (class)
2372         {
2373             /* The caller wants one class. Check if it matches deviceset class */
2374             if (IsEqualIID(&list->ClassGuid, class)
2375              || IsEqualIID(&list->ClassGuid, &GUID_NULL))
2376             {
2377                 pClassGuid = class;
2378             }
2379             else
2380             {
2381                 SetLastError(ERROR_INVALID_PARAMETER);
2382                 goto cleanup;
2383             }
2384         }
2385         else if (!IsEqualIID(&list->ClassGuid, &GUID_NULL))
2386         {
2387             /* No class specified. Try to use the one of the deviceset */
2388             if (IsEqualIID(&list->ClassGuid, &GUID_NULL))
2389                 pClassGuid = &list->ClassGuid;
2390             else
2391             {
2392                 SetLastError(ERROR_INVALID_PARAMETER);
2393                 goto cleanup;
2394             }
2395         }
2396         else
2397         {
2398             SetLastError(ERROR_INVALID_PARAMETER);
2399             goto cleanup;
2400         }
2401         rc = SETUP_CreateDevicesList(list, machine, pClassGuid, enumstr);
2402     }
2403     if (rc != ERROR_SUCCESS)
2404     {
2405         SetLastError(rc);
2406         goto cleanup;
2407     }
2408     set = hDeviceInfo;
2409 
2410 cleanup:
2411     if (!deviceset && hDeviceInfo != INVALID_HANDLE_VALUE && hDeviceInfo != set)
2412         SetupDiDestroyDeviceInfoList(hDeviceInfo);
2413     return set;
2414 }
2415 
2416 /***********************************************************************
2417  *		SetupDiGetDeviceInfoListDetailA  (SETUPAPI.@)
2418  */
2419 BOOL WINAPI SetupDiGetDeviceInfoListDetailA(
2420         HDEVINFO DeviceInfoSet,
2421         PSP_DEVINFO_LIST_DETAIL_DATA_A DevInfoData )
2422 {
2423     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2424 
2425     TRACE("%s(%p %p)\n", __FUNCTION__, DeviceInfoSet, DevInfoData);
2426 
2427     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
2428     {
2429         SetLastError(ERROR_INVALID_HANDLE);
2430         return FALSE;
2431     }
2432     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2433     {
2434         SetLastError(ERROR_INVALID_HANDLE);
2435         return FALSE;
2436     }
2437     if (!DevInfoData ||
2438             DevInfoData->cbSize != sizeof(SP_DEVINFO_LIST_DETAIL_DATA_A))
2439     {
2440         SetLastError(ERROR_INVALID_PARAMETER);
2441         return FALSE;
2442     }
2443     memcpy(&DevInfoData->ClassGuid, &set->ClassGuid, sizeof(GUID));
2444     DevInfoData->RemoteMachineHandle = set->hMachine;
2445     if (set->MachineName)
2446     {
2447         FIXME("Stub\n");
2448         SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2449         return FALSE;
2450     }
2451     else
2452         DevInfoData->RemoteMachineName[0] = 0;
2453 
2454     return TRUE;
2455 }
2456 
2457 /***********************************************************************
2458  *		SetupDiGetDeviceInfoListDetailW  (SETUPAPI.@)
2459  */
2460 BOOL WINAPI SetupDiGetDeviceInfoListDetailW(
2461         HDEVINFO DeviceInfoSet,
2462         PSP_DEVINFO_LIST_DETAIL_DATA_W DevInfoData )
2463 {
2464     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2465 
2466     TRACE("%s(%p %p)\n", __FUNCTION__, DeviceInfoSet, DevInfoData);
2467 
2468     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
2469     {
2470         SetLastError(ERROR_INVALID_HANDLE);
2471         return FALSE;
2472     }
2473     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2474     {
2475         SetLastError(ERROR_INVALID_HANDLE);
2476         return FALSE;
2477     }
2478     if (!DevInfoData ||
2479             DevInfoData->cbSize != sizeof(SP_DEVINFO_LIST_DETAIL_DATA_W))
2480     {
2481         SetLastError(ERROR_INVALID_PARAMETER);
2482         return FALSE;
2483     }
2484     memcpy(&DevInfoData->ClassGuid, &set->ClassGuid, sizeof(GUID));
2485     DevInfoData->RemoteMachineHandle = set->hMachine;
2486     if (set->MachineName)
2487         strcpyW(DevInfoData->RemoteMachineName, set->MachineName + 2);
2488     else
2489         DevInfoData->RemoteMachineName[0] = 0;
2490 
2491     return TRUE;
2492 }
2493 
2494 /***********************************************************************
2495  *		SetupDiCreateDeviceInterfaceA (SETUPAPI.@)
2496  */
2497 BOOL WINAPI SetupDiCreateDeviceInterfaceA(
2498         HDEVINFO DeviceInfoSet,
2499         PSP_DEVINFO_DATA DeviceInfoData,
2500         const GUID *InterfaceClassGuid,
2501         PCSTR ReferenceString,
2502         DWORD CreationFlags,
2503         PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
2504 {
2505     BOOL ret;
2506     LPWSTR ReferenceStringW = NULL;
2507 
2508     TRACE("%s(%p %p %s %s %08x %p)\n", __FUNCTION__, DeviceInfoSet, DeviceInfoData,
2509             debugstr_guid(InterfaceClassGuid), debugstr_a(ReferenceString),
2510             CreationFlags, DeviceInterfaceData);
2511 
2512     if (ReferenceString)
2513     {
2514         ReferenceStringW = pSetupMultiByteToUnicode(ReferenceString, CP_ACP);
2515         if (ReferenceStringW == NULL) return FALSE;
2516     }
2517 
2518     ret = SetupDiCreateDeviceInterfaceW(DeviceInfoSet, DeviceInfoData,
2519             InterfaceClassGuid, ReferenceStringW, CreationFlags,
2520             DeviceInterfaceData);
2521 
2522     MyFree(ReferenceStringW);
2523 
2524     return ret;
2525 }
2526 
2527 /***********************************************************************
2528  *		SetupDiCreateDeviceInterfaceW (SETUPAPI.@)
2529  */
2530 BOOL WINAPI SetupDiCreateDeviceInterfaceW(
2531         HDEVINFO DeviceInfoSet,
2532         PSP_DEVINFO_DATA DeviceInfoData,
2533         const GUID *InterfaceClassGuid,
2534         PCWSTR ReferenceString,
2535         DWORD CreationFlags,
2536         PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
2537 {
2538     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2539     TRACE("%s(%p %p %s %s %08x %p)\n", __FUNCTION__, DeviceInfoSet, DeviceInfoData,
2540             debugstr_guid(InterfaceClassGuid), debugstr_w(ReferenceString),
2541             CreationFlags, DeviceInterfaceData);
2542 
2543     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
2544     {
2545         SetLastError(ERROR_INVALID_HANDLE);
2546         return FALSE;
2547     }
2548     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2549     {
2550         SetLastError(ERROR_INVALID_HANDLE);
2551         return FALSE;
2552     }
2553     if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
2554             || !DeviceInfoData->Reserved)
2555     {
2556         SetLastError(ERROR_INVALID_PARAMETER);
2557         return FALSE;
2558     }
2559     if (!InterfaceClassGuid)
2560     {
2561         SetLastError(ERROR_INVALID_USER_BUFFER);
2562         return FALSE;
2563     }
2564 
2565     FIXME("%p %p %s %s %08x %p\n", DeviceInfoSet, DeviceInfoData,
2566             debugstr_guid(InterfaceClassGuid), debugstr_w(ReferenceString),
2567             CreationFlags, DeviceInterfaceData);
2568     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2569     return FALSE;
2570 }
2571 
2572 /***********************************************************************
2573  *		SetupDiCreateDeviceInterfaceRegKeyA (SETUPAPI.@)
2574  */
2575 HKEY WINAPI SetupDiCreateDeviceInterfaceRegKeyA(
2576         HDEVINFO DeviceInfoSet,
2577         PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
2578         DWORD Reserved,
2579         REGSAM samDesired,
2580         HINF InfHandle,
2581         PCSTR InfSectionName)
2582 {
2583     HKEY key;
2584     PWSTR InfSectionNameW = NULL;
2585 
2586     TRACE("%s(%p %p %d %08x %p %p)\n", __FUNCTION__, DeviceInfoSet, DeviceInterfaceData, Reserved,
2587             samDesired, InfHandle, InfSectionName);
2588     if (InfHandle)
2589     {
2590         if (!InfSectionName)
2591         {
2592             SetLastError(ERROR_INVALID_PARAMETER);
2593             return INVALID_HANDLE_VALUE;
2594         }
2595         InfSectionNameW = pSetupMultiByteToUnicode(InfSectionName, CP_ACP);
2596         if (!InfSectionNameW)
2597             return INVALID_HANDLE_VALUE;
2598     }
2599     key = SetupDiCreateDeviceInterfaceRegKeyW(DeviceInfoSet,
2600             DeviceInterfaceData, Reserved, samDesired, InfHandle,
2601             InfSectionNameW);
2602     MyFree(InfSectionNameW);
2603     return key;
2604 }
2605 
2606 /***********************************************************************
2607  *		SetupDiCreateDeviceInterfaceRegKeyW (SETUPAPI.@)
2608  */
2609 HKEY WINAPI SetupDiCreateDeviceInterfaceRegKeyW(
2610         HDEVINFO DeviceInfoSet,
2611         PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
2612         DWORD Reserved,
2613         REGSAM samDesired,
2614         HINF InfHandle,
2615         PCWSTR InfSectionName)
2616 {
2617     HKEY hKey, hDevKey;
2618     LPWSTR SymbolicLink;
2619     DWORD Length, Index;
2620     LONG rc;
2621     WCHAR bracedGuidString[39];
2622     struct DeviceInterface *DevItf;
2623     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2624 
2625     TRACE("%s(%p %p %d %08x %p %p)\n", __FUNCTION__, DeviceInfoSet, DeviceInterfaceData, Reserved,
2626             samDesired, InfHandle, InfSectionName);
2627 
2628     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE ||
2629             set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2630     {
2631         SetLastError(ERROR_INVALID_HANDLE);
2632         return INVALID_HANDLE_VALUE;
2633     }
2634     if (!DeviceInterfaceData ||
2635             DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA) ||
2636             !DeviceInterfaceData->Reserved)
2637     {
2638         SetLastError(ERROR_INVALID_PARAMETER);
2639         return INVALID_HANDLE_VALUE;
2640     }
2641     if (InfHandle && !InfSectionName)
2642     {
2643         SetLastError(ERROR_INVALID_PARAMETER);
2644         return INVALID_HANDLE_VALUE;
2645     }
2646 
2647     hKey = SetupDiOpenClassRegKeyExW(&DeviceInterfaceData->InterfaceClassGuid, samDesired, DIOCR_INTERFACE, NULL, NULL);
2648     if (hKey == INVALID_HANDLE_VALUE)
2649     {
2650         hKey = SetupDiOpenClassRegKeyExW(NULL, samDesired, DIOCR_INTERFACE, NULL, NULL);
2651         if (hKey == INVALID_HANDLE_VALUE)
2652         {
2653             SetLastError(ERROR_INVALID_PARAMETER);
2654             return INVALID_HANDLE_VALUE;
2655         }
2656         SETUPDI_GuidToString(&DeviceInterfaceData->InterfaceClassGuid, bracedGuidString);
2657 
2658         if (RegCreateKeyExW(hKey, bracedGuidString, 0, NULL, 0, samDesired, NULL, &hDevKey, NULL) != ERROR_SUCCESS)
2659         {
2660             SetLastError(ERROR_INVALID_PARAMETER);
2661             return INVALID_HANDLE_VALUE;
2662         }
2663         RegCloseKey(hKey);
2664         hKey = hDevKey;
2665     }
2666 
2667     DevItf = (struct DeviceInterface *)DeviceInterfaceData->Reserved;
2668 
2669     Length = (wcslen(DevItf->SymbolicLink)+1) * sizeof(WCHAR);
2670     SymbolicLink = HeapAlloc(GetProcessHeap(), 0, Length);
2671     if (!SymbolicLink)
2672     {
2673         RegCloseKey(hKey);
2674         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2675         return INVALID_HANDLE_VALUE;
2676     }
2677 
2678     wcscpy(SymbolicLink, DevItf->SymbolicLink);
2679 
2680     Index = 0;
2681     while(SymbolicLink[Index])
2682     {
2683         if (SymbolicLink[Index] == L'\\')
2684         {
2685             SymbolicLink[Index] = L'#';
2686         }
2687         Index++;
2688     }
2689 
2690     rc = RegCreateKeyExW(hKey, SymbolicLink, 0, NULL, 0, samDesired, NULL, &hDevKey, NULL);
2691 
2692     RegCloseKey(hKey);
2693     HeapFree(GetProcessHeap(), 0, SymbolicLink);
2694 
2695     if (rc == ERROR_SUCCESS)
2696     {
2697         if (InfHandle && InfSectionName)
2698         {
2699             if (!SetupInstallFromInfSection(NULL /*FIXME */,
2700                                             InfHandle,
2701                                             InfSectionName,
2702                                             SPINST_INIFILES | SPINST_REGISTRY | SPINST_INI2REG | SPINST_FILES | SPINST_BITREG | SPINST_REGSVR | SPINST_UNREGSVR | SPINST_PROFILEITEMS | SPINST_COPYINF,
2703                                             hDevKey,
2704                                             NULL,
2705                                             0,
2706                                             set->SelectedDevice->InstallParams.InstallMsgHandler,
2707                                             set->SelectedDevice->InstallParams.InstallMsgHandlerContext,
2708                                             INVALID_HANDLE_VALUE,
2709                                             NULL))
2710             {
2711                 RegCloseKey(hDevKey);
2712                 return INVALID_HANDLE_VALUE;
2713             }
2714         }
2715     }
2716 
2717     SetLastError(rc);
2718     return hDevKey;
2719 }
2720 
2721 /***********************************************************************
2722  *		SetupDiDeleteDeviceInterfaceRegKey (SETUPAPI.@)
2723  */
2724 BOOL WINAPI SetupDiDeleteDeviceInterfaceRegKey(
2725         HDEVINFO DeviceInfoSet,
2726         PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
2727         DWORD Reserved)
2728 {
2729     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2730     BOOL ret = FALSE;
2731 
2732     TRACE("%s(%p %p %d)\n", __FUNCTION__, DeviceInfoSet, DeviceInterfaceData, Reserved);
2733 
2734     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE ||
2735             set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2736     {
2737         SetLastError(ERROR_INVALID_HANDLE);
2738         return FALSE;
2739     }
2740     if (!DeviceInterfaceData ||
2741             DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA) ||
2742             !DeviceInterfaceData->Reserved)
2743     {
2744         SetLastError(ERROR_INVALID_PARAMETER);
2745         return FALSE;
2746     }
2747 
2748     FIXME("%p %p %d\n", DeviceInfoSet, DeviceInterfaceData, Reserved);
2749     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2750     return ret;
2751 }
2752 
2753 /***********************************************************************
2754  *		SetupDiEnumDeviceInterfaces (SETUPAPI.@)
2755  *
2756  * PARAMS
2757  *   DeviceInfoSet      [I]    Set of devices from which to enumerate
2758  *                             interfaces
2759  *   DeviceInfoData     [I]    (Optional) If specified, a specific device
2760  *                             instance from which to enumerate interfaces.
2761  *                             If it isn't specified, all interfaces for all
2762  *                             devices in the set are enumerated.
2763  *   InterfaceClassGuid [I]    The interface class to enumerate.
2764  *   MemberIndex        [I]    An index of the interface instance to enumerate.
2765  *                             A caller should start with MemberIndex set to 0,
2766  *                             and continue until the function fails with
2767  *                             ERROR_NO_MORE_ITEMS.
2768  *   DeviceInterfaceData [I/O] Returns an enumerated interface.  Its cbSize
2769  *                             member must be set to
2770  *                             sizeof(SP_DEVICE_INTERFACE_DATA).
2771  *
2772  * RETURNS
2773  *   Success: non-zero value.
2774  *   Failure: FALSE.  Call GetLastError() for more info.
2775  */
2776 BOOL WINAPI SetupDiEnumDeviceInterfaces(
2777         HDEVINFO DeviceInfoSet,
2778         PSP_DEVINFO_DATA DeviceInfoData,
2779         CONST GUID * InterfaceClassGuid,
2780         DWORD MemberIndex,
2781         PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
2782 {
2783     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2784     BOOL ret = FALSE;
2785 
2786     TRACE("%s(%p, %p, %s, %d, %p)\n", __FUNCTION__, DeviceInfoSet, DeviceInfoData,
2787      debugstr_guid(InterfaceClassGuid), MemberIndex, DeviceInterfaceData);
2788 
2789     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE ||
2790             set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2791     {
2792         SetLastError(ERROR_INVALID_HANDLE);
2793         return FALSE;
2794     }
2795     if (DeviceInfoData && (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA) ||
2796                 !DeviceInfoData->Reserved))
2797     {
2798         SetLastError(ERROR_INVALID_PARAMETER);
2799         return FALSE;
2800     }
2801     if (!DeviceInterfaceData ||
2802             DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA))
2803     {
2804         SetLastError(ERROR_INVALID_PARAMETER);
2805         return FALSE;
2806     }
2807     if (DeviceInfoData)
2808     {
2809         struct DeviceInfo *devInfo =
2810             (struct DeviceInfo *)DeviceInfoData->Reserved;
2811         BOOL found = FALSE;
2812         PLIST_ENTRY InterfaceListEntry = devInfo->InterfaceListHead.Flink;
2813         while (InterfaceListEntry != &devInfo->InterfaceListHead && !found)
2814         {
2815             struct DeviceInterface *DevItf = CONTAINING_RECORD(InterfaceListEntry, struct DeviceInterface, ListEntry);
2816             if (!IsEqualIID(&DevItf->InterfaceClassGuid, InterfaceClassGuid))
2817             {
2818                 InterfaceListEntry = InterfaceListEntry->Flink;
2819                 continue;
2820             }
2821             if (MemberIndex-- == 0)
2822             {
2823                 /* return this item */
2824                 memcpy(&DeviceInterfaceData->InterfaceClassGuid,
2825                     &DevItf->InterfaceClassGuid,
2826                     sizeof(GUID));
2827                 DeviceInterfaceData->Flags = DevItf->Flags;
2828                 DeviceInterfaceData->Reserved = (ULONG_PTR)DevItf;
2829                 found = TRUE;
2830                 ret = TRUE;
2831             }
2832             InterfaceListEntry = InterfaceListEntry->Flink;
2833         }
2834         if (!found)
2835             SetLastError(ERROR_NO_MORE_ITEMS);
2836     }
2837     else
2838     {
2839         BOOL found = FALSE;
2840         PLIST_ENTRY ItemList = set->ListHead.Flink;
2841         while (ItemList != &set->ListHead && !found)
2842         {
2843             PLIST_ENTRY InterfaceListEntry;
2844             struct DeviceInfo *devInfo =
2845                 CONTAINING_RECORD(ItemList, struct DeviceInfo, ListEntry);
2846             InterfaceListEntry = devInfo->InterfaceListHead.Flink;
2847             while (InterfaceListEntry != &devInfo->InterfaceListHead && !found)
2848             {
2849                 struct DeviceInterface *DevItf = CONTAINING_RECORD(InterfaceListEntry, struct DeviceInterface, ListEntry);
2850                 if (!IsEqualIID(&DevItf->InterfaceClassGuid, InterfaceClassGuid))
2851                 {
2852                     InterfaceListEntry = InterfaceListEntry->Flink;
2853                     continue;
2854                 }
2855                 if (MemberIndex-- == 0)
2856                 {
2857                     /* return this item */
2858                     memcpy(&DeviceInterfaceData->InterfaceClassGuid,
2859                         &DevItf->InterfaceClassGuid,
2860                         sizeof(GUID));
2861                     DeviceInterfaceData->Flags = DevItf->Flags;
2862                     DeviceInterfaceData->Reserved = (ULONG_PTR)DevItf;
2863                     found = TRUE;
2864                     ret = TRUE;
2865                 }
2866                 InterfaceListEntry = InterfaceListEntry->Flink;
2867             }
2868             ItemList = ItemList->Flink;
2869 
2870         }
2871         if (!found)
2872             SetLastError(ERROR_NO_MORE_ITEMS);
2873     }
2874     return ret;
2875 }
2876 
2877 /***********************************************************************
2878  *		SetupDiDestroyDeviceInfoList (SETUPAPI.@)
2879   *
2880  * Destroy a DeviceInfoList and free all used memory of the list.
2881  *
2882  * PARAMS
2883  *   devinfo [I] DeviceInfoList pointer to list to destroy
2884  *
2885  * RETURNS
2886  *   Success: non zero value.
2887  *   Failure: zero value.
2888  */
2889 BOOL WINAPI SetupDiDestroyDeviceInfoList(HDEVINFO devinfo)
2890 {
2891     BOOL ret = FALSE;
2892 
2893     TRACE("%s(%p)\n", __FUNCTION__, devinfo);
2894     if (devinfo && devinfo != INVALID_HANDLE_VALUE)
2895     {
2896         struct DeviceInfoSet *list = (struct DeviceInfoSet *)devinfo;
2897 
2898         if (list->magic == SETUP_DEVICE_INFO_SET_MAGIC)
2899         {
2900             ret = DestroyDeviceInfoSet(list);
2901         }
2902     }
2903 
2904     if (ret == FALSE)
2905         SetLastError(ERROR_INVALID_HANDLE);
2906 
2907     return ret;
2908 }
2909 
2910 /***********************************************************************
2911  *		SetupDiGetDeviceInterfaceDetailA (SETUPAPI.@)
2912  */
2913 BOOL WINAPI SetupDiGetDeviceInterfaceDetailA(
2914         HDEVINFO DeviceInfoSet,
2915         PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
2916         PSP_DEVICE_INTERFACE_DETAIL_DATA_A DeviceInterfaceDetailData,
2917         DWORD DeviceInterfaceDetailDataSize,
2918         PDWORD RequiredSize,
2919         PSP_DEVINFO_DATA DeviceInfoData)
2920 {
2921     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2922     PSP_DEVICE_INTERFACE_DETAIL_DATA_W DeviceInterfaceDetailDataW = NULL;
2923     DWORD sizeW = 0, bytesNeeded;
2924     BOOL ret = FALSE;
2925 
2926     TRACE("%s(%p, %p, %p, %d, %p, %p)\n", __FUNCTION__, DeviceInfoSet,
2927      DeviceInterfaceData, DeviceInterfaceDetailData,
2928      DeviceInterfaceDetailDataSize, RequiredSize, DeviceInfoData);
2929 
2930     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE ||
2931             set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2932     {
2933         SetLastError(ERROR_INVALID_HANDLE);
2934         return FALSE;
2935     }
2936     if (!DeviceInterfaceData ||
2937             DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA) ||
2938             !DeviceInterfaceData->Reserved)
2939     {
2940         SetLastError(ERROR_INVALID_PARAMETER);
2941         return FALSE;
2942     }
2943     if (DeviceInterfaceDetailData && (DeviceInterfaceDetailData->cbSize != sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A)))
2944     {
2945         SetLastError(ERROR_INVALID_USER_BUFFER);
2946         return FALSE;
2947     }
2948 
2949     if((DeviceInterfaceDetailDataSize != 0) &&
2950         (DeviceInterfaceDetailDataSize < (FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath) + sizeof(CHAR))))
2951     {
2952         SetLastError(ERROR_INVALID_USER_BUFFER);
2953         return FALSE;
2954     }
2955 
2956     if (!DeviceInterfaceDetailData && DeviceInterfaceDetailDataSize)
2957     {
2958         SetLastError(ERROR_INVALID_USER_BUFFER);
2959         return FALSE;
2960     }
2961 
2962 
2963     if (DeviceInterfaceDetailData != NULL)
2964     {
2965         sizeW = FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath)
2966             + (DeviceInterfaceDetailDataSize - FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath)) * sizeof(WCHAR);
2967         DeviceInterfaceDetailDataW = (PSP_DEVICE_INTERFACE_DETAIL_DATA_W)MyMalloc(sizeW);
2968         if (!DeviceInterfaceDetailDataW)
2969         {
2970             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2971         }
2972         DeviceInterfaceDetailDataW->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W);
2973     }
2974     if (!DeviceInterfaceDetailData || (DeviceInterfaceDetailData && DeviceInterfaceDetailDataW))
2975     {
2976         ret = SetupDiGetDeviceInterfaceDetailW(
2977             DeviceInfoSet,
2978             DeviceInterfaceData,
2979             DeviceInterfaceDetailDataW,
2980             sizeW,
2981             &sizeW,
2982             DeviceInfoData);
2983         bytesNeeded = (sizeW - FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath)) / sizeof(WCHAR)
2984             + FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath);
2985         if (RequiredSize)
2986             *RequiredSize = bytesNeeded;
2987         if (ret && DeviceInterfaceDetailData && DeviceInterfaceDetailDataSize >= bytesNeeded)
2988         {
2989             if (!WideCharToMultiByte(
2990                 CP_ACP, 0,
2991                 DeviceInterfaceDetailDataW->DevicePath, -1,
2992                 DeviceInterfaceDetailData->DevicePath, DeviceInterfaceDetailDataSize - FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath),
2993                 NULL, NULL))
2994             {
2995                 ret = FALSE;
2996             }
2997         }
2998     }
2999     MyFree(DeviceInterfaceDetailDataW);
3000 
3001     return ret;
3002 }
3003 
3004 /***********************************************************************
3005  *		SetupDiGetDeviceInterfaceDetailW (SETUPAPI.@)
3006  */
3007 BOOL WINAPI SetupDiGetDeviceInterfaceDetailW(
3008         HDEVINFO DeviceInfoSet,
3009         PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
3010         PSP_DEVICE_INTERFACE_DETAIL_DATA_W DeviceInterfaceDetailData,
3011         DWORD DeviceInterfaceDetailDataSize,
3012         PDWORD RequiredSize,
3013         PSP_DEVINFO_DATA DeviceInfoData)
3014 {
3015     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
3016     BOOL ret = FALSE;
3017 
3018     TRACE("%s(%p, %p, %p, %d, %p, %p)\n", __FUNCTION__, DeviceInfoSet,
3019      DeviceInterfaceData, DeviceInterfaceDetailData,
3020      DeviceInterfaceDetailDataSize, RequiredSize, DeviceInfoData);
3021 
3022     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE ||
3023             set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
3024     {
3025         SetLastError(ERROR_INVALID_HANDLE);
3026         return FALSE;
3027     }
3028     if (!DeviceInterfaceData ||
3029             DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA) ||
3030             !DeviceInterfaceData->Reserved)
3031     {
3032         SetLastError(ERROR_INVALID_PARAMETER);
3033         return FALSE;
3034     }
3035     if (DeviceInterfaceDetailData && DeviceInterfaceDetailData->cbSize != sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W))
3036     {
3037         SetLastError(ERROR_INVALID_USER_BUFFER);
3038         return FALSE;
3039     }
3040     if (!DeviceInterfaceDetailData && DeviceInterfaceDetailDataSize)
3041     {
3042         SetLastError(ERROR_INVALID_USER_BUFFER);
3043         return FALSE;
3044     }
3045     if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
3046     {
3047         SetLastError(ERROR_INVALID_PARAMETER);
3048         return FALSE;
3049     }
3050     if ((DeviceInterfaceDetailData != NULL)
3051         && (DeviceInterfaceDetailDataSize < (FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath)) + sizeof(WCHAR)))
3052     {
3053         SetLastError(ERROR_INVALID_PARAMETER);
3054         return FALSE;
3055     }
3056     else
3057     {
3058         struct DeviceInterface *deviceInterface = (struct DeviceInterface *)DeviceInterfaceData->Reserved;
3059         LPCWSTR devName = deviceInterface->SymbolicLink;
3060         DWORD sizeRequired = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W) +
3061             (lstrlenW(devName) + 1) * sizeof(WCHAR);
3062 
3063         if (sizeRequired > DeviceInterfaceDetailDataSize)
3064         {
3065             SetLastError(ERROR_INSUFFICIENT_BUFFER);
3066             if (RequiredSize)
3067                 *RequiredSize = sizeRequired;
3068         }
3069         else
3070         {
3071             strcpyW(DeviceInterfaceDetailData->DevicePath, devName);
3072             TRACE("DevicePath is %s\n", debugstr_w(DeviceInterfaceDetailData->DevicePath));
3073             if (DeviceInfoData)
3074             {
3075                 memcpy(&DeviceInfoData->ClassGuid,
3076                     &deviceInterface->DeviceInfo->ClassGuid,
3077                     sizeof(GUID));
3078                 DeviceInfoData->DevInst = deviceInterface->DeviceInfo->dnDevInst;
3079                 DeviceInfoData->Reserved = (ULONG_PTR)deviceInterface->DeviceInfo;
3080             }
3081             ret = TRUE;
3082         }
3083     }
3084     return ret;
3085 }
3086 
3087 struct PropertyMapEntry
3088 {
3089     DWORD   regType;
3090     LPCSTR  nameA;
3091     LPCWSTR nameW;
3092 };
3093 
3094 static struct PropertyMapEntry PropertyMap[] = {
3095     { REG_SZ, "DeviceDesc", REGSTR_VAL_DEVDESC },
3096     { REG_MULTI_SZ, "HardwareId", REGSTR_VAL_HARDWAREID },
3097     { REG_MULTI_SZ, "CompatibleIDs", REGSTR_VAL_COMPATIBLEIDS },
3098     { 0, NULL, NULL }, /* SPDRP_UNUSED0 */
3099     { REG_SZ, "Service", REGSTR_VAL_SERVICE },
3100     { 0, NULL, NULL }, /* SPDRP_UNUSED1 */
3101     { 0, NULL, NULL }, /* SPDRP_UNUSED2 */
3102     { REG_SZ, "Class", REGSTR_VAL_CLASS },
3103     { REG_SZ, "ClassGUID", REGSTR_VAL_CLASSGUID },
3104     { REG_SZ, "Driver", REGSTR_VAL_DRIVER },
3105     { REG_DWORD, "ConfigFlags", REGSTR_VAL_CONFIGFLAGS },
3106     { REG_SZ, "Mfg", REGSTR_VAL_MFG },
3107     { REG_SZ, "FriendlyName", REGSTR_VAL_FRIENDLYNAME },
3108     { REG_SZ, "LocationInformation", REGSTR_VAL_LOCATION_INFORMATION },
3109     { 0, NULL, NULL }, /* SPDRP_PHYSICAL_DEVICE_OBJECT_NAME */
3110     { REG_DWORD, "Capabilities", REGSTR_VAL_CAPABILITIES },
3111     { REG_DWORD, "UINumber", REGSTR_VAL_UI_NUMBER },
3112     { REG_MULTI_SZ, "UpperFilters", REGSTR_VAL_UPPERFILTERS },
3113     { REG_MULTI_SZ, "LowerFilters", REGSTR_VAL_LOWERFILTERS },
3114     { 0, NULL, NULL }, /* SPDRP_BUSTYPEGUID */
3115     { 0, NULL, NULL }, /* SPDRP_LEGACYBUSTYPE */
3116     { 0, NULL, NULL }, /* SPDRP_BUSNUMBER */
3117     { 0, NULL, NULL }, /* SPDRP_ENUMERATOR_NAME */
3118     { REG_BINARY, "Security", REGSTR_SECURITY },
3119     { 0, NULL, NULL }, /* SPDRP_SECURITY_SDS */
3120     { 0, NULL, NULL }, /* SPDRP_DEVTYPE */
3121     { 0, NULL, NULL }, /* SPDRP_EXCLUSIVE */
3122     { 0, NULL, NULL }, /* SPDRP_CHARACTERISTICS */
3123     { 0, NULL, NULL }, /* SPDRP_ADDRESS */
3124     { REG_SZ, "UINumberDescFormat", REGSTR_UI_NUMBER_DESC_FORMAT },
3125     { 0, NULL, NULL }, /* SPDRP_DEVICE_POWER_DATA */
3126     { 0, NULL, NULL }, /* SPDRP_REMOVAL_POLICY */
3127     { 0, NULL, NULL }, /* SPDRP_REMOVAL_POLICY_HW_DEFAULT */
3128     { 0, NULL, NULL }, /* SPDRP_REMOVAL_POLICY_OVERRIDE */
3129     { 0, NULL, NULL }, /* SPDRP_INSTALL_STATE */
3130 };
3131 
3132 /***********************************************************************
3133  *		SetupDiGetDeviceRegistryPropertyA (SETUPAPI.@)
3134  */
3135 BOOL WINAPI SetupDiGetDeviceRegistryPropertyA(
3136         HDEVINFO  DeviceInfoSet,
3137         PSP_DEVINFO_DATA  DeviceInfoData,
3138         DWORD   Property,
3139         PDWORD  PropertyRegDataType,
3140         PBYTE   PropertyBuffer,
3141         DWORD   PropertyBufferSize,
3142         PDWORD  RequiredSize)
3143 {
3144     BOOL ret;
3145     BOOL bIsStringProperty;
3146     DWORD RegType;
3147     DWORD RequiredSizeA, RequiredSizeW;
3148     DWORD PropertyBufferSizeW = 0;
3149     PBYTE PropertyBufferW = NULL;
3150 
3151     TRACE("%s(%p %p %d %p %p %d %p)\n", __FUNCTION__, DeviceInfoSet, DeviceInfoData,
3152         Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize,
3153         RequiredSize);
3154 
3155     if (PropertyBufferSize != 0)
3156     {
3157         PropertyBufferSizeW = PropertyBufferSize * 2;
3158         PropertyBufferW = HeapAlloc(GetProcessHeap(), 0, PropertyBufferSizeW);
3159         if (!PropertyBufferW)
3160         {
3161             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3162             return FALSE;
3163         }
3164     }
3165 
3166     ret = SetupDiGetDeviceRegistryPropertyW(DeviceInfoSet,
3167                                             DeviceInfoData,
3168                                             Property,
3169                                             &RegType,
3170                                             PropertyBufferW,
3171                                             PropertyBufferSizeW,
3172                                             &RequiredSizeW);
3173 
3174     if (ret || GetLastError() == ERROR_INSUFFICIENT_BUFFER)
3175     {
3176         bIsStringProperty = (RegType == REG_SZ || RegType == REG_MULTI_SZ || RegType == REG_EXPAND_SZ);
3177 
3178         if (bIsStringProperty)
3179            RequiredSizeA = RequiredSizeW / sizeof(WCHAR);
3180         else
3181             RequiredSizeA = RequiredSizeW;
3182         if (RequiredSize)
3183             *RequiredSize = RequiredSizeA;
3184         if (PropertyRegDataType)
3185             *PropertyRegDataType = RegType;
3186     }
3187 
3188     if (!ret)
3189     {
3190         HeapFree(GetProcessHeap(), 0, PropertyBufferW);
3191         return ret;
3192     }
3193 
3194     if (RequiredSizeA <= PropertyBufferSize)
3195     {
3196         if (bIsStringProperty && PropertyBufferSize > 0)
3197         {
3198             if (WideCharToMultiByte(CP_ACP, 0, (LPWSTR)PropertyBufferW, RequiredSizeW / sizeof(WCHAR), (LPSTR)PropertyBuffer, PropertyBufferSize, NULL, NULL) == 0)
3199             {
3200                 /* Last error is already set by WideCharToMultiByte */
3201                 ret = FALSE;
3202             }
3203         }
3204         else
3205             memcpy(PropertyBuffer, PropertyBufferW, RequiredSizeA);
3206     }
3207     else
3208     {
3209         SetLastError(ERROR_INSUFFICIENT_BUFFER);
3210         ret = FALSE;
3211     }
3212 
3213     HeapFree(GetProcessHeap(), 0, PropertyBufferW);
3214     return ret;
3215 }
3216 
3217 /***********************************************************************
3218  *		SetupDiGetDeviceRegistryPropertyW (SETUPAPI.@)
3219  */
3220 BOOL WINAPI SetupDiGetDeviceRegistryPropertyW(
3221         HDEVINFO  DeviceInfoSet,
3222         PSP_DEVINFO_DATA  DeviceInfoData,
3223         DWORD   Property,
3224         PDWORD  PropertyRegDataType,
3225         PBYTE   PropertyBuffer,
3226         DWORD   PropertyBufferSize,
3227         PDWORD  RequiredSize)
3228 {
3229     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
3230     struct DeviceInfo *devInfo;
3231     CONFIGRET cr;
3232     LONG lError = ERROR_SUCCESS;
3233     DWORD size;
3234 
3235     TRACE("%s(%p %p %d %p %p %d %p)\n", __FUNCTION__, DeviceInfoSet, DeviceInfoData,
3236         Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize,
3237         RequiredSize);
3238 
3239     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
3240     {
3241         SetLastError(ERROR_INVALID_HANDLE);
3242         return FALSE;
3243     }
3244     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
3245     {
3246         SetLastError(ERROR_INVALID_HANDLE);
3247         return FALSE;
3248     }
3249     if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
3250             || !DeviceInfoData->Reserved)
3251     {
3252         SetLastError(ERROR_INVALID_PARAMETER);
3253         return FALSE;
3254     }
3255 
3256     if (Property >= SPDRP_MAXIMUM_PROPERTY)
3257     {
3258         SetLastError(ERROR_INVALID_REG_PROPERTY);
3259         return FALSE;
3260     }
3261 
3262     devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
3263 
3264     if (Property < sizeof(PropertyMap) / sizeof(PropertyMap[0])
3265         && PropertyMap[Property].nameW)
3266     {
3267         HKEY hKey;
3268         size = PropertyBufferSize;
3269         hKey = SETUPDI_OpenDevKey(set->HKLM, devInfo, KEY_QUERY_VALUE);
3270         if (hKey == INVALID_HANDLE_VALUE)
3271             return FALSE;
3272         lError = RegQueryValueExW(hKey, PropertyMap[Property].nameW,
3273                  NULL, PropertyRegDataType, PropertyBuffer, &size);
3274         RegCloseKey(hKey);
3275 
3276         if (RequiredSize)
3277             *RequiredSize = size;
3278 
3279         switch (lError)
3280         {
3281             case ERROR_SUCCESS:
3282                 if (PropertyBuffer == NULL && size != 0)
3283                     lError = ERROR_INSUFFICIENT_BUFFER;
3284                 break;
3285             case ERROR_MORE_DATA:
3286                 lError = ERROR_INSUFFICIENT_BUFFER;
3287                 break;
3288             default:
3289                 break;
3290         }
3291     }
3292     else if (Property == SPDRP_PHYSICAL_DEVICE_OBJECT_NAME)
3293     {
3294         size = (strlenW(devInfo->Data) + 1) * sizeof(WCHAR);
3295 
3296         if (PropertyRegDataType)
3297             *PropertyRegDataType = REG_SZ;
3298         if (RequiredSize)
3299             *RequiredSize = size;
3300         if (PropertyBufferSize >= size)
3301         {
3302             strcpyW((LPWSTR)PropertyBuffer, devInfo->Data);
3303         }
3304         else
3305             lError = ERROR_INSUFFICIENT_BUFFER;
3306     }
3307     else
3308     {
3309         size = PropertyBufferSize;
3310 
3311         cr = CM_Get_DevNode_Registry_Property_ExW(devInfo->dnDevInst,
3312                                                   Property + (CM_DRP_DEVICEDESC - SPDRP_DEVICEDESC),
3313                                                   PropertyRegDataType,
3314                                                   PropertyBuffer,
3315                                                   &size,
3316                                                   0,
3317                                                   set->hMachine);
3318         if ((cr == CR_SUCCESS) || (cr == CR_BUFFER_SMALL))
3319         {
3320             if (RequiredSize)
3321                 *RequiredSize = size;
3322         }
3323 
3324         if (cr != CR_SUCCESS)
3325         {
3326             switch (cr)
3327             {
3328                 case CR_INVALID_DEVINST:
3329                     lError = ERROR_NO_SUCH_DEVINST;
3330                     break;
3331 
3332                 case CR_INVALID_PROPERTY:
3333                     lError = ERROR_INVALID_REG_PROPERTY;
3334                     break;
3335 
3336                 case CR_BUFFER_SMALL:
3337                     lError = ERROR_INSUFFICIENT_BUFFER;
3338                     break;
3339 
3340                 default :
3341                     lError = ERROR_INVALID_DATA;
3342                     break;
3343             }
3344         }
3345     }
3346 
3347     SetLastError(lError);
3348     return (lError == ERROR_SUCCESS);
3349 }
3350 
3351 /***********************************************************************
3352  *		Internal for SetupDiSetDeviceRegistryPropertyA/W
3353  */
3354 BOOL WINAPI IntSetupDiSetDeviceRegistryPropertyAW(
3355         HDEVINFO DeviceInfoSet,
3356         PSP_DEVINFO_DATA DeviceInfoData,
3357         DWORD Property,
3358         const BYTE *PropertyBuffer,
3359         DWORD PropertyBufferSize,
3360         BOOL isAnsi)
3361 {
3362     BOOL ret = FALSE;
3363     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
3364     struct DeviceInfo *deviceInfo;
3365 
3366     TRACE("%s(%p %p %d %p %d)\n", __FUNCTION__, DeviceInfoSet, DeviceInfoData, Property,
3367         PropertyBuffer, PropertyBufferSize);
3368 
3369     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
3370     {
3371         SetLastError(ERROR_INVALID_HANDLE);
3372         return FALSE;
3373     }
3374     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
3375     {
3376         SetLastError(ERROR_INVALID_HANDLE);
3377         return FALSE;
3378     }
3379     if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
3380             || !DeviceInfoData->Reserved)
3381     {
3382         SetLastError(ERROR_INVALID_PARAMETER);
3383         return FALSE;
3384     }
3385 
3386     deviceInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
3387 
3388     if (Property < sizeof(PropertyMap) / sizeof(PropertyMap[0])
3389         && PropertyMap[Property].nameW
3390         && PropertyMap[Property].nameA)
3391     {
3392         HKEY hKey;
3393         LONG l;
3394         hKey = SETUPDI_OpenDevKey(set->HKLM, deviceInfo, KEY_SET_VALUE);
3395         if (hKey == INVALID_HANDLE_VALUE)
3396             return FALSE;
3397         /* Write new data */
3398         if (isAnsi)
3399         {
3400             l = RegSetValueExA(
3401                 hKey, PropertyMap[Property].nameA, 0,
3402                     PropertyMap[Property].regType, PropertyBuffer,
3403                     PropertyBufferSize);
3404         }
3405         else
3406         {
3407             l = RegSetValueExW(
3408                 hKey, PropertyMap[Property].nameW, 0,
3409                     PropertyMap[Property].regType, PropertyBuffer,
3410                     PropertyBufferSize);
3411         }
3412         if (!l)
3413             ret = TRUE;
3414         else
3415             SetLastError(l);
3416         RegCloseKey(hKey);
3417     }
3418     else
3419     {
3420         ERR("Property 0x%lx not implemented\n", Property);
3421         SetLastError(ERROR_NOT_SUPPORTED);
3422     }
3423 
3424     TRACE("Returning %d\n", ret);
3425     return ret;
3426 }
3427 /***********************************************************************
3428  *		SetupDiSetDeviceRegistryPropertyA (SETUPAPI.@)
3429  */
3430 BOOL WINAPI SetupDiSetDeviceRegistryPropertyA(
3431         HDEVINFO DeviceInfoSet,
3432         PSP_DEVINFO_DATA DeviceInfoData,
3433         DWORD Property,
3434         const BYTE *PropertyBuffer,
3435         DWORD PropertyBufferSize)
3436 {
3437     return IntSetupDiSetDeviceRegistryPropertyAW(DeviceInfoSet,
3438                                                  DeviceInfoData,
3439                                                  Property,
3440                                                  PropertyBuffer,
3441                                                  PropertyBufferSize,
3442                                                  TRUE);
3443 }
3444 
3445 /***********************************************************************
3446  *		SetupDiSetDeviceRegistryPropertyW (SETUPAPI.@)
3447  */
3448 BOOL WINAPI SetupDiSetDeviceRegistryPropertyW(
3449         HDEVINFO DeviceInfoSet,
3450         PSP_DEVINFO_DATA DeviceInfoData,
3451         DWORD Property,
3452         const BYTE *PropertyBuffer,
3453         DWORD PropertyBufferSize)
3454 {
3455     return IntSetupDiSetDeviceRegistryPropertyAW(DeviceInfoSet,
3456                                                  DeviceInfoData,
3457                                                  Property,
3458                                                  PropertyBuffer,
3459                                                  PropertyBufferSize,
3460                                                  FALSE);
3461 }
3462 
3463 /***********************************************************************
3464  *		SetupDiInstallClassA (SETUPAPI.@)
3465  */
3466 BOOL WINAPI SetupDiInstallClassA(
3467         HWND hwndParent,
3468         PCSTR InfFileName,
3469         DWORD Flags,
3470         HSPFILEQ FileQueue)
3471 {
3472     return SetupDiInstallClassExA(hwndParent, InfFileName, Flags, FileQueue, NULL, NULL, NULL);
3473 }
3474 
3475 /***********************************************************************
3476  *		SetupDiInstallClassExA (SETUPAPI.@)
3477  */
3478 BOOL WINAPI
3479 SetupDiInstallClassExA(
3480     IN HWND hwndParent OPTIONAL,
3481     IN PCSTR InfFileName OPTIONAL,
3482     IN DWORD Flags,
3483     IN HSPFILEQ FileQueue OPTIONAL,
3484     IN CONST GUID *InterfaceClassGuid OPTIONAL,
3485     IN PVOID Reserved1,
3486     IN PVOID Reserved2)
3487 {
3488     PWSTR InfFileNameW = NULL;
3489     BOOL Result;
3490 
3491     if (!InfFileName)
3492     {
3493         SetLastError(ERROR_INVALID_PARAMETER);
3494         return FALSE;
3495     }
3496     else
3497     {
3498         InfFileNameW = pSetupMultiByteToUnicode(InfFileName, CP_ACP);
3499         if (InfFileNameW == NULL)
3500         {
3501             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3502             return FALSE;
3503         }
3504     }
3505 
3506     Result = SetupDiInstallClassExW(hwndParent, InfFileNameW, Flags,
3507         FileQueue, InterfaceClassGuid, Reserved1, Reserved2);
3508 
3509     MyFree(InfFileNameW);
3510 
3511     return Result;
3512 }
3513 
3514 HKEY SETUP_CreateClassKey(HINF hInf)
3515 {
3516     WCHAR FullBuffer[MAX_PATH];
3517     WCHAR Buffer[MAX_PATH];
3518     DWORD RequiredSize;
3519     HKEY hClassKey;
3520     DWORD Disposition;
3521 
3522     /* Obtain the Class GUID for this class */
3523     if (!SetupGetLineTextW(NULL,
3524                            hInf,
3525                            Version,
3526                            REGSTR_VAL_CLASSGUID,
3527                            Buffer,
3528                            sizeof(Buffer) / sizeof(WCHAR),
3529                            &RequiredSize))
3530     {
3531         return INVALID_HANDLE_VALUE;
3532     }
3533 
3534     /* Build the corresponding registry key name */
3535     lstrcpyW(FullBuffer, REGSTR_PATH_CLASS_NT);
3536     lstrcatW(FullBuffer, BackSlash);
3537     lstrcatW(FullBuffer, Buffer);
3538 
3539     /* Obtain the Class name for this class */
3540     if (!SetupGetLineTextW(NULL,
3541                            hInf,
3542                            Version,
3543                            REGSTR_VAL_CLASS,
3544                            Buffer,
3545                            sizeof(Buffer) / sizeof(WCHAR),
3546                            &RequiredSize))
3547     {
3548         return INVALID_HANDLE_VALUE;
3549     }
3550 
3551     /* Try to open or create the registry key */
3552     TRACE("Opening class key %s\n", debugstr_w(FullBuffer));
3553 #if 0 // I keep this for reference...
3554     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
3555                       FullBuffer,
3556                       0,
3557                       KEY_SET_VALUE,
3558                       &hClassKey))
3559     {
3560         /* Use RegCreateKeyExW */
3561     }
3562 #endif
3563     if (RegCreateKeyExW(HKEY_LOCAL_MACHINE,
3564                         FullBuffer,
3565                         0,
3566                         NULL,
3567                         REG_OPTION_NON_VOLATILE,
3568                         KEY_SET_VALUE,
3569                         NULL,
3570                         &hClassKey,
3571                         &Disposition))
3572     {
3573         ERR("RegCreateKeyExW(%s) failed\n", debugstr_w(FullBuffer));
3574         return INVALID_HANDLE_VALUE;
3575     }
3576     if (Disposition == REG_CREATED_NEW_KEY)
3577         TRACE("The class key %s was successfully created\n", debugstr_w(FullBuffer));
3578     else
3579         TRACE("The class key %s was successfully opened\n", debugstr_w(FullBuffer));
3580 
3581     TRACE( "setting value %s to %s\n", debugstr_w(REGSTR_VAL_CLASS), debugstr_w(Buffer) );
3582     if (RegSetValueExW(hClassKey,
3583                        REGSTR_VAL_CLASS,
3584                        0,
3585                        REG_SZ,
3586                        (LPBYTE)Buffer,
3587                        RequiredSize * sizeof(WCHAR)))
3588     {
3589         RegCloseKey(hClassKey);
3590         RegDeleteKeyW(HKEY_LOCAL_MACHINE,
3591                       FullBuffer);
3592         return INVALID_HANDLE_VALUE;
3593     }
3594 
3595     return hClassKey;
3596 }
3597 
3598 /***********************************************************************
3599  *		SetupDiInstallClassW (SETUPAPI.@)
3600  */
3601 BOOL WINAPI SetupDiInstallClassW(
3602         HWND hwndParent,
3603         PCWSTR InfFileName,
3604         DWORD Flags,
3605         HSPFILEQ FileQueue)
3606 {
3607     return SetupDiInstallClassExW(hwndParent, InfFileName, Flags, FileQueue, NULL, NULL, NULL);
3608 }
3609 
3610 
3611 /***********************************************************************
3612  *		SetupDiOpenClassRegKey  (SETUPAPI.@)
3613  */
3614 HKEY WINAPI SetupDiOpenClassRegKey(
3615         const GUID* ClassGuid,
3616         REGSAM samDesired)
3617 {
3618     return SetupDiOpenClassRegKeyExW(ClassGuid, samDesired,
3619                                      DIOCR_INSTALLER, NULL, NULL);
3620 }
3621 
3622 
3623 /***********************************************************************
3624  *		SetupDiOpenClassRegKeyExA  (SETUPAPI.@)
3625  */
3626 HKEY WINAPI SetupDiOpenClassRegKeyExA(
3627         const GUID* ClassGuid,
3628         REGSAM samDesired,
3629         DWORD Flags,
3630         PCSTR MachineName,
3631         PVOID Reserved)
3632 {
3633     PWSTR MachineNameW = NULL;
3634     HKEY hKey;
3635 
3636     TRACE("%s(%s 0x%lx 0x%lx %s %p)\n", __FUNCTION__, debugstr_guid(ClassGuid), samDesired,
3637         Flags, debugstr_a(MachineName), Reserved);
3638 
3639     if (MachineName)
3640     {
3641         MachineNameW = pSetupMultiByteToUnicode(MachineName, CP_ACP);
3642         if (MachineNameW == NULL)
3643             return INVALID_HANDLE_VALUE;
3644     }
3645 
3646     hKey = SetupDiOpenClassRegKeyExW(ClassGuid, samDesired,
3647                                      Flags, MachineNameW, Reserved);
3648 
3649     MyFree(MachineNameW);
3650 
3651     return hKey;
3652 }
3653 
3654 
3655 /***********************************************************************
3656  *		SetupDiOpenClassRegKeyExW  (SETUPAPI.@)
3657  */
3658 HKEY WINAPI SetupDiOpenClassRegKeyExW(
3659         const GUID* ClassGuid,
3660         REGSAM samDesired,
3661         DWORD Flags,
3662         PCWSTR MachineName,
3663         PVOID Reserved)
3664 {
3665     HKEY HKLM;
3666     HKEY hClassesKey;
3667     HKEY key;
3668     LPCWSTR lpKeyName;
3669     LONG l;
3670 
3671     TRACE("%s(%s 0x%lx 0x%lx %s %p)\n", __FUNCTION__, debugstr_guid(ClassGuid), samDesired,
3672         Flags, debugstr_w(MachineName), Reserved);
3673 
3674     if (MachineName != NULL)
3675     {
3676         l = RegConnectRegistryW(MachineName, HKEY_LOCAL_MACHINE, &HKLM);
3677         if (l != ERROR_SUCCESS)
3678         {
3679             SetLastError(l);
3680             return INVALID_HANDLE_VALUE;
3681         }
3682     }
3683     else
3684         HKLM = HKEY_LOCAL_MACHINE;
3685 
3686     if (Flags == DIOCR_INSTALLER)
3687     {
3688         lpKeyName = REGSTR_PATH_CLASS_NT;
3689     }
3690     else if (Flags == DIOCR_INTERFACE)
3691     {
3692         lpKeyName = REGSTR_PATH_DEVICE_CLASSES;
3693     }
3694     else
3695     {
3696         ERR("Invalid Flags parameter!\n");
3697         SetLastError(ERROR_INVALID_FLAGS);
3698         if (MachineName != NULL) RegCloseKey(HKLM);
3699         return INVALID_HANDLE_VALUE;
3700     }
3701 
3702     if (!ClassGuid)
3703     {
3704         if ((l = RegOpenKeyExW(HKLM,
3705                                lpKeyName,
3706                                0,
3707                                samDesired,
3708                                &hClassesKey)))
3709         {
3710             SetLastError(ERROR_INVALID_CLASS);
3711             hClassesKey = INVALID_HANDLE_VALUE;
3712         }
3713         if (MachineName != NULL)
3714             RegCloseKey(HKLM);
3715         key = hClassesKey;
3716     }
3717     else
3718     {
3719         WCHAR bracedGuidString[39];
3720 
3721         SETUPDI_GuidToString(ClassGuid, bracedGuidString);
3722 
3723         if (!(l = RegOpenKeyExW(HKLM,
3724                                 lpKeyName,
3725                                 0,
3726                                 samDesired,
3727                                 &hClassesKey)))
3728         {
3729             if (MachineName != NULL)
3730                 RegCloseKey(HKLM);
3731 
3732             if ((l = RegOpenKeyExW(hClassesKey,
3733                                    bracedGuidString,
3734                                    0,
3735                                    samDesired,
3736                                    &key)))
3737             {
3738                 SetLastError(l);
3739                 key = INVALID_HANDLE_VALUE;
3740             }
3741             RegCloseKey(hClassesKey);
3742         }
3743         else
3744         {
3745             if (MachineName != NULL) RegCloseKey(HKLM);
3746             SetLastError(l);
3747             key = INVALID_HANDLE_VALUE;
3748         }
3749     }
3750 
3751     return key;
3752 }
3753 
3754 /***********************************************************************
3755  *		SetupDiOpenDeviceInterfaceW (SETUPAPI.@)
3756  */
3757 BOOL WINAPI SetupDiOpenDeviceInterfaceW(
3758         HDEVINFO DeviceInfoSet,
3759         PCWSTR DevicePath,
3760         DWORD OpenFlags,
3761         PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
3762 {
3763     struct DeviceInfoSet * list;
3764     PCWSTR pEnd;
3765     DWORD dwLength, dwError, dwIndex, dwKeyName, dwSubIndex;
3766     CLSID ClassId;
3767     WCHAR Buffer[MAX_PATH + 1];
3768     WCHAR SymBuffer[MAX_PATH + 1];
3769     WCHAR InstancePath[MAX_PATH + 1];
3770     HKEY hKey, hDevKey, hSymKey;
3771     struct DeviceInfo * deviceInfo;
3772     struct DeviceInterface *deviceInterface;
3773     BOOL Ret;
3774     PLIST_ENTRY ItemList;
3775     PLIST_ENTRY InterfaceListEntry;
3776 
3777     TRACE("%s(%p %s %08x %p)\n", __FUNCTION__,
3778         DeviceInfoSet, debugstr_w(DevicePath), OpenFlags, DeviceInterfaceData);
3779 
3780 
3781     if (DeviceInterfaceData && DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA))
3782     {
3783         SetLastError(ERROR_INVALID_PARAMETER);
3784         return FALSE;
3785     }
3786 
3787     if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
3788     {
3789         SetLastError(ERROR_INVALID_HANDLE);
3790         return FALSE;
3791     }
3792 
3793     list = (struct DeviceInfoSet * )DeviceInfoSet;
3794 
3795     dwLength = wcslen(DevicePath);
3796     if (dwLength < 39)
3797     {
3798         /* path must be at least a guid length + L'\0' */
3799         SetLastError(ERROR_BAD_PATHNAME);
3800         return FALSE;
3801     }
3802 
3803     if (DevicePath[0] != L'\\' ||
3804         DevicePath[1] != L'\\' ||
3805         (DevicePath[2] != L'?' && DevicePath[2] != L'.') ||
3806         DevicePath[3] != L'\\')
3807     {
3808         /* invalid formatted path */
3809         SetLastError(ERROR_BAD_PATHNAME);
3810         return FALSE;
3811     }
3812 
3813     /* check for reference strings */
3814     pEnd = wcschr(&DevicePath[4], L'\\');
3815     if (!pEnd)
3816     {
3817         /* no reference string */
3818         pEnd = DevicePath + dwLength;
3819     }
3820 
3821     /* copy guid */
3822     wcscpy(Buffer, pEnd - 37);
3823     Buffer[36] = L'\0';
3824 
3825     dwError = UuidFromStringW(Buffer, &ClassId);
3826     if (dwError != NOERROR)
3827     {
3828         /* invalid formatted path */
3829         SetLastError(ERROR_BAD_PATHNAME);
3830         return FALSE;
3831     }
3832 
3833     hKey = SetupDiOpenClassRegKeyExW(&ClassId, KEY_READ, DIOCR_INTERFACE, list->MachineName, NULL);
3834 
3835     if (hKey == INVALID_HANDLE_VALUE)
3836     {
3837         /* invalid device class */
3838         return FALSE;
3839     }
3840 
3841     ItemList = list->ListHead.Flink;
3842     while (ItemList != &list->ListHead)
3843     {
3844         deviceInfo = CONTAINING_RECORD(ItemList, struct DeviceInfo, ListEntry);
3845         InterfaceListEntry = deviceInfo->InterfaceListHead.Flink;
3846         while (InterfaceListEntry != &deviceInfo->InterfaceListHead)
3847         {
3848             deviceInterface = CONTAINING_RECORD(InterfaceListEntry, struct DeviceInterface, ListEntry);
3849             if (!IsEqualIID(&deviceInterface->InterfaceClassGuid, &ClassId))
3850             {
3851                 InterfaceListEntry = InterfaceListEntry->Flink;
3852                 continue;
3853             }
3854 
3855             if (!wcsicmp(deviceInterface->SymbolicLink, DevicePath))
3856             {
3857                 if (DeviceInterfaceData)
3858                 {
3859                     DeviceInterfaceData->Reserved = (ULONG_PTR)deviceInterface;
3860                     DeviceInterfaceData->Flags = deviceInterface->Flags;
3861                     CopyMemory(&DeviceInterfaceData->InterfaceClassGuid, &ClassId, sizeof(GUID));
3862                 }
3863 
3864                 return TRUE;
3865             }
3866 
3867         }
3868     }
3869 
3870 
3871     dwIndex = 0;
3872     do
3873     {
3874         Buffer[0] = 0;
3875         dwKeyName = sizeof(Buffer) / sizeof(WCHAR);
3876         dwError = RegEnumKeyExW(hKey, dwIndex, Buffer, &dwKeyName, NULL, NULL, NULL, NULL);
3877 
3878         if (dwError != ERROR_SUCCESS)
3879             break;
3880 
3881         if (RegOpenKeyExW(hKey, Buffer, 0, KEY_READ, &hDevKey) != ERROR_SUCCESS)
3882             break;
3883 
3884         dwSubIndex = 0;
3885         InstancePath[0] = 0;
3886         dwKeyName = sizeof(InstancePath);
3887 
3888         dwError = RegQueryValueExW(hDevKey, L"DeviceInstance", NULL, NULL, (LPBYTE)InstancePath, &dwKeyName);
3889 
3890         while(TRUE)
3891         {
3892             Buffer[0] = 0;
3893             dwKeyName = sizeof(Buffer) / sizeof(WCHAR);
3894             dwError = RegEnumKeyExW(hDevKey, dwSubIndex, Buffer, &dwKeyName, NULL, NULL, NULL, NULL);
3895 
3896             if (dwError != ERROR_SUCCESS)
3897                 break;
3898 
3899             dwError = RegOpenKeyExW(hDevKey, Buffer, 0, KEY_READ, &hSymKey);
3900             if (dwError != ERROR_SUCCESS)
3901                 break;
3902 
3903             /* query for symbolic link */
3904             dwKeyName = sizeof(SymBuffer);
3905             SymBuffer[0] = L'\0';
3906             dwError = RegQueryValueExW(hSymKey, L"SymbolicLink", NULL, NULL, (LPBYTE)SymBuffer, &dwKeyName);
3907 
3908             if (dwError != ERROR_SUCCESS)
3909             {
3910                 RegCloseKey(hSymKey);
3911                 break;
3912             }
3913 
3914             if (!wcsicmp(SymBuffer, DevicePath))
3915             {
3916                 Ret = CreateDeviceInfo(list, InstancePath, &ClassId, &deviceInfo);
3917                 RegCloseKey(hSymKey);
3918                 RegCloseKey(hDevKey);
3919                 RegCloseKey(hKey);
3920 
3921                 if (Ret)
3922                 {
3923                     deviceInterface = HeapAlloc(GetProcessHeap(), 0, sizeof(struct DeviceInterface) + (wcslen(SymBuffer) + 1) * sizeof(WCHAR));
3924                     if (deviceInterface)
3925                     {
3926 
3927                         CopyMemory(&deviceInterface->InterfaceClassGuid, &ClassId, sizeof(GUID));
3928                         deviceInterface->DeviceInfo = deviceInfo;
3929                         deviceInterface->Flags = SPINT_ACTIVE; //FIXME
3930 
3931                         wcscpy(deviceInterface->SymbolicLink, SymBuffer);
3932 
3933                         InsertTailList(&deviceInfo->InterfaceListHead, &deviceInterface->ListEntry);
3934                         InsertTailList(&list->ListHead, &deviceInfo->ListEntry);
3935 
3936 
3937                         if (DeviceInterfaceData)
3938                         {
3939                             DeviceInterfaceData->Reserved = (ULONG_PTR)deviceInterface;
3940                             DeviceInterfaceData->Flags = deviceInterface->Flags;
3941                             CopyMemory(&DeviceInterfaceData->InterfaceClassGuid, &ClassId, sizeof(GUID));
3942                         }
3943                         else
3944                         {
3945                             Ret = FALSE;
3946                             SetLastError(ERROR_INVALID_USER_BUFFER);
3947                         }
3948                     }
3949                 }
3950                 else
3951                 {
3952                     HeapFree(GetProcessHeap(), 0, deviceInfo);
3953                     Ret = FALSE;
3954                 }
3955                 return Ret;
3956         }
3957         RegCloseKey(hSymKey);
3958         dwSubIndex++;
3959     }
3960 
3961     RegCloseKey(hDevKey);
3962     dwIndex++;
3963     } while(TRUE);
3964 
3965     RegCloseKey(hKey);
3966     return FALSE;
3967 }
3968 
3969 /***********************************************************************
3970  *		SetupDiOpenDeviceInterfaceA (SETUPAPI.@)
3971  */
3972 BOOL WINAPI SetupDiOpenDeviceInterfaceA(
3973         HDEVINFO DeviceInfoSet,
3974         PCSTR DevicePath,
3975         DWORD OpenFlags,
3976         PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
3977 {
3978     LPWSTR DevicePathW = NULL;
3979     BOOL bResult;
3980 
3981     TRACE("%s(%p %s %08lx %p)\n", __FUNCTION__, DeviceInfoSet, debugstr_a(DevicePath), OpenFlags, DeviceInterfaceData);
3982 
3983     DevicePathW = pSetupMultiByteToUnicode(DevicePath, CP_ACP);
3984     if (DevicePathW == NULL)
3985         return FALSE;
3986 
3987     bResult = SetupDiOpenDeviceInterfaceW(DeviceInfoSet,
3988         DevicePathW, OpenFlags, DeviceInterfaceData);
3989 
3990     MyFree(DevicePathW);
3991 
3992     return bResult;
3993 }
3994 
3995 /***********************************************************************
3996  *		SetupDiSetClassInstallParamsA (SETUPAPI.@)
3997  */
3998 BOOL WINAPI SetupDiSetClassInstallParamsA(
3999         HDEVINFO  DeviceInfoSet,
4000         PSP_DEVINFO_DATA DeviceInfoData,
4001         PSP_CLASSINSTALL_HEADER ClassInstallParams,
4002         DWORD ClassInstallParamsSize)
4003 {
4004     FIXME("%p %p %x %u\n",DeviceInfoSet, DeviceInfoData,
4005           ClassInstallParams->InstallFunction, ClassInstallParamsSize);
4006     return FALSE;
4007 }
4008 
4009 static BOOL WINAPI
4010 IntSetupDiRegisterDeviceInfo(
4011         IN HDEVINFO DeviceInfoSet,
4012         IN OUT PSP_DEVINFO_DATA DeviceInfoData)
4013 {
4014     return SetupDiRegisterDeviceInfo(DeviceInfoSet, DeviceInfoData, 0, NULL, NULL, NULL);
4015 }
4016 
4017 /***********************************************************************
4018  *		SetupDiCallClassInstaller (SETUPAPI.@)
4019  */
4020 BOOL WINAPI SetupDiCallClassInstaller(
4021         DI_FUNCTION InstallFunction,
4022         HDEVINFO DeviceInfoSet,
4023         PSP_DEVINFO_DATA DeviceInfoData)
4024 {
4025     BOOL ret = FALSE;
4026 
4027     TRACE("%s(%u %p %p)\n", __FUNCTION__, InstallFunction, DeviceInfoSet, DeviceInfoData);
4028 
4029     if (!DeviceInfoSet)
4030         SetLastError(ERROR_INVALID_PARAMETER);
4031     else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
4032         SetLastError(ERROR_INVALID_HANDLE);
4033     else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
4034         SetLastError(ERROR_INVALID_HANDLE);
4035     else if (((struct DeviceInfoSet *)DeviceInfoSet)->HKLM != HKEY_LOCAL_MACHINE)
4036         SetLastError(ERROR_INVALID_HANDLE);
4037     else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
4038         SetLastError(ERROR_INVALID_USER_BUFFER);
4039     else
4040     {
4041         SP_DEVINSTALL_PARAMS_W InstallParams;
4042 #define CLASS_COINSTALLER  0x1
4043 #define DEVICE_COINSTALLER 0x2
4044 #define CLASS_INSTALLER    0x4
4045         UCHAR CanHandle = 0;
4046         DEFAULT_CLASS_INSTALL_PROC DefaultHandler = NULL;
4047 
4048         switch (InstallFunction)
4049         {
4050             case DIF_ADDPROPERTYPAGE_ADVANCED:
4051                 CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
4052                 break;
4053             case DIF_ADDREMOTEPROPERTYPAGE_ADVANCED:
4054                 CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
4055                 break;
4056             case DIF_ALLOW_INSTALL:
4057                 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4058                 break;
4059             case DIF_DETECT:
4060                 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4061                 break;
4062             case DIF_DESTROYPRIVATEDATA:
4063                 CanHandle = CLASS_INSTALLER;
4064                 break;
4065             case DIF_INSTALLDEVICE:
4066                 CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
4067                 DefaultHandler = SetupDiInstallDevice;
4068                 break;
4069             case DIF_INSTALLDEVICEFILES:
4070                 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4071                 DefaultHandler = SetupDiInstallDriverFiles;
4072                 break;
4073             case DIF_INSTALLINTERFACES:
4074                 CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
4075                 DefaultHandler = SetupDiInstallDeviceInterfaces;
4076                 break;
4077             case DIF_NEWDEVICEWIZARD_FINISHINSTALL:
4078                 CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
4079                 break;
4080             case DIF_NEWDEVICEWIZARD_POSTANALYZE:
4081                 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4082                 break;
4083             case DIF_NEWDEVICEWIZARD_PREANALYZE:
4084                 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4085                 break;
4086             case DIF_NEWDEVICEWIZARD_PRESELECT:
4087                 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4088                 break;
4089             case DIF_NEWDEVICEWIZARD_SELECT:
4090                 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4091                 break;
4092             case DIF_POWERMESSAGEWAKE:
4093                 CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
4094                 break;
4095             case DIF_PROPERTYCHANGE:
4096                 CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
4097                 DefaultHandler = SetupDiChangeState;
4098                 break;
4099             case DIF_REGISTER_COINSTALLERS:
4100                 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4101                 DefaultHandler = SetupDiRegisterCoDeviceInstallers;
4102                 break;
4103             case DIF_REGISTERDEVICE:
4104                 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4105                 DefaultHandler = IntSetupDiRegisterDeviceInfo;
4106                 break;
4107             case DIF_REMOVE:
4108                 CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
4109                 DefaultHandler = SetupDiRemoveDevice;
4110                 break;
4111             case DIF_SELECTBESTCOMPATDRV:
4112                 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4113                 DefaultHandler = SetupDiSelectBestCompatDrv;
4114                 break;
4115             case DIF_SELECTDEVICE:
4116                 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4117                 DefaultHandler = SetupDiSelectDevice;
4118                 break;
4119             case DIF_TROUBLESHOOTER:
4120                 CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
4121                 break;
4122             case DIF_UNREMOVE:
4123                 CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
4124                 DefaultHandler = SetupDiUnremoveDevice;
4125                 break;
4126             default:
4127                 ERR("Install function %u not supported\n", InstallFunction);
4128                 SetLastError(ERROR_NOT_SUPPORTED);
4129         }
4130 
4131         InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
4132         if (!SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams))
4133             /* Don't process this call, as a parameter is invalid */
4134             CanHandle = 0;
4135 
4136         if (CanHandle != 0)
4137         {
4138             LIST_ENTRY ClassCoInstallersListHead;
4139             LIST_ENTRY DeviceCoInstallersListHead;
4140             HMODULE ClassInstallerLibrary = NULL;
4141             CLASS_INSTALL_PROC ClassInstaller = NULL;
4142             COINSTALLER_CONTEXT_DATA Context;
4143             PLIST_ENTRY ListEntry;
4144             HKEY hKey;
4145             DWORD dwRegType, dwLength;
4146             DWORD rc = NO_ERROR;
4147 
4148             InitializeListHead(&ClassCoInstallersListHead);
4149             InitializeListHead(&DeviceCoInstallersListHead);
4150 
4151             if (CanHandle & DEVICE_COINSTALLER)
4152             {
4153                 hKey = SETUPDI_OpenDrvKey(((struct DeviceInfoSet *)DeviceInfoSet)->HKLM, (struct DeviceInfo *)DeviceInfoData->Reserved, KEY_QUERY_VALUE);
4154                 if (hKey != INVALID_HANDLE_VALUE)
4155                 {
4156                     rc = RegQueryValueExW(hKey, REGSTR_VAL_COINSTALLERS_32, NULL, &dwRegType, NULL, &dwLength);
4157                     if (rc == ERROR_SUCCESS && dwRegType == REG_MULTI_SZ)
4158                     {
4159                         LPWSTR KeyBuffer = HeapAlloc(GetProcessHeap(), 0, dwLength);
4160                         if (KeyBuffer != NULL)
4161                         {
4162                             rc = RegQueryValueExW(hKey, REGSTR_VAL_COINSTALLERS_32, NULL, NULL, (LPBYTE)KeyBuffer, &dwLength);
4163                             if (rc == ERROR_SUCCESS)
4164                             {
4165                                 LPWSTR ptr;
4166                                 for (ptr = KeyBuffer; *ptr; ptr += strlenW(ptr) + 1)
4167                                 {
4168                                     /* Add coinstaller to DeviceCoInstallersListHead list */
4169                                     struct CoInstallerElement *coinstaller;
4170                                     TRACE("Got device coinstaller '%s'\n", debugstr_w(ptr));
4171                                     coinstaller = HeapAlloc(GetProcessHeap(), 0, sizeof(struct CoInstallerElement));
4172                                     if (!coinstaller)
4173                                         continue;
4174                                     ZeroMemory(coinstaller, sizeof(struct CoInstallerElement));
4175                                     if (GetFunctionPointer(ptr, &coinstaller->Module, (PVOID*)&coinstaller->Function) == ERROR_SUCCESS)
4176                                         InsertTailList(&DeviceCoInstallersListHead, &coinstaller->ListEntry);
4177                                     else
4178                                         HeapFree(GetProcessHeap(), 0, coinstaller);
4179                                 }
4180                             }
4181                             HeapFree(GetProcessHeap(), 0, KeyBuffer);
4182                         }
4183                     }
4184                     RegCloseKey(hKey);
4185                 }
4186             }
4187             if (CanHandle & CLASS_COINSTALLER)
4188             {
4189                 rc = RegOpenKeyExW(
4190                     HKEY_LOCAL_MACHINE,
4191                     REGSTR_PATH_CODEVICEINSTALLERS,
4192                     0, /* Options */
4193                     KEY_QUERY_VALUE,
4194                     &hKey);
4195                 if (rc == ERROR_SUCCESS)
4196                 {
4197                     WCHAR szGuidString[40];
4198                     if (pSetupStringFromGuid(&DeviceInfoData->ClassGuid, szGuidString, ARRAYSIZE(szGuidString)) == ERROR_SUCCESS)
4199                     {
4200                         rc = RegQueryValueExW(hKey, szGuidString, NULL, &dwRegType, NULL, &dwLength);
4201                         if (rc == ERROR_SUCCESS && dwRegType == REG_MULTI_SZ)
4202                         {
4203                             LPWSTR KeyBuffer = HeapAlloc(GetProcessHeap(), 0, dwLength);
4204                             if (KeyBuffer != NULL)
4205                             {
4206                                 rc = RegQueryValueExW(hKey, szGuidString, NULL, NULL, (LPBYTE)KeyBuffer, &dwLength);
4207                                 if (rc == ERROR_SUCCESS)
4208                                 {
4209                                     LPWSTR ptr;
4210                                     for (ptr = KeyBuffer; *ptr; ptr += strlenW(ptr) + 1)
4211                                     {
4212                                         /* Add coinstaller to ClassCoInstallersListHead list */
4213                                         struct CoInstallerElement *coinstaller;
4214                                         TRACE("Got class coinstaller '%s'\n", debugstr_w(ptr));
4215                                         coinstaller = HeapAlloc(GetProcessHeap(), 0, sizeof(struct CoInstallerElement));
4216                                         if (!coinstaller)
4217                                             continue;
4218                                         ZeroMemory(coinstaller, sizeof(struct CoInstallerElement));
4219                                         if (GetFunctionPointer(ptr, &coinstaller->Module, (PVOID*)&coinstaller->Function) == ERROR_SUCCESS)
4220                                             InsertTailList(&ClassCoInstallersListHead, &coinstaller->ListEntry);
4221                                         else
4222                                             HeapFree(GetProcessHeap(), 0, coinstaller);
4223                                     }
4224                                 }
4225                                 HeapFree(GetProcessHeap(), 0, KeyBuffer);
4226                             }
4227                         }
4228                     }
4229                     RegCloseKey(hKey);
4230                 }
4231             }
4232             if ((CanHandle & CLASS_INSTALLER) && !(InstallParams.FlagsEx & DI_FLAGSEX_CI_FAILED))
4233             {
4234                 hKey = SetupDiOpenClassRegKey(&DeviceInfoData->ClassGuid, KEY_QUERY_VALUE);
4235                 if (hKey != INVALID_HANDLE_VALUE)
4236                 {
4237                     rc = RegQueryValueExW(hKey, REGSTR_VAL_INSTALLER_32, NULL, &dwRegType, NULL, &dwLength);
4238                     if (rc == ERROR_SUCCESS && dwRegType == REG_SZ)
4239                     {
4240                         LPWSTR KeyBuffer = HeapAlloc(GetProcessHeap(), 0, dwLength);
4241                         if (KeyBuffer != NULL)
4242                         {
4243                             rc = RegQueryValueExW(hKey, REGSTR_VAL_INSTALLER_32, NULL, NULL, (LPBYTE)KeyBuffer, &dwLength);
4244                             if (rc == ERROR_SUCCESS)
4245                             {
4246                                 /* Get ClassInstaller function pointer */
4247                                 TRACE("Got class installer '%s'\n", debugstr_w(KeyBuffer));
4248                                 if (GetFunctionPointer(KeyBuffer, &ClassInstallerLibrary, (PVOID*)&ClassInstaller) != ERROR_SUCCESS)
4249                                 {
4250                                     InstallParams.FlagsEx |= DI_FLAGSEX_CI_FAILED;
4251                                     SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
4252                                 }
4253                             }
4254                             HeapFree(GetProcessHeap(), 0, KeyBuffer);
4255                         }
4256                     }
4257                     RegCloseKey(hKey);
4258                 }
4259             }
4260 
4261             /* Call Class co-installers */
4262             Context.PostProcessing = FALSE;
4263             rc = NO_ERROR;
4264             ListEntry = ClassCoInstallersListHead.Flink;
4265             while (rc == NO_ERROR && ListEntry != &ClassCoInstallersListHead)
4266             {
4267                 struct CoInstallerElement *coinstaller;
4268                 coinstaller = CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry);
4269                 rc = (*coinstaller->Function)(InstallFunction, DeviceInfoSet, DeviceInfoData, &Context);
4270                 coinstaller->PrivateData = Context.PrivateData;
4271                 if (rc == ERROR_DI_POSTPROCESSING_REQUIRED)
4272                 {
4273                     coinstaller->DoPostProcessing = TRUE;
4274                     rc = NO_ERROR;
4275                 }
4276                 ListEntry = ListEntry->Flink;
4277             }
4278 
4279             /* Call Device co-installers */
4280             ListEntry = DeviceCoInstallersListHead.Flink;
4281             while (rc == NO_ERROR && ListEntry != &DeviceCoInstallersListHead)
4282             {
4283                 struct CoInstallerElement *coinstaller;
4284                 coinstaller = CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry);
4285                 rc = (*coinstaller->Function)(InstallFunction, DeviceInfoSet, DeviceInfoData, &Context);
4286                 coinstaller->PrivateData = Context.PrivateData;
4287                 if (rc == ERROR_DI_POSTPROCESSING_REQUIRED)
4288                 {
4289                     coinstaller->DoPostProcessing = TRUE;
4290                     rc = NO_ERROR;
4291                 }
4292                 ListEntry = ListEntry->Flink;
4293             }
4294 
4295             /* Call Class installer */
4296             if (ClassInstaller)
4297             {
4298                 rc = (*ClassInstaller)(InstallFunction, DeviceInfoSet, DeviceInfoData);
4299                 FreeFunctionPointer(ClassInstallerLibrary, ClassInstaller);
4300             }
4301             else
4302                 rc = ERROR_DI_DO_DEFAULT;
4303 
4304             /* Call default handler */
4305             if (rc == ERROR_DI_DO_DEFAULT)
4306             {
4307                 if (DefaultHandler && !(InstallParams.Flags & DI_NODI_DEFAULTACTION))
4308                 {
4309                     if ((*DefaultHandler)(DeviceInfoSet, DeviceInfoData))
4310                         rc = NO_ERROR;
4311                     else
4312                         rc = GetLastError();
4313                 }
4314                 else
4315                     rc = NO_ERROR;
4316             }
4317 
4318             /* Call Class co-installers that required postprocessing */
4319             Context.PostProcessing = TRUE;
4320             ListEntry = ClassCoInstallersListHead.Flink;
4321             while (ListEntry != &ClassCoInstallersListHead)
4322             {
4323                 struct CoInstallerElement *coinstaller;
4324                 coinstaller = CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry);
4325                 if (coinstaller->DoPostProcessing)
4326                 {
4327                     Context.InstallResult = rc;
4328                     Context.PrivateData = coinstaller->PrivateData;
4329                     rc = (*coinstaller->Function)(InstallFunction, DeviceInfoSet, DeviceInfoData, &Context);
4330                 }
4331                 FreeFunctionPointer(coinstaller->Module, coinstaller->Function);
4332                 ListEntry = ListEntry->Flink;
4333             }
4334 
4335             /* Call Device co-installers that required postprocessing */
4336             ListEntry = DeviceCoInstallersListHead.Flink;
4337             while (ListEntry != &DeviceCoInstallersListHead)
4338             {
4339                 struct CoInstallerElement *coinstaller;
4340                 coinstaller = CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry);
4341                 if (coinstaller->DoPostProcessing)
4342                 {
4343                     Context.InstallResult = rc;
4344                     Context.PrivateData = coinstaller->PrivateData;
4345                     rc = (*coinstaller->Function)(InstallFunction, DeviceInfoSet, DeviceInfoData, &Context);
4346                 }
4347                 FreeFunctionPointer(coinstaller->Module, coinstaller->Function);
4348                 ListEntry = ListEntry->Flink;
4349             }
4350 
4351             /* Free allocated memory */
4352             while (!IsListEmpty(&ClassCoInstallersListHead))
4353             {
4354                 ListEntry = RemoveHeadList(&ClassCoInstallersListHead);
4355                 HeapFree(GetProcessHeap(), 0, CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry));
4356             }
4357             while (!IsListEmpty(&DeviceCoInstallersListHead))
4358             {
4359                 ListEntry = RemoveHeadList(&DeviceCoInstallersListHead);
4360                 HeapFree(GetProcessHeap(), 0, CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry));
4361             }
4362 
4363             ret = (rc == NO_ERROR);
4364         }
4365     }
4366 
4367     TRACE("Returning %d\n", ret);
4368     return ret;
4369 }
4370 
4371 /***********************************************************************
4372  *		SetupDiGetDeviceInstallParamsA (SETUPAPI.@)
4373  */
4374 BOOL WINAPI SetupDiGetDeviceInstallParamsA(
4375         HDEVINFO DeviceInfoSet,
4376         PSP_DEVINFO_DATA DeviceInfoData,
4377         PSP_DEVINSTALL_PARAMS_A DeviceInstallParams)
4378 {
4379     SP_DEVINSTALL_PARAMS_W deviceInstallParamsW;
4380     BOOL ret = FALSE;
4381 
4382     TRACE("%s(%p %p %p)\n", __FUNCTION__, DeviceInfoSet, DeviceInfoData, DeviceInstallParams);
4383 
4384     if (DeviceInstallParams == NULL)
4385         SetLastError(ERROR_INVALID_PARAMETER);
4386     else if (DeviceInstallParams->cbSize != sizeof(SP_DEVINSTALL_PARAMS_A))
4387         SetLastError(ERROR_INVALID_USER_BUFFER);
4388     else
4389     {
4390         deviceInstallParamsW.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
4391         ret = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &deviceInstallParamsW);
4392 
4393         if (ret)
4394         {
4395             /* Do W->A conversion */
4396             memcpy(
4397                 DeviceInstallParams,
4398                 &deviceInstallParamsW,
4399                 FIELD_OFFSET(SP_DEVINSTALL_PARAMS_W, DriverPath));
4400             if (WideCharToMultiByte(CP_ACP, 0, deviceInstallParamsW.DriverPath, -1,
4401                 DeviceInstallParams->DriverPath, MAX_PATH, NULL, NULL) == 0)
4402             {
4403                 DeviceInstallParams->DriverPath[0] = '\0';
4404                 ret = FALSE;
4405             }
4406         }
4407     }
4408 
4409     TRACE("Returning %d\n", ret);
4410     return ret;
4411 }
4412 
4413 /***********************************************************************
4414  *		SetupDiGetDeviceInfoListClass  (SETUPAPI.@)
4415  */
4416 BOOL WINAPI
4417 SetupDiGetDeviceInfoListClass(
4418         IN HDEVINFO DeviceInfoSet,
4419         OUT LPGUID ClassGuid)
4420 {
4421     struct DeviceInfoSet *list;
4422     BOOL ret = FALSE;
4423 
4424     TRACE("%s(%p %p)\n", __FUNCTION__, DeviceInfoSet, ClassGuid);
4425 
4426     if (!DeviceInfoSet)
4427         SetLastError(ERROR_INVALID_HANDLE);
4428     else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
4429         SetLastError(ERROR_INVALID_HANDLE);
4430     else if (IsEqualIID(&list->ClassGuid, &GUID_NULL))
4431         SetLastError(ERROR_NO_ASSOCIATED_CLASS);
4432     else
4433     {
4434         *ClassGuid = list->ClassGuid;
4435 
4436         ret = TRUE;
4437     }
4438 
4439     TRACE("Returning %d\n", ret);
4440     return ret;
4441 }
4442 
4443 /***********************************************************************
4444  *		SetupDiGetDeviceInstallParamsW (SETUPAPI.@)
4445  */
4446 BOOL WINAPI
4447 SetupDiGetDeviceInstallParamsW(
4448         IN HDEVINFO DeviceInfoSet,
4449         IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
4450         OUT PSP_DEVINSTALL_PARAMS_W DeviceInstallParams)
4451 {
4452     struct DeviceInfoSet *list;
4453     BOOL ret = FALSE;
4454 
4455     TRACE("%s(%p %p %p)\n", __FUNCTION__, DeviceInfoSet, DeviceInfoData, DeviceInstallParams);
4456 
4457     if (!DeviceInfoSet)
4458         SetLastError(ERROR_INVALID_HANDLE);
4459     else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
4460         SetLastError(ERROR_INVALID_HANDLE);
4461     else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
4462         SetLastError(ERROR_INVALID_USER_BUFFER);
4463     else if (!DeviceInstallParams)
4464         SetLastError(ERROR_INVALID_PARAMETER);
4465     else if (DeviceInstallParams->cbSize != sizeof(SP_DEVINSTALL_PARAMS_W))
4466         SetLastError(ERROR_INVALID_USER_BUFFER);
4467     else
4468     {
4469         PSP_DEVINSTALL_PARAMS_W Source;
4470 
4471         if (DeviceInfoData)
4472             Source = &((struct DeviceInfo *)DeviceInfoData->Reserved)->InstallParams;
4473         else
4474             Source = &list->InstallParams;
4475 
4476         ret = TRUE;
4477 
4478         _SEH2_TRY
4479         {
4480             memcpy(DeviceInstallParams, Source, Source->cbSize);
4481         }
4482         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4483         {
4484             SetLastError(RtlNtStatusToDosError(_SEH2_GetExceptionCode()));
4485             ret = FALSE;
4486         }
4487         _SEH2_END;
4488     }
4489 
4490     TRACE("Returning %d\n", ret);
4491     return ret;
4492 }
4493 
4494 static BOOL
4495 CheckDeviceInstallParameters(
4496         IN PSP_DEVINSTALL_PARAMS_W DeviceInstallParams)
4497 {
4498     DWORD SupportedFlags =
4499         DI_NOVCP |                            /* 0x00000008 */
4500         DI_DIDCOMPAT |                        /* 0x00000010 */
4501         DI_DIDCLASS |                         /* 0x00000020 */
4502         DI_NEEDRESTART |                      /* 0x00000080 */
4503         DI_NEEDREBOOT |                       /* 0x00000100 */
4504         DI_RESOURCEPAGE_ADDED |               /* 0x00002000 */
4505         DI_PROPERTIES_CHANGE |                /* 0x00004000 */
4506         DI_ENUMSINGLEINF |                    /* 0x00010000 */
4507         DI_DONOTCALLCONFIGMG |                /* 0x00020000 */
4508         DI_CLASSINSTALLPARAMS |               /* 0x00100000 */
4509         DI_NODI_DEFAULTACTION |               /* 0x00200000 */
4510         DI_QUIETINSTALL |                     /* 0x00800000 */
4511         DI_NOFILECOPY |                       /* 0x01000000 */
4512         DI_DRIVERPAGE_ADDED;                  /* 0x04000000 */
4513     DWORD SupportedFlagsEx =
4514         DI_FLAGSEX_CI_FAILED |                /* 0x00000004 */
4515         DI_FLAGSEX_DIDINFOLIST |              /* 0x00000010 */
4516         DI_FLAGSEX_DIDCOMPATINFO |            /* 0x00000020 */
4517         DI_FLAGSEX_ALLOWEXCLUDEDDRVS |        /* 0x00000800 */
4518         DI_FLAGSEX_NO_DRVREG_MODIFY |         /* 0x00008000 */
4519         DI_FLAGSEX_INSTALLEDDRIVER;           /* 0x04000000 */
4520     BOOL ret = FALSE;
4521 
4522     /* FIXME: add support for more flags */
4523 
4524     /* FIXME: DI_CLASSINSTALLPARAMS flag is not correctly used.
4525      * It should be checked before accessing to other values
4526      * of the SP_DEVINSTALL_PARAMS structure */
4527 
4528     if (DeviceInstallParams->Flags & ~SupportedFlags)
4529     {
4530         FIXME("Unknown Flags: 0x%08lx\n", DeviceInstallParams->Flags & ~SupportedFlags);
4531         SetLastError(ERROR_INVALID_FLAGS);
4532     }
4533     else if (DeviceInstallParams->FlagsEx & ~SupportedFlagsEx)
4534     {
4535         FIXME("Unknown FlagsEx: 0x%08lx\n", DeviceInstallParams->FlagsEx & ~SupportedFlagsEx);
4536         SetLastError(ERROR_INVALID_FLAGS);
4537     }
4538     else if ((DeviceInstallParams->Flags & DI_NOVCP)
4539         && (DeviceInstallParams->FileQueue == NULL || DeviceInstallParams->FileQueue == (HSPFILEQ)INVALID_HANDLE_VALUE))
4540         SetLastError(ERROR_INVALID_USER_BUFFER);
4541     else
4542     {
4543         /* FIXME: check Reserved field */
4544         ret = TRUE;
4545     }
4546 
4547     return ret;
4548 }
4549 
4550 /***********************************************************************
4551  *		SetupDiSetDeviceInstallParamsW (SETUPAPI.@)
4552  */
4553 BOOL WINAPI
4554 SetupDiSetDeviceInstallParamsW(
4555         IN HDEVINFO DeviceInfoSet,
4556         IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
4557         IN PSP_DEVINSTALL_PARAMS_W DeviceInstallParams)
4558 {
4559     struct DeviceInfoSet *list;
4560     BOOL ret = FALSE;
4561 
4562     TRACE("%s(%p %p %p)\n", __FUNCTION__, DeviceInfoSet, DeviceInfoData, DeviceInstallParams);
4563 
4564     if (!DeviceInfoSet)
4565         SetLastError(ERROR_INVALID_HANDLE);
4566     else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
4567         SetLastError(ERROR_INVALID_HANDLE);
4568     else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
4569         SetLastError(ERROR_INVALID_USER_BUFFER);
4570     else if (!DeviceInstallParams)
4571         SetLastError(ERROR_INVALID_PARAMETER);
4572     else if (DeviceInstallParams->cbSize != sizeof(SP_DEVINSTALL_PARAMS_W))
4573         SetLastError(ERROR_INVALID_USER_BUFFER);
4574     else if (CheckDeviceInstallParameters(DeviceInstallParams))
4575     {
4576         PSP_DEVINSTALL_PARAMS_W Destination;
4577 
4578         if (DeviceInfoData)
4579             Destination = &((struct DeviceInfo *)DeviceInfoData->Reserved)->InstallParams;
4580         else
4581             Destination = &list->InstallParams;
4582         memcpy(Destination, DeviceInstallParams, DeviceInstallParams->cbSize);
4583         ret = TRUE;
4584     }
4585 
4586     TRACE("Returning %d\n", ret);
4587     return ret;
4588 }
4589 
4590 /***********************************************************************
4591  *		SetupDiSetDeviceInstallParamsW (SETUPAPI.@)
4592  */
4593 BOOL WINAPI
4594 SetupDiSetDeviceInstallParamsA(
4595         HDEVINFO DeviceInfoSet,
4596         PSP_DEVINFO_DATA DeviceInfoData,
4597         PSP_DEVINSTALL_PARAMS_A DeviceInstallParams)
4598 {
4599     SP_DEVINSTALL_PARAMS_W deviceInstallParamsW;
4600     int len = 0;
4601     BOOL ret = FALSE;
4602 
4603     TRACE("%s(%p %p %p)\n", __FUNCTION__, DeviceInfoSet, DeviceInfoData, DeviceInstallParams);
4604 
4605     if (DeviceInstallParams == NULL)
4606         SetLastError(ERROR_INVALID_PARAMETER);
4607     else if (DeviceInstallParams->cbSize < sizeof(SP_DEVINSTALL_PARAMS_A))
4608         SetLastError(ERROR_INVALID_USER_BUFFER);
4609     else
4610     {
4611         memcpy(&deviceInstallParamsW, DeviceInstallParams, FIELD_OFFSET(SP_DEVINSTALL_PARAMS_A, DriverPath));
4612         deviceInstallParamsW.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
4613         len = MultiByteToWideChar(CP_ACP, 0, DeviceInstallParams->DriverPath, -1, NULL, 0);
4614         if (!len)
4615         {
4616             ERR("DrivePath is NULL\n");
4617             ret = FALSE;
4618         }
4619         else
4620         {
4621             MultiByteToWideChar(CP_ACP, 0, DeviceInstallParams->DriverPath, -1, deviceInstallParamsW.DriverPath, len);
4622             ret = SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &deviceInstallParamsW);
4623         }
4624     }
4625 
4626     TRACE("Returning %d\n", ret);
4627     return ret;
4628 }
4629 
4630 static HKEY
4631 OpenHardwareProfileKey(
4632         IN HKEY HKLM,
4633         IN DWORD HwProfile,
4634         IN DWORD samDesired)
4635 {
4636     HKEY hHWProfilesKey = NULL;
4637     HKEY hHWProfileKey = NULL;
4638     HKEY ret = INVALID_HANDLE_VALUE;
4639     LONG rc;
4640 
4641     rc = RegOpenKeyExW(HKLM,
4642                        REGSTR_PATH_HWPROFILES,
4643                        0,
4644                        READ_CONTROL,
4645                        &hHWProfilesKey);
4646     if (rc != ERROR_SUCCESS)
4647     {
4648         SetLastError(rc);
4649         goto cleanup;
4650     }
4651     if (HwProfile == 0)
4652     {
4653         rc = RegOpenKeyExW(hHWProfilesKey,
4654                            REGSTR_KEY_CURRENT,
4655                            0,
4656                            KEY_CREATE_SUB_KEY,
4657                            &hHWProfileKey);
4658     }
4659     else
4660     {
4661         WCHAR subKey[5];
4662         snprintfW(subKey, 4, InstanceKeyFormat, HwProfile);
4663         subKey[4] = '\0';
4664         rc = RegOpenKeyExW(hHWProfilesKey,
4665                            subKey,
4666                            0,
4667                            KEY_CREATE_SUB_KEY,
4668                            &hHWProfileKey);
4669     }
4670     if (rc != ERROR_SUCCESS)
4671     {
4672         SetLastError(rc);
4673         goto cleanup;
4674     }
4675     ret = hHWProfileKey;
4676 
4677 cleanup:
4678     if (hHWProfilesKey != NULL)
4679         RegCloseKey(hHWProfilesKey);
4680     if (hHWProfileKey != NULL && hHWProfileKey != ret)
4681         RegCloseKey(hHWProfileKey);
4682     return ret;
4683 }
4684 
4685 static BOOL
4686 IsDeviceInfoInDeviceInfoSet(
4687         struct DeviceInfoSet *deviceInfoSet,
4688         struct DeviceInfo *deviceInfo)
4689 {
4690     PLIST_ENTRY ListEntry;
4691 
4692     ListEntry = deviceInfoSet->ListHead.Flink;
4693     while (ListEntry != &deviceInfoSet->ListHead)
4694     {
4695         if (deviceInfo == CONTAINING_RECORD(ListEntry, struct DeviceInfo, ListEntry))
4696             return TRUE;
4697 
4698         ListEntry = ListEntry->Flink;
4699     }
4700 
4701     return FALSE;
4702 }
4703 
4704 /***********************************************************************
4705  *		SetupDiDeleteDeviceInfo (SETUPAPI.@)
4706  */
4707 BOOL WINAPI
4708 SetupDiDeleteDeviceInfo(
4709         IN HDEVINFO DeviceInfoSet,
4710         IN PSP_DEVINFO_DATA DeviceInfoData)
4711 {
4712     struct DeviceInfoSet *deviceInfoSet;
4713     struct DeviceInfo *deviceInfo = (struct DeviceInfo *)DeviceInfoData;
4714     BOOL ret = FALSE;
4715 
4716     TRACE("%s(%p %p)\n", __FUNCTION__, DeviceInfoSet, DeviceInfoData);
4717 
4718     if (!DeviceInfoSet)
4719         SetLastError(ERROR_INVALID_HANDLE);
4720     else if ((deviceInfoSet = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
4721         SetLastError(ERROR_INVALID_HANDLE);
4722     else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
4723         SetLastError(ERROR_INVALID_USER_BUFFER);
4724     else if (!IsDeviceInfoInDeviceInfoSet(deviceInfoSet, deviceInfo))
4725         SetLastError(ERROR_INVALID_PARAMETER);
4726     else
4727     {
4728         RemoveEntryList(&deviceInfo->ListEntry);
4729         DestroyDeviceInfo(deviceInfo);
4730         ret = TRUE;
4731     }
4732 
4733     return ret;
4734 }
4735 
4736 
4737 /***********************************************************************
4738  *		SetupDiOpenDeviceInfoA (SETUPAPI.@)
4739  */
4740 BOOL WINAPI
4741 SetupDiOpenDeviceInfoA(
4742         IN HDEVINFO DeviceInfoSet,
4743         IN PCSTR DeviceInstanceId,
4744         IN HWND hwndParent OPTIONAL,
4745         IN DWORD OpenFlags,
4746         OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
4747 {
4748     LPWSTR DeviceInstanceIdW = NULL;
4749     BOOL bResult;
4750 
4751     TRACE("%s(%p %s %p %lx %p)\n", __FUNCTION__, DeviceInfoSet, DeviceInstanceId, hwndParent, OpenFlags, DeviceInfoData);
4752 
4753     DeviceInstanceIdW = pSetupMultiByteToUnicode(DeviceInstanceId, CP_ACP);
4754     if (DeviceInstanceIdW == NULL)
4755         return FALSE;
4756 
4757     bResult = SetupDiOpenDeviceInfoW(DeviceInfoSet,
4758         DeviceInstanceIdW, hwndParent, OpenFlags, DeviceInfoData);
4759 
4760     MyFree(DeviceInstanceIdW);
4761 
4762     return bResult;
4763 }
4764 
4765 
4766 /***********************************************************************
4767  *		SetupDiOpenDeviceInfoW (SETUPAPI.@)
4768  */
4769 BOOL WINAPI
4770 SetupDiOpenDeviceInfoW(
4771         IN HDEVINFO DeviceInfoSet,
4772         IN PCWSTR DeviceInstanceId,
4773         IN HWND hwndParent OPTIONAL,
4774         IN DWORD OpenFlags,
4775         OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
4776 {
4777     struct DeviceInfoSet *list;
4778     HKEY hEnumKey, hKey = NULL;
4779     DWORD rc, dwSize;
4780     BOOL ret = FALSE;
4781 
4782     TRACE("%s(%p %s %p %lx %p)\n", __FUNCTION__,
4783         DeviceInfoSet, debugstr_w(DeviceInstanceId),
4784         hwndParent, OpenFlags, DeviceInfoData);
4785 
4786     if (OpenFlags & DIOD_CANCEL_REMOVE)
4787         FIXME("DIOD_CANCEL_REMOVE flag not implemented\n");
4788 
4789     if (!DeviceInfoSet)
4790         SetLastError(ERROR_INVALID_HANDLE);
4791     else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
4792         SetLastError(ERROR_INVALID_HANDLE);
4793     else if (!DeviceInstanceId)
4794         SetLastError(ERROR_INVALID_PARAMETER);
4795     else if (OpenFlags & ~(DIOD_CANCEL_REMOVE | DIOD_INHERIT_CLASSDRVS))
4796     {
4797         TRACE("Unknown flags: 0x%08lx\n", OpenFlags & ~(DIOD_CANCEL_REMOVE | DIOD_INHERIT_CLASSDRVS));
4798         SetLastError(ERROR_INVALID_FLAGS);
4799     }
4800     else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
4801         SetLastError(ERROR_INVALID_USER_BUFFER);
4802     else
4803     {
4804         struct DeviceInfo *deviceInfo = NULL;
4805         /* Search if device already exists in DeviceInfoSet.
4806          *    If yes, return the existing element
4807          *    If no, create a new element using information in registry
4808          */
4809         PLIST_ENTRY ItemList = list->ListHead.Flink;
4810         while (ItemList != &list->ListHead)
4811         {
4812             deviceInfo = CONTAINING_RECORD(ItemList, struct DeviceInfo, ListEntry);
4813             if (!wcscmp(deviceInfo->instanceId, DeviceInstanceId))
4814                 break;
4815             deviceInfo = NULL;
4816             ItemList = ItemList->Flink;
4817         }
4818 
4819         if (deviceInfo)
4820         {
4821             /* good one found */
4822             ret = TRUE;
4823         }
4824         else
4825         {
4826             GUID ClassGUID;
4827             WCHAR szClassGuid[MAX_GUID_STRING_LEN];
4828 
4829             /* Open supposed registry key */
4830             rc = RegOpenKeyExW(
4831                 list->HKLM,
4832                 REGSTR_PATH_SYSTEMENUM,
4833                 0, /* Options */
4834                 READ_CONTROL,
4835                 &hEnumKey);
4836             if (rc != ERROR_SUCCESS)
4837             {
4838                 SetLastError(rc);
4839                 goto cleanup;
4840             }
4841             rc = RegOpenKeyExW(
4842                 hEnumKey,
4843                 DeviceInstanceId,
4844                 0, /* Options */
4845                 KEY_QUERY_VALUE,
4846                 &hKey);
4847             RegCloseKey(hEnumKey);
4848             if (rc != ERROR_SUCCESS)
4849             {
4850                 if (rc == ERROR_FILE_NOT_FOUND)
4851                     rc = ERROR_NO_SUCH_DEVINST;
4852                 SetLastError(rc);
4853                 goto cleanup;
4854             }
4855 
4856             ClassGUID = GUID_NULL;
4857             dwSize = MAX_GUID_STRING_LEN * sizeof(WCHAR);
4858 
4859             if (RegQueryValueExW(hKey,
4860                                  REGSTR_VAL_CLASSGUID,
4861                                  NULL,
4862                                  NULL,
4863                                  (LPBYTE)szClassGuid,
4864                                  &dwSize) == ERROR_SUCCESS)
4865             {
4866                 szClassGuid[MAX_GUID_STRING_LEN - 2] = UNICODE_NULL;
4867 
4868                 /* Convert a string to a ClassGuid */
4869                 UuidFromStringW(&szClassGuid[1], &ClassGUID);
4870             }
4871 
4872             if (!CreateDeviceInfo(list, DeviceInstanceId, &ClassGUID, &deviceInfo))
4873                 goto cleanup;
4874 
4875             InsertTailList(&list->ListHead, &deviceInfo->ListEntry);
4876 
4877             ret = TRUE;
4878         }
4879 
4880         if (ret && deviceInfo && DeviceInfoData)
4881         {
4882             memcpy(&DeviceInfoData->ClassGuid, &deviceInfo->ClassGuid, sizeof(GUID));
4883             DeviceInfoData->DevInst = deviceInfo->dnDevInst;
4884             DeviceInfoData->Reserved = (ULONG_PTR)deviceInfo;
4885         }
4886     }
4887 
4888 cleanup:
4889     if (hKey != NULL)
4890         RegCloseKey(hKey);
4891     return ret;
4892 }
4893 
4894 
4895 /***********************************************************************
4896  *		SetupDiGetSelectedDevice (SETUPAPI.@)
4897  */
4898 BOOL WINAPI
4899 SetupDiGetSelectedDevice(
4900         IN HDEVINFO DeviceInfoSet,
4901         OUT PSP_DEVINFO_DATA DeviceInfoData)
4902 {
4903     struct DeviceInfoSet *list;
4904     BOOL ret = FALSE;
4905 
4906     TRACE("%s(%p %p)\n", __FUNCTION__, DeviceInfoSet, DeviceInfoData);
4907 
4908     if (!DeviceInfoSet)
4909         SetLastError(ERROR_INVALID_HANDLE);
4910     else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
4911         SetLastError(ERROR_INVALID_HANDLE);
4912     else if (list->SelectedDevice == NULL)
4913         SetLastError(ERROR_NO_DEVICE_SELECTED);
4914     else if (!DeviceInfoData)
4915         SetLastError(ERROR_INVALID_PARAMETER);
4916     else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
4917         SetLastError(ERROR_INVALID_USER_BUFFER);
4918     else
4919     {
4920         memcpy(&DeviceInfoData->ClassGuid,
4921             &list->SelectedDevice->ClassGuid,
4922             sizeof(GUID));
4923         DeviceInfoData->DevInst = list->SelectedDevice->dnDevInst;
4924         DeviceInfoData->Reserved = (ULONG_PTR)list->SelectedDevice;
4925         ret = TRUE;
4926     }
4927 
4928     TRACE("Returning %d\n", ret);
4929     return ret;
4930 }
4931 
4932 
4933 /***********************************************************************
4934  *		SetupDiSetSelectedDevice (SETUPAPI.@)
4935  */
4936 BOOL WINAPI
4937 SetupDiSetSelectedDevice(
4938         IN HDEVINFO DeviceInfoSet,
4939         IN PSP_DEVINFO_DATA DeviceInfoData)
4940 {
4941     struct DeviceInfoSet *list;
4942     BOOL ret = FALSE;
4943 
4944     TRACE("%s(%p %p)\n", __FUNCTION__, DeviceInfoSet, DeviceInfoData);
4945 
4946     if (!DeviceInfoSet)
4947         SetLastError(ERROR_INVALID_HANDLE);
4948     else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
4949         SetLastError(ERROR_INVALID_HANDLE);
4950     else if (!DeviceInfoData)
4951         SetLastError(ERROR_INVALID_PARAMETER);
4952     else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
4953         SetLastError(ERROR_INVALID_USER_BUFFER);
4954     else if (DeviceInfoData->Reserved == 0)
4955         SetLastError(ERROR_INVALID_USER_BUFFER);
4956     else
4957     {
4958         list->SelectedDevice = (struct DeviceInfo *)DeviceInfoData->Reserved;
4959         ret = TRUE;
4960     }
4961 
4962     TRACE("Returning %d\n", ret);
4963     return ret;
4964 }
4965 
4966 
4967 /* Return the current hardware profile id, or -1 if error */
4968 static DWORD
4969 SETUPAPI_GetCurrentHwProfile(
4970         IN HDEVINFO DeviceInfoSet)
4971 {
4972     HKEY hKey = NULL;
4973     DWORD dwRegType, dwLength;
4974     DWORD hwProfile;
4975     LONG rc;
4976     DWORD ret = (DWORD)-1;
4977 
4978     rc = RegOpenKeyExW(((struct DeviceInfoSet *)DeviceInfoSet)->HKLM,
4979                        REGSTR_PATH_IDCONFIGDB,
4980                        0, /* Options */
4981                        KEY_QUERY_VALUE,
4982                        &hKey);
4983     if (rc != ERROR_SUCCESS)
4984     {
4985         SetLastError(rc);
4986         goto cleanup;
4987     }
4988 
4989     dwLength = sizeof(DWORD);
4990     rc = RegQueryValueExW(hKey,
4991                           REGSTR_VAL_CURRENTCONFIG,
4992                           NULL,
4993                           &dwRegType,
4994                           (LPBYTE)&hwProfile, &dwLength);
4995     if (rc != ERROR_SUCCESS)
4996     {
4997         SetLastError(rc);
4998         goto cleanup;
4999     }
5000     else if (dwRegType != REG_DWORD || dwLength != sizeof(DWORD))
5001     {
5002         SetLastError(ERROR_GEN_FAILURE);
5003         goto cleanup;
5004     }
5005 
5006     ret = hwProfile;
5007 
5008 cleanup:
5009     if (hKey != NULL)
5010         RegCloseKey(hKey);
5011 
5012     return ret;
5013 }
5014 
5015 static BOOL
5016 ResetDevice(
5017         IN HDEVINFO DeviceInfoSet,
5018         IN PSP_DEVINFO_DATA DeviceInfoData)
5019 {
5020 #ifndef __WINESRC__
5021     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
5022     struct DeviceInfo *deviceInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
5023     CONFIGRET cr;
5024 
5025     cr = CM_Enable_DevNode_Ex(deviceInfo->dnDevInst, 0, set->hMachine);
5026     if (cr != CR_SUCCESS)
5027     {
5028         SetLastError(GetErrorCodeFromCrCode(cr));
5029         return FALSE;
5030     }
5031 
5032     return TRUE;
5033 #else
5034     FIXME("Stub: ResetDevice(%p %p)\n", DeviceInfoSet, DeviceInfoData);
5035     return TRUE;
5036 #endif
5037 }
5038 
5039 static BOOL
5040 StopDevice(
5041         IN HDEVINFO DeviceInfoSet,
5042         IN PSP_DEVINFO_DATA DeviceInfoData)
5043 {
5044 #ifndef __WINESRC__
5045     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
5046     struct DeviceInfo *deviceInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
5047     CONFIGRET cr;
5048 
5049     cr = CM_Disable_DevNode_Ex(deviceInfo->dnDevInst, 0, set->hMachine);
5050     if (cr != CR_SUCCESS)
5051     {
5052         SetLastError(GetErrorCodeFromCrCode(cr));
5053         return FALSE;
5054     }
5055 
5056     return TRUE;
5057 #else
5058     FIXME("Stub: StopDevice(%p %p)\n", DeviceInfoSet, DeviceInfoData);
5059     return TRUE;
5060 #endif
5061 }
5062 
5063 /***********************************************************************
5064  *		SetupDiChangeState (SETUPAPI.@)
5065  */
5066 BOOL WINAPI
5067 SetupDiChangeState(
5068         IN HDEVINFO DeviceInfoSet,
5069         IN OUT PSP_DEVINFO_DATA DeviceInfoData)
5070 {
5071     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
5072     struct DeviceInfo *deviceInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
5073     PSP_PROPCHANGE_PARAMS PropChange;
5074     HKEY hRootKey = INVALID_HANDLE_VALUE, hKey = INVALID_HANDLE_VALUE;
5075     LPCWSTR RegistryValueName;
5076     DWORD dwConfigFlags, dwLength, dwRegType;
5077     LONG rc;
5078     BOOL ret = FALSE;
5079 
5080     TRACE("%s(%p %p)\n", __FUNCTION__, DeviceInfoSet, DeviceInfoData);
5081 
5082     if (!DeviceInfoData)
5083         PropChange = ((struct DeviceInfoSet *)DeviceInfoSet)->ClassInstallParams.PropChangeParams;
5084     else
5085         PropChange = ((struct DeviceInfo *)DeviceInfoData->Reserved)->ClassInstallParams.PropChangeParams;
5086     if (!PropChange)
5087     {
5088         SetLastError(ERROR_INVALID_PARAMETER);
5089         goto cleanup;
5090     }
5091 
5092     if (PropChange->Scope == DICS_FLAG_GLOBAL)
5093         RegistryValueName = REGSTR_VAL_CONFIGFLAGS;
5094     else
5095         RegistryValueName = REGSTR_VAL_CSCONFIGFLAGS;
5096 
5097     switch (PropChange->StateChange)
5098     {
5099         case DICS_ENABLE:
5100         case DICS_DISABLE:
5101         {
5102             if (PropChange->Scope == DICS_FLAG_GLOBAL)
5103                 hRootKey = set->HKLM;
5104             else /* PropChange->Scope == DICS_FLAG_CONFIGSPECIFIC */
5105             {
5106                 hRootKey = OpenHardwareProfileKey(set->HKLM, PropChange->HwProfile, KEY_CREATE_SUB_KEY);
5107                 if (hRootKey == INVALID_HANDLE_VALUE)
5108                     goto cleanup;
5109             }
5110 
5111             /* Enable/disable device in registry */
5112             hKey = SETUPDI_OpenDrvKey(hRootKey, deviceInfo, KEY_QUERY_VALUE | KEY_SET_VALUE);
5113             if (hKey == INVALID_HANDLE_VALUE && GetLastError() == ERROR_FILE_NOT_FOUND)
5114                 hKey = SETUPDI_CreateDevKey(hRootKey, deviceInfo, KEY_QUERY_VALUE | KEY_SET_VALUE);
5115             if (hKey == INVALID_HANDLE_VALUE)
5116                 break;
5117             dwLength = sizeof(DWORD);
5118             rc = RegQueryValueExW(
5119                 hKey,
5120                 RegistryValueName,
5121                 NULL,
5122                 &dwRegType,
5123                 (LPBYTE)&dwConfigFlags, &dwLength);
5124             if (rc == ERROR_FILE_NOT_FOUND)
5125                 dwConfigFlags = 0;
5126             else if (rc != ERROR_SUCCESS)
5127             {
5128                 SetLastError(rc);
5129                 goto cleanup;
5130             }
5131             else if (dwRegType != REG_DWORD || dwLength != sizeof(DWORD))
5132             {
5133                 SetLastError(ERROR_GEN_FAILURE);
5134                 goto cleanup;
5135             }
5136             if (PropChange->StateChange == DICS_ENABLE)
5137                 dwConfigFlags &= ~(PropChange->Scope == DICS_FLAG_GLOBAL ? CONFIGFLAG_DISABLED : CSCONFIGFLAG_DISABLED);
5138             else
5139                 dwConfigFlags |= (PropChange->Scope == DICS_FLAG_GLOBAL ? CONFIGFLAG_DISABLED : CSCONFIGFLAG_DISABLED);
5140             rc = RegSetValueExW(
5141                 hKey,
5142                 RegistryValueName,
5143                 0,
5144                 REG_DWORD,
5145                 (LPBYTE)&dwConfigFlags, sizeof(DWORD));
5146             if (rc != ERROR_SUCCESS)
5147             {
5148                 SetLastError(rc);
5149                 goto cleanup;
5150             }
5151 
5152             /* Enable/disable device if needed */
5153             if (PropChange->Scope == DICS_FLAG_GLOBAL
5154                 || PropChange->HwProfile == 0
5155                 || PropChange->HwProfile == SETUPAPI_GetCurrentHwProfile(DeviceInfoSet))
5156             {
5157                 if (PropChange->StateChange == DICS_ENABLE)
5158                     ret = ResetDevice(DeviceInfoSet, DeviceInfoData);
5159                 else
5160                     ret = StopDevice(DeviceInfoSet, DeviceInfoData);
5161             }
5162             else
5163                 ret = TRUE;
5164             break;
5165         }
5166         case DICS_PROPCHANGE:
5167         {
5168             ret = ResetDevice(DeviceInfoSet, DeviceInfoData);
5169             break;
5170         }
5171         default:
5172         {
5173             ERR("Unknown StateChange 0x%lx\n", PropChange->StateChange);
5174             SetLastError(ERROR_NOT_SUPPORTED);
5175         }
5176     }
5177 
5178 cleanup:
5179     if (hRootKey != INVALID_HANDLE_VALUE && hRootKey != set->HKLM)
5180         RegCloseKey(hRootKey);
5181 
5182     if (hKey != INVALID_HANDLE_VALUE)
5183         RegCloseKey(hKey);
5184 
5185     TRACE("Returning %d\n", ret);
5186     return ret;
5187 }
5188 
5189 /***********************************************************************
5190  *		SetupDiSelectDevice (SETUPAPI.@)
5191  */
5192 BOOL WINAPI
5193 SetupDiSelectDevice(
5194         IN HDEVINFO DeviceInfoSet,
5195         IN OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
5196 {
5197     FIXME("%p %p\n", DeviceInfoSet, DeviceInfoData);
5198     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5199     return FALSE;
5200 }
5201 
5202 
5203 /***********************************************************************
5204  *		SetupDiRegisterCoDeviceInstallers (SETUPAPI.@)
5205  */
5206 BOOL WINAPI
5207 SetupDiRegisterCoDeviceInstallers(
5208         IN HDEVINFO DeviceInfoSet,
5209         IN PSP_DEVINFO_DATA DeviceInfoData)
5210 {
5211     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
5212     struct DeviceInfo *deviceInfo;
5213     BOOL ret = FALSE; /* Return value */
5214 
5215     TRACE("%s(%p %p)\n", __FUNCTION__, DeviceInfoSet, DeviceInfoData);
5216 
5217     if (!DeviceInfoSet)
5218         SetLastError(ERROR_INVALID_PARAMETER);
5219     else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
5220         SetLastError(ERROR_INVALID_HANDLE);
5221     else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
5222         SetLastError(ERROR_INVALID_HANDLE);
5223     else if (!DeviceInfoData)
5224         SetLastError(ERROR_INVALID_PARAMETER);
5225     else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
5226         SetLastError(ERROR_INVALID_USER_BUFFER);
5227     else
5228     {
5229         SP_DEVINSTALL_PARAMS_W InstallParams;
5230         struct DriverInfoElement *SelectedDriver;
5231         BOOL Result;
5232         DWORD DoAction;
5233         WCHAR SectionName[MAX_PATH];
5234         DWORD SectionNameLength = 0;
5235         HKEY hKey = INVALID_HANDLE_VALUE;
5236         PVOID Context = NULL;
5237 
5238         InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
5239         Result = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
5240         if (!Result)
5241             goto cleanup;
5242 
5243         SelectedDriver = (struct DriverInfoElement *)InstallParams.ClassInstallReserved;
5244         if (SelectedDriver == NULL)
5245         {
5246             SetLastError(ERROR_NO_DRIVER_SELECTED);
5247             goto cleanup;
5248         }
5249 
5250         /* Get .CoInstallers section name */
5251         Result = SetupDiGetActualSectionToInstallW(
5252             SelectedDriver->InfFileDetails->hInf,
5253             SelectedDriver->Details.SectionName,
5254             SectionName, MAX_PATH, &SectionNameLength, NULL);
5255         if (!Result || SectionNameLength > MAX_PATH - strlenW(DotCoInstallers) - 1)
5256             goto cleanup;
5257         lstrcatW(SectionName, DotCoInstallers);
5258 
5259         deviceInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
5260 
5261         /* Open/Create driver key information */
5262 #if _WIN32_WINNT >= 0x502
5263         hKey = SETUPDI_OpenDrvKey(set->HKLM, deviceInfo, KEY_READ | KEY_WRITE);
5264 #else
5265         hKey = SETUPDI_OpenDrvKey(set->HKLM, deviceInfo, KEY_ALL_ACCESS);
5266 #endif
5267         if (hKey == INVALID_HANDLE_VALUE && GetLastError() == ERROR_FILE_NOT_FOUND)
5268 #if _WIN32_WINNT >= 0x502
5269             hKey = SETUPDI_CreateDrvKey(set->HKLM, deviceInfo, (UUID*)&DeviceInfoData->ClassGuid, KEY_READ | KEY_WRITE);
5270 #else
5271             hKey = SETUPDI_CreateDrvKey(set->HKLM, deviceInfo, (UUID*)&DeviceInfoData->ClassGuid, KEY_ALL_ACCESS);
5272 #endif
5273         if (hKey == INVALID_HANDLE_VALUE)
5274             goto cleanup;
5275 
5276         /* Install .CoInstallers section */
5277         DoAction = SPINST_REGISTRY;
5278         if (!(InstallParams.Flags & DI_NOFILECOPY))
5279         {
5280             DoAction |= SPINST_FILES;
5281             Context = SetupInitDefaultQueueCallback(InstallParams.hwndParent);
5282             if (!Context)
5283                 goto cleanup;
5284         }
5285         Result = SetupInstallFromInfSectionW(InstallParams.hwndParent,
5286             SelectedDriver->InfFileDetails->hInf, SectionName,
5287             DoAction, hKey, SelectedDriver->InfFileDetails->DirectoryName, SP_COPY_NEWER,
5288             SetupDefaultQueueCallbackW, Context,
5289             DeviceInfoSet, DeviceInfoData);
5290         if (!Result)
5291             goto cleanup;
5292 
5293         ret = TRUE;
5294 
5295 cleanup:
5296         if (Context)
5297             SetupTermDefaultQueueCallback(Context);
5298         if (hKey != INVALID_HANDLE_VALUE)
5299             RegCloseKey(hKey);
5300     }
5301 
5302     TRACE("Returning %d\n", ret);
5303     return ret;
5304 }
5305 
5306 static BOOL
5307 InfIsFromOEMLocation(
5308         IN PCWSTR FullName,
5309         OUT LPBOOL IsOEMLocation)
5310 {
5311     PWCHAR last;
5312 
5313     last = strrchrW(FullName, '\\');
5314     if (!last)
5315     {
5316         /* No directory specified */
5317         *IsOEMLocation = FALSE;
5318     }
5319     else
5320     {
5321         LPWSTR Windir;
5322         UINT ret;
5323 
5324         Windir = MyMalloc((MAX_PATH + 1 + strlenW(InfDirectory)) * sizeof(WCHAR));
5325         if (!Windir)
5326         {
5327             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
5328             return FALSE;
5329         }
5330 
5331         ret = GetSystemWindowsDirectoryW(Windir, MAX_PATH);
5332         if (ret == 0 || ret > MAX_PATH)
5333         {
5334             MyFree(Windir);
5335             SetLastError(ERROR_GEN_FAILURE);
5336             return FALSE;
5337         }
5338         if (*Windir && Windir[strlenW(Windir) - 1] != '\\')
5339             strcatW(Windir, BackSlash);
5340         strcatW(Windir, InfDirectory);
5341 
5342         if (strncmpiW(FullName, Windir, last - FullName) == 0)
5343         {
5344             /* The path is %SYSTEMROOT%\Inf */
5345             *IsOEMLocation = FALSE;
5346         }
5347         else
5348         {
5349             /* The file is in another place */
5350             *IsOEMLocation = TRUE;
5351         }
5352         MyFree(Windir);
5353     }
5354     return TRUE;
5355 }
5356 
5357 /***********************************************************************
5358  *		SetupDiInstallDevice (SETUPAPI.@)
5359  */
5360 BOOL WINAPI
5361 SetupDiInstallDevice(
5362         IN HDEVINFO DeviceInfoSet,
5363         IN OUT PSP_DEVINFO_DATA DeviceInfoData)
5364 {
5365     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
5366     struct DeviceInfo *deviceInfo;
5367     SP_DEVINSTALL_PARAMS_W InstallParams;
5368     struct DriverInfoElement *SelectedDriver;
5369     SYSTEMTIME DriverDate;
5370     WCHAR SectionName[MAX_PATH];
5371     WCHAR Buffer[32];
5372     DWORD SectionNameLength = 0;
5373     BOOL Result = FALSE;
5374     ULONG DoAction;
5375     DWORD RequiredSize;
5376     LPWSTR pSectionName = NULL;
5377     WCHAR ClassName[MAX_CLASS_NAME_LEN];
5378     GUID ClassGuid;
5379     LPWSTR lpGuidString = NULL, lpFullGuidString = NULL;
5380     BOOL RebootRequired = FALSE;
5381     HKEY hKey = INVALID_HANDLE_VALUE;
5382     BOOL NeedtoCopyFile;
5383     LARGE_INTEGER fullVersion;
5384     LONG rc;
5385     PVOID Context = NULL;
5386     BOOL ret = FALSE; /* Return value */
5387 
5388     TRACE("%s(%p %p)\n", __FUNCTION__, DeviceInfoSet, DeviceInfoData);
5389 
5390     if (!DeviceInfoSet)
5391         SetLastError(ERROR_INVALID_PARAMETER);
5392     else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
5393         SetLastError(ERROR_INVALID_HANDLE);
5394     else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
5395         SetLastError(ERROR_INVALID_HANDLE);
5396     else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
5397         SetLastError(ERROR_INVALID_USER_BUFFER);
5398     else
5399         Result = TRUE;
5400 
5401     if (!Result)
5402     {
5403         /* One parameter is bad */
5404         goto cleanup;
5405     }
5406 
5407     InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
5408     Result = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
5409     if (!Result)
5410         goto cleanup;
5411 
5412     if (InstallParams.FlagsEx & DI_FLAGSEX_SETFAILEDINSTALL)
5413     {
5414         /* Set FAILEDINSTALL in ConfigFlags registry value */
5415         DWORD ConfigFlags, regType;
5416         Result = SetupDiGetDeviceRegistryPropertyW(
5417             DeviceInfoSet,
5418             DeviceInfoData,
5419             SPDRP_CONFIGFLAGS,
5420             &regType,
5421             (PBYTE)&ConfigFlags,
5422             sizeof(ConfigFlags),
5423             NULL);
5424         if (!Result || regType != REG_DWORD)
5425         {
5426             SetLastError(ERROR_GEN_FAILURE);
5427             goto cleanup;
5428         }
5429         ConfigFlags |= CONFIGFLAG_FAILEDINSTALL;
5430         Result = SetupDiSetDeviceRegistryPropertyW(
5431             DeviceInfoSet,
5432             DeviceInfoData,
5433             SPDRP_CONFIGFLAGS,
5434             (PBYTE)&ConfigFlags,
5435             sizeof(ConfigFlags));
5436         if (!Result)
5437         {
5438             SetLastError(ERROR_GEN_FAILURE);
5439             goto cleanup;
5440         }
5441 
5442         ret = TRUE;
5443         goto cleanup;
5444     }
5445 
5446     SelectedDriver = (struct DriverInfoElement *)InstallParams.ClassInstallReserved;
5447     if (SelectedDriver == NULL)
5448     {
5449         SetLastError(ERROR_NO_DRIVER_SELECTED);
5450         goto cleanup;
5451     }
5452 
5453     FileTimeToSystemTime(&SelectedDriver->Info.DriverDate, &DriverDate);
5454 
5455     Result = SetupDiGetActualSectionToInstallW(
5456         SelectedDriver->InfFileDetails->hInf,
5457         SelectedDriver->Details.SectionName,
5458         SectionName, MAX_PATH, &SectionNameLength, NULL);
5459     if (!Result || SectionNameLength > MAX_PATH - strlenW(DotServices))
5460         goto cleanup;
5461     pSectionName = &SectionName[strlenW(SectionName)];
5462 
5463     /* Get information from [Version] section */
5464     if (!SetupDiGetINFClassW(SelectedDriver->Details.InfFileName, &ClassGuid, ClassName, MAX_CLASS_NAME_LEN, &RequiredSize))
5465         goto cleanup;
5466     /* Format ClassGuid to a string */
5467     if (UuidToStringW((UUID*)&ClassGuid, &lpGuidString) != RPC_S_OK)
5468         goto cleanup;
5469     RequiredSize = lstrlenW(lpGuidString);
5470     lpFullGuidString = HeapAlloc(GetProcessHeap(), 0, (RequiredSize + 3) * sizeof(WCHAR));
5471     if (!lpFullGuidString)
5472     {
5473         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
5474         goto cleanup;
5475     }
5476     lpFullGuidString[0] = '{';
5477     memcpy(&lpFullGuidString[1], lpGuidString, RequiredSize * sizeof(WCHAR));
5478     lpFullGuidString[RequiredSize + 1] = '}';
5479     lpFullGuidString[RequiredSize + 2] = '\0';
5480 
5481     /* Copy .inf file to Inf\ directory (if needed) */
5482     Result = InfIsFromOEMLocation(SelectedDriver->Details.InfFileName, &NeedtoCopyFile);
5483     if (!Result)
5484         goto cleanup;
5485     if (NeedtoCopyFile)
5486     {
5487         WCHAR NewFileName[MAX_PATH];
5488         struct InfFileDetails *newInfFileDetails;
5489         Result = SetupCopyOEMInfW(
5490             SelectedDriver->Details.InfFileName,
5491             NULL,
5492             SPOST_NONE,
5493             SP_COPY_NOOVERWRITE,
5494             NewFileName, MAX_PATH,
5495             NULL,
5496             NULL);
5497         if (!Result && GetLastError() != ERROR_FILE_EXISTS)
5498             goto cleanup;
5499         /* Create a new struct InfFileDetails, and set it to
5500          * SelectedDriver->InfFileDetails, to release use of
5501          * current InfFile */
5502         newInfFileDetails = CreateInfFileDetails(NewFileName);
5503         if (!newInfFileDetails)
5504             goto cleanup;
5505         DereferenceInfFile(SelectedDriver->InfFileDetails);
5506         SelectedDriver->InfFileDetails = newInfFileDetails;
5507         strcpyW(SelectedDriver->Details.InfFileName, NewFileName);
5508     }
5509 
5510     deviceInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
5511 
5512     /* Open/Create driver key information */
5513 #if _WIN32_WINNT >= 0x502
5514     hKey = SETUPDI_OpenDrvKey(set->HKLM, deviceInfo, KEY_READ | KEY_WRITE);
5515 #else
5516     hKey = SETUPDI_OpenDrvKey(set->HKLM, deviceInfo, KEY_ALL_ACCESS);
5517 #endif
5518     if (hKey == INVALID_HANDLE_VALUE && GetLastError() == ERROR_FILE_NOT_FOUND)
5519 #if _WIN32_WINNT >= 0x502
5520         hKey = SETUPDI_CreateDrvKey(set->HKLM, deviceInfo, (UUID*)&DeviceInfoData->ClassGuid, KEY_READ | KEY_WRITE);
5521 #else
5522         hKey = SETUPDI_CreateDrvKey(set->HKLM, deviceInfo, (UUID*)&DeviceInfoData->ClassGuid, KEY_ALL_ACCESS);
5523 #endif
5524     if (hKey == INVALID_HANDLE_VALUE)
5525         goto cleanup;
5526 
5527     /* Install main section */
5528     DoAction = 0;
5529     if (!(InstallParams.FlagsEx & DI_FLAGSEX_NO_DRVREG_MODIFY))
5530         DoAction |= SPINST_REGISTRY;
5531     if (!(InstallParams.Flags & DI_NOFILECOPY))
5532     {
5533         DoAction |= SPINST_FILES;
5534         Context = SetupInitDefaultQueueCallback(InstallParams.hwndParent);
5535         if (!Context)
5536             goto cleanup;
5537     }
5538     *pSectionName = '\0';
5539     Result = SetupInstallFromInfSectionW(InstallParams.hwndParent,
5540         SelectedDriver->InfFileDetails->hInf, SectionName,
5541         DoAction, hKey, SelectedDriver->InfFileDetails->DirectoryName, SP_COPY_NEWER,
5542         SetupDefaultQueueCallbackW, Context,
5543         DeviceInfoSet, DeviceInfoData);
5544     if (!Result)
5545         goto cleanup;
5546     InstallParams.Flags |= DI_NOFILECOPY;
5547     SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
5548 
5549     /* Write information to driver key */
5550     *pSectionName = UNICODE_NULL;
5551     memcpy(&fullVersion, &SelectedDriver->Info.DriverVersion, sizeof(LARGE_INTEGER));
5552     TRACE("Write information to driver key\n");
5553     TRACE("DriverDate      : '%u-%u-%u'\n", DriverDate.wMonth, DriverDate.wDay, DriverDate.wYear);
5554     TRACE("DriverDesc      : '%s'\n", debugstr_w(SelectedDriver->Info.Description));
5555     TRACE("DriverVersion   : '%ld.%ld.%lu.%ld'\n", fullVersion.HighPart >> 16, fullVersion.HighPart & 0xffff, fullVersion.LowPart >> 16, fullVersion.LowPart & 0xffff);
5556     TRACE("InfPath         : '%s'\n", debugstr_w(SelectedDriver->InfFileDetails->FileName));
5557     TRACE("InfSection      : '%s'\n", debugstr_w(SelectedDriver->Details.SectionName));
5558     TRACE("InfSectionExt   : '%s'\n", debugstr_w(&SectionName[strlenW(SelectedDriver->Details.SectionName)]));
5559     TRACE("MatchingDeviceId: '%s'\n", debugstr_w(SelectedDriver->MatchingId));
5560     TRACE("ProviderName    : '%s'\n", debugstr_w(SelectedDriver->Info.ProviderName));
5561     sprintfW(Buffer, DateFormat, DriverDate.wMonth, DriverDate.wDay, DriverDate.wYear);
5562     rc = RegSetValueExW(hKey, REGSTR_DRIVER_DATE, 0, REG_SZ, (const BYTE *)Buffer, (strlenW(Buffer) + 1) * sizeof(WCHAR));
5563     if (rc == ERROR_SUCCESS)
5564         rc = RegSetValueExW(hKey, REGSTR_DRIVER_DATE_DATA, 0, REG_BINARY, (const BYTE *)&SelectedDriver->Info.DriverDate, sizeof(FILETIME));
5565     if (rc == ERROR_SUCCESS)
5566         rc = RegSetValueExW(hKey, REGSTR_VAL_DRVDESC, 0, REG_SZ, (const BYTE *)SelectedDriver->Info.Description, (strlenW(SelectedDriver->Info.Description) + 1) * sizeof(WCHAR));
5567     if (rc == ERROR_SUCCESS)
5568     {
5569         sprintfW(Buffer, VersionFormat, fullVersion.HighPart >> 16, fullVersion.HighPart & 0xffff, fullVersion.LowPart >> 16, fullVersion.LowPart & 0xffff);
5570         rc = RegSetValueExW(hKey, REGSTR_DRIVER_VERSION, 0, REG_SZ, (const BYTE *)Buffer, (strlenW(Buffer) + 1) * sizeof(WCHAR));
5571     }
5572     if (rc == ERROR_SUCCESS)
5573         rc = RegSetValueExW(hKey, REGSTR_VAL_INFPATH, 0, REG_SZ, (const BYTE *)SelectedDriver->InfFileDetails->FileName, (strlenW(SelectedDriver->InfFileDetails->FileName) + 1) * sizeof(WCHAR));
5574     if (rc == ERROR_SUCCESS)
5575         rc = RegSetValueExW(hKey, REGSTR_VAL_INFSECTION, 0, REG_SZ, (const BYTE *)SelectedDriver->Details.SectionName, (strlenW(SelectedDriver->Details.SectionName) + 1) * sizeof(WCHAR));
5576     if (rc == ERROR_SUCCESS)
5577         rc = RegSetValueExW(hKey, REGSTR_VAL_INFSECTIONEXT, 0, REG_SZ, (const BYTE *)&SectionName[strlenW(SelectedDriver->Details.SectionName)], (strlenW(SectionName) - strlenW(SelectedDriver->Details.SectionName) + 1) * sizeof(WCHAR));
5578     if (rc == ERROR_SUCCESS)
5579         rc = RegSetValueExW(hKey, REGSTR_VAL_MATCHINGDEVID, 0, REG_SZ, (const BYTE *)SelectedDriver->MatchingId, (strlenW(SelectedDriver->MatchingId) + 1) * sizeof(WCHAR));
5580     if (rc == ERROR_SUCCESS)
5581         rc = RegSetValueExW(hKey, REGSTR_VAL_PROVIDER_NAME, 0, REG_SZ, (const BYTE *)SelectedDriver->Info.ProviderName, (strlenW(SelectedDriver->Info.ProviderName) + 1) * sizeof(WCHAR));
5582     if (rc != ERROR_SUCCESS)
5583     {
5584        SetLastError(rc);
5585        goto cleanup;
5586     }
5587     RegCloseKey(hKey);
5588     hKey = INVALID_HANDLE_VALUE;
5589 
5590     /* FIXME: Process .LogConfigOverride section */
5591 
5592     /* Install .Services section */
5593     strcpyW(pSectionName, DotServices);
5594     Result = SetupInstallServicesFromInfSectionExW(
5595         SelectedDriver->InfFileDetails->hInf,
5596         SectionName,
5597         0,
5598         DeviceInfoSet,
5599         DeviceInfoData,
5600         NULL,
5601         NULL);
5602     if (!Result)
5603     {
5604         if (GetLastError() != ERROR_SECTION_NOT_FOUND)
5605             goto cleanup;
5606         SetLastError(ERROR_SUCCESS);
5607     }
5608     if (GetLastError() == ERROR_SUCCESS_REBOOT_REQUIRED)
5609         RebootRequired = TRUE;
5610 
5611     /* Open device registry key */
5612     hKey = SETUPDI_OpenDevKey(((struct DeviceInfoSet *)DeviceInfoSet)->HKLM, (struct DeviceInfo *)DeviceInfoData->Reserved, KEY_SET_VALUE);
5613     if (hKey == INVALID_HANDLE_VALUE)
5614         goto cleanup;
5615 
5616     /* Install .HW section */
5617     DoAction = 0;
5618     if (!(InstallParams.FlagsEx & DI_FLAGSEX_NO_DRVREG_MODIFY))
5619         DoAction |= SPINST_REGISTRY;
5620     strcpyW(pSectionName, DotHW);
5621     Result = SetupInstallFromInfSectionW(InstallParams.hwndParent,
5622         SelectedDriver->InfFileDetails->hInf, SectionName,
5623         DoAction, hKey, NULL, 0,
5624         NULL, NULL,
5625         DeviceInfoSet, DeviceInfoData);
5626     if (!Result)
5627         goto cleanup;
5628 
5629     /* Write information to enum key */
5630     TRACE("Write information to enum key\n");
5631     TRACE("Class           : '%s'\n", debugstr_w(ClassName));
5632     TRACE("ClassGUID       : '%s'\n", debugstr_w(lpFullGuidString));
5633     TRACE("DeviceDesc      : '%s'\n", debugstr_w(SelectedDriver->Info.Description));
5634     TRACE("Mfg             : '%s'\n", debugstr_w(SelectedDriver->Info.MfgName));
5635     rc = RegSetValueExW(hKey, REGSTR_VAL_CLASS, 0, REG_SZ, (const BYTE *)ClassName, (strlenW(ClassName) + 1) * sizeof(WCHAR));
5636     if (rc == ERROR_SUCCESS)
5637         rc = RegSetValueExW(hKey, REGSTR_VAL_CLASSGUID, 0, REG_SZ, (const BYTE *)lpFullGuidString, (strlenW(lpFullGuidString) + 1) * sizeof(WCHAR));
5638     if (rc == ERROR_SUCCESS)
5639         rc = RegSetValueExW(hKey, REGSTR_VAL_DEVDESC, 0, REG_SZ, (const BYTE *)SelectedDriver->Info.Description, (strlenW(SelectedDriver->Info.Description) + 1) * sizeof(WCHAR));
5640     if (rc == ERROR_SUCCESS)
5641         rc = RegSetValueExW(hKey, REGSTR_VAL_MFG, 0, REG_SZ, (const BYTE *)SelectedDriver->Info.MfgName, (strlenW(SelectedDriver->Info.MfgName) + 1) * sizeof(WCHAR));
5642     if (rc != ERROR_SUCCESS)
5643     {
5644        SetLastError(rc);
5645        goto cleanup;
5646     }
5647 
5648     /* Start the device */
5649     if (!RebootRequired && !(InstallParams.Flags & (DI_NEEDRESTART | DI_NEEDREBOOT | DI_DONOTCALLCONFIGMG)))
5650         ret = ResetDevice(DeviceInfoSet, DeviceInfoData);
5651     else
5652         ret = TRUE;
5653 
5654 cleanup:
5655     /* End of installation */
5656     if (hKey != INVALID_HANDLE_VALUE)
5657         RegCloseKey(hKey);
5658     if (lpGuidString)
5659         RpcStringFreeW(&lpGuidString);
5660     HeapFree(GetProcessHeap(), 0, lpFullGuidString);
5661     if (Context)
5662         SetupTermDefaultQueueCallback(Context);
5663     TRACE("Returning %d\n", ret);
5664     return ret;
5665 }
5666 
5667 HKEY SETUPDI_CreateDevKey(HKEY RootKey, struct DeviceInfo *devInfo, REGSAM samDesired)
5668 {
5669     HKEY enumKey, key = INVALID_HANDLE_VALUE;
5670     LONG l;
5671 
5672     l = RegCreateKeyExW(RootKey, REGSTR_PATH_SYSTEMENUM, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_CREATE_SUB_KEY, NULL, &enumKey, NULL);
5673     if (!l)
5674     {
5675         l = RegCreateKeyExW(enumKey, devInfo->instanceId, 0, NULL, REG_OPTION_NON_VOLATILE, samDesired, NULL, &key, NULL);
5676         RegCloseKey(enumKey);
5677     }
5678     if (l)
5679         SetLastError(l);
5680     return key;
5681 }
5682 
5683 HKEY SETUPDI_CreateDrvKey(HKEY RootKey, struct DeviceInfo *devInfo, UUID *ClassGuid, REGSAM samDesired)
5684 {
5685     HKEY key = INVALID_HANDLE_VALUE;
5686     LPWSTR lpGuidString = NULL;
5687     LPWSTR DriverKey = NULL; /* {GUID}\Index */
5688     LPWSTR pDeviceInstance; /* Points into DriverKey, on the Index field */
5689     DWORD Index; /* Index used in the DriverKey name */
5690     DWORD dwSize;
5691     DWORD Disposition;
5692     DWORD rc;
5693     HKEY hHWProfileKey = INVALID_HANDLE_VALUE;
5694     HKEY hEnumKey = NULL;
5695     HKEY hClassKey = NULL;
5696     HKEY hDeviceKey = INVALID_HANDLE_VALUE;
5697     HKEY hKey = NULL;
5698 
5699     /* Open device key, to read Driver value */
5700     hDeviceKey = SETUPDI_OpenDevKey(RootKey, devInfo, KEY_QUERY_VALUE | KEY_SET_VALUE);
5701     if (hDeviceKey == INVALID_HANDLE_VALUE)
5702         goto cleanup;
5703 
5704     rc = RegOpenKeyExW(RootKey, REGSTR_PATH_CLASS_NT, 0, KEY_CREATE_SUB_KEY, &hClassKey);
5705     if (rc != ERROR_SUCCESS)
5706     {
5707         SetLastError(rc);
5708         goto cleanup;
5709     }
5710 
5711     rc = RegQueryValueExW(hDeviceKey, REGSTR_VAL_DRIVER, NULL, NULL, NULL, &dwSize);
5712     if (rc != ERROR_SUCCESS)
5713     {
5714         /* Create a new driver key */
5715 
5716         if (UuidToStringW(ClassGuid, &lpGuidString) != RPC_S_OK)
5717             goto cleanup;
5718 
5719         /* The driver key is in \System\CurrentControlSet\Control\Class\{GUID}\Index */
5720         DriverKey = HeapAlloc(GetProcessHeap(), 0, (strlenW(lpGuidString) + 7) * sizeof(WCHAR) + sizeof(UNICODE_NULL));
5721         if (!DriverKey)
5722         {
5723             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
5724             goto cleanup;
5725         }
5726 
5727         DriverKey[0] = '{';
5728         strcpyW(&DriverKey[1], lpGuidString);
5729         pDeviceInstance = &DriverKey[strlenW(DriverKey)];
5730         *pDeviceInstance++ = '}';
5731         *pDeviceInstance++ = '\\';
5732 
5733         /* Try all values for Index between 0 and 9999 */
5734         Index = 0;
5735         while (Index <= 9999)
5736         {
5737             sprintfW(pDeviceInstance, InstanceKeyFormat, Index);
5738             rc = RegCreateKeyExW(hClassKey,
5739                 DriverKey,
5740                 0,
5741                 NULL,
5742                 REG_OPTION_NON_VOLATILE,
5743 #if _WIN32_WINNT >= 0x502
5744                 KEY_READ | KEY_WRITE,
5745 #else
5746                 KEY_ALL_ACCESS,
5747 #endif
5748                 NULL,
5749                 &hKey,
5750                 &Disposition);
5751             if (rc != ERROR_SUCCESS)
5752             {
5753                 SetLastError(rc);
5754                 goto cleanup;
5755             }
5756             if (Disposition == REG_CREATED_NEW_KEY)
5757                 break;
5758             RegCloseKey(hKey);
5759             hKey = NULL;
5760             Index++;
5761         }
5762 
5763         if (Index > 9999)
5764         {
5765             /* Unable to create more than 9999 devices within the same class */
5766             SetLastError(ERROR_GEN_FAILURE);
5767             goto cleanup;
5768         }
5769 
5770         /* Write the new Driver value */
5771         rc = RegSetValueExW(hDeviceKey, REGSTR_VAL_DRIVER, 0, REG_SZ, (const BYTE *)DriverKey, (strlenW(DriverKey) + 1) * sizeof(WCHAR));
5772         if (rc != ERROR_SUCCESS)
5773         {
5774             SetLastError(rc);
5775             goto cleanup;
5776         }
5777     }
5778     else
5779     {
5780         /* Open the existing driver key */
5781 
5782         DriverKey = HeapAlloc(GetProcessHeap(), 0, dwSize);
5783         if (!DriverKey)
5784         {
5785             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
5786             goto cleanup;
5787         }
5788 
5789         rc = RegQueryValueExW(hDeviceKey, REGSTR_VAL_DRIVER, NULL, NULL, (LPBYTE)DriverKey, &dwSize);
5790         if (rc != ERROR_SUCCESS)
5791         {
5792             SetLastError(rc);
5793             goto cleanup;
5794         }
5795 
5796         rc = RegCreateKeyExW(hClassKey,
5797             DriverKey,
5798             0,
5799             NULL,
5800             REG_OPTION_NON_VOLATILE,
5801 #if _WIN32_WINNT >= 0x502
5802             KEY_READ | KEY_WRITE,
5803 #else
5804             KEY_ALL_ACCESS,
5805 #endif
5806             NULL,
5807             &hKey,
5808             &Disposition);
5809         if (rc != ERROR_SUCCESS)
5810         {
5811             SetLastError(rc);
5812             goto cleanup;
5813         }
5814     }
5815 
5816     key = hKey;
5817 
5818 cleanup:
5819         if (lpGuidString)
5820             RpcStringFreeW(&lpGuidString);
5821         HeapFree(GetProcessHeap(), 0, DriverKey);
5822         if (hHWProfileKey != INVALID_HANDLE_VALUE)
5823             RegCloseKey(hHWProfileKey);
5824         if (hEnumKey != NULL)
5825             RegCloseKey(hEnumKey);
5826         if (hClassKey != NULL)
5827             RegCloseKey(hClassKey);
5828         if (hDeviceKey != INVALID_HANDLE_VALUE)
5829             RegCloseKey(hDeviceKey);
5830         if (hKey != NULL && hKey != key)
5831             RegCloseKey(hKey);
5832 
5833     TRACE("Returning 0x%p\n", hKey);
5834     return hKey;
5835 }
5836 
5837 HKEY SETUPDI_OpenDevKey(HKEY RootKey, struct DeviceInfo *devInfo, REGSAM samDesired)
5838 {
5839     HKEY enumKey, key = INVALID_HANDLE_VALUE;
5840     LONG l;
5841 
5842     l = RegOpenKeyExW(RootKey, REGSTR_PATH_SYSTEMENUM, 0, READ_CONTROL, &enumKey);
5843     if (!l)
5844     {
5845         l = RegOpenKeyExW(enumKey, devInfo->instanceId, 0, samDesired, &key);
5846         RegCloseKey(enumKey);
5847     }
5848     if (l)
5849         SetLastError(l);
5850     return key;
5851 }
5852 
5853 HKEY SETUPDI_OpenDrvKey(HKEY RootKey, struct DeviceInfo *devInfo, REGSAM samDesired)
5854 {
5855     LPWSTR DriverKey = NULL;
5856     DWORD dwLength = 0;
5857     DWORD dwRegType;
5858     DWORD rc;
5859     HKEY hEnumKey = NULL;
5860     HKEY hKey = NULL;
5861     HKEY key = INVALID_HANDLE_VALUE;
5862 
5863     hKey = SETUPDI_OpenDevKey(RootKey, devInfo, KEY_QUERY_VALUE);
5864     if (hKey == INVALID_HANDLE_VALUE)
5865         goto cleanup;
5866     /* Read the 'Driver' key */
5867     rc = RegQueryValueExW(hKey, REGSTR_VAL_DRIVER, NULL, &dwRegType, NULL, &dwLength);
5868     if (rc != ERROR_SUCCESS)
5869     {
5870         SetLastError(rc);
5871         goto cleanup;
5872     }
5873     else if (dwRegType != REG_SZ)
5874     {
5875         SetLastError(ERROR_GEN_FAILURE);
5876         goto cleanup;
5877     }
5878     DriverKey = HeapAlloc(GetProcessHeap(), 0, dwLength);
5879     if (!DriverKey)
5880     {
5881         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
5882         goto cleanup;
5883     }
5884     rc = RegQueryValueExW(hKey, REGSTR_VAL_DRIVER, NULL, &dwRegType, (LPBYTE)DriverKey, &dwLength);
5885     if (rc != ERROR_SUCCESS)
5886     {
5887         SetLastError(rc);
5888         goto cleanup;
5889     }
5890     RegCloseKey(hKey);
5891     hKey = NULL;
5892     /* Need to open the driver key */
5893     rc = RegOpenKeyExW(
5894         RootKey,
5895         REGSTR_PATH_CLASS_NT,
5896         0, /* Options */
5897         READ_CONTROL,
5898         &hEnumKey);
5899     if (rc != ERROR_SUCCESS)
5900     {
5901         SetLastError(rc);
5902         goto cleanup;
5903     }
5904     rc = RegOpenKeyExW(
5905         hEnumKey,
5906         DriverKey,
5907         0, /* Options */
5908         samDesired,
5909         &hKey);
5910     if (rc != ERROR_SUCCESS)
5911     {
5912         SetLastError(rc);
5913         goto cleanup;
5914     }
5915     key = hKey;
5916 
5917 cleanup:
5918     if (hEnumKey != NULL)
5919         RegCloseKey(hEnumKey);
5920     if (hKey != NULL && hKey != key)
5921         RegCloseKey(hKey);
5922     if (DriverKey)
5923         HeapFree(GetProcessHeap(), 0, DriverKey);
5924     return key;
5925 }
5926 
5927 /***********************************************************************
5928  *		SetupDiOpenDevRegKey (SETUPAPI.@)
5929  */
5930 HKEY WINAPI SetupDiOpenDevRegKey(
5931         HDEVINFO DeviceInfoSet,
5932         PSP_DEVINFO_DATA DeviceInfoData,
5933         DWORD Scope,
5934         DWORD HwProfile,
5935         DWORD KeyType,
5936         REGSAM samDesired)
5937 {
5938     struct DeviceInfoSet *set = DeviceInfoSet;
5939     struct DeviceInfo *devInfo;
5940     HKEY key = INVALID_HANDLE_VALUE;
5941     HKEY RootKey;
5942 
5943     TRACE("%s(%p %p %d %d %d %x)\n", __FUNCTION__, DeviceInfoSet, DeviceInfoData,
5944           Scope, HwProfile, KeyType, samDesired);
5945 
5946     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
5947     {
5948         SetLastError(ERROR_INVALID_HANDLE);
5949         return INVALID_HANDLE_VALUE;
5950     }
5951     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
5952     {
5953         SetLastError(ERROR_INVALID_HANDLE);
5954         return INVALID_HANDLE_VALUE;
5955     }
5956     if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
5957             || !DeviceInfoData->Reserved)
5958     {
5959         SetLastError(ERROR_INVALID_PARAMETER);
5960         return INVALID_HANDLE_VALUE;
5961     }
5962     if (Scope != DICS_FLAG_GLOBAL && Scope != DICS_FLAG_CONFIGSPECIFIC)
5963     {
5964         SetLastError(ERROR_INVALID_FLAGS);
5965         return INVALID_HANDLE_VALUE;
5966     }
5967     if (KeyType != DIREG_DEV && KeyType != DIREG_DRV)
5968     {
5969         SetLastError(ERROR_INVALID_FLAGS);
5970         return INVALID_HANDLE_VALUE;
5971     }
5972     devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
5973     if (devInfo->set != set)
5974     {
5975         SetLastError(ERROR_INVALID_PARAMETER);
5976         return INVALID_HANDLE_VALUE;
5977     }
5978     if (Scope != DICS_FLAG_GLOBAL)
5979     {
5980         RootKey = OpenHardwareProfileKey(set->HKLM, HwProfile, 0);
5981         if (RootKey == INVALID_HANDLE_VALUE)
5982             return INVALID_HANDLE_VALUE;
5983     }
5984     else
5985         RootKey = set->HKLM;
5986     switch (KeyType)
5987     {
5988         case DIREG_DEV:
5989             key = SETUPDI_OpenDevKey(RootKey, devInfo, samDesired);
5990             if (Scope == DICS_FLAG_GLOBAL)
5991             {
5992                 LONG rc;
5993                 HKEY hTempKey = key;
5994                 rc = RegOpenKeyExW(hTempKey,
5995                                    L"Device Parameters",
5996                                    0,
5997                                    samDesired,
5998                                    &key);
5999                 if (rc == ERROR_SUCCESS)
6000                     RegCloseKey(hTempKey);
6001             }
6002             break;
6003         case DIREG_DRV:
6004             key = SETUPDI_OpenDrvKey(RootKey, devInfo, samDesired);
6005             break;
6006         default:
6007             WARN("unknown KeyType %d\n", KeyType);
6008     }
6009     if (RootKey != set->HKLM)
6010         RegCloseKey(RootKey);
6011     return key;
6012 }
6013 
6014 static BOOL SETUPDI_DeleteDevKey(HKEY RootKey, struct DeviceInfo *devInfo)
6015 {
6016     FIXME("\n");
6017     return FALSE;
6018 }
6019 
6020 static BOOL SETUPDI_DeleteDrvKey(HKEY RootKey, struct DeviceInfo *devInfo)
6021 {
6022     FIXME("\n");
6023     return FALSE;
6024 }
6025 
6026 /***********************************************************************
6027  *		SetupDiDeleteDevRegKey (SETUPAPI.@)
6028  */
6029 BOOL WINAPI SetupDiDeleteDevRegKey(
6030         HDEVINFO DeviceInfoSet,
6031         PSP_DEVINFO_DATA DeviceInfoData,
6032         DWORD Scope,
6033         DWORD HwProfile,
6034         DWORD KeyType)
6035 {
6036     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
6037     struct DeviceInfo *devInfo;
6038     BOOL ret = FALSE;
6039     HKEY RootKey;
6040 
6041     TRACE("%s(%p %p %d %d %d)\n", __FUNCTION__, DeviceInfoSet, DeviceInfoData, Scope, HwProfile,
6042             KeyType);
6043 
6044     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
6045     {
6046         SetLastError(ERROR_INVALID_HANDLE);
6047         return FALSE;
6048     }
6049     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
6050     {
6051         SetLastError(ERROR_INVALID_HANDLE);
6052         return FALSE;
6053     }
6054     if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
6055             || !DeviceInfoData->Reserved)
6056     {
6057         SetLastError(ERROR_INVALID_PARAMETER);
6058         return FALSE;
6059     }
6060     if (Scope != DICS_FLAG_GLOBAL && Scope != DICS_FLAG_CONFIGSPECIFIC)
6061     {
6062         SetLastError(ERROR_INVALID_FLAGS);
6063         return FALSE;
6064     }
6065     if (KeyType != DIREG_DEV && KeyType != DIREG_DRV && KeyType != DIREG_BOTH)
6066     {
6067         SetLastError(ERROR_INVALID_FLAGS);
6068         return FALSE;
6069     }
6070     devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
6071     if (devInfo->set != set)
6072     {
6073         SetLastError(ERROR_INVALID_PARAMETER);
6074         return FALSE;
6075     }
6076     if (Scope != DICS_FLAG_GLOBAL)
6077     {
6078         RootKey = OpenHardwareProfileKey(set->HKLM, HwProfile, 0);
6079         if (RootKey == INVALID_HANDLE_VALUE)
6080             return FALSE;
6081     }
6082     else
6083         RootKey = set->HKLM;
6084     switch (KeyType)
6085     {
6086         case DIREG_DEV:
6087             ret = SETUPDI_DeleteDevKey(RootKey, devInfo);
6088             break;
6089         case DIREG_DRV:
6090             ret = SETUPDI_DeleteDrvKey(RootKey, devInfo);
6091             break;
6092         case DIREG_BOTH:
6093             ret = SETUPDI_DeleteDevKey(RootKey, devInfo);
6094             if (ret)
6095                 ret = SETUPDI_DeleteDrvKey(RootKey, devInfo);
6096             break;
6097         default:
6098             WARN("unknown KeyType %d\n", KeyType);
6099     }
6100     if (RootKey != set->HKLM)
6101         RegCloseKey(RootKey);
6102     return ret;
6103 }
6104 
6105 /***********************************************************************
6106  *		SetupDiRestartDevices (SETUPAPI.@)
6107  */
6108 BOOL
6109 WINAPI
6110 SetupDiRestartDevices(
6111     HDEVINFO DeviceInfoSet,
6112     PSP_DEVINFO_DATA DeviceInfoData)
6113 {
6114     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
6115     struct DeviceInfo *devInfo;
6116     CONFIGRET cr;
6117 
6118     TRACE("%s(%p %p)\n", __FUNCTION__, DeviceInfoSet, DeviceInfoData);
6119 
6120     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
6121     {
6122         SetLastError(ERROR_INVALID_HANDLE);
6123         return FALSE;
6124     }
6125     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
6126     {
6127         SetLastError(ERROR_INVALID_HANDLE);
6128         return FALSE;
6129     }
6130 
6131     if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
6132             || !DeviceInfoData->Reserved)
6133     {
6134         SetLastError(ERROR_INVALID_PARAMETER);
6135         return FALSE;
6136     }
6137 
6138     devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
6139 
6140     cr = CM_Enable_DevNode_Ex(devInfo->dnDevInst, 0, set->hMachine);
6141     if (cr != CR_SUCCESS)
6142     {
6143         SetLastError(GetErrorCodeFromCrCode(cr));
6144         return FALSE;
6145     }
6146 
6147     return TRUE;
6148 }
6149