xref: /reactos/dll/win32/setupapi/devinst.c (revision 1734f297)
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     DWORD dwFlags;
1587 
1588     TRACE("%s(%p %s %s %s %p %x %p)\n", __FUNCTION__, DeviceInfoSet, debugstr_w(DeviceName),
1589         debugstr_guid(ClassGuid), debugstr_w(DeviceDescription),
1590         hwndParent, CreationFlags, DeviceInfoData);
1591 
1592     if (!DeviceName)
1593     {
1594         SetLastError(ERROR_INVALID_DEVINST_NAME);
1595         return FALSE;
1596     }
1597     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
1598     {
1599         SetLastError(ERROR_INVALID_HANDLE);
1600         return FALSE;
1601     }
1602     if (!ClassGuid)
1603     {
1604         SetLastError(ERROR_INVALID_PARAMETER);
1605         return FALSE;
1606     }
1607     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
1608     {
1609         SetLastError(ERROR_INVALID_HANDLE);
1610         return FALSE;
1611     }
1612     if (!IsEqualGUID(&set->ClassGuid, &GUID_NULL) &&
1613         !IsEqualGUID(ClassGuid, &set->ClassGuid))
1614     {
1615         SetLastError(ERROR_CLASS_MISMATCH);
1616         return FALSE;
1617     }
1618     if (CreationFlags & ~(DICD_GENERATE_ID | DICD_INHERIT_CLASSDRVS))
1619     {
1620         TRACE("Unknown flags: 0x%08lx\n", CreationFlags & ~(DICD_GENERATE_ID | DICD_INHERIT_CLASSDRVS));
1621         SetLastError(ERROR_INVALID_FLAGS);
1622         return FALSE;
1623     }
1624 
1625     /* Get the root device instance */
1626     cr = CM_Locate_DevInst_ExW(&RootDevInst,
1627                                NULL,
1628                                CM_LOCATE_DEVINST_NORMAL,
1629                                set->hMachine);
1630     if (cr != CR_SUCCESS)
1631     {
1632         SetLastError(ERROR_INVALID_DATA);
1633         return FALSE;
1634     }
1635 
1636     dwFlags = CM_CREATE_DEVINST_PHANTOM;
1637     if (CreationFlags & DICD_GENERATE_ID)
1638         dwFlags |= CM_CREATE_DEVINST_GENERATE_ID;
1639 
1640     /* Create the new device instance */
1641     cr = CM_Create_DevInst_ExW(&DevInst,
1642                                (DEVINSTID)DeviceName,
1643                                RootDevInst,
1644                                dwFlags,
1645                                set->hMachine);
1646     if (cr != CR_SUCCESS)
1647     {
1648         SetLastError(GetErrorCodeFromCrCode(cr));
1649         return FALSE;
1650     }
1651 
1652     if (CreationFlags & DICD_GENERATE_ID)
1653     {
1654         /* Grab the actual instance ID that was created */
1655         cr = CM_Get_Device_ID_Ex(DevInst,
1656                                  GenInstanceId,
1657                                  MAX_DEVICE_ID_LEN,
1658                                  0,
1659                                  set->hMachine);
1660         if (cr != CR_SUCCESS)
1661         {
1662             SetLastError(GetErrorCodeFromCrCode(cr));
1663             return FALSE;
1664         }
1665 
1666         DeviceName = GenInstanceId;
1667         TRACE("Using generated instance ID: %s\n", debugstr_w(DeviceName));
1668     }
1669 
1670     if (CreateDeviceInfo(set, DeviceName, ClassGuid, &deviceInfo))
1671     {
1672         InsertTailList(&set->ListHead, &deviceInfo->ListEntry);
1673 
1674         if (!DeviceInfoData)
1675             ret = TRUE;
1676         else
1677         {
1678             if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
1679             {
1680                 SetLastError(ERROR_INVALID_USER_BUFFER);
1681             }
1682             else
1683             {
1684                 memcpy(&DeviceInfoData->ClassGuid, ClassGuid, sizeof(GUID));
1685                 DeviceInfoData->DevInst = deviceInfo->dnDevInst;
1686                 DeviceInfoData->Reserved = (ULONG_PTR)deviceInfo;
1687                 ret = TRUE;
1688             }
1689         }
1690     }
1691 
1692     if (ret == FALSE)
1693     {
1694         if (deviceInfo != NULL)
1695         {
1696             /* Remove deviceInfo from List */
1697             RemoveEntryList(&deviceInfo->ListEntry);
1698 
1699             /* Destroy deviceInfo */
1700             DestroyDeviceInfo(deviceInfo);
1701         }
1702     }
1703 
1704     TRACE("Returning %d\n", ret);
1705     return ret;
1706 }
1707 
1708 /***********************************************************************
1709  *		SetupDiRegisterDeviceInfo (SETUPAPI.@)
1710  */
1711 BOOL WINAPI SetupDiRegisterDeviceInfo(
1712         HDEVINFO DeviceInfoSet,
1713         PSP_DEVINFO_DATA DeviceInfoData,
1714         DWORD Flags,
1715         PSP_DETSIG_CMPPROC CompareProc,
1716         PVOID CompareContext,
1717         PSP_DEVINFO_DATA DupDeviceInfoData)
1718 {
1719     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
1720     WCHAR DevInstId[MAX_DEVICE_ID_LEN];
1721     DEVINST ParentDevInst;
1722     CONFIGRET cr;
1723     DWORD dwError = ERROR_SUCCESS;
1724 
1725     TRACE("%s(%p %p %08x %p %p %p)\n", __FUNCTION__, DeviceInfoSet, DeviceInfoData, Flags,
1726             CompareProc, CompareContext, DupDeviceInfoData);
1727 
1728     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
1729     {
1730         SetLastError(ERROR_INVALID_HANDLE);
1731         return FALSE;
1732     }
1733     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
1734     {
1735         SetLastError(ERROR_INVALID_HANDLE);
1736         return FALSE;
1737     }
1738     if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
1739             || !DeviceInfoData->Reserved)
1740     {
1741         SetLastError(ERROR_INVALID_PARAMETER);
1742         return FALSE;
1743     }
1744 
1745     if (Flags & ~SPRDI_FIND_DUPS)
1746     {
1747         TRACE("Unknown flags: 0x%08lx\n", Flags & ~SPRDI_FIND_DUPS);
1748         SetLastError(ERROR_INVALID_FLAGS);
1749         return FALSE;
1750     }
1751 
1752     if (Flags & SPRDI_FIND_DUPS)
1753     {
1754         FIXME("Unimplemented codepath!\n");
1755     }
1756 
1757     CM_Get_Device_ID_Ex(DeviceInfoData->DevInst,
1758                         DevInstId,
1759                         MAX_DEVICE_ID_LEN,
1760                         0,
1761                         set->hMachine);
1762 
1763     CM_Get_Parent_Ex(&ParentDevInst,
1764                      DeviceInfoData->DevInst,
1765                      0,
1766                      set->hMachine);
1767 
1768     cr = CM_Create_DevInst_Ex(&DeviceInfoData->DevInst,
1769                               DevInstId,
1770                               ParentDevInst,
1771                               CM_CREATE_DEVINST_NORMAL | CM_CREATE_DEVINST_DO_NOT_INSTALL,
1772                               set->hMachine);
1773     if (cr != CR_SUCCESS &&
1774         cr != CR_ALREADY_SUCH_DEVINST)
1775     {
1776         dwError = ERROR_NO_SUCH_DEVINST;
1777     }
1778 
1779     SetLastError(dwError);
1780 
1781     return (dwError == ERROR_SUCCESS);
1782 }
1783 
1784 /***********************************************************************
1785  *		SetupDiEnumDeviceInfo (SETUPAPI.@)
1786  */
1787 BOOL WINAPI SetupDiEnumDeviceInfo(
1788         HDEVINFO  devinfo,
1789         DWORD  index,
1790         PSP_DEVINFO_DATA info)
1791 {
1792     BOOL ret = FALSE;
1793 
1794     TRACE("%s(%p %d %p)\n", __FUNCTION__, devinfo, index, info);
1795 
1796     if(info==NULL)
1797     {
1798         SetLastError(ERROR_INVALID_PARAMETER);
1799         return FALSE;
1800     }
1801     if (devinfo && devinfo != INVALID_HANDLE_VALUE)
1802     {
1803         struct DeviceInfoSet *list = (struct DeviceInfoSet *)devinfo;
1804         if (list->magic == SETUP_DEVICE_INFO_SET_MAGIC)
1805         {
1806             if (info->cbSize != sizeof(SP_DEVINFO_DATA))
1807                 SetLastError(ERROR_INVALID_USER_BUFFER);
1808             else
1809             {
1810                 PLIST_ENTRY ItemList = list->ListHead.Flink;
1811                 while (ItemList != &list->ListHead && index-- > 0)
1812                     ItemList = ItemList->Flink;
1813                 if (ItemList == &list->ListHead)
1814                     SetLastError(ERROR_NO_MORE_ITEMS);
1815                 else
1816                 {
1817                     struct DeviceInfo *DevInfo = CONTAINING_RECORD(ItemList, struct DeviceInfo, ListEntry);
1818                     memcpy(&info->ClassGuid,
1819                         &DevInfo->ClassGuid,
1820                         sizeof(GUID));
1821                     info->DevInst = DevInfo->dnDevInst;
1822                     info->Reserved = (ULONG_PTR)DevInfo;
1823                     ret = TRUE;
1824                 }
1825             }
1826         }
1827         else
1828             SetLastError(ERROR_INVALID_HANDLE);
1829     }
1830     else
1831         SetLastError(ERROR_INVALID_HANDLE);
1832     return ret;
1833 }
1834 
1835 /***********************************************************************
1836  *		SetupDiGetDeviceInstanceIdA (SETUPAPI.@)
1837  */
1838 BOOL WINAPI SetupDiGetDeviceInstanceIdA(
1839         HDEVINFO DeviceInfoSet,
1840         PSP_DEVINFO_DATA DeviceInfoData,
1841         PSTR DeviceInstanceId,
1842         DWORD DeviceInstanceIdSize,
1843         PDWORD RequiredSize)
1844 {
1845     BOOL ret = FALSE;
1846     DWORD size;
1847     PWSTR instanceId;
1848 
1849     TRACE("%s(%p %p %p %d %p)\n", __FUNCTION__, DeviceInfoSet, DeviceInfoData, DeviceInstanceId,
1850             DeviceInstanceIdSize, RequiredSize);
1851 
1852     if (!DeviceInstanceId && DeviceInstanceIdSize > 0)
1853     {
1854         SetLastError(ERROR_INVALID_PARAMETER);
1855         return FALSE;
1856     }
1857 
1858     ret = SetupDiGetDeviceInstanceIdW(DeviceInfoSet,
1859                                 DeviceInfoData,
1860                                 NULL,
1861                                 0,
1862                                 &size);
1863     if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
1864         return FALSE;
1865     instanceId = MyMalloc(size * sizeof(WCHAR));
1866     if (instanceId)
1867     {
1868         ret = SetupDiGetDeviceInstanceIdW(DeviceInfoSet,
1869                                           DeviceInfoData,
1870                                           instanceId,
1871                                           size,
1872                                           &size);
1873         if (ret)
1874         {
1875             int len = WideCharToMultiByte(CP_ACP, 0, instanceId, -1,
1876                                           DeviceInstanceId,
1877                                           DeviceInstanceIdSize, NULL, NULL);
1878 
1879             if (!len)
1880                 ret = FALSE;
1881             else
1882             {
1883                 if (len > DeviceInstanceIdSize)
1884                 {
1885                     SetLastError(ERROR_INSUFFICIENT_BUFFER);
1886                     ret = FALSE;
1887                 }
1888                 if (RequiredSize)
1889                     *RequiredSize = len;
1890             }
1891         }
1892         MyFree(instanceId);
1893     }
1894     else
1895     {
1896         if (RequiredSize)
1897             *RequiredSize = size;
1898         SetLastError(ERROR_INSUFFICIENT_BUFFER);
1899         ret = FALSE;
1900     }
1901     return ret;
1902 }
1903 
1904 /***********************************************************************
1905  *		SetupDiGetDeviceInstanceIdW (SETUPAPI.@)
1906  */
1907 BOOL WINAPI SetupDiGetDeviceInstanceIdW(
1908         HDEVINFO DeviceInfoSet,
1909         PSP_DEVINFO_DATA DeviceInfoData,
1910         PWSTR DeviceInstanceId,
1911         DWORD DeviceInstanceIdSize,
1912         PDWORD RequiredSize)
1913 {
1914     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
1915     struct DeviceInfo *devInfo;
1916 
1917     TRACE("%s(%p %p %p %d %p)\n", __FUNCTION__, DeviceInfoSet, DeviceInfoData, DeviceInstanceId,
1918             DeviceInstanceIdSize, RequiredSize);
1919 
1920     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
1921     {
1922         SetLastError(ERROR_INVALID_HANDLE);
1923         return FALSE;
1924     }
1925     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
1926     {
1927         SetLastError(ERROR_INVALID_HANDLE);
1928         return FALSE;
1929     }
1930     if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
1931             || !DeviceInfoData->Reserved)
1932     {
1933         SetLastError(ERROR_INVALID_PARAMETER);
1934         return FALSE;
1935     }
1936     devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
1937     if (!DeviceInstanceId && DeviceInstanceIdSize > 0)
1938     {
1939         SetLastError(ERROR_INVALID_PARAMETER);
1940         return FALSE;
1941     }
1942     if (DeviceInstanceId && DeviceInstanceIdSize == 0)
1943     {
1944         SetLastError(ERROR_INVALID_PARAMETER);
1945         return FALSE;
1946     }
1947     TRACE("instance ID: %s\n", debugstr_w(devInfo->instanceId));
1948     if (DeviceInstanceIdSize < lstrlenW(devInfo->instanceId) + 1)
1949     {
1950         SetLastError(ERROR_INSUFFICIENT_BUFFER);
1951         if (RequiredSize)
1952             *RequiredSize = lstrlenW(devInfo->instanceId) + 1;
1953         return FALSE;
1954     }
1955     lstrcpyW(DeviceInstanceId, devInfo->instanceId);
1956     if (RequiredSize)
1957         *RequiredSize = lstrlenW(devInfo->instanceId) + 1;
1958     return TRUE;
1959 }
1960 
1961 /***********************************************************************
1962  *		SetupDiGetActualSectionToInstallA (SETUPAPI.@)
1963  */
1964 BOOL WINAPI SetupDiGetActualSectionToInstallA(
1965         HINF InfHandle,
1966         PCSTR InfSectionName,
1967         PSTR InfSectionWithExt,
1968         DWORD InfSectionWithExtSize,
1969         PDWORD RequiredSize,
1970         PSTR *Extension)
1971 {
1972     return SetupDiGetActualSectionToInstallExA(InfHandle, InfSectionName,
1973         NULL, InfSectionWithExt, InfSectionWithExtSize, RequiredSize,
1974         Extension, NULL);
1975 }
1976 
1977 /***********************************************************************
1978  *		SetupDiGetActualSectionToInstallW (SETUPAPI.@)
1979  */
1980 BOOL WINAPI SetupDiGetActualSectionToInstallW(
1981         HINF InfHandle,
1982         PCWSTR InfSectionName,
1983         PWSTR InfSectionWithExt,
1984         DWORD InfSectionWithExtSize,
1985         PDWORD RequiredSize,
1986         PWSTR *Extension)
1987 {
1988     return SetupDiGetActualSectionToInstallExW(InfHandle, InfSectionName,
1989         NULL, InfSectionWithExt, InfSectionWithExtSize, RequiredSize,
1990         Extension, NULL);
1991 }
1992 
1993 /***********************************************************************
1994  *		SetupDiGetActualSectionToInstallExA  (SETUPAPI.@)
1995  */
1996 BOOL WINAPI
1997 SetupDiGetActualSectionToInstallExA(
1998         IN HINF InfHandle,
1999         IN PCSTR InfSectionName,
2000         IN PSP_ALTPLATFORM_INFO AlternatePlatformInfo OPTIONAL,
2001         OUT PSTR InfSectionWithExt OPTIONAL,
2002         IN DWORD InfSectionWithExtSize,
2003         OUT PDWORD RequiredSize OPTIONAL,
2004         OUT PSTR* Extension OPTIONAL,
2005         IN PVOID Reserved)
2006 {
2007     LPWSTR InfSectionNameW = NULL;
2008     LPWSTR InfSectionWithExtW = NULL;
2009     PWSTR ExtensionW;
2010     BOOL bResult = FALSE;
2011 
2012     TRACE("%s()\n", __FUNCTION__);
2013 
2014     if (InfSectionName)
2015     {
2016         InfSectionNameW = pSetupMultiByteToUnicode(InfSectionName, CP_ACP);
2017         if (InfSectionNameW == NULL)
2018             goto cleanup;
2019     }
2020     if (InfSectionWithExt)
2021     {
2022         InfSectionWithExtW = MyMalloc(InfSectionWithExtSize * sizeof(WCHAR));
2023         if (InfSectionWithExtW == NULL)
2024             goto cleanup;
2025     }
2026 
2027     bResult = SetupDiGetActualSectionToInstallExW(
2028         InfHandle, InfSectionNameW, AlternatePlatformInfo,
2029         InfSectionWithExt ? InfSectionWithExtW : NULL,
2030         InfSectionWithExtSize,
2031         RequiredSize,
2032         Extension ? &ExtensionW : NULL,
2033         Reserved);
2034 
2035     if (bResult && InfSectionWithExt)
2036     {
2037          bResult = WideCharToMultiByte(CP_ACP, 0, InfSectionWithExtW, -1, InfSectionWithExt,
2038              InfSectionWithExtSize, NULL, NULL) != 0;
2039     }
2040     if (bResult && Extension)
2041     {
2042         if (ExtensionW == NULL)
2043             *Extension = NULL;
2044          else
2045             *Extension = &InfSectionWithExt[ExtensionW - InfSectionWithExtW];
2046     }
2047 
2048 cleanup:
2049     MyFree(InfSectionNameW);
2050     MyFree(InfSectionWithExtW);
2051 
2052     return bResult;
2053 }
2054 
2055 /***********************************************************************
2056  *		SetupDiGetClassDescriptionA  (SETUPAPI.@)
2057  */
2058 BOOL WINAPI SetupDiGetClassDescriptionA(
2059         const GUID* ClassGuid,
2060         PSTR ClassDescription,
2061         DWORD ClassDescriptionSize,
2062         PDWORD RequiredSize)
2063 {
2064     return SetupDiGetClassDescriptionExA(ClassGuid, ClassDescription,
2065                                          ClassDescriptionSize,
2066                                          RequiredSize, NULL, NULL);
2067 }
2068 
2069 /***********************************************************************
2070  *		SetupDiGetClassDescriptionW  (SETUPAPI.@)
2071  */
2072 BOOL WINAPI SetupDiGetClassDescriptionW(
2073         const GUID* ClassGuid,
2074         PWSTR ClassDescription,
2075         DWORD ClassDescriptionSize,
2076         PDWORD RequiredSize)
2077 {
2078     return SetupDiGetClassDescriptionExW(ClassGuid, ClassDescription,
2079                                          ClassDescriptionSize,
2080                                          RequiredSize, NULL, NULL);
2081 }
2082 
2083 /***********************************************************************
2084  *		SetupDiGetClassDescriptionExA  (SETUPAPI.@)
2085  */
2086 BOOL WINAPI SetupDiGetClassDescriptionExA(
2087         const GUID* ClassGuid,
2088         PSTR ClassDescription,
2089         DWORD ClassDescriptionSize,
2090         PDWORD RequiredSize,
2091         PCSTR MachineName,
2092         PVOID Reserved)
2093 {
2094     PWCHAR ClassDescriptionW = NULL;
2095     LPWSTR MachineNameW = NULL;
2096     BOOL ret = FALSE;
2097 
2098     TRACE("%s(%s %p %lu %p %s %p)\n", __FUNCTION__, debugstr_guid(ClassGuid), ClassDescription,
2099         ClassDescriptionSize, RequiredSize, debugstr_a(MachineName), Reserved);
2100 
2101     if (ClassDescriptionSize > 0)
2102     {
2103         ClassDescriptionW = MyMalloc(ClassDescriptionSize * sizeof(WCHAR));
2104         if (!ClassDescriptionW)
2105         {
2106             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2107             goto cleanup;
2108         }
2109     }
2110 
2111     if (MachineName)
2112     {
2113         MachineNameW = pSetupMultiByteToUnicode(MachineName, CP_ACP);
2114         if (!MachineNameW)
2115         {
2116             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2117             goto cleanup;
2118         }
2119     }
2120 
2121     ret = SetupDiGetClassDescriptionExW(ClassGuid, ClassDescriptionW,
2122         ClassDescriptionSize * sizeof(WCHAR), RequiredSize, MachineNameW, Reserved);
2123     if (ret)
2124     {
2125         DWORD len = (DWORD)WideCharToMultiByte(CP_ACP, 0, ClassDescriptionW, -1, ClassDescription,
2126             ClassDescriptionSize, NULL, NULL);
2127         if (len == 0 || len > ClassDescriptionSize)
2128         {
2129             SetLastError(ERROR_INSUFFICIENT_BUFFER);
2130             ret = FALSE;
2131         }
2132     }
2133 
2134 cleanup:
2135     MyFree(ClassDescriptionW);
2136     MyFree(MachineNameW);
2137     return ret;
2138 }
2139 
2140 /***********************************************************************
2141  *		SetupDiGetClassDescriptionExW  (SETUPAPI.@)
2142  */
2143 BOOL WINAPI SetupDiGetClassDescriptionExW(
2144         const GUID* ClassGuid,
2145         PWSTR ClassDescription,
2146         DWORD ClassDescriptionSize,
2147         PDWORD RequiredSize,
2148         PCWSTR MachineName,
2149         PVOID Reserved)
2150 {
2151     HKEY hKey;
2152     DWORD dwLength;
2153     DWORD dwRegType;
2154     LONG rc;
2155     PWSTR Buffer;
2156 
2157     TRACE("%s(%s %p %lu %p %s %p)\n", __FUNCTION__, debugstr_guid(ClassGuid), ClassDescription,
2158         ClassDescriptionSize, RequiredSize, debugstr_w(MachineName), Reserved);
2159 
2160     /* Make sure there's a GUID */
2161     if (!ClassGuid)
2162     {
2163         SetLastError(ERROR_INVALID_PARAMETER);
2164         return FALSE;
2165     }
2166 
2167     /* Make sure there's a real buffer when there's a size */
2168     if (!ClassDescription && ClassDescriptionSize > 0)
2169     {
2170         SetLastError(ERROR_INVALID_PARAMETER);
2171         return FALSE;
2172     }
2173 
2174     /* Open the key for the GUID */
2175     hKey = SetupDiOpenClassRegKeyExW(ClassGuid,
2176                                      KEY_QUERY_VALUE,
2177                                      DIOCR_INSTALLER,
2178                                      MachineName,
2179                                      Reserved);
2180     if (hKey == INVALID_HANDLE_VALUE)
2181         return FALSE;
2182 
2183     /* Retrieve the class description data and close the key */
2184     rc = QueryRegistryValue(hKey, NULL, (LPBYTE *) &Buffer, &dwRegType, &dwLength);
2185     RegCloseKey(hKey);
2186 
2187     /* Make sure we got the data */
2188     if (rc != ERROR_SUCCESS)
2189     {
2190         SetLastError(rc);
2191         return FALSE;
2192     }
2193 
2194     /* Make sure the data is a string */
2195     if (dwRegType != REG_SZ)
2196     {
2197         MyFree(Buffer);
2198         SetLastError(ERROR_GEN_FAILURE);
2199         return FALSE;
2200     }
2201 
2202     /* Determine the length of the class description */
2203     dwLength /= sizeof(WCHAR);
2204 
2205     /* Count the null-terminator if none is present */
2206     if ((dwLength == 0) || (Buffer[dwLength - 1] != UNICODE_NULL))
2207         dwLength++;
2208 
2209     /* Inform the caller about the class description */
2210     if ((ClassDescription != NULL) && (dwLength <= ClassDescriptionSize))
2211     {
2212         memcpy(ClassDescription, Buffer, (dwLength - 1) * sizeof(WCHAR));
2213         ClassDescription[dwLength - 1] = UNICODE_NULL;
2214     }
2215 
2216     /* Inform the caller about the required size */
2217     if (RequiredSize != NULL)
2218         *RequiredSize = dwLength;
2219 
2220     /* Clean up the buffer */
2221     MyFree(Buffer);
2222 
2223     /* Make sure the buffer was large enough */
2224     if ((ClassDescription == NULL) || (dwLength > ClassDescriptionSize))
2225     {
2226         SetLastError(ERROR_INSUFFICIENT_BUFFER);
2227         return FALSE;
2228     }
2229 
2230     return TRUE;
2231 }
2232 
2233 /***********************************************************************
2234  *		SetupDiGetClassDevsA (SETUPAPI.@)
2235  */
2236 HDEVINFO WINAPI SetupDiGetClassDevsA(
2237         CONST GUID *class,
2238         LPCSTR enumstr,
2239         HWND parent,
2240         DWORD flags)
2241 {
2242     return SetupDiGetClassDevsExA(class, enumstr, parent,
2243                                   flags, NULL, NULL, NULL);
2244 }
2245 
2246 /***********************************************************************
2247  *		  SetupDiGetClassDevsExA (SETUPAPI.@)
2248  */
2249 HDEVINFO WINAPI SetupDiGetClassDevsExA(
2250         const GUID *class,
2251         PCSTR enumstr,
2252         HWND parent,
2253         DWORD flags,
2254         HDEVINFO deviceset,
2255         PCSTR machine,
2256         PVOID reserved)
2257 {
2258     HDEVINFO ret;
2259     LPWSTR enumstrW = NULL, machineW = NULL;
2260 
2261     if (enumstr)
2262     {
2263         enumstrW = pSetupMultiByteToUnicode(enumstr, CP_ACP);
2264         if (!enumstrW)
2265         {
2266             ret = INVALID_HANDLE_VALUE;
2267             goto end;
2268         }
2269     }
2270     if (machine)
2271     {
2272         machineW = pSetupMultiByteToUnicode(machine, CP_ACP);
2273         if (!machineW)
2274         {
2275             MyFree(enumstrW);
2276             ret = INVALID_HANDLE_VALUE;
2277             goto end;
2278         }
2279     }
2280     ret = SetupDiGetClassDevsExW(class, enumstrW, parent, flags, deviceset,
2281             machineW, reserved);
2282     MyFree(enumstrW);
2283     MyFree(machineW);
2284 
2285 end:
2286     return ret;
2287 }
2288 
2289 /***********************************************************************
2290  *		SetupDiGetClassDevsW (SETUPAPI.@)
2291  */
2292 HDEVINFO WINAPI SetupDiGetClassDevsW(
2293         CONST GUID *class,
2294         LPCWSTR enumstr,
2295         HWND parent,
2296         DWORD flags)
2297 {
2298     return SetupDiGetClassDevsExW(class, enumstr, parent, flags, NULL, NULL,
2299             NULL);
2300 }
2301 
2302 /***********************************************************************
2303  *              SetupDiGetClassDevsExW (SETUPAPI.@)
2304  */
2305 HDEVINFO WINAPI SetupDiGetClassDevsExW(
2306         CONST GUID *class,
2307         PCWSTR enumstr,
2308         HWND parent,
2309         DWORD flags,
2310         HDEVINFO deviceset,
2311         PCWSTR machine,
2312         PVOID reserved)
2313 {
2314     HDEVINFO hDeviceInfo = INVALID_HANDLE_VALUE;
2315     struct DeviceInfoSet *list;
2316     CONST GUID *pClassGuid;
2317     LONG rc;
2318     HDEVINFO set = INVALID_HANDLE_VALUE;
2319 
2320     TRACE("%s(%s %s %p 0x%08x %p %s %p)\n", __FUNCTION__, debugstr_guid(class),
2321             debugstr_w(enumstr), parent, flags, deviceset, debugstr_w(machine),
2322             reserved);
2323 
2324     if (!(flags & DIGCF_ALLCLASSES) && !class)
2325     {
2326         SetLastError(ERROR_INVALID_PARAMETER);
2327         return INVALID_HANDLE_VALUE;
2328     }
2329 
2330     /* Create the deviceset if not set */
2331     if (deviceset)
2332     {
2333         list = (struct DeviceInfoSet *)deviceset;
2334         if (list->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2335         {
2336             SetLastError(ERROR_INVALID_HANDLE);
2337             goto cleanup;
2338         }
2339         hDeviceInfo = deviceset;
2340     }
2341     else
2342     {
2343          hDeviceInfo = SetupDiCreateDeviceInfoListExW(
2344              flags & (DIGCF_DEVICEINTERFACE | DIGCF_ALLCLASSES) ? NULL : class,
2345              NULL, machine, NULL);
2346          if (hDeviceInfo == INVALID_HANDLE_VALUE)
2347              goto cleanup;
2348          list = (struct DeviceInfoSet *)hDeviceInfo;
2349     }
2350 
2351     if (flags & DIGCF_PROFILE)
2352         FIXME(": flag DIGCF_PROFILE ignored\n");
2353 
2354     if (flags & DIGCF_DEVICEINTERFACE)
2355     {
2356         if (!class)
2357         {
2358             SetLastError(ERROR_INVALID_PARAMETER);
2359             goto cleanup;
2360         }
2361         rc = SETUP_CreateInterfaceList(list, machine, class, enumstr, flags & DIGCF_PRESENT);
2362     }
2363     else
2364     {
2365         /* Determine which class(es) should be included in the deviceset */
2366         if (flags & DIGCF_ALLCLASSES)
2367         {
2368             /* The caller wants all classes. Check if
2369              * the deviceset limits us to one class */
2370             if (IsEqualIID(&list->ClassGuid, &GUID_NULL))
2371                 pClassGuid = NULL;
2372             else
2373                 pClassGuid = &list->ClassGuid;
2374         }
2375         else if (class)
2376         {
2377             /* The caller wants one class. Check if it matches deviceset class */
2378             if (IsEqualIID(&list->ClassGuid, class)
2379              || IsEqualIID(&list->ClassGuid, &GUID_NULL))
2380             {
2381                 pClassGuid = class;
2382             }
2383             else
2384             {
2385                 SetLastError(ERROR_INVALID_PARAMETER);
2386                 goto cleanup;
2387             }
2388         }
2389         else if (!IsEqualIID(&list->ClassGuid, &GUID_NULL))
2390         {
2391             /* No class specified. Try to use the one of the deviceset */
2392             if (IsEqualIID(&list->ClassGuid, &GUID_NULL))
2393                 pClassGuid = &list->ClassGuid;
2394             else
2395             {
2396                 SetLastError(ERROR_INVALID_PARAMETER);
2397                 goto cleanup;
2398             }
2399         }
2400         else
2401         {
2402             SetLastError(ERROR_INVALID_PARAMETER);
2403             goto cleanup;
2404         }
2405         rc = SETUP_CreateDevicesList(list, machine, pClassGuid, enumstr);
2406     }
2407     if (rc != ERROR_SUCCESS)
2408     {
2409         SetLastError(rc);
2410         goto cleanup;
2411     }
2412     set = hDeviceInfo;
2413 
2414 cleanup:
2415     if (!deviceset && hDeviceInfo != INVALID_HANDLE_VALUE && hDeviceInfo != set)
2416         SetupDiDestroyDeviceInfoList(hDeviceInfo);
2417     return set;
2418 }
2419 
2420 /***********************************************************************
2421  *		SetupDiGetDeviceInfoListDetailA  (SETUPAPI.@)
2422  */
2423 BOOL WINAPI SetupDiGetDeviceInfoListDetailA(
2424         HDEVINFO DeviceInfoSet,
2425         PSP_DEVINFO_LIST_DETAIL_DATA_A DevInfoData )
2426 {
2427     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2428 
2429     TRACE("%s(%p %p)\n", __FUNCTION__, DeviceInfoSet, DevInfoData);
2430 
2431     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
2432     {
2433         SetLastError(ERROR_INVALID_HANDLE);
2434         return FALSE;
2435     }
2436     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2437     {
2438         SetLastError(ERROR_INVALID_HANDLE);
2439         return FALSE;
2440     }
2441     if (!DevInfoData ||
2442             DevInfoData->cbSize != sizeof(SP_DEVINFO_LIST_DETAIL_DATA_A))
2443     {
2444         SetLastError(ERROR_INVALID_PARAMETER);
2445         return FALSE;
2446     }
2447     memcpy(&DevInfoData->ClassGuid, &set->ClassGuid, sizeof(GUID));
2448     DevInfoData->RemoteMachineHandle = set->hMachine;
2449     if (set->MachineName)
2450     {
2451         FIXME("Stub\n");
2452         SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2453         return FALSE;
2454     }
2455     else
2456         DevInfoData->RemoteMachineName[0] = 0;
2457 
2458     return TRUE;
2459 }
2460 
2461 /***********************************************************************
2462  *		SetupDiGetDeviceInfoListDetailW  (SETUPAPI.@)
2463  */
2464 BOOL WINAPI SetupDiGetDeviceInfoListDetailW(
2465         HDEVINFO DeviceInfoSet,
2466         PSP_DEVINFO_LIST_DETAIL_DATA_W DevInfoData )
2467 {
2468     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2469 
2470     TRACE("%s(%p %p)\n", __FUNCTION__, DeviceInfoSet, DevInfoData);
2471 
2472     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
2473     {
2474         SetLastError(ERROR_INVALID_HANDLE);
2475         return FALSE;
2476     }
2477     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2478     {
2479         SetLastError(ERROR_INVALID_HANDLE);
2480         return FALSE;
2481     }
2482     if (!DevInfoData ||
2483             DevInfoData->cbSize != sizeof(SP_DEVINFO_LIST_DETAIL_DATA_W))
2484     {
2485         SetLastError(ERROR_INVALID_PARAMETER);
2486         return FALSE;
2487     }
2488     memcpy(&DevInfoData->ClassGuid, &set->ClassGuid, sizeof(GUID));
2489     DevInfoData->RemoteMachineHandle = set->hMachine;
2490     if (set->MachineName)
2491         strcpyW(DevInfoData->RemoteMachineName, set->MachineName + 2);
2492     else
2493         DevInfoData->RemoteMachineName[0] = 0;
2494 
2495     return TRUE;
2496 }
2497 
2498 /***********************************************************************
2499  *		SetupDiCreateDeviceInterfaceA (SETUPAPI.@)
2500  */
2501 BOOL WINAPI SetupDiCreateDeviceInterfaceA(
2502         HDEVINFO DeviceInfoSet,
2503         PSP_DEVINFO_DATA DeviceInfoData,
2504         const GUID *InterfaceClassGuid,
2505         PCSTR ReferenceString,
2506         DWORD CreationFlags,
2507         PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
2508 {
2509     BOOL ret;
2510     LPWSTR ReferenceStringW = NULL;
2511 
2512     TRACE("%s(%p %p %s %s %08x %p)\n", __FUNCTION__, DeviceInfoSet, DeviceInfoData,
2513             debugstr_guid(InterfaceClassGuid), debugstr_a(ReferenceString),
2514             CreationFlags, DeviceInterfaceData);
2515 
2516     if (ReferenceString)
2517     {
2518         ReferenceStringW = pSetupMultiByteToUnicode(ReferenceString, CP_ACP);
2519         if (ReferenceStringW == NULL) return FALSE;
2520     }
2521 
2522     ret = SetupDiCreateDeviceInterfaceW(DeviceInfoSet, DeviceInfoData,
2523             InterfaceClassGuid, ReferenceStringW, CreationFlags,
2524             DeviceInterfaceData);
2525 
2526     MyFree(ReferenceStringW);
2527 
2528     return ret;
2529 }
2530 
2531 /***********************************************************************
2532  *		SetupDiCreateDeviceInterfaceW (SETUPAPI.@)
2533  */
2534 BOOL WINAPI SetupDiCreateDeviceInterfaceW(
2535         HDEVINFO DeviceInfoSet,
2536         PSP_DEVINFO_DATA DeviceInfoData,
2537         const GUID *InterfaceClassGuid,
2538         PCWSTR ReferenceString,
2539         DWORD CreationFlags,
2540         PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
2541 {
2542     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2543     TRACE("%s(%p %p %s %s %08x %p)\n", __FUNCTION__, DeviceInfoSet, DeviceInfoData,
2544             debugstr_guid(InterfaceClassGuid), debugstr_w(ReferenceString),
2545             CreationFlags, DeviceInterfaceData);
2546 
2547     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
2548     {
2549         SetLastError(ERROR_INVALID_HANDLE);
2550         return FALSE;
2551     }
2552     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2553     {
2554         SetLastError(ERROR_INVALID_HANDLE);
2555         return FALSE;
2556     }
2557     if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
2558             || !DeviceInfoData->Reserved)
2559     {
2560         SetLastError(ERROR_INVALID_PARAMETER);
2561         return FALSE;
2562     }
2563     if (!InterfaceClassGuid)
2564     {
2565         SetLastError(ERROR_INVALID_USER_BUFFER);
2566         return FALSE;
2567     }
2568 
2569     FIXME("%p %p %s %s %08x %p\n", DeviceInfoSet, DeviceInfoData,
2570             debugstr_guid(InterfaceClassGuid), debugstr_w(ReferenceString),
2571             CreationFlags, DeviceInterfaceData);
2572     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2573     return FALSE;
2574 }
2575 
2576 /***********************************************************************
2577  *		SetupDiCreateDeviceInterfaceRegKeyA (SETUPAPI.@)
2578  */
2579 HKEY WINAPI SetupDiCreateDeviceInterfaceRegKeyA(
2580         HDEVINFO DeviceInfoSet,
2581         PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
2582         DWORD Reserved,
2583         REGSAM samDesired,
2584         HINF InfHandle,
2585         PCSTR InfSectionName)
2586 {
2587     HKEY key;
2588     PWSTR InfSectionNameW = NULL;
2589 
2590     TRACE("%s(%p %p %d %08x %p %p)\n", __FUNCTION__, DeviceInfoSet, DeviceInterfaceData, Reserved,
2591             samDesired, InfHandle, InfSectionName);
2592     if (InfHandle)
2593     {
2594         if (!InfSectionName)
2595         {
2596             SetLastError(ERROR_INVALID_PARAMETER);
2597             return INVALID_HANDLE_VALUE;
2598         }
2599         InfSectionNameW = pSetupMultiByteToUnicode(InfSectionName, CP_ACP);
2600         if (!InfSectionNameW)
2601             return INVALID_HANDLE_VALUE;
2602     }
2603     key = SetupDiCreateDeviceInterfaceRegKeyW(DeviceInfoSet,
2604             DeviceInterfaceData, Reserved, samDesired, InfHandle,
2605             InfSectionNameW);
2606     MyFree(InfSectionNameW);
2607     return key;
2608 }
2609 
2610 /***********************************************************************
2611  *		SetupDiCreateDeviceInterfaceRegKeyW (SETUPAPI.@)
2612  */
2613 HKEY WINAPI SetupDiCreateDeviceInterfaceRegKeyW(
2614         HDEVINFO DeviceInfoSet,
2615         PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
2616         DWORD Reserved,
2617         REGSAM samDesired,
2618         HINF InfHandle,
2619         PCWSTR InfSectionName)
2620 {
2621     HKEY hKey, hDevKey;
2622     LPWSTR SymbolicLink;
2623     DWORD Length, Index;
2624     LONG rc;
2625     WCHAR bracedGuidString[39];
2626     struct DeviceInterface *DevItf;
2627     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2628 
2629     TRACE("%s(%p %p %d %08x %p %p)\n", __FUNCTION__, DeviceInfoSet, DeviceInterfaceData, Reserved,
2630             samDesired, InfHandle, InfSectionName);
2631 
2632     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE ||
2633             set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2634     {
2635         SetLastError(ERROR_INVALID_HANDLE);
2636         return INVALID_HANDLE_VALUE;
2637     }
2638     if (!DeviceInterfaceData ||
2639             DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA) ||
2640             !DeviceInterfaceData->Reserved)
2641     {
2642         SetLastError(ERROR_INVALID_PARAMETER);
2643         return INVALID_HANDLE_VALUE;
2644     }
2645     if (InfHandle && !InfSectionName)
2646     {
2647         SetLastError(ERROR_INVALID_PARAMETER);
2648         return INVALID_HANDLE_VALUE;
2649     }
2650 
2651     hKey = SetupDiOpenClassRegKeyExW(&DeviceInterfaceData->InterfaceClassGuid, samDesired, DIOCR_INTERFACE, NULL, NULL);
2652     if (hKey == INVALID_HANDLE_VALUE)
2653     {
2654         hKey = SetupDiOpenClassRegKeyExW(NULL, samDesired, DIOCR_INTERFACE, NULL, NULL);
2655         if (hKey == INVALID_HANDLE_VALUE)
2656         {
2657             SetLastError(ERROR_INVALID_PARAMETER);
2658             return INVALID_HANDLE_VALUE;
2659         }
2660         SETUPDI_GuidToString(&DeviceInterfaceData->InterfaceClassGuid, bracedGuidString);
2661 
2662         if (RegCreateKeyExW(hKey, bracedGuidString, 0, NULL, 0, samDesired, NULL, &hDevKey, NULL) != ERROR_SUCCESS)
2663         {
2664             SetLastError(ERROR_INVALID_PARAMETER);
2665             return INVALID_HANDLE_VALUE;
2666         }
2667         RegCloseKey(hKey);
2668         hKey = hDevKey;
2669     }
2670 
2671     DevItf = (struct DeviceInterface *)DeviceInterfaceData->Reserved;
2672 
2673     Length = (wcslen(DevItf->SymbolicLink)+1) * sizeof(WCHAR);
2674     SymbolicLink = HeapAlloc(GetProcessHeap(), 0, Length);
2675     if (!SymbolicLink)
2676     {
2677         RegCloseKey(hKey);
2678         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2679         return INVALID_HANDLE_VALUE;
2680     }
2681 
2682     wcscpy(SymbolicLink, DevItf->SymbolicLink);
2683 
2684     Index = 0;
2685     while(SymbolicLink[Index])
2686     {
2687         if (SymbolicLink[Index] == L'\\')
2688         {
2689             SymbolicLink[Index] = L'#';
2690         }
2691         Index++;
2692     }
2693 
2694     rc = RegCreateKeyExW(hKey, SymbolicLink, 0, NULL, 0, samDesired, NULL, &hDevKey, NULL);
2695 
2696     RegCloseKey(hKey);
2697     HeapFree(GetProcessHeap(), 0, SymbolicLink);
2698 
2699     if (rc == ERROR_SUCCESS)
2700     {
2701         if (InfHandle && InfSectionName)
2702         {
2703             if (!SetupInstallFromInfSection(NULL /*FIXME */,
2704                                             InfHandle,
2705                                             InfSectionName,
2706                                             SPINST_INIFILES | SPINST_REGISTRY | SPINST_INI2REG | SPINST_FILES | SPINST_BITREG | SPINST_REGSVR | SPINST_UNREGSVR | SPINST_PROFILEITEMS | SPINST_COPYINF,
2707                                             hDevKey,
2708                                             NULL,
2709                                             0,
2710                                             set->SelectedDevice->InstallParams.InstallMsgHandler,
2711                                             set->SelectedDevice->InstallParams.InstallMsgHandlerContext,
2712                                             INVALID_HANDLE_VALUE,
2713                                             NULL))
2714             {
2715                 RegCloseKey(hDevKey);
2716                 return INVALID_HANDLE_VALUE;
2717             }
2718         }
2719     }
2720 
2721     SetLastError(rc);
2722     return hDevKey;
2723 }
2724 
2725 /***********************************************************************
2726  *		SetupDiDeleteDeviceInterfaceRegKey (SETUPAPI.@)
2727  */
2728 BOOL WINAPI SetupDiDeleteDeviceInterfaceRegKey(
2729         HDEVINFO DeviceInfoSet,
2730         PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
2731         DWORD Reserved)
2732 {
2733     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2734     BOOL ret = FALSE;
2735 
2736     TRACE("%s(%p %p %d)\n", __FUNCTION__, DeviceInfoSet, DeviceInterfaceData, Reserved);
2737 
2738     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE ||
2739             set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2740     {
2741         SetLastError(ERROR_INVALID_HANDLE);
2742         return FALSE;
2743     }
2744     if (!DeviceInterfaceData ||
2745             DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA) ||
2746             !DeviceInterfaceData->Reserved)
2747     {
2748         SetLastError(ERROR_INVALID_PARAMETER);
2749         return FALSE;
2750     }
2751 
2752     FIXME("%p %p %d\n", DeviceInfoSet, DeviceInterfaceData, Reserved);
2753     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2754     return ret;
2755 }
2756 
2757 /***********************************************************************
2758  *		SetupDiEnumDeviceInterfaces (SETUPAPI.@)
2759  *
2760  * PARAMS
2761  *   DeviceInfoSet      [I]    Set of devices from which to enumerate
2762  *                             interfaces
2763  *   DeviceInfoData     [I]    (Optional) If specified, a specific device
2764  *                             instance from which to enumerate interfaces.
2765  *                             If it isn't specified, all interfaces for all
2766  *                             devices in the set are enumerated.
2767  *   InterfaceClassGuid [I]    The interface class to enumerate.
2768  *   MemberIndex        [I]    An index of the interface instance to enumerate.
2769  *                             A caller should start with MemberIndex set to 0,
2770  *                             and continue until the function fails with
2771  *                             ERROR_NO_MORE_ITEMS.
2772  *   DeviceInterfaceData [I/O] Returns an enumerated interface.  Its cbSize
2773  *                             member must be set to
2774  *                             sizeof(SP_DEVICE_INTERFACE_DATA).
2775  *
2776  * RETURNS
2777  *   Success: non-zero value.
2778  *   Failure: FALSE.  Call GetLastError() for more info.
2779  */
2780 BOOL WINAPI SetupDiEnumDeviceInterfaces(
2781         HDEVINFO DeviceInfoSet,
2782         PSP_DEVINFO_DATA DeviceInfoData,
2783         CONST GUID * InterfaceClassGuid,
2784         DWORD MemberIndex,
2785         PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
2786 {
2787     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2788     BOOL ret = FALSE;
2789 
2790     TRACE("%s(%p, %p, %s, %d, %p)\n", __FUNCTION__, DeviceInfoSet, DeviceInfoData,
2791      debugstr_guid(InterfaceClassGuid), MemberIndex, DeviceInterfaceData);
2792 
2793     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE ||
2794             set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2795     {
2796         SetLastError(ERROR_INVALID_HANDLE);
2797         return FALSE;
2798     }
2799     if (DeviceInfoData && (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA) ||
2800                 !DeviceInfoData->Reserved))
2801     {
2802         SetLastError(ERROR_INVALID_PARAMETER);
2803         return FALSE;
2804     }
2805     if (!DeviceInterfaceData ||
2806             DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA))
2807     {
2808         SetLastError(ERROR_INVALID_PARAMETER);
2809         return FALSE;
2810     }
2811     if (DeviceInfoData)
2812     {
2813         struct DeviceInfo *devInfo =
2814             (struct DeviceInfo *)DeviceInfoData->Reserved;
2815         BOOL found = FALSE;
2816         PLIST_ENTRY InterfaceListEntry = devInfo->InterfaceListHead.Flink;
2817         while (InterfaceListEntry != &devInfo->InterfaceListHead && !found)
2818         {
2819             struct DeviceInterface *DevItf = CONTAINING_RECORD(InterfaceListEntry, struct DeviceInterface, ListEntry);
2820             if (!IsEqualIID(&DevItf->InterfaceClassGuid, InterfaceClassGuid))
2821             {
2822                 InterfaceListEntry = InterfaceListEntry->Flink;
2823                 continue;
2824             }
2825             if (MemberIndex-- == 0)
2826             {
2827                 /* return this item */
2828                 memcpy(&DeviceInterfaceData->InterfaceClassGuid,
2829                     &DevItf->InterfaceClassGuid,
2830                     sizeof(GUID));
2831                 DeviceInterfaceData->Flags = DevItf->Flags;
2832                 DeviceInterfaceData->Reserved = (ULONG_PTR)DevItf;
2833                 found = TRUE;
2834                 ret = TRUE;
2835             }
2836             InterfaceListEntry = InterfaceListEntry->Flink;
2837         }
2838         if (!found)
2839             SetLastError(ERROR_NO_MORE_ITEMS);
2840     }
2841     else
2842     {
2843         BOOL found = FALSE;
2844         PLIST_ENTRY ItemList = set->ListHead.Flink;
2845         while (ItemList != &set->ListHead && !found)
2846         {
2847             PLIST_ENTRY InterfaceListEntry;
2848             struct DeviceInfo *devInfo =
2849                 CONTAINING_RECORD(ItemList, struct DeviceInfo, ListEntry);
2850             InterfaceListEntry = devInfo->InterfaceListHead.Flink;
2851             while (InterfaceListEntry != &devInfo->InterfaceListHead && !found)
2852             {
2853                 struct DeviceInterface *DevItf = CONTAINING_RECORD(InterfaceListEntry, struct DeviceInterface, ListEntry);
2854                 if (!IsEqualIID(&DevItf->InterfaceClassGuid, InterfaceClassGuid))
2855                 {
2856                     InterfaceListEntry = InterfaceListEntry->Flink;
2857                     continue;
2858                 }
2859                 if (MemberIndex-- == 0)
2860                 {
2861                     /* return this item */
2862                     memcpy(&DeviceInterfaceData->InterfaceClassGuid,
2863                         &DevItf->InterfaceClassGuid,
2864                         sizeof(GUID));
2865                     DeviceInterfaceData->Flags = DevItf->Flags;
2866                     DeviceInterfaceData->Reserved = (ULONG_PTR)DevItf;
2867                     found = TRUE;
2868                     ret = TRUE;
2869                 }
2870                 InterfaceListEntry = InterfaceListEntry->Flink;
2871             }
2872             ItemList = ItemList->Flink;
2873 
2874         }
2875         if (!found)
2876             SetLastError(ERROR_NO_MORE_ITEMS);
2877     }
2878     return ret;
2879 }
2880 
2881 /***********************************************************************
2882  *		SetupDiDestroyDeviceInfoList (SETUPAPI.@)
2883   *
2884  * Destroy a DeviceInfoList and free all used memory of the list.
2885  *
2886  * PARAMS
2887  *   devinfo [I] DeviceInfoList pointer to list to destroy
2888  *
2889  * RETURNS
2890  *   Success: non zero value.
2891  *   Failure: zero value.
2892  */
2893 BOOL WINAPI SetupDiDestroyDeviceInfoList(HDEVINFO devinfo)
2894 {
2895     BOOL ret = FALSE;
2896 
2897     TRACE("%s(%p)\n", __FUNCTION__, devinfo);
2898     if (devinfo && devinfo != INVALID_HANDLE_VALUE)
2899     {
2900         struct DeviceInfoSet *list = (struct DeviceInfoSet *)devinfo;
2901 
2902         if (list->magic == SETUP_DEVICE_INFO_SET_MAGIC)
2903         {
2904             ret = DestroyDeviceInfoSet(list);
2905         }
2906     }
2907 
2908     if (ret == FALSE)
2909         SetLastError(ERROR_INVALID_HANDLE);
2910 
2911     return ret;
2912 }
2913 
2914 /***********************************************************************
2915  *		SetupDiGetDeviceInterfaceDetailA (SETUPAPI.@)
2916  */
2917 BOOL WINAPI SetupDiGetDeviceInterfaceDetailA(
2918         HDEVINFO DeviceInfoSet,
2919         PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
2920         PSP_DEVICE_INTERFACE_DETAIL_DATA_A DeviceInterfaceDetailData,
2921         DWORD DeviceInterfaceDetailDataSize,
2922         PDWORD RequiredSize,
2923         PSP_DEVINFO_DATA DeviceInfoData)
2924 {
2925     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2926     PSP_DEVICE_INTERFACE_DETAIL_DATA_W DeviceInterfaceDetailDataW = NULL;
2927     DWORD sizeW = 0, bytesNeeded;
2928     BOOL ret = FALSE;
2929 
2930     TRACE("%s(%p, %p, %p, %d, %p, %p)\n", __FUNCTION__, DeviceInfoSet,
2931      DeviceInterfaceData, DeviceInterfaceDetailData,
2932      DeviceInterfaceDetailDataSize, RequiredSize, DeviceInfoData);
2933 
2934     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE ||
2935             set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2936     {
2937         SetLastError(ERROR_INVALID_HANDLE);
2938         return FALSE;
2939     }
2940     if (!DeviceInterfaceData ||
2941             DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA) ||
2942             !DeviceInterfaceData->Reserved)
2943     {
2944         SetLastError(ERROR_INVALID_PARAMETER);
2945         return FALSE;
2946     }
2947     if (DeviceInterfaceDetailData && (DeviceInterfaceDetailData->cbSize != sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A)))
2948     {
2949         SetLastError(ERROR_INVALID_USER_BUFFER);
2950         return FALSE;
2951     }
2952 
2953     if((DeviceInterfaceDetailDataSize != 0) &&
2954         (DeviceInterfaceDetailDataSize < (FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath) + sizeof(CHAR))))
2955     {
2956         SetLastError(ERROR_INVALID_USER_BUFFER);
2957         return FALSE;
2958     }
2959 
2960     if (!DeviceInterfaceDetailData && DeviceInterfaceDetailDataSize)
2961     {
2962         SetLastError(ERROR_INVALID_USER_BUFFER);
2963         return FALSE;
2964     }
2965 
2966 
2967     if (DeviceInterfaceDetailData != NULL)
2968     {
2969         sizeW = FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath)
2970             + (DeviceInterfaceDetailDataSize - FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath)) * sizeof(WCHAR);
2971         DeviceInterfaceDetailDataW = (PSP_DEVICE_INTERFACE_DETAIL_DATA_W)MyMalloc(sizeW);
2972         if (!DeviceInterfaceDetailDataW)
2973         {
2974             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2975         }
2976         DeviceInterfaceDetailDataW->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W);
2977     }
2978     if (!DeviceInterfaceDetailData || (DeviceInterfaceDetailData && DeviceInterfaceDetailDataW))
2979     {
2980         ret = SetupDiGetDeviceInterfaceDetailW(
2981             DeviceInfoSet,
2982             DeviceInterfaceData,
2983             DeviceInterfaceDetailDataW,
2984             sizeW,
2985             &sizeW,
2986             DeviceInfoData);
2987         bytesNeeded = (sizeW - FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath)) / sizeof(WCHAR)
2988             + FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath);
2989         if (RequiredSize)
2990             *RequiredSize = bytesNeeded;
2991         if (ret && DeviceInterfaceDetailData && DeviceInterfaceDetailDataSize >= bytesNeeded)
2992         {
2993             if (!WideCharToMultiByte(
2994                 CP_ACP, 0,
2995                 DeviceInterfaceDetailDataW->DevicePath, -1,
2996                 DeviceInterfaceDetailData->DevicePath, DeviceInterfaceDetailDataSize - FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath),
2997                 NULL, NULL))
2998             {
2999                 ret = FALSE;
3000             }
3001         }
3002     }
3003     MyFree(DeviceInterfaceDetailDataW);
3004 
3005     return ret;
3006 }
3007 
3008 /***********************************************************************
3009  *		SetupDiGetDeviceInterfaceDetailW (SETUPAPI.@)
3010  */
3011 BOOL WINAPI SetupDiGetDeviceInterfaceDetailW(
3012         HDEVINFO DeviceInfoSet,
3013         PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
3014         PSP_DEVICE_INTERFACE_DETAIL_DATA_W DeviceInterfaceDetailData,
3015         DWORD DeviceInterfaceDetailDataSize,
3016         PDWORD RequiredSize,
3017         PSP_DEVINFO_DATA DeviceInfoData)
3018 {
3019     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
3020     BOOL ret = FALSE;
3021 
3022     TRACE("%s(%p, %p, %p, %d, %p, %p)\n", __FUNCTION__, DeviceInfoSet,
3023      DeviceInterfaceData, DeviceInterfaceDetailData,
3024      DeviceInterfaceDetailDataSize, RequiredSize, DeviceInfoData);
3025 
3026     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE ||
3027             set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
3028     {
3029         SetLastError(ERROR_INVALID_HANDLE);
3030         return FALSE;
3031     }
3032     if (!DeviceInterfaceData ||
3033             DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA) ||
3034             !DeviceInterfaceData->Reserved)
3035     {
3036         SetLastError(ERROR_INVALID_PARAMETER);
3037         return FALSE;
3038     }
3039     if (DeviceInterfaceDetailData && DeviceInterfaceDetailData->cbSize != sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W))
3040     {
3041         SetLastError(ERROR_INVALID_USER_BUFFER);
3042         return FALSE;
3043     }
3044     if (!DeviceInterfaceDetailData && DeviceInterfaceDetailDataSize)
3045     {
3046         SetLastError(ERROR_INVALID_USER_BUFFER);
3047         return FALSE;
3048     }
3049     if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
3050     {
3051         SetLastError(ERROR_INVALID_PARAMETER);
3052         return FALSE;
3053     }
3054     if ((DeviceInterfaceDetailData != NULL)
3055         && (DeviceInterfaceDetailDataSize < (FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath)) + sizeof(WCHAR)))
3056     {
3057         SetLastError(ERROR_INVALID_PARAMETER);
3058         return FALSE;
3059     }
3060     else
3061     {
3062         struct DeviceInterface *deviceInterface = (struct DeviceInterface *)DeviceInterfaceData->Reserved;
3063         LPCWSTR devName = deviceInterface->SymbolicLink;
3064         DWORD sizeRequired = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W) +
3065             (lstrlenW(devName) + 1) * sizeof(WCHAR);
3066 
3067         if (sizeRequired > DeviceInterfaceDetailDataSize)
3068         {
3069             SetLastError(ERROR_INSUFFICIENT_BUFFER);
3070             if (RequiredSize)
3071                 *RequiredSize = sizeRequired;
3072         }
3073         else
3074         {
3075             strcpyW(DeviceInterfaceDetailData->DevicePath, devName);
3076             TRACE("DevicePath is %s\n", debugstr_w(DeviceInterfaceDetailData->DevicePath));
3077             if (DeviceInfoData)
3078             {
3079                 memcpy(&DeviceInfoData->ClassGuid,
3080                     &deviceInterface->DeviceInfo->ClassGuid,
3081                     sizeof(GUID));
3082                 DeviceInfoData->DevInst = deviceInterface->DeviceInfo->dnDevInst;
3083                 DeviceInfoData->Reserved = (ULONG_PTR)deviceInterface->DeviceInfo;
3084             }
3085             ret = TRUE;
3086         }
3087     }
3088     return ret;
3089 }
3090 
3091 struct PropertyMapEntry
3092 {
3093     DWORD   regType;
3094     LPCSTR  nameA;
3095     LPCWSTR nameW;
3096 };
3097 
3098 static struct PropertyMapEntry PropertyMap[] = {
3099     { REG_SZ, "DeviceDesc", REGSTR_VAL_DEVDESC },
3100     { REG_MULTI_SZ, "HardwareId", REGSTR_VAL_HARDWAREID },
3101     { REG_MULTI_SZ, "CompatibleIDs", REGSTR_VAL_COMPATIBLEIDS },
3102     { 0, NULL, NULL }, /* SPDRP_UNUSED0 */
3103     { REG_SZ, "Service", REGSTR_VAL_SERVICE },
3104     { 0, NULL, NULL }, /* SPDRP_UNUSED1 */
3105     { 0, NULL, NULL }, /* SPDRP_UNUSED2 */
3106     { REG_SZ, "Class", REGSTR_VAL_CLASS },
3107     { REG_SZ, "ClassGUID", REGSTR_VAL_CLASSGUID },
3108     { REG_SZ, "Driver", REGSTR_VAL_DRIVER },
3109     { REG_DWORD, "ConfigFlags", REGSTR_VAL_CONFIGFLAGS },
3110     { REG_SZ, "Mfg", REGSTR_VAL_MFG },
3111     { REG_SZ, "FriendlyName", REGSTR_VAL_FRIENDLYNAME },
3112     { REG_SZ, "LocationInformation", REGSTR_VAL_LOCATION_INFORMATION },
3113     { 0, NULL, NULL }, /* SPDRP_PHYSICAL_DEVICE_OBJECT_NAME */
3114     { REG_DWORD, "Capabilities", REGSTR_VAL_CAPABILITIES },
3115     { REG_DWORD, "UINumber", REGSTR_VAL_UI_NUMBER },
3116     { REG_MULTI_SZ, "UpperFilters", REGSTR_VAL_UPPERFILTERS },
3117     { REG_MULTI_SZ, "LowerFilters", REGSTR_VAL_LOWERFILTERS },
3118     { 0, NULL, NULL }, /* SPDRP_BUSTYPEGUID */
3119     { 0, NULL, NULL }, /* SPDRP_LEGACYBUSTYPE */
3120     { 0, NULL, NULL }, /* SPDRP_BUSNUMBER */
3121     { 0, NULL, NULL }, /* SPDRP_ENUMERATOR_NAME */
3122     { REG_BINARY, "Security", REGSTR_SECURITY },
3123     { 0, NULL, NULL }, /* SPDRP_SECURITY_SDS */
3124     { 0, NULL, NULL }, /* SPDRP_DEVTYPE */
3125     { 0, NULL, NULL }, /* SPDRP_EXCLUSIVE */
3126     { 0, NULL, NULL }, /* SPDRP_CHARACTERISTICS */
3127     { 0, NULL, NULL }, /* SPDRP_ADDRESS */
3128     { REG_SZ, "UINumberDescFormat", REGSTR_UI_NUMBER_DESC_FORMAT },
3129     { 0, NULL, NULL }, /* SPDRP_DEVICE_POWER_DATA */
3130     { 0, NULL, NULL }, /* SPDRP_REMOVAL_POLICY */
3131     { 0, NULL, NULL }, /* SPDRP_REMOVAL_POLICY_HW_DEFAULT */
3132     { 0, NULL, NULL }, /* SPDRP_REMOVAL_POLICY_OVERRIDE */
3133     { 0, NULL, NULL }, /* SPDRP_INSTALL_STATE */
3134 };
3135 
3136 /***********************************************************************
3137  *		SetupDiGetDeviceRegistryPropertyA (SETUPAPI.@)
3138  */
3139 BOOL WINAPI SetupDiGetDeviceRegistryPropertyA(
3140         HDEVINFO  DeviceInfoSet,
3141         PSP_DEVINFO_DATA  DeviceInfoData,
3142         DWORD   Property,
3143         PDWORD  PropertyRegDataType,
3144         PBYTE   PropertyBuffer,
3145         DWORD   PropertyBufferSize,
3146         PDWORD  RequiredSize)
3147 {
3148     BOOL ret;
3149     BOOL bIsStringProperty;
3150     DWORD RegType;
3151     DWORD RequiredSizeA, RequiredSizeW;
3152     DWORD PropertyBufferSizeW = 0;
3153     PBYTE PropertyBufferW = NULL;
3154 
3155     TRACE("%s(%p %p %d %p %p %d %p)\n", __FUNCTION__, DeviceInfoSet, DeviceInfoData,
3156         Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize,
3157         RequiredSize);
3158 
3159     if (PropertyBufferSize != 0)
3160     {
3161         PropertyBufferSizeW = PropertyBufferSize * 2;
3162         PropertyBufferW = HeapAlloc(GetProcessHeap(), 0, PropertyBufferSizeW);
3163         if (!PropertyBufferW)
3164         {
3165             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3166             return FALSE;
3167         }
3168     }
3169 
3170     ret = SetupDiGetDeviceRegistryPropertyW(DeviceInfoSet,
3171                                             DeviceInfoData,
3172                                             Property,
3173                                             &RegType,
3174                                             PropertyBufferW,
3175                                             PropertyBufferSizeW,
3176                                             &RequiredSizeW);
3177 
3178     if (ret || GetLastError() == ERROR_INSUFFICIENT_BUFFER)
3179     {
3180         bIsStringProperty = (RegType == REG_SZ || RegType == REG_MULTI_SZ || RegType == REG_EXPAND_SZ);
3181 
3182         if (bIsStringProperty)
3183            RequiredSizeA = RequiredSizeW / sizeof(WCHAR);
3184         else
3185             RequiredSizeA = RequiredSizeW;
3186         if (RequiredSize)
3187             *RequiredSize = RequiredSizeA;
3188         if (PropertyRegDataType)
3189             *PropertyRegDataType = RegType;
3190     }
3191 
3192     if (!ret)
3193     {
3194         HeapFree(GetProcessHeap(), 0, PropertyBufferW);
3195         return ret;
3196     }
3197 
3198     if (RequiredSizeA <= PropertyBufferSize)
3199     {
3200         if (bIsStringProperty && PropertyBufferSize > 0)
3201         {
3202             if (WideCharToMultiByte(CP_ACP, 0, (LPWSTR)PropertyBufferW, RequiredSizeW / sizeof(WCHAR), (LPSTR)PropertyBuffer, PropertyBufferSize, NULL, NULL) == 0)
3203             {
3204                 /* Last error is already set by WideCharToMultiByte */
3205                 ret = FALSE;
3206             }
3207         }
3208         else
3209             memcpy(PropertyBuffer, PropertyBufferW, RequiredSizeA);
3210     }
3211     else
3212     {
3213         SetLastError(ERROR_INSUFFICIENT_BUFFER);
3214         ret = FALSE;
3215     }
3216 
3217     HeapFree(GetProcessHeap(), 0, PropertyBufferW);
3218     return ret;
3219 }
3220 
3221 /***********************************************************************
3222  *		SetupDiGetDeviceRegistryPropertyW (SETUPAPI.@)
3223  */
3224 BOOL WINAPI SetupDiGetDeviceRegistryPropertyW(
3225         HDEVINFO  DeviceInfoSet,
3226         PSP_DEVINFO_DATA  DeviceInfoData,
3227         DWORD   Property,
3228         PDWORD  PropertyRegDataType,
3229         PBYTE   PropertyBuffer,
3230         DWORD   PropertyBufferSize,
3231         PDWORD  RequiredSize)
3232 {
3233     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
3234     struct DeviceInfo *devInfo;
3235     CONFIGRET cr;
3236     LONG lError = ERROR_SUCCESS;
3237     DWORD size;
3238 
3239     TRACE("%s(%p %p %d %p %p %d %p)\n", __FUNCTION__, DeviceInfoSet, DeviceInfoData,
3240         Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize,
3241         RequiredSize);
3242 
3243     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
3244     {
3245         SetLastError(ERROR_INVALID_HANDLE);
3246         return FALSE;
3247     }
3248     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
3249     {
3250         SetLastError(ERROR_INVALID_HANDLE);
3251         return FALSE;
3252     }
3253     if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
3254             || !DeviceInfoData->Reserved)
3255     {
3256         SetLastError(ERROR_INVALID_PARAMETER);
3257         return FALSE;
3258     }
3259 
3260     if (Property >= SPDRP_MAXIMUM_PROPERTY)
3261     {
3262         SetLastError(ERROR_INVALID_REG_PROPERTY);
3263         return FALSE;
3264     }
3265 
3266     devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
3267 
3268     if (Property < sizeof(PropertyMap) / sizeof(PropertyMap[0])
3269         && PropertyMap[Property].nameW)
3270     {
3271         HKEY hKey;
3272         size = PropertyBufferSize;
3273         hKey = SETUPDI_OpenDevKey(set->HKLM, devInfo, KEY_QUERY_VALUE);
3274         if (hKey == INVALID_HANDLE_VALUE)
3275             return FALSE;
3276         lError = RegQueryValueExW(hKey, PropertyMap[Property].nameW,
3277                  NULL, PropertyRegDataType, PropertyBuffer, &size);
3278         RegCloseKey(hKey);
3279 
3280         if (RequiredSize)
3281             *RequiredSize = size;
3282 
3283         switch (lError)
3284         {
3285             case ERROR_SUCCESS:
3286                 if (PropertyBuffer == NULL && size != 0)
3287                     lError = ERROR_INSUFFICIENT_BUFFER;
3288                 break;
3289             case ERROR_MORE_DATA:
3290                 lError = ERROR_INSUFFICIENT_BUFFER;
3291                 break;
3292             default:
3293                 break;
3294         }
3295     }
3296     else if (Property == SPDRP_PHYSICAL_DEVICE_OBJECT_NAME)
3297     {
3298         size = (strlenW(devInfo->Data) + 1) * sizeof(WCHAR);
3299 
3300         if (PropertyRegDataType)
3301             *PropertyRegDataType = REG_SZ;
3302         if (RequiredSize)
3303             *RequiredSize = size;
3304         if (PropertyBufferSize >= size)
3305         {
3306             strcpyW((LPWSTR)PropertyBuffer, devInfo->Data);
3307         }
3308         else
3309             lError = ERROR_INSUFFICIENT_BUFFER;
3310     }
3311     else
3312     {
3313         size = PropertyBufferSize;
3314 
3315         cr = CM_Get_DevNode_Registry_Property_ExW(devInfo->dnDevInst,
3316                                                   Property + (CM_DRP_DEVICEDESC - SPDRP_DEVICEDESC),
3317                                                   PropertyRegDataType,
3318                                                   PropertyBuffer,
3319                                                   &size,
3320                                                   0,
3321                                                   set->hMachine);
3322         if ((cr == CR_SUCCESS) || (cr == CR_BUFFER_SMALL))
3323         {
3324             if (RequiredSize)
3325                 *RequiredSize = size;
3326         }
3327 
3328         if (cr != CR_SUCCESS)
3329         {
3330             switch (cr)
3331             {
3332                 case CR_INVALID_DEVINST:
3333                     lError = ERROR_NO_SUCH_DEVINST;
3334                     break;
3335 
3336                 case CR_INVALID_PROPERTY:
3337                     lError = ERROR_INVALID_REG_PROPERTY;
3338                     break;
3339 
3340                 case CR_BUFFER_SMALL:
3341                     lError = ERROR_INSUFFICIENT_BUFFER;
3342                     break;
3343 
3344                 default :
3345                     lError = ERROR_INVALID_DATA;
3346                     break;
3347             }
3348         }
3349     }
3350 
3351     SetLastError(lError);
3352     return (lError == ERROR_SUCCESS);
3353 }
3354 
3355 /***********************************************************************
3356  *		Internal for SetupDiSetDeviceRegistryPropertyA/W
3357  */
3358 BOOL WINAPI IntSetupDiSetDeviceRegistryPropertyAW(
3359         HDEVINFO DeviceInfoSet,
3360         PSP_DEVINFO_DATA DeviceInfoData,
3361         DWORD Property,
3362         const BYTE *PropertyBuffer,
3363         DWORD PropertyBufferSize,
3364         BOOL isAnsi)
3365 {
3366     BOOL ret = FALSE;
3367     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
3368     struct DeviceInfo *deviceInfo;
3369 
3370     TRACE("%s(%p %p %d %p %d)\n", __FUNCTION__, DeviceInfoSet, DeviceInfoData, Property,
3371         PropertyBuffer, PropertyBufferSize);
3372 
3373     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
3374     {
3375         SetLastError(ERROR_INVALID_HANDLE);
3376         return FALSE;
3377     }
3378     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
3379     {
3380         SetLastError(ERROR_INVALID_HANDLE);
3381         return FALSE;
3382     }
3383     if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
3384             || !DeviceInfoData->Reserved)
3385     {
3386         SetLastError(ERROR_INVALID_PARAMETER);
3387         return FALSE;
3388     }
3389 
3390     deviceInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
3391 
3392     if (Property < sizeof(PropertyMap) / sizeof(PropertyMap[0])
3393         && PropertyMap[Property].nameW
3394         && PropertyMap[Property].nameA)
3395     {
3396         HKEY hKey;
3397         LONG l;
3398         hKey = SETUPDI_OpenDevKey(set->HKLM, deviceInfo, KEY_SET_VALUE);
3399         if (hKey == INVALID_HANDLE_VALUE)
3400             return FALSE;
3401         /* Write new data */
3402         if (isAnsi)
3403         {
3404             l = RegSetValueExA(
3405                 hKey, PropertyMap[Property].nameA, 0,
3406                     PropertyMap[Property].regType, PropertyBuffer,
3407                     PropertyBufferSize);
3408         }
3409         else
3410         {
3411             l = RegSetValueExW(
3412                 hKey, PropertyMap[Property].nameW, 0,
3413                     PropertyMap[Property].regType, PropertyBuffer,
3414                     PropertyBufferSize);
3415         }
3416         if (!l)
3417             ret = TRUE;
3418         else
3419             SetLastError(l);
3420         RegCloseKey(hKey);
3421     }
3422     else
3423     {
3424         ERR("Property 0x%lx not implemented\n", Property);
3425         SetLastError(ERROR_NOT_SUPPORTED);
3426     }
3427 
3428     TRACE("Returning %d\n", ret);
3429     return ret;
3430 }
3431 /***********************************************************************
3432  *		SetupDiSetDeviceRegistryPropertyA (SETUPAPI.@)
3433  */
3434 BOOL WINAPI SetupDiSetDeviceRegistryPropertyA(
3435         HDEVINFO DeviceInfoSet,
3436         PSP_DEVINFO_DATA DeviceInfoData,
3437         DWORD Property,
3438         const BYTE *PropertyBuffer,
3439         DWORD PropertyBufferSize)
3440 {
3441     return IntSetupDiSetDeviceRegistryPropertyAW(DeviceInfoSet,
3442                                                  DeviceInfoData,
3443                                                  Property,
3444                                                  PropertyBuffer,
3445                                                  PropertyBufferSize,
3446                                                  TRUE);
3447 }
3448 
3449 /***********************************************************************
3450  *		SetupDiSetDeviceRegistryPropertyW (SETUPAPI.@)
3451  */
3452 BOOL WINAPI SetupDiSetDeviceRegistryPropertyW(
3453         HDEVINFO DeviceInfoSet,
3454         PSP_DEVINFO_DATA DeviceInfoData,
3455         DWORD Property,
3456         const BYTE *PropertyBuffer,
3457         DWORD PropertyBufferSize)
3458 {
3459     return IntSetupDiSetDeviceRegistryPropertyAW(DeviceInfoSet,
3460                                                  DeviceInfoData,
3461                                                  Property,
3462                                                  PropertyBuffer,
3463                                                  PropertyBufferSize,
3464                                                  FALSE);
3465 }
3466 
3467 /***********************************************************************
3468  *		SetupDiInstallClassA (SETUPAPI.@)
3469  */
3470 BOOL WINAPI SetupDiInstallClassA(
3471         HWND hwndParent,
3472         PCSTR InfFileName,
3473         DWORD Flags,
3474         HSPFILEQ FileQueue)
3475 {
3476     return SetupDiInstallClassExA(hwndParent, InfFileName, Flags, FileQueue, NULL, NULL, NULL);
3477 }
3478 
3479 /***********************************************************************
3480  *		SetupDiInstallClassExA (SETUPAPI.@)
3481  */
3482 BOOL WINAPI
3483 SetupDiInstallClassExA(
3484     IN HWND hwndParent OPTIONAL,
3485     IN PCSTR InfFileName OPTIONAL,
3486     IN DWORD Flags,
3487     IN HSPFILEQ FileQueue OPTIONAL,
3488     IN CONST GUID *InterfaceClassGuid OPTIONAL,
3489     IN PVOID Reserved1,
3490     IN PVOID Reserved2)
3491 {
3492     PWSTR InfFileNameW = NULL;
3493     BOOL Result;
3494 
3495     if (!InfFileName)
3496     {
3497         SetLastError(ERROR_INVALID_PARAMETER);
3498         return FALSE;
3499     }
3500     else
3501     {
3502         InfFileNameW = pSetupMultiByteToUnicode(InfFileName, CP_ACP);
3503         if (InfFileNameW == NULL)
3504         {
3505             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3506             return FALSE;
3507         }
3508     }
3509 
3510     Result = SetupDiInstallClassExW(hwndParent, InfFileNameW, Flags,
3511         FileQueue, InterfaceClassGuid, Reserved1, Reserved2);
3512 
3513     MyFree(InfFileNameW);
3514 
3515     return Result;
3516 }
3517 
3518 HKEY SETUP_CreateClassKey(HINF hInf)
3519 {
3520     WCHAR FullBuffer[MAX_PATH];
3521     WCHAR Buffer[MAX_PATH];
3522     DWORD RequiredSize;
3523     HKEY hClassKey;
3524     DWORD Disposition;
3525 
3526     /* Obtain the Class GUID for this class */
3527     if (!SetupGetLineTextW(NULL,
3528                            hInf,
3529                            Version,
3530                            REGSTR_VAL_CLASSGUID,
3531                            Buffer,
3532                            sizeof(Buffer) / sizeof(WCHAR),
3533                            &RequiredSize))
3534     {
3535         return INVALID_HANDLE_VALUE;
3536     }
3537 
3538     /* Build the corresponding registry key name */
3539     lstrcpyW(FullBuffer, REGSTR_PATH_CLASS_NT);
3540     lstrcatW(FullBuffer, BackSlash);
3541     lstrcatW(FullBuffer, Buffer);
3542 
3543     /* Obtain the Class name for this class */
3544     if (!SetupGetLineTextW(NULL,
3545                            hInf,
3546                            Version,
3547                            REGSTR_VAL_CLASS,
3548                            Buffer,
3549                            sizeof(Buffer) / sizeof(WCHAR),
3550                            &RequiredSize))
3551     {
3552         return INVALID_HANDLE_VALUE;
3553     }
3554 
3555     /* Try to open or create the registry key */
3556     TRACE("Opening class key %s\n", debugstr_w(FullBuffer));
3557 #if 0 // I keep this for reference...
3558     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
3559                       FullBuffer,
3560                       0,
3561                       KEY_SET_VALUE,
3562                       &hClassKey))
3563     {
3564         /* Use RegCreateKeyExW */
3565     }
3566 #endif
3567     if (RegCreateKeyExW(HKEY_LOCAL_MACHINE,
3568                         FullBuffer,
3569                         0,
3570                         NULL,
3571                         REG_OPTION_NON_VOLATILE,
3572                         KEY_SET_VALUE,
3573                         NULL,
3574                         &hClassKey,
3575                         &Disposition))
3576     {
3577         ERR("RegCreateKeyExW(%s) failed\n", debugstr_w(FullBuffer));
3578         return INVALID_HANDLE_VALUE;
3579     }
3580     if (Disposition == REG_CREATED_NEW_KEY)
3581         TRACE("The class key %s was successfully created\n", debugstr_w(FullBuffer));
3582     else
3583         TRACE("The class key %s was successfully opened\n", debugstr_w(FullBuffer));
3584 
3585     TRACE( "setting value %s to %s\n", debugstr_w(REGSTR_VAL_CLASS), debugstr_w(Buffer) );
3586     if (RegSetValueExW(hClassKey,
3587                        REGSTR_VAL_CLASS,
3588                        0,
3589                        REG_SZ,
3590                        (LPBYTE)Buffer,
3591                        RequiredSize * sizeof(WCHAR)))
3592     {
3593         RegCloseKey(hClassKey);
3594         RegDeleteKeyW(HKEY_LOCAL_MACHINE,
3595                       FullBuffer);
3596         return INVALID_HANDLE_VALUE;
3597     }
3598 
3599     return hClassKey;
3600 }
3601 
3602 /***********************************************************************
3603  *		SetupDiInstallClassW (SETUPAPI.@)
3604  */
3605 BOOL WINAPI SetupDiInstallClassW(
3606         HWND hwndParent,
3607         PCWSTR InfFileName,
3608         DWORD Flags,
3609         HSPFILEQ FileQueue)
3610 {
3611     return SetupDiInstallClassExW(hwndParent, InfFileName, Flags, FileQueue, NULL, NULL, NULL);
3612 }
3613 
3614 
3615 /***********************************************************************
3616  *		SetupDiOpenClassRegKey  (SETUPAPI.@)
3617  */
3618 HKEY WINAPI SetupDiOpenClassRegKey(
3619         const GUID* ClassGuid,
3620         REGSAM samDesired)
3621 {
3622     return SetupDiOpenClassRegKeyExW(ClassGuid, samDesired,
3623                                      DIOCR_INSTALLER, NULL, NULL);
3624 }
3625 
3626 
3627 /***********************************************************************
3628  *		SetupDiOpenClassRegKeyExA  (SETUPAPI.@)
3629  */
3630 HKEY WINAPI SetupDiOpenClassRegKeyExA(
3631         const GUID* ClassGuid,
3632         REGSAM samDesired,
3633         DWORD Flags,
3634         PCSTR MachineName,
3635         PVOID Reserved)
3636 {
3637     PWSTR MachineNameW = NULL;
3638     HKEY hKey;
3639 
3640     TRACE("%s(%s 0x%lx 0x%lx %s %p)\n", __FUNCTION__, debugstr_guid(ClassGuid), samDesired,
3641         Flags, debugstr_a(MachineName), Reserved);
3642 
3643     if (MachineName)
3644     {
3645         MachineNameW = pSetupMultiByteToUnicode(MachineName, CP_ACP);
3646         if (MachineNameW == NULL)
3647             return INVALID_HANDLE_VALUE;
3648     }
3649 
3650     hKey = SetupDiOpenClassRegKeyExW(ClassGuid, samDesired,
3651                                      Flags, MachineNameW, Reserved);
3652 
3653     MyFree(MachineNameW);
3654 
3655     return hKey;
3656 }
3657 
3658 
3659 /***********************************************************************
3660  *		SetupDiOpenClassRegKeyExW  (SETUPAPI.@)
3661  */
3662 HKEY WINAPI SetupDiOpenClassRegKeyExW(
3663         const GUID* ClassGuid,
3664         REGSAM samDesired,
3665         DWORD Flags,
3666         PCWSTR MachineName,
3667         PVOID Reserved)
3668 {
3669     HKEY HKLM;
3670     HKEY hClassesKey;
3671     HKEY key;
3672     LPCWSTR lpKeyName;
3673     LONG l;
3674 
3675     TRACE("%s(%s 0x%lx 0x%lx %s %p)\n", __FUNCTION__, debugstr_guid(ClassGuid), samDesired,
3676         Flags, debugstr_w(MachineName), Reserved);
3677 
3678     if (MachineName != NULL)
3679     {
3680         l = RegConnectRegistryW(MachineName, HKEY_LOCAL_MACHINE, &HKLM);
3681         if (l != ERROR_SUCCESS)
3682         {
3683             SetLastError(l);
3684             return INVALID_HANDLE_VALUE;
3685         }
3686     }
3687     else
3688         HKLM = HKEY_LOCAL_MACHINE;
3689 
3690     if (Flags == DIOCR_INSTALLER)
3691     {
3692         lpKeyName = REGSTR_PATH_CLASS_NT;
3693     }
3694     else if (Flags == DIOCR_INTERFACE)
3695     {
3696         lpKeyName = REGSTR_PATH_DEVICE_CLASSES;
3697     }
3698     else
3699     {
3700         ERR("Invalid Flags parameter!\n");
3701         SetLastError(ERROR_INVALID_FLAGS);
3702         if (MachineName != NULL) RegCloseKey(HKLM);
3703         return INVALID_HANDLE_VALUE;
3704     }
3705 
3706     if (!ClassGuid)
3707     {
3708         if ((l = RegOpenKeyExW(HKLM,
3709                                lpKeyName,
3710                                0,
3711                                samDesired,
3712                                &hClassesKey)))
3713         {
3714             SetLastError(ERROR_INVALID_CLASS);
3715             hClassesKey = INVALID_HANDLE_VALUE;
3716         }
3717         if (MachineName != NULL)
3718             RegCloseKey(HKLM);
3719         key = hClassesKey;
3720     }
3721     else
3722     {
3723         WCHAR bracedGuidString[39];
3724 
3725         SETUPDI_GuidToString(ClassGuid, bracedGuidString);
3726 
3727         if (!(l = RegOpenKeyExW(HKLM,
3728                                 lpKeyName,
3729                                 0,
3730                                 samDesired,
3731                                 &hClassesKey)))
3732         {
3733             if (MachineName != NULL)
3734                 RegCloseKey(HKLM);
3735 
3736             if ((l = RegOpenKeyExW(hClassesKey,
3737                                    bracedGuidString,
3738                                    0,
3739                                    samDesired,
3740                                    &key)))
3741             {
3742                 SetLastError(l);
3743                 key = INVALID_HANDLE_VALUE;
3744             }
3745             RegCloseKey(hClassesKey);
3746         }
3747         else
3748         {
3749             if (MachineName != NULL) RegCloseKey(HKLM);
3750             SetLastError(l);
3751             key = INVALID_HANDLE_VALUE;
3752         }
3753     }
3754 
3755     return key;
3756 }
3757 
3758 /***********************************************************************
3759  *		SetupDiOpenDeviceInterfaceW (SETUPAPI.@)
3760  */
3761 BOOL WINAPI SetupDiOpenDeviceInterfaceW(
3762         HDEVINFO DeviceInfoSet,
3763         PCWSTR DevicePath,
3764         DWORD OpenFlags,
3765         PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
3766 {
3767     struct DeviceInfoSet * list;
3768     PCWSTR pEnd;
3769     DWORD dwLength, dwError, dwIndex, dwKeyName, dwSubIndex;
3770     CLSID ClassId;
3771     WCHAR Buffer[MAX_PATH + 1];
3772     WCHAR SymBuffer[MAX_PATH + 1];
3773     WCHAR InstancePath[MAX_PATH + 1];
3774     HKEY hKey, hDevKey, hSymKey;
3775     struct DeviceInfo * deviceInfo;
3776     struct DeviceInterface *deviceInterface;
3777     BOOL Ret;
3778     PLIST_ENTRY ItemList;
3779     PLIST_ENTRY InterfaceListEntry;
3780 
3781     TRACE("%s(%p %s %08x %p)\n", __FUNCTION__,
3782         DeviceInfoSet, debugstr_w(DevicePath), OpenFlags, DeviceInterfaceData);
3783 
3784 
3785     if (DeviceInterfaceData && DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA))
3786     {
3787         SetLastError(ERROR_INVALID_PARAMETER);
3788         return FALSE;
3789     }
3790 
3791     if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
3792     {
3793         SetLastError(ERROR_INVALID_HANDLE);
3794         return FALSE;
3795     }
3796 
3797     list = (struct DeviceInfoSet * )DeviceInfoSet;
3798 
3799     dwLength = wcslen(DevicePath);
3800     if (dwLength < 39)
3801     {
3802         /* path must be at least a guid length + L'\0' */
3803         SetLastError(ERROR_BAD_PATHNAME);
3804         return FALSE;
3805     }
3806 
3807     if (DevicePath[0] != L'\\' ||
3808         DevicePath[1] != L'\\' ||
3809         (DevicePath[2] != L'?' && DevicePath[2] != L'.') ||
3810         DevicePath[3] != L'\\')
3811     {
3812         /* invalid formatted path */
3813         SetLastError(ERROR_BAD_PATHNAME);
3814         return FALSE;
3815     }
3816 
3817     /* check for reference strings */
3818     pEnd = wcschr(&DevicePath[4], L'\\');
3819     if (!pEnd)
3820     {
3821         /* no reference string */
3822         pEnd = DevicePath + dwLength;
3823     }
3824 
3825     /* copy guid */
3826     wcscpy(Buffer, pEnd - 37);
3827     Buffer[36] = L'\0';
3828 
3829     dwError = UuidFromStringW(Buffer, &ClassId);
3830     if (dwError != NOERROR)
3831     {
3832         /* invalid formatted path */
3833         SetLastError(ERROR_BAD_PATHNAME);
3834         return FALSE;
3835     }
3836 
3837     hKey = SetupDiOpenClassRegKeyExW(&ClassId, KEY_READ, DIOCR_INTERFACE, list->MachineName, NULL);
3838 
3839     if (hKey == INVALID_HANDLE_VALUE)
3840     {
3841         /* invalid device class */
3842         return FALSE;
3843     }
3844 
3845     ItemList = list->ListHead.Flink;
3846     while (ItemList != &list->ListHead)
3847     {
3848         deviceInfo = CONTAINING_RECORD(ItemList, struct DeviceInfo, ListEntry);
3849         InterfaceListEntry = deviceInfo->InterfaceListHead.Flink;
3850         while (InterfaceListEntry != &deviceInfo->InterfaceListHead)
3851         {
3852             deviceInterface = CONTAINING_RECORD(InterfaceListEntry, struct DeviceInterface, ListEntry);
3853             if (!IsEqualIID(&deviceInterface->InterfaceClassGuid, &ClassId))
3854             {
3855                 InterfaceListEntry = InterfaceListEntry->Flink;
3856                 continue;
3857             }
3858 
3859             if (!wcsicmp(deviceInterface->SymbolicLink, DevicePath))
3860             {
3861                 if (DeviceInterfaceData)
3862                 {
3863                     DeviceInterfaceData->Reserved = (ULONG_PTR)deviceInterface;
3864                     DeviceInterfaceData->Flags = deviceInterface->Flags;
3865                     CopyMemory(&DeviceInterfaceData->InterfaceClassGuid, &ClassId, sizeof(GUID));
3866                 }
3867 
3868                 return TRUE;
3869             }
3870 
3871         }
3872     }
3873 
3874 
3875     dwIndex = 0;
3876     do
3877     {
3878         Buffer[0] = 0;
3879         dwKeyName = sizeof(Buffer) / sizeof(WCHAR);
3880         dwError = RegEnumKeyExW(hKey, dwIndex, Buffer, &dwKeyName, NULL, NULL, NULL, NULL);
3881 
3882         if (dwError != ERROR_SUCCESS)
3883             break;
3884 
3885         if (RegOpenKeyExW(hKey, Buffer, 0, KEY_READ, &hDevKey) != ERROR_SUCCESS)
3886             break;
3887 
3888         dwSubIndex = 0;
3889         InstancePath[0] = 0;
3890         dwKeyName = sizeof(InstancePath);
3891 
3892         dwError = RegQueryValueExW(hDevKey, L"DeviceInstance", NULL, NULL, (LPBYTE)InstancePath, &dwKeyName);
3893 
3894         while(TRUE)
3895         {
3896             Buffer[0] = 0;
3897             dwKeyName = sizeof(Buffer) / sizeof(WCHAR);
3898             dwError = RegEnumKeyExW(hDevKey, dwSubIndex, Buffer, &dwKeyName, NULL, NULL, NULL, NULL);
3899 
3900             if (dwError != ERROR_SUCCESS)
3901                 break;
3902 
3903             dwError = RegOpenKeyExW(hDevKey, Buffer, 0, KEY_READ, &hSymKey);
3904             if (dwError != ERROR_SUCCESS)
3905                 break;
3906 
3907             /* query for symbolic link */
3908             dwKeyName = sizeof(SymBuffer);
3909             SymBuffer[0] = L'\0';
3910             dwError = RegQueryValueExW(hSymKey, L"SymbolicLink", NULL, NULL, (LPBYTE)SymBuffer, &dwKeyName);
3911 
3912             if (dwError != ERROR_SUCCESS)
3913             {
3914                 RegCloseKey(hSymKey);
3915                 break;
3916             }
3917 
3918             if (!wcsicmp(SymBuffer, DevicePath))
3919             {
3920                 Ret = CreateDeviceInfo(list, InstancePath, &ClassId, &deviceInfo);
3921                 RegCloseKey(hSymKey);
3922                 RegCloseKey(hDevKey);
3923                 RegCloseKey(hKey);
3924 
3925                 if (Ret)
3926                 {
3927                     deviceInterface = HeapAlloc(GetProcessHeap(), 0, sizeof(struct DeviceInterface) + (wcslen(SymBuffer) + 1) * sizeof(WCHAR));
3928                     if (deviceInterface)
3929                     {
3930 
3931                         CopyMemory(&deviceInterface->InterfaceClassGuid, &ClassId, sizeof(GUID));
3932                         deviceInterface->DeviceInfo = deviceInfo;
3933                         deviceInterface->Flags = SPINT_ACTIVE; //FIXME
3934 
3935                         wcscpy(deviceInterface->SymbolicLink, SymBuffer);
3936 
3937                         InsertTailList(&deviceInfo->InterfaceListHead, &deviceInterface->ListEntry);
3938                         InsertTailList(&list->ListHead, &deviceInfo->ListEntry);
3939 
3940 
3941                         if (DeviceInterfaceData)
3942                         {
3943                             DeviceInterfaceData->Reserved = (ULONG_PTR)deviceInterface;
3944                             DeviceInterfaceData->Flags = deviceInterface->Flags;
3945                             CopyMemory(&DeviceInterfaceData->InterfaceClassGuid, &ClassId, sizeof(GUID));
3946                         }
3947                         else
3948                         {
3949                             Ret = FALSE;
3950                             SetLastError(ERROR_INVALID_USER_BUFFER);
3951                         }
3952                     }
3953                 }
3954                 else
3955                 {
3956                     HeapFree(GetProcessHeap(), 0, deviceInfo);
3957                     Ret = FALSE;
3958                 }
3959                 return Ret;
3960         }
3961         RegCloseKey(hSymKey);
3962         dwSubIndex++;
3963     }
3964 
3965     RegCloseKey(hDevKey);
3966     dwIndex++;
3967     } while(TRUE);
3968 
3969     RegCloseKey(hKey);
3970     return FALSE;
3971 }
3972 
3973 /***********************************************************************
3974  *		SetupDiOpenDeviceInterfaceA (SETUPAPI.@)
3975  */
3976 BOOL WINAPI SetupDiOpenDeviceInterfaceA(
3977         HDEVINFO DeviceInfoSet,
3978         PCSTR DevicePath,
3979         DWORD OpenFlags,
3980         PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
3981 {
3982     LPWSTR DevicePathW = NULL;
3983     BOOL bResult;
3984 
3985     TRACE("%s(%p %s %08lx %p)\n", __FUNCTION__, DeviceInfoSet, debugstr_a(DevicePath), OpenFlags, DeviceInterfaceData);
3986 
3987     DevicePathW = pSetupMultiByteToUnicode(DevicePath, CP_ACP);
3988     if (DevicePathW == NULL)
3989         return FALSE;
3990 
3991     bResult = SetupDiOpenDeviceInterfaceW(DeviceInfoSet,
3992         DevicePathW, OpenFlags, DeviceInterfaceData);
3993 
3994     MyFree(DevicePathW);
3995 
3996     return bResult;
3997 }
3998 
3999 /***********************************************************************
4000  *		SetupDiSetClassInstallParamsA (SETUPAPI.@)
4001  */
4002 BOOL WINAPI SetupDiSetClassInstallParamsA(
4003         HDEVINFO  DeviceInfoSet,
4004         PSP_DEVINFO_DATA DeviceInfoData,
4005         PSP_CLASSINSTALL_HEADER ClassInstallParams,
4006         DWORD ClassInstallParamsSize)
4007 {
4008     FIXME("%p %p %x %u\n",DeviceInfoSet, DeviceInfoData,
4009           ClassInstallParams->InstallFunction, ClassInstallParamsSize);
4010     return FALSE;
4011 }
4012 
4013 static BOOL WINAPI
4014 IntSetupDiRegisterDeviceInfo(
4015         IN HDEVINFO DeviceInfoSet,
4016         IN OUT PSP_DEVINFO_DATA DeviceInfoData)
4017 {
4018     return SetupDiRegisterDeviceInfo(DeviceInfoSet, DeviceInfoData, 0, NULL, NULL, NULL);
4019 }
4020 
4021 /***********************************************************************
4022  *		SetupDiCallClassInstaller (SETUPAPI.@)
4023  */
4024 BOOL WINAPI SetupDiCallClassInstaller(
4025         DI_FUNCTION InstallFunction,
4026         HDEVINFO DeviceInfoSet,
4027         PSP_DEVINFO_DATA DeviceInfoData)
4028 {
4029     BOOL ret = FALSE;
4030 
4031     TRACE("%s(%u %p %p)\n", __FUNCTION__, InstallFunction, DeviceInfoSet, DeviceInfoData);
4032 
4033     if (!DeviceInfoSet)
4034         SetLastError(ERROR_INVALID_PARAMETER);
4035     else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
4036         SetLastError(ERROR_INVALID_HANDLE);
4037     else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
4038         SetLastError(ERROR_INVALID_HANDLE);
4039     else if (((struct DeviceInfoSet *)DeviceInfoSet)->HKLM != HKEY_LOCAL_MACHINE)
4040         SetLastError(ERROR_INVALID_HANDLE);
4041     else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
4042         SetLastError(ERROR_INVALID_USER_BUFFER);
4043     else
4044     {
4045         SP_DEVINSTALL_PARAMS_W InstallParams;
4046 #define CLASS_COINSTALLER  0x1
4047 #define DEVICE_COINSTALLER 0x2
4048 #define CLASS_INSTALLER    0x4
4049         UCHAR CanHandle = 0;
4050         DEFAULT_CLASS_INSTALL_PROC DefaultHandler = NULL;
4051 
4052         switch (InstallFunction)
4053         {
4054             case DIF_ADDPROPERTYPAGE_ADVANCED:
4055                 CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
4056                 break;
4057             case DIF_ADDREMOTEPROPERTYPAGE_ADVANCED:
4058                 CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
4059                 break;
4060             case DIF_ALLOW_INSTALL:
4061                 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4062                 break;
4063             case DIF_DETECT:
4064                 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4065                 break;
4066             case DIF_DESTROYPRIVATEDATA:
4067                 CanHandle = CLASS_INSTALLER;
4068                 break;
4069             case DIF_INSTALLDEVICE:
4070                 CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
4071                 DefaultHandler = SetupDiInstallDevice;
4072                 break;
4073             case DIF_INSTALLDEVICEFILES:
4074                 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4075                 DefaultHandler = SetupDiInstallDriverFiles;
4076                 break;
4077             case DIF_INSTALLINTERFACES:
4078                 CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
4079                 DefaultHandler = SetupDiInstallDeviceInterfaces;
4080                 break;
4081             case DIF_NEWDEVICEWIZARD_FINISHINSTALL:
4082                 CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
4083                 break;
4084             case DIF_NEWDEVICEWIZARD_POSTANALYZE:
4085                 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4086                 break;
4087             case DIF_NEWDEVICEWIZARD_PREANALYZE:
4088                 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4089                 break;
4090             case DIF_NEWDEVICEWIZARD_PRESELECT:
4091                 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4092                 break;
4093             case DIF_NEWDEVICEWIZARD_SELECT:
4094                 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4095                 break;
4096             case DIF_POWERMESSAGEWAKE:
4097                 CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
4098                 break;
4099             case DIF_PROPERTYCHANGE:
4100                 CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
4101                 DefaultHandler = SetupDiChangeState;
4102                 break;
4103             case DIF_REGISTER_COINSTALLERS:
4104                 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4105                 DefaultHandler = SetupDiRegisterCoDeviceInstallers;
4106                 break;
4107             case DIF_REGISTERDEVICE:
4108                 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4109                 DefaultHandler = IntSetupDiRegisterDeviceInfo;
4110                 break;
4111             case DIF_REMOVE:
4112                 CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
4113                 DefaultHandler = SetupDiRemoveDevice;
4114                 break;
4115             case DIF_SELECTBESTCOMPATDRV:
4116                 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4117                 DefaultHandler = SetupDiSelectBestCompatDrv;
4118                 break;
4119             case DIF_SELECTDEVICE:
4120                 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4121                 DefaultHandler = SetupDiSelectDevice;
4122                 break;
4123             case DIF_TROUBLESHOOTER:
4124                 CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
4125                 break;
4126             case DIF_UNREMOVE:
4127                 CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
4128                 DefaultHandler = SetupDiUnremoveDevice;
4129                 break;
4130             default:
4131                 ERR("Install function %u not supported\n", InstallFunction);
4132                 SetLastError(ERROR_NOT_SUPPORTED);
4133         }
4134 
4135         InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
4136         if (!SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams))
4137             /* Don't process this call, as a parameter is invalid */
4138             CanHandle = 0;
4139 
4140         if (CanHandle != 0)
4141         {
4142             LIST_ENTRY ClassCoInstallersListHead;
4143             LIST_ENTRY DeviceCoInstallersListHead;
4144             HMODULE ClassInstallerLibrary = NULL;
4145             CLASS_INSTALL_PROC ClassInstaller = NULL;
4146             COINSTALLER_CONTEXT_DATA Context;
4147             PLIST_ENTRY ListEntry;
4148             HKEY hKey;
4149             DWORD dwRegType, dwLength;
4150             DWORD rc = NO_ERROR;
4151 
4152             InitializeListHead(&ClassCoInstallersListHead);
4153             InitializeListHead(&DeviceCoInstallersListHead);
4154 
4155             if (CanHandle & DEVICE_COINSTALLER)
4156             {
4157                 hKey = SETUPDI_OpenDrvKey(((struct DeviceInfoSet *)DeviceInfoSet)->HKLM, (struct DeviceInfo *)DeviceInfoData->Reserved, KEY_QUERY_VALUE);
4158                 if (hKey != INVALID_HANDLE_VALUE)
4159                 {
4160                     rc = RegQueryValueExW(hKey, REGSTR_VAL_COINSTALLERS_32, NULL, &dwRegType, NULL, &dwLength);
4161                     if (rc == ERROR_SUCCESS && dwRegType == REG_MULTI_SZ)
4162                     {
4163                         LPWSTR KeyBuffer = HeapAlloc(GetProcessHeap(), 0, dwLength);
4164                         if (KeyBuffer != NULL)
4165                         {
4166                             rc = RegQueryValueExW(hKey, REGSTR_VAL_COINSTALLERS_32, NULL, NULL, (LPBYTE)KeyBuffer, &dwLength);
4167                             if (rc == ERROR_SUCCESS)
4168                             {
4169                                 LPWSTR ptr;
4170                                 for (ptr = KeyBuffer; *ptr; ptr += strlenW(ptr) + 1)
4171                                 {
4172                                     /* Add coinstaller to DeviceCoInstallersListHead list */
4173                                     struct CoInstallerElement *coinstaller;
4174                                     TRACE("Got device coinstaller '%s'\n", debugstr_w(ptr));
4175                                     coinstaller = HeapAlloc(GetProcessHeap(), 0, sizeof(struct CoInstallerElement));
4176                                     if (!coinstaller)
4177                                         continue;
4178                                     ZeroMemory(coinstaller, sizeof(struct CoInstallerElement));
4179                                     if (GetFunctionPointer(ptr, &coinstaller->Module, (PVOID*)&coinstaller->Function) == ERROR_SUCCESS)
4180                                         InsertTailList(&DeviceCoInstallersListHead, &coinstaller->ListEntry);
4181                                     else
4182                                         HeapFree(GetProcessHeap(), 0, coinstaller);
4183                                 }
4184                             }
4185                             HeapFree(GetProcessHeap(), 0, KeyBuffer);
4186                         }
4187                     }
4188                     RegCloseKey(hKey);
4189                 }
4190             }
4191             if (CanHandle & CLASS_COINSTALLER)
4192             {
4193                 rc = RegOpenKeyExW(
4194                     HKEY_LOCAL_MACHINE,
4195                     REGSTR_PATH_CODEVICEINSTALLERS,
4196                     0, /* Options */
4197                     KEY_QUERY_VALUE,
4198                     &hKey);
4199                 if (rc == ERROR_SUCCESS)
4200                 {
4201                     WCHAR szGuidString[40];
4202                     if (pSetupStringFromGuid(&DeviceInfoData->ClassGuid, szGuidString, ARRAYSIZE(szGuidString)) == ERROR_SUCCESS)
4203                     {
4204                         rc = RegQueryValueExW(hKey, szGuidString, NULL, &dwRegType, NULL, &dwLength);
4205                         if (rc == ERROR_SUCCESS && dwRegType == REG_MULTI_SZ)
4206                         {
4207                             LPWSTR KeyBuffer = HeapAlloc(GetProcessHeap(), 0, dwLength);
4208                             if (KeyBuffer != NULL)
4209                             {
4210                                 rc = RegQueryValueExW(hKey, szGuidString, NULL, NULL, (LPBYTE)KeyBuffer, &dwLength);
4211                                 if (rc == ERROR_SUCCESS)
4212                                 {
4213                                     LPWSTR ptr;
4214                                     for (ptr = KeyBuffer; *ptr; ptr += strlenW(ptr) + 1)
4215                                     {
4216                                         /* Add coinstaller to ClassCoInstallersListHead list */
4217                                         struct CoInstallerElement *coinstaller;
4218                                         TRACE("Got class coinstaller '%s'\n", debugstr_w(ptr));
4219                                         coinstaller = HeapAlloc(GetProcessHeap(), 0, sizeof(struct CoInstallerElement));
4220                                         if (!coinstaller)
4221                                             continue;
4222                                         ZeroMemory(coinstaller, sizeof(struct CoInstallerElement));
4223                                         if (GetFunctionPointer(ptr, &coinstaller->Module, (PVOID*)&coinstaller->Function) == ERROR_SUCCESS)
4224                                             InsertTailList(&ClassCoInstallersListHead, &coinstaller->ListEntry);
4225                                         else
4226                                             HeapFree(GetProcessHeap(), 0, coinstaller);
4227                                     }
4228                                 }
4229                                 HeapFree(GetProcessHeap(), 0, KeyBuffer);
4230                             }
4231                         }
4232                     }
4233                     RegCloseKey(hKey);
4234                 }
4235             }
4236             if ((CanHandle & CLASS_INSTALLER) && !(InstallParams.FlagsEx & DI_FLAGSEX_CI_FAILED))
4237             {
4238                 hKey = SetupDiOpenClassRegKey(&DeviceInfoData->ClassGuid, KEY_QUERY_VALUE);
4239                 if (hKey != INVALID_HANDLE_VALUE)
4240                 {
4241                     rc = RegQueryValueExW(hKey, REGSTR_VAL_INSTALLER_32, NULL, &dwRegType, NULL, &dwLength);
4242                     if (rc == ERROR_SUCCESS && dwRegType == REG_SZ)
4243                     {
4244                         LPWSTR KeyBuffer = HeapAlloc(GetProcessHeap(), 0, dwLength);
4245                         if (KeyBuffer != NULL)
4246                         {
4247                             rc = RegQueryValueExW(hKey, REGSTR_VAL_INSTALLER_32, NULL, NULL, (LPBYTE)KeyBuffer, &dwLength);
4248                             if (rc == ERROR_SUCCESS)
4249                             {
4250                                 /* Get ClassInstaller function pointer */
4251                                 TRACE("Got class installer '%s'\n", debugstr_w(KeyBuffer));
4252                                 if (GetFunctionPointer(KeyBuffer, &ClassInstallerLibrary, (PVOID*)&ClassInstaller) != ERROR_SUCCESS)
4253                                 {
4254                                     InstallParams.FlagsEx |= DI_FLAGSEX_CI_FAILED;
4255                                     SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
4256                                 }
4257                             }
4258                             HeapFree(GetProcessHeap(), 0, KeyBuffer);
4259                         }
4260                     }
4261                     RegCloseKey(hKey);
4262                 }
4263             }
4264 
4265             /* Call Class co-installers */
4266             Context.PostProcessing = FALSE;
4267             rc = NO_ERROR;
4268             ListEntry = ClassCoInstallersListHead.Flink;
4269             while (rc == NO_ERROR && ListEntry != &ClassCoInstallersListHead)
4270             {
4271                 struct CoInstallerElement *coinstaller;
4272                 coinstaller = CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry);
4273                 rc = (*coinstaller->Function)(InstallFunction, DeviceInfoSet, DeviceInfoData, &Context);
4274                 coinstaller->PrivateData = Context.PrivateData;
4275                 if (rc == ERROR_DI_POSTPROCESSING_REQUIRED)
4276                 {
4277                     coinstaller->DoPostProcessing = TRUE;
4278                     rc = NO_ERROR;
4279                 }
4280                 ListEntry = ListEntry->Flink;
4281             }
4282 
4283             /* Call Device co-installers */
4284             ListEntry = DeviceCoInstallersListHead.Flink;
4285             while (rc == NO_ERROR && ListEntry != &DeviceCoInstallersListHead)
4286             {
4287                 struct CoInstallerElement *coinstaller;
4288                 coinstaller = CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry);
4289                 rc = (*coinstaller->Function)(InstallFunction, DeviceInfoSet, DeviceInfoData, &Context);
4290                 coinstaller->PrivateData = Context.PrivateData;
4291                 if (rc == ERROR_DI_POSTPROCESSING_REQUIRED)
4292                 {
4293                     coinstaller->DoPostProcessing = TRUE;
4294                     rc = NO_ERROR;
4295                 }
4296                 ListEntry = ListEntry->Flink;
4297             }
4298 
4299             /* Call Class installer */
4300             if (ClassInstaller)
4301             {
4302                 rc = (*ClassInstaller)(InstallFunction, DeviceInfoSet, DeviceInfoData);
4303                 FreeFunctionPointer(ClassInstallerLibrary, ClassInstaller);
4304             }
4305             else
4306                 rc = ERROR_DI_DO_DEFAULT;
4307 
4308             /* Call default handler */
4309             if (rc == ERROR_DI_DO_DEFAULT)
4310             {
4311                 if (DefaultHandler && !(InstallParams.Flags & DI_NODI_DEFAULTACTION))
4312                 {
4313                     if ((*DefaultHandler)(DeviceInfoSet, DeviceInfoData))
4314                         rc = NO_ERROR;
4315                     else
4316                         rc = GetLastError();
4317                 }
4318                 else
4319                     rc = NO_ERROR;
4320             }
4321 
4322             /* Call Class co-installers that required postprocessing */
4323             Context.PostProcessing = TRUE;
4324             ListEntry = ClassCoInstallersListHead.Flink;
4325             while (ListEntry != &ClassCoInstallersListHead)
4326             {
4327                 struct CoInstallerElement *coinstaller;
4328                 coinstaller = CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry);
4329                 if (coinstaller->DoPostProcessing)
4330                 {
4331                     Context.InstallResult = rc;
4332                     Context.PrivateData = coinstaller->PrivateData;
4333                     rc = (*coinstaller->Function)(InstallFunction, DeviceInfoSet, DeviceInfoData, &Context);
4334                 }
4335                 FreeFunctionPointer(coinstaller->Module, coinstaller->Function);
4336                 ListEntry = ListEntry->Flink;
4337             }
4338 
4339             /* Call Device co-installers that required postprocessing */
4340             ListEntry = DeviceCoInstallersListHead.Flink;
4341             while (ListEntry != &DeviceCoInstallersListHead)
4342             {
4343                 struct CoInstallerElement *coinstaller;
4344                 coinstaller = CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry);
4345                 if (coinstaller->DoPostProcessing)
4346                 {
4347                     Context.InstallResult = rc;
4348                     Context.PrivateData = coinstaller->PrivateData;
4349                     rc = (*coinstaller->Function)(InstallFunction, DeviceInfoSet, DeviceInfoData, &Context);
4350                 }
4351                 FreeFunctionPointer(coinstaller->Module, coinstaller->Function);
4352                 ListEntry = ListEntry->Flink;
4353             }
4354 
4355             /* Free allocated memory */
4356             while (!IsListEmpty(&ClassCoInstallersListHead))
4357             {
4358                 ListEntry = RemoveHeadList(&ClassCoInstallersListHead);
4359                 HeapFree(GetProcessHeap(), 0, CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry));
4360             }
4361             while (!IsListEmpty(&DeviceCoInstallersListHead))
4362             {
4363                 ListEntry = RemoveHeadList(&DeviceCoInstallersListHead);
4364                 HeapFree(GetProcessHeap(), 0, CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry));
4365             }
4366 
4367             ret = (rc == NO_ERROR);
4368         }
4369     }
4370 
4371     TRACE("Returning %d\n", ret);
4372     return ret;
4373 }
4374 
4375 /***********************************************************************
4376  *		SetupDiGetDeviceInstallParamsA (SETUPAPI.@)
4377  */
4378 BOOL WINAPI SetupDiGetDeviceInstallParamsA(
4379         HDEVINFO DeviceInfoSet,
4380         PSP_DEVINFO_DATA DeviceInfoData,
4381         PSP_DEVINSTALL_PARAMS_A DeviceInstallParams)
4382 {
4383     SP_DEVINSTALL_PARAMS_W deviceInstallParamsW;
4384     BOOL ret = FALSE;
4385 
4386     TRACE("%s(%p %p %p)\n", __FUNCTION__, DeviceInfoSet, DeviceInfoData, DeviceInstallParams);
4387 
4388     if (DeviceInstallParams == NULL)
4389         SetLastError(ERROR_INVALID_PARAMETER);
4390     else if (DeviceInstallParams->cbSize != sizeof(SP_DEVINSTALL_PARAMS_A))
4391         SetLastError(ERROR_INVALID_USER_BUFFER);
4392     else
4393     {
4394         deviceInstallParamsW.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
4395         ret = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &deviceInstallParamsW);
4396 
4397         if (ret)
4398         {
4399             /* Do W->A conversion */
4400             memcpy(
4401                 DeviceInstallParams,
4402                 &deviceInstallParamsW,
4403                 FIELD_OFFSET(SP_DEVINSTALL_PARAMS_W, DriverPath));
4404             if (WideCharToMultiByte(CP_ACP, 0, deviceInstallParamsW.DriverPath, -1,
4405                 DeviceInstallParams->DriverPath, MAX_PATH, NULL, NULL) == 0)
4406             {
4407                 DeviceInstallParams->DriverPath[0] = '\0';
4408                 ret = FALSE;
4409             }
4410         }
4411     }
4412 
4413     TRACE("Returning %d\n", ret);
4414     return ret;
4415 }
4416 
4417 /***********************************************************************
4418  *		SetupDiGetDeviceInfoListClass  (SETUPAPI.@)
4419  */
4420 BOOL WINAPI
4421 SetupDiGetDeviceInfoListClass(
4422         IN HDEVINFO DeviceInfoSet,
4423         OUT LPGUID ClassGuid)
4424 {
4425     struct DeviceInfoSet *list;
4426     BOOL ret = FALSE;
4427 
4428     TRACE("%s(%p %p)\n", __FUNCTION__, DeviceInfoSet, ClassGuid);
4429 
4430     if (!DeviceInfoSet)
4431         SetLastError(ERROR_INVALID_HANDLE);
4432     else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
4433         SetLastError(ERROR_INVALID_HANDLE);
4434     else if (IsEqualIID(&list->ClassGuid, &GUID_NULL))
4435         SetLastError(ERROR_NO_ASSOCIATED_CLASS);
4436     else
4437     {
4438         *ClassGuid = list->ClassGuid;
4439 
4440         ret = TRUE;
4441     }
4442 
4443     TRACE("Returning %d\n", ret);
4444     return ret;
4445 }
4446 
4447 /***********************************************************************
4448  *		SetupDiGetDeviceInstallParamsW (SETUPAPI.@)
4449  */
4450 BOOL WINAPI
4451 SetupDiGetDeviceInstallParamsW(
4452         IN HDEVINFO DeviceInfoSet,
4453         IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
4454         OUT PSP_DEVINSTALL_PARAMS_W DeviceInstallParams)
4455 {
4456     struct DeviceInfoSet *list;
4457     BOOL ret = FALSE;
4458 
4459     TRACE("%s(%p %p %p)\n", __FUNCTION__, DeviceInfoSet, DeviceInfoData, DeviceInstallParams);
4460 
4461     if (!DeviceInfoSet)
4462         SetLastError(ERROR_INVALID_HANDLE);
4463     else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
4464         SetLastError(ERROR_INVALID_HANDLE);
4465     else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
4466         SetLastError(ERROR_INVALID_USER_BUFFER);
4467     else if (!DeviceInstallParams)
4468         SetLastError(ERROR_INVALID_PARAMETER);
4469     else if (DeviceInstallParams->cbSize != sizeof(SP_DEVINSTALL_PARAMS_W))
4470         SetLastError(ERROR_INVALID_USER_BUFFER);
4471     else
4472     {
4473         PSP_DEVINSTALL_PARAMS_W Source;
4474 
4475         if (DeviceInfoData)
4476             Source = &((struct DeviceInfo *)DeviceInfoData->Reserved)->InstallParams;
4477         else
4478             Source = &list->InstallParams;
4479 
4480         ret = TRUE;
4481 
4482         _SEH2_TRY
4483         {
4484             memcpy(DeviceInstallParams, Source, Source->cbSize);
4485         }
4486         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4487         {
4488             SetLastError(RtlNtStatusToDosError(_SEH2_GetExceptionCode()));
4489             ret = FALSE;
4490         }
4491         _SEH2_END;
4492     }
4493 
4494     TRACE("Returning %d\n", ret);
4495     return ret;
4496 }
4497 
4498 static BOOL
4499 CheckDeviceInstallParameters(
4500         IN PSP_DEVINSTALL_PARAMS_W DeviceInstallParams)
4501 {
4502     DWORD SupportedFlags =
4503         DI_NOVCP |                            /* 0x00000008 */
4504         DI_DIDCOMPAT |                        /* 0x00000010 */
4505         DI_DIDCLASS |                         /* 0x00000020 */
4506         DI_NEEDRESTART |                      /* 0x00000080 */
4507         DI_NEEDREBOOT |                       /* 0x00000100 */
4508         DI_RESOURCEPAGE_ADDED |               /* 0x00002000 */
4509         DI_PROPERTIES_CHANGE |                /* 0x00004000 */
4510         DI_ENUMSINGLEINF |                    /* 0x00010000 */
4511         DI_DONOTCALLCONFIGMG |                /* 0x00020000 */
4512         DI_CLASSINSTALLPARAMS |               /* 0x00100000 */
4513         DI_NODI_DEFAULTACTION |               /* 0x00200000 */
4514         DI_QUIETINSTALL |                     /* 0x00800000 */
4515         DI_NOFILECOPY |                       /* 0x01000000 */
4516         DI_DRIVERPAGE_ADDED;                  /* 0x04000000 */
4517     DWORD SupportedFlagsEx =
4518         DI_FLAGSEX_CI_FAILED |                /* 0x00000004 */
4519         DI_FLAGSEX_DIDINFOLIST |              /* 0x00000010 */
4520         DI_FLAGSEX_DIDCOMPATINFO |            /* 0x00000020 */
4521         DI_FLAGSEX_ALLOWEXCLUDEDDRVS |        /* 0x00000800 */
4522         DI_FLAGSEX_NO_DRVREG_MODIFY |         /* 0x00008000 */
4523         DI_FLAGSEX_INSTALLEDDRIVER;           /* 0x04000000 */
4524     BOOL ret = FALSE;
4525 
4526     /* FIXME: add support for more flags */
4527 
4528     /* FIXME: DI_CLASSINSTALLPARAMS flag is not correctly used.
4529      * It should be checked before accessing to other values
4530      * of the SP_DEVINSTALL_PARAMS structure */
4531 
4532     if (DeviceInstallParams->Flags & ~SupportedFlags)
4533     {
4534         FIXME("Unknown Flags: 0x%08lx\n", DeviceInstallParams->Flags & ~SupportedFlags);
4535         SetLastError(ERROR_INVALID_FLAGS);
4536     }
4537     else if (DeviceInstallParams->FlagsEx & ~SupportedFlagsEx)
4538     {
4539         FIXME("Unknown FlagsEx: 0x%08lx\n", DeviceInstallParams->FlagsEx & ~SupportedFlagsEx);
4540         SetLastError(ERROR_INVALID_FLAGS);
4541     }
4542     else if ((DeviceInstallParams->Flags & DI_NOVCP)
4543         && (DeviceInstallParams->FileQueue == NULL || DeviceInstallParams->FileQueue == (HSPFILEQ)INVALID_HANDLE_VALUE))
4544         SetLastError(ERROR_INVALID_USER_BUFFER);
4545     else
4546     {
4547         /* FIXME: check Reserved field */
4548         ret = TRUE;
4549     }
4550 
4551     return ret;
4552 }
4553 
4554 /***********************************************************************
4555  *		SetupDiSetDeviceInstallParamsW (SETUPAPI.@)
4556  */
4557 BOOL WINAPI
4558 SetupDiSetDeviceInstallParamsW(
4559         IN HDEVINFO DeviceInfoSet,
4560         IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
4561         IN PSP_DEVINSTALL_PARAMS_W DeviceInstallParams)
4562 {
4563     struct DeviceInfoSet *list;
4564     BOOL ret = FALSE;
4565 
4566     TRACE("%s(%p %p %p)\n", __FUNCTION__, DeviceInfoSet, DeviceInfoData, DeviceInstallParams);
4567 
4568     if (!DeviceInfoSet)
4569         SetLastError(ERROR_INVALID_HANDLE);
4570     else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
4571         SetLastError(ERROR_INVALID_HANDLE);
4572     else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
4573         SetLastError(ERROR_INVALID_USER_BUFFER);
4574     else if (!DeviceInstallParams)
4575         SetLastError(ERROR_INVALID_PARAMETER);
4576     else if (DeviceInstallParams->cbSize != sizeof(SP_DEVINSTALL_PARAMS_W))
4577         SetLastError(ERROR_INVALID_USER_BUFFER);
4578     else if (CheckDeviceInstallParameters(DeviceInstallParams))
4579     {
4580         PSP_DEVINSTALL_PARAMS_W Destination;
4581 
4582         if (DeviceInfoData)
4583             Destination = &((struct DeviceInfo *)DeviceInfoData->Reserved)->InstallParams;
4584         else
4585             Destination = &list->InstallParams;
4586         memcpy(Destination, DeviceInstallParams, DeviceInstallParams->cbSize);
4587         ret = TRUE;
4588     }
4589 
4590     TRACE("Returning %d\n", ret);
4591     return ret;
4592 }
4593 
4594 /***********************************************************************
4595  *		SetupDiSetDeviceInstallParamsW (SETUPAPI.@)
4596  */
4597 BOOL WINAPI
4598 SetupDiSetDeviceInstallParamsA(
4599         HDEVINFO DeviceInfoSet,
4600         PSP_DEVINFO_DATA DeviceInfoData,
4601         PSP_DEVINSTALL_PARAMS_A DeviceInstallParams)
4602 {
4603     SP_DEVINSTALL_PARAMS_W deviceInstallParamsW;
4604     int len = 0;
4605     BOOL ret = FALSE;
4606 
4607     TRACE("%s(%p %p %p)\n", __FUNCTION__, DeviceInfoSet, DeviceInfoData, DeviceInstallParams);
4608 
4609     if (DeviceInstallParams == NULL)
4610         SetLastError(ERROR_INVALID_PARAMETER);
4611     else if (DeviceInstallParams->cbSize < sizeof(SP_DEVINSTALL_PARAMS_A))
4612         SetLastError(ERROR_INVALID_USER_BUFFER);
4613     else
4614     {
4615         memcpy(&deviceInstallParamsW, DeviceInstallParams, FIELD_OFFSET(SP_DEVINSTALL_PARAMS_A, DriverPath));
4616         deviceInstallParamsW.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
4617         len = MultiByteToWideChar(CP_ACP, 0, DeviceInstallParams->DriverPath, -1, NULL, 0);
4618         if (!len)
4619         {
4620             ERR("DrivePath is NULL\n");
4621             ret = FALSE;
4622         }
4623         else
4624         {
4625             MultiByteToWideChar(CP_ACP, 0, DeviceInstallParams->DriverPath, -1, deviceInstallParamsW.DriverPath, len);
4626             ret = SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &deviceInstallParamsW);
4627         }
4628     }
4629 
4630     TRACE("Returning %d\n", ret);
4631     return ret;
4632 }
4633 
4634 static HKEY
4635 OpenHardwareProfileKey(
4636         IN HKEY HKLM,
4637         IN DWORD HwProfile,
4638         IN DWORD samDesired)
4639 {
4640     HKEY hHWProfilesKey = NULL;
4641     HKEY hHWProfileKey = NULL;
4642     HKEY ret = INVALID_HANDLE_VALUE;
4643     LONG rc;
4644 
4645     rc = RegOpenKeyExW(HKLM,
4646                        REGSTR_PATH_HWPROFILES,
4647                        0,
4648                        READ_CONTROL,
4649                        &hHWProfilesKey);
4650     if (rc != ERROR_SUCCESS)
4651     {
4652         SetLastError(rc);
4653         goto cleanup;
4654     }
4655     if (HwProfile == 0)
4656     {
4657         rc = RegOpenKeyExW(hHWProfilesKey,
4658                            REGSTR_KEY_CURRENT,
4659                            0,
4660                            KEY_CREATE_SUB_KEY,
4661                            &hHWProfileKey);
4662     }
4663     else
4664     {
4665         WCHAR subKey[5];
4666         snprintfW(subKey, 4, InstanceKeyFormat, HwProfile);
4667         subKey[4] = '\0';
4668         rc = RegOpenKeyExW(hHWProfilesKey,
4669                            subKey,
4670                            0,
4671                            KEY_CREATE_SUB_KEY,
4672                            &hHWProfileKey);
4673     }
4674     if (rc != ERROR_SUCCESS)
4675     {
4676         SetLastError(rc);
4677         goto cleanup;
4678     }
4679     ret = hHWProfileKey;
4680 
4681 cleanup:
4682     if (hHWProfilesKey != NULL)
4683         RegCloseKey(hHWProfilesKey);
4684     if (hHWProfileKey != NULL && hHWProfileKey != ret)
4685         RegCloseKey(hHWProfileKey);
4686     return ret;
4687 }
4688 
4689 static BOOL
4690 IsDeviceInfoInDeviceInfoSet(
4691         struct DeviceInfoSet *deviceInfoSet,
4692         struct DeviceInfo *deviceInfo)
4693 {
4694     PLIST_ENTRY ListEntry;
4695 
4696     ListEntry = deviceInfoSet->ListHead.Flink;
4697     while (ListEntry != &deviceInfoSet->ListHead)
4698     {
4699         if (deviceInfo == CONTAINING_RECORD(ListEntry, struct DeviceInfo, ListEntry))
4700             return TRUE;
4701 
4702         ListEntry = ListEntry->Flink;
4703     }
4704 
4705     return FALSE;
4706 }
4707 
4708 /***********************************************************************
4709  *		SetupDiDeleteDeviceInfo (SETUPAPI.@)
4710  */
4711 BOOL WINAPI
4712 SetupDiDeleteDeviceInfo(
4713         IN HDEVINFO DeviceInfoSet,
4714         IN PSP_DEVINFO_DATA DeviceInfoData)
4715 {
4716     struct DeviceInfoSet *deviceInfoSet;
4717     struct DeviceInfo *deviceInfo = (struct DeviceInfo *)DeviceInfoData;
4718     BOOL ret = FALSE;
4719 
4720     TRACE("%s(%p %p)\n", __FUNCTION__, DeviceInfoSet, DeviceInfoData);
4721 
4722     if (!DeviceInfoSet)
4723         SetLastError(ERROR_INVALID_HANDLE);
4724     else if ((deviceInfoSet = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
4725         SetLastError(ERROR_INVALID_HANDLE);
4726     else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
4727         SetLastError(ERROR_INVALID_USER_BUFFER);
4728     else if (!IsDeviceInfoInDeviceInfoSet(deviceInfoSet, deviceInfo))
4729         SetLastError(ERROR_INVALID_PARAMETER);
4730     else
4731     {
4732         RemoveEntryList(&deviceInfo->ListEntry);
4733         DestroyDeviceInfo(deviceInfo);
4734         ret = TRUE;
4735     }
4736 
4737     return ret;
4738 }
4739 
4740 
4741 /***********************************************************************
4742  *		SetupDiOpenDeviceInfoA (SETUPAPI.@)
4743  */
4744 BOOL WINAPI
4745 SetupDiOpenDeviceInfoA(
4746         IN HDEVINFO DeviceInfoSet,
4747         IN PCSTR DeviceInstanceId,
4748         IN HWND hwndParent OPTIONAL,
4749         IN DWORD OpenFlags,
4750         OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
4751 {
4752     LPWSTR DeviceInstanceIdW = NULL;
4753     BOOL bResult;
4754 
4755     TRACE("%s(%p %s %p %lx %p)\n", __FUNCTION__, DeviceInfoSet, DeviceInstanceId, hwndParent, OpenFlags, DeviceInfoData);
4756 
4757     DeviceInstanceIdW = pSetupMultiByteToUnicode(DeviceInstanceId, CP_ACP);
4758     if (DeviceInstanceIdW == NULL)
4759         return FALSE;
4760 
4761     bResult = SetupDiOpenDeviceInfoW(DeviceInfoSet,
4762         DeviceInstanceIdW, hwndParent, OpenFlags, DeviceInfoData);
4763 
4764     MyFree(DeviceInstanceIdW);
4765 
4766     return bResult;
4767 }
4768 
4769 
4770 /***********************************************************************
4771  *		SetupDiOpenDeviceInfoW (SETUPAPI.@)
4772  */
4773 BOOL WINAPI
4774 SetupDiOpenDeviceInfoW(
4775         IN HDEVINFO DeviceInfoSet,
4776         IN PCWSTR DeviceInstanceId,
4777         IN HWND hwndParent OPTIONAL,
4778         IN DWORD OpenFlags,
4779         OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
4780 {
4781     struct DeviceInfoSet *list;
4782     HKEY hEnumKey, hKey = NULL;
4783     DWORD rc, dwSize;
4784     BOOL ret = FALSE;
4785 
4786     TRACE("%s(%p %s %p %lx %p)\n", __FUNCTION__,
4787         DeviceInfoSet, debugstr_w(DeviceInstanceId),
4788         hwndParent, OpenFlags, DeviceInfoData);
4789 
4790     if (OpenFlags & DIOD_CANCEL_REMOVE)
4791         FIXME("DIOD_CANCEL_REMOVE flag not implemented\n");
4792 
4793     if (!DeviceInfoSet)
4794         SetLastError(ERROR_INVALID_HANDLE);
4795     else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
4796         SetLastError(ERROR_INVALID_HANDLE);
4797     else if (!DeviceInstanceId)
4798         SetLastError(ERROR_INVALID_PARAMETER);
4799     else if (OpenFlags & ~(DIOD_CANCEL_REMOVE | DIOD_INHERIT_CLASSDRVS))
4800     {
4801         TRACE("Unknown flags: 0x%08lx\n", OpenFlags & ~(DIOD_CANCEL_REMOVE | DIOD_INHERIT_CLASSDRVS));
4802         SetLastError(ERROR_INVALID_FLAGS);
4803     }
4804     else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
4805         SetLastError(ERROR_INVALID_USER_BUFFER);
4806     else
4807     {
4808         struct DeviceInfo *deviceInfo = NULL;
4809         /* Search if device already exists in DeviceInfoSet.
4810          *    If yes, return the existing element
4811          *    If no, create a new element using information in registry
4812          */
4813         PLIST_ENTRY ItemList = list->ListHead.Flink;
4814         while (ItemList != &list->ListHead)
4815         {
4816             deviceInfo = CONTAINING_RECORD(ItemList, struct DeviceInfo, ListEntry);
4817             if (!wcscmp(deviceInfo->instanceId, DeviceInstanceId))
4818                 break;
4819             deviceInfo = NULL;
4820             ItemList = ItemList->Flink;
4821         }
4822 
4823         if (deviceInfo)
4824         {
4825             /* good one found */
4826             ret = TRUE;
4827         }
4828         else
4829         {
4830             GUID ClassGUID;
4831             WCHAR szClassGuid[MAX_GUID_STRING_LEN];
4832 
4833             /* Open supposed registry key */
4834             rc = RegOpenKeyExW(
4835                 list->HKLM,
4836                 REGSTR_PATH_SYSTEMENUM,
4837                 0, /* Options */
4838                 READ_CONTROL,
4839                 &hEnumKey);
4840             if (rc != ERROR_SUCCESS)
4841             {
4842                 SetLastError(rc);
4843                 goto cleanup;
4844             }
4845             rc = RegOpenKeyExW(
4846                 hEnumKey,
4847                 DeviceInstanceId,
4848                 0, /* Options */
4849                 KEY_QUERY_VALUE,
4850                 &hKey);
4851             RegCloseKey(hEnumKey);
4852             if (rc != ERROR_SUCCESS)
4853             {
4854                 if (rc == ERROR_FILE_NOT_FOUND)
4855                     rc = ERROR_NO_SUCH_DEVINST;
4856                 SetLastError(rc);
4857                 goto cleanup;
4858             }
4859 
4860             ClassGUID = GUID_NULL;
4861             dwSize = MAX_GUID_STRING_LEN * sizeof(WCHAR);
4862 
4863             if (RegQueryValueExW(hKey,
4864                                  REGSTR_VAL_CLASSGUID,
4865                                  NULL,
4866                                  NULL,
4867                                  (LPBYTE)szClassGuid,
4868                                  &dwSize) == ERROR_SUCCESS)
4869             {
4870                 szClassGuid[MAX_GUID_STRING_LEN - 2] = UNICODE_NULL;
4871 
4872                 /* Convert a string to a ClassGuid */
4873                 UuidFromStringW(&szClassGuid[1], &ClassGUID);
4874             }
4875 
4876             if (!CreateDeviceInfo(list, DeviceInstanceId, &ClassGUID, &deviceInfo))
4877                 goto cleanup;
4878 
4879             InsertTailList(&list->ListHead, &deviceInfo->ListEntry);
4880 
4881             ret = TRUE;
4882         }
4883 
4884         if (ret && deviceInfo && DeviceInfoData)
4885         {
4886             memcpy(&DeviceInfoData->ClassGuid, &deviceInfo->ClassGuid, sizeof(GUID));
4887             DeviceInfoData->DevInst = deviceInfo->dnDevInst;
4888             DeviceInfoData->Reserved = (ULONG_PTR)deviceInfo;
4889         }
4890     }
4891 
4892 cleanup:
4893     if (hKey != NULL)
4894         RegCloseKey(hKey);
4895     return ret;
4896 }
4897 
4898 
4899 /***********************************************************************
4900  *		SetupDiGetSelectedDevice (SETUPAPI.@)
4901  */
4902 BOOL WINAPI
4903 SetupDiGetSelectedDevice(
4904         IN HDEVINFO DeviceInfoSet,
4905         OUT PSP_DEVINFO_DATA DeviceInfoData)
4906 {
4907     struct DeviceInfoSet *list;
4908     BOOL ret = FALSE;
4909 
4910     TRACE("%s(%p %p)\n", __FUNCTION__, DeviceInfoSet, DeviceInfoData);
4911 
4912     if (!DeviceInfoSet)
4913         SetLastError(ERROR_INVALID_HANDLE);
4914     else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
4915         SetLastError(ERROR_INVALID_HANDLE);
4916     else if (list->SelectedDevice == NULL)
4917         SetLastError(ERROR_NO_DEVICE_SELECTED);
4918     else if (!DeviceInfoData)
4919         SetLastError(ERROR_INVALID_PARAMETER);
4920     else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
4921         SetLastError(ERROR_INVALID_USER_BUFFER);
4922     else
4923     {
4924         memcpy(&DeviceInfoData->ClassGuid,
4925             &list->SelectedDevice->ClassGuid,
4926             sizeof(GUID));
4927         DeviceInfoData->DevInst = list->SelectedDevice->dnDevInst;
4928         DeviceInfoData->Reserved = (ULONG_PTR)list->SelectedDevice;
4929         ret = TRUE;
4930     }
4931 
4932     TRACE("Returning %d\n", ret);
4933     return ret;
4934 }
4935 
4936 
4937 /***********************************************************************
4938  *		SetupDiSetSelectedDevice (SETUPAPI.@)
4939  */
4940 BOOL WINAPI
4941 SetupDiSetSelectedDevice(
4942         IN HDEVINFO DeviceInfoSet,
4943         IN PSP_DEVINFO_DATA DeviceInfoData)
4944 {
4945     struct DeviceInfoSet *list;
4946     BOOL ret = FALSE;
4947 
4948     TRACE("%s(%p %p)\n", __FUNCTION__, DeviceInfoSet, DeviceInfoData);
4949 
4950     if (!DeviceInfoSet)
4951         SetLastError(ERROR_INVALID_HANDLE);
4952     else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
4953         SetLastError(ERROR_INVALID_HANDLE);
4954     else if (!DeviceInfoData)
4955         SetLastError(ERROR_INVALID_PARAMETER);
4956     else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
4957         SetLastError(ERROR_INVALID_USER_BUFFER);
4958     else if (DeviceInfoData->Reserved == 0)
4959         SetLastError(ERROR_INVALID_USER_BUFFER);
4960     else
4961     {
4962         list->SelectedDevice = (struct DeviceInfo *)DeviceInfoData->Reserved;
4963         ret = TRUE;
4964     }
4965 
4966     TRACE("Returning %d\n", ret);
4967     return ret;
4968 }
4969 
4970 
4971 /* Return the current hardware profile id, or -1 if error */
4972 static DWORD
4973 SETUPAPI_GetCurrentHwProfile(
4974         IN HDEVINFO DeviceInfoSet)
4975 {
4976     HKEY hKey = NULL;
4977     DWORD dwRegType, dwLength;
4978     DWORD hwProfile;
4979     LONG rc;
4980     DWORD ret = (DWORD)-1;
4981 
4982     rc = RegOpenKeyExW(((struct DeviceInfoSet *)DeviceInfoSet)->HKLM,
4983                        REGSTR_PATH_IDCONFIGDB,
4984                        0, /* Options */
4985                        KEY_QUERY_VALUE,
4986                        &hKey);
4987     if (rc != ERROR_SUCCESS)
4988     {
4989         SetLastError(rc);
4990         goto cleanup;
4991     }
4992 
4993     dwLength = sizeof(DWORD);
4994     rc = RegQueryValueExW(hKey,
4995                           REGSTR_VAL_CURRENTCONFIG,
4996                           NULL,
4997                           &dwRegType,
4998                           (LPBYTE)&hwProfile, &dwLength);
4999     if (rc != ERROR_SUCCESS)
5000     {
5001         SetLastError(rc);
5002         goto cleanup;
5003     }
5004     else if (dwRegType != REG_DWORD || dwLength != sizeof(DWORD))
5005     {
5006         SetLastError(ERROR_GEN_FAILURE);
5007         goto cleanup;
5008     }
5009 
5010     ret = hwProfile;
5011 
5012 cleanup:
5013     if (hKey != NULL)
5014         RegCloseKey(hKey);
5015 
5016     return ret;
5017 }
5018 
5019 static BOOL
5020 ResetDevice(
5021         IN HDEVINFO DeviceInfoSet,
5022         IN PSP_DEVINFO_DATA DeviceInfoData)
5023 {
5024 #ifndef __WINESRC__
5025     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
5026     struct DeviceInfo *deviceInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
5027     CONFIGRET cr;
5028 
5029     cr = CM_Enable_DevNode_Ex(deviceInfo->dnDevInst, 0, set->hMachine);
5030     if (cr != CR_SUCCESS)
5031     {
5032         SetLastError(GetErrorCodeFromCrCode(cr));
5033         return FALSE;
5034     }
5035 
5036     return TRUE;
5037 #else
5038     FIXME("Stub: ResetDevice(%p %p)\n", DeviceInfoSet, DeviceInfoData);
5039     return TRUE;
5040 #endif
5041 }
5042 
5043 static BOOL
5044 StopDevice(
5045         IN HDEVINFO DeviceInfoSet,
5046         IN PSP_DEVINFO_DATA DeviceInfoData)
5047 {
5048 #ifndef __WINESRC__
5049     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
5050     struct DeviceInfo *deviceInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
5051     CONFIGRET cr;
5052 
5053     cr = CM_Disable_DevNode_Ex(deviceInfo->dnDevInst, 0, set->hMachine);
5054     if (cr != CR_SUCCESS)
5055     {
5056         SetLastError(GetErrorCodeFromCrCode(cr));
5057         return FALSE;
5058     }
5059 
5060     return TRUE;
5061 #else
5062     FIXME("Stub: StopDevice(%p %p)\n", DeviceInfoSet, DeviceInfoData);
5063     return TRUE;
5064 #endif
5065 }
5066 
5067 /***********************************************************************
5068  *		SetupDiChangeState (SETUPAPI.@)
5069  */
5070 BOOL WINAPI
5071 SetupDiChangeState(
5072         IN HDEVINFO DeviceInfoSet,
5073         IN OUT PSP_DEVINFO_DATA DeviceInfoData)
5074 {
5075     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
5076     struct DeviceInfo *deviceInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
5077     PSP_PROPCHANGE_PARAMS PropChange;
5078     HKEY hRootKey = INVALID_HANDLE_VALUE, hKey = INVALID_HANDLE_VALUE;
5079     LPCWSTR RegistryValueName;
5080     DWORD dwConfigFlags, dwLength, dwRegType;
5081     LONG rc;
5082     BOOL ret = FALSE;
5083 
5084     TRACE("%s(%p %p)\n", __FUNCTION__, DeviceInfoSet, DeviceInfoData);
5085 
5086     if (!DeviceInfoData)
5087         PropChange = ((struct DeviceInfoSet *)DeviceInfoSet)->ClassInstallParams.PropChangeParams;
5088     else
5089         PropChange = ((struct DeviceInfo *)DeviceInfoData->Reserved)->ClassInstallParams.PropChangeParams;
5090     if (!PropChange)
5091     {
5092         SetLastError(ERROR_INVALID_PARAMETER);
5093         goto cleanup;
5094     }
5095 
5096     if (PropChange->Scope == DICS_FLAG_GLOBAL)
5097         RegistryValueName = REGSTR_VAL_CONFIGFLAGS;
5098     else
5099         RegistryValueName = REGSTR_VAL_CSCONFIGFLAGS;
5100 
5101     switch (PropChange->StateChange)
5102     {
5103         case DICS_ENABLE:
5104         case DICS_DISABLE:
5105         {
5106             if (PropChange->Scope == DICS_FLAG_GLOBAL)
5107                 hRootKey = set->HKLM;
5108             else /* PropChange->Scope == DICS_FLAG_CONFIGSPECIFIC */
5109             {
5110                 hRootKey = OpenHardwareProfileKey(set->HKLM, PropChange->HwProfile, KEY_CREATE_SUB_KEY);
5111                 if (hRootKey == INVALID_HANDLE_VALUE)
5112                     goto cleanup;
5113             }
5114 
5115             /* Enable/disable device in registry */
5116             hKey = SETUPDI_OpenDrvKey(hRootKey, deviceInfo, KEY_QUERY_VALUE | KEY_SET_VALUE);
5117             if (hKey == INVALID_HANDLE_VALUE && GetLastError() == ERROR_FILE_NOT_FOUND)
5118                 hKey = SETUPDI_CreateDevKey(hRootKey, deviceInfo, KEY_QUERY_VALUE | KEY_SET_VALUE);
5119             if (hKey == INVALID_HANDLE_VALUE)
5120                 break;
5121             dwLength = sizeof(DWORD);
5122             rc = RegQueryValueExW(
5123                 hKey,
5124                 RegistryValueName,
5125                 NULL,
5126                 &dwRegType,
5127                 (LPBYTE)&dwConfigFlags, &dwLength);
5128             if (rc == ERROR_FILE_NOT_FOUND)
5129                 dwConfigFlags = 0;
5130             else if (rc != ERROR_SUCCESS)
5131             {
5132                 SetLastError(rc);
5133                 goto cleanup;
5134             }
5135             else if (dwRegType != REG_DWORD || dwLength != sizeof(DWORD))
5136             {
5137                 SetLastError(ERROR_GEN_FAILURE);
5138                 goto cleanup;
5139             }
5140             if (PropChange->StateChange == DICS_ENABLE)
5141                 dwConfigFlags &= ~(PropChange->Scope == DICS_FLAG_GLOBAL ? CONFIGFLAG_DISABLED : CSCONFIGFLAG_DISABLED);
5142             else
5143                 dwConfigFlags |= (PropChange->Scope == DICS_FLAG_GLOBAL ? CONFIGFLAG_DISABLED : CSCONFIGFLAG_DISABLED);
5144             rc = RegSetValueExW(
5145                 hKey,
5146                 RegistryValueName,
5147                 0,
5148                 REG_DWORD,
5149                 (LPBYTE)&dwConfigFlags, sizeof(DWORD));
5150             if (rc != ERROR_SUCCESS)
5151             {
5152                 SetLastError(rc);
5153                 goto cleanup;
5154             }
5155 
5156             /* Enable/disable device if needed */
5157             if (PropChange->Scope == DICS_FLAG_GLOBAL
5158                 || PropChange->HwProfile == 0
5159                 || PropChange->HwProfile == SETUPAPI_GetCurrentHwProfile(DeviceInfoSet))
5160             {
5161                 if (PropChange->StateChange == DICS_ENABLE)
5162                     ret = ResetDevice(DeviceInfoSet, DeviceInfoData);
5163                 else
5164                     ret = StopDevice(DeviceInfoSet, DeviceInfoData);
5165             }
5166             else
5167                 ret = TRUE;
5168             break;
5169         }
5170         case DICS_PROPCHANGE:
5171         {
5172             ret = ResetDevice(DeviceInfoSet, DeviceInfoData);
5173             break;
5174         }
5175         default:
5176         {
5177             ERR("Unknown StateChange 0x%lx\n", PropChange->StateChange);
5178             SetLastError(ERROR_NOT_SUPPORTED);
5179         }
5180     }
5181 
5182 cleanup:
5183     if (hRootKey != INVALID_HANDLE_VALUE && hRootKey != set->HKLM)
5184         RegCloseKey(hRootKey);
5185 
5186     if (hKey != INVALID_HANDLE_VALUE)
5187         RegCloseKey(hKey);
5188 
5189     TRACE("Returning %d\n", ret);
5190     return ret;
5191 }
5192 
5193 /***********************************************************************
5194  *		SetupDiSelectDevice (SETUPAPI.@)
5195  */
5196 BOOL WINAPI
5197 SetupDiSelectDevice(
5198         IN HDEVINFO DeviceInfoSet,
5199         IN OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
5200 {
5201     FIXME("%p %p\n", DeviceInfoSet, DeviceInfoData);
5202     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5203     return FALSE;
5204 }
5205 
5206 
5207 /***********************************************************************
5208  *		SetupDiRegisterCoDeviceInstallers (SETUPAPI.@)
5209  */
5210 BOOL WINAPI
5211 SetupDiRegisterCoDeviceInstallers(
5212         IN HDEVINFO DeviceInfoSet,
5213         IN PSP_DEVINFO_DATA DeviceInfoData)
5214 {
5215     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
5216     struct DeviceInfo *deviceInfo;
5217     BOOL ret = FALSE; /* Return value */
5218 
5219     TRACE("%s(%p %p)\n", __FUNCTION__, DeviceInfoSet, DeviceInfoData);
5220 
5221     if (!DeviceInfoSet)
5222         SetLastError(ERROR_INVALID_PARAMETER);
5223     else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
5224         SetLastError(ERROR_INVALID_HANDLE);
5225     else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
5226         SetLastError(ERROR_INVALID_HANDLE);
5227     else if (!DeviceInfoData)
5228         SetLastError(ERROR_INVALID_PARAMETER);
5229     else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
5230         SetLastError(ERROR_INVALID_USER_BUFFER);
5231     else
5232     {
5233         SP_DEVINSTALL_PARAMS_W InstallParams;
5234         struct DriverInfoElement *SelectedDriver;
5235         BOOL Result;
5236         DWORD DoAction;
5237         WCHAR SectionName[MAX_PATH];
5238         DWORD SectionNameLength = 0;
5239         HKEY hKey = INVALID_HANDLE_VALUE;
5240         PVOID Context = NULL;
5241 
5242         InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
5243         Result = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
5244         if (!Result)
5245             goto cleanup;
5246 
5247         SelectedDriver = (struct DriverInfoElement *)InstallParams.ClassInstallReserved;
5248         if (SelectedDriver == NULL)
5249         {
5250             SetLastError(ERROR_NO_DRIVER_SELECTED);
5251             goto cleanup;
5252         }
5253 
5254         /* Get .CoInstallers section name */
5255         Result = SetupDiGetActualSectionToInstallW(
5256             SelectedDriver->InfFileDetails->hInf,
5257             SelectedDriver->Details.SectionName,
5258             SectionName, MAX_PATH, &SectionNameLength, NULL);
5259         if (!Result || SectionNameLength > MAX_PATH - strlenW(DotCoInstallers) - 1)
5260             goto cleanup;
5261         lstrcatW(SectionName, DotCoInstallers);
5262 
5263         deviceInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
5264 
5265         /* Open/Create driver key information */
5266 #if _WIN32_WINNT >= 0x502
5267         hKey = SETUPDI_OpenDrvKey(set->HKLM, deviceInfo, KEY_READ | KEY_WRITE);
5268 #else
5269         hKey = SETUPDI_OpenDrvKey(set->HKLM, deviceInfo, KEY_ALL_ACCESS);
5270 #endif
5271         if (hKey == INVALID_HANDLE_VALUE && GetLastError() == ERROR_FILE_NOT_FOUND)
5272 #if _WIN32_WINNT >= 0x502
5273             hKey = SETUPDI_CreateDrvKey(set->HKLM, deviceInfo, (UUID*)&DeviceInfoData->ClassGuid, KEY_READ | KEY_WRITE);
5274 #else
5275             hKey = SETUPDI_CreateDrvKey(set->HKLM, deviceInfo, (UUID*)&DeviceInfoData->ClassGuid, KEY_ALL_ACCESS);
5276 #endif
5277         if (hKey == INVALID_HANDLE_VALUE)
5278             goto cleanup;
5279 
5280         /* Install .CoInstallers section */
5281         DoAction = SPINST_REGISTRY;
5282         if (!(InstallParams.Flags & DI_NOFILECOPY))
5283         {
5284             DoAction |= SPINST_FILES;
5285             Context = SetupInitDefaultQueueCallback(InstallParams.hwndParent);
5286             if (!Context)
5287                 goto cleanup;
5288         }
5289         Result = SetupInstallFromInfSectionW(InstallParams.hwndParent,
5290             SelectedDriver->InfFileDetails->hInf, SectionName,
5291             DoAction, hKey, SelectedDriver->InfFileDetails->DirectoryName, SP_COPY_NEWER,
5292             SetupDefaultQueueCallbackW, Context,
5293             DeviceInfoSet, DeviceInfoData);
5294         if (!Result)
5295             goto cleanup;
5296 
5297         ret = TRUE;
5298 
5299 cleanup:
5300         if (Context)
5301             SetupTermDefaultQueueCallback(Context);
5302         if (hKey != INVALID_HANDLE_VALUE)
5303             RegCloseKey(hKey);
5304     }
5305 
5306     TRACE("Returning %d\n", ret);
5307     return ret;
5308 }
5309 
5310 static BOOL
5311 InfIsFromOEMLocation(
5312         IN PCWSTR FullName,
5313         OUT LPBOOL IsOEMLocation)
5314 {
5315     PWCHAR last;
5316 
5317     last = strrchrW(FullName, '\\');
5318     if (!last)
5319     {
5320         /* No directory specified */
5321         *IsOEMLocation = FALSE;
5322     }
5323     else
5324     {
5325         LPWSTR Windir;
5326         UINT ret;
5327 
5328         Windir = MyMalloc((MAX_PATH + 1 + strlenW(InfDirectory)) * sizeof(WCHAR));
5329         if (!Windir)
5330         {
5331             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
5332             return FALSE;
5333         }
5334 
5335         ret = GetSystemWindowsDirectoryW(Windir, MAX_PATH);
5336         if (ret == 0 || ret > MAX_PATH)
5337         {
5338             MyFree(Windir);
5339             SetLastError(ERROR_GEN_FAILURE);
5340             return FALSE;
5341         }
5342         if (*Windir && Windir[strlenW(Windir) - 1] != '\\')
5343             strcatW(Windir, BackSlash);
5344         strcatW(Windir, InfDirectory);
5345 
5346         if (strncmpiW(FullName, Windir, last - FullName) == 0)
5347         {
5348             /* The path is %SYSTEMROOT%\Inf */
5349             *IsOEMLocation = FALSE;
5350         }
5351         else
5352         {
5353             /* The file is in another place */
5354             *IsOEMLocation = TRUE;
5355         }
5356         MyFree(Windir);
5357     }
5358     return TRUE;
5359 }
5360 
5361 /***********************************************************************
5362  *		SetupDiInstallDevice (SETUPAPI.@)
5363  */
5364 BOOL WINAPI
5365 SetupDiInstallDevice(
5366         IN HDEVINFO DeviceInfoSet,
5367         IN OUT PSP_DEVINFO_DATA DeviceInfoData)
5368 {
5369     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
5370     struct DeviceInfo *deviceInfo;
5371     SP_DEVINSTALL_PARAMS_W InstallParams;
5372     struct DriverInfoElement *SelectedDriver;
5373     SYSTEMTIME DriverDate;
5374     WCHAR SectionName[MAX_PATH];
5375     WCHAR Buffer[32];
5376     DWORD SectionNameLength = 0;
5377     BOOL Result = FALSE;
5378     ULONG DoAction;
5379     DWORD RequiredSize;
5380     LPWSTR pSectionName = NULL;
5381     WCHAR ClassName[MAX_CLASS_NAME_LEN];
5382     GUID ClassGuid;
5383     LPWSTR lpGuidString = NULL, lpFullGuidString = NULL;
5384     BOOL RebootRequired = FALSE;
5385     HKEY hKey = INVALID_HANDLE_VALUE;
5386     BOOL NeedtoCopyFile;
5387     LARGE_INTEGER fullVersion;
5388     LONG rc;
5389     PVOID Context = NULL;
5390     BOOL ret = FALSE; /* Return value */
5391 
5392     TRACE("%s(%p %p)\n", __FUNCTION__, DeviceInfoSet, DeviceInfoData);
5393 
5394     if (!DeviceInfoSet)
5395         SetLastError(ERROR_INVALID_PARAMETER);
5396     else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
5397         SetLastError(ERROR_INVALID_HANDLE);
5398     else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
5399         SetLastError(ERROR_INVALID_HANDLE);
5400     else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
5401         SetLastError(ERROR_INVALID_USER_BUFFER);
5402     else
5403         Result = TRUE;
5404 
5405     if (!Result)
5406     {
5407         /* One parameter is bad */
5408         goto cleanup;
5409     }
5410 
5411     InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
5412     Result = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
5413     if (!Result)
5414         goto cleanup;
5415 
5416     if (InstallParams.FlagsEx & DI_FLAGSEX_SETFAILEDINSTALL)
5417     {
5418         /* Set FAILEDINSTALL in ConfigFlags registry value */
5419         DWORD ConfigFlags, regType;
5420         Result = SetupDiGetDeviceRegistryPropertyW(
5421             DeviceInfoSet,
5422             DeviceInfoData,
5423             SPDRP_CONFIGFLAGS,
5424             &regType,
5425             (PBYTE)&ConfigFlags,
5426             sizeof(ConfigFlags),
5427             NULL);
5428         if (!Result || regType != REG_DWORD)
5429         {
5430             SetLastError(ERROR_GEN_FAILURE);
5431             goto cleanup;
5432         }
5433         ConfigFlags |= CONFIGFLAG_FAILEDINSTALL;
5434         Result = SetupDiSetDeviceRegistryPropertyW(
5435             DeviceInfoSet,
5436             DeviceInfoData,
5437             SPDRP_CONFIGFLAGS,
5438             (PBYTE)&ConfigFlags,
5439             sizeof(ConfigFlags));
5440         if (!Result)
5441         {
5442             SetLastError(ERROR_GEN_FAILURE);
5443             goto cleanup;
5444         }
5445 
5446         ret = TRUE;
5447         goto cleanup;
5448     }
5449 
5450     SelectedDriver = (struct DriverInfoElement *)InstallParams.ClassInstallReserved;
5451     if (SelectedDriver == NULL)
5452     {
5453         SetLastError(ERROR_NO_DRIVER_SELECTED);
5454         goto cleanup;
5455     }
5456 
5457     FileTimeToSystemTime(&SelectedDriver->Info.DriverDate, &DriverDate);
5458 
5459     Result = SetupDiGetActualSectionToInstallW(
5460         SelectedDriver->InfFileDetails->hInf,
5461         SelectedDriver->Details.SectionName,
5462         SectionName, MAX_PATH, &SectionNameLength, NULL);
5463     if (!Result || SectionNameLength > MAX_PATH - strlenW(DotServices))
5464         goto cleanup;
5465     pSectionName = &SectionName[strlenW(SectionName)];
5466 
5467     /* Get information from [Version] section */
5468     if (!SetupDiGetINFClassW(SelectedDriver->Details.InfFileName, &ClassGuid, ClassName, MAX_CLASS_NAME_LEN, &RequiredSize))
5469         goto cleanup;
5470     /* Format ClassGuid to a string */
5471     if (UuidToStringW((UUID*)&ClassGuid, &lpGuidString) != RPC_S_OK)
5472         goto cleanup;
5473     RequiredSize = lstrlenW(lpGuidString);
5474     lpFullGuidString = HeapAlloc(GetProcessHeap(), 0, (RequiredSize + 3) * sizeof(WCHAR));
5475     if (!lpFullGuidString)
5476     {
5477         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
5478         goto cleanup;
5479     }
5480     lpFullGuidString[0] = '{';
5481     memcpy(&lpFullGuidString[1], lpGuidString, RequiredSize * sizeof(WCHAR));
5482     lpFullGuidString[RequiredSize + 1] = '}';
5483     lpFullGuidString[RequiredSize + 2] = '\0';
5484 
5485     /* Copy .inf file to Inf\ directory (if needed) */
5486     Result = InfIsFromOEMLocation(SelectedDriver->Details.InfFileName, &NeedtoCopyFile);
5487     if (!Result)
5488         goto cleanup;
5489     if (NeedtoCopyFile)
5490     {
5491         WCHAR NewFileName[MAX_PATH];
5492         struct InfFileDetails *newInfFileDetails;
5493         Result = SetupCopyOEMInfW(
5494             SelectedDriver->Details.InfFileName,
5495             NULL,
5496             SPOST_NONE,
5497             SP_COPY_NOOVERWRITE,
5498             NewFileName, MAX_PATH,
5499             NULL,
5500             NULL);
5501         if (!Result && GetLastError() != ERROR_FILE_EXISTS)
5502             goto cleanup;
5503         /* Create a new struct InfFileDetails, and set it to
5504          * SelectedDriver->InfFileDetails, to release use of
5505          * current InfFile */
5506         newInfFileDetails = CreateInfFileDetails(NewFileName);
5507         if (!newInfFileDetails)
5508             goto cleanup;
5509         DereferenceInfFile(SelectedDriver->InfFileDetails);
5510         SelectedDriver->InfFileDetails = newInfFileDetails;
5511         strcpyW(SelectedDriver->Details.InfFileName, NewFileName);
5512     }
5513 
5514     deviceInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
5515 
5516     /* Open/Create driver key information */
5517 #if _WIN32_WINNT >= 0x502
5518     hKey = SETUPDI_OpenDrvKey(set->HKLM, deviceInfo, KEY_READ | KEY_WRITE);
5519 #else
5520     hKey = SETUPDI_OpenDrvKey(set->HKLM, deviceInfo, KEY_ALL_ACCESS);
5521 #endif
5522     if (hKey == INVALID_HANDLE_VALUE && GetLastError() == ERROR_FILE_NOT_FOUND)
5523 #if _WIN32_WINNT >= 0x502
5524         hKey = SETUPDI_CreateDrvKey(set->HKLM, deviceInfo, (UUID*)&DeviceInfoData->ClassGuid, KEY_READ | KEY_WRITE);
5525 #else
5526         hKey = SETUPDI_CreateDrvKey(set->HKLM, deviceInfo, (UUID*)&DeviceInfoData->ClassGuid, KEY_ALL_ACCESS);
5527 #endif
5528     if (hKey == INVALID_HANDLE_VALUE)
5529         goto cleanup;
5530 
5531     /* Install main section */
5532     DoAction = 0;
5533     if (!(InstallParams.FlagsEx & DI_FLAGSEX_NO_DRVREG_MODIFY))
5534         DoAction |= SPINST_REGISTRY;
5535     if (!(InstallParams.Flags & DI_NOFILECOPY))
5536     {
5537         DoAction |= SPINST_FILES;
5538         Context = SetupInitDefaultQueueCallback(InstallParams.hwndParent);
5539         if (!Context)
5540             goto cleanup;
5541     }
5542     *pSectionName = '\0';
5543     Result = SetupInstallFromInfSectionW(InstallParams.hwndParent,
5544         SelectedDriver->InfFileDetails->hInf, SectionName,
5545         DoAction, hKey, SelectedDriver->InfFileDetails->DirectoryName, SP_COPY_NEWER,
5546         SetupDefaultQueueCallbackW, Context,
5547         DeviceInfoSet, DeviceInfoData);
5548     if (!Result)
5549         goto cleanup;
5550     InstallParams.Flags |= DI_NOFILECOPY;
5551     SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
5552 
5553     /* Write information to driver key */
5554     *pSectionName = UNICODE_NULL;
5555     memcpy(&fullVersion, &SelectedDriver->Info.DriverVersion, sizeof(LARGE_INTEGER));
5556     TRACE("Write information to driver key\n");
5557     TRACE("DriverDate      : '%u-%u-%u'\n", DriverDate.wMonth, DriverDate.wDay, DriverDate.wYear);
5558     TRACE("DriverDesc      : '%s'\n", debugstr_w(SelectedDriver->Info.Description));
5559     TRACE("DriverVersion   : '%ld.%ld.%lu.%ld'\n", fullVersion.HighPart >> 16, fullVersion.HighPart & 0xffff, fullVersion.LowPart >> 16, fullVersion.LowPart & 0xffff);
5560     TRACE("InfPath         : '%s'\n", debugstr_w(SelectedDriver->InfFileDetails->FileName));
5561     TRACE("InfSection      : '%s'\n", debugstr_w(SelectedDriver->Details.SectionName));
5562     TRACE("InfSectionExt   : '%s'\n", debugstr_w(&SectionName[strlenW(SelectedDriver->Details.SectionName)]));
5563     TRACE("MatchingDeviceId: '%s'\n", debugstr_w(SelectedDriver->MatchingId));
5564     TRACE("ProviderName    : '%s'\n", debugstr_w(SelectedDriver->Info.ProviderName));
5565     sprintfW(Buffer, DateFormat, DriverDate.wMonth, DriverDate.wDay, DriverDate.wYear);
5566     rc = RegSetValueExW(hKey, REGSTR_DRIVER_DATE, 0, REG_SZ, (const BYTE *)Buffer, (strlenW(Buffer) + 1) * sizeof(WCHAR));
5567     if (rc == ERROR_SUCCESS)
5568         rc = RegSetValueExW(hKey, REGSTR_DRIVER_DATE_DATA, 0, REG_BINARY, (const BYTE *)&SelectedDriver->Info.DriverDate, sizeof(FILETIME));
5569     if (rc == ERROR_SUCCESS)
5570         rc = RegSetValueExW(hKey, REGSTR_VAL_DRVDESC, 0, REG_SZ, (const BYTE *)SelectedDriver->Info.Description, (strlenW(SelectedDriver->Info.Description) + 1) * sizeof(WCHAR));
5571     if (rc == ERROR_SUCCESS)
5572     {
5573         sprintfW(Buffer, VersionFormat, fullVersion.HighPart >> 16, fullVersion.HighPart & 0xffff, fullVersion.LowPart >> 16, fullVersion.LowPart & 0xffff);
5574         rc = RegSetValueExW(hKey, REGSTR_DRIVER_VERSION, 0, REG_SZ, (const BYTE *)Buffer, (strlenW(Buffer) + 1) * sizeof(WCHAR));
5575     }
5576     if (rc == ERROR_SUCCESS)
5577         rc = RegSetValueExW(hKey, REGSTR_VAL_INFPATH, 0, REG_SZ, (const BYTE *)SelectedDriver->InfFileDetails->FileName, (strlenW(SelectedDriver->InfFileDetails->FileName) + 1) * sizeof(WCHAR));
5578     if (rc == ERROR_SUCCESS)
5579         rc = RegSetValueExW(hKey, REGSTR_VAL_INFSECTION, 0, REG_SZ, (const BYTE *)SelectedDriver->Details.SectionName, (strlenW(SelectedDriver->Details.SectionName) + 1) * sizeof(WCHAR));
5580     if (rc == ERROR_SUCCESS)
5581         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));
5582     if (rc == ERROR_SUCCESS)
5583         rc = RegSetValueExW(hKey, REGSTR_VAL_MATCHINGDEVID, 0, REG_SZ, (const BYTE *)SelectedDriver->MatchingId, (strlenW(SelectedDriver->MatchingId) + 1) * sizeof(WCHAR));
5584     if (rc == ERROR_SUCCESS)
5585         rc = RegSetValueExW(hKey, REGSTR_VAL_PROVIDER_NAME, 0, REG_SZ, (const BYTE *)SelectedDriver->Info.ProviderName, (strlenW(SelectedDriver->Info.ProviderName) + 1) * sizeof(WCHAR));
5586     if (rc != ERROR_SUCCESS)
5587     {
5588        SetLastError(rc);
5589        goto cleanup;
5590     }
5591     RegCloseKey(hKey);
5592     hKey = INVALID_HANDLE_VALUE;
5593 
5594     /* FIXME: Process .LogConfigOverride section */
5595 
5596     /* Install .Services section */
5597     strcpyW(pSectionName, DotServices);
5598     Result = SetupInstallServicesFromInfSectionExW(
5599         SelectedDriver->InfFileDetails->hInf,
5600         SectionName,
5601         0,
5602         DeviceInfoSet,
5603         DeviceInfoData,
5604         NULL,
5605         NULL);
5606     if (!Result)
5607     {
5608         if (GetLastError() != ERROR_SECTION_NOT_FOUND)
5609             goto cleanup;
5610         SetLastError(ERROR_SUCCESS);
5611     }
5612     if (GetLastError() == ERROR_SUCCESS_REBOOT_REQUIRED)
5613         RebootRequired = TRUE;
5614 
5615     /* Open device registry key */
5616     hKey = SETUPDI_OpenDevKey(((struct DeviceInfoSet *)DeviceInfoSet)->HKLM, (struct DeviceInfo *)DeviceInfoData->Reserved, KEY_SET_VALUE);
5617     if (hKey == INVALID_HANDLE_VALUE)
5618         goto cleanup;
5619 
5620     /* Install .HW section */
5621     DoAction = 0;
5622     if (!(InstallParams.FlagsEx & DI_FLAGSEX_NO_DRVREG_MODIFY))
5623         DoAction |= SPINST_REGISTRY;
5624     strcpyW(pSectionName, DotHW);
5625     Result = SetupInstallFromInfSectionW(InstallParams.hwndParent,
5626         SelectedDriver->InfFileDetails->hInf, SectionName,
5627         DoAction, hKey, NULL, 0,
5628         NULL, NULL,
5629         DeviceInfoSet, DeviceInfoData);
5630     if (!Result)
5631         goto cleanup;
5632 
5633     /* Write information to enum key */
5634     TRACE("Write information to enum key\n");
5635     TRACE("Class           : '%s'\n", debugstr_w(ClassName));
5636     TRACE("ClassGUID       : '%s'\n", debugstr_w(lpFullGuidString));
5637     TRACE("DeviceDesc      : '%s'\n", debugstr_w(SelectedDriver->Info.Description));
5638     TRACE("Mfg             : '%s'\n", debugstr_w(SelectedDriver->Info.MfgName));
5639     rc = RegSetValueExW(hKey, REGSTR_VAL_CLASS, 0, REG_SZ, (const BYTE *)ClassName, (strlenW(ClassName) + 1) * sizeof(WCHAR));
5640     if (rc == ERROR_SUCCESS)
5641         rc = RegSetValueExW(hKey, REGSTR_VAL_CLASSGUID, 0, REG_SZ, (const BYTE *)lpFullGuidString, (strlenW(lpFullGuidString) + 1) * sizeof(WCHAR));
5642     if (rc == ERROR_SUCCESS)
5643         rc = RegSetValueExW(hKey, REGSTR_VAL_DEVDESC, 0, REG_SZ, (const BYTE *)SelectedDriver->Info.Description, (strlenW(SelectedDriver->Info.Description) + 1) * sizeof(WCHAR));
5644     if (rc == ERROR_SUCCESS)
5645         rc = RegSetValueExW(hKey, REGSTR_VAL_MFG, 0, REG_SZ, (const BYTE *)SelectedDriver->Info.MfgName, (strlenW(SelectedDriver->Info.MfgName) + 1) * sizeof(WCHAR));
5646     if (rc != ERROR_SUCCESS)
5647     {
5648        SetLastError(rc);
5649        goto cleanup;
5650     }
5651 
5652     /* Start the device */
5653     if (!RebootRequired && !(InstallParams.Flags & (DI_NEEDRESTART | DI_NEEDREBOOT | DI_DONOTCALLCONFIGMG)))
5654         ret = ResetDevice(DeviceInfoSet, DeviceInfoData);
5655     else
5656         ret = TRUE;
5657 
5658 cleanup:
5659     /* End of installation */
5660     if (hKey != INVALID_HANDLE_VALUE)
5661         RegCloseKey(hKey);
5662     if (lpGuidString)
5663         RpcStringFreeW(&lpGuidString);
5664     HeapFree(GetProcessHeap(), 0, lpFullGuidString);
5665     if (Context)
5666         SetupTermDefaultQueueCallback(Context);
5667     TRACE("Returning %d\n", ret);
5668     return ret;
5669 }
5670 
5671 HKEY SETUPDI_CreateDevKey(HKEY RootKey, struct DeviceInfo *devInfo, REGSAM samDesired)
5672 {
5673     HKEY enumKey, key = INVALID_HANDLE_VALUE;
5674     LONG l;
5675 
5676     l = RegCreateKeyExW(RootKey, REGSTR_PATH_SYSTEMENUM, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_CREATE_SUB_KEY, NULL, &enumKey, NULL);
5677     if (!l)
5678     {
5679         l = RegCreateKeyExW(enumKey, devInfo->instanceId, 0, NULL, REG_OPTION_NON_VOLATILE, samDesired, NULL, &key, NULL);
5680         RegCloseKey(enumKey);
5681     }
5682     if (l)
5683         SetLastError(l);
5684     return key;
5685 }
5686 
5687 HKEY SETUPDI_CreateDrvKey(HKEY RootKey, struct DeviceInfo *devInfo, UUID *ClassGuid, REGSAM samDesired)
5688 {
5689     HKEY key = INVALID_HANDLE_VALUE;
5690     LPWSTR lpGuidString = NULL;
5691     LPWSTR DriverKey = NULL; /* {GUID}\Index */
5692     LPWSTR pDeviceInstance; /* Points into DriverKey, on the Index field */
5693     DWORD Index; /* Index used in the DriverKey name */
5694     DWORD dwSize;
5695     DWORD Disposition;
5696     DWORD rc;
5697     HKEY hHWProfileKey = INVALID_HANDLE_VALUE;
5698     HKEY hEnumKey = NULL;
5699     HKEY hClassKey = NULL;
5700     HKEY hDeviceKey = INVALID_HANDLE_VALUE;
5701     HKEY hKey = NULL;
5702 
5703     /* Open device key, to read Driver value */
5704     hDeviceKey = SETUPDI_OpenDevKey(RootKey, devInfo, KEY_QUERY_VALUE | KEY_SET_VALUE);
5705     if (hDeviceKey == INVALID_HANDLE_VALUE)
5706         goto cleanup;
5707 
5708     rc = RegOpenKeyExW(RootKey, REGSTR_PATH_CLASS_NT, 0, KEY_CREATE_SUB_KEY, &hClassKey);
5709     if (rc != ERROR_SUCCESS)
5710     {
5711         SetLastError(rc);
5712         goto cleanup;
5713     }
5714 
5715     rc = RegQueryValueExW(hDeviceKey, REGSTR_VAL_DRIVER, NULL, NULL, NULL, &dwSize);
5716     if (rc != ERROR_SUCCESS)
5717     {
5718         /* Create a new driver key */
5719 
5720         if (UuidToStringW(ClassGuid, &lpGuidString) != RPC_S_OK)
5721             goto cleanup;
5722 
5723         /* The driver key is in \System\CurrentControlSet\Control\Class\{GUID}\Index */
5724         DriverKey = HeapAlloc(GetProcessHeap(), 0, (strlenW(lpGuidString) + 7) * sizeof(WCHAR) + sizeof(UNICODE_NULL));
5725         if (!DriverKey)
5726         {
5727             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
5728             goto cleanup;
5729         }
5730 
5731         DriverKey[0] = '{';
5732         strcpyW(&DriverKey[1], lpGuidString);
5733         pDeviceInstance = &DriverKey[strlenW(DriverKey)];
5734         *pDeviceInstance++ = '}';
5735         *pDeviceInstance++ = '\\';
5736 
5737         /* Try all values for Index between 0 and 9999 */
5738         Index = 0;
5739         while (Index <= 9999)
5740         {
5741             sprintfW(pDeviceInstance, InstanceKeyFormat, Index);
5742             rc = RegCreateKeyExW(hClassKey,
5743                 DriverKey,
5744                 0,
5745                 NULL,
5746                 REG_OPTION_NON_VOLATILE,
5747 #if _WIN32_WINNT >= 0x502
5748                 KEY_READ | KEY_WRITE,
5749 #else
5750                 KEY_ALL_ACCESS,
5751 #endif
5752                 NULL,
5753                 &hKey,
5754                 &Disposition);
5755             if (rc != ERROR_SUCCESS)
5756             {
5757                 SetLastError(rc);
5758                 goto cleanup;
5759             }
5760             if (Disposition == REG_CREATED_NEW_KEY)
5761                 break;
5762             RegCloseKey(hKey);
5763             hKey = NULL;
5764             Index++;
5765         }
5766 
5767         if (Index > 9999)
5768         {
5769             /* Unable to create more than 9999 devices within the same class */
5770             SetLastError(ERROR_GEN_FAILURE);
5771             goto cleanup;
5772         }
5773 
5774         /* Write the new Driver value */
5775         rc = RegSetValueExW(hDeviceKey, REGSTR_VAL_DRIVER, 0, REG_SZ, (const BYTE *)DriverKey, (strlenW(DriverKey) + 1) * sizeof(WCHAR));
5776         if (rc != ERROR_SUCCESS)
5777         {
5778             SetLastError(rc);
5779             goto cleanup;
5780         }
5781     }
5782     else
5783     {
5784         /* Open the existing driver key */
5785 
5786         DriverKey = HeapAlloc(GetProcessHeap(), 0, dwSize);
5787         if (!DriverKey)
5788         {
5789             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
5790             goto cleanup;
5791         }
5792 
5793         rc = RegQueryValueExW(hDeviceKey, REGSTR_VAL_DRIVER, NULL, NULL, (LPBYTE)DriverKey, &dwSize);
5794         if (rc != ERROR_SUCCESS)
5795         {
5796             SetLastError(rc);
5797             goto cleanup;
5798         }
5799 
5800         rc = RegCreateKeyExW(hClassKey,
5801             DriverKey,
5802             0,
5803             NULL,
5804             REG_OPTION_NON_VOLATILE,
5805 #if _WIN32_WINNT >= 0x502
5806             KEY_READ | KEY_WRITE,
5807 #else
5808             KEY_ALL_ACCESS,
5809 #endif
5810             NULL,
5811             &hKey,
5812             &Disposition);
5813         if (rc != ERROR_SUCCESS)
5814         {
5815             SetLastError(rc);
5816             goto cleanup;
5817         }
5818     }
5819 
5820     key = hKey;
5821 
5822 cleanup:
5823         if (lpGuidString)
5824             RpcStringFreeW(&lpGuidString);
5825         HeapFree(GetProcessHeap(), 0, DriverKey);
5826         if (hHWProfileKey != INVALID_HANDLE_VALUE)
5827             RegCloseKey(hHWProfileKey);
5828         if (hEnumKey != NULL)
5829             RegCloseKey(hEnumKey);
5830         if (hClassKey != NULL)
5831             RegCloseKey(hClassKey);
5832         if (hDeviceKey != INVALID_HANDLE_VALUE)
5833             RegCloseKey(hDeviceKey);
5834         if (hKey != NULL && hKey != key)
5835             RegCloseKey(hKey);
5836 
5837     TRACE("Returning 0x%p\n", hKey);
5838     return hKey;
5839 }
5840 
5841 HKEY SETUPDI_OpenDevKey(HKEY RootKey, struct DeviceInfo *devInfo, REGSAM samDesired)
5842 {
5843     HKEY enumKey, key = INVALID_HANDLE_VALUE;
5844     LONG l;
5845 
5846     l = RegOpenKeyExW(RootKey, REGSTR_PATH_SYSTEMENUM, 0, READ_CONTROL, &enumKey);
5847     if (!l)
5848     {
5849         l = RegOpenKeyExW(enumKey, devInfo->instanceId, 0, samDesired, &key);
5850         RegCloseKey(enumKey);
5851     }
5852     if (l)
5853         SetLastError(l);
5854     return key;
5855 }
5856 
5857 HKEY SETUPDI_OpenDrvKey(HKEY RootKey, struct DeviceInfo *devInfo, REGSAM samDesired)
5858 {
5859     LPWSTR DriverKey = NULL;
5860     DWORD dwLength = 0;
5861     DWORD dwRegType;
5862     DWORD rc;
5863     HKEY hEnumKey = NULL;
5864     HKEY hKey = NULL;
5865     HKEY key = INVALID_HANDLE_VALUE;
5866 
5867     hKey = SETUPDI_OpenDevKey(RootKey, devInfo, KEY_QUERY_VALUE);
5868     if (hKey == INVALID_HANDLE_VALUE)
5869         goto cleanup;
5870     /* Read the 'Driver' key */
5871     rc = RegQueryValueExW(hKey, REGSTR_VAL_DRIVER, NULL, &dwRegType, NULL, &dwLength);
5872     if (rc != ERROR_SUCCESS)
5873     {
5874         SetLastError(rc);
5875         goto cleanup;
5876     }
5877     else if (dwRegType != REG_SZ)
5878     {
5879         SetLastError(ERROR_GEN_FAILURE);
5880         goto cleanup;
5881     }
5882     DriverKey = HeapAlloc(GetProcessHeap(), 0, dwLength);
5883     if (!DriverKey)
5884     {
5885         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
5886         goto cleanup;
5887     }
5888     rc = RegQueryValueExW(hKey, REGSTR_VAL_DRIVER, NULL, &dwRegType, (LPBYTE)DriverKey, &dwLength);
5889     if (rc != ERROR_SUCCESS)
5890     {
5891         SetLastError(rc);
5892         goto cleanup;
5893     }
5894     RegCloseKey(hKey);
5895     hKey = NULL;
5896     /* Need to open the driver key */
5897     rc = RegOpenKeyExW(
5898         RootKey,
5899         REGSTR_PATH_CLASS_NT,
5900         0, /* Options */
5901         READ_CONTROL,
5902         &hEnumKey);
5903     if (rc != ERROR_SUCCESS)
5904     {
5905         SetLastError(rc);
5906         goto cleanup;
5907     }
5908     rc = RegOpenKeyExW(
5909         hEnumKey,
5910         DriverKey,
5911         0, /* Options */
5912         samDesired,
5913         &hKey);
5914     if (rc != ERROR_SUCCESS)
5915     {
5916         SetLastError(rc);
5917         goto cleanup;
5918     }
5919     key = hKey;
5920 
5921 cleanup:
5922     if (hEnumKey != NULL)
5923         RegCloseKey(hEnumKey);
5924     if (hKey != NULL && hKey != key)
5925         RegCloseKey(hKey);
5926     if (DriverKey)
5927         HeapFree(GetProcessHeap(), 0, DriverKey);
5928     return key;
5929 }
5930 
5931 /***********************************************************************
5932  *		SetupDiOpenDevRegKey (SETUPAPI.@)
5933  */
5934 HKEY WINAPI SetupDiOpenDevRegKey(
5935         HDEVINFO DeviceInfoSet,
5936         PSP_DEVINFO_DATA DeviceInfoData,
5937         DWORD Scope,
5938         DWORD HwProfile,
5939         DWORD KeyType,
5940         REGSAM samDesired)
5941 {
5942     struct DeviceInfoSet *set = DeviceInfoSet;
5943     struct DeviceInfo *devInfo;
5944     HKEY key = INVALID_HANDLE_VALUE;
5945     HKEY RootKey;
5946 
5947     TRACE("%s(%p %p %d %d %d %x)\n", __FUNCTION__, DeviceInfoSet, DeviceInfoData,
5948           Scope, HwProfile, KeyType, samDesired);
5949 
5950     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
5951     {
5952         SetLastError(ERROR_INVALID_HANDLE);
5953         return INVALID_HANDLE_VALUE;
5954     }
5955     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
5956     {
5957         SetLastError(ERROR_INVALID_HANDLE);
5958         return INVALID_HANDLE_VALUE;
5959     }
5960     if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
5961             || !DeviceInfoData->Reserved)
5962     {
5963         SetLastError(ERROR_INVALID_PARAMETER);
5964         return INVALID_HANDLE_VALUE;
5965     }
5966     if (Scope != DICS_FLAG_GLOBAL && Scope != DICS_FLAG_CONFIGSPECIFIC)
5967     {
5968         SetLastError(ERROR_INVALID_FLAGS);
5969         return INVALID_HANDLE_VALUE;
5970     }
5971     if (KeyType != DIREG_DEV && KeyType != DIREG_DRV)
5972     {
5973         SetLastError(ERROR_INVALID_FLAGS);
5974         return INVALID_HANDLE_VALUE;
5975     }
5976     devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
5977     if (devInfo->set != set)
5978     {
5979         SetLastError(ERROR_INVALID_PARAMETER);
5980         return INVALID_HANDLE_VALUE;
5981     }
5982     if (Scope != DICS_FLAG_GLOBAL)
5983     {
5984         RootKey = OpenHardwareProfileKey(set->HKLM, HwProfile, 0);
5985         if (RootKey == INVALID_HANDLE_VALUE)
5986             return INVALID_HANDLE_VALUE;
5987     }
5988     else
5989         RootKey = set->HKLM;
5990     switch (KeyType)
5991     {
5992         case DIREG_DEV:
5993             key = SETUPDI_OpenDevKey(RootKey, devInfo, samDesired);
5994             if (Scope == DICS_FLAG_GLOBAL)
5995             {
5996                 LONG rc;
5997                 HKEY hTempKey = key;
5998                 rc = RegOpenKeyExW(hTempKey,
5999                                    L"Device Parameters",
6000                                    0,
6001                                    samDesired,
6002                                    &key);
6003                 if (rc == ERROR_SUCCESS)
6004                     RegCloseKey(hTempKey);
6005             }
6006             break;
6007         case DIREG_DRV:
6008             key = SETUPDI_OpenDrvKey(RootKey, devInfo, samDesired);
6009             break;
6010         default:
6011             WARN("unknown KeyType %d\n", KeyType);
6012     }
6013     if (RootKey != set->HKLM)
6014         RegCloseKey(RootKey);
6015     return key;
6016 }
6017 
6018 static BOOL SETUPDI_DeleteDevKey(HKEY RootKey, struct DeviceInfo *devInfo)
6019 {
6020     FIXME("\n");
6021     return FALSE;
6022 }
6023 
6024 static BOOL SETUPDI_DeleteDrvKey(HKEY RootKey, struct DeviceInfo *devInfo)
6025 {
6026     FIXME("\n");
6027     return FALSE;
6028 }
6029 
6030 /***********************************************************************
6031  *		SetupDiDeleteDevRegKey (SETUPAPI.@)
6032  */
6033 BOOL WINAPI SetupDiDeleteDevRegKey(
6034         HDEVINFO DeviceInfoSet,
6035         PSP_DEVINFO_DATA DeviceInfoData,
6036         DWORD Scope,
6037         DWORD HwProfile,
6038         DWORD KeyType)
6039 {
6040     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
6041     struct DeviceInfo *devInfo;
6042     BOOL ret = FALSE;
6043     HKEY RootKey;
6044 
6045     TRACE("%s(%p %p %d %d %d)\n", __FUNCTION__, DeviceInfoSet, DeviceInfoData, Scope, HwProfile,
6046             KeyType);
6047 
6048     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
6049     {
6050         SetLastError(ERROR_INVALID_HANDLE);
6051         return FALSE;
6052     }
6053     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
6054     {
6055         SetLastError(ERROR_INVALID_HANDLE);
6056         return FALSE;
6057     }
6058     if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
6059             || !DeviceInfoData->Reserved)
6060     {
6061         SetLastError(ERROR_INVALID_PARAMETER);
6062         return FALSE;
6063     }
6064     if (Scope != DICS_FLAG_GLOBAL && Scope != DICS_FLAG_CONFIGSPECIFIC)
6065     {
6066         SetLastError(ERROR_INVALID_FLAGS);
6067         return FALSE;
6068     }
6069     if (KeyType != DIREG_DEV && KeyType != DIREG_DRV && KeyType != DIREG_BOTH)
6070     {
6071         SetLastError(ERROR_INVALID_FLAGS);
6072         return FALSE;
6073     }
6074     devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
6075     if (devInfo->set != set)
6076     {
6077         SetLastError(ERROR_INVALID_PARAMETER);
6078         return FALSE;
6079     }
6080     if (Scope != DICS_FLAG_GLOBAL)
6081     {
6082         RootKey = OpenHardwareProfileKey(set->HKLM, HwProfile, 0);
6083         if (RootKey == INVALID_HANDLE_VALUE)
6084             return FALSE;
6085     }
6086     else
6087         RootKey = set->HKLM;
6088     switch (KeyType)
6089     {
6090         case DIREG_DEV:
6091             ret = SETUPDI_DeleteDevKey(RootKey, devInfo);
6092             break;
6093         case DIREG_DRV:
6094             ret = SETUPDI_DeleteDrvKey(RootKey, devInfo);
6095             break;
6096         case DIREG_BOTH:
6097             ret = SETUPDI_DeleteDevKey(RootKey, devInfo);
6098             if (ret)
6099                 ret = SETUPDI_DeleteDrvKey(RootKey, devInfo);
6100             break;
6101         default:
6102             WARN("unknown KeyType %d\n", KeyType);
6103     }
6104     if (RootKey != set->HKLM)
6105         RegCloseKey(RootKey);
6106     return ret;
6107 }
6108 
6109 /***********************************************************************
6110  *		SetupDiRestartDevices (SETUPAPI.@)
6111  */
6112 BOOL
6113 WINAPI
6114 SetupDiRestartDevices(
6115     HDEVINFO DeviceInfoSet,
6116     PSP_DEVINFO_DATA DeviceInfoData)
6117 {
6118     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
6119     struct DeviceInfo *devInfo;
6120     CONFIGRET cr;
6121 
6122     TRACE("%s(%p %p)\n", __FUNCTION__, DeviceInfoSet, DeviceInfoData);
6123 
6124     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
6125     {
6126         SetLastError(ERROR_INVALID_HANDLE);
6127         return FALSE;
6128     }
6129     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
6130     {
6131         SetLastError(ERROR_INVALID_HANDLE);
6132         return FALSE;
6133     }
6134 
6135     if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
6136             || !DeviceInfoData->Reserved)
6137     {
6138         SetLastError(ERROR_INVALID_PARAMETER);
6139         return FALSE;
6140     }
6141 
6142     devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
6143 
6144     cr = CM_Enable_DevNode_Ex(devInfo->dnDevInst, 0, set->hMachine);
6145     if (cr != CR_SUCCESS)
6146     {
6147         SetLastError(GetErrorCodeFromCrCode(cr));
6148         return FALSE;
6149     }
6150 
6151     return TRUE;
6152 }
6153