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