wintrust: Add a helper function to initialize chain creation parameters.
[wine] / dlls / setupapi / devinst.c
1 /*
2  * SetupAPI device installer
3  *
4  * Copyright 2000 Andreas Mohr for CodeWeavers
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23  
24 #include <stdarg.h>
25
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winnt.h"
29 #include "winreg.h"
30 #include "winternl.h"
31 #include "wingdi.h"
32 #include "winuser.h"
33 #include "winnls.h"
34 #include "setupapi.h"
35 #include "wine/debug.h"
36 #include "wine/list.h"
37 #include "wine/unicode.h"
38 #include "cfgmgr32.h"
39 #include "initguid.h"
40 #include "winioctl.h"
41 #include "rpc.h"
42 #include "rpcdce.h"
43
44 #include "setupapi_private.h"
45
46
47 WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
48
49 /* Unicode constants */
50 static const WCHAR ClassGUID[]  = {'C','l','a','s','s','G','U','I','D',0};
51 static const WCHAR Class[]  = {'C','l','a','s','s',0};
52 static const WCHAR ClassInstall32[]  = {'C','l','a','s','s','I','n','s','t','a','l','l','3','2',0};
53 static const WCHAR NoDisplayClass[]  = {'N','o','D','i','s','p','l','a','y','C','l','a','s','s',0};
54 static const WCHAR NoInstallClass[]  = {'N','o','I','n','s','t','a','l','l','C','l','a','s','s',0};
55 static const WCHAR NoUseClass[]  = {'N','o','U','s','e','C','l','a','s','s',0};
56 static const WCHAR NtExtension[]  = {'.','N','T',0};
57 static const WCHAR NtPlatformExtension[]  = {'.','N','T','x','8','6',0};
58 static const WCHAR Version[]  = {'V','e','r','s','i','o','n',0};
59 static const WCHAR WinExtension[]  = {'.','W','i','n',0};
60
61 /* Registry key and value names */
62 static const WCHAR ControlClass[] = {'S','y','s','t','e','m','\\',
63                                   'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
64                                   'C','o','n','t','r','o','l','\\',
65                                   'C','l','a','s','s',0};
66
67 static const WCHAR DeviceClasses[] = {'S','y','s','t','e','m','\\',
68                                   'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
69                                   'C','o','n','t','r','o','l','\\',
70                                   'D','e','v','i','c','e','C','l','a','s','s','e','s',0};
71 static const WCHAR Enum[] = {'S','y','s','t','e','m','\\',
72                                   'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
73                                   'E','n','u','m',0};
74 static const WCHAR DeviceDesc[] = {'D','e','v','i','c','e','D','e','s','c',0};
75 static const WCHAR DeviceInstance[] = {'D','e','v','i','c','e','I','n','s','t','a','n','c','e',0};
76 static const WCHAR HardwareId[] = {'H','a','r','d','w','a','r','e','I','D',0};
77 static const WCHAR CompatibleIDs[] = {'C','o','m','p','a','t','i','b','l','e','I','d','s',0};
78 static const WCHAR Service[] = {'S','e','r','v','i','c','e',0};
79 static const WCHAR Driver[] = {'D','r','i','v','e','r',0};
80 static const WCHAR ConfigFlags[] = {'C','o','n','f','i','g','F','l','a','g','s',0};
81 static const WCHAR Mfg[] = {'M','f','g',0};
82 static const WCHAR FriendlyName[] = {'F','r','i','e','n','d','l','y','N','a','m','e',0};
83 static const WCHAR LocationInformation[] = {'L','o','c','a','t','i','o','n','I','n','f','o','r','m','a','t','i','o','n',0};
84 static const WCHAR Capabilities[] = {'C','a','p','a','b','i','l','i','t','i','e','s',0};
85 static const WCHAR UINumber[] = {'U','I','N','u','m','b','e','r',0};
86 static const WCHAR UpperFilters[] = {'U','p','p','e','r','F','i','l','t','e','r','s',0};
87 static const WCHAR LowerFilters[] = {'L','o','w','e','r','F','i','l','t','e','r','s',0};
88 static const WCHAR Phantom[] = {'P','h','a','n','t','o','m',0};
89 static const WCHAR SymbolicLink[] = {'S','y','m','b','o','l','i','c','L','i','n','k',0};
90
91 /* is used to identify if a DeviceInfoSet pointer is
92 valid or not */
93 #define SETUP_DEVICE_INFO_SET_MAGIC 0xd00ff056
94
95 struct DeviceInfoSet
96 {
97     DWORD magic;        /* if is equal to SETUP_DEVICE_INFO_SET_MAGIC struct is okay */
98     GUID ClassGuid;
99     HWND hwndParent;
100     DWORD cDevices;
101     SP_DEVINFO_DATA *devices;
102 };
103
104 /* Pointed to by SP_DEVICE_INTERFACE_DATA's Reserved member */
105 struct InterfaceInfo
106 {
107     LPWSTR           referenceString;
108     LPWSTR           symbolicLink;
109     PSP_DEVINFO_DATA device;
110 };
111
112 /* A device may have multiple instances of the same interface, so this holds
113  * each instance belonging to a particular interface.
114  */
115 struct InterfaceInstances
116 {
117     GUID                      guid;
118     DWORD                     cInstances;
119     DWORD                     cInstancesAllocated;
120     SP_DEVICE_INTERFACE_DATA *instances;
121     struct list               entry;
122 };
123
124 /* Pointed to by SP_DEVINFO_DATA's Reserved member */
125 struct DeviceInfo
126 {
127     struct DeviceInfoSet *set;
128     HKEY                  key;
129     BOOL                  phantom;
130     LPWSTR                instanceId;
131     struct list           interfaces;
132 };
133
134 static void SETUPDI_GuidToString(const GUID *guid, LPWSTR guidStr)
135 {
136     static const WCHAR fmt[] = {'{','%','0','8','X','-','%','0','4','X','-',
137         '%','0','4','X','-','%','0','2','X','%','0','2','X','-','%','0','2',
138         'X','%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X','%',
139         '0','2','X','}',0};
140
141     sprintfW(guidStr, fmt, guid->Data1, guid->Data2, guid->Data3,
142         guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
143         guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
144 }
145
146 static void SETUPDI_FreeInterfaceInstances(struct InterfaceInstances *instances)
147 {
148     DWORD i;
149
150     for (i = 0; i < instances->cInstances; i++)
151     {
152         struct InterfaceInfo *ifaceInfo =
153             (struct InterfaceInfo *)instances->instances[i].Reserved;
154
155         if (ifaceInfo->device && ifaceInfo->device->Reserved)
156         {
157             struct DeviceInfo *devInfo =
158                 (struct DeviceInfo *)ifaceInfo->device->Reserved;
159
160             if (devInfo->phantom)
161                 SetupDiDeleteDeviceInterfaceRegKey(devInfo->set,
162                         &instances->instances[i], 0);
163         }
164         HeapFree(GetProcessHeap(), 0, ifaceInfo->referenceString);
165         HeapFree(GetProcessHeap(), 0, ifaceInfo->symbolicLink);
166     }
167     HeapFree(GetProcessHeap(), 0, instances->instances);
168 }
169
170 /* Finds the interface with interface class InterfaceClassGuid in the device.
171  * Returns TRUE if found, and updates *interface to point to device's
172  * interfaces member where the given interface was found.
173  * Returns FALSE if not found.
174  */
175 static BOOL SETUPDI_FindInterface(const struct DeviceInfo *devInfo,
176         const GUID *InterfaceClassGuid, struct InterfaceInstances **interface)
177 {
178     BOOL found = FALSE;
179     struct InterfaceInstances *iface;
180
181     TRACE("%s\n", debugstr_guid(InterfaceClassGuid));
182
183     LIST_FOR_EACH_ENTRY(iface, &devInfo->interfaces, struct InterfaceInstances,
184             entry)
185     {
186         if (IsEqualGUID(&iface->guid, InterfaceClassGuid))
187         {
188             *interface = iface;
189             found = TRUE;
190             break;
191         }
192     }
193     TRACE("returning %d (%p)\n", found, found ? *interface : NULL);
194     return found;
195 }
196
197 /* Finds the interface instance with reference string ReferenceString in the
198  * interface instance map.  Returns TRUE if found, and updates instanceIndex to
199  * the index of the interface instance's instances member
200  * where the given instance was found.  Returns FALSE if not found.
201  */
202 static BOOL SETUPDI_FindInterfaceInstance(
203         const struct InterfaceInstances *instances,
204         LPCWSTR ReferenceString, DWORD *instanceIndex)
205 {
206     BOOL found = FALSE;
207     DWORD i;
208
209     TRACE("%s\n", debugstr_w(ReferenceString));
210
211     for (i = 0; !found && i < instances->cInstances; i++)
212     {
213         SP_DEVICE_INTERFACE_DATA *ifaceData = &instances->instances[i];
214         struct InterfaceInfo *ifaceInfo =
215             (struct InterfaceInfo *)ifaceData->Reserved;
216
217         if (!ReferenceString && !ifaceInfo->referenceString)
218         {
219             *instanceIndex = i;
220             found = TRUE;
221         }
222         else if (ReferenceString && ifaceInfo->referenceString &&
223                 !lstrcmpiW(ifaceInfo->referenceString, ReferenceString))
224         {
225             *instanceIndex = i;
226             found = TRUE;
227         }
228     }
229     TRACE("returning %d (%d)\n", found, found ? *instanceIndex : 0);
230     return found;
231 }
232
233 static LPWSTR SETUPDI_CreateSymbolicLinkPath(LPCWSTR instanceId,
234         const GUID *InterfaceClassGuid, LPCWSTR ReferenceString)
235 {
236     static const WCHAR fmt[] = {'\\','\\','?','\\','%','s','#','%','s',0};
237     WCHAR guidStr[39];
238     DWORD len;
239     LPWSTR ret;
240
241     SETUPDI_GuidToString(InterfaceClassGuid, guidStr);
242     /* omit length of format specifiers, but include NULL terminator: */
243     len = lstrlenW(fmt) - 4 + 1;
244     len += lstrlenW(instanceId) + lstrlenW(guidStr);
245     if (ReferenceString)
246     {
247         /* space for a hash between string and reference string: */
248         len += lstrlenW(ReferenceString) + 1;
249     }
250     ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
251     if (ret)
252     {
253         int printed = sprintfW(ret, fmt, instanceId, guidStr);
254         LPWSTR ptr;
255
256         /* replace '\\' with '#' after the "\\\\?\\" beginning */
257         for (ptr = strchrW(ret + 4, '\\'); ptr; ptr = strchrW(ptr + 1, '\\'))
258             *ptr = '#';
259         if (ReferenceString)
260         {
261             ret[printed - 1] = '\\';
262             lstrcpyW(ret + printed, ReferenceString);
263         }
264     }
265     return ret;
266 }
267
268 /* Adds an interface with the given interface class and reference string to
269  * the device, if it doesn't already exist in the device.  If iface is not
270  * NULL, returns a pointer to the newly added (or already existing) interface.
271  */
272 static BOOL SETUPDI_AddInterfaceInstance(PSP_DEVINFO_DATA DeviceInfoData,
273         const GUID *InterfaceClassGuid, LPCWSTR ReferenceString,
274         SP_DEVICE_INTERFACE_DATA **ifaceData)
275 {
276     struct DeviceInfo *devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
277     BOOL newInterface = FALSE, ret;
278     struct InterfaceInstances *iface = NULL;
279
280     TRACE("%p %s %s %p\n", devInfo, debugstr_guid(InterfaceClassGuid),
281             debugstr_w(ReferenceString), iface);
282
283     if (!(ret = SETUPDI_FindInterface(devInfo, InterfaceClassGuid, &iface)))
284     {
285         iface = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
286                 sizeof(struct InterfaceInstances));
287         if (iface)
288         {
289             list_add_tail(&devInfo->interfaces, &iface->entry);
290             newInterface = TRUE;
291         }
292     }
293     if (iface)
294     {
295         DWORD instanceIndex = 0;
296
297         if (!(ret = SETUPDI_FindInterfaceInstance(iface, ReferenceString,
298                         &instanceIndex)))
299         {
300             SP_DEVICE_INTERFACE_DATA *instance = NULL;
301
302             if (!iface->cInstancesAllocated)
303             {
304                 iface->instances = HeapAlloc(GetProcessHeap(), 0,
305                         sizeof(SP_DEVICE_INTERFACE_DATA));
306                 if (iface->instances)
307                     instance = &iface->instances[iface->cInstancesAllocated++];
308             }
309             else if (iface->cInstances == iface->cInstancesAllocated)
310             {
311                 iface->instances = HeapReAlloc(GetProcessHeap(), 0,
312                         iface->instances,
313                         (iface->cInstancesAllocated + 1) *
314                         sizeof(SP_DEVICE_INTERFACE_DATA));
315                 if (iface->instances)
316                     instance = &iface->instances[iface->cInstancesAllocated++];
317             }
318             else
319                 instance = &iface->instances[iface->cInstances];
320             if (instance)
321             {
322                 struct InterfaceInfo *ifaceInfo = HeapAlloc(GetProcessHeap(),
323                         0, sizeof(struct InterfaceInfo));
324
325                 if (ifaceInfo)
326                 {
327                     ret = TRUE;
328                     ifaceInfo->device = DeviceInfoData;
329                     ifaceInfo->symbolicLink = SETUPDI_CreateSymbolicLinkPath(
330                             devInfo->instanceId, InterfaceClassGuid,
331                             ReferenceString);
332                     if (ReferenceString)
333                     {
334                         ifaceInfo->referenceString =
335                             HeapAlloc(GetProcessHeap(), 0,
336                                 (lstrlenW(ReferenceString) + 1) *
337                                 sizeof(WCHAR));
338                         if (ifaceInfo->referenceString)
339                             lstrcpyW(ifaceInfo->referenceString,
340                                     ReferenceString);
341                         else
342                             ret = FALSE;
343                     }
344                     else
345                         ifaceInfo->referenceString = NULL;
346                     if (ret)
347                     {
348                         HKEY key;
349
350                         iface->cInstances++;
351                         instance->cbSize =
352                             sizeof(SP_DEVICE_INTERFACE_DATA);
353                         memcpy(&instance->InterfaceClassGuid,
354                                 InterfaceClassGuid, sizeof(GUID));
355                         instance->Flags = SPINT_ACTIVE; /* FIXME */
356                         instance->Reserved = (ULONG_PTR)ifaceInfo;
357                         if (newInterface)
358                             memcpy(&iface->guid, InterfaceClassGuid,
359                                     sizeof(GUID));
360                         key = SetupDiCreateDeviceInterfaceRegKeyW(devInfo->set,
361                                 instance, 0, KEY_WRITE, NULL, NULL);
362                         if (key != INVALID_HANDLE_VALUE)
363                         {
364                             RegSetValueExW(key, SymbolicLink, 0, REG_SZ,
365                                     (BYTE *)ifaceInfo->symbolicLink,
366                                     lstrlenW(ifaceInfo->symbolicLink) *
367                                     sizeof(WCHAR));
368                             RegCloseKey(key);
369                         }
370                         if (ifaceData)
371                             *ifaceData = instance;
372                     }
373                     else
374                         HeapFree(GetProcessHeap(), 0, ifaceInfo);
375                 }
376             }
377         }
378         else
379         {
380             if (ifaceData)
381                 *ifaceData = &iface->instances[instanceIndex];
382         }
383     }
384     else
385         ret = FALSE;
386     TRACE("returning %d\n", ret);
387     return ret;
388 }
389
390 static BOOL SETUPDI_SetInterfaceSymbolicLink(SP_DEVICE_INTERFACE_DATA *iface,
391         LPCWSTR symbolicLink)
392 {
393     struct InterfaceInfo *info = (struct InterfaceInfo *)iface->Reserved;
394     BOOL ret = FALSE;
395
396     if (info)
397     {
398         HeapFree(GetProcessHeap(), 0, info->symbolicLink);
399         info->symbolicLink = HeapAlloc(GetProcessHeap(), 0,
400                 (lstrlenW(symbolicLink) + 1) * sizeof(WCHAR));
401         if (info->symbolicLink)
402         {
403             lstrcpyW(info->symbolicLink, symbolicLink);
404             ret = TRUE;
405         }
406     }
407     return ret;
408 }
409
410 static struct DeviceInfo *SETUPDI_AllocateDeviceInfo(struct DeviceInfoSet *set,
411         LPCWSTR instanceId, BOOL phantom)
412 {
413     struct DeviceInfo *devInfo = HeapAlloc(GetProcessHeap(), 0,
414             sizeof(struct DeviceInfo));
415
416     if (devInfo)
417     {
418         devInfo->set = set;
419         devInfo->instanceId = HeapAlloc(GetProcessHeap(), 0,
420                 (lstrlenW(instanceId) + 1) * sizeof(WCHAR));
421         if (devInfo->instanceId)
422         {
423             HKEY enumKey;
424             LONG l;
425
426             devInfo->key = INVALID_HANDLE_VALUE;
427             devInfo->phantom = phantom;
428             lstrcpyW(devInfo->instanceId, instanceId);
429             struprW(devInfo->instanceId);
430             l = RegCreateKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, NULL, 0,
431                     KEY_ALL_ACCESS, NULL, &enumKey, NULL);
432             if (!l)
433             {
434                 RegCreateKeyExW(enumKey, devInfo->instanceId, 0, NULL, 0,
435                         KEY_ALL_ACCESS, NULL, &devInfo->key, NULL);
436                 if (phantom)
437                     RegSetValueExW(devInfo->key, Phantom, 0, REG_DWORD,
438                             (LPBYTE)&phantom, sizeof(phantom));
439                 RegCloseKey(enumKey);
440             }
441             list_init(&devInfo->interfaces);
442         }
443         else
444         {
445             HeapFree(GetProcessHeap(), 0, devInfo);
446             devInfo = NULL;
447         }
448     }
449     return devInfo;
450 }
451
452 static void SETUPDI_FreeDeviceInfo(struct DeviceInfo *devInfo)
453 {
454     struct InterfaceInstances *iface, *next;
455
456     if (devInfo->key != INVALID_HANDLE_VALUE)
457         RegCloseKey(devInfo->key);
458     if (devInfo->phantom)
459     {
460         HKEY enumKey;
461         LONG l;
462
463         l = RegCreateKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, NULL, 0,
464                 KEY_ALL_ACCESS, NULL, &enumKey, NULL);
465         if (!l)
466         {
467             RegDeleteTreeW(enumKey, devInfo->instanceId);
468             RegCloseKey(enumKey);
469         }
470     }
471     HeapFree(GetProcessHeap(), 0, devInfo->instanceId);
472     LIST_FOR_EACH_ENTRY_SAFE(iface, next, &devInfo->interfaces,
473             struct InterfaceInstances, entry)
474     {
475         list_remove(&iface->entry);
476         SETUPDI_FreeInterfaceInstances(iface);
477         HeapFree(GetProcessHeap(), 0, iface);
478     }
479     HeapFree(GetProcessHeap(), 0, devInfo);
480 }
481
482 /* Adds a device with GUID guid and identifer devInst to set.  Allocates a
483  * struct DeviceInfo, and points the returned device info's Reserved member
484  * to it.  "Phantom" devices are deleted from the registry when closed.
485  * Returns a pointer to the newly allocated device info.
486  */
487 static BOOL SETUPDI_AddDeviceToSet(struct DeviceInfoSet *set,
488         const GUID *guid,
489         DWORD devInst,
490         LPCWSTR instanceId,
491         BOOL phantom,
492         SP_DEVINFO_DATA **dev)
493 {
494     BOOL ret = FALSE;
495     struct DeviceInfo *devInfo = SETUPDI_AllocateDeviceInfo(set, instanceId,
496             phantom);
497
498     TRACE("%p, %s, %d, %s, %d\n", set, debugstr_guid(guid), devInst,
499             debugstr_w(instanceId), phantom);
500
501     if (devInfo)
502     {
503         if (set->devices)
504             set->devices = HeapReAlloc(GetProcessHeap(), 0, set->devices,
505                     (set->cDevices + 1) * sizeof(SP_DEVINFO_DATA));
506         else
507             set->devices = HeapAlloc(GetProcessHeap(), 0,
508                     sizeof(SP_DEVINFO_DATA));
509         if (set->devices)
510         {
511             WCHAR classGuidStr[39];
512
513             *dev = &set->devices[set->cDevices++];
514             (*dev)->cbSize = sizeof(SP_DEVINFO_DATA);
515             memcpy(&(*dev)->ClassGuid, guid, sizeof(GUID));
516             (*dev)->DevInst = devInst;
517             (*dev)->Reserved = (ULONG_PTR)devInfo;
518             SETUPDI_GuidToString(guid, classGuidStr);
519             SetupDiSetDeviceRegistryPropertyW((HDEVINFO)set,
520                 *dev, SPDRP_CLASSGUID, (const BYTE *)classGuidStr,
521                 lstrlenW(classGuidStr) * sizeof(WCHAR));
522             ret = TRUE;
523         }
524         else
525         {
526             HeapFree(GetProcessHeap(), 0, devInfo);
527             SetLastError(ERROR_OUTOFMEMORY);
528         }
529     }
530     return ret;
531 }
532
533 /***********************************************************************
534  *              SetupDiBuildClassInfoList  (SETUPAPI.@)
535  *
536  * Returns a list of setup class GUIDs that identify the classes
537  * that are installed on a local machine.
538  *
539  * PARAMS
540  *   Flags [I] control exclusion of classes from the list.
541  *   ClassGuidList [O] pointer to a GUID-typed array that receives a list of setup class GUIDs.
542  *   ClassGuidListSize [I] The number of GUIDs in the array (ClassGuidList).
543  *   RequiredSize [O] pointer, which receives the number of GUIDs that are returned.
544  *
545  * RETURNS
546  *   Success: TRUE.
547  *   Failure: FALSE.
548  */
549 BOOL WINAPI SetupDiBuildClassInfoList(
550         DWORD Flags,
551         LPGUID ClassGuidList,
552         DWORD ClassGuidListSize,
553         PDWORD RequiredSize)
554 {
555     TRACE("\n");
556     return SetupDiBuildClassInfoListExW(Flags, ClassGuidList,
557                                         ClassGuidListSize, RequiredSize,
558                                         NULL, NULL);
559 }
560
561 /***********************************************************************
562  *              SetupDiBuildClassInfoListExA  (SETUPAPI.@)
563  *
564  * Returns a list of setup class GUIDs that identify the classes
565  * that are installed on a local or remote macine.
566  *
567  * PARAMS
568  *   Flags [I] control exclusion of classes from the list.
569  *   ClassGuidList [O] pointer to a GUID-typed array that receives a list of setup class GUIDs.
570  *   ClassGuidListSize [I] The number of GUIDs in the array (ClassGuidList).
571  *   RequiredSize [O] pointer, which receives the number of GUIDs that are returned.
572  *   MachineName [I] name of a remote machine.
573  *   Reserved [I] must be NULL.
574  *
575  * RETURNS
576  *   Success: TRUE.
577  *   Failure: FALSE.
578  */
579 BOOL WINAPI SetupDiBuildClassInfoListExA(
580         DWORD Flags,
581         LPGUID ClassGuidList,
582         DWORD ClassGuidListSize,
583         PDWORD RequiredSize,
584         LPCSTR MachineName,
585         PVOID Reserved)
586 {
587     LPWSTR MachineNameW = NULL;
588     BOOL bResult;
589
590     TRACE("\n");
591
592     if (MachineName)
593     {
594         MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
595         if (MachineNameW == NULL) return FALSE;
596     }
597
598     bResult = SetupDiBuildClassInfoListExW(Flags, ClassGuidList,
599                                            ClassGuidListSize, RequiredSize,
600                                            MachineNameW, Reserved);
601
602     MyFree(MachineNameW);
603
604     return bResult;
605 }
606
607 /***********************************************************************
608  *              SetupDiBuildClassInfoListExW  (SETUPAPI.@)
609  *
610  * Returns a list of setup class GUIDs that identify the classes
611  * that are installed on a local or remote macine.
612  *
613  * PARAMS
614  *   Flags [I] control exclusion of classes from the list.
615  *   ClassGuidList [O] pointer to a GUID-typed array that receives a list of setup class GUIDs.
616  *   ClassGuidListSize [I] The number of GUIDs in the array (ClassGuidList).
617  *   RequiredSize [O] pointer, which receives the number of GUIDs that are returned.
618  *   MachineName [I] name of a remote machine.
619  *   Reserved [I] must be NULL.
620  *
621  * RETURNS
622  *   Success: TRUE.
623  *   Failure: FALSE.
624  */
625 BOOL WINAPI SetupDiBuildClassInfoListExW(
626         DWORD Flags,
627         LPGUID ClassGuidList,
628         DWORD ClassGuidListSize,
629         PDWORD RequiredSize,
630         LPCWSTR MachineName,
631         PVOID Reserved)
632 {
633     WCHAR szKeyName[40];
634     HKEY hClassesKey;
635     HKEY hClassKey;
636     DWORD dwLength;
637     DWORD dwIndex;
638     LONG lError;
639     DWORD dwGuidListIndex = 0;
640
641     TRACE("\n");
642
643     if (RequiredSize != NULL)
644         *RequiredSize = 0;
645
646     hClassesKey = SetupDiOpenClassRegKeyExW(NULL,
647                                             KEY_ALL_ACCESS,
648                                             DIOCR_INSTALLER,
649                                             MachineName,
650                                             Reserved);
651     if (hClassesKey == INVALID_HANDLE_VALUE)
652     {
653         return FALSE;
654     }
655
656     for (dwIndex = 0; ; dwIndex++)
657     {
658         dwLength = 40;
659         lError = RegEnumKeyExW(hClassesKey,
660                                dwIndex,
661                                szKeyName,
662                                &dwLength,
663                                NULL,
664                                NULL,
665                                NULL,
666                                NULL);
667         TRACE("RegEnumKeyExW() returns %d\n", lError);
668         if (lError == ERROR_SUCCESS || lError == ERROR_MORE_DATA)
669         {
670             TRACE("Key name: %p\n", szKeyName);
671
672             if (RegOpenKeyExW(hClassesKey,
673                               szKeyName,
674                               0,
675                               KEY_ALL_ACCESS,
676                               &hClassKey))
677             {
678                 RegCloseKey(hClassesKey);
679                 return FALSE;
680             }
681
682             if (!RegQueryValueExW(hClassKey,
683                                   NoUseClass,
684                                   NULL,
685                                   NULL,
686                                   NULL,
687                                   NULL))
688             {
689                 TRACE("'NoUseClass' value found!\n");
690                 RegCloseKey(hClassKey);
691                 continue;
692             }
693
694             if ((Flags & DIBCI_NOINSTALLCLASS) &&
695                 (!RegQueryValueExW(hClassKey,
696                                    NoInstallClass,
697                                    NULL,
698                                    NULL,
699                                    NULL,
700                                    NULL)))
701             {
702                 TRACE("'NoInstallClass' value found!\n");
703                 RegCloseKey(hClassKey);
704                 continue;
705             }
706
707             if ((Flags & DIBCI_NODISPLAYCLASS) &&
708                 (!RegQueryValueExW(hClassKey,
709                                    NoDisplayClass,
710                                    NULL,
711                                    NULL,
712                                    NULL,
713                                    NULL)))
714             {
715                 TRACE("'NoDisplayClass' value found!\n");
716                 RegCloseKey(hClassKey);
717                 continue;
718             }
719
720             RegCloseKey(hClassKey);
721
722             TRACE("Guid: %p\n", szKeyName);
723             if (dwGuidListIndex < ClassGuidListSize)
724             {
725                 if (szKeyName[0] == '{' && szKeyName[37] == '}')
726                 {
727                     szKeyName[37] = 0;
728                 }
729                 TRACE("Guid: %p\n", &szKeyName[1]);
730
731                 UuidFromStringW(&szKeyName[1],
732                                 &ClassGuidList[dwGuidListIndex]);
733             }
734
735             dwGuidListIndex++;
736         }
737
738         if (lError != ERROR_SUCCESS)
739             break;
740     }
741
742     RegCloseKey(hClassesKey);
743
744     if (RequiredSize != NULL)
745         *RequiredSize = dwGuidListIndex;
746
747     if (ClassGuidListSize < dwGuidListIndex)
748     {
749         SetLastError(ERROR_INSUFFICIENT_BUFFER);
750         return FALSE;
751     }
752
753     return TRUE;
754 }
755
756 /***********************************************************************
757  *              SetupDiClassGuidsFromNameA  (SETUPAPI.@)
758  */
759 BOOL WINAPI SetupDiClassGuidsFromNameA(
760         LPCSTR ClassName,
761         LPGUID ClassGuidList,
762         DWORD ClassGuidListSize,
763         PDWORD RequiredSize)
764 {
765   return SetupDiClassGuidsFromNameExA(ClassName, ClassGuidList,
766                                       ClassGuidListSize, RequiredSize,
767                                       NULL, NULL);
768 }
769
770 /***********************************************************************
771  *              SetupDiClassGuidsFromNameW  (SETUPAPI.@)
772  */
773 BOOL WINAPI SetupDiClassGuidsFromNameW(
774         LPCWSTR ClassName,
775         LPGUID ClassGuidList,
776         DWORD ClassGuidListSize,
777         PDWORD RequiredSize)
778 {
779   return SetupDiClassGuidsFromNameExW(ClassName, ClassGuidList,
780                                       ClassGuidListSize, RequiredSize,
781                                       NULL, NULL);
782 }
783
784 /***********************************************************************
785  *              SetupDiClassGuidsFromNameExA  (SETUPAPI.@)
786  */
787 BOOL WINAPI SetupDiClassGuidsFromNameExA(
788         LPCSTR ClassName,
789         LPGUID ClassGuidList,
790         DWORD ClassGuidListSize,
791         PDWORD RequiredSize,
792         LPCSTR MachineName,
793         PVOID Reserved)
794 {
795     LPWSTR ClassNameW = NULL;
796     LPWSTR MachineNameW = NULL;
797     BOOL bResult;
798
799     ClassNameW = MultiByteToUnicode(ClassName, CP_ACP);
800     if (ClassNameW == NULL)
801         return FALSE;
802
803     if (MachineName)
804     {
805         MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
806         if (MachineNameW == NULL)
807         {
808             MyFree(ClassNameW);
809             return FALSE;
810         }
811     }
812
813     bResult = SetupDiClassGuidsFromNameExW(ClassNameW, ClassGuidList,
814                                            ClassGuidListSize, RequiredSize,
815                                            MachineNameW, Reserved);
816
817     MyFree(MachineNameW);
818     MyFree(ClassNameW);
819
820     return bResult;
821 }
822
823 /***********************************************************************
824  *              SetupDiClassGuidsFromNameExW  (SETUPAPI.@)
825  */
826 BOOL WINAPI SetupDiClassGuidsFromNameExW(
827         LPCWSTR ClassName,
828         LPGUID ClassGuidList,
829         DWORD ClassGuidListSize,
830         PDWORD RequiredSize,
831         LPCWSTR MachineName,
832         PVOID Reserved)
833 {
834     WCHAR szKeyName[40];
835     WCHAR szClassName[256];
836     HKEY hClassesKey;
837     HKEY hClassKey;
838     DWORD dwLength;
839     DWORD dwIndex;
840     LONG lError;
841     DWORD dwGuidListIndex = 0;
842
843     if (RequiredSize != NULL)
844         *RequiredSize = 0;
845
846     hClassesKey = SetupDiOpenClassRegKeyExW(NULL,
847                                             KEY_ALL_ACCESS,
848                                             DIOCR_INSTALLER,
849                                             MachineName,
850                                             Reserved);
851     if (hClassesKey == INVALID_HANDLE_VALUE)
852     {
853         return FALSE;
854     }
855
856     for (dwIndex = 0; ; dwIndex++)
857     {
858         dwLength = 40;
859         lError = RegEnumKeyExW(hClassesKey,
860                                dwIndex,
861                                szKeyName,
862                                &dwLength,
863                                NULL,
864                                NULL,
865                                NULL,
866                                NULL);
867         TRACE("RegEnumKeyExW() returns %d\n", lError);
868         if (lError == ERROR_SUCCESS || lError == ERROR_MORE_DATA)
869         {
870             TRACE("Key name: %p\n", szKeyName);
871
872             if (RegOpenKeyExW(hClassesKey,
873                               szKeyName,
874                               0,
875                               KEY_ALL_ACCESS,
876                               &hClassKey))
877             {
878                 RegCloseKey(hClassesKey);
879                 return FALSE;
880             }
881
882             dwLength = 256 * sizeof(WCHAR);
883             if (!RegQueryValueExW(hClassKey,
884                                   Class,
885                                   NULL,
886                                   NULL,
887                                   (LPBYTE)szClassName,
888                                   &dwLength))
889             {
890                 TRACE("Class name: %p\n", szClassName);
891
892                 if (strcmpiW(szClassName, ClassName) == 0)
893                 {
894                     TRACE("Found matching class name\n");
895
896                     TRACE("Guid: %p\n", szKeyName);
897                     if (dwGuidListIndex < ClassGuidListSize)
898                     {
899                         if (szKeyName[0] == '{' && szKeyName[37] == '}')
900                         {
901                             szKeyName[37] = 0;
902                         }
903                         TRACE("Guid: %p\n", &szKeyName[1]);
904
905                         UuidFromStringW(&szKeyName[1],
906                                         &ClassGuidList[dwGuidListIndex]);
907                     }
908
909                     dwGuidListIndex++;
910                 }
911             }
912
913             RegCloseKey(hClassKey);
914         }
915
916         if (lError != ERROR_SUCCESS)
917             break;
918     }
919
920     RegCloseKey(hClassesKey);
921
922     if (RequiredSize != NULL)
923         *RequiredSize = dwGuidListIndex;
924
925     if (ClassGuidListSize < dwGuidListIndex)
926     {
927         SetLastError(ERROR_INSUFFICIENT_BUFFER);
928         return FALSE;
929     }
930
931     return TRUE;
932 }
933
934 /***********************************************************************
935  *              SetupDiClassNameFromGuidA  (SETUPAPI.@)
936  */
937 BOOL WINAPI SetupDiClassNameFromGuidA(
938         const GUID* ClassGuid,
939         PSTR ClassName,
940         DWORD ClassNameSize,
941         PDWORD RequiredSize)
942 {
943   return SetupDiClassNameFromGuidExA(ClassGuid, ClassName,
944                                      ClassNameSize, RequiredSize,
945                                      NULL, NULL);
946 }
947
948 /***********************************************************************
949  *              SetupDiClassNameFromGuidW  (SETUPAPI.@)
950  */
951 BOOL WINAPI SetupDiClassNameFromGuidW(
952         const GUID* ClassGuid,
953         PWSTR ClassName,
954         DWORD ClassNameSize,
955         PDWORD RequiredSize)
956 {
957   return SetupDiClassNameFromGuidExW(ClassGuid, ClassName,
958                                      ClassNameSize, RequiredSize,
959                                      NULL, NULL);
960 }
961
962 /***********************************************************************
963  *              SetupDiClassNameFromGuidExA  (SETUPAPI.@)
964  */
965 BOOL WINAPI SetupDiClassNameFromGuidExA(
966         const GUID* ClassGuid,
967         PSTR ClassName,
968         DWORD ClassNameSize,
969         PDWORD RequiredSize,
970         PCSTR MachineName,
971         PVOID Reserved)
972 {
973     WCHAR ClassNameW[MAX_CLASS_NAME_LEN];
974     LPWSTR MachineNameW = NULL;
975     BOOL ret;
976
977     if (MachineName)
978         MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
979     ret = SetupDiClassNameFromGuidExW(ClassGuid, ClassNameW, MAX_CLASS_NAME_LEN,
980      NULL, MachineNameW, Reserved);
981     if (ret)
982     {
983         int len = WideCharToMultiByte(CP_ACP, 0, ClassNameW, -1, ClassName,
984          ClassNameSize, NULL, NULL);
985
986         if (!ClassNameSize && RequiredSize)
987             *RequiredSize = len;
988     }
989     MyFree(MachineNameW);
990     return ret;
991 }
992
993 /***********************************************************************
994  *              SetupDiClassNameFromGuidExW  (SETUPAPI.@)
995  */
996 BOOL WINAPI SetupDiClassNameFromGuidExW(
997         const GUID* ClassGuid,
998         PWSTR ClassName,
999         DWORD ClassNameSize,
1000         PDWORD RequiredSize,
1001         PCWSTR MachineName,
1002         PVOID Reserved)
1003 {
1004     HKEY hKey;
1005     DWORD dwLength;
1006
1007     hKey = SetupDiOpenClassRegKeyExW(ClassGuid,
1008                                      KEY_ALL_ACCESS,
1009                                      DIOCR_INSTALLER,
1010                                      MachineName,
1011                                      Reserved);
1012     if (hKey == INVALID_HANDLE_VALUE)
1013     {
1014         return FALSE;
1015     }
1016
1017     if (RequiredSize != NULL)
1018     {
1019         dwLength = 0;
1020         if (RegQueryValueExW(hKey,
1021                              Class,
1022                              NULL,
1023                              NULL,
1024                              NULL,
1025                              &dwLength))
1026         {
1027             RegCloseKey(hKey);
1028             return FALSE;
1029         }
1030
1031         *RequiredSize = dwLength / sizeof(WCHAR);
1032     }
1033
1034     dwLength = ClassNameSize * sizeof(WCHAR);
1035     if (RegQueryValueExW(hKey,
1036                          Class,
1037                          NULL,
1038                          NULL,
1039                          (LPBYTE)ClassName,
1040                          &dwLength))
1041     {
1042         RegCloseKey(hKey);
1043         return FALSE;
1044     }
1045
1046     RegCloseKey(hKey);
1047
1048     return TRUE;
1049 }
1050
1051 /***********************************************************************
1052  *              SetupDiCreateDeviceInfoList (SETUPAPI.@)
1053  */
1054 HDEVINFO WINAPI
1055 SetupDiCreateDeviceInfoList(const GUID *ClassGuid,
1056                             HWND hwndParent)
1057 {
1058   return SetupDiCreateDeviceInfoListExW(ClassGuid, hwndParent, NULL, NULL);
1059 }
1060
1061 /***********************************************************************
1062  *              SetupDiCreateDeviceInfoListExA (SETUPAPI.@)
1063  */
1064 HDEVINFO WINAPI
1065 SetupDiCreateDeviceInfoListExA(const GUID *ClassGuid,
1066                                HWND hwndParent,
1067                                PCSTR MachineName,
1068                                PVOID Reserved)
1069 {
1070     LPWSTR MachineNameW = NULL;
1071     HDEVINFO hDevInfo;
1072
1073     TRACE("\n");
1074
1075     if (MachineName)
1076     {
1077         MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
1078         if (MachineNameW == NULL)
1079             return (HDEVINFO)INVALID_HANDLE_VALUE;
1080     }
1081
1082     hDevInfo = SetupDiCreateDeviceInfoListExW(ClassGuid, hwndParent,
1083                                               MachineNameW, Reserved);
1084
1085     MyFree(MachineNameW);
1086
1087     return hDevInfo;
1088 }
1089
1090 /***********************************************************************
1091  *              SetupDiCreateDeviceInfoListExW (SETUPAPI.@)
1092  *
1093  * Create an empty DeviceInfoSet list.
1094  *
1095  * PARAMS
1096  *   ClassGuid [I] if not NULL only devices with GUID ClcassGuid are associated
1097  *                 with this list.
1098  *   hwndParent [I] hwnd needed for interface related actions.
1099  *   MachineName [I] name of machine to create emtpy DeviceInfoSet list, if NULL
1100  *                   local registry will be used.
1101  *   Reserved [I] must be NULL
1102  *
1103  * RETURNS
1104  *   Success: empty list.
1105  *   Failure: INVALID_HANDLE_VALUE.
1106  */
1107 HDEVINFO WINAPI
1108 SetupDiCreateDeviceInfoListExW(const GUID *ClassGuid,
1109                                HWND hwndParent,
1110                                PCWSTR MachineName,
1111                                PVOID Reserved)
1112 {
1113     struct DeviceInfoSet *list = NULL;
1114     DWORD size = sizeof(struct DeviceInfoSet);
1115
1116     TRACE("%s %p %s %p\n", debugstr_guid(ClassGuid), hwndParent,
1117       debugstr_w(MachineName), Reserved);
1118
1119     if (MachineName != NULL)
1120     {
1121         FIXME("remote support is not implemented\n");
1122         SetLastError(ERROR_INVALID_MACHINENAME);
1123         return (HDEVINFO)INVALID_HANDLE_VALUE;
1124     }
1125
1126     if (Reserved != NULL)
1127     {
1128         SetLastError(ERROR_INVALID_PARAMETER);
1129         return (HDEVINFO)INVALID_HANDLE_VALUE;
1130     }
1131
1132     list = HeapAlloc(GetProcessHeap(), 0, size);
1133     if (!list)
1134     {
1135         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1136         return (HDEVINFO)INVALID_HANDLE_VALUE;
1137     }
1138
1139     list->magic = SETUP_DEVICE_INFO_SET_MAGIC;
1140     list->hwndParent = hwndParent;
1141     memcpy(&list->ClassGuid,
1142             ClassGuid ? ClassGuid : &GUID_NULL,
1143             sizeof(list->ClassGuid));
1144     list->cDevices = 0;
1145     list->devices = NULL;
1146
1147     return (HDEVINFO)list;
1148 }
1149
1150 /***********************************************************************
1151  *              SetupDiCreateDeviceInfoA (SETUPAPI.@)
1152  */
1153 BOOL WINAPI SetupDiCreateDeviceInfoA(
1154        HDEVINFO DeviceInfoSet,
1155        PCSTR DeviceName,
1156        CONST GUID *ClassGuid,
1157        PCSTR DeviceDescription,
1158        HWND hwndParent,
1159        DWORD CreationFlags,
1160        PSP_DEVINFO_DATA DeviceInfoData)
1161 {
1162     BOOL ret = FALSE;
1163     LPWSTR DeviceNameW = NULL;
1164     LPWSTR DeviceDescriptionW = NULL;
1165
1166     if (DeviceName)
1167     {
1168         DeviceNameW = MultiByteToUnicode(DeviceName, CP_ACP);
1169         if (DeviceNameW == NULL) return FALSE;
1170     }
1171     if (DeviceDescription)
1172     {
1173         DeviceDescriptionW = MultiByteToUnicode(DeviceDescription, CP_ACP);
1174         if (DeviceDescriptionW == NULL)
1175         {
1176             MyFree(DeviceNameW);
1177             return FALSE;
1178         }
1179     }
1180
1181     ret = SetupDiCreateDeviceInfoW(DeviceInfoSet, DeviceNameW, ClassGuid, DeviceDescriptionW,
1182             hwndParent, CreationFlags, DeviceInfoData);
1183
1184     MyFree(DeviceNameW);
1185     MyFree(DeviceDescriptionW);
1186
1187     return ret;
1188 }
1189
1190 static DWORD SETUPDI_DevNameToDevID(LPCWSTR devName)
1191 {
1192     LPCWSTR ptr;
1193     DWORD devNameLen = lstrlenW(devName), devInst = 0;
1194     BOOL valid = TRUE;
1195
1196     TRACE("%s\n", debugstr_w(devName));
1197     for (ptr = devName; valid && *ptr && ptr - devName < devNameLen; )
1198     {
1199         if (isdigitW(*ptr))
1200         {
1201             devInst *= 10;
1202             devInst |= *ptr - '0';
1203             ptr++;
1204         }
1205         else
1206             valid = FALSE;
1207     }
1208     TRACE("%d\n", valid ? devInst : 0xffffffff);
1209     return valid ? devInst : 0xffffffff;
1210 }
1211
1212 /***********************************************************************
1213  *              SetupDiCreateDeviceInfoW (SETUPAPI.@)
1214  */
1215 BOOL WINAPI SetupDiCreateDeviceInfoW(
1216        HDEVINFO DeviceInfoSet,
1217        PCWSTR DeviceName,
1218        CONST GUID *ClassGuid,
1219        PCWSTR DeviceDescription,
1220        HWND hwndParent,
1221        DWORD CreationFlags,
1222        PSP_DEVINFO_DATA DeviceInfoData)
1223 {
1224     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
1225     BOOL ret = FALSE, allocatedInstanceId = FALSE;
1226     LPCWSTR instanceId = NULL;
1227
1228     TRACE("%p %s %s %s %p %x %p\n", DeviceInfoSet, debugstr_w(DeviceName),
1229         debugstr_guid(ClassGuid), debugstr_w(DeviceDescription),
1230         hwndParent, CreationFlags, DeviceInfoData);
1231
1232     if (!DeviceName)
1233     {
1234         SetLastError(ERROR_INVALID_DEVINST_NAME);
1235         return FALSE;
1236     }
1237     if (!DeviceInfoSet || DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
1238     {
1239         SetLastError(ERROR_INVALID_HANDLE);
1240         return FALSE;
1241     }
1242     if (!ClassGuid)
1243     {
1244         SetLastError(ERROR_INVALID_PARAMETER);
1245         return FALSE;
1246     }
1247     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
1248     {
1249         SetLastError(ERROR_INVALID_HANDLE);
1250         return FALSE;
1251     }
1252     if (!IsEqualGUID(&set->ClassGuid, &GUID_NULL) &&
1253         !IsEqualGUID(ClassGuid, &set->ClassGuid))
1254     {
1255         SetLastError(ERROR_CLASS_MISMATCH);
1256         return FALSE;
1257     }
1258     if ((CreationFlags & DICD_GENERATE_ID))
1259     {
1260         if (strchrW(DeviceName, '\\'))
1261             SetLastError(ERROR_INVALID_DEVINST_NAME);
1262         else
1263         {
1264             static const WCHAR newDeviceFmt[] = {'R','O','O','T','\\','%','s',
1265                 '\\','%','0','4','d',0};
1266             DWORD devId;
1267
1268             if (set->cDevices)
1269             {
1270                 DWORD i, highestDevID = 0;
1271
1272                 for (i = 0; i < set->cDevices; i++)
1273                 {
1274                     struct DeviceInfo *devInfo =
1275                         (struct DeviceInfo *)set->devices[i].Reserved;
1276                     LPCWSTR devName = strrchrW(devInfo->instanceId, '\\');
1277                     DWORD id;
1278
1279                     if (devName)
1280                         devName++;
1281                     else
1282                         devName = devInfo->instanceId;
1283                     id = SETUPDI_DevNameToDevID(devName);
1284                     if (id != 0xffffffff && id > highestDevID)
1285                         highestDevID = id;
1286                 }
1287                 devId = highestDevID + 1;
1288             }
1289             else
1290                 devId = 0;
1291             /* 17 == lstrlenW(L"Root\\") + lstrlenW("\\") + 1 + %d max size */
1292             instanceId = HeapAlloc(GetProcessHeap(), 0,
1293                     (17 + lstrlenW(DeviceName)) * sizeof(WCHAR));
1294             if (instanceId)
1295             {
1296                 sprintfW((LPWSTR)instanceId, newDeviceFmt, DeviceName,
1297                         devId);
1298                 allocatedInstanceId = TRUE;
1299                 ret = TRUE;
1300             }
1301             else
1302                 ret = FALSE;
1303         }
1304     }
1305     else
1306     {
1307         DWORD i;
1308
1309         ret = TRUE;
1310         instanceId = DeviceName;
1311         for (i = 0; ret && i < set->cDevices; i++)
1312         {
1313             struct DeviceInfo *devInfo =
1314                 (struct DeviceInfo *)set->devices[i].Reserved;
1315
1316             if (!lstrcmpiW(DeviceName, devInfo->instanceId))
1317             {
1318                 SetLastError(ERROR_DEVINST_ALREADY_EXISTS);
1319                 ret = FALSE;
1320             }
1321         }
1322     }
1323     if (ret)
1324     {
1325         SP_DEVINFO_DATA *dev = NULL;
1326
1327         ret = SETUPDI_AddDeviceToSet(set, ClassGuid, 0 /* FIXME: DevInst */,
1328                 instanceId, TRUE, &dev);
1329         if (ret)
1330         {
1331             if (DeviceDescription)
1332                 SetupDiSetDeviceRegistryPropertyW(DeviceInfoSet,
1333                     dev, SPDRP_DEVICEDESC, (const BYTE *)DeviceDescription,
1334                     lstrlenW(DeviceDescription) * sizeof(WCHAR));
1335             if (DeviceInfoData)
1336             {
1337                 if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
1338                 {
1339                     SetLastError(ERROR_INVALID_USER_BUFFER);
1340                     ret = FALSE;
1341                 }
1342                 else
1343                     memcpy(DeviceInfoData, dev, sizeof(SP_DEVINFO_DATA));
1344             }
1345         }
1346     }
1347     if (allocatedInstanceId)
1348         HeapFree(GetProcessHeap(), 0, (LPWSTR)instanceId);
1349
1350     return ret;
1351 }
1352
1353 /***********************************************************************
1354  *              SetupDiRegisterDeviceInfo (SETUPAPI.@)
1355  */
1356 BOOL WINAPI SetupDiRegisterDeviceInfo(
1357         HDEVINFO DeviceInfoSet,
1358         PSP_DEVINFO_DATA DeviceInfoData,
1359         DWORD Flags,
1360         PSP_DETSIG_CMPPROC CompareProc,
1361         PVOID CompareContext,
1362         PSP_DEVINFO_DATA DupDeviceInfoData)
1363 {
1364     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
1365     struct DeviceInfo *devInfo;
1366
1367     TRACE("%p %p %08x %p %p %p\n", DeviceInfoSet, DeviceInfoData, Flags,
1368             CompareProc, CompareContext, DupDeviceInfoData);
1369
1370     if (!DeviceInfoSet || DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
1371     {
1372         SetLastError(ERROR_INVALID_HANDLE);
1373         return FALSE;
1374     }
1375     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
1376     {
1377         SetLastError(ERROR_INVALID_HANDLE);
1378         return FALSE;
1379     }
1380     if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
1381             || !DeviceInfoData->Reserved)
1382     {
1383         SetLastError(ERROR_INVALID_PARAMETER);
1384         return FALSE;
1385     }
1386     devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
1387     if (devInfo->set != set)
1388     {
1389         SetLastError(ERROR_INVALID_PARAMETER);
1390         return FALSE;
1391     }
1392     if (devInfo->phantom)
1393     {
1394         devInfo->phantom = FALSE;
1395         RegDeleteValueW(devInfo->key, Phantom);
1396     }
1397     return TRUE;
1398 }
1399
1400 /***********************************************************************
1401  *              SetupDiEnumDeviceInfo (SETUPAPI.@)
1402  */
1403 BOOL WINAPI SetupDiEnumDeviceInfo(
1404         HDEVINFO  devinfo,
1405         DWORD  index,
1406         PSP_DEVINFO_DATA info)
1407 {
1408     BOOL ret = FALSE;
1409
1410     TRACE("%p %d %p\n", devinfo, index, info);
1411
1412     if(info==NULL)
1413     {
1414         SetLastError(ERROR_INVALID_PARAMETER);
1415         return FALSE;
1416     }
1417     if (devinfo && devinfo != (HDEVINFO)INVALID_HANDLE_VALUE)
1418     {
1419         struct DeviceInfoSet *list = (struct DeviceInfoSet *)devinfo;
1420         if (list->magic == SETUP_DEVICE_INFO_SET_MAGIC)
1421         {
1422             if (index < list->cDevices)
1423             {
1424                 if (info->cbSize == sizeof(SP_DEVINFO_DATA))
1425                 {
1426                     memcpy(info, &list->devices[index], info->cbSize);
1427                     ret = TRUE;
1428                 }
1429                 else
1430                     SetLastError(ERROR_INVALID_USER_BUFFER);
1431             }
1432             else
1433                 SetLastError(ERROR_NO_MORE_ITEMS);
1434         }
1435         else
1436             SetLastError(ERROR_INVALID_HANDLE);
1437     }
1438     else
1439         SetLastError(ERROR_INVALID_HANDLE);
1440     return ret;
1441 }
1442
1443 /***********************************************************************
1444  *              SetupDiGetDeviceInstanceIdA (SETUPAPI.@)
1445  */
1446 BOOL WINAPI SetupDiGetDeviceInstanceIdA(
1447         HDEVINFO DeviceInfoSet,
1448         PSP_DEVINFO_DATA DeviceInfoData,
1449         PSTR DeviceInstanceId,
1450         DWORD DeviceInstanceIdSize,
1451         PDWORD RequiredSize)
1452 {
1453     BOOL ret = FALSE;
1454     DWORD size;
1455     PWSTR instanceId;
1456
1457     TRACE("%p %p %p %d %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstanceId,
1458             DeviceInstanceIdSize, RequiredSize);
1459
1460     SetupDiGetDeviceInstanceIdW(DeviceInfoSet,
1461                                 DeviceInfoData,
1462                                 NULL,
1463                                 0,
1464                                 &size);
1465     if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
1466         return FALSE;
1467     instanceId = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
1468     if (instanceId)
1469     {
1470         ret = SetupDiGetDeviceInstanceIdW(DeviceInfoSet,
1471                                           DeviceInfoData,
1472                                           instanceId,
1473                                           size,
1474                                           &size);
1475         if (ret)
1476         {
1477             int len = WideCharToMultiByte(CP_ACP, 0, instanceId, -1,
1478                                           DeviceInstanceId,
1479                                           DeviceInstanceIdSize, NULL, NULL);
1480
1481             if (!len)
1482                 ret = FALSE;
1483             else
1484             {
1485                 if (len > DeviceInstanceIdSize)
1486                 {
1487                     SetLastError(ERROR_INSUFFICIENT_BUFFER);
1488                     ret = FALSE;
1489                 }
1490                 if (RequiredSize)
1491                     *RequiredSize = len;
1492             }
1493         }
1494         HeapFree(GetProcessHeap(), 0, instanceId);
1495     }
1496     return ret;
1497 }
1498
1499 /***********************************************************************
1500  *              SetupDiGetDeviceInstanceIdW (SETUPAPI.@)
1501  */
1502 BOOL WINAPI SetupDiGetDeviceInstanceIdW(
1503         HDEVINFO DeviceInfoSet,
1504         PSP_DEVINFO_DATA DeviceInfoData,
1505         PWSTR DeviceInstanceId,
1506         DWORD DeviceInstanceIdSize,
1507         PDWORD RequiredSize)
1508 {
1509     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
1510     struct DeviceInfo *devInfo;
1511
1512     TRACE("%p %p %p %d %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstanceId,
1513             DeviceInstanceIdSize, RequiredSize);
1514
1515     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
1516     {
1517         SetLastError(ERROR_INVALID_HANDLE);
1518         return FALSE;
1519     }
1520     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
1521     {
1522         SetLastError(ERROR_INVALID_HANDLE);
1523         return FALSE;
1524     }
1525     if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
1526             || !DeviceInfoData->Reserved)
1527     {
1528         SetLastError(ERROR_INVALID_PARAMETER);
1529         return FALSE;
1530     }
1531     devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
1532     if (devInfo->set != set)
1533     {
1534         SetLastError(ERROR_INVALID_PARAMETER);
1535         return FALSE;
1536     }
1537     TRACE("instance ID: %s\n", debugstr_w(devInfo->instanceId));
1538     if (DeviceInstanceIdSize < lstrlenW(devInfo->instanceId) + 1)
1539     {
1540         SetLastError(ERROR_INSUFFICIENT_BUFFER);
1541         if (RequiredSize)
1542             *RequiredSize = lstrlenW(devInfo->instanceId) + 1;
1543         return FALSE;
1544     }
1545     lstrcpyW(DeviceInstanceId, devInfo->instanceId);
1546     if (RequiredSize)
1547         *RequiredSize = lstrlenW(devInfo->instanceId) + 1;
1548     return TRUE;
1549 }
1550
1551 /***********************************************************************
1552  *              SetupDiGetActualSectionToInstallA (SETUPAPI.@)
1553  */
1554 BOOL WINAPI SetupDiGetActualSectionToInstallA(
1555         HINF InfHandle,
1556         PCSTR InfSectionName,
1557         PSTR InfSectionWithExt,
1558         DWORD InfSectionWithExtSize,
1559         PDWORD RequiredSize,
1560         PSTR *Extension)
1561 {
1562     FIXME("\n");
1563     return FALSE;
1564 }
1565
1566 /***********************************************************************
1567  *              SetupDiGetActualSectionToInstallW (SETUPAPI.@)
1568  */
1569 BOOL WINAPI SetupDiGetActualSectionToInstallW(
1570         HINF InfHandle,
1571         PCWSTR InfSectionName,
1572         PWSTR InfSectionWithExt,
1573         DWORD InfSectionWithExtSize,
1574         PDWORD RequiredSize,
1575         PWSTR *Extension)
1576 {
1577     WCHAR szBuffer[MAX_PATH];
1578     DWORD dwLength;
1579     DWORD dwFullLength;
1580     LONG lLineCount = -1;
1581
1582     lstrcpyW(szBuffer, InfSectionName);
1583     dwLength = lstrlenW(szBuffer);
1584
1585     if (OsVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
1586     {
1587         /* Test section name with '.NTx86' extension */
1588         lstrcpyW(&szBuffer[dwLength], NtPlatformExtension);
1589         lLineCount = SetupGetLineCountW(InfHandle, szBuffer);
1590
1591         if (lLineCount == -1)
1592         {
1593             /* Test section name with '.NT' extension */
1594             lstrcpyW(&szBuffer[dwLength], NtExtension);
1595             lLineCount = SetupGetLineCountW(InfHandle, szBuffer);
1596         }
1597     }
1598     else
1599     {
1600         /* Test section name with '.Win' extension */
1601         lstrcpyW(&szBuffer[dwLength], WinExtension);
1602         lLineCount = SetupGetLineCountW(InfHandle, szBuffer);
1603     }
1604
1605     if (lLineCount == -1)
1606     {
1607         /* Test section name without extension */
1608         szBuffer[dwLength] = 0;
1609         lLineCount = SetupGetLineCountW(InfHandle, szBuffer);
1610     }
1611
1612     if (lLineCount == -1)
1613     {
1614         SetLastError(ERROR_INVALID_PARAMETER);
1615         return FALSE;
1616     }
1617
1618     dwFullLength = lstrlenW(szBuffer);
1619
1620     if (InfSectionWithExt != NULL && InfSectionWithExtSize != 0)
1621     {
1622         if (InfSectionWithExtSize < (dwFullLength + 1))
1623         {
1624             SetLastError(ERROR_INSUFFICIENT_BUFFER);
1625             return FALSE;
1626         }
1627
1628         lstrcpyW(InfSectionWithExt, szBuffer);
1629         if (Extension != NULL)
1630         {
1631             *Extension = (dwLength == dwFullLength) ? NULL : &InfSectionWithExt[dwLength];
1632         }
1633     }
1634
1635     if (RequiredSize != NULL)
1636     {
1637         *RequiredSize = dwFullLength + 1;
1638     }
1639
1640     return TRUE;
1641 }
1642
1643 /***********************************************************************
1644  *              SetupDiGetClassDescriptionA  (SETUPAPI.@)
1645  */
1646 BOOL WINAPI SetupDiGetClassDescriptionA(
1647         const GUID* ClassGuid,
1648         PSTR ClassDescription,
1649         DWORD ClassDescriptionSize,
1650         PDWORD RequiredSize)
1651 {
1652   return SetupDiGetClassDescriptionExA(ClassGuid, ClassDescription,
1653                                        ClassDescriptionSize,
1654                                        RequiredSize, NULL, NULL);
1655 }
1656
1657 /***********************************************************************
1658  *              SetupDiGetClassDescriptionW  (SETUPAPI.@)
1659  */
1660 BOOL WINAPI SetupDiGetClassDescriptionW(
1661         const GUID* ClassGuid,
1662         PWSTR ClassDescription,
1663         DWORD ClassDescriptionSize,
1664         PDWORD RequiredSize)
1665 {
1666   return SetupDiGetClassDescriptionExW(ClassGuid, ClassDescription,
1667                                        ClassDescriptionSize,
1668                                        RequiredSize, NULL, NULL);
1669 }
1670
1671 /***********************************************************************
1672  *              SetupDiGetClassDescriptionExA  (SETUPAPI.@)
1673  */
1674 BOOL WINAPI SetupDiGetClassDescriptionExA(
1675         const GUID* ClassGuid,
1676         PSTR ClassDescription,
1677         DWORD ClassDescriptionSize,
1678         PDWORD RequiredSize,
1679         PCSTR MachineName,
1680         PVOID Reserved)
1681 {
1682     HKEY hKey;
1683     DWORD dwLength;
1684     BOOL ret;
1685
1686     hKey = SetupDiOpenClassRegKeyExA(ClassGuid,
1687                                      KEY_ALL_ACCESS,
1688                                      DIOCR_INSTALLER,
1689                                      MachineName,
1690                                      Reserved);
1691     if (hKey == INVALID_HANDLE_VALUE)
1692     {
1693         WARN("SetupDiOpenClassRegKeyExA() failed (Error %u)\n", GetLastError());
1694         return FALSE;
1695     }
1696
1697     dwLength = ClassDescriptionSize;
1698     ret = !RegQueryValueExA( hKey, NULL, NULL, NULL,
1699                              (LPBYTE)ClassDescription, &dwLength );
1700     if (RequiredSize) *RequiredSize = dwLength;
1701     RegCloseKey(hKey);
1702     return ret;
1703 }
1704
1705 /***********************************************************************
1706  *              SetupDiGetClassDescriptionExW  (SETUPAPI.@)
1707  */
1708 BOOL WINAPI SetupDiGetClassDescriptionExW(
1709         const GUID* ClassGuid,
1710         PWSTR ClassDescription,
1711         DWORD ClassDescriptionSize,
1712         PDWORD RequiredSize,
1713         PCWSTR MachineName,
1714         PVOID Reserved)
1715 {
1716     HKEY hKey;
1717     DWORD dwLength;
1718     BOOL ret;
1719
1720     hKey = SetupDiOpenClassRegKeyExW(ClassGuid,
1721                                      KEY_ALL_ACCESS,
1722                                      DIOCR_INSTALLER,
1723                                      MachineName,
1724                                      Reserved);
1725     if (hKey == INVALID_HANDLE_VALUE)
1726     {
1727         WARN("SetupDiOpenClassRegKeyExW() failed (Error %u)\n", GetLastError());
1728         return FALSE;
1729     }
1730
1731     dwLength = ClassDescriptionSize * sizeof(WCHAR);
1732     ret = !RegQueryValueExW( hKey, NULL, NULL, NULL,
1733                              (LPBYTE)ClassDescription, &dwLength );
1734     if (RequiredSize) *RequiredSize = dwLength / sizeof(WCHAR);
1735     RegCloseKey(hKey);
1736     return ret;
1737 }
1738
1739 /***********************************************************************
1740  *              SetupDiGetClassDevsA (SETUPAPI.@)
1741  */
1742 HDEVINFO WINAPI SetupDiGetClassDevsA(
1743        CONST GUID *class,
1744        LPCSTR enumstr,
1745        HWND parent,
1746        DWORD flags)
1747 {
1748     HDEVINFO ret;
1749     LPWSTR enumstrW = NULL;
1750
1751     if (enumstr)
1752     {
1753         int len = MultiByteToWideChar(CP_ACP, 0, enumstr, -1, NULL, 0);
1754         enumstrW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1755         if (!enumstrW)
1756         {
1757             ret = (HDEVINFO)INVALID_HANDLE_VALUE;
1758             goto end;
1759         }
1760         MultiByteToWideChar(CP_ACP, 0, enumstr, -1, enumstrW, len);
1761     }
1762     ret = SetupDiGetClassDevsExW(class, enumstrW, parent, flags, NULL, NULL,
1763             NULL);
1764     HeapFree(GetProcessHeap(), 0, enumstrW);
1765
1766 end:
1767     return ret;
1768 }
1769
1770 /***********************************************************************
1771  *                SetupDiGetClassDevsExA (SETUPAPI.@)
1772  */
1773 HDEVINFO WINAPI SetupDiGetClassDevsExA(
1774         const GUID *class,
1775         PCSTR enumstr,
1776         HWND parent,
1777         DWORD flags,
1778         HDEVINFO deviceset,
1779         PCSTR machine,
1780         PVOID reserved)
1781 {
1782     HDEVINFO ret;
1783     LPWSTR enumstrW = NULL, machineW = NULL;
1784
1785     if (enumstr)
1786     {
1787         int len = MultiByteToWideChar(CP_ACP, 0, enumstr, -1, NULL, 0);
1788         enumstrW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1789         if (!enumstrW)
1790         {
1791             ret = (HDEVINFO)INVALID_HANDLE_VALUE;
1792             goto end;
1793         }
1794         MultiByteToWideChar(CP_ACP, 0, enumstr, -1, enumstrW, len);
1795     }
1796     if (machine)
1797     {
1798         int len = MultiByteToWideChar(CP_ACP, 0, machine, -1, NULL, 0);
1799         machineW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1800         if (!machineW)
1801         {
1802             HeapFree(GetProcessHeap(), 0, enumstrW);
1803             ret = (HDEVINFO)INVALID_HANDLE_VALUE;
1804             goto end;
1805         }
1806         MultiByteToWideChar(CP_ACP, 0, machine, -1, machineW, len);
1807     }
1808     ret = SetupDiGetClassDevsExW(class, enumstrW, parent, flags, deviceset,
1809             machineW, reserved);
1810     HeapFree(GetProcessHeap(), 0, enumstrW);
1811     HeapFree(GetProcessHeap(), 0, machineW);
1812
1813 end:
1814     return ret;
1815 }
1816
1817 static void SETUPDI_AddDeviceInterfaces(SP_DEVINFO_DATA *dev, HKEY key,
1818         const GUID *interface)
1819 {
1820     DWORD i, len;
1821     WCHAR subKeyName[MAX_PATH];
1822     LONG l = ERROR_SUCCESS;
1823
1824     for (i = 0; !l; i++)
1825     {
1826         len = sizeof(subKeyName) / sizeof(subKeyName[0]);
1827         l = RegEnumKeyExW(key, i, subKeyName, &len, NULL, NULL, NULL, NULL);
1828         if (!l)
1829         {
1830             HKEY subKey;
1831             SP_DEVICE_INTERFACE_DATA *iface = NULL;
1832
1833             /* The subkey name is the reference string, with a '#' prepended */
1834             SETUPDI_AddInterfaceInstance(dev, interface, subKeyName + 1,
1835                     &iface);
1836             l = RegOpenKeyExW(key, subKeyName, 0, KEY_READ, &subKey);
1837             if (!l)
1838             {
1839                 WCHAR symbolicLink[MAX_PATH];
1840                 DWORD dataType;
1841
1842                 len = sizeof(symbolicLink);
1843                 l = RegQueryValueExW(subKey, SymbolicLink, NULL, &dataType,
1844                         (BYTE *)symbolicLink, &len);
1845                 if (!l && dataType == REG_SZ)
1846                     SETUPDI_SetInterfaceSymbolicLink(iface, symbolicLink);
1847                 RegCloseKey(subKey);
1848             }
1849         }
1850     }
1851     /* FIXME: find and add all the device's interfaces to the device */
1852 }
1853
1854 static void SETUPDI_EnumerateMatchingInterfaces(HDEVINFO DeviceInfoSet,
1855         HKEY key, const GUID *interface, LPCWSTR enumstr)
1856 {
1857     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
1858     DWORD i, len;
1859     WCHAR subKeyName[MAX_PATH];
1860     LONG l;
1861     HKEY enumKey = INVALID_HANDLE_VALUE;
1862
1863     TRACE("%s\n", debugstr_w(enumstr));
1864
1865     l = RegCreateKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, NULL, 0, KEY_READ, NULL,
1866             &enumKey, NULL);
1867     for (i = 0; !l; i++)
1868     {
1869         len = sizeof(subKeyName) / sizeof(subKeyName[0]);
1870         l = RegEnumKeyExW(key, i, subKeyName, &len, NULL, NULL, NULL, NULL);
1871         if (!l)
1872         {
1873             HKEY subKey;
1874
1875             l = RegOpenKeyExW(key, subKeyName, 0, KEY_READ, &subKey);
1876             if (!l)
1877             {
1878                 WCHAR deviceInst[MAX_PATH * 3];
1879                 DWORD dataType;
1880
1881                 len = sizeof(deviceInst);
1882                 l = RegQueryValueExW(subKey, DeviceInstance, NULL, &dataType,
1883                         (BYTE *)deviceInst, &len);
1884                 if (!l && dataType == REG_SZ)
1885                 {
1886                     TRACE("found instance ID %s\n", debugstr_w(deviceInst));
1887                     if (!enumstr || !lstrcmpiW(enumstr, deviceInst))
1888                     {
1889                         HKEY deviceKey;
1890
1891                         l = RegOpenKeyExW(enumKey, deviceInst, 0, KEY_READ,
1892                                 &deviceKey);
1893                         if (!l)
1894                         {
1895                             WCHAR deviceClassStr[40];
1896
1897                             len = sizeof(deviceClassStr);
1898                             l = RegQueryValueExW(deviceKey, ClassGUID, NULL,
1899                                     &dataType, (BYTE *)deviceClassStr, &len);
1900                             if (!l && dataType == REG_SZ &&
1901                                     deviceClassStr[0] == '{' &&
1902                                     deviceClassStr[37] == '}')
1903                             {
1904                                 GUID deviceClass;
1905                                 SP_DEVINFO_DATA *dev;
1906
1907                                 deviceClassStr[37] = 0;
1908                                 UuidFromStringW(&deviceClassStr[1],
1909                                         &deviceClass);
1910                                 if (SETUPDI_AddDeviceToSet(set, &deviceClass,
1911                                         0 /* FIXME: DevInst */, deviceInst,
1912                                         FALSE, &dev))
1913                                     SETUPDI_AddDeviceInterfaces(dev, subKey,
1914                                             interface);
1915                             }
1916                             RegCloseKey(deviceKey);
1917                         }
1918                     }
1919                 }
1920                 RegCloseKey(subKey);
1921             }
1922         }
1923     }
1924     if (enumKey != INVALID_HANDLE_VALUE)
1925         RegCloseKey(enumKey);
1926 }
1927
1928 static void SETUPDI_EnumerateInterfaces(HDEVINFO DeviceInfoSet,
1929         const GUID *interface, LPCWSTR enumstr, DWORD flags)
1930 {
1931     HKEY interfacesKey = SetupDiOpenClassRegKeyExW(interface, KEY_READ,
1932             DIOCR_INTERFACE, NULL, NULL);
1933
1934     TRACE("%p, %s, %s, %08x\n", DeviceInfoSet, debugstr_guid(interface),
1935             debugstr_w(enumstr), flags);
1936
1937     if (interfacesKey != INVALID_HANDLE_VALUE)
1938     {
1939         if (flags & DIGCF_ALLCLASSES)
1940         {
1941             DWORD i, len;
1942             WCHAR interfaceGuidStr[40];
1943             LONG l = ERROR_SUCCESS;
1944
1945             for (i = 0; !l; i++)
1946             {
1947                 len = sizeof(interfaceGuidStr) / sizeof(interfaceGuidStr[0]);
1948                 l = RegEnumKeyExW(interfacesKey, i, interfaceGuidStr, &len,
1949                         NULL, NULL, NULL, NULL);
1950                 if (!l)
1951                 {
1952                     if (interfaceGuidStr[0] == '{' &&
1953                             interfaceGuidStr[37] == '}')
1954                     {
1955                         HKEY interfaceKey;
1956                         GUID interfaceGuid;
1957
1958                         interfaceGuidStr[37] = 0;
1959                         UuidFromStringW(&interfaceGuidStr[1], &interfaceGuid);
1960                         l = RegOpenKeyExW(interfacesKey, interfaceGuidStr, 0,
1961                                 KEY_READ, &interfaceKey);
1962                         if (!l)
1963                         {
1964                             SETUPDI_EnumerateMatchingInterfaces(DeviceInfoSet,
1965                                     interfaceKey, &interfaceGuid, enumstr);
1966                             RegCloseKey(interfaceKey);
1967                         }
1968                     }
1969                 }
1970             }
1971         }
1972         else
1973         {
1974             /* In this case, SetupDiOpenClassRegKeyExW opened the specific
1975              * interface's key, so just pass that long
1976              */
1977             SETUPDI_EnumerateMatchingInterfaces(DeviceInfoSet,
1978                     interfacesKey, interface, enumstr);
1979         }
1980         RegCloseKey(interfacesKey);
1981     }
1982 }
1983
1984 static void SETUPDI_EnumerateMatchingDevices(HDEVINFO DeviceInfoSet,
1985         LPCWSTR parent, HKEY key, const GUID *class, DWORD flags)
1986 {
1987     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
1988     DWORD i, len;
1989     WCHAR subKeyName[MAX_PATH];
1990     LONG l = ERROR_SUCCESS;
1991
1992     TRACE("%s\n", debugstr_w(parent));
1993
1994     for (i = 0; !l; i++)
1995     {
1996         len = sizeof(subKeyName) / sizeof(subKeyName[0]);
1997         l = RegEnumKeyExW(key, i, subKeyName, &len, NULL, NULL, NULL, NULL);
1998         if (!l)
1999         {
2000             HKEY subKey;
2001
2002             l = RegOpenKeyExW(key, subKeyName, 0, KEY_READ, &subKey);
2003             if (!l)
2004             {
2005                 WCHAR classGuid[40];
2006                 DWORD dataType;
2007
2008                 len = sizeof(classGuid);
2009                 l = RegQueryValueExW(subKey, ClassGUID, NULL, &dataType,
2010                         (BYTE *)classGuid, &len);
2011                 if (!l && dataType == REG_SZ)
2012                 {
2013                     if (classGuid[0] == '{' && classGuid[37] == '}')
2014                     {
2015                         GUID deviceClass;
2016
2017                         classGuid[37] = 0;
2018                         UuidFromStringW(&classGuid[1], &deviceClass);
2019                         if ((flags & DIGCF_ALLCLASSES) ||
2020                                 IsEqualGUID(class, &deviceClass))
2021                         {
2022                             static const WCHAR fmt[] = {'%','s','\\','%','s',0};
2023                             LPWSTR instanceId;
2024
2025                             instanceId = HeapAlloc(GetProcessHeap(), 0,
2026                                 (lstrlenW(parent) + lstrlenW(subKeyName) + 2)
2027                                 * sizeof(WCHAR));
2028                             if (instanceId)
2029                             {
2030                                 SP_DEVINFO_DATA *dev;
2031
2032                                 sprintfW(instanceId, fmt, parent, subKeyName);
2033                                 SETUPDI_AddDeviceToSet(set, &deviceClass,
2034                                         0 /* FIXME: DevInst */, instanceId,
2035                                         FALSE, &dev);
2036                                 HeapFree(GetProcessHeap(), 0, instanceId);
2037                             }
2038                         }
2039                     }
2040                 }
2041                 RegCloseKey(subKey);
2042             }
2043         }
2044     }
2045 }
2046
2047 static void SETUPDI_EnumerateDevices(HDEVINFO DeviceInfoSet, const GUID *class,
2048         LPCWSTR enumstr, DWORD flags)
2049 {
2050     HKEY classesKey = SetupDiOpenClassRegKeyExW(class, KEY_READ,
2051             DIOCR_INSTALLER, NULL, NULL);
2052
2053     TRACE("%p, %s, %s, %08x\n", DeviceInfoSet, debugstr_guid(class),
2054             debugstr_w(enumstr), flags);
2055
2056     if (classesKey != INVALID_HANDLE_VALUE)
2057     {
2058         if (enumstr)
2059         {
2060             HKEY enumKey;
2061             LONG l = RegOpenKeyExW(classesKey, enumstr, 0, KEY_READ,
2062                     &enumKey);
2063
2064             if (!l)
2065             {
2066                 SETUPDI_EnumerateMatchingDevices(DeviceInfoSet, enumstr,
2067                         enumKey, class, flags);
2068                 RegCloseKey(enumKey);
2069             }
2070         }
2071         else
2072         {
2073             DWORD i, len;
2074             WCHAR subKeyName[MAX_PATH];
2075             LONG l = ERROR_SUCCESS;
2076
2077             for (i = 0; !l; i++)
2078             {
2079                 len = sizeof(subKeyName) / sizeof(subKeyName[0]);
2080                 l = RegEnumKeyExW(classesKey, i, subKeyName, &len, NULL,
2081                         NULL, NULL, NULL);
2082                 if (!l)
2083                 {
2084                     HKEY subKey;
2085
2086                     l = RegOpenKeyExW(classesKey, subKeyName, 0, KEY_READ,
2087                             &subKey);
2088                     if (!l)
2089                     {
2090                         SETUPDI_EnumerateMatchingDevices(DeviceInfoSet,
2091                                 subKeyName, subKey, class, flags);
2092                         RegCloseKey(subKey);
2093                     }
2094                 }
2095             }
2096         }
2097         RegCloseKey(classesKey);
2098     }
2099 }
2100
2101 /***********************************************************************
2102  *              SetupDiGetClassDevsW (SETUPAPI.@)
2103  */
2104 HDEVINFO WINAPI SetupDiGetClassDevsW(
2105        CONST GUID *class,
2106        LPCWSTR enumstr,
2107        HWND parent,
2108        DWORD flags)
2109 {
2110     return SetupDiGetClassDevsExW(class, enumstr, parent, flags, NULL, NULL,
2111             NULL);
2112 }
2113
2114 /***********************************************************************
2115  *              SetupDiGetClassDevsExW (SETUPAPI.@)
2116  */
2117 HDEVINFO WINAPI SetupDiGetClassDevsExW(
2118         CONST GUID *class,
2119         PCWSTR enumstr,
2120         HWND parent,
2121         DWORD flags,
2122         HDEVINFO deviceset,
2123         PCWSTR machine,
2124         PVOID reserved)
2125 {
2126     static const DWORD unsupportedFlags = DIGCF_DEFAULT | DIGCF_PRESENT |
2127         DIGCF_PROFILE;
2128     HDEVINFO set;
2129
2130     TRACE("%s %s %p 0x%08x %p %s %p\n", debugstr_guid(class),
2131             debugstr_w(enumstr), parent, flags, deviceset, debugstr_w(machine),
2132             reserved);
2133
2134     if (!(flags & DIGCF_ALLCLASSES) && !class)
2135     {
2136         SetLastError(ERROR_INVALID_PARAMETER);
2137         return NULL;
2138     }
2139     if (flags & unsupportedFlags)
2140         WARN("unsupported flags %08x\n", flags & unsupportedFlags);
2141     if (deviceset)
2142         set = deviceset;
2143     else
2144         set = SetupDiCreateDeviceInfoListExW(class, parent, machine, reserved);
2145     if (set)
2146     {
2147         if (machine)
2148             FIXME("%s: unimplemented for remote machines\n",
2149                     debugstr_w(machine));
2150         else if (flags & DIGCF_DEVICEINTERFACE)
2151             SETUPDI_EnumerateInterfaces(set, class, enumstr, flags);
2152         else
2153             SETUPDI_EnumerateDevices(set, class, enumstr, flags);
2154     }
2155     return set;
2156 }
2157
2158 /***********************************************************************
2159  *              SetupDiGetDeviceInfoListDetailA  (SETUPAPI.@)
2160  */
2161 BOOL WINAPI SetupDiGetDeviceInfoListDetailA(
2162         HDEVINFO DeviceInfoSet,
2163         PSP_DEVINFO_LIST_DETAIL_DATA_A DevInfoData )
2164 {
2165     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2166
2167     TRACE("%p %p\n", DeviceInfoSet, DevInfoData);
2168
2169     if (!DeviceInfoSet || DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
2170     {
2171         SetLastError(ERROR_INVALID_HANDLE);
2172         return FALSE;
2173     }
2174     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2175     {
2176         SetLastError(ERROR_INVALID_HANDLE);
2177         return FALSE;
2178     }
2179     if (!DevInfoData ||
2180             DevInfoData->cbSize != sizeof(SP_DEVINFO_LIST_DETAIL_DATA_A))
2181     {
2182         SetLastError(ERROR_INVALID_PARAMETER);
2183         return FALSE;
2184     }
2185     memcpy(&DevInfoData->ClassGuid, &set->ClassGuid, sizeof(GUID));
2186     DevInfoData->RemoteMachineHandle = NULL;
2187     DevInfoData->RemoteMachineName[0] = '\0';
2188     return TRUE;
2189 }
2190
2191 /***********************************************************************
2192  *              SetupDiGetDeviceInfoListDetailW  (SETUPAPI.@)
2193  */
2194 BOOL WINAPI SetupDiGetDeviceInfoListDetailW(
2195         HDEVINFO DeviceInfoSet,
2196         PSP_DEVINFO_LIST_DETAIL_DATA_W DevInfoData )
2197 {
2198     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2199
2200     TRACE("%p %p\n", DeviceInfoSet, DevInfoData);
2201
2202     if (!DeviceInfoSet || DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
2203     {
2204         SetLastError(ERROR_INVALID_HANDLE);
2205         return FALSE;
2206     }
2207     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2208     {
2209         SetLastError(ERROR_INVALID_HANDLE);
2210         return FALSE;
2211     }
2212     if (!DevInfoData ||
2213             DevInfoData->cbSize != sizeof(SP_DEVINFO_LIST_DETAIL_DATA_W))
2214     {
2215         SetLastError(ERROR_INVALID_PARAMETER);
2216         return FALSE;
2217     }
2218     memcpy(&DevInfoData->ClassGuid, &set->ClassGuid, sizeof(GUID));
2219     DevInfoData->RemoteMachineHandle = NULL;
2220     DevInfoData->RemoteMachineName[0] = '\0';
2221     return TRUE;
2222 }
2223
2224 /***********************************************************************
2225  *              SetupDiCreateDeviceInterfaceA (SETUPAPI.@)
2226  */
2227 BOOL WINAPI SetupDiCreateDeviceInterfaceA(
2228         HDEVINFO DeviceInfoSet,
2229         PSP_DEVINFO_DATA DeviceInfoData,
2230         const GUID *InterfaceClassGuid,
2231         PCSTR ReferenceString,
2232         DWORD CreationFlags,
2233         PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
2234 {
2235     BOOL ret;
2236     LPWSTR ReferenceStringW = NULL;
2237
2238     TRACE("%p %p %s %s %08x %p\n", DeviceInfoSet, DeviceInfoData,
2239             debugstr_guid(InterfaceClassGuid), debugstr_a(ReferenceString),
2240             CreationFlags, DeviceInterfaceData);
2241
2242     if (ReferenceString)
2243     {
2244         ReferenceStringW = MultiByteToUnicode(ReferenceString, CP_ACP);
2245         if (ReferenceStringW == NULL) return FALSE;
2246     }
2247
2248     ret = SetupDiCreateDeviceInterfaceW(DeviceInfoSet, DeviceInfoData,
2249             InterfaceClassGuid, ReferenceStringW, CreationFlags,
2250             DeviceInterfaceData);
2251
2252     MyFree(ReferenceStringW);
2253
2254     return ret;
2255 }
2256
2257 /***********************************************************************
2258  *              SetupDiCreateDeviceInterfaceW (SETUPAPI.@)
2259  */
2260 BOOL WINAPI SetupDiCreateDeviceInterfaceW(
2261         HDEVINFO DeviceInfoSet,
2262         PSP_DEVINFO_DATA DeviceInfoData,
2263         const GUID *InterfaceClassGuid,
2264         PCWSTR ReferenceString,
2265         DWORD CreationFlags,
2266         PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
2267 {
2268     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2269     struct DeviceInfo *devInfo;
2270     SP_DEVICE_INTERFACE_DATA *iface = NULL;
2271     BOOL ret;
2272
2273     TRACE("%p %p %s %s %08x %p\n", DeviceInfoSet, DeviceInfoData,
2274             debugstr_guid(InterfaceClassGuid), debugstr_w(ReferenceString),
2275             CreationFlags, DeviceInterfaceData);
2276
2277     if (!DeviceInfoSet || DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
2278     {
2279         SetLastError(ERROR_INVALID_HANDLE);
2280         return FALSE;
2281     }
2282     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2283     {
2284         SetLastError(ERROR_INVALID_HANDLE);
2285         return FALSE;
2286     }
2287     if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
2288             || !DeviceInfoData->Reserved)
2289     {
2290         SetLastError(ERROR_INVALID_PARAMETER);
2291         return FALSE;
2292     }
2293     devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
2294     if (devInfo->set != set)
2295     {
2296         SetLastError(ERROR_INVALID_PARAMETER);
2297         return FALSE;
2298     }
2299     if (!InterfaceClassGuid)
2300     {
2301         SetLastError(ERROR_INVALID_USER_BUFFER);
2302         return FALSE;
2303     }
2304     if ((ret = SETUPDI_AddInterfaceInstance(DeviceInfoData, InterfaceClassGuid,
2305                     ReferenceString, &iface)))
2306     {
2307         if (DeviceInterfaceData)
2308         {
2309             if (DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA))
2310             {
2311                 SetLastError(ERROR_INVALID_USER_BUFFER);
2312                 ret = FALSE;
2313             }
2314             else
2315                 memcpy(DeviceInterfaceData, iface, sizeof(*iface));
2316         }
2317     }
2318     return ret;
2319 }
2320
2321 /***********************************************************************
2322  *              SetupDiCreateDeviceInterfaceRegKeyA (SETUPAPI.@)
2323  */
2324 HKEY WINAPI SetupDiCreateDeviceInterfaceRegKeyA(
2325         HDEVINFO DeviceInfoSet,
2326         PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
2327         DWORD Reserved,
2328         REGSAM samDesired,
2329         HINF InfHandle,
2330         PCSTR InfSectionName)
2331 {
2332     HKEY key;
2333     PWSTR InfSectionNameW = NULL;
2334
2335     TRACE("%p %p %d %08x %p %p\n", DeviceInfoSet, DeviceInterfaceData, Reserved,
2336             samDesired, InfHandle, InfSectionName);
2337     if (InfHandle)
2338     {
2339         if (!InfSectionName)
2340         {
2341             SetLastError(ERROR_INVALID_PARAMETER);
2342             return INVALID_HANDLE_VALUE;
2343         }
2344         InfSectionNameW = MultiByteToUnicode(InfSectionName, CP_ACP);
2345         if (!InfSectionNameW)
2346             return INVALID_HANDLE_VALUE;
2347     }
2348     key = SetupDiCreateDeviceInterfaceRegKeyW(DeviceInfoSet,
2349             DeviceInterfaceData, Reserved, samDesired, InfHandle,
2350             InfSectionNameW);
2351     MyFree(InfSectionNameW);
2352     return key;
2353 }
2354
2355 static PWSTR SETUPDI_GetInstancePath(struct InterfaceInfo *ifaceInfo)
2356 {
2357     static const WCHAR hash[] = {'#',0};
2358     PWSTR instancePath = NULL;
2359
2360     if (ifaceInfo->referenceString)
2361     {
2362         instancePath = HeapAlloc(GetProcessHeap(), 0,
2363                 (lstrlenW(ifaceInfo->referenceString) + 2) * sizeof(WCHAR));
2364         if (instancePath)
2365         {
2366             lstrcpyW(instancePath, hash);
2367             lstrcatW(instancePath, ifaceInfo->referenceString);
2368         }
2369         else
2370             SetLastError(ERROR_OUTOFMEMORY);
2371     }
2372     else
2373     {
2374         instancePath = HeapAlloc(GetProcessHeap(), 0,
2375                 (lstrlenW(hash) + 1) * sizeof(WCHAR));
2376         if (instancePath)
2377             lstrcpyW(instancePath, hash);
2378     }
2379     return instancePath;
2380 }
2381
2382 /***********************************************************************
2383  *              SetupDiCreateDeviceInterfaceRegKeyW (SETUPAPI.@)
2384  */
2385 HKEY WINAPI SetupDiCreateDeviceInterfaceRegKeyW(
2386         HDEVINFO DeviceInfoSet,
2387         PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
2388         DWORD Reserved,
2389         REGSAM samDesired,
2390         HINF InfHandle,
2391         PCWSTR InfSectionName)
2392 {
2393     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2394     HKEY key = INVALID_HANDLE_VALUE, interfacesKey;
2395     LONG l;
2396
2397     TRACE("%p %p %d %08x %p %p\n", DeviceInfoSet, DeviceInterfaceData, Reserved,
2398             samDesired, InfHandle, InfSectionName);
2399
2400     if (!DeviceInfoSet || DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE ||
2401             set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2402     {
2403         SetLastError(ERROR_INVALID_HANDLE);
2404         return INVALID_HANDLE_VALUE;
2405     }
2406     if (!DeviceInterfaceData ||
2407             DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA) ||
2408             !DeviceInterfaceData->Reserved)
2409     {
2410         SetLastError(ERROR_INVALID_PARAMETER);
2411         return INVALID_HANDLE_VALUE;
2412     }
2413     if (InfHandle && !InfSectionName)
2414     {
2415         SetLastError(ERROR_INVALID_PARAMETER);
2416         return INVALID_HANDLE_VALUE;
2417     }
2418     if (!(l = RegCreateKeyExW(HKEY_LOCAL_MACHINE, DeviceClasses, 0, NULL, 0,
2419                     samDesired, NULL, &interfacesKey, NULL)))
2420     {
2421         HKEY parent;
2422         WCHAR bracedGuidString[39];
2423
2424         SETUPDI_GuidToString(&DeviceInterfaceData->InterfaceClassGuid,
2425                 bracedGuidString);
2426         if (!(l = RegCreateKeyExW(interfacesKey, bracedGuidString, 0, NULL, 0,
2427                         samDesired, NULL, &parent, NULL)))
2428         {
2429             struct InterfaceInfo *ifaceInfo =
2430                 (struct InterfaceInfo *)DeviceInterfaceData->Reserved;
2431             PWSTR instancePath = SETUPDI_GetInstancePath(ifaceInfo);
2432
2433             if (instancePath)
2434             {
2435                 LONG l;
2436
2437                 l = RegCreateKeyExW(parent, instancePath, 0, NULL, 0,
2438                         samDesired, NULL, &key, NULL);
2439                 if (l)
2440                 {
2441                     SetLastError(l);
2442                     key = INVALID_HANDLE_VALUE;
2443                 }
2444                 else if (InfHandle)
2445                     FIXME("INF section installation unsupported\n");
2446             }
2447             HeapFree(GetProcessHeap(), 0, instancePath);
2448             RegCloseKey(parent);
2449         }
2450         else
2451             SetLastError(l);
2452         RegCloseKey(interfacesKey);
2453     }
2454     else
2455         SetLastError(l);
2456     return key;
2457 }
2458
2459 /***********************************************************************
2460  *              SetupDiDeleteDeviceInterfaceRegKey (SETUPAPI.@)
2461  */
2462 BOOL WINAPI SetupDiDeleteDeviceInterfaceRegKey(
2463         HDEVINFO DeviceInfoSet,
2464         PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
2465         DWORD Reserved)
2466 {
2467     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2468     HKEY parent;
2469     BOOL ret = FALSE;
2470
2471     TRACE("%p %p %d\n", DeviceInfoSet, DeviceInterfaceData, Reserved);
2472
2473     if (!DeviceInfoSet || DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE ||
2474             set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2475     {
2476         SetLastError(ERROR_INVALID_HANDLE);
2477         return FALSE;
2478     }
2479     if (!DeviceInterfaceData ||
2480             DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA) ||
2481             !DeviceInterfaceData->Reserved)
2482     {
2483         SetLastError(ERROR_INVALID_PARAMETER);
2484         return FALSE;
2485     }
2486     parent = SetupDiOpenClassRegKeyExW(&DeviceInterfaceData->InterfaceClassGuid,
2487             KEY_ALL_ACCESS, DIOCR_INTERFACE, NULL, NULL);
2488     if (parent != INVALID_HANDLE_VALUE)
2489     {
2490         struct InterfaceInfo *ifaceInfo =
2491             (struct InterfaceInfo *)DeviceInterfaceData->Reserved;
2492         PWSTR instancePath = SETUPDI_GetInstancePath(ifaceInfo);
2493
2494         if (instancePath)
2495         {
2496             LONG l = RegDeleteKeyW(parent, instancePath);
2497
2498             if (l)
2499                 SetLastError(l);
2500             else
2501                 ret = TRUE;
2502             HeapFree(GetProcessHeap(), 0, instancePath);
2503         }
2504         RegCloseKey(parent);
2505     }
2506     return ret;
2507 }
2508
2509 /***********************************************************************
2510  *              SetupDiEnumDeviceInterfaces (SETUPAPI.@)
2511  *
2512  * PARAMS
2513  *   DeviceInfoSet      [I]    Set of devices from which to enumerate
2514  *                             interfaces
2515  *   DeviceInfoData     [I]    (Optional) If specified, a specific device
2516  *                             instance from which to enumerate interfaces.
2517  *                             If it isn't specified, all interfaces for all
2518  *                             devices in the set are enumerated.
2519  *   InterfaceClassGuid [I]    The interface class to enumerate.
2520  *   MemberIndex        [I]    An index of the interface instance to enumerate.
2521  *                             A caller should start with MemberIndex set to 0,
2522  *                             and continue until the function fails with
2523  *                             ERROR_NO_MORE_ITEMS.
2524  *   DeviceInterfaceData [I/O] Returns an enumerated interface.  Its cbSize
2525  *                             member must be set to
2526  *                             sizeof(SP_DEVICE_INTERFACE_DATA).
2527  *
2528  * RETURNS
2529  *   Success: non-zero value.
2530  *   Failure: FALSE.  Call GetLastError() for more info.
2531  */
2532 BOOL WINAPI SetupDiEnumDeviceInterfaces(
2533        HDEVINFO DeviceInfoSet,
2534        PSP_DEVINFO_DATA DeviceInfoData,
2535        CONST GUID * InterfaceClassGuid,
2536        DWORD MemberIndex,
2537        PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
2538 {
2539     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2540     BOOL ret = FALSE;
2541
2542     TRACE("%p, %p, %s, %d, %p\n", DeviceInfoSet, DeviceInfoData,
2543      debugstr_guid(InterfaceClassGuid), MemberIndex, DeviceInterfaceData);
2544
2545     if (!DeviceInfoSet || DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE ||
2546             set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2547     {
2548         SetLastError(ERROR_INVALID_HANDLE);
2549         return FALSE;
2550     }
2551     if (DeviceInfoData && (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA) ||
2552                 !DeviceInfoData->Reserved))
2553     {
2554         SetLastError(ERROR_INVALID_PARAMETER);
2555         return FALSE;
2556     }
2557     if (!DeviceInterfaceData ||
2558             DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA))
2559     {
2560         SetLastError(ERROR_INVALID_PARAMETER);
2561         return FALSE;
2562     }
2563     if (DeviceInfoData)
2564     {
2565         struct DeviceInfo *devInfo =
2566             (struct DeviceInfo *)DeviceInfoData->Reserved;
2567         struct InterfaceInstances *iface;
2568
2569         if ((ret = SETUPDI_FindInterface(devInfo, InterfaceClassGuid, &iface)))
2570         {
2571             if (MemberIndex < iface->cInstances)
2572                 memcpy(DeviceInterfaceData, &iface->instances[MemberIndex],
2573                     sizeof(SP_DEVICE_INTERFACE_DATA));
2574             else
2575             {
2576                 SetLastError(ERROR_NO_MORE_ITEMS);
2577                 ret = FALSE;
2578             }
2579         }
2580         else
2581             SetLastError(ERROR_NO_MORE_ITEMS);
2582     }
2583     else
2584     {
2585         DWORD i, cEnumerated = 0;
2586         BOOL found = FALSE;
2587
2588         for (i = 0; !found && cEnumerated < MemberIndex + 1 &&
2589                 i < set->cDevices; i++)
2590         {
2591             struct DeviceInfo *devInfo =
2592                 (struct DeviceInfo *)set->devices[i].Reserved;
2593             struct InterfaceInstances *iface;
2594
2595             if (SETUPDI_FindInterface(devInfo, InterfaceClassGuid, &iface))
2596             {
2597                 if (cEnumerated + iface->cInstances < MemberIndex + 1)
2598                     cEnumerated += iface->cInstances;
2599                 else
2600                 {
2601                     DWORD instanceIndex = MemberIndex - cEnumerated;
2602
2603                     memcpy(DeviceInterfaceData,
2604                             &iface->instances[instanceIndex],
2605                             sizeof(SP_DEVICE_INTERFACE_DATA));
2606                     cEnumerated += instanceIndex + 1;
2607                     found = TRUE;
2608                     ret = TRUE;
2609                 }
2610             }
2611         }
2612         if (!found)
2613             SetLastError(ERROR_NO_MORE_ITEMS);
2614     }
2615     return ret;
2616 }
2617
2618 /***********************************************************************
2619  *              SetupDiDestroyDeviceInfoList (SETUPAPI.@)
2620   *
2621  * Destroy a DeviceInfoList and free all used memory of the list.
2622  *
2623  * PARAMS
2624  *   devinfo [I] DeviceInfoList pointer to list to destroy
2625  *
2626  * RETURNS
2627  *   Success: non zero value.
2628  *   Failure: zero value.
2629  */
2630 BOOL WINAPI SetupDiDestroyDeviceInfoList(HDEVINFO devinfo)
2631 {
2632     BOOL ret = FALSE;
2633
2634     TRACE("%p\n", devinfo);
2635     if (devinfo && devinfo != (HDEVINFO)INVALID_HANDLE_VALUE)
2636     {
2637         struct DeviceInfoSet *list = (struct DeviceInfoSet *)devinfo;
2638
2639         if (list->magic == SETUP_DEVICE_INFO_SET_MAGIC)
2640         {
2641             DWORD i;
2642
2643             for (i = 0; i < list->cDevices; i++)
2644                 SETUPDI_FreeDeviceInfo(
2645                         (struct DeviceInfo *)list->devices[i].Reserved);
2646             HeapFree(GetProcessHeap(), 0, list->devices);
2647             HeapFree(GetProcessHeap(), 0, list);
2648             ret = TRUE;
2649         }
2650     }
2651
2652     if (ret == FALSE)
2653         SetLastError(ERROR_INVALID_HANDLE);
2654
2655     return ret;
2656 }
2657
2658 /***********************************************************************
2659  *              SetupDiGetDeviceInterfaceDetailA (SETUPAPI.@)
2660  */
2661 BOOL WINAPI SetupDiGetDeviceInterfaceDetailA(
2662       HDEVINFO DeviceInfoSet,
2663       PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
2664       PSP_DEVICE_INTERFACE_DETAIL_DATA_A DeviceInterfaceDetailData,
2665       DWORD DeviceInterfaceDetailDataSize,
2666       PDWORD RequiredSize,
2667       PSP_DEVINFO_DATA DeviceInfoData)
2668 {
2669     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2670     struct InterfaceInfo *info;
2671     DWORD bytesNeeded = offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath)
2672         + 1;
2673     BOOL ret = FALSE;
2674
2675     TRACE("(%p, %p, %p, %d, %p, %p)\n", DeviceInfoSet,
2676      DeviceInterfaceData, DeviceInterfaceDetailData,
2677      DeviceInterfaceDetailDataSize, RequiredSize, DeviceInfoData);
2678
2679     if (!DeviceInfoSet || DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE ||
2680             set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2681     {
2682         SetLastError(ERROR_INVALID_HANDLE);
2683         return FALSE;
2684     }
2685     if (!DeviceInterfaceData ||
2686             DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA) ||
2687             !DeviceInterfaceData->Reserved)
2688     {
2689         SetLastError(ERROR_INVALID_PARAMETER);
2690         return FALSE;
2691     }
2692     if (DeviceInterfaceDetailData && (DeviceInterfaceDetailData->cbSize <
2693             offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath) + sizeof(char) ||
2694             DeviceInterfaceDetailData->cbSize > sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A)))
2695     {
2696         SetLastError(ERROR_INVALID_USER_BUFFER);
2697         return FALSE;
2698     }
2699     if (!DeviceInterfaceDetailData && DeviceInterfaceDetailDataSize)
2700     {
2701         SetLastError(ERROR_INVALID_USER_BUFFER);
2702         return FALSE;
2703     }
2704     info = (struct InterfaceInfo *)DeviceInterfaceData->Reserved;
2705     if (info->symbolicLink)
2706         bytesNeeded += WideCharToMultiByte(CP_ACP, 0, info->symbolicLink, -1,
2707                 NULL, 0, NULL, NULL);
2708     if (DeviceInterfaceDetailDataSize >= bytesNeeded)
2709     {
2710         if (info->symbolicLink)
2711             WideCharToMultiByte(CP_ACP, 0, info->symbolicLink, -1,
2712                     DeviceInterfaceDetailData->DevicePath,
2713                     DeviceInterfaceDetailDataSize -
2714                     offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath),
2715                     NULL, NULL);
2716         else
2717             DeviceInterfaceDetailData->DevicePath[0] = '\0';
2718         if (DeviceInfoData && DeviceInfoData->cbSize == sizeof(SP_DEVINFO_DATA))
2719             memcpy(DeviceInfoData, info->device, sizeof(SP_DEVINFO_DATA));
2720         ret = TRUE;
2721     }
2722     else
2723     {
2724         if (RequiredSize)
2725             *RequiredSize = bytesNeeded;
2726         SetLastError(ERROR_INSUFFICIENT_BUFFER);
2727     }
2728     return ret;
2729 }
2730
2731 /***********************************************************************
2732  *              SetupDiGetDeviceInterfaceDetailW (SETUPAPI.@)
2733  */
2734 BOOL WINAPI SetupDiGetDeviceInterfaceDetailW(
2735       HDEVINFO DeviceInfoSet,
2736       PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
2737       PSP_DEVICE_INTERFACE_DETAIL_DATA_W DeviceInterfaceDetailData,
2738       DWORD DeviceInterfaceDetailDataSize,
2739       PDWORD RequiredSize,
2740       PSP_DEVINFO_DATA DeviceInfoData)
2741 {
2742     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2743     struct InterfaceInfo *info;
2744     DWORD bytesNeeded = offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath)
2745         + sizeof(WCHAR); /* include NULL terminator */
2746     BOOL ret = FALSE;
2747
2748     TRACE("(%p, %p, %p, %d, %p, %p)\n", DeviceInfoSet,
2749      DeviceInterfaceData, DeviceInterfaceDetailData,
2750      DeviceInterfaceDetailDataSize, RequiredSize, DeviceInfoData);
2751
2752     if (!DeviceInfoSet || DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE ||
2753             set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2754     {
2755         SetLastError(ERROR_INVALID_HANDLE);
2756         return FALSE;
2757     }
2758     if (!DeviceInterfaceData ||
2759             DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA) ||
2760             !DeviceInterfaceData->Reserved)
2761     {
2762         SetLastError(ERROR_INVALID_PARAMETER);
2763         return FALSE;
2764     }
2765     if (DeviceInterfaceDetailData && (DeviceInterfaceDetailData->cbSize <
2766             offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath) + sizeof(WCHAR) ||
2767             DeviceInterfaceDetailData->cbSize > sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W)))
2768     {
2769         SetLastError(ERROR_INVALID_USER_BUFFER);
2770         return FALSE;
2771     }
2772     if (!DeviceInterfaceDetailData && DeviceInterfaceDetailDataSize)
2773     {
2774         SetLastError(ERROR_INVALID_USER_BUFFER);
2775         return FALSE;
2776     }
2777     info = (struct InterfaceInfo *)DeviceInterfaceData->Reserved;
2778     if (info->symbolicLink)
2779         bytesNeeded += lstrlenW(info->symbolicLink);
2780     if (DeviceInterfaceDetailDataSize >= bytesNeeded)
2781     {
2782         if (info->symbolicLink)
2783             lstrcpyW(DeviceInterfaceDetailData->DevicePath, info->symbolicLink);
2784         else
2785             DeviceInterfaceDetailData->DevicePath[0] = '\0';
2786         if (DeviceInfoData && DeviceInfoData->cbSize == sizeof(SP_DEVINFO_DATA))
2787             memcpy(DeviceInfoData, info->device, sizeof(SP_DEVINFO_DATA));
2788         ret = TRUE;
2789     }
2790     else
2791     {
2792         if (RequiredSize)
2793             *RequiredSize = bytesNeeded;
2794         SetLastError(ERROR_INSUFFICIENT_BUFFER);
2795     }
2796     return ret;
2797 }
2798
2799 struct PropertyMapEntry
2800 {
2801     DWORD   regType;
2802     LPCSTR  nameA;
2803     LPCWSTR nameW;
2804 };
2805
2806 static struct PropertyMapEntry PropertyMap[] = {
2807     { REG_SZ, "DeviceDesc", DeviceDesc },
2808     { REG_MULTI_SZ, "HardwareId", HardwareId },
2809     { REG_MULTI_SZ, "CompatibleIDs", CompatibleIDs },
2810     { 0, NULL, NULL }, /* SPDRP_UNUSED0 */
2811     { REG_SZ, "Service", Service },
2812     { 0, NULL, NULL }, /* SPDRP_UNUSED1 */
2813     { 0, NULL, NULL }, /* SPDRP_UNUSED2 */
2814     { REG_SZ, "Class", Class },
2815     { REG_SZ, "ClassGUID", ClassGUID },
2816     { REG_SZ, "Driver", Driver },
2817     { REG_DWORD, "ConfigFlags", ConfigFlags },
2818     { REG_SZ, "Mfg", Mfg },
2819     { REG_SZ, "FriendlyName", FriendlyName },
2820     { REG_SZ, "LocationInformation", LocationInformation },
2821     { 0, NULL, NULL }, /* SPDRP_PHYSICAL_DEVICE_OBJECT_NAME */
2822     { REG_DWORD, "Capabilities", Capabilities },
2823     { REG_DWORD, "UINumber", UINumber },
2824     { REG_MULTI_SZ, "UpperFilters", UpperFilters },
2825     { REG_MULTI_SZ, "LowerFilters", LowerFilters },
2826 };
2827
2828 /***********************************************************************
2829  *              SetupDiGetDeviceRegistryPropertyA (SETUPAPI.@)
2830  */
2831 BOOL WINAPI SetupDiGetDeviceRegistryPropertyA(
2832         HDEVINFO  DeviceInfoSet,
2833         PSP_DEVINFO_DATA  DeviceInfoData,
2834         DWORD   Property,
2835         PDWORD  PropertyRegDataType,
2836         PBYTE   PropertyBuffer,
2837         DWORD   PropertyBufferSize,
2838         PDWORD  RequiredSize)
2839 {
2840     BOOL ret = FALSE;
2841     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2842     struct DeviceInfo *devInfo;
2843
2844     TRACE("%04x %p %d %p %p %d %p\n", (DWORD)DeviceInfoSet, DeviceInfoData,
2845         Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize,
2846         RequiredSize);
2847
2848     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
2849     {
2850         SetLastError(ERROR_INVALID_HANDLE);
2851         return FALSE;
2852     }
2853     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2854     {
2855         SetLastError(ERROR_INVALID_HANDLE);
2856         return FALSE;
2857     }
2858     if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
2859             || !DeviceInfoData->Reserved)
2860     {
2861         SetLastError(ERROR_INVALID_PARAMETER);
2862         return FALSE;
2863     }
2864     devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
2865     if (Property < sizeof(PropertyMap) / sizeof(PropertyMap[0])
2866         && PropertyMap[Property].nameA)
2867     {
2868         DWORD size = PropertyBufferSize;
2869         LONG l = RegQueryValueExA(devInfo->key, PropertyMap[Property].nameA,
2870                 NULL, PropertyRegDataType, PropertyBuffer, &size);
2871
2872         if (RequiredSize)
2873             *RequiredSize = size;
2874         if (!l)
2875             ret = TRUE;
2876         else
2877             SetLastError(l);
2878     }
2879     return ret;
2880 }
2881
2882 /***********************************************************************
2883  *              SetupDiGetDeviceRegistryPropertyW (SETUPAPI.@)
2884  */
2885 BOOL WINAPI SetupDiGetDeviceRegistryPropertyW(
2886         HDEVINFO  DeviceInfoSet,
2887         PSP_DEVINFO_DATA  DeviceInfoData,
2888         DWORD   Property,
2889         PDWORD  PropertyRegDataType,
2890         PBYTE   PropertyBuffer,
2891         DWORD   PropertyBufferSize,
2892         PDWORD  RequiredSize)
2893 {
2894     BOOL ret = FALSE;
2895     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2896     struct DeviceInfo *devInfo;
2897
2898     TRACE("%04x %p %d %p %p %d %p\n", (DWORD)DeviceInfoSet, DeviceInfoData,
2899         Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize,
2900         RequiredSize);
2901
2902     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
2903     {
2904         SetLastError(ERROR_INVALID_HANDLE);
2905         return FALSE;
2906     }
2907     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2908     {
2909         SetLastError(ERROR_INVALID_HANDLE);
2910         return FALSE;
2911     }
2912     if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
2913             || !DeviceInfoData->Reserved)
2914     {
2915         SetLastError(ERROR_INVALID_PARAMETER);
2916         return FALSE;
2917     }
2918     devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
2919     if (Property < sizeof(PropertyMap) / sizeof(PropertyMap[0])
2920         && PropertyMap[Property].nameW)
2921     {
2922         DWORD size = PropertyBufferSize;
2923         LONG l = RegQueryValueExW(devInfo->key, PropertyMap[Property].nameW,
2924                 NULL, PropertyRegDataType, PropertyBuffer, &size);
2925
2926         if (RequiredSize)
2927             *RequiredSize = size;
2928         if (!l)
2929             ret = TRUE;
2930         else
2931             SetLastError(l);
2932     }
2933     return ret;
2934 }
2935
2936 /***********************************************************************
2937  *              SetupDiSetDeviceRegistryPropertyA (SETUPAPI.@)
2938  */
2939 BOOL WINAPI SetupDiSetDeviceRegistryPropertyA(
2940         HDEVINFO DeviceInfoSet,
2941         PSP_DEVINFO_DATA DeviceInfoData,
2942         DWORD Property,
2943         const BYTE *PropertyBuffer,
2944         DWORD PropertyBufferSize)
2945 {
2946     BOOL ret = FALSE;
2947     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2948     struct DeviceInfo *devInfo;
2949
2950     TRACE("%p %p %d %p %d\n", DeviceInfoSet, DeviceInfoData, Property,
2951         PropertyBuffer, PropertyBufferSize);
2952
2953     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
2954     {
2955         SetLastError(ERROR_INVALID_HANDLE);
2956         return FALSE;
2957     }
2958     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2959     {
2960         SetLastError(ERROR_INVALID_HANDLE);
2961         return FALSE;
2962     }
2963     if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
2964             || !DeviceInfoData->Reserved)
2965     {
2966         SetLastError(ERROR_INVALID_PARAMETER);
2967         return FALSE;
2968     }
2969     devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
2970     if (Property < sizeof(PropertyMap) / sizeof(PropertyMap[0])
2971         && PropertyMap[Property].nameA)
2972     {
2973         LONG l = RegSetValueExA(devInfo->key, PropertyMap[Property].nameA, 0,
2974                 PropertyMap[Property].regType, PropertyBuffer,
2975                 PropertyBufferSize);
2976         if (!l)
2977             ret = TRUE;
2978         else
2979             SetLastError(l);
2980     }
2981     return ret;
2982 }
2983
2984 /***********************************************************************
2985  *              SetupDiSetDeviceRegistryPropertyW (SETUPAPI.@)
2986  */
2987 BOOL WINAPI SetupDiSetDeviceRegistryPropertyW(
2988         HDEVINFO DeviceInfoSet,
2989         PSP_DEVINFO_DATA DeviceInfoData,
2990         DWORD Property,
2991         const BYTE *PropertyBuffer,
2992         DWORD PropertyBufferSize)
2993 {
2994     BOOL ret = FALSE;
2995     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2996     struct DeviceInfo *devInfo;
2997
2998     TRACE("%p %p %d %p %d\n", DeviceInfoSet, DeviceInfoData, Property,
2999         PropertyBuffer, PropertyBufferSize);
3000
3001     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
3002     {
3003         SetLastError(ERROR_INVALID_HANDLE);
3004         return FALSE;
3005     }
3006     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
3007     {
3008         SetLastError(ERROR_INVALID_HANDLE);
3009         return FALSE;
3010     }
3011     if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
3012             || !DeviceInfoData->Reserved)
3013     {
3014         SetLastError(ERROR_INVALID_PARAMETER);
3015         return FALSE;
3016     }
3017     devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
3018     if (Property < sizeof(PropertyMap) / sizeof(PropertyMap[0])
3019         && PropertyMap[Property].nameW)
3020     {
3021         LONG l = RegSetValueExW(devInfo->key, PropertyMap[Property].nameW, 0,
3022                 PropertyMap[Property].regType, PropertyBuffer,
3023                 PropertyBufferSize);
3024         if (!l)
3025             ret = TRUE;
3026         else
3027             SetLastError(l);
3028     }
3029     return ret;
3030 }
3031
3032 /***********************************************************************
3033  *              SetupDiInstallClassA (SETUPAPI.@)
3034  */
3035 BOOL WINAPI SetupDiInstallClassA(
3036         HWND hwndParent,
3037         PCSTR InfFileName,
3038         DWORD Flags,
3039         HSPFILEQ FileQueue)
3040 {
3041     UNICODE_STRING FileNameW;
3042     BOOL Result;
3043
3044     if (!RtlCreateUnicodeStringFromAsciiz(&FileNameW, InfFileName))
3045     {
3046         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3047         return FALSE;
3048     }
3049
3050     Result = SetupDiInstallClassW(hwndParent, FileNameW.Buffer, Flags, FileQueue);
3051
3052     RtlFreeUnicodeString(&FileNameW);
3053
3054     return Result;
3055 }
3056
3057 static HKEY CreateClassKey(HINF hInf)
3058 {
3059     WCHAR FullBuffer[MAX_PATH];
3060     WCHAR Buffer[MAX_PATH];
3061     DWORD RequiredSize;
3062     HKEY hClassKey;
3063
3064     if (!SetupGetLineTextW(NULL,
3065                            hInf,
3066                            Version,
3067                            ClassGUID,
3068                            Buffer,
3069                            MAX_PATH,
3070                            &RequiredSize))
3071     {
3072         return INVALID_HANDLE_VALUE;
3073     }
3074
3075     lstrcpyW(FullBuffer, ControlClass);
3076     lstrcatW(FullBuffer, Buffer);
3077
3078     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
3079                       FullBuffer,
3080                       0,
3081                       KEY_ALL_ACCESS,
3082                       &hClassKey))
3083     {
3084         if (!SetupGetLineTextW(NULL,
3085                                hInf,
3086                                Version,
3087                                Class,
3088                                Buffer,
3089                                MAX_PATH,
3090                                &RequiredSize))
3091         {
3092             return INVALID_HANDLE_VALUE;
3093         }
3094
3095         if (RegCreateKeyExW(HKEY_LOCAL_MACHINE,
3096                             FullBuffer,
3097                             0,
3098                             NULL,
3099                             REG_OPTION_NON_VOLATILE,
3100                             KEY_ALL_ACCESS,
3101                             NULL,
3102                             &hClassKey,
3103                             NULL))
3104         {
3105             return INVALID_HANDLE_VALUE;
3106         }
3107
3108     }
3109
3110     if (RegSetValueExW(hClassKey,
3111                        Class,
3112                        0,
3113                        REG_SZ,
3114                        (LPBYTE)Buffer,
3115                        RequiredSize * sizeof(WCHAR)))
3116     {
3117         RegCloseKey(hClassKey);
3118         RegDeleteKeyW(HKEY_LOCAL_MACHINE,
3119                       FullBuffer);
3120         return INVALID_HANDLE_VALUE;
3121     }
3122
3123     return hClassKey;
3124 }
3125
3126 /***********************************************************************
3127  *              SetupDiInstallClassW (SETUPAPI.@)
3128  */
3129 BOOL WINAPI SetupDiInstallClassW(
3130         HWND hwndParent,
3131         PCWSTR InfFileName,
3132         DWORD Flags,
3133         HSPFILEQ FileQueue)
3134 {
3135     WCHAR SectionName[MAX_PATH];
3136     DWORD SectionNameLength = 0;
3137     HINF hInf;
3138     BOOL bFileQueueCreated = FALSE;
3139     HKEY hClassKey;
3140
3141
3142     FIXME("\n");
3143
3144     if ((Flags & DI_NOVCP) && (FileQueue == NULL || FileQueue == INVALID_HANDLE_VALUE))
3145     {
3146         SetLastError(ERROR_INVALID_PARAMETER);
3147         return FALSE;
3148     }
3149
3150     /* Open the .inf file */
3151     hInf = SetupOpenInfFileW(InfFileName,
3152                              NULL,
3153                              INF_STYLE_WIN4,
3154                              NULL);
3155     if (hInf == INVALID_HANDLE_VALUE)
3156     {
3157
3158         return FALSE;
3159     }
3160
3161     /* Create or open the class registry key 'HKLM\\CurrentControlSet\\Class\\{GUID}' */
3162     hClassKey = CreateClassKey(hInf);
3163     if (hClassKey == INVALID_HANDLE_VALUE)
3164     {
3165         SetupCloseInfFile(hInf);
3166         return FALSE;
3167     }
3168
3169
3170     /* Try to append a layout file */
3171 #if 0
3172     SetupOpenAppendInfFileW(NULL, hInf, NULL);
3173 #endif
3174
3175     /* Retrieve the actual section name */
3176     SetupDiGetActualSectionToInstallW(hInf,
3177                                       ClassInstall32,
3178                                       SectionName,
3179                                       MAX_PATH,
3180                                       &SectionNameLength,
3181                                       NULL);
3182
3183 #if 0
3184     if (!(Flags & DI_NOVCP))
3185     {
3186         FileQueue = SetupOpenFileQueue();
3187         if (FileQueue == INVALID_HANDLE_VALUE)
3188         {
3189             SetupCloseInfFile(hInf);
3190             return FALSE;
3191         }
3192
3193         bFileQueueCreated = TRUE;
3194
3195     }
3196 #endif
3197
3198     SetupInstallFromInfSectionW(NULL,
3199                                 hInf,
3200                                 SectionName,
3201                                 SPINST_REGISTRY,
3202                                 hClassKey,
3203                                 NULL,
3204                                 0,
3205                                 NULL,
3206                                 NULL,
3207                                 INVALID_HANDLE_VALUE,
3208                                 NULL);
3209
3210     /* FIXME: More code! */
3211
3212     if (bFileQueueCreated)
3213         SetupCloseFileQueue(FileQueue);
3214
3215     SetupCloseInfFile(hInf);
3216
3217     return TRUE;
3218 }
3219
3220
3221 /***********************************************************************
3222  *              SetupDiOpenClassRegKey  (SETUPAPI.@)
3223  */
3224 HKEY WINAPI SetupDiOpenClassRegKey(
3225         const GUID* ClassGuid,
3226         REGSAM samDesired)
3227 {
3228     return SetupDiOpenClassRegKeyExW(ClassGuid, samDesired,
3229                                      DIOCR_INSTALLER, NULL, NULL);
3230 }
3231
3232
3233 /***********************************************************************
3234  *              SetupDiOpenClassRegKeyExA  (SETUPAPI.@)
3235  */
3236 HKEY WINAPI SetupDiOpenClassRegKeyExA(
3237         const GUID* ClassGuid,
3238         REGSAM samDesired,
3239         DWORD Flags,
3240         PCSTR MachineName,
3241         PVOID Reserved)
3242 {
3243     PWSTR MachineNameW = NULL;
3244     HKEY hKey;
3245
3246     TRACE("\n");
3247
3248     if (MachineName)
3249     {
3250         MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
3251         if (MachineNameW == NULL)
3252             return INVALID_HANDLE_VALUE;
3253     }
3254
3255     hKey = SetupDiOpenClassRegKeyExW(ClassGuid, samDesired,
3256                                      Flags, MachineNameW, Reserved);
3257
3258     MyFree(MachineNameW);
3259
3260     return hKey;
3261 }
3262
3263
3264 /***********************************************************************
3265  *              SetupDiOpenClassRegKeyExW  (SETUPAPI.@)
3266  */
3267 HKEY WINAPI SetupDiOpenClassRegKeyExW(
3268         const GUID* ClassGuid,
3269         REGSAM samDesired,
3270         DWORD Flags,
3271         PCWSTR MachineName,
3272         PVOID Reserved)
3273 {
3274     HKEY hClassesKey;
3275     HKEY key;
3276     LPCWSTR lpKeyName;
3277     LONG l;
3278
3279     if (MachineName != NULL)
3280     {
3281         FIXME("Remote access not supported yet!\n");
3282         return INVALID_HANDLE_VALUE;
3283     }
3284
3285     if (Flags == DIOCR_INSTALLER)
3286     {
3287         lpKeyName = ControlClass;
3288     }
3289     else if (Flags == DIOCR_INTERFACE)
3290     {
3291         lpKeyName = DeviceClasses;
3292     }
3293     else
3294     {
3295         ERR("Invalid Flags parameter!\n");
3296         SetLastError(ERROR_INVALID_PARAMETER);
3297         return INVALID_HANDLE_VALUE;
3298     }
3299
3300     if (!ClassGuid)
3301     {
3302         if ((l = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
3303                           lpKeyName,
3304                           0,
3305                           samDesired,
3306                           &hClassesKey)))
3307         {
3308             SetLastError(l);
3309             hClassesKey = INVALID_HANDLE_VALUE;
3310         }
3311         key = hClassesKey;
3312     }
3313     else
3314     {
3315         WCHAR bracedGuidString[39];
3316
3317         SETUPDI_GuidToString(ClassGuid, bracedGuidString);
3318
3319         if (!(l = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
3320                           lpKeyName,
3321                           0,
3322                           samDesired,
3323                           &hClassesKey)))
3324         {
3325             if ((l = RegOpenKeyExW(hClassesKey,
3326                               bracedGuidString,
3327                               0,
3328                               samDesired,
3329                               &key)))
3330             {
3331                 SetLastError(l);
3332                 key = INVALID_HANDLE_VALUE;
3333             }
3334             RegCloseKey(hClassesKey);
3335         }
3336         else
3337         {
3338             SetLastError(l);
3339             key = INVALID_HANDLE_VALUE;
3340         }
3341     }
3342     return key;
3343 }
3344
3345 /***********************************************************************
3346  *              SetupDiOpenDeviceInterfaceW (SETUPAPI.@)
3347  */
3348 BOOL WINAPI SetupDiOpenDeviceInterfaceW(
3349        HDEVINFO DeviceInfoSet,
3350        PCWSTR DevicePath,
3351        DWORD OpenFlags,
3352        PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
3353 {
3354     FIXME("%p %s %08x %p\n",
3355         DeviceInfoSet, debugstr_w(DevicePath), OpenFlags, DeviceInterfaceData);
3356     return FALSE;
3357 }
3358
3359 /***********************************************************************
3360  *              SetupDiOpenDeviceInterfaceA (SETUPAPI.@)
3361  */
3362 BOOL WINAPI SetupDiOpenDeviceInterfaceA(
3363        HDEVINFO DeviceInfoSet,
3364        PCSTR DevicePath,
3365        DWORD OpenFlags,
3366        PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
3367 {
3368     FIXME("%p %s %08x %p\n", DeviceInfoSet,
3369         debugstr_a(DevicePath), OpenFlags, DeviceInterfaceData);
3370     return FALSE;
3371 }
3372
3373 /***********************************************************************
3374  *              SetupDiSetClassInstallParamsA (SETUPAPI.@)
3375  */
3376 BOOL WINAPI SetupDiSetClassInstallParamsA(
3377        HDEVINFO  DeviceInfoSet,
3378        PSP_DEVINFO_DATA DeviceInfoData,
3379        PSP_CLASSINSTALL_HEADER ClassInstallParams,
3380        DWORD ClassInstallParamsSize)
3381 {
3382     FIXME("%p %p %x %u\n",DeviceInfoSet, DeviceInfoData,
3383           ClassInstallParams->InstallFunction, ClassInstallParamsSize);
3384     return FALSE;
3385 }
3386
3387 /***********************************************************************
3388  *              SetupDiCallClassInstaller (SETUPAPI.@)
3389  */
3390 BOOL WINAPI SetupDiCallClassInstaller(
3391        DI_FUNCTION InstallFunction,
3392        HDEVINFO DeviceInfoSet,
3393        PSP_DEVINFO_DATA DeviceInfoData)
3394 {
3395     FIXME("%d %p %p\n", InstallFunction, DeviceInfoSet, DeviceInfoData);
3396     return FALSE;
3397 }
3398
3399 /***********************************************************************
3400  *              SetupDiGetDeviceInstallParamsA (SETUPAPI.@)
3401  */
3402 BOOL WINAPI SetupDiGetDeviceInstallParamsA(
3403        HDEVINFO DeviceInfoSet,
3404        PSP_DEVINFO_DATA DeviceInfoData,
3405        PSP_DEVINSTALL_PARAMS_A DeviceInstallParams)
3406 {
3407     FIXME("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstallParams);
3408     return FALSE;
3409 }
3410
3411 /***********************************************************************
3412  *              SetupDiOpenDevRegKey (SETUPAPI.@)
3413  */
3414 HKEY WINAPI SetupDiOpenDevRegKey(
3415        HDEVINFO DeviceInfoSet,
3416        PSP_DEVINFO_DATA DeviceInfoData,
3417        DWORD Scope,
3418        DWORD HwProfile,
3419        DWORD KeyType,
3420        REGSAM samDesired)
3421 {
3422     FIXME("%p %p %d %d %d %x\n", DeviceInfoSet, DeviceInfoData,
3423           Scope, HwProfile, KeyType, samDesired);
3424     return INVALID_HANDLE_VALUE;
3425 }