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