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