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