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