xref: /reactos/dll/win32/setupapi/devinst.c (revision 3c774903)
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                     LPWSTR lpGuidString;
4292                     if (UuidToStringW((UUID*)&DeviceInfoData->ClassGuid, &lpGuidString) == RPC_S_OK)
4293                     {
4294                         rc = RegQueryValueExW(hKey, lpGuidString, 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, lpGuidString, 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                         RpcStringFreeW(&lpGuidString);
4323                     }
4324                     RegCloseKey(hKey);
4325                 }
4326             }
4327             if ((CanHandle & CLASS_INSTALLER) && !(InstallParams.FlagsEx & DI_FLAGSEX_CI_FAILED))
4328             {
4329                 hKey = SetupDiOpenClassRegKey(&DeviceInfoData->ClassGuid, KEY_QUERY_VALUE);
4330                 if (hKey != INVALID_HANDLE_VALUE)
4331                 {
4332                     rc = RegQueryValueExW(hKey, REGSTR_VAL_INSTALLER_32, NULL, &dwRegType, NULL, &dwLength);
4333                     if (rc == ERROR_SUCCESS && dwRegType == REG_SZ)
4334                     {
4335                         LPWSTR KeyBuffer = HeapAlloc(GetProcessHeap(), 0, dwLength);
4336                         if (KeyBuffer != NULL)
4337                         {
4338                             rc = RegQueryValueExW(hKey, REGSTR_VAL_INSTALLER_32, NULL, NULL, (LPBYTE)KeyBuffer, &dwLength);
4339                             if (rc == ERROR_SUCCESS)
4340                             {
4341                                 /* Get ClassInstaller function pointer */
4342                                 TRACE("Got class installer '%s'\n", debugstr_w(KeyBuffer));
4343                                 if (GetFunctionPointer(KeyBuffer, &ClassInstallerLibrary, (PVOID*)&ClassInstaller) != ERROR_SUCCESS)
4344                                 {
4345                                     InstallParams.FlagsEx |= DI_FLAGSEX_CI_FAILED;
4346                                     SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
4347                                 }
4348                             }
4349                             HeapFree(GetProcessHeap(), 0, KeyBuffer);
4350                         }
4351                     }
4352                     RegCloseKey(hKey);
4353                 }
4354             }
4355 
4356             /* Call Class co-installers */
4357             Context.PostProcessing = FALSE;
4358             rc = NO_ERROR;
4359             ListEntry = ClassCoInstallersListHead.Flink;
4360             while (rc == NO_ERROR && ListEntry != &ClassCoInstallersListHead)
4361             {
4362                 struct CoInstallerElement *coinstaller;
4363                 coinstaller = CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry);
4364                 rc = (*coinstaller->Function)(InstallFunction, DeviceInfoSet, DeviceInfoData, &Context);
4365                 coinstaller->PrivateData = Context.PrivateData;
4366                 if (rc == ERROR_DI_POSTPROCESSING_REQUIRED)
4367                 {
4368                     coinstaller->DoPostProcessing = TRUE;
4369                     rc = NO_ERROR;
4370                 }
4371                 ListEntry = ListEntry->Flink;
4372             }
4373 
4374             /* Call Device co-installers */
4375             ListEntry = DeviceCoInstallersListHead.Flink;
4376             while (rc == NO_ERROR && ListEntry != &DeviceCoInstallersListHead)
4377             {
4378                 struct CoInstallerElement *coinstaller;
4379                 coinstaller = CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry);
4380                 rc = (*coinstaller->Function)(InstallFunction, DeviceInfoSet, DeviceInfoData, &Context);
4381                 coinstaller->PrivateData = Context.PrivateData;
4382                 if (rc == ERROR_DI_POSTPROCESSING_REQUIRED)
4383                 {
4384                     coinstaller->DoPostProcessing = TRUE;
4385                     rc = NO_ERROR;
4386                 }
4387                 ListEntry = ListEntry->Flink;
4388             }
4389 
4390             /* Call Class installer */
4391             if (ClassInstaller)
4392             {
4393                 rc = (*ClassInstaller)(InstallFunction, DeviceInfoSet, DeviceInfoData);
4394                 FreeFunctionPointer(ClassInstallerLibrary, ClassInstaller);
4395             }
4396             else
4397                 rc = ERROR_DI_DO_DEFAULT;
4398 
4399             /* Call default handler */
4400             if (rc == ERROR_DI_DO_DEFAULT)
4401             {
4402                 if (DefaultHandler && !(InstallParams.Flags & DI_NODI_DEFAULTACTION))
4403                 {
4404                     if ((*DefaultHandler)(DeviceInfoSet, DeviceInfoData))
4405                         rc = NO_ERROR;
4406                     else
4407                         rc = GetLastError();
4408                 }
4409                 else
4410                     rc = NO_ERROR;
4411             }
4412 
4413             /* Call Class co-installers that required postprocessing */
4414             Context.PostProcessing = TRUE;
4415             ListEntry = ClassCoInstallersListHead.Flink;
4416             while (ListEntry != &ClassCoInstallersListHead)
4417             {
4418                 struct CoInstallerElement *coinstaller;
4419                 coinstaller = CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry);
4420                 if (coinstaller->DoPostProcessing)
4421                 {
4422                     Context.InstallResult = rc;
4423                     Context.PrivateData = coinstaller->PrivateData;
4424                     rc = (*coinstaller->Function)(InstallFunction, DeviceInfoSet, DeviceInfoData, &Context);
4425                 }
4426                 FreeFunctionPointer(coinstaller->Module, coinstaller->Function);
4427                 ListEntry = ListEntry->Flink;
4428             }
4429 
4430             /* Call Device co-installers that required postprocessing */
4431             ListEntry = DeviceCoInstallersListHead.Flink;
4432             while (ListEntry != &DeviceCoInstallersListHead)
4433             {
4434                 struct CoInstallerElement *coinstaller;
4435                 coinstaller = CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry);
4436                 if (coinstaller->DoPostProcessing)
4437                 {
4438                     Context.InstallResult = rc;
4439                     Context.PrivateData = coinstaller->PrivateData;
4440                     rc = (*coinstaller->Function)(InstallFunction, DeviceInfoSet, DeviceInfoData, &Context);
4441                 }
4442                 FreeFunctionPointer(coinstaller->Module, coinstaller->Function);
4443                 ListEntry = ListEntry->Flink;
4444             }
4445 
4446             /* Free allocated memory */
4447             while (!IsListEmpty(&ClassCoInstallersListHead))
4448             {
4449                 ListEntry = RemoveHeadList(&ClassCoInstallersListHead);
4450                 HeapFree(GetProcessHeap(), 0, CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry));
4451             }
4452             while (!IsListEmpty(&DeviceCoInstallersListHead))
4453             {
4454                 ListEntry = RemoveHeadList(&DeviceCoInstallersListHead);
4455                 HeapFree(GetProcessHeap(), 0, CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry));
4456             }
4457 
4458             ret = (rc == NO_ERROR);
4459         }
4460     }
4461 
4462     TRACE("Returning %d\n", ret);
4463     return ret;
4464 }
4465 
4466 /***********************************************************************
4467  *		SetupDiGetDeviceInstallParamsA (SETUPAPI.@)
4468  */
4469 BOOL WINAPI SetupDiGetDeviceInstallParamsA(
4470         HDEVINFO DeviceInfoSet,
4471         PSP_DEVINFO_DATA DeviceInfoData,
4472         PSP_DEVINSTALL_PARAMS_A DeviceInstallParams)
4473 {
4474     SP_DEVINSTALL_PARAMS_W deviceInstallParamsW;
4475     BOOL ret = FALSE;
4476 
4477     TRACE("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstallParams);
4478 
4479     if (DeviceInstallParams == NULL)
4480         SetLastError(ERROR_INVALID_PARAMETER);
4481     else if (DeviceInstallParams->cbSize != sizeof(SP_DEVINSTALL_PARAMS_A))
4482         SetLastError(ERROR_INVALID_USER_BUFFER);
4483     else
4484     {
4485         deviceInstallParamsW.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
4486         ret = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &deviceInstallParamsW);
4487 
4488         if (ret)
4489         {
4490             /* Do W->A conversion */
4491             memcpy(
4492                 DeviceInstallParams,
4493                 &deviceInstallParamsW,
4494                 FIELD_OFFSET(SP_DEVINSTALL_PARAMS_W, DriverPath));
4495             if (WideCharToMultiByte(CP_ACP, 0, deviceInstallParamsW.DriverPath, -1,
4496                 DeviceInstallParams->DriverPath, MAX_PATH, NULL, NULL) == 0)
4497             {
4498                 DeviceInstallParams->DriverPath[0] = '\0';
4499                 ret = FALSE;
4500             }
4501         }
4502     }
4503 
4504     TRACE("Returning %d\n", ret);
4505     return ret;
4506 }
4507 
4508 /***********************************************************************
4509  *		SetupDiGetDeviceInfoListClass  (SETUPAPI.@)
4510  */
4511 BOOL WINAPI
4512 SetupDiGetDeviceInfoListClass(
4513         IN HDEVINFO DeviceInfoSet,
4514         OUT LPGUID ClassGuid)
4515 {
4516     struct DeviceInfoSet *list;
4517     BOOL ret = FALSE;
4518 
4519     TRACE("%p %p\n", DeviceInfoSet, ClassGuid);
4520 
4521     if (!DeviceInfoSet)
4522         SetLastError(ERROR_INVALID_HANDLE);
4523     else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
4524         SetLastError(ERROR_INVALID_HANDLE);
4525     else if (IsEqualIID(&list->ClassGuid, &GUID_NULL))
4526         SetLastError(ERROR_NO_ASSOCIATED_CLASS);
4527     else
4528     {
4529         memcpy(&ClassGuid, &list->ClassGuid, sizeof(GUID));
4530 
4531         ret = TRUE;
4532     }
4533 
4534     TRACE("Returning %d\n", ret);
4535     return ret;
4536 }
4537 
4538 /***********************************************************************
4539  *		SetupDiGetDeviceInstallParamsW (SETUPAPI.@)
4540  */
4541 BOOL WINAPI
4542 SetupDiGetDeviceInstallParamsW(
4543         IN HDEVINFO DeviceInfoSet,
4544         IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
4545         OUT PSP_DEVINSTALL_PARAMS_W DeviceInstallParams)
4546 {
4547     struct DeviceInfoSet *list;
4548     BOOL ret = FALSE;
4549 
4550     TRACE("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstallParams);
4551 
4552     if (!DeviceInfoSet)
4553         SetLastError(ERROR_INVALID_HANDLE);
4554     else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
4555         SetLastError(ERROR_INVALID_HANDLE);
4556     else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
4557         SetLastError(ERROR_INVALID_USER_BUFFER);
4558     else if (!DeviceInstallParams)
4559         SetLastError(ERROR_INVALID_PARAMETER);
4560     else if (DeviceInstallParams->cbSize != sizeof(SP_DEVINSTALL_PARAMS_W))
4561         SetLastError(ERROR_INVALID_USER_BUFFER);
4562     else
4563     {
4564         PSP_DEVINSTALL_PARAMS_W Source;
4565 
4566         if (DeviceInfoData)
4567             Source = &((struct DeviceInfo *)DeviceInfoData->Reserved)->InstallParams;
4568         else
4569             Source = &list->InstallParams;
4570 
4571         ret = TRUE;
4572 
4573         _SEH2_TRY
4574         {
4575             memcpy(DeviceInstallParams, Source, Source->cbSize);
4576         }
4577         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4578         {
4579             SetLastError(RtlNtStatusToDosError(_SEH2_GetExceptionCode()));
4580             ret = FALSE;
4581         }
4582         _SEH2_END;
4583     }
4584 
4585     TRACE("Returning %d\n", ret);
4586     return ret;
4587 }
4588 
4589 static BOOL
4590 CheckDeviceInstallParameters(
4591         IN PSP_DEVINSTALL_PARAMS_W DeviceInstallParams)
4592 {
4593     DWORD SupportedFlags =
4594         DI_NOVCP |                            /* 0x00000008 */
4595         DI_DIDCOMPAT |                        /* 0x00000010 */
4596         DI_DIDCLASS |                         /* 0x00000020 */
4597         DI_NEEDRESTART |                      /* 0x00000080 */
4598         DI_NEEDREBOOT |                       /* 0x00000100 */
4599         DI_RESOURCEPAGE_ADDED |               /* 0x00002000 */
4600         DI_PROPERTIES_CHANGE |                /* 0x00004000 */
4601         DI_ENUMSINGLEINF |                    /* 0x00010000 */
4602         DI_DONOTCALLCONFIGMG |                /* 0x00020000 */
4603         DI_CLASSINSTALLPARAMS |               /* 0x00100000 */
4604         DI_NODI_DEFAULTACTION |               /* 0x00200000 */
4605         DI_QUIETINSTALL |                     /* 0x00800000 */
4606         DI_NOFILECOPY |                       /* 0x01000000 */
4607         DI_DRIVERPAGE_ADDED;                  /* 0x04000000 */
4608     DWORD SupportedFlagsEx =
4609         DI_FLAGSEX_CI_FAILED |                /* 0x00000004 */
4610         DI_FLAGSEX_DIDINFOLIST |              /* 0x00000010 */
4611         DI_FLAGSEX_DIDCOMPATINFO |            /* 0x00000020 */
4612         DI_FLAGSEX_ALLOWEXCLUDEDDRVS |        /* 0x00000800 */
4613         DI_FLAGSEX_NO_DRVREG_MODIFY |         /* 0x00008000 */
4614         DI_FLAGSEX_INSTALLEDDRIVER;           /* 0x04000000 */
4615     BOOL ret = FALSE;
4616 
4617     /* FIXME: add support for more flags */
4618 
4619     /* FIXME: DI_CLASSINSTALLPARAMS flag is not correctly used.
4620      * It should be checked before accessing to other values
4621      * of the SP_DEVINSTALL_PARAMS structure */
4622 
4623     if (DeviceInstallParams->Flags & ~SupportedFlags)
4624     {
4625         FIXME("Unknown Flags: 0x%08lx\n", DeviceInstallParams->Flags & ~SupportedFlags);
4626         SetLastError(ERROR_INVALID_FLAGS);
4627     }
4628     else if (DeviceInstallParams->FlagsEx & ~SupportedFlagsEx)
4629     {
4630         FIXME("Unknown FlagsEx: 0x%08lx\n", DeviceInstallParams->FlagsEx & ~SupportedFlagsEx);
4631         SetLastError(ERROR_INVALID_FLAGS);
4632     }
4633     else if ((DeviceInstallParams->Flags & DI_NOVCP)
4634         && (DeviceInstallParams->FileQueue == NULL || DeviceInstallParams->FileQueue == (HSPFILEQ)INVALID_HANDLE_VALUE))
4635         SetLastError(ERROR_INVALID_USER_BUFFER);
4636     else
4637     {
4638         /* FIXME: check Reserved field */
4639         ret = TRUE;
4640     }
4641 
4642     return ret;
4643 }
4644 
4645 /***********************************************************************
4646  *		SetupDiSetDeviceInstallParamsW (SETUPAPI.@)
4647  */
4648 BOOL WINAPI
4649 SetupDiSetDeviceInstallParamsW(
4650         IN HDEVINFO DeviceInfoSet,
4651         IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
4652         IN PSP_DEVINSTALL_PARAMS_W DeviceInstallParams)
4653 {
4654     struct DeviceInfoSet *list;
4655     BOOL ret = FALSE;
4656 
4657     TRACE("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstallParams);
4658 
4659     if (!DeviceInfoSet)
4660         SetLastError(ERROR_INVALID_HANDLE);
4661     else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
4662         SetLastError(ERROR_INVALID_HANDLE);
4663     else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
4664         SetLastError(ERROR_INVALID_USER_BUFFER);
4665     else if (!DeviceInstallParams)
4666         SetLastError(ERROR_INVALID_PARAMETER);
4667     else if (DeviceInstallParams->cbSize != sizeof(SP_DEVINSTALL_PARAMS_W))
4668         SetLastError(ERROR_INVALID_USER_BUFFER);
4669     else if (CheckDeviceInstallParameters(DeviceInstallParams))
4670     {
4671         PSP_DEVINSTALL_PARAMS_W Destination;
4672 
4673         if (DeviceInfoData)
4674             Destination = &((struct DeviceInfo *)DeviceInfoData->Reserved)->InstallParams;
4675         else
4676             Destination = &list->InstallParams;
4677         memcpy(Destination, DeviceInstallParams, DeviceInstallParams->cbSize);
4678         ret = TRUE;
4679     }
4680 
4681     TRACE("Returning %d\n", ret);
4682     return ret;
4683 }
4684 
4685 /***********************************************************************
4686  *		SetupDiSetDeviceInstallParamsW (SETUPAPI.@)
4687  */
4688 BOOL WINAPI
4689 SetupDiSetDeviceInstallParamsA(
4690         HDEVINFO DeviceInfoSet,
4691         PSP_DEVINFO_DATA DeviceInfoData,
4692         PSP_DEVINSTALL_PARAMS_A DeviceInstallParams)
4693 {
4694     SP_DEVINSTALL_PARAMS_W deviceInstallParamsW;
4695     int len = 0;
4696     BOOL ret = FALSE;
4697 
4698     TRACE("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstallParams);
4699 
4700     if (DeviceInstallParams == NULL)
4701         SetLastError(ERROR_INVALID_PARAMETER);
4702     else if (DeviceInstallParams->cbSize < sizeof(SP_DEVINSTALL_PARAMS_A))
4703         SetLastError(ERROR_INVALID_USER_BUFFER);
4704     else
4705     {
4706         memcpy(&deviceInstallParamsW, DeviceInstallParams, FIELD_OFFSET(SP_DEVINSTALL_PARAMS_A, DriverPath));
4707         deviceInstallParamsW.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
4708         len = MultiByteToWideChar(CP_ACP, 0, DeviceInstallParams->DriverPath, -1, NULL, 0);
4709         if (!len)
4710         {
4711             ERR("DrivePath is NULL\n");
4712             ret = FALSE;
4713         }
4714         else
4715         {
4716             MultiByteToWideChar(CP_ACP, 0, DeviceInstallParams->DriverPath, -1, deviceInstallParamsW.DriverPath, len);
4717             ret = SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &deviceInstallParamsW);
4718         }
4719     }
4720 
4721     TRACE("Returning %d\n", ret);
4722     return ret;
4723 }
4724 
4725 static HKEY
4726 OpenHardwareProfileKey(
4727         IN HKEY HKLM,
4728         IN DWORD HwProfile,
4729         IN DWORD samDesired)
4730 {
4731     HKEY hHWProfilesKey = NULL;
4732     HKEY hHWProfileKey = NULL;
4733     HKEY ret = INVALID_HANDLE_VALUE;
4734     LONG rc;
4735 
4736     rc = RegOpenKeyExW(HKLM,
4737                        REGSTR_PATH_HWPROFILES,
4738                        0,
4739                        READ_CONTROL,
4740                        &hHWProfilesKey);
4741     if (rc != ERROR_SUCCESS)
4742     {
4743         SetLastError(rc);
4744         goto cleanup;
4745     }
4746     if (HwProfile == 0)
4747     {
4748         rc = RegOpenKeyExW(hHWProfilesKey,
4749                            REGSTR_KEY_CURRENT,
4750                            0,
4751                            KEY_CREATE_SUB_KEY,
4752                            &hHWProfileKey);
4753     }
4754     else
4755     {
4756         WCHAR subKey[5];
4757         snprintfW(subKey, 4, InstanceKeyFormat, HwProfile);
4758         subKey[4] = '\0';
4759         rc = RegOpenKeyExW(hHWProfilesKey,
4760                            subKey,
4761                            0,
4762                            KEY_CREATE_SUB_KEY,
4763                            &hHWProfileKey);
4764     }
4765     if (rc != ERROR_SUCCESS)
4766     {
4767         SetLastError(rc);
4768         goto cleanup;
4769     }
4770     ret = hHWProfileKey;
4771 
4772 cleanup:
4773     if (hHWProfilesKey != NULL)
4774         RegCloseKey(hHWProfilesKey);
4775     if (hHWProfileKey != NULL && hHWProfileKey != ret)
4776         RegCloseKey(hHWProfileKey);
4777     return ret;
4778 }
4779 
4780 static BOOL
4781 IsDeviceInfoInDeviceInfoSet(
4782         struct DeviceInfoSet *deviceInfoSet,
4783         struct DeviceInfo *deviceInfo)
4784 {
4785     PLIST_ENTRY ListEntry;
4786 
4787     ListEntry = deviceInfoSet->ListHead.Flink;
4788     while (ListEntry != &deviceInfoSet->ListHead)
4789     {
4790         if (deviceInfo == CONTAINING_RECORD(ListEntry, struct DeviceInfo, ListEntry))
4791             return TRUE;
4792 
4793         ListEntry = ListEntry->Flink;
4794     }
4795 
4796     return FALSE;
4797 }
4798 
4799 /***********************************************************************
4800  *		SetupDiDeleteDeviceInfo (SETUPAPI.@)
4801  */
4802 BOOL WINAPI
4803 SetupDiDeleteDeviceInfo(
4804         IN HDEVINFO DeviceInfoSet,
4805         IN PSP_DEVINFO_DATA DeviceInfoData)
4806 {
4807     struct DeviceInfoSet *deviceInfoSet;
4808     struct DeviceInfo *deviceInfo = (struct DeviceInfo *)DeviceInfoData;
4809     BOOL ret = FALSE;
4810 
4811     TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
4812 
4813     if (!DeviceInfoSet)
4814         SetLastError(ERROR_INVALID_HANDLE);
4815     else if ((deviceInfoSet = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
4816         SetLastError(ERROR_INVALID_HANDLE);
4817     else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
4818         SetLastError(ERROR_INVALID_USER_BUFFER);
4819     else if (!IsDeviceInfoInDeviceInfoSet(deviceInfoSet, deviceInfo))
4820         SetLastError(ERROR_INVALID_PARAMETER);
4821     else
4822     {
4823         RemoveEntryList(&deviceInfo->ListEntry);
4824         DestroyDeviceInfo(deviceInfo);
4825         ret = TRUE;
4826     }
4827 
4828     return ret;
4829 }
4830 
4831 
4832 /***********************************************************************
4833  *		SetupDiOpenDeviceInfoA (SETUPAPI.@)
4834  */
4835 BOOL WINAPI
4836 SetupDiOpenDeviceInfoA(
4837         IN HDEVINFO DeviceInfoSet,
4838         IN PCSTR DeviceInstanceId,
4839         IN HWND hwndParent OPTIONAL,
4840         IN DWORD OpenFlags,
4841         OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
4842 {
4843     LPWSTR DeviceInstanceIdW = NULL;
4844     BOOL bResult;
4845 
4846     TRACE("%p %s %p %lx %p\n", DeviceInfoSet, DeviceInstanceId, hwndParent, OpenFlags, DeviceInfoData);
4847 
4848     DeviceInstanceIdW = pSetupMultiByteToUnicode(DeviceInstanceId, CP_ACP);
4849     if (DeviceInstanceIdW == NULL)
4850         return FALSE;
4851 
4852     bResult = SetupDiOpenDeviceInfoW(DeviceInfoSet,
4853         DeviceInstanceIdW, hwndParent, OpenFlags, DeviceInfoData);
4854 
4855     MyFree(DeviceInstanceIdW);
4856 
4857     return bResult;
4858 }
4859 
4860 
4861 /***********************************************************************
4862  *		SetupDiOpenDeviceInfoW (SETUPAPI.@)
4863  */
4864 BOOL WINAPI
4865 SetupDiOpenDeviceInfoW(
4866         IN HDEVINFO DeviceInfoSet,
4867         IN PCWSTR DeviceInstanceId,
4868         IN HWND hwndParent OPTIONAL,
4869         IN DWORD OpenFlags,
4870         OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
4871 {
4872     struct DeviceInfoSet *list;
4873     HKEY hEnumKey, hKey = NULL;
4874     DWORD rc, dwSize;
4875     BOOL ret = FALSE;
4876 
4877     TRACE("%p %s %p %lx %p\n",
4878         DeviceInfoSet, debugstr_w(DeviceInstanceId),
4879         hwndParent, OpenFlags, DeviceInfoData);
4880 
4881     if (OpenFlags & DIOD_CANCEL_REMOVE)
4882         FIXME("DIOD_CANCEL_REMOVE flag not implemented\n");
4883 
4884     if (!DeviceInfoSet)
4885         SetLastError(ERROR_INVALID_HANDLE);
4886     else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
4887         SetLastError(ERROR_INVALID_HANDLE);
4888     else if (!DeviceInstanceId)
4889         SetLastError(ERROR_INVALID_PARAMETER);
4890     else if (OpenFlags & ~(DIOD_CANCEL_REMOVE | DIOD_INHERIT_CLASSDRVS))
4891     {
4892         TRACE("Unknown flags: 0x%08lx\n", OpenFlags & ~(DIOD_CANCEL_REMOVE | DIOD_INHERIT_CLASSDRVS));
4893         SetLastError(ERROR_INVALID_FLAGS);
4894     }
4895     else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
4896         SetLastError(ERROR_INVALID_USER_BUFFER);
4897     else
4898     {
4899         struct DeviceInfo *deviceInfo = NULL;
4900         /* Search if device already exists in DeviceInfoSet.
4901          *    If yes, return the existing element
4902          *    If no, create a new element using information in registry
4903          */
4904         PLIST_ENTRY ItemList = list->ListHead.Flink;
4905         while (ItemList != &list->ListHead)
4906         {
4907             deviceInfo = CONTAINING_RECORD(ItemList, struct DeviceInfo, ListEntry);
4908             if (!wcscmp(deviceInfo->instanceId, DeviceInstanceId))
4909                 break;
4910             deviceInfo = NULL;
4911             ItemList = ItemList->Flink;
4912         }
4913 
4914         if (deviceInfo)
4915         {
4916             /* good one found */
4917             ret = TRUE;
4918         }
4919         else
4920         {
4921             GUID ClassGUID;
4922             WCHAR szClassGuid[MAX_GUID_STRING_LEN];
4923 
4924             /* Open supposed registry key */
4925             rc = RegOpenKeyExW(
4926                 list->HKLM,
4927                 REGSTR_PATH_SYSTEMENUM,
4928                 0, /* Options */
4929                 READ_CONTROL,
4930                 &hEnumKey);
4931             if (rc != ERROR_SUCCESS)
4932             {
4933                 SetLastError(rc);
4934                 goto cleanup;
4935             }
4936             rc = RegOpenKeyExW(
4937                 hEnumKey,
4938                 DeviceInstanceId,
4939                 0, /* Options */
4940                 KEY_QUERY_VALUE,
4941                 &hKey);
4942             RegCloseKey(hEnumKey);
4943             if (rc != ERROR_SUCCESS)
4944             {
4945                 if (rc == ERROR_FILE_NOT_FOUND)
4946                     rc = ERROR_NO_SUCH_DEVINST;
4947                 SetLastError(rc);
4948                 goto cleanup;
4949             }
4950 
4951             ClassGUID = GUID_NULL;
4952             dwSize = MAX_GUID_STRING_LEN * sizeof(WCHAR);
4953 
4954             if (RegQueryValueExW(hKey,
4955                                  REGSTR_VAL_CLASSGUID,
4956                                  NULL,
4957                                  NULL,
4958                                  (LPBYTE)szClassGuid,
4959                                  &dwSize) == ERROR_SUCCESS)
4960             {
4961                 szClassGuid[MAX_GUID_STRING_LEN - 2] = UNICODE_NULL;
4962 
4963                 /* Convert a string to a ClassGuid */
4964                 UuidFromStringW(&szClassGuid[1], &ClassGUID);
4965             }
4966 
4967             if (!CreateDeviceInfo(list, DeviceInstanceId, &ClassGUID, &deviceInfo))
4968                 goto cleanup;
4969 
4970             InsertTailList(&list->ListHead, &deviceInfo->ListEntry);
4971 
4972             ret = TRUE;
4973         }
4974 
4975         if (ret && deviceInfo && DeviceInfoData)
4976         {
4977             memcpy(&DeviceInfoData->ClassGuid, &deviceInfo->ClassGuid, sizeof(GUID));
4978             DeviceInfoData->DevInst = deviceInfo->dnDevInst;
4979             DeviceInfoData->Reserved = (ULONG_PTR)deviceInfo;
4980         }
4981     }
4982 
4983 cleanup:
4984     if (hKey != NULL)
4985         RegCloseKey(hKey);
4986     return ret;
4987 }
4988 
4989 
4990 /***********************************************************************
4991  *		SetupDiGetSelectedDevice (SETUPAPI.@)
4992  */
4993 BOOL WINAPI
4994 SetupDiGetSelectedDevice(
4995         IN HDEVINFO DeviceInfoSet,
4996         OUT PSP_DEVINFO_DATA DeviceInfoData)
4997 {
4998     struct DeviceInfoSet *list;
4999     BOOL ret = FALSE;
5000 
5001     TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
5002 
5003     if (!DeviceInfoSet)
5004         SetLastError(ERROR_INVALID_HANDLE);
5005     else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
5006         SetLastError(ERROR_INVALID_HANDLE);
5007     else if (list->SelectedDevice == NULL)
5008         SetLastError(ERROR_NO_DEVICE_SELECTED);
5009     else if (!DeviceInfoData)
5010         SetLastError(ERROR_INVALID_PARAMETER);
5011     else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
5012         SetLastError(ERROR_INVALID_USER_BUFFER);
5013     else
5014     {
5015         memcpy(&DeviceInfoData->ClassGuid,
5016             &list->SelectedDevice->ClassGuid,
5017             sizeof(GUID));
5018         DeviceInfoData->DevInst = list->SelectedDevice->dnDevInst;
5019         DeviceInfoData->Reserved = (ULONG_PTR)list->SelectedDevice;
5020         ret = TRUE;
5021     }
5022 
5023     TRACE("Returning %d\n", ret);
5024     return ret;
5025 }
5026 
5027 
5028 /***********************************************************************
5029  *		SetupDiSetSelectedDevice (SETUPAPI.@)
5030  */
5031 BOOL WINAPI
5032 SetupDiSetSelectedDevice(
5033         IN HDEVINFO DeviceInfoSet,
5034         IN PSP_DEVINFO_DATA DeviceInfoData)
5035 {
5036     struct DeviceInfoSet *list;
5037     BOOL ret = FALSE;
5038 
5039     TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
5040 
5041     if (!DeviceInfoSet)
5042         SetLastError(ERROR_INVALID_HANDLE);
5043     else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
5044         SetLastError(ERROR_INVALID_HANDLE);
5045     else if (!DeviceInfoData)
5046         SetLastError(ERROR_INVALID_PARAMETER);
5047     else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
5048         SetLastError(ERROR_INVALID_USER_BUFFER);
5049     else if (DeviceInfoData->Reserved == 0)
5050         SetLastError(ERROR_INVALID_USER_BUFFER);
5051     else
5052     {
5053         list->SelectedDevice = (struct DeviceInfo *)DeviceInfoData->Reserved;
5054         ret = TRUE;
5055     }
5056 
5057     TRACE("Returning %d\n", ret);
5058     return ret;
5059 }
5060 
5061 
5062 /* Return the current hardware profile id, or -1 if error */
5063 static DWORD
5064 SETUPAPI_GetCurrentHwProfile(
5065         IN HDEVINFO DeviceInfoSet)
5066 {
5067     HKEY hKey = NULL;
5068     DWORD dwRegType, dwLength;
5069     DWORD hwProfile;
5070     LONG rc;
5071     DWORD ret = (DWORD)-1;
5072 
5073     rc = RegOpenKeyExW(((struct DeviceInfoSet *)DeviceInfoSet)->HKLM,
5074                        REGSTR_PATH_IDCONFIGDB,
5075                        0, /* Options */
5076                        KEY_QUERY_VALUE,
5077                        &hKey);
5078     if (rc != ERROR_SUCCESS)
5079     {
5080         SetLastError(rc);
5081         goto cleanup;
5082     }
5083 
5084     dwLength = sizeof(DWORD);
5085     rc = RegQueryValueExW(hKey,
5086                           REGSTR_VAL_CURRENTCONFIG,
5087                           NULL,
5088                           &dwRegType,
5089                           (LPBYTE)&hwProfile, &dwLength);
5090     if (rc != ERROR_SUCCESS)
5091     {
5092         SetLastError(rc);
5093         goto cleanup;
5094     }
5095     else if (dwRegType != REG_DWORD || dwLength != sizeof(DWORD))
5096     {
5097         SetLastError(ERROR_GEN_FAILURE);
5098         goto cleanup;
5099     }
5100 
5101     ret = hwProfile;
5102 
5103 cleanup:
5104     if (hKey != NULL)
5105         RegCloseKey(hKey);
5106 
5107     return ret;
5108 }
5109 
5110 static BOOL
5111 ResetDevice(
5112         IN HDEVINFO DeviceInfoSet,
5113         IN PSP_DEVINFO_DATA DeviceInfoData)
5114 {
5115 #ifndef __WINESRC__
5116     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
5117     struct DeviceInfo *deviceInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
5118     CONFIGRET cr;
5119 
5120     cr = CM_Enable_DevNode_Ex(deviceInfo->dnDevInst, 0, set->hMachine);
5121     if (cr != CR_SUCCESS)
5122     {
5123         SetLastError(GetErrorCodeFromCrCode(cr));
5124         return FALSE;
5125     }
5126 
5127     return TRUE;
5128 #else
5129     FIXME("Stub: ResetDevice(%p %p)\n", DeviceInfoSet, DeviceInfoData);
5130     return TRUE;
5131 #endif
5132 }
5133 
5134 static BOOL StopDevice(
5135         IN HDEVINFO DeviceInfoSet,
5136         IN PSP_DEVINFO_DATA DeviceInfoData)
5137 {
5138     FIXME("Stub: StopDevice(%p %p)\n", DeviceInfoSet, DeviceInfoData);
5139     return TRUE;
5140 }
5141 
5142 /***********************************************************************
5143  *		SetupDiChangeState (SETUPAPI.@)
5144  */
5145 BOOL WINAPI
5146 SetupDiChangeState(
5147         IN HDEVINFO DeviceInfoSet,
5148         IN OUT PSP_DEVINFO_DATA DeviceInfoData)
5149 {
5150     PSP_PROPCHANGE_PARAMS PropChange;
5151     HKEY hKey = INVALID_HANDLE_VALUE;
5152     LPCWSTR RegistryValueName;
5153     DWORD dwConfigFlags, dwLength, dwRegType;
5154     LONG rc;
5155     BOOL ret = FALSE;
5156 
5157     TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
5158 
5159     if (!DeviceInfoData)
5160         PropChange = ((struct DeviceInfoSet *)DeviceInfoSet)->ClassInstallParams.PropChangeParams;
5161     else
5162         PropChange = ((struct DeviceInfo *)DeviceInfoData->Reserved)->ClassInstallParams.PropChangeParams;
5163     if (!PropChange)
5164     {
5165         SetLastError(ERROR_INVALID_PARAMETER);
5166         goto cleanup;
5167     }
5168 
5169     if (PropChange->Scope == DICS_FLAG_GLOBAL)
5170         RegistryValueName = REGSTR_VAL_CONFIGFLAGS;
5171     else
5172         RegistryValueName = REGSTR_VAL_CSCONFIGFLAGS;
5173 
5174     switch (PropChange->StateChange)
5175     {
5176         case DICS_ENABLE:
5177         case DICS_DISABLE:
5178         {
5179             /* Enable/disable device in registry */
5180             hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, PropChange->Scope, PropChange->HwProfile, DIREG_DEV, KEY_QUERY_VALUE | KEY_SET_VALUE);
5181             if (hKey == INVALID_HANDLE_VALUE && GetLastError() == ERROR_FILE_NOT_FOUND)
5182                 hKey = SetupDiCreateDevRegKeyW(DeviceInfoSet, DeviceInfoData, PropChange->Scope, PropChange->HwProfile, DIREG_DEV, NULL, NULL);
5183             if (hKey == INVALID_HANDLE_VALUE)
5184                 break;
5185             dwLength = sizeof(DWORD);
5186             rc = RegQueryValueExW(
5187                 hKey,
5188                 RegistryValueName,
5189                 NULL,
5190                 &dwRegType,
5191                 (LPBYTE)&dwConfigFlags, &dwLength);
5192             if (rc == ERROR_FILE_NOT_FOUND)
5193                 dwConfigFlags = 0;
5194             else if (rc != ERROR_SUCCESS)
5195             {
5196                 SetLastError(rc);
5197                 goto cleanup;
5198             }
5199             else if (dwRegType != REG_DWORD || dwLength != sizeof(DWORD))
5200             {
5201                 SetLastError(ERROR_GEN_FAILURE);
5202                 goto cleanup;
5203             }
5204             if (PropChange->StateChange == DICS_ENABLE)
5205                 dwConfigFlags &= ~(PropChange->Scope == DICS_FLAG_GLOBAL ? CONFIGFLAG_DISABLED : CSCONFIGFLAG_DISABLED);
5206             else
5207                 dwConfigFlags |= (PropChange->Scope == DICS_FLAG_GLOBAL ? CONFIGFLAG_DISABLED : CSCONFIGFLAG_DISABLED);
5208             rc = RegSetValueExW(
5209                 hKey,
5210                 RegistryValueName,
5211                 0,
5212                 REG_DWORD,
5213                 (LPBYTE)&dwConfigFlags, sizeof(DWORD));
5214             if (rc != ERROR_SUCCESS)
5215             {
5216                 SetLastError(rc);
5217                 goto cleanup;
5218             }
5219 
5220             /* Enable/disable device if needed */
5221             if (PropChange->Scope == DICS_FLAG_GLOBAL
5222                 || PropChange->HwProfile == 0
5223                 || PropChange->HwProfile == SETUPAPI_GetCurrentHwProfile(DeviceInfoSet))
5224             {
5225                 if (PropChange->StateChange == DICS_ENABLE)
5226                     ret = ResetDevice(DeviceInfoSet, DeviceInfoData);
5227                 else
5228                     ret = StopDevice(DeviceInfoSet, DeviceInfoData);
5229             }
5230             else
5231                 ret = TRUE;
5232             break;
5233         }
5234         case DICS_PROPCHANGE:
5235         {
5236             ret = ResetDevice(DeviceInfoSet, DeviceInfoData);
5237             break;
5238         }
5239         default:
5240         {
5241             ERR("Unknown StateChange 0x%lx\n", PropChange->StateChange);
5242             SetLastError(ERROR_NOT_SUPPORTED);
5243         }
5244     }
5245 
5246 cleanup:
5247     if (hKey != INVALID_HANDLE_VALUE)
5248         RegCloseKey(hKey);
5249 
5250     TRACE("Returning %d\n", ret);
5251     return ret;
5252 }
5253 
5254 /***********************************************************************
5255  *		SetupDiSelectDevice (SETUPAPI.@)
5256  */
5257 BOOL WINAPI
5258 SetupDiSelectDevice(
5259         IN HDEVINFO DeviceInfoSet,
5260         IN OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
5261 {
5262     FIXME("%p %p\n", DeviceInfoSet, DeviceInfoData);
5263     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5264     return FALSE;
5265 }
5266 
5267 
5268 /***********************************************************************
5269  *		SetupDiRegisterCoDeviceInstallers (SETUPAPI.@)
5270  */
5271 BOOL WINAPI
5272 SetupDiRegisterCoDeviceInstallers(
5273         IN HDEVINFO DeviceInfoSet,
5274         IN PSP_DEVINFO_DATA DeviceInfoData)
5275 {
5276     BOOL ret = FALSE; /* Return value */
5277 
5278     TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
5279 
5280     if (!DeviceInfoSet)
5281         SetLastError(ERROR_INVALID_PARAMETER);
5282     else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
5283         SetLastError(ERROR_INVALID_HANDLE);
5284     else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
5285         SetLastError(ERROR_INVALID_HANDLE);
5286     else if (!DeviceInfoData)
5287         SetLastError(ERROR_INVALID_PARAMETER);
5288     else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
5289         SetLastError(ERROR_INVALID_USER_BUFFER);
5290     else
5291     {
5292         SP_DEVINSTALL_PARAMS_W InstallParams;
5293         struct DriverInfoElement *SelectedDriver;
5294         BOOL Result;
5295         DWORD DoAction;
5296         WCHAR SectionName[MAX_PATH];
5297         DWORD SectionNameLength = 0;
5298         HKEY hKey = INVALID_HANDLE_VALUE;
5299         PVOID Context = NULL;
5300 
5301         InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
5302         Result = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
5303         if (!Result)
5304             goto cleanup;
5305 
5306         SelectedDriver = (struct DriverInfoElement *)InstallParams.Reserved;
5307         if (SelectedDriver == NULL)
5308         {
5309             SetLastError(ERROR_NO_DRIVER_SELECTED);
5310             goto cleanup;
5311         }
5312 
5313         /* Get .CoInstallers section name */
5314         Result = SetupDiGetActualSectionToInstallW(
5315             SelectedDriver->InfFileDetails->hInf,
5316             SelectedDriver->Details.SectionName,
5317             SectionName, MAX_PATH, &SectionNameLength, NULL);
5318         if (!Result || SectionNameLength > MAX_PATH - strlenW(DotCoInstallers) - 1)
5319             goto cleanup;
5320         lstrcatW(SectionName, DotCoInstallers);
5321 
5322         /* Open/Create driver key information */
5323 #if _WIN32_WINNT >= 0x502
5324         hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_READ | KEY_WRITE);
5325 #else
5326         hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_ALL_ACCESS);
5327 #endif
5328         if (hKey == INVALID_HANDLE_VALUE && GetLastError() == ERROR_FILE_NOT_FOUND)
5329             hKey = SetupDiCreateDevRegKeyW(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, NULL, NULL);
5330         if (hKey == INVALID_HANDLE_VALUE)
5331             goto cleanup;
5332 
5333         /* Install .CoInstallers section */
5334         DoAction = SPINST_REGISTRY;
5335         if (!(InstallParams.Flags & DI_NOFILECOPY))
5336         {
5337             DoAction |= SPINST_FILES;
5338             Context = SetupInitDefaultQueueCallback(InstallParams.hwndParent);
5339             if (!Context)
5340                 goto cleanup;
5341         }
5342         Result = SetupInstallFromInfSectionW(InstallParams.hwndParent,
5343             SelectedDriver->InfFileDetails->hInf, SectionName,
5344             DoAction, hKey, SelectedDriver->InfFileDetails->DirectoryName, SP_COPY_NEWER,
5345             SetupDefaultQueueCallbackW, Context,
5346             DeviceInfoSet, DeviceInfoData);
5347         if (!Result)
5348             goto cleanup;
5349 
5350         ret = TRUE;
5351 
5352 cleanup:
5353         if (Context)
5354             SetupTermDefaultQueueCallback(Context);
5355         if (hKey != INVALID_HANDLE_VALUE)
5356             RegCloseKey(hKey);
5357     }
5358 
5359     TRACE("Returning %d\n", ret);
5360     return ret;
5361 }
5362 
5363 static BOOL
5364 InfIsFromOEMLocation(
5365         IN PCWSTR FullName,
5366         OUT LPBOOL IsOEMLocation)
5367 {
5368     PWCHAR last;
5369 
5370     last = strrchrW(FullName, '\\');
5371     if (!last)
5372     {
5373         /* No directory specified */
5374         *IsOEMLocation = FALSE;
5375     }
5376     else
5377     {
5378         LPWSTR Windir;
5379         UINT ret;
5380 
5381         Windir = MyMalloc((MAX_PATH + 1 + strlenW(InfDirectory)) * sizeof(WCHAR));
5382         if (!Windir)
5383         {
5384             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
5385             return FALSE;
5386         }
5387 
5388         ret = GetSystemWindowsDirectoryW(Windir, MAX_PATH);
5389         if (ret == 0 || ret > MAX_PATH)
5390         {
5391             MyFree(Windir);
5392             SetLastError(ERROR_GEN_FAILURE);
5393             return FALSE;
5394         }
5395         if (*Windir && Windir[strlenW(Windir) - 1] != '\\')
5396             strcatW(Windir, BackSlash);
5397         strcatW(Windir, InfDirectory);
5398 
5399         if (strncmpiW(FullName, Windir, last - FullName) == 0)
5400         {
5401             /* The path is %SYSTEMROOT%\Inf */
5402             *IsOEMLocation = FALSE;
5403         }
5404         else
5405         {
5406             /* The file is in another place */
5407             *IsOEMLocation = TRUE;
5408         }
5409         MyFree(Windir);
5410     }
5411     return TRUE;
5412 }
5413 
5414 /***********************************************************************
5415  *		SetupDiInstallDevice (SETUPAPI.@)
5416  */
5417 BOOL WINAPI
5418 SetupDiInstallDevice(
5419         IN HDEVINFO DeviceInfoSet,
5420         IN OUT PSP_DEVINFO_DATA DeviceInfoData)
5421 {
5422     SP_DEVINSTALL_PARAMS_W InstallParams;
5423     struct DriverInfoElement *SelectedDriver;
5424     SYSTEMTIME DriverDate;
5425     WCHAR SectionName[MAX_PATH];
5426     WCHAR Buffer[32];
5427     DWORD SectionNameLength = 0;
5428     BOOL Result = FALSE;
5429     ULONG DoAction;
5430     DWORD RequiredSize;
5431     LPWSTR pSectionName = NULL;
5432     WCHAR ClassName[MAX_CLASS_NAME_LEN];
5433     GUID ClassGuid;
5434     LPWSTR lpGuidString = NULL, lpFullGuidString = NULL;
5435     BOOL RebootRequired = FALSE;
5436     HKEY hKey = INVALID_HANDLE_VALUE;
5437     BOOL NeedtoCopyFile;
5438     LARGE_INTEGER fullVersion;
5439     LONG rc;
5440     PVOID Context = NULL;
5441     BOOL ret = FALSE; /* Return value */
5442 
5443     TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
5444 
5445     if (!DeviceInfoSet)
5446         SetLastError(ERROR_INVALID_PARAMETER);
5447     else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
5448         SetLastError(ERROR_INVALID_HANDLE);
5449     else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
5450         SetLastError(ERROR_INVALID_HANDLE);
5451     else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
5452         SetLastError(ERROR_INVALID_USER_BUFFER);
5453     else
5454         Result = TRUE;
5455 
5456     if (!Result)
5457     {
5458         /* One parameter is bad */
5459         goto cleanup;
5460     }
5461 
5462     InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
5463     Result = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
5464     if (!Result)
5465         goto cleanup;
5466 
5467     if (InstallParams.FlagsEx & DI_FLAGSEX_SETFAILEDINSTALL)
5468     {
5469         /* Set FAILEDINSTALL in ConfigFlags registry value */
5470         DWORD ConfigFlags, regType;
5471         Result = SetupDiGetDeviceRegistryPropertyW(
5472             DeviceInfoSet,
5473             DeviceInfoData,
5474             SPDRP_CONFIGFLAGS,
5475             &regType,
5476             (PBYTE)&ConfigFlags,
5477             sizeof(ConfigFlags),
5478             NULL);
5479         if (!Result || regType != REG_DWORD)
5480         {
5481             SetLastError(ERROR_GEN_FAILURE);
5482             goto cleanup;
5483         }
5484         ConfigFlags |= DNF_DISABLED;
5485         Result = SetupDiSetDeviceRegistryPropertyW(
5486             DeviceInfoSet,
5487             DeviceInfoData,
5488             SPDRP_CONFIGFLAGS,
5489             (PBYTE)&ConfigFlags,
5490             sizeof(ConfigFlags));
5491         if (!Result)
5492         {
5493             SetLastError(ERROR_GEN_FAILURE);
5494             goto cleanup;
5495         }
5496 
5497         ret = TRUE;
5498         goto cleanup;
5499     }
5500 
5501     SelectedDriver = (struct DriverInfoElement *)InstallParams.Reserved;
5502     if (SelectedDriver == NULL)
5503     {
5504         SetLastError(ERROR_NO_DRIVER_SELECTED);
5505         goto cleanup;
5506     }
5507 
5508     FileTimeToSystemTime(&SelectedDriver->Info.DriverDate, &DriverDate);
5509 
5510     Result = SetupDiGetActualSectionToInstallW(
5511         SelectedDriver->InfFileDetails->hInf,
5512         SelectedDriver->Details.SectionName,
5513         SectionName, MAX_PATH, &SectionNameLength, NULL);
5514     if (!Result || SectionNameLength > MAX_PATH - strlenW(DotServices))
5515         goto cleanup;
5516     pSectionName = &SectionName[strlenW(SectionName)];
5517 
5518     /* Get information from [Version] section */
5519     if (!SetupDiGetINFClassW(SelectedDriver->Details.InfFileName, &ClassGuid, ClassName, MAX_CLASS_NAME_LEN, &RequiredSize))
5520         goto cleanup;
5521     /* Format ClassGuid to a string */
5522     if (UuidToStringW((UUID*)&ClassGuid, &lpGuidString) != RPC_S_OK)
5523         goto cleanup;
5524     RequiredSize = lstrlenW(lpGuidString);
5525     lpFullGuidString = HeapAlloc(GetProcessHeap(), 0, (RequiredSize + 3) * sizeof(WCHAR));
5526     if (!lpFullGuidString)
5527     {
5528         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
5529         goto cleanup;
5530     }
5531     lpFullGuidString[0] = '{';
5532     memcpy(&lpFullGuidString[1], lpGuidString, RequiredSize * sizeof(WCHAR));
5533     lpFullGuidString[RequiredSize + 1] = '}';
5534     lpFullGuidString[RequiredSize + 2] = '\0';
5535 
5536     /* Copy .inf file to Inf\ directory (if needed) */
5537     Result = InfIsFromOEMLocation(SelectedDriver->Details.InfFileName, &NeedtoCopyFile);
5538     if (!Result)
5539         goto cleanup;
5540     if (NeedtoCopyFile)
5541     {
5542         WCHAR NewFileName[MAX_PATH];
5543         struct InfFileDetails *newInfFileDetails;
5544         Result = SetupCopyOEMInfW(
5545             SelectedDriver->Details.InfFileName,
5546             NULL,
5547             SPOST_NONE,
5548             SP_COPY_NOOVERWRITE,
5549             NewFileName, MAX_PATH,
5550             NULL,
5551             NULL);
5552         if (!Result && GetLastError() != ERROR_FILE_EXISTS)
5553             goto cleanup;
5554         /* Create a new struct InfFileDetails, and set it to
5555          * SelectedDriver->InfFileDetails, to release use of
5556          * current InfFile */
5557         newInfFileDetails = CreateInfFileDetails(NewFileName);
5558         if (!newInfFileDetails)
5559             goto cleanup;
5560         DereferenceInfFile(SelectedDriver->InfFileDetails);
5561         SelectedDriver->InfFileDetails = newInfFileDetails;
5562         strcpyW(SelectedDriver->Details.InfFileName, NewFileName);
5563     }
5564 
5565     /* Open/Create driver key information */
5566 #if _WIN32_WINNT >= 0x502
5567     hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_READ | KEY_WRITE);
5568 #else
5569     hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_ALL_ACCESS);
5570 #endif
5571     if (hKey == INVALID_HANDLE_VALUE && GetLastError() == ERROR_FILE_NOT_FOUND)
5572         hKey = SetupDiCreateDevRegKeyW(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, NULL, NULL);
5573     if (hKey == INVALID_HANDLE_VALUE)
5574         goto cleanup;
5575 
5576     /* Install main section */
5577     DoAction = 0;
5578     if (!(InstallParams.FlagsEx & DI_FLAGSEX_NO_DRVREG_MODIFY))
5579         DoAction |= SPINST_REGISTRY;
5580     if (!(InstallParams.Flags & DI_NOFILECOPY))
5581     {
5582         DoAction |= SPINST_FILES;
5583         Context = SetupInitDefaultQueueCallback(InstallParams.hwndParent);
5584         if (!Context)
5585             goto cleanup;
5586     }
5587     *pSectionName = '\0';
5588     Result = SetupInstallFromInfSectionW(InstallParams.hwndParent,
5589         SelectedDriver->InfFileDetails->hInf, SectionName,
5590         DoAction, hKey, SelectedDriver->InfFileDetails->DirectoryName, SP_COPY_NEWER,
5591         SetupDefaultQueueCallbackW, Context,
5592         DeviceInfoSet, DeviceInfoData);
5593     if (!Result)
5594         goto cleanup;
5595     InstallParams.Flags |= DI_NOFILECOPY;
5596     SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
5597 
5598     /* Write information to driver key */
5599     *pSectionName = UNICODE_NULL;
5600     memcpy(&fullVersion, &SelectedDriver->Info.DriverVersion, sizeof(LARGE_INTEGER));
5601     TRACE("Write information to driver key\n");
5602     TRACE("DriverDate      : '%u-%u-%u'\n", DriverDate.wMonth, DriverDate.wDay, DriverDate.wYear);
5603     TRACE("DriverDesc      : '%s'\n", debugstr_w(SelectedDriver->Info.Description));
5604     TRACE("DriverVersion   : '%ld.%ld.%lu.%ld'\n", fullVersion.HighPart >> 16, fullVersion.HighPart & 0xffff, fullVersion.LowPart >> 16, fullVersion.LowPart & 0xffff);
5605     TRACE("InfPath         : '%s'\n", debugstr_w(SelectedDriver->InfFileDetails->FileName));
5606     TRACE("InfSection      : '%s'\n", debugstr_w(SelectedDriver->Details.SectionName));
5607     TRACE("InfSectionExt   : '%s'\n", debugstr_w(&SectionName[strlenW(SelectedDriver->Details.SectionName)]));
5608     TRACE("MatchingDeviceId: '%s'\n", debugstr_w(SelectedDriver->MatchingId));
5609     TRACE("ProviderName    : '%s'\n", debugstr_w(SelectedDriver->Info.ProviderName));
5610     sprintfW(Buffer, DateFormat, DriverDate.wMonth, DriverDate.wDay, DriverDate.wYear);
5611     rc = RegSetValueExW(hKey, REGSTR_DRIVER_DATE, 0, REG_SZ, (const BYTE *)Buffer, (strlenW(Buffer) + 1) * sizeof(WCHAR));
5612     if (rc == ERROR_SUCCESS)
5613         rc = RegSetValueExW(hKey, REGSTR_DRIVER_DATE_DATA, 0, REG_BINARY, (const BYTE *)&SelectedDriver->Info.DriverDate, sizeof(FILETIME));
5614     if (rc == ERROR_SUCCESS)
5615         rc = RegSetValueExW(hKey, REGSTR_VAL_DRVDESC, 0, REG_SZ, (const BYTE *)SelectedDriver->Info.Description, (strlenW(SelectedDriver->Info.Description) + 1) * sizeof(WCHAR));
5616     if (rc == ERROR_SUCCESS)
5617     {
5618         sprintfW(Buffer, VersionFormat, fullVersion.HighPart >> 16, fullVersion.HighPart & 0xffff, fullVersion.LowPart >> 16, fullVersion.LowPart & 0xffff);
5619         rc = RegSetValueExW(hKey, REGSTR_DRIVER_VERSION, 0, REG_SZ, (const BYTE *)Buffer, (strlenW(Buffer) + 1) * sizeof(WCHAR));
5620     }
5621     if (rc == ERROR_SUCCESS)
5622         rc = RegSetValueExW(hKey, REGSTR_VAL_INFPATH, 0, REG_SZ, (const BYTE *)SelectedDriver->InfFileDetails->FileName, (strlenW(SelectedDriver->InfFileDetails->FileName) + 1) * sizeof(WCHAR));
5623     if (rc == ERROR_SUCCESS)
5624         rc = RegSetValueExW(hKey, REGSTR_VAL_INFSECTION, 0, REG_SZ, (const BYTE *)SelectedDriver->Details.SectionName, (strlenW(SelectedDriver->Details.SectionName) + 1) * sizeof(WCHAR));
5625     if (rc == ERROR_SUCCESS)
5626         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));
5627     if (rc == ERROR_SUCCESS)
5628         rc = RegSetValueExW(hKey, REGSTR_VAL_MATCHINGDEVID, 0, REG_SZ, (const BYTE *)SelectedDriver->MatchingId, (strlenW(SelectedDriver->MatchingId) + 1) * sizeof(WCHAR));
5629     if (rc == ERROR_SUCCESS)
5630         rc = RegSetValueExW(hKey, REGSTR_VAL_PROVIDER_NAME, 0, REG_SZ, (const BYTE *)SelectedDriver->Info.ProviderName, (strlenW(SelectedDriver->Info.ProviderName) + 1) * sizeof(WCHAR));
5631     if (rc != ERROR_SUCCESS)
5632     {
5633        SetLastError(rc);
5634        goto cleanup;
5635     }
5636     RegCloseKey(hKey);
5637     hKey = INVALID_HANDLE_VALUE;
5638 
5639     /* FIXME: Process .LogConfigOverride section */
5640 
5641     /* Install .Services section */
5642     strcpyW(pSectionName, DotServices);
5643     Result = SetupInstallServicesFromInfSectionExW(
5644         SelectedDriver->InfFileDetails->hInf,
5645         SectionName,
5646         0,
5647         DeviceInfoSet,
5648         DeviceInfoData,
5649         NULL,
5650         NULL);
5651     if (!Result)
5652         goto cleanup;
5653     if (GetLastError() == ERROR_SUCCESS_REBOOT_REQUIRED)
5654         RebootRequired = TRUE;
5655 
5656     /* Open device registry key */
5657     hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_SET_VALUE);
5658     if (hKey == INVALID_HANDLE_VALUE)
5659         goto cleanup;
5660 
5661     /* Install .HW section */
5662     DoAction = 0;
5663     if (!(InstallParams.FlagsEx & DI_FLAGSEX_NO_DRVREG_MODIFY))
5664         DoAction |= SPINST_REGISTRY;
5665     strcpyW(pSectionName, DotHW);
5666     Result = SetupInstallFromInfSectionW(InstallParams.hwndParent,
5667         SelectedDriver->InfFileDetails->hInf, SectionName,
5668         DoAction, hKey, NULL, 0,
5669         NULL, NULL,
5670         DeviceInfoSet, DeviceInfoData);
5671     if (!Result)
5672         goto cleanup;
5673 
5674     /* Write information to enum key */
5675     TRACE("Write information to enum key\n");
5676     TRACE("Class           : '%s'\n", debugstr_w(ClassName));
5677     TRACE("ClassGUID       : '%s'\n", debugstr_w(lpFullGuidString));
5678     TRACE("DeviceDesc      : '%s'\n", debugstr_w(SelectedDriver->Info.Description));
5679     TRACE("Mfg             : '%s'\n", debugstr_w(SelectedDriver->Info.MfgName));
5680     rc = RegSetValueExW(hKey, REGSTR_VAL_CLASS, 0, REG_SZ, (const BYTE *)ClassName, (strlenW(ClassName) + 1) * sizeof(WCHAR));
5681     if (rc == ERROR_SUCCESS)
5682         rc = RegSetValueExW(hKey, REGSTR_VAL_CLASSGUID, 0, REG_SZ, (const BYTE *)lpFullGuidString, (strlenW(lpFullGuidString) + 1) * sizeof(WCHAR));
5683     if (rc == ERROR_SUCCESS)
5684         rc = RegSetValueExW(hKey, REGSTR_VAL_DEVDESC, 0, REG_SZ, (const BYTE *)SelectedDriver->Info.Description, (strlenW(SelectedDriver->Info.Description) + 1) * sizeof(WCHAR));
5685     if (rc == ERROR_SUCCESS)
5686         rc = RegSetValueExW(hKey, REGSTR_VAL_MFG, 0, REG_SZ, (const BYTE *)SelectedDriver->Info.MfgName, (strlenW(SelectedDriver->Info.MfgName) + 1) * sizeof(WCHAR));
5687     if (rc != ERROR_SUCCESS)
5688     {
5689        SetLastError(rc);
5690        goto cleanup;
5691     }
5692 
5693     /* Start the device */
5694     if (!RebootRequired && !(InstallParams.Flags & (DI_NEEDRESTART | DI_NEEDREBOOT | DI_DONOTCALLCONFIGMG)))
5695         ret = ResetDevice(DeviceInfoSet, DeviceInfoData);
5696     else
5697         ret = TRUE;
5698 
5699 cleanup:
5700     /* End of installation */
5701     if (hKey != INVALID_HANDLE_VALUE)
5702         RegCloseKey(hKey);
5703     if (lpGuidString)
5704         RpcStringFreeW(&lpGuidString);
5705     HeapFree(GetProcessHeap(), 0, lpFullGuidString);
5706     if (Context)
5707         SetupTermDefaultQueueCallback(Context);
5708     TRACE("Returning %d\n", ret);
5709     return ret;
5710 }
5711 
5712 static HKEY SETUPDI_OpenDevKey(HKEY RootKey, struct DeviceInfo *devInfo, REGSAM samDesired)
5713 {
5714     HKEY enumKey, key = INVALID_HANDLE_VALUE;
5715     LONG l;
5716 
5717     l = RegOpenKeyExW(RootKey, REGSTR_PATH_SYSTEMENUM, 0, READ_CONTROL, &enumKey);
5718     if (!l)
5719     {
5720         l = RegOpenKeyExW(enumKey, devInfo->instanceId, 0, samDesired, &key);
5721         RegCloseKey(enumKey);
5722     }
5723     if (l)
5724         SetLastError(l);
5725     return key;
5726 }
5727 
5728 static HKEY SETUPDI_OpenDrvKey(HKEY RootKey, struct DeviceInfo *devInfo, REGSAM samDesired)
5729 {
5730     LPWSTR DriverKey = NULL;
5731     DWORD dwLength = 0;
5732     DWORD dwRegType;
5733     DWORD rc;
5734     HKEY hEnumKey = NULL;
5735     HKEY hKey = NULL;
5736     HKEY key = INVALID_HANDLE_VALUE;
5737 
5738     hKey = SETUPDI_OpenDevKey(RootKey, devInfo, KEY_QUERY_VALUE);
5739     if (hKey == INVALID_HANDLE_VALUE)
5740         goto cleanup;
5741     /* Read the 'Driver' key */
5742     rc = RegQueryValueExW(hKey, REGSTR_VAL_DRIVER, NULL, &dwRegType, NULL, &dwLength);
5743     if (rc != ERROR_SUCCESS)
5744     {
5745         SetLastError(rc);
5746         goto cleanup;
5747     }
5748     else if (dwRegType != REG_SZ)
5749     {
5750         SetLastError(ERROR_GEN_FAILURE);
5751         goto cleanup;
5752     }
5753     DriverKey = HeapAlloc(GetProcessHeap(), 0, dwLength);
5754     if (!DriverKey)
5755     {
5756         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
5757         goto cleanup;
5758     }
5759     rc = RegQueryValueExW(hKey, REGSTR_VAL_DRIVER, NULL, &dwRegType, (LPBYTE)DriverKey, &dwLength);
5760     if (rc != ERROR_SUCCESS)
5761     {
5762         SetLastError(rc);
5763         goto cleanup;
5764     }
5765     RegCloseKey(hKey);
5766     hKey = NULL;
5767     /* Need to open the driver key */
5768     rc = RegOpenKeyExW(
5769         RootKey,
5770         REGSTR_PATH_CLASS_NT,
5771         0, /* Options */
5772         READ_CONTROL,
5773         &hEnumKey);
5774     if (rc != ERROR_SUCCESS)
5775     {
5776         SetLastError(rc);
5777         goto cleanup;
5778     }
5779     rc = RegOpenKeyExW(
5780         hEnumKey,
5781         DriverKey,
5782         0, /* Options */
5783         samDesired,
5784         &hKey);
5785     if (rc != ERROR_SUCCESS)
5786     {
5787         SetLastError(rc);
5788         goto cleanup;
5789     }
5790     key = hKey;
5791 
5792 cleanup:
5793     if (hEnumKey != NULL)
5794         RegCloseKey(hEnumKey);
5795     if (hKey != NULL && hKey != key)
5796         RegCloseKey(hKey);
5797     if (DriverKey)
5798         HeapFree(GetProcessHeap(), 0, DriverKey);
5799     return key;
5800 }
5801 
5802 /***********************************************************************
5803  *		SetupDiOpenDevRegKey (SETUPAPI.@)
5804  */
5805 HKEY WINAPI SetupDiOpenDevRegKey(
5806         HDEVINFO DeviceInfoSet,
5807         PSP_DEVINFO_DATA DeviceInfoData,
5808         DWORD Scope,
5809         DWORD HwProfile,
5810         DWORD KeyType,
5811         REGSAM samDesired)
5812 {
5813     struct DeviceInfoSet *set = DeviceInfoSet;
5814     struct DeviceInfo *devInfo;
5815     HKEY key = INVALID_HANDLE_VALUE;
5816     HKEY RootKey;
5817 
5818     TRACE("%p %p %d %d %d %x\n", DeviceInfoSet, DeviceInfoData,
5819           Scope, HwProfile, KeyType, samDesired);
5820 
5821     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
5822     {
5823         SetLastError(ERROR_INVALID_HANDLE);
5824         return INVALID_HANDLE_VALUE;
5825     }
5826     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
5827     {
5828         SetLastError(ERROR_INVALID_HANDLE);
5829         return INVALID_HANDLE_VALUE;
5830     }
5831     if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
5832             || !DeviceInfoData->Reserved)
5833     {
5834         SetLastError(ERROR_INVALID_PARAMETER);
5835         return INVALID_HANDLE_VALUE;
5836     }
5837     if (Scope != DICS_FLAG_GLOBAL && Scope != DICS_FLAG_CONFIGSPECIFIC)
5838     {
5839         SetLastError(ERROR_INVALID_FLAGS);
5840         return INVALID_HANDLE_VALUE;
5841     }
5842     if (KeyType != DIREG_DEV && KeyType != DIREG_DRV)
5843     {
5844         SetLastError(ERROR_INVALID_FLAGS);
5845         return INVALID_HANDLE_VALUE;
5846     }
5847     devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
5848     if (devInfo->set != set)
5849     {
5850         SetLastError(ERROR_INVALID_PARAMETER);
5851         return INVALID_HANDLE_VALUE;
5852     }
5853     if (Scope != DICS_FLAG_GLOBAL)
5854     {
5855         RootKey = OpenHardwareProfileKey(set->HKLM, HwProfile, 0);
5856         if (RootKey == INVALID_HANDLE_VALUE)
5857             return INVALID_HANDLE_VALUE;
5858     }
5859     else
5860         RootKey = set->HKLM;
5861     switch (KeyType)
5862     {
5863         case DIREG_DEV:
5864             key = SETUPDI_OpenDevKey(RootKey, devInfo, samDesired);
5865             break;
5866         case DIREG_DRV:
5867             key = SETUPDI_OpenDrvKey(RootKey, devInfo, samDesired);
5868             break;
5869         default:
5870             WARN("unknown KeyType %d\n", KeyType);
5871     }
5872     if (RootKey != set->HKLM)
5873         RegCloseKey(RootKey);
5874     return key;
5875 }
5876 
5877 static BOOL SETUPDI_DeleteDevKey(HKEY RootKey, struct DeviceInfo *devInfo)
5878 {
5879     FIXME("\n");
5880     return FALSE;
5881 }
5882 
5883 static BOOL SETUPDI_DeleteDrvKey(HKEY RootKey, struct DeviceInfo *devInfo)
5884 {
5885     FIXME("\n");
5886     return FALSE;
5887 }
5888 
5889 /***********************************************************************
5890  *		SetupDiDeleteDevRegKey (SETUPAPI.@)
5891  */
5892 BOOL WINAPI SetupDiDeleteDevRegKey(
5893         HDEVINFO DeviceInfoSet,
5894         PSP_DEVINFO_DATA DeviceInfoData,
5895         DWORD Scope,
5896         DWORD HwProfile,
5897         DWORD KeyType)
5898 {
5899     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
5900     struct DeviceInfo *devInfo;
5901     BOOL ret = FALSE;
5902     HKEY RootKey;
5903 
5904     TRACE("%p %p %d %d %d\n", DeviceInfoSet, DeviceInfoData, Scope, HwProfile,
5905             KeyType);
5906 
5907     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
5908     {
5909         SetLastError(ERROR_INVALID_HANDLE);
5910         return FALSE;
5911     }
5912     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
5913     {
5914         SetLastError(ERROR_INVALID_HANDLE);
5915         return FALSE;
5916     }
5917     if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
5918             || !DeviceInfoData->Reserved)
5919     {
5920         SetLastError(ERROR_INVALID_PARAMETER);
5921         return FALSE;
5922     }
5923     if (Scope != DICS_FLAG_GLOBAL && Scope != DICS_FLAG_CONFIGSPECIFIC)
5924     {
5925         SetLastError(ERROR_INVALID_FLAGS);
5926         return FALSE;
5927     }
5928     if (KeyType != DIREG_DEV && KeyType != DIREG_DRV && KeyType != DIREG_BOTH)
5929     {
5930         SetLastError(ERROR_INVALID_FLAGS);
5931         return FALSE;
5932     }
5933     devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
5934     if (devInfo->set != set)
5935     {
5936         SetLastError(ERROR_INVALID_PARAMETER);
5937         return FALSE;
5938     }
5939     if (Scope != DICS_FLAG_GLOBAL)
5940     {
5941         RootKey = OpenHardwareProfileKey(set->HKLM, HwProfile, 0);
5942         if (RootKey == INVALID_HANDLE_VALUE)
5943             return FALSE;
5944     }
5945     else
5946         RootKey = set->HKLM;
5947     switch (KeyType)
5948     {
5949         case DIREG_DEV:
5950             ret = SETUPDI_DeleteDevKey(RootKey, devInfo);
5951             break;
5952         case DIREG_DRV:
5953             ret = SETUPDI_DeleteDrvKey(RootKey, devInfo);
5954             break;
5955         case DIREG_BOTH:
5956             ret = SETUPDI_DeleteDevKey(RootKey, devInfo);
5957             if (ret)
5958                 ret = SETUPDI_DeleteDrvKey(RootKey, devInfo);
5959             break;
5960         default:
5961             WARN("unknown KeyType %d\n", KeyType);
5962     }
5963     if (RootKey != set->HKLM)
5964         RegCloseKey(RootKey);
5965     return ret;
5966 }
5967