richedit: Avoid rewrapping all text for isolated format changes.
[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(set, &devInst->data,
565                 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 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     int devNameLen = lstrlenW(devName);
1353     DWORD devInst = 0;
1354     BOOL valid = TRUE;
1355
1356     TRACE("%s\n", debugstr_w(devName));
1357     for (ptr = devName; valid && *ptr && ptr - devName < devNameLen; )
1358     {
1359         if (isdigitW(*ptr))
1360         {
1361             devInst *= 10;
1362             devInst |= *ptr - '0';
1363             ptr++;
1364         }
1365         else
1366             valid = FALSE;
1367     }
1368     TRACE("%d\n", valid ? devInst : 0xffffffff);
1369     return valid ? devInst : 0xffffffff;
1370 }
1371
1372 /***********************************************************************
1373  *              SetupDiCreateDeviceInfoW (SETUPAPI.@)
1374  */
1375 BOOL WINAPI SetupDiCreateDeviceInfoW(
1376        HDEVINFO DeviceInfoSet,
1377        PCWSTR DeviceName,
1378        CONST GUID *ClassGuid,
1379        PCWSTR DeviceDescription,
1380        HWND hwndParent,
1381        DWORD CreationFlags,
1382        PSP_DEVINFO_DATA DeviceInfoData)
1383 {
1384     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
1385     BOOL ret = FALSE, allocatedInstanceId = FALSE;
1386     LPCWSTR instanceId = NULL;
1387
1388     TRACE("%p %s %s %s %p %x %p\n", DeviceInfoSet, debugstr_w(DeviceName),
1389         debugstr_guid(ClassGuid), debugstr_w(DeviceDescription),
1390         hwndParent, CreationFlags, DeviceInfoData);
1391
1392     if (!DeviceName)
1393     {
1394         SetLastError(ERROR_INVALID_DEVINST_NAME);
1395         return FALSE;
1396     }
1397     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
1398     {
1399         SetLastError(ERROR_INVALID_HANDLE);
1400         return FALSE;
1401     }
1402     if (!ClassGuid)
1403     {
1404         SetLastError(ERROR_INVALID_PARAMETER);
1405         return FALSE;
1406     }
1407     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
1408     {
1409         SetLastError(ERROR_INVALID_HANDLE);
1410         return FALSE;
1411     }
1412     if (!IsEqualGUID(&set->ClassGuid, &GUID_NULL) &&
1413         !IsEqualGUID(ClassGuid, &set->ClassGuid))
1414     {
1415         SetLastError(ERROR_CLASS_MISMATCH);
1416         return FALSE;
1417     }
1418     if ((CreationFlags & DICD_GENERATE_ID))
1419     {
1420         if (strchrW(DeviceName, '\\'))
1421             SetLastError(ERROR_INVALID_DEVINST_NAME);
1422         else
1423         {
1424             static const WCHAR newDeviceFmt[] = {'R','O','O','T','\\','%','s',
1425                 '\\','%','0','4','d',0};
1426             DWORD devId;
1427
1428             if (set->cDevices)
1429             {
1430                 DWORD highestDevID = 0;
1431                 struct DeviceInstance *devInst;
1432
1433                 LIST_FOR_EACH_ENTRY(devInst, &set->devices, struct DeviceInstance, entry)
1434                 {
1435                     struct DeviceInfo *devInfo = (struct DeviceInfo *)devInst->data.Reserved;
1436                     LPCWSTR devName = strrchrW(devInfo->instanceId, '\\');
1437                     DWORD id;
1438
1439                     if (devName)
1440                         devName++;
1441                     else
1442                         devName = devInfo->instanceId;
1443                     id = SETUPDI_DevNameToDevID(devName);
1444                     if (id != 0xffffffff && id > highestDevID)
1445                         highestDevID = id;
1446                 }
1447                 devId = highestDevID + 1;
1448             }
1449             else
1450                 devId = 0;
1451             /* 17 == lstrlenW(L"Root\\") + lstrlenW("\\") + 1 + %d max size */
1452             instanceId = HeapAlloc(GetProcessHeap(), 0,
1453                     (17 + lstrlenW(DeviceName)) * sizeof(WCHAR));
1454             if (instanceId)
1455             {
1456                 sprintfW((LPWSTR)instanceId, newDeviceFmt, DeviceName,
1457                         devId);
1458                 allocatedInstanceId = TRUE;
1459                 ret = TRUE;
1460             }
1461             else
1462                 ret = FALSE;
1463         }
1464     }
1465     else
1466     {
1467         struct DeviceInstance *devInst;
1468
1469         ret = TRUE;
1470         instanceId = DeviceName;
1471         LIST_FOR_EACH_ENTRY(devInst, &set->devices, struct DeviceInstance, entry)
1472         {
1473             struct DeviceInfo *devInfo = (struct DeviceInfo *)devInst->data.Reserved;
1474
1475             if (!lstrcmpiW(DeviceName, devInfo->instanceId))
1476             {
1477                 SetLastError(ERROR_DEVINST_ALREADY_EXISTS);
1478                 ret = FALSE;
1479             }
1480         }
1481     }
1482     if (ret)
1483     {
1484         SP_DEVINFO_DATA *dev = NULL;
1485
1486         ret = SETUPDI_AddDeviceToSet(set, ClassGuid, 0 /* FIXME: DevInst */,
1487                 instanceId, TRUE, &dev);
1488         if (ret)
1489         {
1490             if (DeviceDescription)
1491                 SetupDiSetDeviceRegistryPropertyW(DeviceInfoSet,
1492                     dev, SPDRP_DEVICEDESC, (const BYTE *)DeviceDescription,
1493                     lstrlenW(DeviceDescription) * sizeof(WCHAR));
1494             if (DeviceInfoData)
1495             {
1496                 if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
1497                 {
1498                     SetLastError(ERROR_INVALID_USER_BUFFER);
1499                     ret = FALSE;
1500                 }
1501                 else
1502                     *DeviceInfoData = *dev;
1503             }
1504         }
1505     }
1506     if (allocatedInstanceId)
1507         HeapFree(GetProcessHeap(), 0, (LPWSTR)instanceId);
1508
1509     return ret;
1510 }
1511
1512 /***********************************************************************
1513  *              SetupDiRegisterDeviceInfo (SETUPAPI.@)
1514  */
1515 BOOL WINAPI SetupDiRegisterDeviceInfo(
1516         HDEVINFO DeviceInfoSet,
1517         PSP_DEVINFO_DATA DeviceInfoData,
1518         DWORD Flags,
1519         PSP_DETSIG_CMPPROC CompareProc,
1520         PVOID CompareContext,
1521         PSP_DEVINFO_DATA DupDeviceInfoData)
1522 {
1523     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
1524     struct DeviceInfo *devInfo;
1525
1526     TRACE("%p %p %08x %p %p %p\n", DeviceInfoSet, DeviceInfoData, Flags,
1527             CompareProc, CompareContext, DupDeviceInfoData);
1528
1529     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
1530     {
1531         SetLastError(ERROR_INVALID_HANDLE);
1532         return FALSE;
1533     }
1534     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
1535     {
1536         SetLastError(ERROR_INVALID_HANDLE);
1537         return FALSE;
1538     }
1539     if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
1540             || !DeviceInfoData->Reserved)
1541     {
1542         SetLastError(ERROR_INVALID_PARAMETER);
1543         return FALSE;
1544     }
1545     devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
1546     if (devInfo->set != set)
1547     {
1548         SetLastError(ERROR_INVALID_PARAMETER);
1549         return FALSE;
1550     }
1551     if (devInfo->phantom)
1552     {
1553         devInfo->phantom = FALSE;
1554         RegDeleteValueW(devInfo->key, Phantom);
1555     }
1556     return TRUE;
1557 }
1558
1559 /***********************************************************************
1560  *              SetupDiEnumDeviceInfo (SETUPAPI.@)
1561  */
1562 BOOL WINAPI SetupDiEnumDeviceInfo(
1563         HDEVINFO  devinfo,
1564         DWORD  index,
1565         PSP_DEVINFO_DATA info)
1566 {
1567     BOOL ret = FALSE;
1568
1569     TRACE("%p %d %p\n", devinfo, index, info);
1570
1571     if(info==NULL)
1572     {
1573         SetLastError(ERROR_INVALID_PARAMETER);
1574         return FALSE;
1575     }
1576     if (devinfo && devinfo != INVALID_HANDLE_VALUE)
1577     {
1578         struct DeviceInfoSet *list = (struct DeviceInfoSet *)devinfo;
1579         if (list->magic == SETUP_DEVICE_INFO_SET_MAGIC)
1580         {
1581             if (index < list->cDevices)
1582             {
1583                 if (info->cbSize == sizeof(SP_DEVINFO_DATA))
1584                 {
1585                     struct DeviceInstance *devInst;
1586                     DWORD i = 0;
1587
1588                     LIST_FOR_EACH_ENTRY(devInst, &list->devices,
1589                             struct DeviceInstance, entry)
1590                     {
1591                         if (i++ == index)
1592                         {
1593                             *info = devInst->data;
1594                             break;
1595                         }
1596                     }
1597                     ret = TRUE;
1598                 }
1599                 else
1600                     SetLastError(ERROR_INVALID_USER_BUFFER);
1601             }
1602             else
1603                 SetLastError(ERROR_NO_MORE_ITEMS);
1604         }
1605         else
1606             SetLastError(ERROR_INVALID_HANDLE);
1607     }
1608     else
1609         SetLastError(ERROR_INVALID_HANDLE);
1610     return ret;
1611 }
1612
1613 /***********************************************************************
1614  *              SetupDiGetDeviceInstanceIdA (SETUPAPI.@)
1615  */
1616 BOOL WINAPI SetupDiGetDeviceInstanceIdA(
1617         HDEVINFO DeviceInfoSet,
1618         PSP_DEVINFO_DATA DeviceInfoData,
1619         PSTR DeviceInstanceId,
1620         DWORD DeviceInstanceIdSize,
1621         PDWORD RequiredSize)
1622 {
1623     BOOL ret = FALSE;
1624     DWORD size;
1625     PWSTR instanceId;
1626
1627     TRACE("%p %p %p %d %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstanceId,
1628             DeviceInstanceIdSize, RequiredSize);
1629
1630     SetupDiGetDeviceInstanceIdW(DeviceInfoSet,
1631                                 DeviceInfoData,
1632                                 NULL,
1633                                 0,
1634                                 &size);
1635     if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
1636         return FALSE;
1637     instanceId = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
1638     if (instanceId)
1639     {
1640         ret = SetupDiGetDeviceInstanceIdW(DeviceInfoSet,
1641                                           DeviceInfoData,
1642                                           instanceId,
1643                                           size,
1644                                           &size);
1645         if (ret)
1646         {
1647             int len = WideCharToMultiByte(CP_ACP, 0, instanceId, -1,
1648                                           DeviceInstanceId,
1649                                           DeviceInstanceIdSize, NULL, NULL);
1650
1651             if (!len)
1652                 ret = FALSE;
1653             else
1654             {
1655                 if (len > DeviceInstanceIdSize)
1656                 {
1657                     SetLastError(ERROR_INSUFFICIENT_BUFFER);
1658                     ret = FALSE;
1659                 }
1660                 if (RequiredSize)
1661                     *RequiredSize = len;
1662             }
1663         }
1664         HeapFree(GetProcessHeap(), 0, instanceId);
1665     }
1666     return ret;
1667 }
1668
1669 /***********************************************************************
1670  *              SetupDiGetDeviceInstanceIdW (SETUPAPI.@)
1671  */
1672 BOOL WINAPI SetupDiGetDeviceInstanceIdW(
1673         HDEVINFO DeviceInfoSet,
1674         PSP_DEVINFO_DATA DeviceInfoData,
1675         PWSTR DeviceInstanceId,
1676         DWORD DeviceInstanceIdSize,
1677         PDWORD RequiredSize)
1678 {
1679     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
1680     struct DeviceInfo *devInfo;
1681
1682     TRACE("%p %p %p %d %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstanceId,
1683             DeviceInstanceIdSize, RequiredSize);
1684
1685     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
1686     {
1687         SetLastError(ERROR_INVALID_HANDLE);
1688         return FALSE;
1689     }
1690     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
1691     {
1692         SetLastError(ERROR_INVALID_HANDLE);
1693         return FALSE;
1694     }
1695     if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
1696             || !DeviceInfoData->Reserved)
1697     {
1698         SetLastError(ERROR_INVALID_PARAMETER);
1699         return FALSE;
1700     }
1701     devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
1702     if (devInfo->set != set)
1703     {
1704         SetLastError(ERROR_INVALID_PARAMETER);
1705         return FALSE;
1706     }
1707     TRACE("instance ID: %s\n", debugstr_w(devInfo->instanceId));
1708     if (DeviceInstanceIdSize < strlenW(devInfo->instanceId) + 1)
1709     {
1710         SetLastError(ERROR_INSUFFICIENT_BUFFER);
1711         if (RequiredSize)
1712             *RequiredSize = lstrlenW(devInfo->instanceId) + 1;
1713         return FALSE;
1714     }
1715     lstrcpyW(DeviceInstanceId, devInfo->instanceId);
1716     if (RequiredSize)
1717         *RequiredSize = lstrlenW(devInfo->instanceId) + 1;
1718     return TRUE;
1719 }
1720
1721 /***********************************************************************
1722  *              SetupDiGetActualSectionToInstallA (SETUPAPI.@)
1723  */
1724 BOOL WINAPI SetupDiGetActualSectionToInstallA(
1725         HINF InfHandle,
1726         PCSTR InfSectionName,
1727         PSTR InfSectionWithExt,
1728         DWORD InfSectionWithExtSize,
1729         PDWORD RequiredSize,
1730         PSTR *Extension)
1731 {
1732     FIXME("\n");
1733     return FALSE;
1734 }
1735
1736 /***********************************************************************
1737  *              SetupDiGetActualSectionToInstallW (SETUPAPI.@)
1738  */
1739 BOOL WINAPI SetupDiGetActualSectionToInstallW(
1740         HINF InfHandle,
1741         PCWSTR InfSectionName,
1742         PWSTR InfSectionWithExt,
1743         DWORD InfSectionWithExtSize,
1744         PDWORD RequiredSize,
1745         PWSTR *Extension)
1746 {
1747     WCHAR szBuffer[MAX_PATH];
1748     DWORD dwLength;
1749     DWORD dwFullLength;
1750     LONG lLineCount = -1;
1751
1752     lstrcpyW(szBuffer, InfSectionName);
1753     dwLength = lstrlenW(szBuffer);
1754
1755     if (OsVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
1756     {
1757         /* Test section name with '.NTx86' extension */
1758         lstrcpyW(&szBuffer[dwLength], NtPlatformExtension);
1759         lLineCount = SetupGetLineCountW(InfHandle, szBuffer);
1760
1761         if (lLineCount == -1)
1762         {
1763             /* Test section name with '.NT' extension */
1764             lstrcpyW(&szBuffer[dwLength], NtExtension);
1765             lLineCount = SetupGetLineCountW(InfHandle, szBuffer);
1766         }
1767     }
1768     else
1769     {
1770         /* Test section name with '.Win' extension */
1771         lstrcpyW(&szBuffer[dwLength], WinExtension);
1772         lLineCount = SetupGetLineCountW(InfHandle, szBuffer);
1773     }
1774
1775     if (lLineCount == -1)
1776     {
1777         /* Test section name without extension */
1778         szBuffer[dwLength] = 0;
1779         lLineCount = SetupGetLineCountW(InfHandle, szBuffer);
1780     }
1781
1782     if (lLineCount == -1)
1783     {
1784         SetLastError(ERROR_INVALID_PARAMETER);
1785         return FALSE;
1786     }
1787
1788     dwFullLength = lstrlenW(szBuffer);
1789
1790     if (InfSectionWithExt != NULL && InfSectionWithExtSize != 0)
1791     {
1792         if (InfSectionWithExtSize < (dwFullLength + 1))
1793         {
1794             SetLastError(ERROR_INSUFFICIENT_BUFFER);
1795             return FALSE;
1796         }
1797
1798         lstrcpyW(InfSectionWithExt, szBuffer);
1799         if (Extension != NULL)
1800         {
1801             *Extension = (dwLength == dwFullLength) ? NULL : &InfSectionWithExt[dwLength];
1802         }
1803     }
1804
1805     if (RequiredSize != NULL)
1806     {
1807         *RequiredSize = dwFullLength + 1;
1808     }
1809
1810     return TRUE;
1811 }
1812
1813 /***********************************************************************
1814  *              SetupDiGetClassDescriptionA  (SETUPAPI.@)
1815  */
1816 BOOL WINAPI SetupDiGetClassDescriptionA(
1817         const GUID* ClassGuid,
1818         PSTR ClassDescription,
1819         DWORD ClassDescriptionSize,
1820         PDWORD RequiredSize)
1821 {
1822   return SetupDiGetClassDescriptionExA(ClassGuid, ClassDescription,
1823                                        ClassDescriptionSize,
1824                                        RequiredSize, NULL, NULL);
1825 }
1826
1827 /***********************************************************************
1828  *              SetupDiGetClassDescriptionW  (SETUPAPI.@)
1829  */
1830 BOOL WINAPI SetupDiGetClassDescriptionW(
1831         const GUID* ClassGuid,
1832         PWSTR ClassDescription,
1833         DWORD ClassDescriptionSize,
1834         PDWORD RequiredSize)
1835 {
1836   return SetupDiGetClassDescriptionExW(ClassGuid, ClassDescription,
1837                                        ClassDescriptionSize,
1838                                        RequiredSize, NULL, NULL);
1839 }
1840
1841 /***********************************************************************
1842  *              SetupDiGetClassDescriptionExA  (SETUPAPI.@)
1843  */
1844 BOOL WINAPI SetupDiGetClassDescriptionExA(
1845         const GUID* ClassGuid,
1846         PSTR ClassDescription,
1847         DWORD ClassDescriptionSize,
1848         PDWORD RequiredSize,
1849         PCSTR MachineName,
1850         PVOID Reserved)
1851 {
1852     HKEY hKey;
1853     DWORD dwLength;
1854     BOOL ret;
1855
1856     hKey = SetupDiOpenClassRegKeyExA(ClassGuid,
1857                                      KEY_ALL_ACCESS,
1858                                      DIOCR_INSTALLER,
1859                                      MachineName,
1860                                      Reserved);
1861     if (hKey == INVALID_HANDLE_VALUE)
1862     {
1863         WARN("SetupDiOpenClassRegKeyExA() failed (Error %u)\n", GetLastError());
1864         return FALSE;
1865     }
1866
1867     dwLength = ClassDescriptionSize;
1868     ret = !RegQueryValueExA( hKey, NULL, NULL, NULL,
1869                              (LPBYTE)ClassDescription, &dwLength );
1870     if (RequiredSize) *RequiredSize = dwLength;
1871     RegCloseKey(hKey);
1872     return ret;
1873 }
1874
1875 /***********************************************************************
1876  *              SetupDiGetClassDescriptionExW  (SETUPAPI.@)
1877  */
1878 BOOL WINAPI SetupDiGetClassDescriptionExW(
1879         const GUID* ClassGuid,
1880         PWSTR ClassDescription,
1881         DWORD ClassDescriptionSize,
1882         PDWORD RequiredSize,
1883         PCWSTR MachineName,
1884         PVOID Reserved)
1885 {
1886     HKEY hKey;
1887     DWORD dwLength;
1888     BOOL ret;
1889
1890     hKey = SetupDiOpenClassRegKeyExW(ClassGuid,
1891                                      KEY_ALL_ACCESS,
1892                                      DIOCR_INSTALLER,
1893                                      MachineName,
1894                                      Reserved);
1895     if (hKey == INVALID_HANDLE_VALUE)
1896     {
1897         WARN("SetupDiOpenClassRegKeyExW() failed (Error %u)\n", GetLastError());
1898         return FALSE;
1899     }
1900
1901     dwLength = ClassDescriptionSize * sizeof(WCHAR);
1902     ret = !RegQueryValueExW( hKey, NULL, NULL, NULL,
1903                              (LPBYTE)ClassDescription, &dwLength );
1904     if (RequiredSize) *RequiredSize = dwLength / sizeof(WCHAR);
1905     RegCloseKey(hKey);
1906     return ret;
1907 }
1908
1909 /***********************************************************************
1910  *              SetupDiGetClassDevsA (SETUPAPI.@)
1911  */
1912 HDEVINFO WINAPI SetupDiGetClassDevsA(
1913        CONST GUID *class,
1914        LPCSTR enumstr,
1915        HWND parent,
1916        DWORD flags)
1917 {
1918     HDEVINFO ret;
1919     LPWSTR enumstrW = NULL;
1920
1921     if (enumstr)
1922     {
1923         int len = MultiByteToWideChar(CP_ACP, 0, enumstr, -1, NULL, 0);
1924         enumstrW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1925         if (!enumstrW)
1926         {
1927             ret = INVALID_HANDLE_VALUE;
1928             goto end;
1929         }
1930         MultiByteToWideChar(CP_ACP, 0, enumstr, -1, enumstrW, len);
1931     }
1932     ret = SetupDiGetClassDevsExW(class, enumstrW, parent, flags, NULL, NULL,
1933             NULL);
1934     HeapFree(GetProcessHeap(), 0, enumstrW);
1935
1936 end:
1937     return ret;
1938 }
1939
1940 /***********************************************************************
1941  *                SetupDiGetClassDevsExA (SETUPAPI.@)
1942  */
1943 HDEVINFO WINAPI SetupDiGetClassDevsExA(
1944         const GUID *class,
1945         PCSTR enumstr,
1946         HWND parent,
1947         DWORD flags,
1948         HDEVINFO deviceset,
1949         PCSTR machine,
1950         PVOID reserved)
1951 {
1952     HDEVINFO ret;
1953     LPWSTR enumstrW = NULL, machineW = NULL;
1954
1955     if (enumstr)
1956     {
1957         int len = MultiByteToWideChar(CP_ACP, 0, enumstr, -1, NULL, 0);
1958         enumstrW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1959         if (!enumstrW)
1960         {
1961             ret = INVALID_HANDLE_VALUE;
1962             goto end;
1963         }
1964         MultiByteToWideChar(CP_ACP, 0, enumstr, -1, enumstrW, len);
1965     }
1966     if (machine)
1967     {
1968         int len = MultiByteToWideChar(CP_ACP, 0, machine, -1, NULL, 0);
1969         machineW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1970         if (!machineW)
1971         {
1972             HeapFree(GetProcessHeap(), 0, enumstrW);
1973             ret = INVALID_HANDLE_VALUE;
1974             goto end;
1975         }
1976         MultiByteToWideChar(CP_ACP, 0, machine, -1, machineW, len);
1977     }
1978     ret = SetupDiGetClassDevsExW(class, enumstrW, parent, flags, deviceset,
1979             machineW, reserved);
1980     HeapFree(GetProcessHeap(), 0, enumstrW);
1981     HeapFree(GetProcessHeap(), 0, machineW);
1982
1983 end:
1984     return ret;
1985 }
1986
1987 static void SETUPDI_AddDeviceInterfaces(SP_DEVINFO_DATA *dev, HKEY key,
1988         const GUID *interface)
1989 {
1990     DWORD i, len;
1991     WCHAR subKeyName[MAX_PATH];
1992     LONG l = ERROR_SUCCESS;
1993
1994     for (i = 0; !l; i++)
1995     {
1996         len = sizeof(subKeyName) / sizeof(subKeyName[0]);
1997         l = RegEnumKeyExW(key, i, subKeyName, &len, NULL, NULL, NULL, NULL);
1998         if (!l)
1999         {
2000             HKEY subKey;
2001             SP_DEVICE_INTERFACE_DATA *iface = NULL;
2002
2003             if (*subKeyName == '#')
2004             {
2005                 /* The subkey name is the reference string, with a '#' prepended */
2006                 SETUPDI_AddInterfaceInstance(dev, interface, subKeyName + 1,
2007                         &iface);
2008                 l = RegOpenKeyExW(key, subKeyName, 0, KEY_READ, &subKey);
2009                 if (!l)
2010                 {
2011                     WCHAR symbolicLink[MAX_PATH];
2012                     DWORD dataType;
2013
2014                     len = sizeof(symbolicLink);
2015                     l = RegQueryValueExW(subKey, SymbolicLink, NULL, &dataType,
2016                             (BYTE *)symbolicLink, &len);
2017                     if (!l && dataType == REG_SZ)
2018                         SETUPDI_SetInterfaceSymbolicLink(iface, symbolicLink);
2019                     RegCloseKey(subKey);
2020                 }
2021             }
2022             /* Allow enumeration to continue */
2023             l = ERROR_SUCCESS;
2024         }
2025     }
2026     /* FIXME: find and add all the device's interfaces to the device */
2027 }
2028
2029 static void SETUPDI_EnumerateMatchingInterfaces(HDEVINFO DeviceInfoSet,
2030         HKEY key, const GUID *interface, LPCWSTR enumstr)
2031 {
2032     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2033     DWORD i, len;
2034     WCHAR subKeyName[MAX_PATH];
2035     LONG l;
2036     HKEY enumKey = INVALID_HANDLE_VALUE;
2037
2038     TRACE("%s\n", debugstr_w(enumstr));
2039
2040     l = RegCreateKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, NULL, 0, KEY_READ, NULL,
2041             &enumKey, NULL);
2042     for (i = 0; !l; i++)
2043     {
2044         len = sizeof(subKeyName) / sizeof(subKeyName[0]);
2045         l = RegEnumKeyExW(key, i, subKeyName, &len, NULL, NULL, NULL, NULL);
2046         if (!l)
2047         {
2048             HKEY subKey;
2049
2050             l = RegOpenKeyExW(key, subKeyName, 0, KEY_READ, &subKey);
2051             if (!l)
2052             {
2053                 WCHAR deviceInst[MAX_PATH * 3];
2054                 DWORD dataType;
2055
2056                 len = sizeof(deviceInst);
2057                 l = RegQueryValueExW(subKey, DeviceInstance, NULL, &dataType,
2058                         (BYTE *)deviceInst, &len);
2059                 if (!l && dataType == REG_SZ)
2060                 {
2061                     TRACE("found instance ID %s\n", debugstr_w(deviceInst));
2062                     if (!enumstr || !lstrcmpiW(enumstr, deviceInst))
2063                     {
2064                         HKEY deviceKey;
2065
2066                         l = RegOpenKeyExW(enumKey, deviceInst, 0, KEY_READ,
2067                                 &deviceKey);
2068                         if (!l)
2069                         {
2070                             WCHAR deviceClassStr[40];
2071
2072                             len = sizeof(deviceClassStr);
2073                             l = RegQueryValueExW(deviceKey, ClassGUID, NULL,
2074                                     &dataType, (BYTE *)deviceClassStr, &len);
2075                             if (!l && dataType == REG_SZ &&
2076                                     deviceClassStr[0] == '{' &&
2077                                     deviceClassStr[37] == '}')
2078                             {
2079                                 GUID deviceClass;
2080                                 SP_DEVINFO_DATA *dev;
2081
2082                                 deviceClassStr[37] = 0;
2083                                 UuidFromStringW(&deviceClassStr[1],
2084                                         &deviceClass);
2085                                 if (SETUPDI_AddDeviceToSet(set, &deviceClass,
2086                                         0 /* FIXME: DevInst */, deviceInst,
2087                                         FALSE, &dev))
2088                                     SETUPDI_AddDeviceInterfaces(dev, subKey,
2089                                             interface);
2090                             }
2091                             RegCloseKey(deviceKey);
2092                         }
2093                     }
2094                 }
2095                 RegCloseKey(subKey);
2096             }
2097             /* Allow enumeration to continue */
2098             l = ERROR_SUCCESS;
2099         }
2100     }
2101     if (enumKey != INVALID_HANDLE_VALUE)
2102         RegCloseKey(enumKey);
2103 }
2104
2105 static void SETUPDI_EnumerateInterfaces(HDEVINFO DeviceInfoSet,
2106         const GUID *interface, LPCWSTR enumstr, DWORD flags)
2107 {
2108     HKEY interfacesKey = SetupDiOpenClassRegKeyExW(interface, KEY_READ,
2109             DIOCR_INTERFACE, NULL, NULL);
2110
2111     TRACE("%p, %s, %s, %08x\n", DeviceInfoSet, debugstr_guid(interface),
2112             debugstr_w(enumstr), flags);
2113
2114     if (interfacesKey != INVALID_HANDLE_VALUE)
2115     {
2116         if (flags & DIGCF_ALLCLASSES)
2117         {
2118             DWORD i, len;
2119             WCHAR interfaceGuidStr[40];
2120             LONG l = ERROR_SUCCESS;
2121
2122             for (i = 0; !l; i++)
2123             {
2124                 len = sizeof(interfaceGuidStr) / sizeof(interfaceGuidStr[0]);
2125                 l = RegEnumKeyExW(interfacesKey, i, interfaceGuidStr, &len,
2126                         NULL, NULL, NULL, NULL);
2127                 if (!l)
2128                 {
2129                     if (interfaceGuidStr[0] == '{' &&
2130                             interfaceGuidStr[37] == '}')
2131                     {
2132                         HKEY interfaceKey;
2133                         GUID interfaceGuid;
2134
2135                         interfaceGuidStr[37] = 0;
2136                         UuidFromStringW(&interfaceGuidStr[1], &interfaceGuid);
2137                         l = RegOpenKeyExW(interfacesKey, interfaceGuidStr, 0,
2138                                 KEY_READ, &interfaceKey);
2139                         if (!l)
2140                         {
2141                             SETUPDI_EnumerateMatchingInterfaces(DeviceInfoSet,
2142                                     interfaceKey, &interfaceGuid, enumstr);
2143                             RegCloseKey(interfaceKey);
2144                         }
2145                     }
2146                 }
2147             }
2148         }
2149         else
2150         {
2151             /* In this case, SetupDiOpenClassRegKeyExW opened the specific
2152              * interface's key, so just pass that long
2153              */
2154             SETUPDI_EnumerateMatchingInterfaces(DeviceInfoSet,
2155                     interfacesKey, interface, enumstr);
2156         }
2157         RegCloseKey(interfacesKey);
2158     }
2159 }
2160
2161 static void SETUPDI_EnumerateMatchingDeviceInstances(struct DeviceInfoSet *set,
2162         LPCWSTR enumerator, LPCWSTR deviceName, HKEY deviceKey,
2163         const GUID *class, DWORD flags)
2164 {
2165     DWORD i, len;
2166     WCHAR deviceInstance[MAX_PATH];
2167     LONG l = ERROR_SUCCESS;
2168
2169     TRACE("%s %s\n", debugstr_w(enumerator), debugstr_w(deviceName));
2170
2171     for (i = 0; !l; i++)
2172     {
2173         len = sizeof(deviceInstance) / sizeof(deviceInstance[0]);
2174         l = RegEnumKeyExW(deviceKey, i, deviceInstance, &len, NULL, NULL, NULL,
2175                 NULL);
2176         if (!l)
2177         {
2178             HKEY subKey;
2179
2180             l = RegOpenKeyExW(deviceKey, deviceInstance, 0, KEY_READ, &subKey);
2181             if (!l)
2182             {
2183                 WCHAR classGuid[40];
2184                 DWORD dataType;
2185
2186                 len = sizeof(classGuid);
2187                 l = RegQueryValueExW(subKey, ClassGUID, NULL, &dataType,
2188                         (BYTE *)classGuid, &len);
2189                 if (!l && dataType == REG_SZ)
2190                 {
2191                     if (classGuid[0] == '{' && classGuid[37] == '}')
2192                     {
2193                         GUID deviceClass;
2194
2195                         classGuid[37] = 0;
2196                         UuidFromStringW(&classGuid[1], &deviceClass);
2197                         if ((flags & DIGCF_ALLCLASSES) ||
2198                                 IsEqualGUID(class, &deviceClass))
2199                         {
2200                             static const WCHAR fmt[] =
2201                              {'%','s','\\','%','s','\\','%','s',0};
2202                             LPWSTR instanceId;
2203
2204                             instanceId = HeapAlloc(GetProcessHeap(), 0,
2205                                 (lstrlenW(enumerator) + lstrlenW(deviceName) +
2206                                 lstrlenW(deviceInstance) + 3) * sizeof(WCHAR));
2207                             if (instanceId)
2208                             {
2209                                 sprintfW(instanceId, fmt, enumerator,
2210                                         deviceName, deviceInstance);
2211                                 SETUPDI_AddDeviceToSet(set, &deviceClass,
2212                                         0 /* FIXME: DevInst */, instanceId,
2213                                         FALSE, NULL);
2214                                 HeapFree(GetProcessHeap(), 0, instanceId);
2215                             }
2216                         }
2217                     }
2218                 }
2219                 RegCloseKey(subKey);
2220             }
2221             /* Allow enumeration to continue */
2222             l = ERROR_SUCCESS;
2223         }
2224     }
2225 }
2226
2227 static void SETUPDI_EnumerateMatchingDevices(HDEVINFO DeviceInfoSet,
2228         LPCWSTR parent, HKEY key, const GUID *class, DWORD flags)
2229 {
2230     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2231     DWORD i, len;
2232     WCHAR subKeyName[MAX_PATH];
2233     LONG l = ERROR_SUCCESS;
2234
2235     TRACE("%s\n", debugstr_w(parent));
2236
2237     for (i = 0; !l; i++)
2238     {
2239         len = sizeof(subKeyName) / sizeof(subKeyName[0]);
2240         l = RegEnumKeyExW(key, i, subKeyName, &len, NULL, NULL, NULL, NULL);
2241         if (!l)
2242         {
2243             HKEY subKey;
2244
2245             l = RegOpenKeyExW(key, subKeyName, 0, KEY_READ, &subKey);
2246             if (!l)
2247             {
2248                 TRACE("%s\n", debugstr_w(subKeyName));
2249                 SETUPDI_EnumerateMatchingDeviceInstances(set, parent,
2250                         subKeyName, subKey, class, flags);
2251                 RegCloseKey(subKey);
2252             }
2253             /* Allow enumeration to continue */
2254             l = ERROR_SUCCESS;
2255         }
2256     }
2257 }
2258
2259 static void SETUPDI_EnumerateDevices(HDEVINFO DeviceInfoSet, const GUID *class,
2260         LPCWSTR enumstr, DWORD flags)
2261 {
2262     HKEY enumKey;
2263     LONG l;
2264
2265     TRACE("%p, %s, %s, %08x\n", DeviceInfoSet, debugstr_guid(class),
2266             debugstr_w(enumstr), flags);
2267
2268     l = RegCreateKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, NULL, 0, KEY_READ, NULL,
2269             &enumKey, NULL);
2270     if (enumKey != INVALID_HANDLE_VALUE)
2271     {
2272         if (enumstr)
2273         {
2274             HKEY enumStrKey;
2275
2276             l = RegOpenKeyExW(enumKey, enumstr, 0, KEY_READ,
2277                     &enumStrKey);
2278             if (!l)
2279             {
2280                 SETUPDI_EnumerateMatchingDevices(DeviceInfoSet, enumstr,
2281                         enumStrKey, class, flags);
2282                 RegCloseKey(enumStrKey);
2283             }
2284         }
2285         else
2286         {
2287             DWORD i, len;
2288             WCHAR subKeyName[MAX_PATH];
2289
2290             l = ERROR_SUCCESS;
2291             for (i = 0; !l; i++)
2292             {
2293                 len = sizeof(subKeyName) / sizeof(subKeyName[0]);
2294                 l = RegEnumKeyExW(enumKey, i, subKeyName, &len, NULL,
2295                         NULL, NULL, NULL);
2296                 if (!l)
2297                 {
2298                     HKEY subKey;
2299
2300                     l = RegOpenKeyExW(enumKey, subKeyName, 0, KEY_READ,
2301                             &subKey);
2302                     if (!l)
2303                     {
2304                         SETUPDI_EnumerateMatchingDevices(DeviceInfoSet,
2305                                 subKeyName, subKey, class, flags);
2306                         RegCloseKey(subKey);
2307                     }
2308                     /* Allow enumeration to continue */
2309                     l = ERROR_SUCCESS;
2310                 }
2311             }
2312         }
2313         RegCloseKey(enumKey);
2314     }
2315 }
2316
2317 /***********************************************************************
2318  *              SetupDiGetClassDevsW (SETUPAPI.@)
2319  */
2320 HDEVINFO WINAPI SetupDiGetClassDevsW(
2321        CONST GUID *class,
2322        LPCWSTR enumstr,
2323        HWND parent,
2324        DWORD flags)
2325 {
2326     return SetupDiGetClassDevsExW(class, enumstr, parent, flags, NULL, NULL,
2327             NULL);
2328 }
2329
2330 /***********************************************************************
2331  *              SetupDiGetClassDevsExW (SETUPAPI.@)
2332  */
2333 HDEVINFO WINAPI SetupDiGetClassDevsExW(
2334         CONST GUID *class,
2335         PCWSTR enumstr,
2336         HWND parent,
2337         DWORD flags,
2338         HDEVINFO deviceset,
2339         PCWSTR machine,
2340         PVOID reserved)
2341 {
2342     static const DWORD unsupportedFlags = DIGCF_DEFAULT | DIGCF_PRESENT |
2343         DIGCF_PROFILE;
2344     HDEVINFO set;
2345
2346     TRACE("%s %s %p 0x%08x %p %s %p\n", debugstr_guid(class),
2347             debugstr_w(enumstr), parent, flags, deviceset, debugstr_w(machine),
2348             reserved);
2349
2350     if (!(flags & DIGCF_ALLCLASSES) && !class)
2351     {
2352         SetLastError(ERROR_INVALID_PARAMETER);
2353         return NULL;
2354     }
2355     if (flags & unsupportedFlags)
2356         WARN("unsupported flags %08x\n", flags & unsupportedFlags);
2357     if (deviceset)
2358         set = deviceset;
2359     else
2360         set = SetupDiCreateDeviceInfoListExW(class, parent, machine, reserved);
2361     if (set)
2362     {
2363         if (machine)
2364             FIXME("%s: unimplemented for remote machines\n",
2365                     debugstr_w(machine));
2366         else if (flags & DIGCF_DEVICEINTERFACE)
2367             SETUPDI_EnumerateInterfaces(set, class, enumstr, flags);
2368         else
2369             SETUPDI_EnumerateDevices(set, class, enumstr, flags);
2370     }
2371     return set;
2372 }
2373
2374 /***********************************************************************
2375  *              SetupDiGetDeviceInfoListDetailA  (SETUPAPI.@)
2376  */
2377 BOOL WINAPI SetupDiGetDeviceInfoListDetailA(
2378         HDEVINFO DeviceInfoSet,
2379         PSP_DEVINFO_LIST_DETAIL_DATA_A DevInfoData )
2380 {
2381     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2382
2383     TRACE("%p %p\n", DeviceInfoSet, DevInfoData);
2384
2385     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
2386     {
2387         SetLastError(ERROR_INVALID_HANDLE);
2388         return FALSE;
2389     }
2390     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2391     {
2392         SetLastError(ERROR_INVALID_HANDLE);
2393         return FALSE;
2394     }
2395     if (!DevInfoData ||
2396             DevInfoData->cbSize != sizeof(SP_DEVINFO_LIST_DETAIL_DATA_A))
2397     {
2398         SetLastError(ERROR_INVALID_PARAMETER);
2399         return FALSE;
2400     }
2401     DevInfoData->ClassGuid = set->ClassGuid;
2402     DevInfoData->RemoteMachineHandle = NULL;
2403     DevInfoData->RemoteMachineName[0] = '\0';
2404     return TRUE;
2405 }
2406
2407 /***********************************************************************
2408  *              SetupDiGetDeviceInfoListDetailW  (SETUPAPI.@)
2409  */
2410 BOOL WINAPI SetupDiGetDeviceInfoListDetailW(
2411         HDEVINFO DeviceInfoSet,
2412         PSP_DEVINFO_LIST_DETAIL_DATA_W DevInfoData )
2413 {
2414     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2415
2416     TRACE("%p %p\n", DeviceInfoSet, DevInfoData);
2417
2418     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
2419     {
2420         SetLastError(ERROR_INVALID_HANDLE);
2421         return FALSE;
2422     }
2423     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2424     {
2425         SetLastError(ERROR_INVALID_HANDLE);
2426         return FALSE;
2427     }
2428     if (!DevInfoData ||
2429             DevInfoData->cbSize != sizeof(SP_DEVINFO_LIST_DETAIL_DATA_W))
2430     {
2431         SetLastError(ERROR_INVALID_PARAMETER);
2432         return FALSE;
2433     }
2434     DevInfoData->ClassGuid = set->ClassGuid;
2435     DevInfoData->RemoteMachineHandle = NULL;
2436     DevInfoData->RemoteMachineName[0] = '\0';
2437     return TRUE;
2438 }
2439
2440 /***********************************************************************
2441  *              SetupDiCreateDeviceInterfaceA (SETUPAPI.@)
2442  */
2443 BOOL WINAPI SetupDiCreateDeviceInterfaceA(
2444         HDEVINFO DeviceInfoSet,
2445         PSP_DEVINFO_DATA DeviceInfoData,
2446         const GUID *InterfaceClassGuid,
2447         PCSTR ReferenceString,
2448         DWORD CreationFlags,
2449         PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
2450 {
2451     BOOL ret;
2452     LPWSTR ReferenceStringW = NULL;
2453
2454     TRACE("%p %p %s %s %08x %p\n", DeviceInfoSet, DeviceInfoData,
2455             debugstr_guid(InterfaceClassGuid), debugstr_a(ReferenceString),
2456             CreationFlags, DeviceInterfaceData);
2457
2458     if (ReferenceString)
2459     {
2460         ReferenceStringW = MultiByteToUnicode(ReferenceString, CP_ACP);
2461         if (ReferenceStringW == NULL) return FALSE;
2462     }
2463
2464     ret = SetupDiCreateDeviceInterfaceW(DeviceInfoSet, DeviceInfoData,
2465             InterfaceClassGuid, ReferenceStringW, CreationFlags,
2466             DeviceInterfaceData);
2467
2468     MyFree(ReferenceStringW);
2469
2470     return ret;
2471 }
2472
2473 /***********************************************************************
2474  *              SetupDiCreateDeviceInterfaceW (SETUPAPI.@)
2475  */
2476 BOOL WINAPI SetupDiCreateDeviceInterfaceW(
2477         HDEVINFO DeviceInfoSet,
2478         PSP_DEVINFO_DATA DeviceInfoData,
2479         const GUID *InterfaceClassGuid,
2480         PCWSTR ReferenceString,
2481         DWORD CreationFlags,
2482         PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
2483 {
2484     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2485     struct DeviceInfo *devInfo;
2486     SP_DEVICE_INTERFACE_DATA *iface = NULL;
2487     BOOL ret;
2488
2489     TRACE("%p %p %s %s %08x %p\n", DeviceInfoSet, DeviceInfoData,
2490             debugstr_guid(InterfaceClassGuid), debugstr_w(ReferenceString),
2491             CreationFlags, DeviceInterfaceData);
2492
2493     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
2494     {
2495         SetLastError(ERROR_INVALID_HANDLE);
2496         return FALSE;
2497     }
2498     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2499     {
2500         SetLastError(ERROR_INVALID_HANDLE);
2501         return FALSE;
2502     }
2503     if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
2504             || !DeviceInfoData->Reserved)
2505     {
2506         SetLastError(ERROR_INVALID_PARAMETER);
2507         return FALSE;
2508     }
2509     devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
2510     if (devInfo->set != set)
2511     {
2512         SetLastError(ERROR_INVALID_PARAMETER);
2513         return FALSE;
2514     }
2515     if (!InterfaceClassGuid)
2516     {
2517         SetLastError(ERROR_INVALID_USER_BUFFER);
2518         return FALSE;
2519     }
2520     if ((ret = SETUPDI_AddInterfaceInstance(DeviceInfoData, InterfaceClassGuid,
2521                     ReferenceString, &iface)))
2522     {
2523         if (DeviceInterfaceData)
2524         {
2525             if (DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA))
2526             {
2527                 SetLastError(ERROR_INVALID_USER_BUFFER);
2528                 ret = FALSE;
2529             }
2530             else
2531                 *DeviceInterfaceData = *iface;
2532         }
2533     }
2534     return ret;
2535 }
2536
2537 /***********************************************************************
2538  *              SetupDiCreateDeviceInterfaceRegKeyA (SETUPAPI.@)
2539  */
2540 HKEY WINAPI SetupDiCreateDeviceInterfaceRegKeyA(
2541         HDEVINFO DeviceInfoSet,
2542         PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
2543         DWORD Reserved,
2544         REGSAM samDesired,
2545         HINF InfHandle,
2546         PCSTR InfSectionName)
2547 {
2548     HKEY key;
2549     PWSTR InfSectionNameW = NULL;
2550
2551     TRACE("%p %p %d %08x %p %p\n", DeviceInfoSet, DeviceInterfaceData, Reserved,
2552             samDesired, InfHandle, InfSectionName);
2553     if (InfHandle)
2554     {
2555         if (!InfSectionName)
2556         {
2557             SetLastError(ERROR_INVALID_PARAMETER);
2558             return INVALID_HANDLE_VALUE;
2559         }
2560         InfSectionNameW = MultiByteToUnicode(InfSectionName, CP_ACP);
2561         if (!InfSectionNameW)
2562             return INVALID_HANDLE_VALUE;
2563     }
2564     key = SetupDiCreateDeviceInterfaceRegKeyW(DeviceInfoSet,
2565             DeviceInterfaceData, Reserved, samDesired, InfHandle,
2566             InfSectionNameW);
2567     MyFree(InfSectionNameW);
2568     return key;
2569 }
2570
2571 static PWSTR SETUPDI_GetInstancePath(struct InterfaceInfo *ifaceInfo)
2572 {
2573     static const WCHAR hash[] = {'#',0};
2574     PWSTR instancePath = NULL;
2575
2576     if (ifaceInfo->referenceString)
2577     {
2578         instancePath = HeapAlloc(GetProcessHeap(), 0,
2579                 (lstrlenW(ifaceInfo->referenceString) + 2) * sizeof(WCHAR));
2580         if (instancePath)
2581         {
2582             lstrcpyW(instancePath, hash);
2583             lstrcatW(instancePath, ifaceInfo->referenceString);
2584         }
2585         else
2586             SetLastError(ERROR_OUTOFMEMORY);
2587     }
2588     else
2589     {
2590         instancePath = HeapAlloc(GetProcessHeap(), 0,
2591                 (lstrlenW(hash) + 1) * sizeof(WCHAR));
2592         if (instancePath)
2593             lstrcpyW(instancePath, hash);
2594     }
2595     return instancePath;
2596 }
2597
2598 /***********************************************************************
2599  *              SetupDiCreateDeviceInterfaceRegKeyW (SETUPAPI.@)
2600  */
2601 HKEY WINAPI SetupDiCreateDeviceInterfaceRegKeyW(
2602         HDEVINFO DeviceInfoSet,
2603         PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
2604         DWORD Reserved,
2605         REGSAM samDesired,
2606         HINF InfHandle,
2607         PCWSTR InfSectionName)
2608 {
2609     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2610     HKEY key = INVALID_HANDLE_VALUE, interfacesKey;
2611     LONG l;
2612
2613     TRACE("%p %p %d %08x %p %p\n", DeviceInfoSet, DeviceInterfaceData, Reserved,
2614             samDesired, InfHandle, InfSectionName);
2615
2616     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE ||
2617             set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2618     {
2619         SetLastError(ERROR_INVALID_HANDLE);
2620         return INVALID_HANDLE_VALUE;
2621     }
2622     if (!DeviceInterfaceData ||
2623             DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA) ||
2624             !DeviceInterfaceData->Reserved)
2625     {
2626         SetLastError(ERROR_INVALID_PARAMETER);
2627         return INVALID_HANDLE_VALUE;
2628     }
2629     if (InfHandle && !InfSectionName)
2630     {
2631         SetLastError(ERROR_INVALID_PARAMETER);
2632         return INVALID_HANDLE_VALUE;
2633     }
2634     if (!(l = RegCreateKeyExW(HKEY_LOCAL_MACHINE, DeviceClasses, 0, NULL, 0,
2635                     samDesired, NULL, &interfacesKey, NULL)))
2636     {
2637         HKEY parent;
2638         WCHAR bracedGuidString[39];
2639
2640         SETUPDI_GuidToString(&DeviceInterfaceData->InterfaceClassGuid,
2641                 bracedGuidString);
2642         if (!(l = RegCreateKeyExW(interfacesKey, bracedGuidString, 0, NULL, 0,
2643                         samDesired, NULL, &parent, NULL)))
2644         {
2645             struct InterfaceInfo *ifaceInfo =
2646                 (struct InterfaceInfo *)DeviceInterfaceData->Reserved;
2647             PWSTR instancePath = SETUPDI_GetInstancePath(ifaceInfo);
2648             PWSTR interfKeyName = HeapAlloc(GetProcessHeap(), 0,
2649                     (lstrlenW(ifaceInfo->symbolicLink) + 1) * sizeof(WCHAR));
2650             HKEY interfKey;
2651             WCHAR *ptr;
2652
2653             lstrcpyW(interfKeyName, ifaceInfo->symbolicLink);
2654             if (lstrlenW(ifaceInfo->symbolicLink) > 3)
2655             {
2656                 interfKeyName[0] = '#';
2657                 interfKeyName[1] = '#';
2658                 interfKeyName[3] = '#';
2659             }
2660             ptr = strchrW(interfKeyName, '\\');
2661             if (ptr)
2662                 *ptr = 0;
2663             l = RegCreateKeyExW(parent, interfKeyName, 0, NULL, 0,
2664                     samDesired, NULL, &interfKey, NULL);
2665             if (!l)
2666             {
2667                 struct DeviceInfo *devInfo =
2668                         (struct DeviceInfo *)ifaceInfo->device->Reserved;
2669
2670                 l = RegSetValueExW(interfKey, DeviceInstance, 0, REG_SZ,
2671                         (BYTE *)devInfo->instanceId,
2672                         (lstrlenW(devInfo->instanceId) + 1) * sizeof(WCHAR));
2673                 if (!l)
2674                 {
2675                     if (instancePath)
2676                     {
2677                         LONG l;
2678
2679                         l = RegCreateKeyExW(interfKey, instancePath, 0, NULL, 0,
2680                                 samDesired, NULL, &key, NULL);
2681                         if (l)
2682                         {
2683                             SetLastError(l);
2684                             key = INVALID_HANDLE_VALUE;
2685                         }
2686                         else if (InfHandle)
2687                             FIXME("INF section installation unsupported\n");
2688                     }
2689                 }
2690                 else
2691                     SetLastError(l);
2692                 RegCloseKey(interfKey);
2693             }
2694             else
2695                 SetLastError(l);
2696             HeapFree(GetProcessHeap(), 0, interfKeyName);
2697             HeapFree(GetProcessHeap(), 0, instancePath);
2698             RegCloseKey(parent);
2699         }
2700         else
2701             SetLastError(l);
2702         RegCloseKey(interfacesKey);
2703     }
2704     else
2705         SetLastError(l);
2706     return key;
2707 }
2708
2709 /***********************************************************************
2710  *              SetupDiDeleteDeviceInterfaceRegKey (SETUPAPI.@)
2711  */
2712 BOOL WINAPI SetupDiDeleteDeviceInterfaceRegKey(
2713         HDEVINFO DeviceInfoSet,
2714         PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
2715         DWORD Reserved)
2716 {
2717     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2718     HKEY parent;
2719     BOOL ret = FALSE;
2720
2721     TRACE("%p %p %d\n", DeviceInfoSet, DeviceInterfaceData, Reserved);
2722
2723     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE ||
2724             set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2725     {
2726         SetLastError(ERROR_INVALID_HANDLE);
2727         return FALSE;
2728     }
2729     if (!DeviceInterfaceData ||
2730             DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA) ||
2731             !DeviceInterfaceData->Reserved)
2732     {
2733         SetLastError(ERROR_INVALID_PARAMETER);
2734         return FALSE;
2735     }
2736     parent = SetupDiOpenClassRegKeyExW(&DeviceInterfaceData->InterfaceClassGuid,
2737             KEY_ALL_ACCESS, DIOCR_INTERFACE, NULL, NULL);
2738     if (parent != INVALID_HANDLE_VALUE)
2739     {
2740         struct InterfaceInfo *ifaceInfo =
2741             (struct InterfaceInfo *)DeviceInterfaceData->Reserved;
2742         PWSTR instancePath = SETUPDI_GetInstancePath(ifaceInfo);
2743
2744         if (instancePath)
2745         {
2746             LONG l = RegDeleteKeyW(parent, instancePath);
2747
2748             if (l)
2749                 SetLastError(l);
2750             else
2751                 ret = TRUE;
2752             HeapFree(GetProcessHeap(), 0, instancePath);
2753         }
2754         RegCloseKey(parent);
2755     }
2756     return ret;
2757 }
2758
2759 /***********************************************************************
2760  *              SetupDiEnumDeviceInterfaces (SETUPAPI.@)
2761  *
2762  * PARAMS
2763  *   DeviceInfoSet      [I]    Set of devices from which to enumerate
2764  *                             interfaces
2765  *   DeviceInfoData     [I]    (Optional) If specified, a specific device
2766  *                             instance from which to enumerate interfaces.
2767  *                             If it isn't specified, all interfaces for all
2768  *                             devices in the set are enumerated.
2769  *   InterfaceClassGuid [I]    The interface class to enumerate.
2770  *   MemberIndex        [I]    An index of the interface instance to enumerate.
2771  *                             A caller should start with MemberIndex set to 0,
2772  *                             and continue until the function fails with
2773  *                             ERROR_NO_MORE_ITEMS.
2774  *   DeviceInterfaceData [I/O] Returns an enumerated interface.  Its cbSize
2775  *                             member must be set to
2776  *                             sizeof(SP_DEVICE_INTERFACE_DATA).
2777  *
2778  * RETURNS
2779  *   Success: non-zero value.
2780  *   Failure: FALSE.  Call GetLastError() for more info.
2781  */
2782 BOOL WINAPI SetupDiEnumDeviceInterfaces(
2783        HDEVINFO DeviceInfoSet,
2784        PSP_DEVINFO_DATA DeviceInfoData,
2785        CONST GUID * InterfaceClassGuid,
2786        DWORD MemberIndex,
2787        PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
2788 {
2789     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2790     BOOL ret = FALSE;
2791
2792     TRACE("%p, %p, %s, %d, %p\n", DeviceInfoSet, DeviceInfoData,
2793      debugstr_guid(InterfaceClassGuid), MemberIndex, DeviceInterfaceData);
2794
2795     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE ||
2796             set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2797     {
2798         SetLastError(ERROR_INVALID_HANDLE);
2799         return FALSE;
2800     }
2801     if (DeviceInfoData && (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA) ||
2802                 !DeviceInfoData->Reserved))
2803     {
2804         SetLastError(ERROR_INVALID_PARAMETER);
2805         return FALSE;
2806     }
2807     if (!DeviceInterfaceData ||
2808             DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA))
2809     {
2810         SetLastError(ERROR_INVALID_PARAMETER);
2811         return FALSE;
2812     }
2813     if (DeviceInfoData)
2814     {
2815         struct DeviceInfo *devInfo =
2816             (struct DeviceInfo *)DeviceInfoData->Reserved;
2817         struct InterfaceInstances *iface;
2818
2819         if ((ret = SETUPDI_FindInterface(devInfo, InterfaceClassGuid, &iface)))
2820         {
2821             if (MemberIndex < iface->cInstances)
2822                 *DeviceInterfaceData = iface->instances[MemberIndex];
2823             else
2824             {
2825                 SetLastError(ERROR_NO_MORE_ITEMS);
2826                 ret = FALSE;
2827             }
2828         }
2829         else
2830             SetLastError(ERROR_NO_MORE_ITEMS);
2831     }
2832     else
2833     {
2834         struct DeviceInstance *devInst;
2835         DWORD cEnumerated = 0;
2836         BOOL found = FALSE;
2837
2838         LIST_FOR_EACH_ENTRY(devInst, &set->devices, struct DeviceInstance, entry)
2839         {
2840             struct DeviceInfo *devInfo = (struct DeviceInfo *)devInst->data.Reserved;
2841             struct InterfaceInstances *iface;
2842
2843             if (found || cEnumerated >= MemberIndex + 1)
2844                 break;
2845             if (SETUPDI_FindInterface(devInfo, InterfaceClassGuid, &iface))
2846             {
2847                 if (cEnumerated + iface->cInstances < MemberIndex + 1)
2848                     cEnumerated += iface->cInstances;
2849                 else
2850                 {
2851                     DWORD instanceIndex = MemberIndex - cEnumerated;
2852
2853                     *DeviceInterfaceData = iface->instances[instanceIndex];
2854                     cEnumerated += instanceIndex + 1;
2855                     found = TRUE;
2856                     ret = TRUE;
2857                 }
2858             }
2859         }
2860         if (!found)
2861             SetLastError(ERROR_NO_MORE_ITEMS);
2862     }
2863     return ret;
2864 }
2865
2866 /***********************************************************************
2867  *              SetupDiDestroyDeviceInfoList (SETUPAPI.@)
2868   *
2869  * Destroy a DeviceInfoList and free all used memory of the list.
2870  *
2871  * PARAMS
2872  *   devinfo [I] DeviceInfoList pointer to list to destroy
2873  *
2874  * RETURNS
2875  *   Success: non zero value.
2876  *   Failure: zero value.
2877  */
2878 BOOL WINAPI SetupDiDestroyDeviceInfoList(HDEVINFO devinfo)
2879 {
2880     BOOL ret = FALSE;
2881
2882     TRACE("%p\n", devinfo);
2883     if (devinfo && devinfo != INVALID_HANDLE_VALUE)
2884     {
2885         struct DeviceInfoSet *list = (struct DeviceInfoSet *)devinfo;
2886
2887         if (list->magic == SETUP_DEVICE_INFO_SET_MAGIC)
2888         {
2889             struct DeviceInstance *devInst, *devInst2;
2890
2891             LIST_FOR_EACH_ENTRY_SAFE(devInst, devInst2, &list->devices,
2892                     struct DeviceInstance, entry)
2893             {
2894                 SETUPDI_FreeDeviceInfo( (struct DeviceInfo *)devInst->data.Reserved );
2895                 list_remove(&devInst->entry);
2896                 HeapFree(GetProcessHeap(), 0, devInst);
2897             }
2898             HeapFree(GetProcessHeap(), 0, list);
2899             ret = TRUE;
2900         }
2901     }
2902
2903     if (ret == FALSE)
2904         SetLastError(ERROR_INVALID_HANDLE);
2905
2906     return ret;
2907 }
2908
2909 /***********************************************************************
2910  *              SetupDiGetDeviceInterfaceDetailA (SETUPAPI.@)
2911  */
2912 BOOL WINAPI SetupDiGetDeviceInterfaceDetailA(
2913       HDEVINFO DeviceInfoSet,
2914       PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
2915       PSP_DEVICE_INTERFACE_DETAIL_DATA_A DeviceInterfaceDetailData,
2916       DWORD DeviceInterfaceDetailDataSize,
2917       PDWORD RequiredSize,
2918       PSP_DEVINFO_DATA DeviceInfoData)
2919 {
2920     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2921     struct InterfaceInfo *info;
2922     DWORD bytesNeeded = offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath)
2923         + 1;
2924     BOOL ret = FALSE;
2925
2926     TRACE("(%p, %p, %p, %d, %p, %p)\n", DeviceInfoSet,
2927      DeviceInterfaceData, DeviceInterfaceDetailData,
2928      DeviceInterfaceDetailDataSize, RequiredSize, DeviceInfoData);
2929
2930     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE ||
2931             set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2932     {
2933         SetLastError(ERROR_INVALID_HANDLE);
2934         return FALSE;
2935     }
2936     if (!DeviceInterfaceData ||
2937             DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA) ||
2938             !DeviceInterfaceData->Reserved)
2939     {
2940         SetLastError(ERROR_INVALID_PARAMETER);
2941         return FALSE;
2942     }
2943     if (DeviceInterfaceDetailData && (DeviceInterfaceDetailData->cbSize !=
2944             offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath) + sizeof(char)))
2945     {
2946         SetLastError(ERROR_INVALID_USER_BUFFER);
2947         return FALSE;
2948     }
2949     if (!DeviceInterfaceDetailData && DeviceInterfaceDetailDataSize)
2950     {
2951         SetLastError(ERROR_INVALID_USER_BUFFER);
2952         return FALSE;
2953     }
2954     info = (struct InterfaceInfo *)DeviceInterfaceData->Reserved;
2955     if (info->symbolicLink)
2956         bytesNeeded += WideCharToMultiByte(CP_ACP, 0, info->symbolicLink, -1,
2957                 NULL, 0, NULL, NULL);
2958     if (DeviceInterfaceDetailDataSize >= bytesNeeded)
2959     {
2960         if (info->symbolicLink)
2961             WideCharToMultiByte(CP_ACP, 0, info->symbolicLink, -1,
2962                     DeviceInterfaceDetailData->DevicePath,
2963                     DeviceInterfaceDetailDataSize -
2964                     offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath),
2965                     NULL, NULL);
2966         else
2967             DeviceInterfaceDetailData->DevicePath[0] = '\0';
2968         if (DeviceInfoData && DeviceInfoData->cbSize == sizeof(SP_DEVINFO_DATA))
2969             *DeviceInfoData = *info->device;
2970         ret = TRUE;
2971     }
2972     else
2973     {
2974         if (RequiredSize)
2975             *RequiredSize = bytesNeeded;
2976         SetLastError(ERROR_INSUFFICIENT_BUFFER);
2977     }
2978     return ret;
2979 }
2980
2981 /***********************************************************************
2982  *              SetupDiGetDeviceInterfaceDetailW (SETUPAPI.@)
2983  */
2984 BOOL WINAPI SetupDiGetDeviceInterfaceDetailW(
2985       HDEVINFO DeviceInfoSet,
2986       PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
2987       PSP_DEVICE_INTERFACE_DETAIL_DATA_W DeviceInterfaceDetailData,
2988       DWORD DeviceInterfaceDetailDataSize,
2989       PDWORD RequiredSize,
2990       PSP_DEVINFO_DATA DeviceInfoData)
2991 {
2992     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2993     struct InterfaceInfo *info;
2994     DWORD bytesNeeded = offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath)
2995         + sizeof(WCHAR); /* include NULL terminator */
2996     BOOL ret = FALSE;
2997
2998     TRACE("(%p, %p, %p, %d, %p, %p)\n", DeviceInfoSet,
2999      DeviceInterfaceData, DeviceInterfaceDetailData,
3000      DeviceInterfaceDetailDataSize, RequiredSize, DeviceInfoData);
3001
3002     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE ||
3003             set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
3004     {
3005         SetLastError(ERROR_INVALID_HANDLE);
3006         return FALSE;
3007     }
3008     if (!DeviceInterfaceData ||
3009             DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA) ||
3010             !DeviceInterfaceData->Reserved)
3011     {
3012         SetLastError(ERROR_INVALID_PARAMETER);
3013         return FALSE;
3014     }
3015     if (DeviceInterfaceDetailData && (DeviceInterfaceDetailData->cbSize <
3016             offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath) + sizeof(WCHAR) ||
3017             DeviceInterfaceDetailData->cbSize > sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W)))
3018     {
3019         SetLastError(ERROR_INVALID_USER_BUFFER);
3020         return FALSE;
3021     }
3022     if (!DeviceInterfaceDetailData && DeviceInterfaceDetailDataSize)
3023     {
3024         SetLastError(ERROR_INVALID_USER_BUFFER);
3025         return FALSE;
3026     }
3027     info = (struct InterfaceInfo *)DeviceInterfaceData->Reserved;
3028     if (info->symbolicLink)
3029         bytesNeeded += sizeof(WCHAR)*lstrlenW(info->symbolicLink);
3030     if (DeviceInterfaceDetailDataSize >= bytesNeeded)
3031     {
3032         if (info->symbolicLink)
3033             lstrcpyW(DeviceInterfaceDetailData->DevicePath, info->symbolicLink);
3034         else
3035             DeviceInterfaceDetailData->DevicePath[0] = '\0';
3036         if (DeviceInfoData && DeviceInfoData->cbSize == sizeof(SP_DEVINFO_DATA))
3037             *DeviceInfoData = *info->device;
3038         ret = TRUE;
3039     }
3040     else
3041     {
3042         if (RequiredSize)
3043             *RequiredSize = bytesNeeded;
3044         SetLastError(ERROR_INSUFFICIENT_BUFFER);
3045     }
3046     return ret;
3047 }
3048
3049 struct PropertyMapEntry
3050 {
3051     DWORD   regType;
3052     LPCSTR  nameA;
3053     LPCWSTR nameW;
3054 };
3055
3056 static const struct PropertyMapEntry PropertyMap[] = {
3057     { REG_SZ, "DeviceDesc", DeviceDesc },
3058     { REG_MULTI_SZ, "HardwareId", HardwareId },
3059     { REG_MULTI_SZ, "CompatibleIDs", CompatibleIDs },
3060     { 0, NULL, NULL }, /* SPDRP_UNUSED0 */
3061     { REG_SZ, "Service", Service },
3062     { 0, NULL, NULL }, /* SPDRP_UNUSED1 */
3063     { 0, NULL, NULL }, /* SPDRP_UNUSED2 */
3064     { REG_SZ, "Class", Class },
3065     { REG_SZ, "ClassGUID", ClassGUID },
3066     { REG_SZ, "Driver", Driver },
3067     { REG_DWORD, "ConfigFlags", ConfigFlags },
3068     { REG_SZ, "Mfg", Mfg },
3069     { REG_SZ, "FriendlyName", FriendlyName },
3070     { REG_SZ, "LocationInformation", LocationInformation },
3071     { 0, NULL, NULL }, /* SPDRP_PHYSICAL_DEVICE_OBJECT_NAME */
3072     { REG_DWORD, "Capabilities", Capabilities },
3073     { REG_DWORD, "UINumber", UINumber },
3074     { REG_MULTI_SZ, "UpperFilters", UpperFilters },
3075     { REG_MULTI_SZ, "LowerFilters", LowerFilters },
3076 };
3077
3078 /***********************************************************************
3079  *              SetupDiGetDeviceRegistryPropertyA (SETUPAPI.@)
3080  */
3081 BOOL WINAPI SetupDiGetDeviceRegistryPropertyA(
3082         HDEVINFO  DeviceInfoSet,
3083         PSP_DEVINFO_DATA  DeviceInfoData,
3084         DWORD   Property,
3085         PDWORD  PropertyRegDataType,
3086         PBYTE   PropertyBuffer,
3087         DWORD   PropertyBufferSize,
3088         PDWORD  RequiredSize)
3089 {
3090     BOOL ret = FALSE;
3091     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
3092     struct DeviceInfo *devInfo;
3093
3094     TRACE("%04x %p %d %p %p %d %p\n", (DWORD)DeviceInfoSet, DeviceInfoData,
3095         Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize,
3096         RequiredSize);
3097
3098     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
3099     {
3100         SetLastError(ERROR_INVALID_HANDLE);
3101         return FALSE;
3102     }
3103     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
3104     {
3105         SetLastError(ERROR_INVALID_HANDLE);
3106         return FALSE;
3107     }
3108     if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
3109             || !DeviceInfoData->Reserved)
3110     {
3111         SetLastError(ERROR_INVALID_PARAMETER);
3112         return FALSE;
3113     }
3114     if (PropertyBufferSize && PropertyBuffer == NULL)
3115     {
3116         SetLastError(ERROR_INVALID_DATA);
3117         return FALSE;
3118     }
3119     devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
3120     if (Property < sizeof(PropertyMap) / sizeof(PropertyMap[0])
3121         && PropertyMap[Property].nameA)
3122     {
3123         DWORD size = PropertyBufferSize;
3124         LONG l = RegQueryValueExA(devInfo->key, PropertyMap[Property].nameA,
3125                 NULL, PropertyRegDataType, PropertyBuffer, &size);
3126
3127         if (l == ERROR_MORE_DATA || !PropertyBufferSize)
3128             SetLastError(ERROR_INSUFFICIENT_BUFFER);
3129         else if (!l)
3130             ret = TRUE;
3131         else
3132             SetLastError(l);
3133         if (RequiredSize)
3134             *RequiredSize = size;
3135     }
3136     return ret;
3137 }
3138
3139 /***********************************************************************
3140  *              SetupDiGetDeviceRegistryPropertyW (SETUPAPI.@)
3141  */
3142 BOOL WINAPI SetupDiGetDeviceRegistryPropertyW(
3143         HDEVINFO  DeviceInfoSet,
3144         PSP_DEVINFO_DATA  DeviceInfoData,
3145         DWORD   Property,
3146         PDWORD  PropertyRegDataType,
3147         PBYTE   PropertyBuffer,
3148         DWORD   PropertyBufferSize,
3149         PDWORD  RequiredSize)
3150 {
3151     BOOL ret = FALSE;
3152     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
3153     struct DeviceInfo *devInfo;
3154
3155     TRACE("%04x %p %d %p %p %d %p\n", (DWORD)DeviceInfoSet, DeviceInfoData,
3156         Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize,
3157         RequiredSize);
3158
3159     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
3160     {
3161         SetLastError(ERROR_INVALID_HANDLE);
3162         return FALSE;
3163     }
3164     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
3165     {
3166         SetLastError(ERROR_INVALID_HANDLE);
3167         return FALSE;
3168     }
3169     if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
3170             || !DeviceInfoData->Reserved)
3171     {
3172         SetLastError(ERROR_INVALID_PARAMETER);
3173         return FALSE;
3174     }
3175     if (PropertyBufferSize && PropertyBuffer == NULL)
3176     {
3177         SetLastError(ERROR_INVALID_DATA);
3178         return FALSE;
3179     }
3180     devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
3181     if (Property < sizeof(PropertyMap) / sizeof(PropertyMap[0])
3182         && PropertyMap[Property].nameW)
3183     {
3184         DWORD size = PropertyBufferSize;
3185         LONG l = RegQueryValueExW(devInfo->key, PropertyMap[Property].nameW,
3186                 NULL, PropertyRegDataType, PropertyBuffer, &size);
3187
3188         if (l == ERROR_MORE_DATA || !PropertyBufferSize)
3189             SetLastError(ERROR_INSUFFICIENT_BUFFER);
3190         else if (!l)
3191             ret = TRUE;
3192         else
3193             SetLastError(l);
3194         if (RequiredSize)
3195             *RequiredSize = size;
3196     }
3197     return ret;
3198 }
3199
3200 /***********************************************************************
3201  *              SetupDiSetDeviceRegistryPropertyA (SETUPAPI.@)
3202  */
3203 BOOL WINAPI SetupDiSetDeviceRegistryPropertyA(
3204         HDEVINFO DeviceInfoSet,
3205         PSP_DEVINFO_DATA DeviceInfoData,
3206         DWORD Property,
3207         const BYTE *PropertyBuffer,
3208         DWORD PropertyBufferSize)
3209 {
3210     BOOL ret = FALSE;
3211     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
3212     struct DeviceInfo *devInfo;
3213
3214     TRACE("%p %p %d %p %d\n", DeviceInfoSet, DeviceInfoData, Property,
3215         PropertyBuffer, PropertyBufferSize);
3216
3217     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
3218     {
3219         SetLastError(ERROR_INVALID_HANDLE);
3220         return FALSE;
3221     }
3222     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
3223     {
3224         SetLastError(ERROR_INVALID_HANDLE);
3225         return FALSE;
3226     }
3227     if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
3228             || !DeviceInfoData->Reserved)
3229     {
3230         SetLastError(ERROR_INVALID_PARAMETER);
3231         return FALSE;
3232     }
3233     devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
3234     if (Property < sizeof(PropertyMap) / sizeof(PropertyMap[0])
3235         && PropertyMap[Property].nameA)
3236     {
3237         LONG l = RegSetValueExA(devInfo->key, PropertyMap[Property].nameA, 0,
3238                 PropertyMap[Property].regType, PropertyBuffer,
3239                 PropertyBufferSize);
3240         if (!l)
3241             ret = TRUE;
3242         else
3243             SetLastError(l);
3244     }
3245     return ret;
3246 }
3247
3248 /***********************************************************************
3249  *              SetupDiSetDeviceRegistryPropertyW (SETUPAPI.@)
3250  */
3251 BOOL WINAPI SetupDiSetDeviceRegistryPropertyW(
3252         HDEVINFO DeviceInfoSet,
3253         PSP_DEVINFO_DATA DeviceInfoData,
3254         DWORD Property,
3255         const BYTE *PropertyBuffer,
3256         DWORD PropertyBufferSize)
3257 {
3258     BOOL ret = FALSE;
3259     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
3260     struct DeviceInfo *devInfo;
3261
3262     TRACE("%p %p %d %p %d\n", DeviceInfoSet, DeviceInfoData, Property,
3263         PropertyBuffer, PropertyBufferSize);
3264
3265     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
3266     {
3267         SetLastError(ERROR_INVALID_HANDLE);
3268         return FALSE;
3269     }
3270     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
3271     {
3272         SetLastError(ERROR_INVALID_HANDLE);
3273         return FALSE;
3274     }
3275     if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
3276             || !DeviceInfoData->Reserved)
3277     {
3278         SetLastError(ERROR_INVALID_PARAMETER);
3279         return FALSE;
3280     }
3281     devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
3282     if (Property < sizeof(PropertyMap) / sizeof(PropertyMap[0])
3283         && PropertyMap[Property].nameW)
3284     {
3285         LONG l = RegSetValueExW(devInfo->key, PropertyMap[Property].nameW, 0,
3286                 PropertyMap[Property].regType, PropertyBuffer,
3287                 PropertyBufferSize);
3288         if (!l)
3289             ret = TRUE;
3290         else
3291             SetLastError(l);
3292     }
3293     return ret;
3294 }
3295
3296 /***********************************************************************
3297  *              SetupDiInstallClassA (SETUPAPI.@)
3298  */
3299 BOOL WINAPI SetupDiInstallClassA(
3300         HWND hwndParent,
3301         PCSTR InfFileName,
3302         DWORD Flags,
3303         HSPFILEQ FileQueue)
3304 {
3305     UNICODE_STRING FileNameW;
3306     BOOL Result;
3307
3308     if (!InfFileName)
3309     {
3310         SetLastError(ERROR_INVALID_PARAMETER);
3311         return FALSE;
3312     }
3313     if (!RtlCreateUnicodeStringFromAsciiz(&FileNameW, InfFileName))
3314     {
3315         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3316         return FALSE;
3317     }
3318
3319     Result = SetupDiInstallClassW(hwndParent, FileNameW.Buffer, Flags, FileQueue);
3320
3321     RtlFreeUnicodeString(&FileNameW);
3322
3323     return Result;
3324 }
3325
3326 static HKEY CreateClassKey(HINF hInf)
3327 {
3328     static const WCHAR slash[] = { '\\',0 };
3329     WCHAR FullBuffer[MAX_PATH];
3330     WCHAR Buffer[MAX_PATH];
3331     DWORD RequiredSize;
3332     HKEY hClassKey;
3333
3334     if (!SetupGetLineTextW(NULL,
3335                            hInf,
3336                            Version,
3337                            ClassGUID,
3338                            Buffer,
3339                            MAX_PATH,
3340                            &RequiredSize))
3341     {
3342         return INVALID_HANDLE_VALUE;
3343     }
3344
3345     lstrcpyW(FullBuffer, ControlClass);
3346     lstrcatW(FullBuffer, slash);
3347     lstrcatW(FullBuffer, Buffer);
3348
3349     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
3350                       FullBuffer,
3351                       0,
3352                       KEY_ALL_ACCESS,
3353                       &hClassKey))
3354     {
3355         if (!SetupGetLineTextW(NULL,
3356                                hInf,
3357                                Version,
3358                                Class,
3359                                Buffer,
3360                                MAX_PATH,
3361                                &RequiredSize))
3362         {
3363             return INVALID_HANDLE_VALUE;
3364         }
3365
3366         if (RegCreateKeyExW(HKEY_LOCAL_MACHINE,
3367                             FullBuffer,
3368                             0,
3369                             NULL,
3370                             REG_OPTION_NON_VOLATILE,
3371                             KEY_ALL_ACCESS,
3372                             NULL,
3373                             &hClassKey,
3374                             NULL))
3375         {
3376             return INVALID_HANDLE_VALUE;
3377         }
3378
3379     }
3380
3381     if (RegSetValueExW(hClassKey,
3382                        Class,
3383                        0,
3384                        REG_SZ,
3385                        (LPBYTE)Buffer,
3386                        RequiredSize * sizeof(WCHAR)))
3387     {
3388         RegCloseKey(hClassKey);
3389         RegDeleteKeyW(HKEY_LOCAL_MACHINE,
3390                       FullBuffer);
3391         return INVALID_HANDLE_VALUE;
3392     }
3393
3394     return hClassKey;
3395 }
3396
3397 /***********************************************************************
3398  *              SetupDiInstallClassW (SETUPAPI.@)
3399  */
3400 BOOL WINAPI SetupDiInstallClassW(
3401         HWND hwndParent,
3402         PCWSTR InfFileName,
3403         DWORD Flags,
3404         HSPFILEQ FileQueue)
3405 {
3406     WCHAR SectionName[MAX_PATH];
3407     DWORD SectionNameLength = 0;
3408     HINF hInf;
3409     BOOL bFileQueueCreated = FALSE;
3410     HKEY hClassKey;
3411
3412
3413     FIXME("\n");
3414
3415     if (!InfFileName)
3416     {
3417         SetLastError(ERROR_INVALID_PARAMETER);
3418         return FALSE;
3419     }
3420     if ((Flags & DI_NOVCP) && (FileQueue == NULL || FileQueue == INVALID_HANDLE_VALUE))
3421     {
3422         SetLastError(ERROR_INVALID_PARAMETER);
3423         return FALSE;
3424     }
3425
3426     /* Open the .inf file */
3427     hInf = SetupOpenInfFileW(InfFileName,
3428                              NULL,
3429                              INF_STYLE_WIN4,
3430                              NULL);
3431     if (hInf == INVALID_HANDLE_VALUE)
3432     {
3433
3434         return FALSE;
3435     }
3436
3437     /* Create or open the class registry key 'HKLM\\CurrentControlSet\\Class\\{GUID}' */
3438     hClassKey = CreateClassKey(hInf);
3439     if (hClassKey == INVALID_HANDLE_VALUE)
3440     {
3441         SetupCloseInfFile(hInf);
3442         return FALSE;
3443     }
3444
3445
3446     /* Try to append a layout file */
3447     SetupOpenAppendInfFileW(NULL, hInf, NULL);
3448
3449     /* Retrieve the actual section name */
3450     SetupDiGetActualSectionToInstallW(hInf,
3451                                       ClassInstall32,
3452                                       SectionName,
3453                                       MAX_PATH,
3454                                       &SectionNameLength,
3455                                       NULL);
3456
3457 #if 0
3458     if (!(Flags & DI_NOVCP))
3459     {
3460         FileQueue = SetupOpenFileQueue();
3461         if (FileQueue == INVALID_HANDLE_VALUE)
3462         {
3463             SetupCloseInfFile(hInf);
3464             return FALSE;
3465         }
3466
3467         bFileQueueCreated = TRUE;
3468
3469     }
3470 #endif
3471
3472     SetupInstallFromInfSectionW(NULL,
3473                                 hInf,
3474                                 SectionName,
3475                                 SPINST_COPYINF | SPINST_FILES | SPINST_REGISTRY,
3476                                 hClassKey,
3477                                 NULL,
3478                                 0,
3479                                 NULL,
3480                                 NULL,
3481                                 INVALID_HANDLE_VALUE,
3482                                 NULL);
3483
3484     /* FIXME: More code! */
3485
3486     if (bFileQueueCreated)
3487         SetupCloseFileQueue(FileQueue);
3488
3489     SetupCloseInfFile(hInf);
3490
3491     return TRUE;
3492 }
3493
3494
3495 /***********************************************************************
3496  *              SetupDiOpenClassRegKey  (SETUPAPI.@)
3497  */
3498 HKEY WINAPI SetupDiOpenClassRegKey(
3499         const GUID* ClassGuid,
3500         REGSAM samDesired)
3501 {
3502     return SetupDiOpenClassRegKeyExW(ClassGuid, samDesired,
3503                                      DIOCR_INSTALLER, NULL, NULL);
3504 }
3505
3506
3507 /***********************************************************************
3508  *              SetupDiOpenClassRegKeyExA  (SETUPAPI.@)
3509  */
3510 HKEY WINAPI SetupDiOpenClassRegKeyExA(
3511         const GUID* ClassGuid,
3512         REGSAM samDesired,
3513         DWORD Flags,
3514         PCSTR MachineName,
3515         PVOID Reserved)
3516 {
3517     PWSTR MachineNameW = NULL;
3518     HKEY hKey;
3519
3520     TRACE("\n");
3521
3522     if (MachineName)
3523     {
3524         MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
3525         if (MachineNameW == NULL)
3526             return INVALID_HANDLE_VALUE;
3527     }
3528
3529     hKey = SetupDiOpenClassRegKeyExW(ClassGuid, samDesired,
3530                                      Flags, MachineNameW, Reserved);
3531
3532     MyFree(MachineNameW);
3533
3534     return hKey;
3535 }
3536
3537
3538 /***********************************************************************
3539  *              SetupDiOpenClassRegKeyExW  (SETUPAPI.@)
3540  */
3541 HKEY WINAPI SetupDiOpenClassRegKeyExW(
3542         const GUID* ClassGuid,
3543         REGSAM samDesired,
3544         DWORD Flags,
3545         PCWSTR MachineName,
3546         PVOID Reserved)
3547 {
3548     HKEY hClassesKey;
3549     HKEY key;
3550     LPCWSTR lpKeyName;
3551     LONG l;
3552
3553     if (MachineName != NULL)
3554     {
3555         FIXME("Remote access not supported yet!\n");
3556         return INVALID_HANDLE_VALUE;
3557     }
3558
3559     if (Flags == DIOCR_INSTALLER)
3560     {
3561         lpKeyName = ControlClass;
3562     }
3563     else if (Flags == DIOCR_INTERFACE)
3564     {
3565         lpKeyName = DeviceClasses;
3566     }
3567     else
3568     {
3569         ERR("Invalid Flags parameter!\n");
3570         SetLastError(ERROR_INVALID_PARAMETER);
3571         return INVALID_HANDLE_VALUE;
3572     }
3573
3574     if (!ClassGuid)
3575     {
3576         if ((l = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
3577                           lpKeyName,
3578                           0,
3579                           samDesired,
3580                           &hClassesKey)))
3581         {
3582             SetLastError(l);
3583             hClassesKey = INVALID_HANDLE_VALUE;
3584         }
3585         key = hClassesKey;
3586     }
3587     else
3588     {
3589         WCHAR bracedGuidString[39];
3590
3591         SETUPDI_GuidToString(ClassGuid, bracedGuidString);
3592
3593         if (!(l = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
3594                           lpKeyName,
3595                           0,
3596                           samDesired,
3597                           &hClassesKey)))
3598         {
3599             if ((l = RegOpenKeyExW(hClassesKey,
3600                               bracedGuidString,
3601                               0,
3602                               samDesired,
3603                               &key)))
3604             {
3605                 SetLastError(l);
3606                 key = INVALID_HANDLE_VALUE;
3607             }
3608             RegCloseKey(hClassesKey);
3609         }
3610         else
3611         {
3612             SetLastError(l);
3613             key = INVALID_HANDLE_VALUE;
3614         }
3615     }
3616     return key;
3617 }
3618
3619 /***********************************************************************
3620  *              SetupDiOpenDeviceInterfaceW (SETUPAPI.@)
3621  */
3622 BOOL WINAPI SetupDiOpenDeviceInterfaceW(
3623        HDEVINFO DeviceInfoSet,
3624        PCWSTR DevicePath,
3625        DWORD OpenFlags,
3626        PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
3627 {
3628     FIXME("%p %s %08x %p\n",
3629         DeviceInfoSet, debugstr_w(DevicePath), OpenFlags, DeviceInterfaceData);
3630     return FALSE;
3631 }
3632
3633 /***********************************************************************
3634  *              SetupDiOpenDeviceInterfaceA (SETUPAPI.@)
3635  */
3636 BOOL WINAPI SetupDiOpenDeviceInterfaceA(
3637        HDEVINFO DeviceInfoSet,
3638        PCSTR DevicePath,
3639        DWORD OpenFlags,
3640        PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
3641 {
3642     FIXME("%p %s %08x %p\n", DeviceInfoSet,
3643         debugstr_a(DevicePath), OpenFlags, DeviceInterfaceData);
3644     return FALSE;
3645 }
3646
3647 /***********************************************************************
3648  *              SetupDiSetClassInstallParamsA (SETUPAPI.@)
3649  */
3650 BOOL WINAPI SetupDiSetClassInstallParamsA(
3651        HDEVINFO  DeviceInfoSet,
3652        PSP_DEVINFO_DATA DeviceInfoData,
3653        PSP_CLASSINSTALL_HEADER ClassInstallParams,
3654        DWORD ClassInstallParamsSize)
3655 {
3656     FIXME("%p %p %x %u\n",DeviceInfoSet, DeviceInfoData,
3657           ClassInstallParams->InstallFunction, ClassInstallParamsSize);
3658     return FALSE;
3659 }
3660
3661 /***********************************************************************
3662  *              SetupDiCallClassInstaller (SETUPAPI.@)
3663  */
3664 BOOL WINAPI SetupDiCallClassInstaller(
3665        DI_FUNCTION InstallFunction,
3666        HDEVINFO DeviceInfoSet,
3667        PSP_DEVINFO_DATA DeviceInfoData)
3668 {
3669     FIXME("%d %p %p\n", InstallFunction, DeviceInfoSet, DeviceInfoData);
3670     return FALSE;
3671 }
3672
3673 /***********************************************************************
3674  *              SetupDiGetDeviceInstallParamsA (SETUPAPI.@)
3675  */
3676 BOOL WINAPI SetupDiGetDeviceInstallParamsA(
3677        HDEVINFO DeviceInfoSet,
3678        PSP_DEVINFO_DATA DeviceInfoData,
3679        PSP_DEVINSTALL_PARAMS_A DeviceInstallParams)
3680 {
3681     FIXME("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstallParams);
3682     return FALSE;
3683 }
3684
3685 static HKEY SETUPDI_OpenDevKey(struct DeviceInfo *devInfo, REGSAM samDesired)
3686 {
3687     HKEY enumKey, key = INVALID_HANDLE_VALUE;
3688     LONG l;
3689
3690     l = RegCreateKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, NULL, 0, KEY_ALL_ACCESS,
3691             NULL, &enumKey, NULL);
3692     if (!l)
3693     {
3694         RegOpenKeyExW(enumKey, devInfo->instanceId, 0, samDesired, &key);
3695         RegCloseKey(enumKey);
3696     }
3697     return key;
3698 }
3699
3700 static HKEY SETUPDI_OpenDrvKey(struct DeviceInfo *devInfo, REGSAM samDesired)
3701 {
3702     static const WCHAR slash[] = { '\\',0 };
3703     WCHAR classKeyPath[MAX_PATH];
3704     HKEY classKey, key = INVALID_HANDLE_VALUE;
3705     LONG l;
3706
3707     lstrcpyW(classKeyPath, ControlClass);
3708     lstrcatW(classKeyPath, slash);
3709     SETUPDI_GuidToString(&devInfo->set->ClassGuid,
3710             classKeyPath + lstrlenW(classKeyPath));
3711     l = RegCreateKeyExW(HKEY_LOCAL_MACHINE, classKeyPath, 0, NULL, 0,
3712             KEY_ALL_ACCESS, NULL, &classKey, NULL);
3713     if (!l)
3714     {
3715         static const WCHAR fmt[] = { '%','0','4','u',0 };
3716         WCHAR devId[10];
3717
3718         sprintfW(devId, fmt, devInfo->devId);
3719         RegOpenKeyExW(classKey, devId, 0, samDesired, &key);
3720         RegCloseKey(classKey);
3721     }
3722     return key;
3723 }
3724
3725 /***********************************************************************
3726  *              SetupDiOpenDevRegKey (SETUPAPI.@)
3727  */
3728 HKEY WINAPI SetupDiOpenDevRegKey(
3729        HDEVINFO DeviceInfoSet,
3730        PSP_DEVINFO_DATA DeviceInfoData,
3731        DWORD Scope,
3732        DWORD HwProfile,
3733        DWORD KeyType,
3734        REGSAM samDesired)
3735 {
3736     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
3737     struct DeviceInfo *devInfo;
3738     HKEY key = INVALID_HANDLE_VALUE;
3739
3740     TRACE("%p %p %d %d %d %x\n", DeviceInfoSet, DeviceInfoData,
3741           Scope, HwProfile, KeyType, samDesired);
3742
3743     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
3744     {
3745         SetLastError(ERROR_INVALID_HANDLE);
3746         return INVALID_HANDLE_VALUE;
3747     }
3748     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
3749     {
3750         SetLastError(ERROR_INVALID_HANDLE);
3751         return INVALID_HANDLE_VALUE;
3752     }
3753     if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
3754             || !DeviceInfoData->Reserved)
3755     {
3756         SetLastError(ERROR_INVALID_PARAMETER);
3757         return INVALID_HANDLE_VALUE;
3758     }
3759     if (Scope != DICS_FLAG_GLOBAL && Scope != DICS_FLAG_CONFIGSPECIFIC)
3760     {
3761         SetLastError(ERROR_INVALID_FLAGS);
3762         return INVALID_HANDLE_VALUE;
3763     }
3764     if (KeyType != DIREG_DEV && KeyType != DIREG_DRV)
3765     {
3766         SetLastError(ERROR_INVALID_FLAGS);
3767         return INVALID_HANDLE_VALUE;
3768     }
3769     devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
3770     if (devInfo->set != set)
3771     {
3772         SetLastError(ERROR_INVALID_PARAMETER);
3773         return INVALID_HANDLE_VALUE;
3774     }
3775     if (devInfo->phantom)
3776     {
3777         SetLastError(ERROR_DEVINFO_NOT_REGISTERED);
3778         return INVALID_HANDLE_VALUE;
3779     }
3780     if (Scope != DICS_FLAG_GLOBAL)
3781         FIXME("unimplemented for scope %d\n", Scope);
3782     switch (KeyType)
3783     {
3784         case DIREG_DEV:
3785             key = SETUPDI_OpenDevKey(devInfo, samDesired);
3786             break;
3787         case DIREG_DRV:
3788             key = SETUPDI_OpenDrvKey(devInfo, samDesired);
3789             break;
3790         default:
3791             WARN("unknown KeyType %d\n", KeyType);
3792     }
3793     return key;
3794 }
3795
3796 static BOOL SETUPDI_DeleteDevKey(struct DeviceInfo *devInfo)
3797 {
3798     HKEY enumKey;
3799     BOOL ret = FALSE;
3800     LONG l;
3801
3802     l = RegCreateKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, NULL, 0, KEY_ALL_ACCESS,
3803             NULL, &enumKey, NULL);
3804     if (!l)
3805     {
3806         ret = RegDeleteTreeW(enumKey, devInfo->instanceId);
3807         RegCloseKey(enumKey);
3808     }
3809     else
3810         SetLastError(l);
3811     return ret;
3812 }
3813
3814 static BOOL SETUPDI_DeleteDrvKey(struct DeviceInfo *devInfo)
3815 {
3816     static const WCHAR slash[] = { '\\',0 };
3817     WCHAR classKeyPath[MAX_PATH];
3818     HKEY classKey;
3819     LONG l;
3820     BOOL ret = FALSE;
3821
3822     lstrcpyW(classKeyPath, ControlClass);
3823     lstrcatW(classKeyPath, slash);
3824     SETUPDI_GuidToString(&devInfo->set->ClassGuid,
3825             classKeyPath + lstrlenW(classKeyPath));
3826     l = RegCreateKeyExW(HKEY_LOCAL_MACHINE, classKeyPath, 0, NULL, 0,
3827             KEY_ALL_ACCESS, NULL, &classKey, NULL);
3828     if (!l)
3829     {
3830         static const WCHAR fmt[] = { '%','0','4','u',0 };
3831         WCHAR devId[10];
3832
3833         sprintfW(devId, fmt, devInfo->devId);
3834         ret = RegDeleteTreeW(classKey, devId);
3835         RegCloseKey(classKey);
3836     }
3837     else
3838         SetLastError(l);
3839     return ret;
3840 }
3841
3842 /***********************************************************************
3843  *              SetupDiOpenDevRegKey (SETUPAPI.@)
3844  */
3845 BOOL WINAPI SetupDiDeleteDevRegKey(
3846        HDEVINFO DeviceInfoSet,
3847        PSP_DEVINFO_DATA DeviceInfoData,
3848        DWORD Scope,
3849        DWORD HwProfile,
3850        DWORD KeyType)
3851 {
3852     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
3853     struct DeviceInfo *devInfo;
3854     BOOL ret = FALSE;
3855
3856     TRACE("%p %p %d %d %d\n", DeviceInfoSet, DeviceInfoData, Scope, HwProfile,
3857             KeyType);
3858
3859     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
3860     {
3861         SetLastError(ERROR_INVALID_HANDLE);
3862         return FALSE;
3863     }
3864     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
3865     {
3866         SetLastError(ERROR_INVALID_HANDLE);
3867         return FALSE;
3868     }
3869     if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
3870             || !DeviceInfoData->Reserved)
3871     {
3872         SetLastError(ERROR_INVALID_PARAMETER);
3873         return FALSE;
3874     }
3875     if (Scope != DICS_FLAG_GLOBAL && Scope != DICS_FLAG_CONFIGSPECIFIC)
3876     {
3877         SetLastError(ERROR_INVALID_FLAGS);
3878         return FALSE;
3879     }
3880     if (KeyType != DIREG_DEV && KeyType != DIREG_DRV && KeyType != DIREG_BOTH)
3881     {
3882         SetLastError(ERROR_INVALID_FLAGS);
3883         return FALSE;
3884     }
3885     devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
3886     if (devInfo->set != set)
3887     {
3888         SetLastError(ERROR_INVALID_PARAMETER);
3889         return FALSE;
3890     }
3891     if (devInfo->phantom)
3892     {
3893         SetLastError(ERROR_DEVINFO_NOT_REGISTERED);
3894         return FALSE;
3895     }
3896     if (Scope != DICS_FLAG_GLOBAL)
3897         FIXME("unimplemented for scope %d\n", Scope);
3898     switch (KeyType)
3899     {
3900         case DIREG_DEV:
3901             ret = SETUPDI_DeleteDevKey(devInfo);
3902             break;
3903         case DIREG_DRV:
3904             ret = SETUPDI_DeleteDrvKey(devInfo);
3905             break;
3906         case DIREG_BOTH:
3907             ret = SETUPDI_DeleteDevKey(devInfo);
3908             if (ret)
3909                 ret = SETUPDI_DeleteDrvKey(devInfo);
3910             break;
3911         default:
3912             WARN("unknown KeyType %d\n", KeyType);
3913     }
3914     return ret;
3915 }
3916
3917 /***********************************************************************
3918  *              CM_Get_Device_IDA  (SETUPAPI.@)
3919  */
3920 CONFIGRET WINAPI CM_Get_Device_IDA( DEVINST dnDevInst, PSTR Buffer,
3921                                    ULONG  BufferLen, ULONG  ulFlags)
3922 {
3923     struct DeviceInfo *devInfo = GlobalLock((HANDLE)dnDevInst);
3924
3925     TRACE("%x->%p, %p, %u %u\n", dnDevInst, devInfo, Buffer, BufferLen, ulFlags);
3926
3927     if (!devInfo)
3928         return CR_NO_SUCH_DEVINST;
3929
3930     WideCharToMultiByte(CP_ACP, 0, devInfo->instanceId, -1, Buffer, BufferLen, 0, 0);
3931     TRACE("Returning %s\n", debugstr_a(Buffer));
3932     return CR_SUCCESS;
3933 }
3934
3935 /***********************************************************************
3936  *              CM_Get_Device_IDW  (SETUPAPI.@)
3937  */
3938 CONFIGRET WINAPI CM_Get_Device_IDW( DEVINST dnDevInst, LPWSTR Buffer,
3939                                    ULONG  BufferLen, ULONG  ulFlags)
3940 {
3941     struct DeviceInfo *devInfo = GlobalLock((HANDLE)dnDevInst);
3942
3943     TRACE("%x->%p, %p, %u %u\n", dnDevInst, devInfo, Buffer, BufferLen, ulFlags);
3944
3945     if (!devInfo)
3946     {
3947         WARN("dev instance %d not found!\n", dnDevInst);
3948         return CR_NO_SUCH_DEVINST;
3949     }
3950
3951     lstrcpynW(Buffer, devInfo->instanceId, BufferLen);
3952     TRACE("Returning %s\n", debugstr_w(Buffer));
3953     GlobalUnlock((HANDLE)dnDevInst);
3954     return CR_SUCCESS;
3955 }
3956
3957
3958
3959 /***********************************************************************
3960  *              CM_Get_Device_ID_Size  (SETUPAPI.@)
3961  */
3962 CONFIGRET WINAPI CM_Get_Device_ID_Size( PULONG  pulLen, DEVINST dnDevInst,
3963                                         ULONG  ulFlags)
3964 {
3965     struct DeviceInfo *ppdevInfo = GlobalLock((HANDLE)dnDevInst);
3966
3967     TRACE("%x->%p, %p, %u\n", dnDevInst, ppdevInfo, pulLen, ulFlags);
3968
3969     if (!ppdevInfo)
3970     {
3971         WARN("dev instance %d not found!\n", dnDevInst);
3972         return CR_NO_SUCH_DEVINST;
3973     }
3974
3975     *pulLen = lstrlenW(ppdevInfo->instanceId);
3976     GlobalUnlock((HANDLE)dnDevInst);
3977     return CR_SUCCESS;
3978 }