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