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