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