xref: /reactos/dll/win32/setupapi/devinst.c (revision d5399189)
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  *		Internal for SetupDiSetDeviceRegistryPropertyA/W
3451  */
3452 BOOL WINAPI IntSetupDiSetDeviceRegistryPropertyAW(
3453         HDEVINFO DeviceInfoSet,
3454         PSP_DEVINFO_DATA DeviceInfoData,
3455         DWORD Property,
3456         const BYTE *PropertyBuffer,
3457         DWORD PropertyBufferSize,
3458         BOOL isAnsi)
3459 {
3460     BOOL ret = FALSE;
3461     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
3462 
3463     TRACE("%p %p %d %p %d\n", DeviceInfoSet, DeviceInfoData, Property,
3464         PropertyBuffer, PropertyBufferSize);
3465 
3466     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
3467     {
3468         SetLastError(ERROR_INVALID_HANDLE);
3469         return FALSE;
3470     }
3471     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
3472     {
3473         SetLastError(ERROR_INVALID_HANDLE);
3474         return FALSE;
3475     }
3476     if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
3477             || !DeviceInfoData->Reserved)
3478     {
3479         SetLastError(ERROR_INVALID_PARAMETER);
3480         return FALSE;
3481     }
3482     if (Property < sizeof(PropertyMap) / sizeof(PropertyMap[0])
3483         && PropertyMap[Property].nameW
3484         && PropertyMap[Property].nameA)
3485     {
3486         HKEY hKey;
3487         LONG l;
3488         hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_SET_VALUE);
3489         if (hKey == INVALID_HANDLE_VALUE)
3490             return FALSE;
3491         /* Write new data */
3492         if (isAnsi)
3493         {
3494             l = RegSetValueExA(
3495                 hKey, PropertyMap[Property].nameA, 0,
3496                     PropertyMap[Property].regType, PropertyBuffer,
3497                     PropertyBufferSize);
3498         }
3499         else
3500         {
3501             l = RegSetValueExW(
3502                 hKey, PropertyMap[Property].nameW, 0,
3503                     PropertyMap[Property].regType, PropertyBuffer,
3504                     PropertyBufferSize);
3505         }
3506         if (!l)
3507             ret = TRUE;
3508         else
3509             SetLastError(l);
3510         RegCloseKey(hKey);
3511     }
3512     else
3513     {
3514         ERR("Property 0x%lx not implemented\n", Property);
3515         SetLastError(ERROR_NOT_SUPPORTED);
3516     }
3517 
3518     TRACE("Returning %d\n", ret);
3519     return ret;
3520 }
3521 /***********************************************************************
3522  *		SetupDiSetDeviceRegistryPropertyA (SETUPAPI.@)
3523  */
3524 BOOL WINAPI SetupDiSetDeviceRegistryPropertyA(
3525         HDEVINFO DeviceInfoSet,
3526         PSP_DEVINFO_DATA DeviceInfoData,
3527         DWORD Property,
3528         const BYTE *PropertyBuffer,
3529         DWORD PropertyBufferSize)
3530 {
3531     return IntSetupDiSetDeviceRegistryPropertyAW(DeviceInfoSet,
3532                                                  DeviceInfoData,
3533                                                  Property,
3534                                                  PropertyBuffer,
3535                                                  PropertyBufferSize,
3536                                                  TRUE);
3537 }
3538 
3539 /***********************************************************************
3540  *		SetupDiSetDeviceRegistryPropertyW (SETUPAPI.@)
3541  */
3542 BOOL WINAPI SetupDiSetDeviceRegistryPropertyW(
3543         HDEVINFO DeviceInfoSet,
3544         PSP_DEVINFO_DATA DeviceInfoData,
3545         DWORD Property,
3546         const BYTE *PropertyBuffer,
3547         DWORD PropertyBufferSize)
3548 {
3549     return IntSetupDiSetDeviceRegistryPropertyAW(DeviceInfoSet,
3550                                                  DeviceInfoData,
3551                                                  Property,
3552                                                  PropertyBuffer,
3553                                                  PropertyBufferSize,
3554                                                  FALSE);
3555 }
3556 
3557 /***********************************************************************
3558  *		SetupDiInstallClassA (SETUPAPI.@)
3559  */
3560 BOOL WINAPI SetupDiInstallClassA(
3561         HWND hwndParent,
3562         PCSTR InfFileName,
3563         DWORD Flags,
3564         HSPFILEQ FileQueue)
3565 {
3566     return SetupDiInstallClassExA(hwndParent, InfFileName, Flags, FileQueue, NULL, NULL, NULL);
3567 }
3568 
3569 /***********************************************************************
3570  *		SetupDiInstallClassExA (SETUPAPI.@)
3571  */
3572 BOOL WINAPI
3573 SetupDiInstallClassExA(
3574     IN HWND hwndParent OPTIONAL,
3575     IN PCSTR InfFileName OPTIONAL,
3576     IN DWORD Flags,
3577     IN HSPFILEQ FileQueue OPTIONAL,
3578     IN CONST GUID *InterfaceClassGuid OPTIONAL,
3579     IN PVOID Reserved1,
3580     IN PVOID Reserved2)
3581 {
3582     PWSTR InfFileNameW = NULL;
3583     BOOL Result;
3584 
3585     if (!InfFileName)
3586     {
3587         SetLastError(ERROR_INVALID_PARAMETER);
3588         return FALSE;
3589     }
3590     else
3591     {
3592         InfFileNameW = pSetupMultiByteToUnicode(InfFileName, CP_ACP);
3593         if (InfFileNameW == NULL)
3594         {
3595             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3596             return FALSE;
3597         }
3598     }
3599 
3600     Result = SetupDiInstallClassExW(hwndParent, InfFileNameW, Flags,
3601         FileQueue, InterfaceClassGuid, Reserved1, Reserved2);
3602 
3603     MyFree(InfFileNameW);
3604 
3605     return Result;
3606 }
3607 
3608 HKEY SETUP_CreateClassKey(HINF hInf)
3609 {
3610     WCHAR FullBuffer[MAX_PATH];
3611     WCHAR Buffer[MAX_PATH];
3612     DWORD RequiredSize;
3613     HKEY hClassKey;
3614     DWORD Disposition;
3615 
3616     /* Obtain the Class GUID for this class */
3617     if (!SetupGetLineTextW(NULL,
3618                            hInf,
3619                            Version,
3620                            REGSTR_VAL_CLASSGUID,
3621                            Buffer,
3622                            sizeof(Buffer) / sizeof(WCHAR),
3623                            &RequiredSize))
3624     {
3625         return INVALID_HANDLE_VALUE;
3626     }
3627 
3628     /* Build the corresponding registry key name */
3629     lstrcpyW(FullBuffer, REGSTR_PATH_CLASS_NT);
3630     lstrcatW(FullBuffer, BackSlash);
3631     lstrcatW(FullBuffer, Buffer);
3632 
3633     /* Obtain the Class name for this class */
3634     if (!SetupGetLineTextW(NULL,
3635                            hInf,
3636                            Version,
3637                            REGSTR_VAL_CLASS,
3638                            Buffer,
3639                            sizeof(Buffer) / sizeof(WCHAR),
3640                            &RequiredSize))
3641     {
3642         return INVALID_HANDLE_VALUE;
3643     }
3644 
3645     /* Try to open or create the registry key */
3646     TRACE("Opening class key %s\n", debugstr_w(FullBuffer));
3647 #if 0 // I keep this for reference...
3648     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
3649                       FullBuffer,
3650                       0,
3651                       KEY_SET_VALUE,
3652                       &hClassKey))
3653     {
3654         /* Use RegCreateKeyExW */
3655     }
3656 #endif
3657     if (RegCreateKeyExW(HKEY_LOCAL_MACHINE,
3658                         FullBuffer,
3659                         0,
3660                         NULL,
3661                         REG_OPTION_NON_VOLATILE,
3662                         KEY_SET_VALUE,
3663                         NULL,
3664                         &hClassKey,
3665                         &Disposition))
3666     {
3667         ERR("RegCreateKeyExW(%s) failed\n", debugstr_w(FullBuffer));
3668         return INVALID_HANDLE_VALUE;
3669     }
3670     if (Disposition == REG_CREATED_NEW_KEY)
3671         TRACE("The class key %s was successfully created\n", debugstr_w(FullBuffer));
3672     else
3673         TRACE("The class key %s was successfully opened\n", debugstr_w(FullBuffer));
3674 
3675     TRACE( "setting value %s to %s\n", debugstr_w(REGSTR_VAL_CLASS), debugstr_w(Buffer) );
3676     if (RegSetValueExW(hClassKey,
3677                        REGSTR_VAL_CLASS,
3678                        0,
3679                        REG_SZ,
3680                        (LPBYTE)Buffer,
3681                        RequiredSize * sizeof(WCHAR)))
3682     {
3683         RegCloseKey(hClassKey);
3684         RegDeleteKeyW(HKEY_LOCAL_MACHINE,
3685                       FullBuffer);
3686         return INVALID_HANDLE_VALUE;
3687     }
3688 
3689     return hClassKey;
3690 }
3691 
3692 /***********************************************************************
3693  *		SetupDiInstallClassW (SETUPAPI.@)
3694  */
3695 BOOL WINAPI SetupDiInstallClassW(
3696         HWND hwndParent,
3697         PCWSTR InfFileName,
3698         DWORD Flags,
3699         HSPFILEQ FileQueue)
3700 {
3701     return SetupDiInstallClassExW(hwndParent, InfFileName, Flags, FileQueue, NULL, NULL, NULL);
3702 }
3703 
3704 
3705 /***********************************************************************
3706  *		SetupDiOpenClassRegKey  (SETUPAPI.@)
3707  */
3708 HKEY WINAPI SetupDiOpenClassRegKey(
3709         const GUID* ClassGuid,
3710         REGSAM samDesired)
3711 {
3712     return SetupDiOpenClassRegKeyExW(ClassGuid, samDesired,
3713                                      DIOCR_INSTALLER, NULL, NULL);
3714 }
3715 
3716 
3717 /***********************************************************************
3718  *		SetupDiOpenClassRegKeyExA  (SETUPAPI.@)
3719  */
3720 HKEY WINAPI SetupDiOpenClassRegKeyExA(
3721         const GUID* ClassGuid,
3722         REGSAM samDesired,
3723         DWORD Flags,
3724         PCSTR MachineName,
3725         PVOID Reserved)
3726 {
3727     PWSTR MachineNameW = NULL;
3728     HKEY hKey;
3729 
3730     TRACE("%s 0x%lx 0x%lx %s %p\n", debugstr_guid(ClassGuid), samDesired,
3731         Flags, debugstr_a(MachineName), Reserved);
3732 
3733     if (MachineName)
3734     {
3735         MachineNameW = pSetupMultiByteToUnicode(MachineName, CP_ACP);
3736         if (MachineNameW == NULL)
3737             return INVALID_HANDLE_VALUE;
3738     }
3739 
3740     hKey = SetupDiOpenClassRegKeyExW(ClassGuid, samDesired,
3741                                      Flags, MachineNameW, Reserved);
3742 
3743     MyFree(MachineNameW);
3744 
3745     return hKey;
3746 }
3747 
3748 
3749 /***********************************************************************
3750  *		SetupDiOpenClassRegKeyExW  (SETUPAPI.@)
3751  */
3752 HKEY WINAPI SetupDiOpenClassRegKeyExW(
3753         const GUID* ClassGuid,
3754         REGSAM samDesired,
3755         DWORD Flags,
3756         PCWSTR MachineName,
3757         PVOID Reserved)
3758 {
3759     HKEY HKLM;
3760     HKEY hClassesKey;
3761     HKEY key;
3762     LPCWSTR lpKeyName;
3763     LONG l;
3764 
3765     TRACE("%s 0x%lx 0x%lx %s %p\n", debugstr_guid(ClassGuid), samDesired,
3766         Flags, debugstr_w(MachineName), Reserved);
3767 
3768     if (MachineName != NULL)
3769     {
3770         l = RegConnectRegistryW(MachineName, HKEY_LOCAL_MACHINE, &HKLM);
3771         if (l != ERROR_SUCCESS)
3772         {
3773             SetLastError(l);
3774             return INVALID_HANDLE_VALUE;
3775         }
3776     }
3777     else
3778         HKLM = HKEY_LOCAL_MACHINE;
3779 
3780     if (Flags == DIOCR_INSTALLER)
3781     {
3782         lpKeyName = REGSTR_PATH_CLASS_NT;
3783     }
3784     else if (Flags == DIOCR_INTERFACE)
3785     {
3786         lpKeyName = REGSTR_PATH_DEVICE_CLASSES;
3787     }
3788     else
3789     {
3790         ERR("Invalid Flags parameter!\n");
3791         SetLastError(ERROR_INVALID_FLAGS);
3792         if (MachineName != NULL) RegCloseKey(HKLM);
3793         return INVALID_HANDLE_VALUE;
3794     }
3795 
3796     if (!ClassGuid)
3797     {
3798         if ((l = RegOpenKeyExW(HKLM,
3799                                lpKeyName,
3800                                0,
3801                                samDesired,
3802                                &hClassesKey)))
3803         {
3804             SetLastError(ERROR_INVALID_CLASS);
3805             hClassesKey = INVALID_HANDLE_VALUE;
3806         }
3807         if (MachineName != NULL)
3808             RegCloseKey(HKLM);
3809         key = hClassesKey;
3810     }
3811     else
3812     {
3813         WCHAR bracedGuidString[39];
3814 
3815         SETUPDI_GuidToString(ClassGuid, bracedGuidString);
3816 
3817         if (!(l = RegOpenKeyExW(HKLM,
3818                                 lpKeyName,
3819                                 0,
3820                                 samDesired,
3821                                 &hClassesKey)))
3822         {
3823             if (MachineName != NULL)
3824                 RegCloseKey(HKLM);
3825 
3826             if ((l = RegOpenKeyExW(hClassesKey,
3827                                    bracedGuidString,
3828                                    0,
3829                                    samDesired,
3830                                    &key)))
3831             {
3832                 SetLastError(l);
3833                 key = INVALID_HANDLE_VALUE;
3834             }
3835             RegCloseKey(hClassesKey);
3836         }
3837         else
3838         {
3839             if (MachineName != NULL) RegCloseKey(HKLM);
3840             SetLastError(l);
3841             key = INVALID_HANDLE_VALUE;
3842         }
3843     }
3844 
3845     return key;
3846 }
3847 
3848 /***********************************************************************
3849  *		SetupDiOpenDeviceInterfaceW (SETUPAPI.@)
3850  */
3851 BOOL WINAPI SetupDiOpenDeviceInterfaceW(
3852         HDEVINFO DeviceInfoSet,
3853         PCWSTR DevicePath,
3854         DWORD OpenFlags,
3855         PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
3856 {
3857     struct DeviceInfoSet * list;
3858     PCWSTR pEnd;
3859     DWORD dwLength, dwError, dwIndex, dwKeyName, dwSubIndex;
3860     CLSID ClassId;
3861     WCHAR Buffer[MAX_PATH + 1];
3862     WCHAR SymBuffer[MAX_PATH + 1];
3863     WCHAR InstancePath[MAX_PATH + 1];
3864     HKEY hKey, hDevKey, hSymKey;
3865     struct DeviceInfo * deviceInfo;
3866     struct DeviceInterface *deviceInterface;
3867     BOOL Ret;
3868     PLIST_ENTRY ItemList;
3869     PLIST_ENTRY InterfaceListEntry;
3870 
3871     TRACE("%p %s %08x %p\n",
3872         DeviceInfoSet, debugstr_w(DevicePath), OpenFlags, DeviceInterfaceData);
3873 
3874 
3875     if (DeviceInterfaceData && DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA))
3876     {
3877         SetLastError(ERROR_INVALID_PARAMETER);
3878         return FALSE;
3879     }
3880 
3881     if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
3882     {
3883         SetLastError(ERROR_INVALID_HANDLE);
3884         return FALSE;
3885     }
3886 
3887     list = (struct DeviceInfoSet * )DeviceInfoSet;
3888 
3889     dwLength = wcslen(DevicePath);
3890     if (dwLength < 39)
3891     {
3892         /* path must be at least a guid length + L'\0' */
3893         SetLastError(ERROR_BAD_PATHNAME);
3894         return FALSE;
3895     }
3896 
3897     if (DevicePath[0] != L'\\' ||
3898         DevicePath[1] != L'\\' ||
3899         (DevicePath[2] != L'?' && DevicePath[2] != L'.') ||
3900         DevicePath[3] != L'\\')
3901     {
3902         /* invalid formatted path */
3903         SetLastError(ERROR_BAD_PATHNAME);
3904         return FALSE;
3905     }
3906 
3907     /* check for reference strings */
3908     pEnd = wcschr(&DevicePath[4], L'\\');
3909     if (!pEnd)
3910     {
3911         /* no reference string */
3912         pEnd = DevicePath + dwLength;
3913     }
3914 
3915     /* copy guid */
3916     wcscpy(Buffer, pEnd - 37);
3917     Buffer[36] = L'\0';
3918 
3919     dwError = UuidFromStringW(Buffer, &ClassId);
3920     if (dwError != NOERROR)
3921     {
3922         /* invalid formatted path */
3923         SetLastError(ERROR_BAD_PATHNAME);
3924         return FALSE;
3925     }
3926 
3927     hKey = SetupDiOpenClassRegKeyExW(&ClassId, KEY_READ, DIOCR_INTERFACE, list->MachineName, NULL);
3928 
3929     if (hKey == INVALID_HANDLE_VALUE)
3930     {
3931         /* invalid device class */
3932         return FALSE;
3933     }
3934 
3935     ItemList = list->ListHead.Flink;
3936     while (ItemList != &list->ListHead)
3937     {
3938         deviceInfo = CONTAINING_RECORD(ItemList, struct DeviceInfo, ListEntry);
3939         InterfaceListEntry = deviceInfo->InterfaceListHead.Flink;
3940         while (InterfaceListEntry != &deviceInfo->InterfaceListHead)
3941         {
3942             deviceInterface = CONTAINING_RECORD(InterfaceListEntry, struct DeviceInterface, ListEntry);
3943             if (!IsEqualIID(&deviceInterface->InterfaceClassGuid, &ClassId))
3944             {
3945                 InterfaceListEntry = InterfaceListEntry->Flink;
3946                 continue;
3947             }
3948 
3949             if (!wcsicmp(deviceInterface->SymbolicLink, DevicePath))
3950             {
3951                 if (DeviceInterfaceData)
3952                 {
3953                     DeviceInterfaceData->Reserved = (ULONG_PTR)deviceInterface;
3954                     DeviceInterfaceData->Flags = deviceInterface->Flags;
3955                     CopyMemory(&DeviceInterfaceData->InterfaceClassGuid, &ClassId, sizeof(GUID));
3956                 }
3957 
3958                 return TRUE;
3959             }
3960 
3961         }
3962     }
3963 
3964 
3965     dwIndex = 0;
3966     do
3967     {
3968         Buffer[0] = 0;
3969         dwKeyName = sizeof(Buffer) / sizeof(WCHAR);
3970         dwError = RegEnumKeyExW(hKey, dwIndex, Buffer, &dwKeyName, NULL, NULL, NULL, NULL);
3971 
3972         if (dwError != ERROR_SUCCESS)
3973             break;
3974 
3975         if (RegOpenKeyExW(hKey, Buffer, 0, KEY_READ, &hDevKey) != ERROR_SUCCESS)
3976             break;
3977 
3978         dwSubIndex = 0;
3979         InstancePath[0] = 0;
3980         dwKeyName = sizeof(InstancePath);
3981 
3982         dwError = RegQueryValueExW(hDevKey, L"DeviceInstance", NULL, NULL, (LPBYTE)InstancePath, &dwKeyName);
3983 
3984         while(TRUE)
3985         {
3986             Buffer[0] = 0;
3987             dwKeyName = sizeof(Buffer) / sizeof(WCHAR);
3988             dwError = RegEnumKeyExW(hDevKey, dwSubIndex, Buffer, &dwKeyName, NULL, NULL, NULL, NULL);
3989 
3990             if (dwError != ERROR_SUCCESS)
3991                 break;
3992 
3993             dwError = RegOpenKeyExW(hDevKey, Buffer, 0, KEY_READ, &hSymKey);
3994             if (dwError != ERROR_SUCCESS)
3995                 break;
3996 
3997             /* query for symbolic link */
3998             dwKeyName = sizeof(SymBuffer);
3999             SymBuffer[0] = L'\0';
4000             dwError = RegQueryValueExW(hSymKey, L"SymbolicLink", NULL, NULL, (LPBYTE)SymBuffer, &dwKeyName);
4001 
4002             if (dwError != ERROR_SUCCESS)
4003             {
4004                 RegCloseKey(hSymKey);
4005                 break;
4006             }
4007 
4008             if (!wcsicmp(SymBuffer, DevicePath))
4009             {
4010                 Ret = CreateDeviceInfo(list, InstancePath, &ClassId, &deviceInfo);
4011                 RegCloseKey(hSymKey);
4012                 RegCloseKey(hDevKey);
4013                 RegCloseKey(hKey);
4014 
4015                 if (Ret)
4016                 {
4017                     deviceInterface = HeapAlloc(GetProcessHeap(), 0, sizeof(struct DeviceInterface) + (wcslen(SymBuffer) + 1) * sizeof(WCHAR));
4018                     if (deviceInterface)
4019                     {
4020 
4021                         CopyMemory(&deviceInterface->InterfaceClassGuid, &ClassId, sizeof(GUID));
4022                         deviceInterface->DeviceInfo = deviceInfo;
4023                         deviceInterface->Flags = SPINT_ACTIVE; //FIXME
4024 
4025                         wcscpy(deviceInterface->SymbolicLink, SymBuffer);
4026 
4027                         InsertTailList(&deviceInfo->InterfaceListHead, &deviceInterface->ListEntry);
4028                         InsertTailList(&list->ListHead, &deviceInfo->ListEntry);
4029 
4030 
4031                         if (DeviceInterfaceData)
4032                         {
4033                             DeviceInterfaceData->Reserved = (ULONG_PTR)deviceInterface;
4034                             DeviceInterfaceData->Flags = deviceInterface->Flags;
4035                             CopyMemory(&DeviceInterfaceData->InterfaceClassGuid, &ClassId, sizeof(GUID));
4036                         }
4037                         else
4038                         {
4039                             Ret = FALSE;
4040                             SetLastError(ERROR_INVALID_USER_BUFFER);
4041                         }
4042                     }
4043                 }
4044                 else
4045                 {
4046                     HeapFree(GetProcessHeap(), 0, deviceInfo);
4047                     Ret = FALSE;
4048                 }
4049                 return Ret;
4050         }
4051         RegCloseKey(hSymKey);
4052         dwSubIndex++;
4053     }
4054 
4055     RegCloseKey(hDevKey);
4056     dwIndex++;
4057     } while(TRUE);
4058 
4059     RegCloseKey(hKey);
4060     return FALSE;
4061 }
4062 
4063 /***********************************************************************
4064  *		SetupDiOpenDeviceInterfaceA (SETUPAPI.@)
4065  */
4066 BOOL WINAPI SetupDiOpenDeviceInterfaceA(
4067         HDEVINFO DeviceInfoSet,
4068         PCSTR DevicePath,
4069         DWORD OpenFlags,
4070         PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
4071 {
4072     LPWSTR DevicePathW = NULL;
4073     BOOL bResult;
4074 
4075     TRACE("%p %s %08lx %p\n", DeviceInfoSet, debugstr_a(DevicePath), OpenFlags, DeviceInterfaceData);
4076 
4077     DevicePathW = pSetupMultiByteToUnicode(DevicePath, CP_ACP);
4078     if (DevicePathW == NULL)
4079         return FALSE;
4080 
4081     bResult = SetupDiOpenDeviceInterfaceW(DeviceInfoSet,
4082         DevicePathW, OpenFlags, DeviceInterfaceData);
4083 
4084     MyFree(DevicePathW);
4085 
4086     return bResult;
4087 }
4088 
4089 /***********************************************************************
4090  *		SetupDiSetClassInstallParamsA (SETUPAPI.@)
4091  */
4092 BOOL WINAPI SetupDiSetClassInstallParamsA(
4093         HDEVINFO  DeviceInfoSet,
4094         PSP_DEVINFO_DATA DeviceInfoData,
4095         PSP_CLASSINSTALL_HEADER ClassInstallParams,
4096         DWORD ClassInstallParamsSize)
4097 {
4098     FIXME("%p %p %x %u\n",DeviceInfoSet, DeviceInfoData,
4099           ClassInstallParams->InstallFunction, ClassInstallParamsSize);
4100     return FALSE;
4101 }
4102 
4103 static BOOL WINAPI
4104 IntSetupDiRegisterDeviceInfo(
4105         IN HDEVINFO DeviceInfoSet,
4106         IN OUT PSP_DEVINFO_DATA DeviceInfoData)
4107 {
4108     return SetupDiRegisterDeviceInfo(DeviceInfoSet, DeviceInfoData, 0, NULL, NULL, NULL);
4109 }
4110 
4111 /***********************************************************************
4112  *		SetupDiCallClassInstaller (SETUPAPI.@)
4113  */
4114 BOOL WINAPI SetupDiCallClassInstaller(
4115         DI_FUNCTION InstallFunction,
4116         HDEVINFO DeviceInfoSet,
4117         PSP_DEVINFO_DATA DeviceInfoData)
4118 {
4119     BOOL ret = FALSE;
4120 
4121     TRACE("%u %p %p\n", InstallFunction, DeviceInfoSet, DeviceInfoData);
4122 
4123     if (!DeviceInfoSet)
4124         SetLastError(ERROR_INVALID_PARAMETER);
4125     else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
4126         SetLastError(ERROR_INVALID_HANDLE);
4127     else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
4128         SetLastError(ERROR_INVALID_HANDLE);
4129     else if (((struct DeviceInfoSet *)DeviceInfoSet)->HKLM != HKEY_LOCAL_MACHINE)
4130         SetLastError(ERROR_INVALID_HANDLE);
4131     else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
4132         SetLastError(ERROR_INVALID_USER_BUFFER);
4133     else
4134     {
4135         SP_DEVINSTALL_PARAMS_W InstallParams;
4136 #define CLASS_COINSTALLER  0x1
4137 #define DEVICE_COINSTALLER 0x2
4138 #define CLASS_INSTALLER    0x4
4139         UCHAR CanHandle = 0;
4140         DEFAULT_CLASS_INSTALL_PROC DefaultHandler = NULL;
4141 
4142         switch (InstallFunction)
4143         {
4144             case DIF_ADDPROPERTYPAGE_ADVANCED:
4145                 CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
4146                 break;
4147             case DIF_ADDREMOTEPROPERTYPAGE_ADVANCED:
4148                 CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
4149                 break;
4150             case DIF_ALLOW_INSTALL:
4151                 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4152                 break;
4153             case DIF_DETECT:
4154                 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4155                 break;
4156             case DIF_DESTROYPRIVATEDATA:
4157                 CanHandle = CLASS_INSTALLER;
4158                 break;
4159             case DIF_INSTALLDEVICE:
4160                 CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
4161                 DefaultHandler = SetupDiInstallDevice;
4162                 break;
4163             case DIF_INSTALLDEVICEFILES:
4164                 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4165                 DefaultHandler = SetupDiInstallDriverFiles;
4166                 break;
4167             case DIF_INSTALLINTERFACES:
4168                 CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
4169                 DefaultHandler = SetupDiInstallDeviceInterfaces;
4170                 break;
4171             case DIF_NEWDEVICEWIZARD_FINISHINSTALL:
4172                 CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
4173                 break;
4174             case DIF_NEWDEVICEWIZARD_POSTANALYZE:
4175                 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4176                 break;
4177             case DIF_NEWDEVICEWIZARD_PREANALYZE:
4178                 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4179                 break;
4180             case DIF_NEWDEVICEWIZARD_PRESELECT:
4181                 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4182                 break;
4183             case DIF_NEWDEVICEWIZARD_SELECT:
4184                 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4185                 break;
4186             case DIF_POWERMESSAGEWAKE:
4187                 CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
4188                 break;
4189             case DIF_PROPERTYCHANGE:
4190                 CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
4191                 DefaultHandler = SetupDiChangeState;
4192                 break;
4193             case DIF_REGISTER_COINSTALLERS:
4194                 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4195                 DefaultHandler = SetupDiRegisterCoDeviceInstallers;
4196                 break;
4197             case DIF_REGISTERDEVICE:
4198                 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4199                 DefaultHandler = IntSetupDiRegisterDeviceInfo;
4200                 break;
4201             case DIF_REMOVE:
4202                 CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
4203                 DefaultHandler = SetupDiRemoveDevice;
4204                 break;
4205             case DIF_SELECTBESTCOMPATDRV:
4206                 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4207                 DefaultHandler = SetupDiSelectBestCompatDrv;
4208                 break;
4209             case DIF_SELECTDEVICE:
4210                 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4211                 DefaultHandler = SetupDiSelectDevice;
4212                 break;
4213             case DIF_TROUBLESHOOTER:
4214                 CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
4215                 break;
4216             case DIF_UNREMOVE:
4217                 CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
4218                 DefaultHandler = SetupDiUnremoveDevice;
4219                 break;
4220             default:
4221                 ERR("Install function %u not supported\n", InstallFunction);
4222                 SetLastError(ERROR_NOT_SUPPORTED);
4223         }
4224 
4225         InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
4226         if (!SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams))
4227             /* Don't process this call, as a parameter is invalid */
4228             CanHandle = 0;
4229 
4230         if (CanHandle != 0)
4231         {
4232             LIST_ENTRY ClassCoInstallersListHead;
4233             LIST_ENTRY DeviceCoInstallersListHead;
4234             HMODULE ClassInstallerLibrary = NULL;
4235             CLASS_INSTALL_PROC ClassInstaller = NULL;
4236             COINSTALLER_CONTEXT_DATA Context;
4237             PLIST_ENTRY ListEntry;
4238             HKEY hKey;
4239             DWORD dwRegType, dwLength;
4240             DWORD rc = NO_ERROR;
4241 
4242             InitializeListHead(&ClassCoInstallersListHead);
4243             InitializeListHead(&DeviceCoInstallersListHead);
4244 
4245             if (CanHandle & DEVICE_COINSTALLER)
4246             {
4247                 hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_QUERY_VALUE);
4248                 if (hKey != INVALID_HANDLE_VALUE)
4249                 {
4250                     rc = RegQueryValueExW(hKey, REGSTR_VAL_COINSTALLERS_32, NULL, &dwRegType, NULL, &dwLength);
4251                     if (rc == ERROR_SUCCESS && dwRegType == REG_MULTI_SZ)
4252                     {
4253                         LPWSTR KeyBuffer = HeapAlloc(GetProcessHeap(), 0, dwLength);
4254                         if (KeyBuffer != NULL)
4255                         {
4256                             rc = RegQueryValueExW(hKey, REGSTR_VAL_COINSTALLERS_32, NULL, NULL, (LPBYTE)KeyBuffer, &dwLength);
4257                             if (rc == ERROR_SUCCESS)
4258                             {
4259                                 LPWSTR ptr;
4260                                 for (ptr = KeyBuffer; *ptr; ptr += strlenW(ptr) + 1)
4261                                 {
4262                                     /* Add coinstaller to DeviceCoInstallersListHead list */
4263                                     struct CoInstallerElement *coinstaller;
4264                                     TRACE("Got device coinstaller '%s'\n", debugstr_w(ptr));
4265                                     coinstaller = HeapAlloc(GetProcessHeap(), 0, sizeof(struct CoInstallerElement));
4266                                     if (!coinstaller)
4267                                         continue;
4268                                     ZeroMemory(coinstaller, sizeof(struct CoInstallerElement));
4269                                     if (GetFunctionPointer(ptr, &coinstaller->Module, (PVOID*)&coinstaller->Function) == ERROR_SUCCESS)
4270                                         InsertTailList(&DeviceCoInstallersListHead, &coinstaller->ListEntry);
4271                                     else
4272                                         HeapFree(GetProcessHeap(), 0, coinstaller);
4273                                 }
4274                             }
4275                             HeapFree(GetProcessHeap(), 0, KeyBuffer);
4276                         }
4277                     }
4278                     RegCloseKey(hKey);
4279                 }
4280             }
4281             if (CanHandle & CLASS_COINSTALLER)
4282             {
4283                 rc = RegOpenKeyExW(
4284                     HKEY_LOCAL_MACHINE,
4285                     REGSTR_PATH_CODEVICEINSTALLERS,
4286                     0, /* Options */
4287                     KEY_QUERY_VALUE,
4288                     &hKey);
4289                 if (rc == ERROR_SUCCESS)
4290                 {
4291                     WCHAR szGuidString[40];
4292                     if (pSetupStringFromGuid(&DeviceInfoData->ClassGuid, szGuidString, ARRAYSIZE(szGuidString)) == ERROR_SUCCESS)
4293                     {
4294                         rc = RegQueryValueExW(hKey, szGuidString, NULL, &dwRegType, NULL, &dwLength);
4295                         if (rc == ERROR_SUCCESS && dwRegType == REG_MULTI_SZ)
4296                         {
4297                             LPWSTR KeyBuffer = HeapAlloc(GetProcessHeap(), 0, dwLength);
4298                             if (KeyBuffer != NULL)
4299                             {
4300                                 rc = RegQueryValueExW(hKey, szGuidString, NULL, NULL, (LPBYTE)KeyBuffer, &dwLength);
4301                                 if (rc == ERROR_SUCCESS)
4302                                 {
4303                                     LPWSTR ptr;
4304                                     for (ptr = KeyBuffer; *ptr; ptr += strlenW(ptr) + 1)
4305                                     {
4306                                         /* Add coinstaller to ClassCoInstallersListHead list */
4307                                         struct CoInstallerElement *coinstaller;
4308                                         TRACE("Got class coinstaller '%s'\n", debugstr_w(ptr));
4309                                         coinstaller = HeapAlloc(GetProcessHeap(), 0, sizeof(struct CoInstallerElement));
4310                                         if (!coinstaller)
4311                                             continue;
4312                                         ZeroMemory(coinstaller, sizeof(struct CoInstallerElement));
4313                                         if (GetFunctionPointer(ptr, &coinstaller->Module, (PVOID*)&coinstaller->Function) == ERROR_SUCCESS)
4314                                             InsertTailList(&ClassCoInstallersListHead, &coinstaller->ListEntry);
4315                                         else
4316                                             HeapFree(GetProcessHeap(), 0, coinstaller);
4317                                     }
4318                                 }
4319                                 HeapFree(GetProcessHeap(), 0, KeyBuffer);
4320                             }
4321                         }
4322                     }
4323                     RegCloseKey(hKey);
4324                 }
4325             }
4326             if ((CanHandle & CLASS_INSTALLER) && !(InstallParams.FlagsEx & DI_FLAGSEX_CI_FAILED))
4327             {
4328                 hKey = SetupDiOpenClassRegKey(&DeviceInfoData->ClassGuid, KEY_QUERY_VALUE);
4329                 if (hKey != INVALID_HANDLE_VALUE)
4330                 {
4331                     rc = RegQueryValueExW(hKey, REGSTR_VAL_INSTALLER_32, NULL, &dwRegType, NULL, &dwLength);
4332                     if (rc == ERROR_SUCCESS && dwRegType == REG_SZ)
4333                     {
4334                         LPWSTR KeyBuffer = HeapAlloc(GetProcessHeap(), 0, dwLength);
4335                         if (KeyBuffer != NULL)
4336                         {
4337                             rc = RegQueryValueExW(hKey, REGSTR_VAL_INSTALLER_32, NULL, NULL, (LPBYTE)KeyBuffer, &dwLength);
4338                             if (rc == ERROR_SUCCESS)
4339                             {
4340                                 /* Get ClassInstaller function pointer */
4341                                 TRACE("Got class installer '%s'\n", debugstr_w(KeyBuffer));
4342                                 if (GetFunctionPointer(KeyBuffer, &ClassInstallerLibrary, (PVOID*)&ClassInstaller) != ERROR_SUCCESS)
4343                                 {
4344                                     InstallParams.FlagsEx |= DI_FLAGSEX_CI_FAILED;
4345                                     SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
4346                                 }
4347                             }
4348                             HeapFree(GetProcessHeap(), 0, KeyBuffer);
4349                         }
4350                     }
4351                     RegCloseKey(hKey);
4352                 }
4353             }
4354 
4355             /* Call Class co-installers */
4356             Context.PostProcessing = FALSE;
4357             rc = NO_ERROR;
4358             ListEntry = ClassCoInstallersListHead.Flink;
4359             while (rc == NO_ERROR && ListEntry != &ClassCoInstallersListHead)
4360             {
4361                 struct CoInstallerElement *coinstaller;
4362                 coinstaller = CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry);
4363                 rc = (*coinstaller->Function)(InstallFunction, DeviceInfoSet, DeviceInfoData, &Context);
4364                 coinstaller->PrivateData = Context.PrivateData;
4365                 if (rc == ERROR_DI_POSTPROCESSING_REQUIRED)
4366                 {
4367                     coinstaller->DoPostProcessing = TRUE;
4368                     rc = NO_ERROR;
4369                 }
4370                 ListEntry = ListEntry->Flink;
4371             }
4372 
4373             /* Call Device co-installers */
4374             ListEntry = DeviceCoInstallersListHead.Flink;
4375             while (rc == NO_ERROR && ListEntry != &DeviceCoInstallersListHead)
4376             {
4377                 struct CoInstallerElement *coinstaller;
4378                 coinstaller = CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry);
4379                 rc = (*coinstaller->Function)(InstallFunction, DeviceInfoSet, DeviceInfoData, &Context);
4380                 coinstaller->PrivateData = Context.PrivateData;
4381                 if (rc == ERROR_DI_POSTPROCESSING_REQUIRED)
4382                 {
4383                     coinstaller->DoPostProcessing = TRUE;
4384                     rc = NO_ERROR;
4385                 }
4386                 ListEntry = ListEntry->Flink;
4387             }
4388 
4389             /* Call Class installer */
4390             if (ClassInstaller)
4391             {
4392                 rc = (*ClassInstaller)(InstallFunction, DeviceInfoSet, DeviceInfoData);
4393                 FreeFunctionPointer(ClassInstallerLibrary, ClassInstaller);
4394             }
4395             else
4396                 rc = ERROR_DI_DO_DEFAULT;
4397 
4398             /* Call default handler */
4399             if (rc == ERROR_DI_DO_DEFAULT)
4400             {
4401                 if (DefaultHandler && !(InstallParams.Flags & DI_NODI_DEFAULTACTION))
4402                 {
4403                     if ((*DefaultHandler)(DeviceInfoSet, DeviceInfoData))
4404                         rc = NO_ERROR;
4405                     else
4406                         rc = GetLastError();
4407                 }
4408                 else
4409                     rc = NO_ERROR;
4410             }
4411 
4412             /* Call Class co-installers that required postprocessing */
4413             Context.PostProcessing = TRUE;
4414             ListEntry = ClassCoInstallersListHead.Flink;
4415             while (ListEntry != &ClassCoInstallersListHead)
4416             {
4417                 struct CoInstallerElement *coinstaller;
4418                 coinstaller = CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry);
4419                 if (coinstaller->DoPostProcessing)
4420                 {
4421                     Context.InstallResult = rc;
4422                     Context.PrivateData = coinstaller->PrivateData;
4423                     rc = (*coinstaller->Function)(InstallFunction, DeviceInfoSet, DeviceInfoData, &Context);
4424                 }
4425                 FreeFunctionPointer(coinstaller->Module, coinstaller->Function);
4426                 ListEntry = ListEntry->Flink;
4427             }
4428 
4429             /* Call Device co-installers that required postprocessing */
4430             ListEntry = DeviceCoInstallersListHead.Flink;
4431             while (ListEntry != &DeviceCoInstallersListHead)
4432             {
4433                 struct CoInstallerElement *coinstaller;
4434                 coinstaller = CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry);
4435                 if (coinstaller->DoPostProcessing)
4436                 {
4437                     Context.InstallResult = rc;
4438                     Context.PrivateData = coinstaller->PrivateData;
4439                     rc = (*coinstaller->Function)(InstallFunction, DeviceInfoSet, DeviceInfoData, &Context);
4440                 }
4441                 FreeFunctionPointer(coinstaller->Module, coinstaller->Function);
4442                 ListEntry = ListEntry->Flink;
4443             }
4444 
4445             /* Free allocated memory */
4446             while (!IsListEmpty(&ClassCoInstallersListHead))
4447             {
4448                 ListEntry = RemoveHeadList(&ClassCoInstallersListHead);
4449                 HeapFree(GetProcessHeap(), 0, CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry));
4450             }
4451             while (!IsListEmpty(&DeviceCoInstallersListHead))
4452             {
4453                 ListEntry = RemoveHeadList(&DeviceCoInstallersListHead);
4454                 HeapFree(GetProcessHeap(), 0, CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry));
4455             }
4456 
4457             ret = (rc == NO_ERROR);
4458         }
4459     }
4460 
4461     TRACE("Returning %d\n", ret);
4462     return ret;
4463 }
4464 
4465 /***********************************************************************
4466  *		SetupDiGetDeviceInstallParamsA (SETUPAPI.@)
4467  */
4468 BOOL WINAPI SetupDiGetDeviceInstallParamsA(
4469         HDEVINFO DeviceInfoSet,
4470         PSP_DEVINFO_DATA DeviceInfoData,
4471         PSP_DEVINSTALL_PARAMS_A DeviceInstallParams)
4472 {
4473     SP_DEVINSTALL_PARAMS_W deviceInstallParamsW;
4474     BOOL ret = FALSE;
4475 
4476     TRACE("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstallParams);
4477 
4478     if (DeviceInstallParams == NULL)
4479         SetLastError(ERROR_INVALID_PARAMETER);
4480     else if (DeviceInstallParams->cbSize != sizeof(SP_DEVINSTALL_PARAMS_A))
4481         SetLastError(ERROR_INVALID_USER_BUFFER);
4482     else
4483     {
4484         deviceInstallParamsW.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
4485         ret = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &deviceInstallParamsW);
4486 
4487         if (ret)
4488         {
4489             /* Do W->A conversion */
4490             memcpy(
4491                 DeviceInstallParams,
4492                 &deviceInstallParamsW,
4493                 FIELD_OFFSET(SP_DEVINSTALL_PARAMS_W, DriverPath));
4494             if (WideCharToMultiByte(CP_ACP, 0, deviceInstallParamsW.DriverPath, -1,
4495                 DeviceInstallParams->DriverPath, MAX_PATH, NULL, NULL) == 0)
4496             {
4497                 DeviceInstallParams->DriverPath[0] = '\0';
4498                 ret = FALSE;
4499             }
4500         }
4501     }
4502 
4503     TRACE("Returning %d\n", ret);
4504     return ret;
4505 }
4506 
4507 /***********************************************************************
4508  *		SetupDiGetDeviceInfoListClass  (SETUPAPI.@)
4509  */
4510 BOOL WINAPI
4511 SetupDiGetDeviceInfoListClass(
4512         IN HDEVINFO DeviceInfoSet,
4513         OUT LPGUID ClassGuid)
4514 {
4515     struct DeviceInfoSet *list;
4516     BOOL ret = FALSE;
4517 
4518     TRACE("%p %p\n", DeviceInfoSet, ClassGuid);
4519 
4520     if (!DeviceInfoSet)
4521         SetLastError(ERROR_INVALID_HANDLE);
4522     else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
4523         SetLastError(ERROR_INVALID_HANDLE);
4524     else if (IsEqualIID(&list->ClassGuid, &GUID_NULL))
4525         SetLastError(ERROR_NO_ASSOCIATED_CLASS);
4526     else
4527     {
4528         memcpy(&ClassGuid, &list->ClassGuid, sizeof(GUID));
4529 
4530         ret = TRUE;
4531     }
4532 
4533     TRACE("Returning %d\n", ret);
4534     return ret;
4535 }
4536 
4537 /***********************************************************************
4538  *		SetupDiGetDeviceInstallParamsW (SETUPAPI.@)
4539  */
4540 BOOL WINAPI
4541 SetupDiGetDeviceInstallParamsW(
4542         IN HDEVINFO DeviceInfoSet,
4543         IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
4544         OUT PSP_DEVINSTALL_PARAMS_W DeviceInstallParams)
4545 {
4546     struct DeviceInfoSet *list;
4547     BOOL ret = FALSE;
4548 
4549     TRACE("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstallParams);
4550 
4551     if (!DeviceInfoSet)
4552         SetLastError(ERROR_INVALID_HANDLE);
4553     else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
4554         SetLastError(ERROR_INVALID_HANDLE);
4555     else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
4556         SetLastError(ERROR_INVALID_USER_BUFFER);
4557     else if (!DeviceInstallParams)
4558         SetLastError(ERROR_INVALID_PARAMETER);
4559     else if (DeviceInstallParams->cbSize != sizeof(SP_DEVINSTALL_PARAMS_W))
4560         SetLastError(ERROR_INVALID_USER_BUFFER);
4561     else
4562     {
4563         PSP_DEVINSTALL_PARAMS_W Source;
4564 
4565         if (DeviceInfoData)
4566             Source = &((struct DeviceInfo *)DeviceInfoData->Reserved)->InstallParams;
4567         else
4568             Source = &list->InstallParams;
4569 
4570         ret = TRUE;
4571 
4572         _SEH2_TRY
4573         {
4574             memcpy(DeviceInstallParams, Source, Source->cbSize);
4575         }
4576         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4577         {
4578             SetLastError(RtlNtStatusToDosError(_SEH2_GetExceptionCode()));
4579             ret = FALSE;
4580         }
4581         _SEH2_END;
4582     }
4583 
4584     TRACE("Returning %d\n", ret);
4585     return ret;
4586 }
4587 
4588 static BOOL
4589 CheckDeviceInstallParameters(
4590         IN PSP_DEVINSTALL_PARAMS_W DeviceInstallParams)
4591 {
4592     DWORD SupportedFlags =
4593         DI_NOVCP |                            /* 0x00000008 */
4594         DI_DIDCOMPAT |                        /* 0x00000010 */
4595         DI_DIDCLASS |                         /* 0x00000020 */
4596         DI_NEEDRESTART |                      /* 0x00000080 */
4597         DI_NEEDREBOOT |                       /* 0x00000100 */
4598         DI_RESOURCEPAGE_ADDED |               /* 0x00002000 */
4599         DI_PROPERTIES_CHANGE |                /* 0x00004000 */
4600         DI_ENUMSINGLEINF |                    /* 0x00010000 */
4601         DI_DONOTCALLCONFIGMG |                /* 0x00020000 */
4602         DI_CLASSINSTALLPARAMS |               /* 0x00100000 */
4603         DI_NODI_DEFAULTACTION |               /* 0x00200000 */
4604         DI_QUIETINSTALL |                     /* 0x00800000 */
4605         DI_NOFILECOPY |                       /* 0x01000000 */
4606         DI_DRIVERPAGE_ADDED;                  /* 0x04000000 */
4607     DWORD SupportedFlagsEx =
4608         DI_FLAGSEX_CI_FAILED |                /* 0x00000004 */
4609         DI_FLAGSEX_DIDINFOLIST |              /* 0x00000010 */
4610         DI_FLAGSEX_DIDCOMPATINFO |            /* 0x00000020 */
4611         DI_FLAGSEX_ALLOWEXCLUDEDDRVS |        /* 0x00000800 */
4612         DI_FLAGSEX_NO_DRVREG_MODIFY |         /* 0x00008000 */
4613         DI_FLAGSEX_INSTALLEDDRIVER;           /* 0x04000000 */
4614     BOOL ret = FALSE;
4615 
4616     /* FIXME: add support for more flags */
4617 
4618     /* FIXME: DI_CLASSINSTALLPARAMS flag is not correctly used.
4619      * It should be checked before accessing to other values
4620      * of the SP_DEVINSTALL_PARAMS structure */
4621 
4622     if (DeviceInstallParams->Flags & ~SupportedFlags)
4623     {
4624         FIXME("Unknown Flags: 0x%08lx\n", DeviceInstallParams->Flags & ~SupportedFlags);
4625         SetLastError(ERROR_INVALID_FLAGS);
4626     }
4627     else if (DeviceInstallParams->FlagsEx & ~SupportedFlagsEx)
4628     {
4629         FIXME("Unknown FlagsEx: 0x%08lx\n", DeviceInstallParams->FlagsEx & ~SupportedFlagsEx);
4630         SetLastError(ERROR_INVALID_FLAGS);
4631     }
4632     else if ((DeviceInstallParams->Flags & DI_NOVCP)
4633         && (DeviceInstallParams->FileQueue == NULL || DeviceInstallParams->FileQueue == (HSPFILEQ)INVALID_HANDLE_VALUE))
4634         SetLastError(ERROR_INVALID_USER_BUFFER);
4635     else
4636     {
4637         /* FIXME: check Reserved field */
4638         ret = TRUE;
4639     }
4640 
4641     return ret;
4642 }
4643 
4644 /***********************************************************************
4645  *		SetupDiSetDeviceInstallParamsW (SETUPAPI.@)
4646  */
4647 BOOL WINAPI
4648 SetupDiSetDeviceInstallParamsW(
4649         IN HDEVINFO DeviceInfoSet,
4650         IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
4651         IN PSP_DEVINSTALL_PARAMS_W DeviceInstallParams)
4652 {
4653     struct DeviceInfoSet *list;
4654     BOOL ret = FALSE;
4655 
4656     TRACE("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstallParams);
4657 
4658     if (!DeviceInfoSet)
4659         SetLastError(ERROR_INVALID_HANDLE);
4660     else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
4661         SetLastError(ERROR_INVALID_HANDLE);
4662     else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
4663         SetLastError(ERROR_INVALID_USER_BUFFER);
4664     else if (!DeviceInstallParams)
4665         SetLastError(ERROR_INVALID_PARAMETER);
4666     else if (DeviceInstallParams->cbSize != sizeof(SP_DEVINSTALL_PARAMS_W))
4667         SetLastError(ERROR_INVALID_USER_BUFFER);
4668     else if (CheckDeviceInstallParameters(DeviceInstallParams))
4669     {
4670         PSP_DEVINSTALL_PARAMS_W Destination;
4671 
4672         if (DeviceInfoData)
4673             Destination = &((struct DeviceInfo *)DeviceInfoData->Reserved)->InstallParams;
4674         else
4675             Destination = &list->InstallParams;
4676         memcpy(Destination, DeviceInstallParams, DeviceInstallParams->cbSize);
4677         ret = TRUE;
4678     }
4679 
4680     TRACE("Returning %d\n", ret);
4681     return ret;
4682 }
4683 
4684 /***********************************************************************
4685  *		SetupDiSetDeviceInstallParamsW (SETUPAPI.@)
4686  */
4687 BOOL WINAPI
4688 SetupDiSetDeviceInstallParamsA(
4689         HDEVINFO DeviceInfoSet,
4690         PSP_DEVINFO_DATA DeviceInfoData,
4691         PSP_DEVINSTALL_PARAMS_A DeviceInstallParams)
4692 {
4693     SP_DEVINSTALL_PARAMS_W deviceInstallParamsW;
4694     int len = 0;
4695     BOOL ret = FALSE;
4696 
4697     TRACE("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstallParams);
4698 
4699     if (DeviceInstallParams == NULL)
4700         SetLastError(ERROR_INVALID_PARAMETER);
4701     else if (DeviceInstallParams->cbSize < sizeof(SP_DEVINSTALL_PARAMS_A))
4702         SetLastError(ERROR_INVALID_USER_BUFFER);
4703     else
4704     {
4705         memcpy(&deviceInstallParamsW, DeviceInstallParams, FIELD_OFFSET(SP_DEVINSTALL_PARAMS_A, DriverPath));
4706         deviceInstallParamsW.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
4707         len = MultiByteToWideChar(CP_ACP, 0, DeviceInstallParams->DriverPath, -1, NULL, 0);
4708         if (!len)
4709         {
4710             ERR("DrivePath is NULL\n");
4711             ret = FALSE;
4712         }
4713         else
4714         {
4715             MultiByteToWideChar(CP_ACP, 0, DeviceInstallParams->DriverPath, -1, deviceInstallParamsW.DriverPath, len);
4716             ret = SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &deviceInstallParamsW);
4717         }
4718     }
4719 
4720     TRACE("Returning %d\n", ret);
4721     return ret;
4722 }
4723 
4724 static HKEY
4725 OpenHardwareProfileKey(
4726         IN HKEY HKLM,
4727         IN DWORD HwProfile,
4728         IN DWORD samDesired)
4729 {
4730     HKEY hHWProfilesKey = NULL;
4731     HKEY hHWProfileKey = NULL;
4732     HKEY ret = INVALID_HANDLE_VALUE;
4733     LONG rc;
4734 
4735     rc = RegOpenKeyExW(HKLM,
4736                        REGSTR_PATH_HWPROFILES,
4737                        0,
4738                        READ_CONTROL,
4739                        &hHWProfilesKey);
4740     if (rc != ERROR_SUCCESS)
4741     {
4742         SetLastError(rc);
4743         goto cleanup;
4744     }
4745     if (HwProfile == 0)
4746     {
4747         rc = RegOpenKeyExW(hHWProfilesKey,
4748                            REGSTR_KEY_CURRENT,
4749                            0,
4750                            KEY_CREATE_SUB_KEY,
4751                            &hHWProfileKey);
4752     }
4753     else
4754     {
4755         WCHAR subKey[5];
4756         snprintfW(subKey, 4, InstanceKeyFormat, HwProfile);
4757         subKey[4] = '\0';
4758         rc = RegOpenKeyExW(hHWProfilesKey,
4759                            subKey,
4760                            0,
4761                            KEY_CREATE_SUB_KEY,
4762                            &hHWProfileKey);
4763     }
4764     if (rc != ERROR_SUCCESS)
4765     {
4766         SetLastError(rc);
4767         goto cleanup;
4768     }
4769     ret = hHWProfileKey;
4770 
4771 cleanup:
4772     if (hHWProfilesKey != NULL)
4773         RegCloseKey(hHWProfilesKey);
4774     if (hHWProfileKey != NULL && hHWProfileKey != ret)
4775         RegCloseKey(hHWProfileKey);
4776     return ret;
4777 }
4778 
4779 static BOOL
4780 IsDeviceInfoInDeviceInfoSet(
4781         struct DeviceInfoSet *deviceInfoSet,
4782         struct DeviceInfo *deviceInfo)
4783 {
4784     PLIST_ENTRY ListEntry;
4785 
4786     ListEntry = deviceInfoSet->ListHead.Flink;
4787     while (ListEntry != &deviceInfoSet->ListHead)
4788     {
4789         if (deviceInfo == CONTAINING_RECORD(ListEntry, struct DeviceInfo, ListEntry))
4790             return TRUE;
4791 
4792         ListEntry = ListEntry->Flink;
4793     }
4794 
4795     return FALSE;
4796 }
4797 
4798 /***********************************************************************
4799  *		SetupDiDeleteDeviceInfo (SETUPAPI.@)
4800  */
4801 BOOL WINAPI
4802 SetupDiDeleteDeviceInfo(
4803         IN HDEVINFO DeviceInfoSet,
4804         IN PSP_DEVINFO_DATA DeviceInfoData)
4805 {
4806     struct DeviceInfoSet *deviceInfoSet;
4807     struct DeviceInfo *deviceInfo = (struct DeviceInfo *)DeviceInfoData;
4808     BOOL ret = FALSE;
4809 
4810     TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
4811 
4812     if (!DeviceInfoSet)
4813         SetLastError(ERROR_INVALID_HANDLE);
4814     else if ((deviceInfoSet = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
4815         SetLastError(ERROR_INVALID_HANDLE);
4816     else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
4817         SetLastError(ERROR_INVALID_USER_BUFFER);
4818     else if (!IsDeviceInfoInDeviceInfoSet(deviceInfoSet, deviceInfo))
4819         SetLastError(ERROR_INVALID_PARAMETER);
4820     else
4821     {
4822         RemoveEntryList(&deviceInfo->ListEntry);
4823         DestroyDeviceInfo(deviceInfo);
4824         ret = TRUE;
4825     }
4826 
4827     return ret;
4828 }
4829 
4830 
4831 /***********************************************************************
4832  *		SetupDiOpenDeviceInfoA (SETUPAPI.@)
4833  */
4834 BOOL WINAPI
4835 SetupDiOpenDeviceInfoA(
4836         IN HDEVINFO DeviceInfoSet,
4837         IN PCSTR DeviceInstanceId,
4838         IN HWND hwndParent OPTIONAL,
4839         IN DWORD OpenFlags,
4840         OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
4841 {
4842     LPWSTR DeviceInstanceIdW = NULL;
4843     BOOL bResult;
4844 
4845     TRACE("%p %s %p %lx %p\n", DeviceInfoSet, DeviceInstanceId, hwndParent, OpenFlags, DeviceInfoData);
4846 
4847     DeviceInstanceIdW = pSetupMultiByteToUnicode(DeviceInstanceId, CP_ACP);
4848     if (DeviceInstanceIdW == NULL)
4849         return FALSE;
4850 
4851     bResult = SetupDiOpenDeviceInfoW(DeviceInfoSet,
4852         DeviceInstanceIdW, hwndParent, OpenFlags, DeviceInfoData);
4853 
4854     MyFree(DeviceInstanceIdW);
4855 
4856     return bResult;
4857 }
4858 
4859 
4860 /***********************************************************************
4861  *		SetupDiOpenDeviceInfoW (SETUPAPI.@)
4862  */
4863 BOOL WINAPI
4864 SetupDiOpenDeviceInfoW(
4865         IN HDEVINFO DeviceInfoSet,
4866         IN PCWSTR DeviceInstanceId,
4867         IN HWND hwndParent OPTIONAL,
4868         IN DWORD OpenFlags,
4869         OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
4870 {
4871     struct DeviceInfoSet *list;
4872     HKEY hEnumKey, hKey = NULL;
4873     DWORD rc, dwSize;
4874     BOOL ret = FALSE;
4875 
4876     TRACE("%p %s %p %lx %p\n",
4877         DeviceInfoSet, debugstr_w(DeviceInstanceId),
4878         hwndParent, OpenFlags, DeviceInfoData);
4879 
4880     if (OpenFlags & DIOD_CANCEL_REMOVE)
4881         FIXME("DIOD_CANCEL_REMOVE flag not implemented\n");
4882 
4883     if (!DeviceInfoSet)
4884         SetLastError(ERROR_INVALID_HANDLE);
4885     else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
4886         SetLastError(ERROR_INVALID_HANDLE);
4887     else if (!DeviceInstanceId)
4888         SetLastError(ERROR_INVALID_PARAMETER);
4889     else if (OpenFlags & ~(DIOD_CANCEL_REMOVE | DIOD_INHERIT_CLASSDRVS))
4890     {
4891         TRACE("Unknown flags: 0x%08lx\n", OpenFlags & ~(DIOD_CANCEL_REMOVE | DIOD_INHERIT_CLASSDRVS));
4892         SetLastError(ERROR_INVALID_FLAGS);
4893     }
4894     else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
4895         SetLastError(ERROR_INVALID_USER_BUFFER);
4896     else
4897     {
4898         struct DeviceInfo *deviceInfo = NULL;
4899         /* Search if device already exists in DeviceInfoSet.
4900          *    If yes, return the existing element
4901          *    If no, create a new element using information in registry
4902          */
4903         PLIST_ENTRY ItemList = list->ListHead.Flink;
4904         while (ItemList != &list->ListHead)
4905         {
4906             deviceInfo = CONTAINING_RECORD(ItemList, struct DeviceInfo, ListEntry);
4907             if (!wcscmp(deviceInfo->instanceId, DeviceInstanceId))
4908                 break;
4909             deviceInfo = NULL;
4910             ItemList = ItemList->Flink;
4911         }
4912 
4913         if (deviceInfo)
4914         {
4915             /* good one found */
4916             ret = TRUE;
4917         }
4918         else
4919         {
4920             GUID ClassGUID;
4921             WCHAR szClassGuid[MAX_GUID_STRING_LEN];
4922 
4923             /* Open supposed registry key */
4924             rc = RegOpenKeyExW(
4925                 list->HKLM,
4926                 REGSTR_PATH_SYSTEMENUM,
4927                 0, /* Options */
4928                 READ_CONTROL,
4929                 &hEnumKey);
4930             if (rc != ERROR_SUCCESS)
4931             {
4932                 SetLastError(rc);
4933                 goto cleanup;
4934             }
4935             rc = RegOpenKeyExW(
4936                 hEnumKey,
4937                 DeviceInstanceId,
4938                 0, /* Options */
4939                 KEY_QUERY_VALUE,
4940                 &hKey);
4941             RegCloseKey(hEnumKey);
4942             if (rc != ERROR_SUCCESS)
4943             {
4944                 if (rc == ERROR_FILE_NOT_FOUND)
4945                     rc = ERROR_NO_SUCH_DEVINST;
4946                 SetLastError(rc);
4947                 goto cleanup;
4948             }
4949 
4950             ClassGUID = GUID_NULL;
4951             dwSize = MAX_GUID_STRING_LEN * sizeof(WCHAR);
4952 
4953             if (RegQueryValueExW(hKey,
4954                                  REGSTR_VAL_CLASSGUID,
4955                                  NULL,
4956                                  NULL,
4957                                  (LPBYTE)szClassGuid,
4958                                  &dwSize) == ERROR_SUCCESS)
4959             {
4960                 szClassGuid[MAX_GUID_STRING_LEN - 2] = UNICODE_NULL;
4961 
4962                 /* Convert a string to a ClassGuid */
4963                 UuidFromStringW(&szClassGuid[1], &ClassGUID);
4964             }
4965 
4966             if (!CreateDeviceInfo(list, DeviceInstanceId, &ClassGUID, &deviceInfo))
4967                 goto cleanup;
4968 
4969             InsertTailList(&list->ListHead, &deviceInfo->ListEntry);
4970 
4971             ret = TRUE;
4972         }
4973 
4974         if (ret && deviceInfo && DeviceInfoData)
4975         {
4976             memcpy(&DeviceInfoData->ClassGuid, &deviceInfo->ClassGuid, sizeof(GUID));
4977             DeviceInfoData->DevInst = deviceInfo->dnDevInst;
4978             DeviceInfoData->Reserved = (ULONG_PTR)deviceInfo;
4979         }
4980     }
4981 
4982 cleanup:
4983     if (hKey != NULL)
4984         RegCloseKey(hKey);
4985     return ret;
4986 }
4987 
4988 
4989 /***********************************************************************
4990  *		SetupDiGetSelectedDevice (SETUPAPI.@)
4991  */
4992 BOOL WINAPI
4993 SetupDiGetSelectedDevice(
4994         IN HDEVINFO DeviceInfoSet,
4995         OUT PSP_DEVINFO_DATA DeviceInfoData)
4996 {
4997     struct DeviceInfoSet *list;
4998     BOOL ret = FALSE;
4999 
5000     TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
5001 
5002     if (!DeviceInfoSet)
5003         SetLastError(ERROR_INVALID_HANDLE);
5004     else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
5005         SetLastError(ERROR_INVALID_HANDLE);
5006     else if (list->SelectedDevice == NULL)
5007         SetLastError(ERROR_NO_DEVICE_SELECTED);
5008     else if (!DeviceInfoData)
5009         SetLastError(ERROR_INVALID_PARAMETER);
5010     else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
5011         SetLastError(ERROR_INVALID_USER_BUFFER);
5012     else
5013     {
5014         memcpy(&DeviceInfoData->ClassGuid,
5015             &list->SelectedDevice->ClassGuid,
5016             sizeof(GUID));
5017         DeviceInfoData->DevInst = list->SelectedDevice->dnDevInst;
5018         DeviceInfoData->Reserved = (ULONG_PTR)list->SelectedDevice;
5019         ret = TRUE;
5020     }
5021 
5022     TRACE("Returning %d\n", ret);
5023     return ret;
5024 }
5025 
5026 
5027 /***********************************************************************
5028  *		SetupDiSetSelectedDevice (SETUPAPI.@)
5029  */
5030 BOOL WINAPI
5031 SetupDiSetSelectedDevice(
5032         IN HDEVINFO DeviceInfoSet,
5033         IN PSP_DEVINFO_DATA DeviceInfoData)
5034 {
5035     struct DeviceInfoSet *list;
5036     BOOL ret = FALSE;
5037 
5038     TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
5039 
5040     if (!DeviceInfoSet)
5041         SetLastError(ERROR_INVALID_HANDLE);
5042     else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
5043         SetLastError(ERROR_INVALID_HANDLE);
5044     else if (!DeviceInfoData)
5045         SetLastError(ERROR_INVALID_PARAMETER);
5046     else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
5047         SetLastError(ERROR_INVALID_USER_BUFFER);
5048     else if (DeviceInfoData->Reserved == 0)
5049         SetLastError(ERROR_INVALID_USER_BUFFER);
5050     else
5051     {
5052         list->SelectedDevice = (struct DeviceInfo *)DeviceInfoData->Reserved;
5053         ret = TRUE;
5054     }
5055 
5056     TRACE("Returning %d\n", ret);
5057     return ret;
5058 }
5059 
5060 
5061 /* Return the current hardware profile id, or -1 if error */
5062 static DWORD
5063 SETUPAPI_GetCurrentHwProfile(
5064         IN HDEVINFO DeviceInfoSet)
5065 {
5066     HKEY hKey = NULL;
5067     DWORD dwRegType, dwLength;
5068     DWORD hwProfile;
5069     LONG rc;
5070     DWORD ret = (DWORD)-1;
5071 
5072     rc = RegOpenKeyExW(((struct DeviceInfoSet *)DeviceInfoSet)->HKLM,
5073                        REGSTR_PATH_IDCONFIGDB,
5074                        0, /* Options */
5075                        KEY_QUERY_VALUE,
5076                        &hKey);
5077     if (rc != ERROR_SUCCESS)
5078     {
5079         SetLastError(rc);
5080         goto cleanup;
5081     }
5082 
5083     dwLength = sizeof(DWORD);
5084     rc = RegQueryValueExW(hKey,
5085                           REGSTR_VAL_CURRENTCONFIG,
5086                           NULL,
5087                           &dwRegType,
5088                           (LPBYTE)&hwProfile, &dwLength);
5089     if (rc != ERROR_SUCCESS)
5090     {
5091         SetLastError(rc);
5092         goto cleanup;
5093     }
5094     else if (dwRegType != REG_DWORD || dwLength != sizeof(DWORD))
5095     {
5096         SetLastError(ERROR_GEN_FAILURE);
5097         goto cleanup;
5098     }
5099 
5100     ret = hwProfile;
5101 
5102 cleanup:
5103     if (hKey != NULL)
5104         RegCloseKey(hKey);
5105 
5106     return ret;
5107 }
5108 
5109 static BOOL
5110 ResetDevice(
5111         IN HDEVINFO DeviceInfoSet,
5112         IN PSP_DEVINFO_DATA DeviceInfoData)
5113 {
5114 #ifndef __WINESRC__
5115     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
5116     struct DeviceInfo *deviceInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
5117     CONFIGRET cr;
5118 
5119     cr = CM_Enable_DevNode_Ex(deviceInfo->dnDevInst, 0, set->hMachine);
5120     if (cr != CR_SUCCESS)
5121     {
5122         SetLastError(GetErrorCodeFromCrCode(cr));
5123         return FALSE;
5124     }
5125 
5126     return TRUE;
5127 #else
5128     FIXME("Stub: ResetDevice(%p %p)\n", DeviceInfoSet, DeviceInfoData);
5129     return TRUE;
5130 #endif
5131 }
5132 
5133 static BOOL StopDevice(
5134         IN HDEVINFO DeviceInfoSet,
5135         IN PSP_DEVINFO_DATA DeviceInfoData)
5136 {
5137     FIXME("Stub: StopDevice(%p %p)\n", DeviceInfoSet, DeviceInfoData);
5138     return TRUE;
5139 }
5140 
5141 /***********************************************************************
5142  *		SetupDiChangeState (SETUPAPI.@)
5143  */
5144 BOOL WINAPI
5145 SetupDiChangeState(
5146         IN HDEVINFO DeviceInfoSet,
5147         IN OUT PSP_DEVINFO_DATA DeviceInfoData)
5148 {
5149     PSP_PROPCHANGE_PARAMS PropChange;
5150     HKEY hKey = INVALID_HANDLE_VALUE;
5151     LPCWSTR RegistryValueName;
5152     DWORD dwConfigFlags, dwLength, dwRegType;
5153     LONG rc;
5154     BOOL ret = FALSE;
5155 
5156     TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
5157 
5158     if (!DeviceInfoData)
5159         PropChange = ((struct DeviceInfoSet *)DeviceInfoSet)->ClassInstallParams.PropChangeParams;
5160     else
5161         PropChange = ((struct DeviceInfo *)DeviceInfoData->Reserved)->ClassInstallParams.PropChangeParams;
5162     if (!PropChange)
5163     {
5164         SetLastError(ERROR_INVALID_PARAMETER);
5165         goto cleanup;
5166     }
5167 
5168     if (PropChange->Scope == DICS_FLAG_GLOBAL)
5169         RegistryValueName = REGSTR_VAL_CONFIGFLAGS;
5170     else
5171         RegistryValueName = REGSTR_VAL_CSCONFIGFLAGS;
5172 
5173     switch (PropChange->StateChange)
5174     {
5175         case DICS_ENABLE:
5176         case DICS_DISABLE:
5177         {
5178             /* Enable/disable device in registry */
5179             hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, PropChange->Scope, PropChange->HwProfile, DIREG_DEV, KEY_QUERY_VALUE | KEY_SET_VALUE);
5180             if (hKey == INVALID_HANDLE_VALUE && GetLastError() == ERROR_FILE_NOT_FOUND)
5181                 hKey = SetupDiCreateDevRegKeyW(DeviceInfoSet, DeviceInfoData, PropChange->Scope, PropChange->HwProfile, DIREG_DEV, NULL, NULL);
5182             if (hKey == INVALID_HANDLE_VALUE)
5183                 break;
5184             dwLength = sizeof(DWORD);
5185             rc = RegQueryValueExW(
5186                 hKey,
5187                 RegistryValueName,
5188                 NULL,
5189                 &dwRegType,
5190                 (LPBYTE)&dwConfigFlags, &dwLength);
5191             if (rc == ERROR_FILE_NOT_FOUND)
5192                 dwConfigFlags = 0;
5193             else if (rc != ERROR_SUCCESS)
5194             {
5195                 SetLastError(rc);
5196                 goto cleanup;
5197             }
5198             else if (dwRegType != REG_DWORD || dwLength != sizeof(DWORD))
5199             {
5200                 SetLastError(ERROR_GEN_FAILURE);
5201                 goto cleanup;
5202             }
5203             if (PropChange->StateChange == DICS_ENABLE)
5204                 dwConfigFlags &= ~(PropChange->Scope == DICS_FLAG_GLOBAL ? CONFIGFLAG_DISABLED : CSCONFIGFLAG_DISABLED);
5205             else
5206                 dwConfigFlags |= (PropChange->Scope == DICS_FLAG_GLOBAL ? CONFIGFLAG_DISABLED : CSCONFIGFLAG_DISABLED);
5207             rc = RegSetValueExW(
5208                 hKey,
5209                 RegistryValueName,
5210                 0,
5211                 REG_DWORD,
5212                 (LPBYTE)&dwConfigFlags, sizeof(DWORD));
5213             if (rc != ERROR_SUCCESS)
5214             {
5215                 SetLastError(rc);
5216                 goto cleanup;
5217             }
5218 
5219             /* Enable/disable device if needed */
5220             if (PropChange->Scope == DICS_FLAG_GLOBAL
5221                 || PropChange->HwProfile == 0
5222                 || PropChange->HwProfile == SETUPAPI_GetCurrentHwProfile(DeviceInfoSet))
5223             {
5224                 if (PropChange->StateChange == DICS_ENABLE)
5225                     ret = ResetDevice(DeviceInfoSet, DeviceInfoData);
5226                 else
5227                     ret = StopDevice(DeviceInfoSet, DeviceInfoData);
5228             }
5229             else
5230                 ret = TRUE;
5231             break;
5232         }
5233         case DICS_PROPCHANGE:
5234         {
5235             ret = ResetDevice(DeviceInfoSet, DeviceInfoData);
5236             break;
5237         }
5238         default:
5239         {
5240             ERR("Unknown StateChange 0x%lx\n", PropChange->StateChange);
5241             SetLastError(ERROR_NOT_SUPPORTED);
5242         }
5243     }
5244 
5245 cleanup:
5246     if (hKey != INVALID_HANDLE_VALUE)
5247         RegCloseKey(hKey);
5248 
5249     TRACE("Returning %d\n", ret);
5250     return ret;
5251 }
5252 
5253 /***********************************************************************
5254  *		SetupDiSelectDevice (SETUPAPI.@)
5255  */
5256 BOOL WINAPI
5257 SetupDiSelectDevice(
5258         IN HDEVINFO DeviceInfoSet,
5259         IN OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
5260 {
5261     FIXME("%p %p\n", DeviceInfoSet, DeviceInfoData);
5262     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5263     return FALSE;
5264 }
5265 
5266 
5267 /***********************************************************************
5268  *		SetupDiRegisterCoDeviceInstallers (SETUPAPI.@)
5269  */
5270 BOOL WINAPI
5271 SetupDiRegisterCoDeviceInstallers(
5272         IN HDEVINFO DeviceInfoSet,
5273         IN PSP_DEVINFO_DATA DeviceInfoData)
5274 {
5275     BOOL ret = FALSE; /* Return value */
5276 
5277     TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
5278 
5279     if (!DeviceInfoSet)
5280         SetLastError(ERROR_INVALID_PARAMETER);
5281     else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
5282         SetLastError(ERROR_INVALID_HANDLE);
5283     else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
5284         SetLastError(ERROR_INVALID_HANDLE);
5285     else if (!DeviceInfoData)
5286         SetLastError(ERROR_INVALID_PARAMETER);
5287     else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
5288         SetLastError(ERROR_INVALID_USER_BUFFER);
5289     else
5290     {
5291         SP_DEVINSTALL_PARAMS_W InstallParams;
5292         struct DriverInfoElement *SelectedDriver;
5293         BOOL Result;
5294         DWORD DoAction;
5295         WCHAR SectionName[MAX_PATH];
5296         DWORD SectionNameLength = 0;
5297         HKEY hKey = INVALID_HANDLE_VALUE;
5298         PVOID Context = NULL;
5299 
5300         InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
5301         Result = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
5302         if (!Result)
5303             goto cleanup;
5304 
5305         SelectedDriver = (struct DriverInfoElement *)InstallParams.Reserved;
5306         if (SelectedDriver == NULL)
5307         {
5308             SetLastError(ERROR_NO_DRIVER_SELECTED);
5309             goto cleanup;
5310         }
5311 
5312         /* Get .CoInstallers section name */
5313         Result = SetupDiGetActualSectionToInstallW(
5314             SelectedDriver->InfFileDetails->hInf,
5315             SelectedDriver->Details.SectionName,
5316             SectionName, MAX_PATH, &SectionNameLength, NULL);
5317         if (!Result || SectionNameLength > MAX_PATH - strlenW(DotCoInstallers) - 1)
5318             goto cleanup;
5319         lstrcatW(SectionName, DotCoInstallers);
5320 
5321         /* Open/Create driver key information */
5322 #if _WIN32_WINNT >= 0x502
5323         hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_READ | KEY_WRITE);
5324 #else
5325         hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_ALL_ACCESS);
5326 #endif
5327         if (hKey == INVALID_HANDLE_VALUE && GetLastError() == ERROR_FILE_NOT_FOUND)
5328             hKey = SetupDiCreateDevRegKeyW(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, NULL, NULL);
5329         if (hKey == INVALID_HANDLE_VALUE)
5330             goto cleanup;
5331 
5332         /* Install .CoInstallers section */
5333         DoAction = SPINST_REGISTRY;
5334         if (!(InstallParams.Flags & DI_NOFILECOPY))
5335         {
5336             DoAction |= SPINST_FILES;
5337             Context = SetupInitDefaultQueueCallback(InstallParams.hwndParent);
5338             if (!Context)
5339                 goto cleanup;
5340         }
5341         Result = SetupInstallFromInfSectionW(InstallParams.hwndParent,
5342             SelectedDriver->InfFileDetails->hInf, SectionName,
5343             DoAction, hKey, SelectedDriver->InfFileDetails->DirectoryName, SP_COPY_NEWER,
5344             SetupDefaultQueueCallbackW, Context,
5345             DeviceInfoSet, DeviceInfoData);
5346         if (!Result)
5347             goto cleanup;
5348 
5349         ret = TRUE;
5350 
5351 cleanup:
5352         if (Context)
5353             SetupTermDefaultQueueCallback(Context);
5354         if (hKey != INVALID_HANDLE_VALUE)
5355             RegCloseKey(hKey);
5356     }
5357 
5358     TRACE("Returning %d\n", ret);
5359     return ret;
5360 }
5361 
5362 static BOOL
5363 InfIsFromOEMLocation(
5364         IN PCWSTR FullName,
5365         OUT LPBOOL IsOEMLocation)
5366 {
5367     PWCHAR last;
5368 
5369     last = strrchrW(FullName, '\\');
5370     if (!last)
5371     {
5372         /* No directory specified */
5373         *IsOEMLocation = FALSE;
5374     }
5375     else
5376     {
5377         LPWSTR Windir;
5378         UINT ret;
5379 
5380         Windir = MyMalloc((MAX_PATH + 1 + strlenW(InfDirectory)) * sizeof(WCHAR));
5381         if (!Windir)
5382         {
5383             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
5384             return FALSE;
5385         }
5386 
5387         ret = GetSystemWindowsDirectoryW(Windir, MAX_PATH);
5388         if (ret == 0 || ret > MAX_PATH)
5389         {
5390             MyFree(Windir);
5391             SetLastError(ERROR_GEN_FAILURE);
5392             return FALSE;
5393         }
5394         if (*Windir && Windir[strlenW(Windir) - 1] != '\\')
5395             strcatW(Windir, BackSlash);
5396         strcatW(Windir, InfDirectory);
5397 
5398         if (strncmpiW(FullName, Windir, last - FullName) == 0)
5399         {
5400             /* The path is %SYSTEMROOT%\Inf */
5401             *IsOEMLocation = FALSE;
5402         }
5403         else
5404         {
5405             /* The file is in another place */
5406             *IsOEMLocation = TRUE;
5407         }
5408         MyFree(Windir);
5409     }
5410     return TRUE;
5411 }
5412 
5413 /***********************************************************************
5414  *		SetupDiInstallDevice (SETUPAPI.@)
5415  */
5416 BOOL WINAPI
5417 SetupDiInstallDevice(
5418         IN HDEVINFO DeviceInfoSet,
5419         IN OUT PSP_DEVINFO_DATA DeviceInfoData)
5420 {
5421     SP_DEVINSTALL_PARAMS_W InstallParams;
5422     struct DriverInfoElement *SelectedDriver;
5423     SYSTEMTIME DriverDate;
5424     WCHAR SectionName[MAX_PATH];
5425     WCHAR Buffer[32];
5426     DWORD SectionNameLength = 0;
5427     BOOL Result = FALSE;
5428     ULONG DoAction;
5429     DWORD RequiredSize;
5430     LPWSTR pSectionName = NULL;
5431     WCHAR ClassName[MAX_CLASS_NAME_LEN];
5432     GUID ClassGuid;
5433     LPWSTR lpGuidString = NULL, lpFullGuidString = NULL;
5434     BOOL RebootRequired = FALSE;
5435     HKEY hKey = INVALID_HANDLE_VALUE;
5436     BOOL NeedtoCopyFile;
5437     LARGE_INTEGER fullVersion;
5438     LONG rc;
5439     PVOID Context = NULL;
5440     BOOL ret = FALSE; /* Return value */
5441 
5442     TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
5443 
5444     if (!DeviceInfoSet)
5445         SetLastError(ERROR_INVALID_PARAMETER);
5446     else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
5447         SetLastError(ERROR_INVALID_HANDLE);
5448     else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
5449         SetLastError(ERROR_INVALID_HANDLE);
5450     else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
5451         SetLastError(ERROR_INVALID_USER_BUFFER);
5452     else
5453         Result = TRUE;
5454 
5455     if (!Result)
5456     {
5457         /* One parameter is bad */
5458         goto cleanup;
5459     }
5460 
5461     InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
5462     Result = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
5463     if (!Result)
5464         goto cleanup;
5465 
5466     if (InstallParams.FlagsEx & DI_FLAGSEX_SETFAILEDINSTALL)
5467     {
5468         /* Set FAILEDINSTALL in ConfigFlags registry value */
5469         DWORD ConfigFlags, regType;
5470         Result = SetupDiGetDeviceRegistryPropertyW(
5471             DeviceInfoSet,
5472             DeviceInfoData,
5473             SPDRP_CONFIGFLAGS,
5474             &regType,
5475             (PBYTE)&ConfigFlags,
5476             sizeof(ConfigFlags),
5477             NULL);
5478         if (!Result || regType != REG_DWORD)
5479         {
5480             SetLastError(ERROR_GEN_FAILURE);
5481             goto cleanup;
5482         }
5483         ConfigFlags |= DNF_DISABLED;
5484         Result = SetupDiSetDeviceRegistryPropertyW(
5485             DeviceInfoSet,
5486             DeviceInfoData,
5487             SPDRP_CONFIGFLAGS,
5488             (PBYTE)&ConfigFlags,
5489             sizeof(ConfigFlags));
5490         if (!Result)
5491         {
5492             SetLastError(ERROR_GEN_FAILURE);
5493             goto cleanup;
5494         }
5495 
5496         ret = TRUE;
5497         goto cleanup;
5498     }
5499 
5500     SelectedDriver = (struct DriverInfoElement *)InstallParams.Reserved;
5501     if (SelectedDriver == NULL)
5502     {
5503         SetLastError(ERROR_NO_DRIVER_SELECTED);
5504         goto cleanup;
5505     }
5506 
5507     FileTimeToSystemTime(&SelectedDriver->Info.DriverDate, &DriverDate);
5508 
5509     Result = SetupDiGetActualSectionToInstallW(
5510         SelectedDriver->InfFileDetails->hInf,
5511         SelectedDriver->Details.SectionName,
5512         SectionName, MAX_PATH, &SectionNameLength, NULL);
5513     if (!Result || SectionNameLength > MAX_PATH - strlenW(DotServices))
5514         goto cleanup;
5515     pSectionName = &SectionName[strlenW(SectionName)];
5516 
5517     /* Get information from [Version] section */
5518     if (!SetupDiGetINFClassW(SelectedDriver->Details.InfFileName, &ClassGuid, ClassName, MAX_CLASS_NAME_LEN, &RequiredSize))
5519         goto cleanup;
5520     /* Format ClassGuid to a string */
5521     if (UuidToStringW((UUID*)&ClassGuid, &lpGuidString) != RPC_S_OK)
5522         goto cleanup;
5523     RequiredSize = lstrlenW(lpGuidString);
5524     lpFullGuidString = HeapAlloc(GetProcessHeap(), 0, (RequiredSize + 3) * sizeof(WCHAR));
5525     if (!lpFullGuidString)
5526     {
5527         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
5528         goto cleanup;
5529     }
5530     lpFullGuidString[0] = '{';
5531     memcpy(&lpFullGuidString[1], lpGuidString, RequiredSize * sizeof(WCHAR));
5532     lpFullGuidString[RequiredSize + 1] = '}';
5533     lpFullGuidString[RequiredSize + 2] = '\0';
5534 
5535     /* Copy .inf file to Inf\ directory (if needed) */
5536     Result = InfIsFromOEMLocation(SelectedDriver->Details.InfFileName, &NeedtoCopyFile);
5537     if (!Result)
5538         goto cleanup;
5539     if (NeedtoCopyFile)
5540     {
5541         WCHAR NewFileName[MAX_PATH];
5542         struct InfFileDetails *newInfFileDetails;
5543         Result = SetupCopyOEMInfW(
5544             SelectedDriver->Details.InfFileName,
5545             NULL,
5546             SPOST_NONE,
5547             SP_COPY_NOOVERWRITE,
5548             NewFileName, MAX_PATH,
5549             NULL,
5550             NULL);
5551         if (!Result && GetLastError() != ERROR_FILE_EXISTS)
5552             goto cleanup;
5553         /* Create a new struct InfFileDetails, and set it to
5554          * SelectedDriver->InfFileDetails, to release use of
5555          * current InfFile */
5556         newInfFileDetails = CreateInfFileDetails(NewFileName);
5557         if (!newInfFileDetails)
5558             goto cleanup;
5559         DereferenceInfFile(SelectedDriver->InfFileDetails);
5560         SelectedDriver->InfFileDetails = newInfFileDetails;
5561         strcpyW(SelectedDriver->Details.InfFileName, NewFileName);
5562     }
5563 
5564     /* Open/Create driver key information */
5565 #if _WIN32_WINNT >= 0x502
5566     hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_READ | KEY_WRITE);
5567 #else
5568     hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_ALL_ACCESS);
5569 #endif
5570     if (hKey == INVALID_HANDLE_VALUE && GetLastError() == ERROR_FILE_NOT_FOUND)
5571         hKey = SetupDiCreateDevRegKeyW(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, NULL, NULL);
5572     if (hKey == INVALID_HANDLE_VALUE)
5573         goto cleanup;
5574 
5575     /* Install main section */
5576     DoAction = 0;
5577     if (!(InstallParams.FlagsEx & DI_FLAGSEX_NO_DRVREG_MODIFY))
5578         DoAction |= SPINST_REGISTRY;
5579     if (!(InstallParams.Flags & DI_NOFILECOPY))
5580     {
5581         DoAction |= SPINST_FILES;
5582         Context = SetupInitDefaultQueueCallback(InstallParams.hwndParent);
5583         if (!Context)
5584             goto cleanup;
5585     }
5586     *pSectionName = '\0';
5587     Result = SetupInstallFromInfSectionW(InstallParams.hwndParent,
5588         SelectedDriver->InfFileDetails->hInf, SectionName,
5589         DoAction, hKey, SelectedDriver->InfFileDetails->DirectoryName, SP_COPY_NEWER,
5590         SetupDefaultQueueCallbackW, Context,
5591         DeviceInfoSet, DeviceInfoData);
5592     if (!Result)
5593         goto cleanup;
5594     InstallParams.Flags |= DI_NOFILECOPY;
5595     SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
5596 
5597     /* Write information to driver key */
5598     *pSectionName = UNICODE_NULL;
5599     memcpy(&fullVersion, &SelectedDriver->Info.DriverVersion, sizeof(LARGE_INTEGER));
5600     TRACE("Write information to driver key\n");
5601     TRACE("DriverDate      : '%u-%u-%u'\n", DriverDate.wMonth, DriverDate.wDay, DriverDate.wYear);
5602     TRACE("DriverDesc      : '%s'\n", debugstr_w(SelectedDriver->Info.Description));
5603     TRACE("DriverVersion   : '%ld.%ld.%lu.%ld'\n", fullVersion.HighPart >> 16, fullVersion.HighPart & 0xffff, fullVersion.LowPart >> 16, fullVersion.LowPart & 0xffff);
5604     TRACE("InfPath         : '%s'\n", debugstr_w(SelectedDriver->InfFileDetails->FileName));
5605     TRACE("InfSection      : '%s'\n", debugstr_w(SelectedDriver->Details.SectionName));
5606     TRACE("InfSectionExt   : '%s'\n", debugstr_w(&SectionName[strlenW(SelectedDriver->Details.SectionName)]));
5607     TRACE("MatchingDeviceId: '%s'\n", debugstr_w(SelectedDriver->MatchingId));
5608     TRACE("ProviderName    : '%s'\n", debugstr_w(SelectedDriver->Info.ProviderName));
5609     sprintfW(Buffer, DateFormat, DriverDate.wMonth, DriverDate.wDay, DriverDate.wYear);
5610     rc = RegSetValueExW(hKey, REGSTR_DRIVER_DATE, 0, REG_SZ, (const BYTE *)Buffer, (strlenW(Buffer) + 1) * sizeof(WCHAR));
5611     if (rc == ERROR_SUCCESS)
5612         rc = RegSetValueExW(hKey, REGSTR_DRIVER_DATE_DATA, 0, REG_BINARY, (const BYTE *)&SelectedDriver->Info.DriverDate, sizeof(FILETIME));
5613     if (rc == ERROR_SUCCESS)
5614         rc = RegSetValueExW(hKey, REGSTR_VAL_DRVDESC, 0, REG_SZ, (const BYTE *)SelectedDriver->Info.Description, (strlenW(SelectedDriver->Info.Description) + 1) * sizeof(WCHAR));
5615     if (rc == ERROR_SUCCESS)
5616     {
5617         sprintfW(Buffer, VersionFormat, fullVersion.HighPart >> 16, fullVersion.HighPart & 0xffff, fullVersion.LowPart >> 16, fullVersion.LowPart & 0xffff);
5618         rc = RegSetValueExW(hKey, REGSTR_DRIVER_VERSION, 0, REG_SZ, (const BYTE *)Buffer, (strlenW(Buffer) + 1) * sizeof(WCHAR));
5619     }
5620     if (rc == ERROR_SUCCESS)
5621         rc = RegSetValueExW(hKey, REGSTR_VAL_INFPATH, 0, REG_SZ, (const BYTE *)SelectedDriver->InfFileDetails->FileName, (strlenW(SelectedDriver->InfFileDetails->FileName) + 1) * sizeof(WCHAR));
5622     if (rc == ERROR_SUCCESS)
5623         rc = RegSetValueExW(hKey, REGSTR_VAL_INFSECTION, 0, REG_SZ, (const BYTE *)SelectedDriver->Details.SectionName, (strlenW(SelectedDriver->Details.SectionName) + 1) * sizeof(WCHAR));
5624     if (rc == ERROR_SUCCESS)
5625         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));
5626     if (rc == ERROR_SUCCESS)
5627         rc = RegSetValueExW(hKey, REGSTR_VAL_MATCHINGDEVID, 0, REG_SZ, (const BYTE *)SelectedDriver->MatchingId, (strlenW(SelectedDriver->MatchingId) + 1) * sizeof(WCHAR));
5628     if (rc == ERROR_SUCCESS)
5629         rc = RegSetValueExW(hKey, REGSTR_VAL_PROVIDER_NAME, 0, REG_SZ, (const BYTE *)SelectedDriver->Info.ProviderName, (strlenW(SelectedDriver->Info.ProviderName) + 1) * sizeof(WCHAR));
5630     if (rc != ERROR_SUCCESS)
5631     {
5632        SetLastError(rc);
5633        goto cleanup;
5634     }
5635     RegCloseKey(hKey);
5636     hKey = INVALID_HANDLE_VALUE;
5637 
5638     /* FIXME: Process .LogConfigOverride section */
5639 
5640     /* Install .Services section */
5641     strcpyW(pSectionName, DotServices);
5642     Result = SetupInstallServicesFromInfSectionExW(
5643         SelectedDriver->InfFileDetails->hInf,
5644         SectionName,
5645         0,
5646         DeviceInfoSet,
5647         DeviceInfoData,
5648         NULL,
5649         NULL);
5650     if (!Result)
5651         goto cleanup;
5652     if (GetLastError() == ERROR_SUCCESS_REBOOT_REQUIRED)
5653         RebootRequired = TRUE;
5654 
5655     /* Open device registry key */
5656     hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_SET_VALUE);
5657     if (hKey == INVALID_HANDLE_VALUE)
5658         goto cleanup;
5659 
5660     /* Install .HW section */
5661     DoAction = 0;
5662     if (!(InstallParams.FlagsEx & DI_FLAGSEX_NO_DRVREG_MODIFY))
5663         DoAction |= SPINST_REGISTRY;
5664     strcpyW(pSectionName, DotHW);
5665     Result = SetupInstallFromInfSectionW(InstallParams.hwndParent,
5666         SelectedDriver->InfFileDetails->hInf, SectionName,
5667         DoAction, hKey, NULL, 0,
5668         NULL, NULL,
5669         DeviceInfoSet, DeviceInfoData);
5670     if (!Result)
5671         goto cleanup;
5672 
5673     /* Write information to enum key */
5674     TRACE("Write information to enum key\n");
5675     TRACE("Class           : '%s'\n", debugstr_w(ClassName));
5676     TRACE("ClassGUID       : '%s'\n", debugstr_w(lpFullGuidString));
5677     TRACE("DeviceDesc      : '%s'\n", debugstr_w(SelectedDriver->Info.Description));
5678     TRACE("Mfg             : '%s'\n", debugstr_w(SelectedDriver->Info.MfgName));
5679     rc = RegSetValueExW(hKey, REGSTR_VAL_CLASS, 0, REG_SZ, (const BYTE *)ClassName, (strlenW(ClassName) + 1) * sizeof(WCHAR));
5680     if (rc == ERROR_SUCCESS)
5681         rc = RegSetValueExW(hKey, REGSTR_VAL_CLASSGUID, 0, REG_SZ, (const BYTE *)lpFullGuidString, (strlenW(lpFullGuidString) + 1) * sizeof(WCHAR));
5682     if (rc == ERROR_SUCCESS)
5683         rc = RegSetValueExW(hKey, REGSTR_VAL_DEVDESC, 0, REG_SZ, (const BYTE *)SelectedDriver->Info.Description, (strlenW(SelectedDriver->Info.Description) + 1) * sizeof(WCHAR));
5684     if (rc == ERROR_SUCCESS)
5685         rc = RegSetValueExW(hKey, REGSTR_VAL_MFG, 0, REG_SZ, (const BYTE *)SelectedDriver->Info.MfgName, (strlenW(SelectedDriver->Info.MfgName) + 1) * sizeof(WCHAR));
5686     if (rc != ERROR_SUCCESS)
5687     {
5688        SetLastError(rc);
5689        goto cleanup;
5690     }
5691 
5692     /* Start the device */
5693     if (!RebootRequired && !(InstallParams.Flags & (DI_NEEDRESTART | DI_NEEDREBOOT | DI_DONOTCALLCONFIGMG)))
5694         ret = ResetDevice(DeviceInfoSet, DeviceInfoData);
5695     else
5696         ret = TRUE;
5697 
5698 cleanup:
5699     /* End of installation */
5700     if (hKey != INVALID_HANDLE_VALUE)
5701         RegCloseKey(hKey);
5702     if (lpGuidString)
5703         RpcStringFreeW(&lpGuidString);
5704     HeapFree(GetProcessHeap(), 0, lpFullGuidString);
5705     if (Context)
5706         SetupTermDefaultQueueCallback(Context);
5707     TRACE("Returning %d\n", ret);
5708     return ret;
5709 }
5710 
5711 static HKEY SETUPDI_OpenDevKey(HKEY RootKey, struct DeviceInfo *devInfo, REGSAM samDesired)
5712 {
5713     HKEY enumKey, key = INVALID_HANDLE_VALUE;
5714     LONG l;
5715 
5716     l = RegOpenKeyExW(RootKey, REGSTR_PATH_SYSTEMENUM, 0, READ_CONTROL, &enumKey);
5717     if (!l)
5718     {
5719         l = RegOpenKeyExW(enumKey, devInfo->instanceId, 0, samDesired, &key);
5720         RegCloseKey(enumKey);
5721     }
5722     if (l)
5723         SetLastError(l);
5724     return key;
5725 }
5726 
5727 static HKEY SETUPDI_OpenDrvKey(HKEY RootKey, struct DeviceInfo *devInfo, REGSAM samDesired)
5728 {
5729     LPWSTR DriverKey = NULL;
5730     DWORD dwLength = 0;
5731     DWORD dwRegType;
5732     DWORD rc;
5733     HKEY hEnumKey = NULL;
5734     HKEY hKey = NULL;
5735     HKEY key = INVALID_HANDLE_VALUE;
5736 
5737     hKey = SETUPDI_OpenDevKey(RootKey, devInfo, KEY_QUERY_VALUE);
5738     if (hKey == INVALID_HANDLE_VALUE)
5739         goto cleanup;
5740     /* Read the 'Driver' key */
5741     rc = RegQueryValueExW(hKey, REGSTR_VAL_DRIVER, NULL, &dwRegType, NULL, &dwLength);
5742     if (rc != ERROR_SUCCESS)
5743     {
5744         SetLastError(rc);
5745         goto cleanup;
5746     }
5747     else if (dwRegType != REG_SZ)
5748     {
5749         SetLastError(ERROR_GEN_FAILURE);
5750         goto cleanup;
5751     }
5752     DriverKey = HeapAlloc(GetProcessHeap(), 0, dwLength);
5753     if (!DriverKey)
5754     {
5755         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
5756         goto cleanup;
5757     }
5758     rc = RegQueryValueExW(hKey, REGSTR_VAL_DRIVER, NULL, &dwRegType, (LPBYTE)DriverKey, &dwLength);
5759     if (rc != ERROR_SUCCESS)
5760     {
5761         SetLastError(rc);
5762         goto cleanup;
5763     }
5764     RegCloseKey(hKey);
5765     hKey = NULL;
5766     /* Need to open the driver key */
5767     rc = RegOpenKeyExW(
5768         RootKey,
5769         REGSTR_PATH_CLASS_NT,
5770         0, /* Options */
5771         READ_CONTROL,
5772         &hEnumKey);
5773     if (rc != ERROR_SUCCESS)
5774     {
5775         SetLastError(rc);
5776         goto cleanup;
5777     }
5778     rc = RegOpenKeyExW(
5779         hEnumKey,
5780         DriverKey,
5781         0, /* Options */
5782         samDesired,
5783         &hKey);
5784     if (rc != ERROR_SUCCESS)
5785     {
5786         SetLastError(rc);
5787         goto cleanup;
5788     }
5789     key = hKey;
5790 
5791 cleanup:
5792     if (hEnumKey != NULL)
5793         RegCloseKey(hEnumKey);
5794     if (hKey != NULL && hKey != key)
5795         RegCloseKey(hKey);
5796     if (DriverKey)
5797         HeapFree(GetProcessHeap(), 0, DriverKey);
5798     return key;
5799 }
5800 
5801 /***********************************************************************
5802  *		SetupDiOpenDevRegKey (SETUPAPI.@)
5803  */
5804 HKEY WINAPI SetupDiOpenDevRegKey(
5805         HDEVINFO DeviceInfoSet,
5806         PSP_DEVINFO_DATA DeviceInfoData,
5807         DWORD Scope,
5808         DWORD HwProfile,
5809         DWORD KeyType,
5810         REGSAM samDesired)
5811 {
5812     struct DeviceInfoSet *set = DeviceInfoSet;
5813     struct DeviceInfo *devInfo;
5814     HKEY key = INVALID_HANDLE_VALUE;
5815     HKEY RootKey;
5816 
5817     TRACE("%p %p %d %d %d %x\n", DeviceInfoSet, DeviceInfoData,
5818           Scope, HwProfile, KeyType, samDesired);
5819 
5820     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
5821     {
5822         SetLastError(ERROR_INVALID_HANDLE);
5823         return INVALID_HANDLE_VALUE;
5824     }
5825     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
5826     {
5827         SetLastError(ERROR_INVALID_HANDLE);
5828         return INVALID_HANDLE_VALUE;
5829     }
5830     if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
5831             || !DeviceInfoData->Reserved)
5832     {
5833         SetLastError(ERROR_INVALID_PARAMETER);
5834         return INVALID_HANDLE_VALUE;
5835     }
5836     if (Scope != DICS_FLAG_GLOBAL && Scope != DICS_FLAG_CONFIGSPECIFIC)
5837     {
5838         SetLastError(ERROR_INVALID_FLAGS);
5839         return INVALID_HANDLE_VALUE;
5840     }
5841     if (KeyType != DIREG_DEV && KeyType != DIREG_DRV)
5842     {
5843         SetLastError(ERROR_INVALID_FLAGS);
5844         return INVALID_HANDLE_VALUE;
5845     }
5846     devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
5847     if (devInfo->set != set)
5848     {
5849         SetLastError(ERROR_INVALID_PARAMETER);
5850         return INVALID_HANDLE_VALUE;
5851     }
5852     if (Scope != DICS_FLAG_GLOBAL)
5853     {
5854         RootKey = OpenHardwareProfileKey(set->HKLM, HwProfile, 0);
5855         if (RootKey == INVALID_HANDLE_VALUE)
5856             return INVALID_HANDLE_VALUE;
5857     }
5858     else
5859         RootKey = set->HKLM;
5860     switch (KeyType)
5861     {
5862         case DIREG_DEV:
5863             key = SETUPDI_OpenDevKey(RootKey, devInfo, samDesired);
5864             break;
5865         case DIREG_DRV:
5866             key = SETUPDI_OpenDrvKey(RootKey, devInfo, samDesired);
5867             break;
5868         default:
5869             WARN("unknown KeyType %d\n", KeyType);
5870     }
5871     if (RootKey != set->HKLM)
5872         RegCloseKey(RootKey);
5873     return key;
5874 }
5875 
5876 static BOOL SETUPDI_DeleteDevKey(HKEY RootKey, struct DeviceInfo *devInfo)
5877 {
5878     FIXME("\n");
5879     return FALSE;
5880 }
5881 
5882 static BOOL SETUPDI_DeleteDrvKey(HKEY RootKey, struct DeviceInfo *devInfo)
5883 {
5884     FIXME("\n");
5885     return FALSE;
5886 }
5887 
5888 /***********************************************************************
5889  *		SetupDiDeleteDevRegKey (SETUPAPI.@)
5890  */
5891 BOOL WINAPI SetupDiDeleteDevRegKey(
5892         HDEVINFO DeviceInfoSet,
5893         PSP_DEVINFO_DATA DeviceInfoData,
5894         DWORD Scope,
5895         DWORD HwProfile,
5896         DWORD KeyType)
5897 {
5898     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
5899     struct DeviceInfo *devInfo;
5900     BOOL ret = FALSE;
5901     HKEY RootKey;
5902 
5903     TRACE("%p %p %d %d %d\n", DeviceInfoSet, DeviceInfoData, Scope, HwProfile,
5904             KeyType);
5905 
5906     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
5907     {
5908         SetLastError(ERROR_INVALID_HANDLE);
5909         return FALSE;
5910     }
5911     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
5912     {
5913         SetLastError(ERROR_INVALID_HANDLE);
5914         return FALSE;
5915     }
5916     if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
5917             || !DeviceInfoData->Reserved)
5918     {
5919         SetLastError(ERROR_INVALID_PARAMETER);
5920         return FALSE;
5921     }
5922     if (Scope != DICS_FLAG_GLOBAL && Scope != DICS_FLAG_CONFIGSPECIFIC)
5923     {
5924         SetLastError(ERROR_INVALID_FLAGS);
5925         return FALSE;
5926     }
5927     if (KeyType != DIREG_DEV && KeyType != DIREG_DRV && KeyType != DIREG_BOTH)
5928     {
5929         SetLastError(ERROR_INVALID_FLAGS);
5930         return FALSE;
5931     }
5932     devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
5933     if (devInfo->set != set)
5934     {
5935         SetLastError(ERROR_INVALID_PARAMETER);
5936         return FALSE;
5937     }
5938     if (Scope != DICS_FLAG_GLOBAL)
5939     {
5940         RootKey = OpenHardwareProfileKey(set->HKLM, HwProfile, 0);
5941         if (RootKey == INVALID_HANDLE_VALUE)
5942             return FALSE;
5943     }
5944     else
5945         RootKey = set->HKLM;
5946     switch (KeyType)
5947     {
5948         case DIREG_DEV:
5949             ret = SETUPDI_DeleteDevKey(RootKey, devInfo);
5950             break;
5951         case DIREG_DRV:
5952             ret = SETUPDI_DeleteDrvKey(RootKey, devInfo);
5953             break;
5954         case DIREG_BOTH:
5955             ret = SETUPDI_DeleteDevKey(RootKey, devInfo);
5956             if (ret)
5957                 ret = SETUPDI_DeleteDrvKey(RootKey, devInfo);
5958             break;
5959         default:
5960             WARN("unknown KeyType %d\n", KeyType);
5961     }
5962     if (RootKey != set->HKLM)
5963         RegCloseKey(RootKey);
5964     return ret;
5965 }
5966