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