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