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