setupapi: Implement SetupDiGetDeviceInterfaceDetailA/W.
[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/unicode.h"
37 #include "cfgmgr32.h"
38 #include "initguid.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 ClassGUID[]  = {'C','l','a','s','s','G','U','I','D',0};
50 static const WCHAR Class[]  = {'C','l','a','s','s',0};
51 static const WCHAR ClassInstall32[]  = {'C','l','a','s','s','I','n','s','t','a','l','l','3','2',0};
52 static const WCHAR NoDisplayClass[]  = {'N','o','D','i','s','p','l','a','y','C','l','a','s','s',0};
53 static const WCHAR NoInstallClass[]  = {'N','o','I','n','s','t','a','l','l','C','l','a','s','s',0};
54 static const WCHAR NoUseClass[]  = {'N','o','U','s','e','C','l','a','s','s',0};
55 static const WCHAR NtExtension[]  = {'.','N','T',0};
56 static const WCHAR NtPlatformExtension[]  = {'.','N','T','x','8','6',0};
57 static const WCHAR Version[]  = {'V','e','r','s','i','o','n',0};
58 static const WCHAR WinExtension[]  = {'.','W','i','n',0};
59
60 /* Registry key and value names */
61 static const WCHAR ControlClass[] = {'S','y','s','t','e','m','\\',
62                                   'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
63                                   'C','o','n','t','r','o','l','\\',
64                                   'C','l','a','s','s',0};
65
66 static const WCHAR DeviceClasses[] = {'S','y','s','t','e','m','\\',
67                                   'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
68                                   'C','o','n','t','r','o','l','\\',
69                                   'D','e','v','i','c','e','C','l','a','s','s','e','s',0};
70 static const WCHAR Enum[] = {'S','y','s','t','e','m','\\',
71                                   'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
72                                   'E','n','u','m',0};
73 static const WCHAR DeviceDesc[] = {'D','e','v','i','c','e','D','e','s','c',0};
74 static const WCHAR DeviceInstance[] = {'D','e','v','i','c','e','I','n','s','t','a','n','c','e',0};
75 static const WCHAR HardwareId[] = {'H','a','r','d','w','a','r','e','I','D',0};
76 static const WCHAR CompatibleIDs[] = {'C','o','m','p','a','t','i','b','l','e','I','d','s',0};
77 static const WCHAR Service[] = {'S','e','r','v','i','c','e',0};
78 static const WCHAR Driver[] = {'D','r','i','v','e','r',0};
79 static const WCHAR ConfigFlags[] = {'C','o','n','f','i','g','F','l','a','g','s',0};
80 static const WCHAR Mfg[] = {'M','f','g',0};
81 static const WCHAR FriendlyName[] = {'F','r','i','e','n','d','l','y','N','a','m','e',0};
82 static const WCHAR LocationInformation[] = {'L','o','c','a','t','i','o','n','I','n','f','o','r','m','a','t','i','o','n',0};
83 static const WCHAR Capabilities[] = {'C','a','p','a','b','i','l','i','t','i','e','s',0};
84 static const WCHAR UINumber[] = {'U','I','N','u','m','b','e','r',0};
85 static const WCHAR UpperFilters[] = {'U','p','p','e','r','F','i','l','t','e','r','s',0};
86 static const WCHAR LowerFilters[] = {'L','o','w','e','r','F','i','l','t','e','r','s',0};
87 static const WCHAR Phantom[] = {'P','h','a','n','t','o','m',0};
88 static const WCHAR SymbolicLink[] = {'S','y','m','b','o','l','i','c','L','i','n','k',0};
89
90 /* is used to identify if a DeviceInfoSet pointer is
91 valid or not */
92 #define SETUP_DEVICE_INFO_SET_MAGIC 0xd00ff056
93
94 struct DeviceInfoSet
95 {
96     DWORD magic;        /* if is equal to SETUP_DEVICE_INFO_SET_MAGIC struct is okay */
97     GUID ClassGuid;
98     HWND hwndParent;
99     DWORD cDevices;
100     SP_DEVINFO_DATA *devices;
101 };
102
103 /* Pointed to by SP_DEVICE_INTERFACE_DATA's Reserved member */
104 struct InterfaceInfo
105 {
106     LPWSTR referenceString;
107     LPWSTR symbolicLink;
108 };
109
110 /* A device may have multiple instances of the same interface, so this holds
111  * each instance belonging to a particular interface.
112  */
113 struct InterfaceInstances
114 {
115     GUID                      guid;
116     DWORD                     cInstances;
117     DWORD                     cInstancesAllocated;
118     SP_DEVICE_INTERFACE_DATA *instances;
119 };
120
121 /* Pointed to by SP_DEVINFO_DATA's Reserved member */
122 struct DeviceInfo
123 {
124     HKEY                       key;
125     BOOL                       phantom;
126     LPWSTR                     instanceId;
127     DWORD                      cInterfaces;
128     DWORD                      cInterfacesAllocated;
129     struct InterfaceInstances *interfaces;
130 };
131
132 static void SETUPDI_FreeInterfaceInstances(struct InterfaceInstances *instances)
133 {
134     DWORD i;
135
136     for (i = 0; i < instances->cInstances; i++)
137     {
138         struct InterfaceInfo *ifaceInfo =
139             (struct InterfaceInfo *)instances->instances[i].Reserved;
140
141         HeapFree(GetProcessHeap(), 0, ifaceInfo->referenceString);
142         HeapFree(GetProcessHeap(), 0, ifaceInfo->symbolicLink);
143     }
144     HeapFree(GetProcessHeap(), 0, instances->instances);
145 }
146
147 /* Finds the interface with interface class InterfaceClassGuid in the device.
148  * Returns TRUE if found, and updates interfaceIndex to the index of the
149  * device's interfaces member where the given interface was found.
150  * Returns FALSE if not found.
151  */
152 static BOOL SETUPDI_FindInterface(const struct DeviceInfo *devInfo,
153         const GUID *InterfaceClassGuid, DWORD *interfaceIndex)
154 {
155     BOOL found = FALSE;
156     DWORD i;
157
158     TRACE("%s\n", debugstr_guid(InterfaceClassGuid));
159
160     for (i = 0; !found && i < devInfo->cInterfaces; i++)
161     {
162         if (IsEqualGUID(&devInfo->interfaces[i].guid, InterfaceClassGuid))
163         {
164             *interfaceIndex = i;
165             found = TRUE;
166         }
167     }
168     TRACE("returning %d (%d)\n", found, found ? *interfaceIndex : 0);
169     return found;
170 }
171
172 /* Finds the interface instance with reference string ReferenceString in the
173  * interface instance map.  Returns TRUE if found, and updates instanceIndex to
174  * the index of the interface instance's instances member
175  * where the given instance was found.  Returns FALSE if not found.
176  */
177 static BOOL SETUPDI_FindInterfaceInstance(
178         const struct InterfaceInstances *instances,
179         LPCWSTR ReferenceString, DWORD *instanceIndex)
180 {
181     BOOL found = FALSE;
182     DWORD i;
183
184     TRACE("%s\n", debugstr_w(ReferenceString));
185
186     for (i = 0; !found && i < instances->cInstances; i++)
187     {
188         SP_DEVICE_INTERFACE_DATA *ifaceData = &instances->instances[i];
189         struct InterfaceInfo *ifaceInfo =
190             (struct InterfaceInfo *)ifaceData->Reserved;
191
192         if (!ReferenceString && !ifaceInfo->referenceString)
193         {
194             *instanceIndex = i;
195             found = TRUE;
196         }
197         else if (ReferenceString && ifaceInfo->referenceString &&
198                 !lstrcmpiW(ifaceInfo->referenceString, ReferenceString))
199         {
200             *instanceIndex = i;
201             found = TRUE;
202         }
203     }
204     TRACE("returning %d (%d)\n", found, found ? *instanceIndex : 0);
205     return found;
206 }
207
208 /* Adds an interface with the given interface class and reference string to
209  * the device, if it doesn't already exist in the device.  If iface is not
210  * NULL, returns a pointer to the newly added (or already existing) interface.
211  */
212 static BOOL SETUPDI_AddInterfaceInstance(struct DeviceInfo *devInfo,
213         const GUID *InterfaceClassGuid, LPCWSTR ReferenceString,
214         SP_DEVICE_INTERFACE_DATA **ifaceData)
215 {
216     BOOL newInterface = FALSE, ret;
217     DWORD interfaceIndex = 0;
218     struct InterfaceInstances *iface = NULL;
219
220     TRACE("%p %s %s %p\n", devInfo, debugstr_guid(InterfaceClassGuid),
221             debugstr_w(ReferenceString), iface);
222
223     if (!(ret = SETUPDI_FindInterface(devInfo, InterfaceClassGuid,
224                     &interfaceIndex)))
225     {
226         if (!devInfo->cInterfacesAllocated)
227         {
228             devInfo->interfaces = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
229                     sizeof(struct InterfaceInstances));
230             if (devInfo->interfaces)
231             {
232                 iface = &devInfo->interfaces[devInfo->cInterfacesAllocated++];
233                 newInterface = TRUE;
234             }
235         }
236         else if (devInfo->cInterfaces == devInfo->cInterfacesAllocated)
237         {
238             devInfo->interfaces = HeapReAlloc(GetProcessHeap(),
239                     HEAP_ZERO_MEMORY, devInfo->interfaces,
240                     (devInfo->cInterfacesAllocated + 1) *
241                     sizeof(struct InterfaceInstances));
242             if (devInfo->interfaces)
243             {
244                 iface = &devInfo->interfaces[devInfo->cInterfacesAllocated++];
245                 newInterface = TRUE;
246             }
247         }
248         else
249             iface = &devInfo->interfaces[devInfo->cInterfaces];
250     }
251     else
252         iface = &devInfo->interfaces[interfaceIndex];
253     if (iface)
254     {
255         DWORD instanceIndex = 0;
256
257         if (!(ret = SETUPDI_FindInterfaceInstance(iface, ReferenceString,
258                         &instanceIndex)))
259         {
260             SP_DEVICE_INTERFACE_DATA *instance = NULL;
261
262             if (!iface->cInstancesAllocated)
263             {
264                 iface->instances = HeapAlloc(GetProcessHeap(), 0,
265                         sizeof(SP_DEVICE_INTERFACE_DATA));
266                 if (iface->instances)
267                     instance = &iface->instances[iface->cInstancesAllocated++];
268             }
269             else if (iface->cInstances == iface->cInstancesAllocated)
270             {
271                 iface->instances = HeapReAlloc(GetProcessHeap(), 0,
272                         iface->instances,
273                         (iface->cInstancesAllocated + 1) *
274                         sizeof(SP_DEVICE_INTERFACE_DATA));
275                 if (iface->instances)
276                     instance = &iface->instances[iface->cInstancesAllocated++];
277             }
278             else
279                 instance = &iface->instances[iface->cInstances];
280             if (instance)
281             {
282                 struct InterfaceInfo *ifaceInfo = HeapAlloc(GetProcessHeap(),
283                         0, sizeof(struct InterfaceInfo));
284
285                 if (ifaceInfo)
286                 {
287                     ret = TRUE;
288                     ifaceInfo->symbolicLink = NULL;
289                     if (ReferenceString)
290                     {
291                         ifaceInfo->referenceString =
292                             HeapAlloc(GetProcessHeap(), 0,
293                                 (lstrlenW(ReferenceString) + 1) *
294                                 sizeof(WCHAR));
295                         if (ifaceInfo->referenceString)
296                             lstrcpyW(ifaceInfo->referenceString,
297                                     ReferenceString);
298                         else
299                             ret = FALSE;
300                     }
301                     else
302                         ifaceInfo->referenceString = NULL;
303                     if (ret)
304                     {
305                         iface->cInstances++;
306                         instance->cbSize =
307                             sizeof(SP_DEVICE_INTERFACE_DATA);
308                         memcpy(&instance->InterfaceClassGuid,
309                                 InterfaceClassGuid, sizeof(GUID));
310                         instance->Flags = SPINT_ACTIVE; /* FIXME */
311                         instance->Reserved = (ULONG_PTR)ifaceInfo;
312                         if (newInterface)
313                         {
314                             memcpy(&iface->guid, InterfaceClassGuid,
315                                     sizeof(GUID));
316                             devInfo->cInterfaces++;
317                         }
318                         /* FIXME: now create this homeboy in the registry */
319                         if (ifaceData)
320                             *ifaceData = instance;
321                     }
322                     else
323                         HeapFree(GetProcessHeap(), 0, ifaceInfo);
324                 }
325             }
326         }
327         else
328         {
329             if (ifaceData)
330                 *ifaceData =
331                     &devInfo->interfaces[interfaceIndex].instances[instanceIndex];
332         }
333     }
334     else
335         ret = FALSE;
336     TRACE("returning %d\n", ret);
337     return ret;
338 }
339
340 static BOOL SETUPDI_SetInterfaceSymbolicLink(SP_DEVICE_INTERFACE_DATA *iface,
341         LPCWSTR symbolicLink)
342 {
343     struct InterfaceInfo *info = (struct InterfaceInfo *)iface->Reserved;
344     BOOL ret = FALSE;
345
346     if (info)
347     {
348         HeapFree(GetProcessHeap(), 0, info->symbolicLink);
349         info->symbolicLink = HeapAlloc(GetProcessHeap(), 0,
350                 (lstrlenW(symbolicLink) + 1) * sizeof(WCHAR));
351         if (info->symbolicLink)
352         {
353             lstrcpyW(info->symbolicLink, symbolicLink);
354             ret = TRUE;
355         }
356     }
357     return ret;
358 }
359
360 static struct DeviceInfo *SETUPDI_AllocateDeviceInfo(LPCWSTR instanceId,
361         BOOL phantom)
362 {
363     struct DeviceInfo *devInfo = HeapAlloc(GetProcessHeap(), 0,
364             sizeof(struct DeviceInfo));
365
366     if (devInfo)
367     {
368         devInfo->instanceId = HeapAlloc(GetProcessHeap(), 0,
369                 (lstrlenW(instanceId) + 1) * sizeof(WCHAR));
370         if (devInfo->instanceId)
371         {
372             HKEY enumKey;
373             LONG l;
374
375             devInfo->key = INVALID_HANDLE_VALUE;
376             devInfo->phantom = phantom;
377             lstrcpyW(devInfo->instanceId, instanceId);
378             struprW(devInfo->instanceId);
379             l = RegCreateKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, NULL, 0,
380                     KEY_ALL_ACCESS, NULL, &enumKey, NULL);
381             if (!l)
382             {
383                 RegCreateKeyExW(enumKey, devInfo->instanceId, 0, NULL, 0,
384                         KEY_ALL_ACCESS, NULL, &devInfo->key, NULL);
385                 if (phantom)
386                     RegSetValueExW(devInfo->key, Phantom, 0, REG_DWORD,
387                             (LPBYTE)&phantom, sizeof(phantom));
388                 RegCloseKey(enumKey);
389             }
390             devInfo->cInterfaces = devInfo->cInterfacesAllocated = 0;
391             devInfo->interfaces = NULL;
392         }
393         else
394         {
395             HeapFree(GetProcessHeap(), 0, devInfo);
396             devInfo = NULL;
397         }
398     }
399     return devInfo;
400 }
401
402 static void SETUPDI_FreeDeviceInfo(struct DeviceInfo *devInfo)
403 {
404     DWORD i;
405
406     if (devInfo->key != INVALID_HANDLE_VALUE)
407         RegCloseKey(devInfo->key);
408     if (devInfo->phantom)
409     {
410         HKEY enumKey;
411         LONG l;
412
413         l = RegCreateKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, NULL, 0,
414                 KEY_ALL_ACCESS, NULL, &enumKey, NULL);
415         if (!l)
416         {
417             RegDeleteTreeW(enumKey, devInfo->instanceId);
418             RegCloseKey(enumKey);
419         }
420     }
421     HeapFree(GetProcessHeap(), 0, devInfo->instanceId);
422     for (i = 0; i < devInfo->cInterfaces; i++)
423         SETUPDI_FreeInterfaceInstances(&devInfo->interfaces[i]);
424     HeapFree(GetProcessHeap(), 0, devInfo->interfaces);
425     HeapFree(GetProcessHeap(), 0, devInfo);
426 }
427
428 static void SETUPDI_GuidToString(const GUID *guid, LPWSTR guidStr)
429 {
430     static const WCHAR fmt[] = {'{','%','0','8','X','-','%','0','4','X','-',
431         '%','0','4','X','-','%','0','2','X','%','0','2','X','-','%','0','2',
432         'X','%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X','%',
433         '0','2','X','}',0};
434
435     sprintfW(guidStr, fmt, guid->Data1, guid->Data2, guid->Data3,
436         guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
437         guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
438 }
439
440 /* Adds a device with GUID guid and identifer devInst to set.  Allocates a
441  * struct DeviceInfo, and points the returned device info's Reserved member
442  * to it.  "Phantom" devices are deleted from the registry when closed.
443  * Returns a pointer to the newly allocated device info.
444  */
445 static BOOL SETUPDI_AddDeviceToSet(struct DeviceInfoSet *set,
446         const GUID *guid,
447         DWORD devInst,
448         LPCWSTR instanceId,
449         BOOL phantom,
450         SP_DEVINFO_DATA **dev)
451 {
452     BOOL ret = FALSE;
453     struct DeviceInfo *devInfo = SETUPDI_AllocateDeviceInfo(instanceId,
454             phantom);
455
456     TRACE("%p, %s, %d, %s, %d\n", set, debugstr_guid(guid), devInst,
457             debugstr_w(instanceId), phantom);
458
459     if (devInfo)
460     {
461         if (set->devices)
462             set->devices = HeapReAlloc(GetProcessHeap(), 0, set->devices,
463                     (set->cDevices + 1) * sizeof(SP_DEVINFO_DATA));
464         else
465             set->devices = HeapAlloc(GetProcessHeap(), 0,
466                     sizeof(SP_DEVINFO_DATA));
467         if (set->devices)
468         {
469             WCHAR classGuidStr[39];
470
471             *dev = &set->devices[set->cDevices++];
472             (*dev)->cbSize = sizeof(SP_DEVINFO_DATA);
473             memcpy(&(*dev)->ClassGuid, guid, sizeof(GUID));
474             (*dev)->DevInst = devInst;
475             (*dev)->Reserved = (ULONG_PTR)devInfo;
476             SETUPDI_GuidToString(guid, classGuidStr);
477             SetupDiSetDeviceRegistryPropertyW((HDEVINFO)set,
478                 *dev, SPDRP_CLASSGUID, (const BYTE *)classGuidStr,
479                 lstrlenW(classGuidStr) * sizeof(WCHAR));
480             ret = TRUE;
481         }
482         else
483         {
484             HeapFree(GetProcessHeap(), 0, devInfo);
485             SetLastError(ERROR_OUTOFMEMORY);
486         }
487     }
488     return ret;
489 }
490
491 /***********************************************************************
492  *              SetupDiBuildClassInfoList  (SETUPAPI.@)
493  *
494  * Returns a list of setup class GUIDs that identify the classes
495  * that are installed on a local machine.
496  *
497  * PARAMS
498  *   Flags [I] control exclusion of classes from the list.
499  *   ClassGuidList [O] pointer to a GUID-typed array that receives a list of setup class GUIDs.
500  *   ClassGuidListSize [I] The number of GUIDs in the array (ClassGuidList).
501  *   RequiredSize [O] pointer, which receives the number of GUIDs that are returned.
502  *
503  * RETURNS
504  *   Success: TRUE.
505  *   Failure: FALSE.
506  */
507 BOOL WINAPI SetupDiBuildClassInfoList(
508         DWORD Flags,
509         LPGUID ClassGuidList,
510         DWORD ClassGuidListSize,
511         PDWORD RequiredSize)
512 {
513     TRACE("\n");
514     return SetupDiBuildClassInfoListExW(Flags, ClassGuidList,
515                                         ClassGuidListSize, RequiredSize,
516                                         NULL, NULL);
517 }
518
519 /***********************************************************************
520  *              SetupDiBuildClassInfoListExA  (SETUPAPI.@)
521  *
522  * Returns a list of setup class GUIDs that identify the classes
523  * that are installed on a local or remote macine.
524  *
525  * PARAMS
526  *   Flags [I] control exclusion of classes from the list.
527  *   ClassGuidList [O] pointer to a GUID-typed array that receives a list of setup class GUIDs.
528  *   ClassGuidListSize [I] The number of GUIDs in the array (ClassGuidList).
529  *   RequiredSize [O] pointer, which receives the number of GUIDs that are returned.
530  *   MachineName [I] name of a remote machine.
531  *   Reserved [I] must be NULL.
532  *
533  * RETURNS
534  *   Success: TRUE.
535  *   Failure: FALSE.
536  */
537 BOOL WINAPI SetupDiBuildClassInfoListExA(
538         DWORD Flags,
539         LPGUID ClassGuidList,
540         DWORD ClassGuidListSize,
541         PDWORD RequiredSize,
542         LPCSTR MachineName,
543         PVOID Reserved)
544 {
545     LPWSTR MachineNameW = NULL;
546     BOOL bResult;
547
548     TRACE("\n");
549
550     if (MachineName)
551     {
552         MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
553         if (MachineNameW == NULL) return FALSE;
554     }
555
556     bResult = SetupDiBuildClassInfoListExW(Flags, ClassGuidList,
557                                            ClassGuidListSize, RequiredSize,
558                                            MachineNameW, Reserved);
559
560     MyFree(MachineNameW);
561
562     return bResult;
563 }
564
565 /***********************************************************************
566  *              SetupDiBuildClassInfoListExW  (SETUPAPI.@)
567  *
568  * Returns a list of setup class GUIDs that identify the classes
569  * that are installed on a local or remote macine.
570  *
571  * PARAMS
572  *   Flags [I] control exclusion of classes from the list.
573  *   ClassGuidList [O] pointer to a GUID-typed array that receives a list of setup class GUIDs.
574  *   ClassGuidListSize [I] The number of GUIDs in the array (ClassGuidList).
575  *   RequiredSize [O] pointer, which receives the number of GUIDs that are returned.
576  *   MachineName [I] name of a remote machine.
577  *   Reserved [I] must be NULL.
578  *
579  * RETURNS
580  *   Success: TRUE.
581  *   Failure: FALSE.
582  */
583 BOOL WINAPI SetupDiBuildClassInfoListExW(
584         DWORD Flags,
585         LPGUID ClassGuidList,
586         DWORD ClassGuidListSize,
587         PDWORD RequiredSize,
588         LPCWSTR MachineName,
589         PVOID Reserved)
590 {
591     WCHAR szKeyName[40];
592     HKEY hClassesKey;
593     HKEY hClassKey;
594     DWORD dwLength;
595     DWORD dwIndex;
596     LONG lError;
597     DWORD dwGuidListIndex = 0;
598
599     TRACE("\n");
600
601     if (RequiredSize != NULL)
602         *RequiredSize = 0;
603
604     hClassesKey = SetupDiOpenClassRegKeyExW(NULL,
605                                             KEY_ALL_ACCESS,
606                                             DIOCR_INSTALLER,
607                                             MachineName,
608                                             Reserved);
609     if (hClassesKey == INVALID_HANDLE_VALUE)
610     {
611         return FALSE;
612     }
613
614     for (dwIndex = 0; ; dwIndex++)
615     {
616         dwLength = 40;
617         lError = RegEnumKeyExW(hClassesKey,
618                                dwIndex,
619                                szKeyName,
620                                &dwLength,
621                                NULL,
622                                NULL,
623                                NULL,
624                                NULL);
625         TRACE("RegEnumKeyExW() returns %d\n", lError);
626         if (lError == ERROR_SUCCESS || lError == ERROR_MORE_DATA)
627         {
628             TRACE("Key name: %p\n", szKeyName);
629
630             if (RegOpenKeyExW(hClassesKey,
631                               szKeyName,
632                               0,
633                               KEY_ALL_ACCESS,
634                               &hClassKey))
635             {
636                 RegCloseKey(hClassesKey);
637                 return FALSE;
638             }
639
640             if (!RegQueryValueExW(hClassKey,
641                                   NoUseClass,
642                                   NULL,
643                                   NULL,
644                                   NULL,
645                                   NULL))
646             {
647                 TRACE("'NoUseClass' value found!\n");
648                 RegCloseKey(hClassKey);
649                 continue;
650             }
651
652             if ((Flags & DIBCI_NOINSTALLCLASS) &&
653                 (!RegQueryValueExW(hClassKey,
654                                    NoInstallClass,
655                                    NULL,
656                                    NULL,
657                                    NULL,
658                                    NULL)))
659             {
660                 TRACE("'NoInstallClass' value found!\n");
661                 RegCloseKey(hClassKey);
662                 continue;
663             }
664
665             if ((Flags & DIBCI_NODISPLAYCLASS) &&
666                 (!RegQueryValueExW(hClassKey,
667                                    NoDisplayClass,
668                                    NULL,
669                                    NULL,
670                                    NULL,
671                                    NULL)))
672             {
673                 TRACE("'NoDisplayClass' value found!\n");
674                 RegCloseKey(hClassKey);
675                 continue;
676             }
677
678             RegCloseKey(hClassKey);
679
680             TRACE("Guid: %p\n", szKeyName);
681             if (dwGuidListIndex < ClassGuidListSize)
682             {
683                 if (szKeyName[0] == '{' && szKeyName[37] == '}')
684                 {
685                     szKeyName[37] = 0;
686                 }
687                 TRACE("Guid: %p\n", &szKeyName[1]);
688
689                 UuidFromStringW(&szKeyName[1],
690                                 &ClassGuidList[dwGuidListIndex]);
691             }
692
693             dwGuidListIndex++;
694         }
695
696         if (lError != ERROR_SUCCESS)
697             break;
698     }
699
700     RegCloseKey(hClassesKey);
701
702     if (RequiredSize != NULL)
703         *RequiredSize = dwGuidListIndex;
704
705     if (ClassGuidListSize < dwGuidListIndex)
706     {
707         SetLastError(ERROR_INSUFFICIENT_BUFFER);
708         return FALSE;
709     }
710
711     return TRUE;
712 }
713
714 /***********************************************************************
715  *              SetupDiClassGuidsFromNameA  (SETUPAPI.@)
716  */
717 BOOL WINAPI SetupDiClassGuidsFromNameA(
718         LPCSTR ClassName,
719         LPGUID ClassGuidList,
720         DWORD ClassGuidListSize,
721         PDWORD RequiredSize)
722 {
723   return SetupDiClassGuidsFromNameExA(ClassName, ClassGuidList,
724                                       ClassGuidListSize, RequiredSize,
725                                       NULL, NULL);
726 }
727
728 /***********************************************************************
729  *              SetupDiClassGuidsFromNameW  (SETUPAPI.@)
730  */
731 BOOL WINAPI SetupDiClassGuidsFromNameW(
732         LPCWSTR ClassName,
733         LPGUID ClassGuidList,
734         DWORD ClassGuidListSize,
735         PDWORD RequiredSize)
736 {
737   return SetupDiClassGuidsFromNameExW(ClassName, ClassGuidList,
738                                       ClassGuidListSize, RequiredSize,
739                                       NULL, NULL);
740 }
741
742 /***********************************************************************
743  *              SetupDiClassGuidsFromNameExA  (SETUPAPI.@)
744  */
745 BOOL WINAPI SetupDiClassGuidsFromNameExA(
746         LPCSTR ClassName,
747         LPGUID ClassGuidList,
748         DWORD ClassGuidListSize,
749         PDWORD RequiredSize,
750         LPCSTR MachineName,
751         PVOID Reserved)
752 {
753     LPWSTR ClassNameW = NULL;
754     LPWSTR MachineNameW = NULL;
755     BOOL bResult;
756
757     FIXME("\n");
758
759     ClassNameW = MultiByteToUnicode(ClassName, CP_ACP);
760     if (ClassNameW == NULL)
761         return FALSE;
762
763     if (MachineName)
764     {
765         MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
766         if (MachineNameW == NULL)
767         {
768             MyFree(ClassNameW);
769             return FALSE;
770         }
771     }
772
773     bResult = SetupDiClassGuidsFromNameExW(ClassNameW, ClassGuidList,
774                                            ClassGuidListSize, RequiredSize,
775                                            MachineNameW, Reserved);
776
777     MyFree(MachineNameW);
778     MyFree(ClassNameW);
779
780     return bResult;
781 }
782
783 /***********************************************************************
784  *              SetupDiClassGuidsFromNameExW  (SETUPAPI.@)
785  */
786 BOOL WINAPI SetupDiClassGuidsFromNameExW(
787         LPCWSTR ClassName,
788         LPGUID ClassGuidList,
789         DWORD ClassGuidListSize,
790         PDWORD RequiredSize,
791         LPCWSTR MachineName,
792         PVOID Reserved)
793 {
794     WCHAR szKeyName[40];
795     WCHAR szClassName[256];
796     HKEY hClassesKey;
797     HKEY hClassKey;
798     DWORD dwLength;
799     DWORD dwIndex;
800     LONG lError;
801     DWORD dwGuidListIndex = 0;
802
803     if (RequiredSize != NULL)
804         *RequiredSize = 0;
805
806     hClassesKey = SetupDiOpenClassRegKeyExW(NULL,
807                                             KEY_ALL_ACCESS,
808                                             DIOCR_INSTALLER,
809                                             MachineName,
810                                             Reserved);
811     if (hClassesKey == INVALID_HANDLE_VALUE)
812     {
813         return FALSE;
814     }
815
816     for (dwIndex = 0; ; dwIndex++)
817     {
818         dwLength = 40;
819         lError = RegEnumKeyExW(hClassesKey,
820                                dwIndex,
821                                szKeyName,
822                                &dwLength,
823                                NULL,
824                                NULL,
825                                NULL,
826                                NULL);
827         TRACE("RegEnumKeyExW() returns %d\n", lError);
828         if (lError == ERROR_SUCCESS || lError == ERROR_MORE_DATA)
829         {
830             TRACE("Key name: %p\n", szKeyName);
831
832             if (RegOpenKeyExW(hClassesKey,
833                               szKeyName,
834                               0,
835                               KEY_ALL_ACCESS,
836                               &hClassKey))
837             {
838                 RegCloseKey(hClassesKey);
839                 return FALSE;
840             }
841
842             dwLength = 256 * sizeof(WCHAR);
843             if (!RegQueryValueExW(hClassKey,
844                                   Class,
845                                   NULL,
846                                   NULL,
847                                   (LPBYTE)szClassName,
848                                   &dwLength))
849             {
850                 TRACE("Class name: %p\n", szClassName);
851
852                 if (strcmpiW(szClassName, ClassName) == 0)
853                 {
854                     TRACE("Found matching class name\n");
855
856                     TRACE("Guid: %p\n", szKeyName);
857                     if (dwGuidListIndex < ClassGuidListSize)
858                     {
859                         if (szKeyName[0] == '{' && szKeyName[37] == '}')
860                         {
861                             szKeyName[37] = 0;
862                         }
863                         TRACE("Guid: %p\n", &szKeyName[1]);
864
865                         UuidFromStringW(&szKeyName[1],
866                                         &ClassGuidList[dwGuidListIndex]);
867                     }
868
869                     dwGuidListIndex++;
870                 }
871             }
872
873             RegCloseKey(hClassKey);
874         }
875
876         if (lError != ERROR_SUCCESS)
877             break;
878     }
879
880     RegCloseKey(hClassesKey);
881
882     if (RequiredSize != NULL)
883         *RequiredSize = dwGuidListIndex;
884
885     if (ClassGuidListSize < dwGuidListIndex)
886     {
887         SetLastError(ERROR_INSUFFICIENT_BUFFER);
888         return FALSE;
889     }
890
891     return TRUE;
892 }
893
894 /***********************************************************************
895  *              SetupDiClassNameFromGuidA  (SETUPAPI.@)
896  */
897 BOOL WINAPI SetupDiClassNameFromGuidA(
898         const GUID* ClassGuid,
899         PSTR ClassName,
900         DWORD ClassNameSize,
901         PDWORD RequiredSize)
902 {
903   return SetupDiClassNameFromGuidExA(ClassGuid, ClassName,
904                                      ClassNameSize, RequiredSize,
905                                      NULL, NULL);
906 }
907
908 /***********************************************************************
909  *              SetupDiClassNameFromGuidW  (SETUPAPI.@)
910  */
911 BOOL WINAPI SetupDiClassNameFromGuidW(
912         const GUID* ClassGuid,
913         PWSTR ClassName,
914         DWORD ClassNameSize,
915         PDWORD RequiredSize)
916 {
917   return SetupDiClassNameFromGuidExW(ClassGuid, ClassName,
918                                      ClassNameSize, RequiredSize,
919                                      NULL, NULL);
920 }
921
922 /***********************************************************************
923  *              SetupDiClassNameFromGuidExA  (SETUPAPI.@)
924  */
925 BOOL WINAPI SetupDiClassNameFromGuidExA(
926         const GUID* ClassGuid,
927         PSTR ClassName,
928         DWORD ClassNameSize,
929         PDWORD RequiredSize,
930         PCSTR MachineName,
931         PVOID Reserved)
932 {
933     WCHAR ClassNameW[MAX_CLASS_NAME_LEN];
934     LPWSTR MachineNameW = NULL;
935     BOOL ret;
936
937     if (MachineName)
938         MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
939     ret = SetupDiClassNameFromGuidExW(ClassGuid, ClassNameW, MAX_CLASS_NAME_LEN,
940      NULL, MachineNameW, Reserved);
941     if (ret)
942     {
943         int len = WideCharToMultiByte(CP_ACP, 0, ClassNameW, -1, ClassName,
944          ClassNameSize, NULL, NULL);
945
946         if (!ClassNameSize && RequiredSize)
947             *RequiredSize = len;
948     }
949     MyFree(MachineNameW);
950     return ret;
951 }
952
953 /***********************************************************************
954  *              SetupDiClassNameFromGuidExW  (SETUPAPI.@)
955  */
956 BOOL WINAPI SetupDiClassNameFromGuidExW(
957         const GUID* ClassGuid,
958         PWSTR ClassName,
959         DWORD ClassNameSize,
960         PDWORD RequiredSize,
961         PCWSTR MachineName,
962         PVOID Reserved)
963 {
964     HKEY hKey;
965     DWORD dwLength;
966
967     hKey = SetupDiOpenClassRegKeyExW(ClassGuid,
968                                      KEY_ALL_ACCESS,
969                                      DIOCR_INSTALLER,
970                                      MachineName,
971                                      Reserved);
972     if (hKey == INVALID_HANDLE_VALUE)
973     {
974         return FALSE;
975     }
976
977     if (RequiredSize != NULL)
978     {
979         dwLength = 0;
980         if (RegQueryValueExW(hKey,
981                              Class,
982                              NULL,
983                              NULL,
984                              NULL,
985                              &dwLength))
986         {
987             RegCloseKey(hKey);
988             return FALSE;
989         }
990
991         *RequiredSize = dwLength / sizeof(WCHAR);
992     }
993
994     dwLength = ClassNameSize * sizeof(WCHAR);
995     if (RegQueryValueExW(hKey,
996                          Class,
997                          NULL,
998                          NULL,
999                          (LPBYTE)ClassName,
1000                          &dwLength))
1001     {
1002         RegCloseKey(hKey);
1003         return FALSE;
1004     }
1005
1006     RegCloseKey(hKey);
1007
1008     return TRUE;
1009 }
1010
1011 /***********************************************************************
1012  *              SetupDiCreateDeviceInfoList (SETUPAPI.@)
1013  */
1014 HDEVINFO WINAPI
1015 SetupDiCreateDeviceInfoList(const GUID *ClassGuid,
1016                             HWND hwndParent)
1017 {
1018   return SetupDiCreateDeviceInfoListExW(ClassGuid, hwndParent, NULL, NULL);
1019 }
1020
1021 /***********************************************************************
1022  *              SetupDiCreateDeviceInfoListExA (SETUPAPI.@)
1023  */
1024 HDEVINFO WINAPI
1025 SetupDiCreateDeviceInfoListExA(const GUID *ClassGuid,
1026                                HWND hwndParent,
1027                                PCSTR MachineName,
1028                                PVOID Reserved)
1029 {
1030     LPWSTR MachineNameW = NULL;
1031     HDEVINFO hDevInfo;
1032
1033     TRACE("\n");
1034
1035     if (MachineName)
1036     {
1037         MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
1038         if (MachineNameW == NULL)
1039             return (HDEVINFO)INVALID_HANDLE_VALUE;
1040     }
1041
1042     hDevInfo = SetupDiCreateDeviceInfoListExW(ClassGuid, hwndParent,
1043                                               MachineNameW, Reserved);
1044
1045     MyFree(MachineNameW);
1046
1047     return hDevInfo;
1048 }
1049
1050 /***********************************************************************
1051  *              SetupDiCreateDeviceInfoListExW (SETUPAPI.@)
1052  *
1053  * Create an empty DeviceInfoSet list.
1054  *
1055  * PARAMS
1056  *   ClassGuid [I] if not NULL only devices with GUID ClcassGuid are associated
1057  *                 with this list.
1058  *   hwndParent [I] hwnd needed for interface related actions.
1059  *   MachineName [I] name of machine to create emtpy DeviceInfoSet list, if NULL
1060  *                   local registry will be used.
1061  *   Reserved [I] must be NULL
1062  *
1063  * RETURNS
1064  *   Success: empty list.
1065  *   Failure: INVALID_HANDLE_VALUE.
1066  */
1067 HDEVINFO WINAPI
1068 SetupDiCreateDeviceInfoListExW(const GUID *ClassGuid,
1069                                HWND hwndParent,
1070                                PCWSTR MachineName,
1071                                PVOID Reserved)
1072 {
1073     struct DeviceInfoSet *list = NULL;
1074     DWORD size = sizeof(struct DeviceInfoSet);
1075
1076     TRACE("%s %p %s %p\n", debugstr_guid(ClassGuid), hwndParent,
1077       debugstr_w(MachineName), Reserved);
1078
1079     if (MachineName != NULL)
1080     {
1081         FIXME("remote support is not implemented\n");
1082         SetLastError(ERROR_INVALID_MACHINENAME);
1083         return (HDEVINFO)INVALID_HANDLE_VALUE;
1084     }
1085
1086     if (Reserved != NULL)
1087     {
1088         SetLastError(ERROR_INVALID_PARAMETER);
1089         return (HDEVINFO)INVALID_HANDLE_VALUE;
1090     }
1091
1092     list = HeapAlloc(GetProcessHeap(), 0, size);
1093     if (!list)
1094     {
1095         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1096         return (HDEVINFO)INVALID_HANDLE_VALUE;
1097     }
1098
1099     list->magic = SETUP_DEVICE_INFO_SET_MAGIC;
1100     list->hwndParent = hwndParent;
1101     memcpy(&list->ClassGuid,
1102             ClassGuid ? ClassGuid : &GUID_NULL,
1103             sizeof(list->ClassGuid));
1104     list->cDevices = 0;
1105     list->devices = NULL;
1106
1107     return (HDEVINFO)list;
1108 }
1109
1110 /***********************************************************************
1111  *              SetupDiCreateDeviceInfoA (SETUPAPI.@)
1112  */
1113 BOOL WINAPI SetupDiCreateDeviceInfoA(
1114        HDEVINFO DeviceInfoSet,
1115        PCSTR DeviceName,
1116        CONST GUID *ClassGuid,
1117        PCSTR DeviceDescription,
1118        HWND hwndParent,
1119        DWORD CreationFlags,
1120        PSP_DEVINFO_DATA DeviceInfoData)
1121 {
1122     BOOL ret = FALSE;
1123     LPWSTR DeviceNameW = NULL;
1124     LPWSTR DeviceDescriptionW = NULL;
1125
1126     if (DeviceName)
1127     {
1128         DeviceNameW = MultiByteToUnicode(DeviceName, CP_ACP);
1129         if (DeviceNameW == NULL) return FALSE;
1130     }
1131     if (DeviceDescription)
1132     {
1133         DeviceDescriptionW = MultiByteToUnicode(DeviceDescription, CP_ACP);
1134         if (DeviceDescriptionW == NULL)
1135         {
1136             MyFree(DeviceNameW);
1137             return FALSE;
1138         }
1139     }
1140
1141     ret = SetupDiCreateDeviceInfoW(DeviceInfoSet, DeviceNameW, ClassGuid, DeviceDescriptionW,
1142             hwndParent, CreationFlags, DeviceInfoData);
1143
1144     MyFree(DeviceNameW);
1145     MyFree(DeviceDescriptionW);
1146
1147     return ret;
1148 }
1149
1150 static DWORD SETUPDI_DevNameToDevID(LPCWSTR devName)
1151 {
1152     LPCWSTR ptr;
1153     DWORD devNameLen = lstrlenW(devName), devInst = 0;
1154     BOOL valid = TRUE;
1155
1156     TRACE("%s\n", debugstr_w(devName));
1157     for (ptr = devName; valid && *ptr && ptr - devName < devNameLen; )
1158     {
1159         if (isdigitW(*ptr))
1160         {
1161             devInst *= 10;
1162             devInst |= *ptr - '0';
1163             ptr++;
1164         }
1165         else
1166             valid = FALSE;
1167     }
1168     TRACE("%d\n", valid ? devInst : 0xffffffff);
1169     return valid ? devInst : 0xffffffff;
1170 }
1171
1172 /***********************************************************************
1173  *              SetupDiCreateDeviceInfoW (SETUPAPI.@)
1174  */
1175 BOOL WINAPI SetupDiCreateDeviceInfoW(
1176        HDEVINFO DeviceInfoSet,
1177        PCWSTR DeviceName,
1178        CONST GUID *ClassGuid,
1179        PCWSTR DeviceDescription,
1180        HWND hwndParent,
1181        DWORD CreationFlags,
1182        PSP_DEVINFO_DATA DeviceInfoData)
1183 {
1184     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
1185     BOOL ret = FALSE, allocatedInstanceId = FALSE;
1186     LPCWSTR instanceId = NULL;
1187
1188     TRACE("%p %s %s %s %p %x %p\n", DeviceInfoSet, debugstr_w(DeviceName),
1189         debugstr_guid(ClassGuid), debugstr_w(DeviceDescription),
1190         hwndParent, CreationFlags, DeviceInfoData);
1191
1192     if (!DeviceName)
1193     {
1194         SetLastError(ERROR_INVALID_DEVINST_NAME);
1195         return FALSE;
1196     }
1197     if (!DeviceInfoSet || DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
1198     {
1199         SetLastError(ERROR_INVALID_HANDLE);
1200         return FALSE;
1201     }
1202     if (!ClassGuid)
1203     {
1204         SetLastError(ERROR_INVALID_PARAMETER);
1205         return FALSE;
1206     }
1207     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
1208     {
1209         SetLastError(ERROR_INVALID_HANDLE);
1210         return FALSE;
1211     }
1212     if (!IsEqualGUID(&set->ClassGuid, &GUID_NULL) &&
1213         !IsEqualGUID(ClassGuid, &set->ClassGuid))
1214     {
1215         SetLastError(ERROR_CLASS_MISMATCH);
1216         return FALSE;
1217     }
1218     if ((CreationFlags & DICD_GENERATE_ID))
1219     {
1220         if (strchrW(DeviceName, '\\'))
1221             SetLastError(ERROR_INVALID_DEVINST_NAME);
1222         else
1223         {
1224             static const WCHAR newDeviceFmt[] = {'R','O','O','T','\\','%','s',
1225                 '\\','%','0','4','d',0};
1226             DWORD devId;
1227
1228             if (set->cDevices)
1229             {
1230                 DWORD i, highestDevID = 0;
1231
1232                 for (i = 0; i < set->cDevices; i++)
1233                 {
1234                     struct DeviceInfo *devInfo =
1235                         (struct DeviceInfo *)set->devices[i].Reserved;
1236                     LPCWSTR devName = strrchrW(devInfo->instanceId, '\\');
1237                     DWORD id;
1238
1239                     if (devName)
1240                         devName++;
1241                     else
1242                         devName = devInfo->instanceId;
1243                     id = SETUPDI_DevNameToDevID(devName);
1244                     if (id != 0xffffffff && id > highestDevID)
1245                         highestDevID = id;
1246                 }
1247                 devId = highestDevID + 1;
1248             }
1249             else
1250                 devId = 0;
1251             /* 17 == lstrlenW(L"Root\\") + lstrlenW("\\") + 1 + %d max size */
1252             instanceId = HeapAlloc(GetProcessHeap(), 0,
1253                     (17 + lstrlenW(DeviceName)) * sizeof(WCHAR));
1254             if (instanceId)
1255             {
1256                 sprintfW((LPWSTR)instanceId, newDeviceFmt, DeviceName,
1257                         devId);
1258                 allocatedInstanceId = TRUE;
1259                 ret = TRUE;
1260             }
1261             else
1262                 ret = FALSE;
1263         }
1264     }
1265     else
1266     {
1267         DWORD i;
1268
1269         ret = TRUE;
1270         instanceId = DeviceName;
1271         for (i = 0; ret && i < set->cDevices; i++)
1272         {
1273             struct DeviceInfo *devInfo =
1274                 (struct DeviceInfo *)set->devices[i].Reserved;
1275
1276             if (!lstrcmpiW(DeviceName, devInfo->instanceId))
1277             {
1278                 SetLastError(ERROR_DEVINST_ALREADY_EXISTS);
1279                 ret = FALSE;
1280             }
1281         }
1282     }
1283     if (ret)
1284     {
1285         SP_DEVINFO_DATA *dev = NULL;
1286
1287         ret = SETUPDI_AddDeviceToSet(set, ClassGuid, 0 /* FIXME: DevInst */,
1288                 instanceId, TRUE, &dev);
1289         if (ret)
1290         {
1291             if (DeviceDescription)
1292                 SetupDiSetDeviceRegistryPropertyW(DeviceInfoSet,
1293                     dev, SPDRP_DEVICEDESC, (const BYTE *)DeviceDescription,
1294                     lstrlenW(DeviceDescription) * sizeof(WCHAR));
1295             if (DeviceInfoData)
1296             {
1297                 if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
1298                 {
1299                     SetLastError(ERROR_INVALID_USER_BUFFER);
1300                     ret = FALSE;
1301                 }
1302                 else
1303                     memcpy(DeviceInfoData, dev, sizeof(SP_DEVINFO_DATA));
1304             }
1305         }
1306     }
1307     if (allocatedInstanceId)
1308         HeapFree(GetProcessHeap(), 0, (LPWSTR)instanceId);
1309
1310     return ret;
1311 }
1312
1313 /***********************************************************************
1314  *              SetupDiRegisterDeviceInfo (SETUPAPI.@)
1315  */
1316 BOOL WINAPI SetupDiRegisterDeviceInfo(
1317         HDEVINFO DeviceInfoSet,
1318         PSP_DEVINFO_DATA DeviceInfoData,
1319         DWORD Flags,
1320         PSP_DETSIG_CMPPROC CompareProc,
1321         PVOID CompareContext,
1322         PSP_DEVINFO_DATA DupDeviceInfoData)
1323 {
1324     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
1325     struct DeviceInfo *devInfo;
1326
1327     TRACE("%p %p %08x %p %p %p\n", DeviceInfoSet, DeviceInfoData, Flags,
1328             CompareProc, CompareContext, DupDeviceInfoData);
1329
1330     if (!DeviceInfoSet || DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
1331     {
1332         SetLastError(ERROR_INVALID_HANDLE);
1333         return FALSE;
1334     }
1335     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
1336     {
1337         SetLastError(ERROR_INVALID_HANDLE);
1338         return FALSE;
1339     }
1340     if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
1341             || !DeviceInfoData->Reserved)
1342     {
1343         SetLastError(ERROR_INVALID_PARAMETER);
1344         return FALSE;
1345     }
1346     devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
1347     if (devInfo->phantom)
1348     {
1349         devInfo->phantom = FALSE;
1350         RegDeleteValueW(devInfo->key, Phantom);
1351     }
1352     return TRUE;
1353 }
1354
1355 /***********************************************************************
1356  *              SetupDiEnumDeviceInfo (SETUPAPI.@)
1357  */
1358 BOOL WINAPI SetupDiEnumDeviceInfo(
1359         HDEVINFO  devinfo,
1360         DWORD  index,
1361         PSP_DEVINFO_DATA info)
1362 {
1363     BOOL ret = FALSE;
1364
1365     TRACE("%p %d %p\n", devinfo, index, info);
1366
1367     if(info==NULL)
1368     {
1369         SetLastError(ERROR_INVALID_PARAMETER);
1370         return FALSE;
1371     }
1372     if (devinfo && devinfo != (HDEVINFO)INVALID_HANDLE_VALUE)
1373     {
1374         struct DeviceInfoSet *list = (struct DeviceInfoSet *)devinfo;
1375         if (list->magic == SETUP_DEVICE_INFO_SET_MAGIC)
1376         {
1377             if (index < list->cDevices)
1378             {
1379                 if (info->cbSize == sizeof(SP_DEVINFO_DATA))
1380                 {
1381                     memcpy(info, &list->devices[index], info->cbSize);
1382                     ret = TRUE;
1383                 }
1384                 else
1385                     SetLastError(ERROR_INVALID_USER_BUFFER);
1386             }
1387             else
1388                 SetLastError(ERROR_NO_MORE_ITEMS);
1389         }
1390         else
1391             SetLastError(ERROR_INVALID_HANDLE);
1392     }
1393     else
1394         SetLastError(ERROR_INVALID_HANDLE);
1395     return ret;
1396 }
1397
1398 /***********************************************************************
1399  *              SetupDiGetDeviceInstanceIdA (SETUPAPI.@)
1400  */
1401 BOOL WINAPI SetupDiGetDeviceInstanceIdA(
1402         HDEVINFO DeviceInfoSet,
1403         PSP_DEVINFO_DATA DeviceInfoData,
1404         PSTR DeviceInstanceId,
1405         DWORD DeviceInstanceIdSize,
1406         PDWORD RequiredSize)
1407 {
1408     BOOL ret = FALSE;
1409     DWORD size;
1410     PWSTR instanceId;
1411
1412     TRACE("%p %p %p %d %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstanceId,
1413             DeviceInstanceIdSize, RequiredSize);
1414
1415     SetupDiGetDeviceInstanceIdW(DeviceInfoSet,
1416                                 DeviceInfoData,
1417                                 NULL,
1418                                 0,
1419                                 &size);
1420     if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
1421         return FALSE;
1422     instanceId = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
1423     if (instanceId)
1424     {
1425         ret = SetupDiGetDeviceInstanceIdW(DeviceInfoSet,
1426                                           DeviceInfoData,
1427                                           instanceId,
1428                                           size,
1429                                           &size);
1430         if (ret)
1431         {
1432             int len = WideCharToMultiByte(CP_ACP, 0, instanceId, -1,
1433                                           DeviceInstanceId,
1434                                           DeviceInstanceIdSize, NULL, NULL);
1435
1436             if (!len)
1437                 ret = FALSE;
1438             else
1439             {
1440                 if (len > DeviceInstanceIdSize)
1441                 {
1442                     SetLastError(ERROR_INSUFFICIENT_BUFFER);
1443                     ret = FALSE;
1444                 }
1445                 if (RequiredSize)
1446                     *RequiredSize = len;
1447             }
1448         }
1449         HeapFree(GetProcessHeap(), 0, instanceId);
1450     }
1451     return ret;
1452 }
1453
1454 /***********************************************************************
1455  *              SetupDiGetDeviceInstanceIdW (SETUPAPI.@)
1456  */
1457 BOOL WINAPI SetupDiGetDeviceInstanceIdW(
1458         HDEVINFO DeviceInfoSet,
1459         PSP_DEVINFO_DATA DeviceInfoData,
1460         PWSTR DeviceInstanceId,
1461         DWORD DeviceInstanceIdSize,
1462         PDWORD RequiredSize)
1463 {
1464     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
1465     struct DeviceInfo *devInfo;
1466
1467     TRACE("%p %p %p %d %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstanceId,
1468             DeviceInstanceIdSize, RequiredSize);
1469
1470     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
1471     {
1472         SetLastError(ERROR_INVALID_HANDLE);
1473         return FALSE;
1474     }
1475     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
1476     {
1477         SetLastError(ERROR_INVALID_HANDLE);
1478         return FALSE;
1479     }
1480     if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
1481             || !DeviceInfoData->Reserved)
1482     {
1483         SetLastError(ERROR_INVALID_PARAMETER);
1484         return FALSE;
1485     }
1486     devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
1487     TRACE("instance ID: %s\n", debugstr_w(devInfo->instanceId));
1488     if (DeviceInstanceIdSize < lstrlenW(devInfo->instanceId) + 1)
1489     {
1490         SetLastError(ERROR_INSUFFICIENT_BUFFER);
1491         if (RequiredSize)
1492             *RequiredSize = lstrlenW(devInfo->instanceId) + 1;
1493         return FALSE;
1494     }
1495     lstrcpyW(DeviceInstanceId, devInfo->instanceId);
1496     if (RequiredSize)
1497         *RequiredSize = lstrlenW(devInfo->instanceId) + 1;
1498     return TRUE;
1499 }
1500
1501 /***********************************************************************
1502  *              SetupDiGetActualSectionToInstallA (SETUPAPI.@)
1503  */
1504 BOOL WINAPI SetupDiGetActualSectionToInstallA(
1505         HINF InfHandle,
1506         PCSTR InfSectionName,
1507         PSTR InfSectionWithExt,
1508         DWORD InfSectionWithExtSize,
1509         PDWORD RequiredSize,
1510         PSTR *Extension)
1511 {
1512     FIXME("\n");
1513     return FALSE;
1514 }
1515
1516 /***********************************************************************
1517  *              SetupDiGetActualSectionToInstallW (SETUPAPI.@)
1518  */
1519 BOOL WINAPI SetupDiGetActualSectionToInstallW(
1520         HINF InfHandle,
1521         PCWSTR InfSectionName,
1522         PWSTR InfSectionWithExt,
1523         DWORD InfSectionWithExtSize,
1524         PDWORD RequiredSize,
1525         PWSTR *Extension)
1526 {
1527     WCHAR szBuffer[MAX_PATH];
1528     DWORD dwLength;
1529     DWORD dwFullLength;
1530     LONG lLineCount = -1;
1531
1532     lstrcpyW(szBuffer, InfSectionName);
1533     dwLength = lstrlenW(szBuffer);
1534
1535     if (OsVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
1536     {
1537         /* Test section name with '.NTx86' extension */
1538         lstrcpyW(&szBuffer[dwLength], NtPlatformExtension);
1539         lLineCount = SetupGetLineCountW(InfHandle, szBuffer);
1540
1541         if (lLineCount == -1)
1542         {
1543             /* Test section name with '.NT' extension */
1544             lstrcpyW(&szBuffer[dwLength], NtExtension);
1545             lLineCount = SetupGetLineCountW(InfHandle, szBuffer);
1546         }
1547     }
1548     else
1549     {
1550         /* Test section name with '.Win' extension */
1551         lstrcpyW(&szBuffer[dwLength], WinExtension);
1552         lLineCount = SetupGetLineCountW(InfHandle, szBuffer);
1553     }
1554
1555     if (lLineCount == -1)
1556     {
1557         /* Test section name without extension */
1558         szBuffer[dwLength] = 0;
1559         lLineCount = SetupGetLineCountW(InfHandle, szBuffer);
1560     }
1561
1562     if (lLineCount == -1)
1563     {
1564         SetLastError(ERROR_INVALID_PARAMETER);
1565         return FALSE;
1566     }
1567
1568     dwFullLength = lstrlenW(szBuffer);
1569
1570     if (InfSectionWithExt != NULL && InfSectionWithExtSize != 0)
1571     {
1572         if (InfSectionWithExtSize < (dwFullLength + 1))
1573         {
1574             SetLastError(ERROR_INSUFFICIENT_BUFFER);
1575             return FALSE;
1576         }
1577
1578         lstrcpyW(InfSectionWithExt, szBuffer);
1579         if (Extension != NULL)
1580         {
1581             *Extension = (dwLength == dwFullLength) ? NULL : &InfSectionWithExt[dwLength];
1582         }
1583     }
1584
1585     if (RequiredSize != NULL)
1586     {
1587         *RequiredSize = dwFullLength + 1;
1588     }
1589
1590     return TRUE;
1591 }
1592
1593 /***********************************************************************
1594  *              SetupDiGetClassDescriptionA  (SETUPAPI.@)
1595  */
1596 BOOL WINAPI SetupDiGetClassDescriptionA(
1597         const GUID* ClassGuid,
1598         PSTR ClassDescription,
1599         DWORD ClassDescriptionSize,
1600         PDWORD RequiredSize)
1601 {
1602   return SetupDiGetClassDescriptionExA(ClassGuid, ClassDescription,
1603                                        ClassDescriptionSize,
1604                                        RequiredSize, NULL, NULL);
1605 }
1606
1607 /***********************************************************************
1608  *              SetupDiGetClassDescriptionW  (SETUPAPI.@)
1609  */
1610 BOOL WINAPI SetupDiGetClassDescriptionW(
1611         const GUID* ClassGuid,
1612         PWSTR ClassDescription,
1613         DWORD ClassDescriptionSize,
1614         PDWORD RequiredSize)
1615 {
1616   return SetupDiGetClassDescriptionExW(ClassGuid, ClassDescription,
1617                                        ClassDescriptionSize,
1618                                        RequiredSize, NULL, NULL);
1619 }
1620
1621 /***********************************************************************
1622  *              SetupDiGetClassDescriptionExA  (SETUPAPI.@)
1623  */
1624 BOOL WINAPI SetupDiGetClassDescriptionExA(
1625         const GUID* ClassGuid,
1626         PSTR ClassDescription,
1627         DWORD ClassDescriptionSize,
1628         PDWORD RequiredSize,
1629         PCSTR MachineName,
1630         PVOID Reserved)
1631 {
1632     HKEY hKey;
1633     DWORD dwLength;
1634     BOOL ret;
1635
1636     hKey = SetupDiOpenClassRegKeyExA(ClassGuid,
1637                                      KEY_ALL_ACCESS,
1638                                      DIOCR_INSTALLER,
1639                                      MachineName,
1640                                      Reserved);
1641     if (hKey == INVALID_HANDLE_VALUE)
1642     {
1643         WARN("SetupDiOpenClassRegKeyExA() failed (Error %u)\n", GetLastError());
1644         return FALSE;
1645     }
1646
1647     dwLength = ClassDescriptionSize;
1648     ret = !RegQueryValueExA( hKey, NULL, NULL, NULL,
1649                              (LPBYTE)ClassDescription, &dwLength );
1650     if (RequiredSize) *RequiredSize = dwLength;
1651     RegCloseKey(hKey);
1652     return ret;
1653 }
1654
1655 /***********************************************************************
1656  *              SetupDiGetClassDescriptionExW  (SETUPAPI.@)
1657  */
1658 BOOL WINAPI SetupDiGetClassDescriptionExW(
1659         const GUID* ClassGuid,
1660         PWSTR ClassDescription,
1661         DWORD ClassDescriptionSize,
1662         PDWORD RequiredSize,
1663         PCWSTR MachineName,
1664         PVOID Reserved)
1665 {
1666     HKEY hKey;
1667     DWORD dwLength;
1668     BOOL ret;
1669
1670     hKey = SetupDiOpenClassRegKeyExW(ClassGuid,
1671                                      KEY_ALL_ACCESS,
1672                                      DIOCR_INSTALLER,
1673                                      MachineName,
1674                                      Reserved);
1675     if (hKey == INVALID_HANDLE_VALUE)
1676     {
1677         WARN("SetupDiOpenClassRegKeyExW() failed (Error %u)\n", GetLastError());
1678         return FALSE;
1679     }
1680
1681     dwLength = ClassDescriptionSize * sizeof(WCHAR);
1682     ret = !RegQueryValueExW( hKey, NULL, NULL, NULL,
1683                              (LPBYTE)ClassDescription, &dwLength );
1684     if (RequiredSize) *RequiredSize = dwLength / sizeof(WCHAR);
1685     RegCloseKey(hKey);
1686     return ret;
1687 }
1688
1689 /***********************************************************************
1690  *              SetupDiGetClassDevsA (SETUPAPI.@)
1691  */
1692 HDEVINFO WINAPI SetupDiGetClassDevsA(
1693        CONST GUID *class,
1694        LPCSTR enumstr,
1695        HWND parent,
1696        DWORD flags)
1697 {
1698     HDEVINFO ret;
1699     LPWSTR enumstrW = NULL;
1700
1701     if (enumstr)
1702     {
1703         int len = MultiByteToWideChar(CP_ACP, 0, enumstr, -1, NULL, 0);
1704         enumstrW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1705         if (!enumstrW)
1706         {
1707             ret = (HDEVINFO)INVALID_HANDLE_VALUE;
1708             goto end;
1709         }
1710         MultiByteToWideChar(CP_ACP, 0, enumstr, -1, enumstrW, len);
1711     }
1712     ret = SetupDiGetClassDevsW(class, enumstrW, parent, flags);
1713     HeapFree(GetProcessHeap(), 0, enumstrW);
1714
1715 end:
1716     return ret;
1717 }
1718
1719 static void SETUPDI_AddDeviceInterfaces(SP_DEVINFO_DATA *dev, HKEY key,
1720         const GUID *interface)
1721 {
1722     struct DeviceInfo *devInfo = (struct DeviceInfo *)dev->Reserved;
1723     DWORD i, len;
1724     WCHAR subKeyName[MAX_PATH];
1725     LONG l = ERROR_SUCCESS;
1726
1727     for (i = 0; !l; i++)
1728     {
1729         len = sizeof(subKeyName) / sizeof(subKeyName[0]);
1730         l = RegEnumKeyExW(key, i, subKeyName, &len, NULL, NULL, NULL, NULL);
1731         if (!l)
1732         {
1733             HKEY subKey;
1734             SP_DEVICE_INTERFACE_DATA *iface = NULL;
1735
1736             /* The subkey name is the reference string, with a '#' prepended */
1737             SETUPDI_AddInterfaceInstance(devInfo, interface, subKeyName + 1,
1738                     &iface);
1739             l = RegOpenKeyExW(key, subKeyName, 0, KEY_READ, &subKey);
1740             if (!l)
1741             {
1742                 WCHAR symbolicLink[MAX_PATH];
1743                 DWORD dataType;
1744
1745                 len = sizeof(symbolicLink);
1746                 l = RegQueryValueExW(subKey, SymbolicLink, NULL, &dataType,
1747                         (BYTE *)symbolicLink, &len);
1748                 if (!l && dataType == REG_SZ)
1749                     SETUPDI_SetInterfaceSymbolicLink(iface, symbolicLink);
1750                 RegCloseKey(subKey);
1751             }
1752         }
1753     }
1754     /* FIXME: find and add all the device's interfaces to the device */
1755 }
1756
1757 static void SETUPDI_EnumerateMatchingInterfaces(HDEVINFO DeviceInfoSet,
1758         HKEY key, const GUID *interface, LPCWSTR enumstr)
1759 {
1760     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
1761     DWORD i, len;
1762     WCHAR subKeyName[MAX_PATH];
1763     LONG l;
1764     HKEY enumKey = INVALID_HANDLE_VALUE;
1765
1766     TRACE("%s\n", debugstr_w(enumstr));
1767
1768     l = RegCreateKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, NULL, 0, KEY_READ, NULL,
1769             &enumKey, NULL);
1770     for (i = 0; !l; i++)
1771     {
1772         len = sizeof(subKeyName) / sizeof(subKeyName[0]);
1773         l = RegEnumKeyExW(key, i, subKeyName, &len, NULL, NULL, NULL, NULL);
1774         if (!l)
1775         {
1776             HKEY subKey;
1777
1778             l = RegOpenKeyExW(key, subKeyName, 0, KEY_READ, &subKey);
1779             if (!l)
1780             {
1781                 WCHAR deviceInst[MAX_PATH * 3];
1782                 DWORD dataType;
1783
1784                 len = sizeof(deviceInst);
1785                 l = RegQueryValueExW(subKey, DeviceInstance, NULL, &dataType,
1786                         (BYTE *)deviceInst, &len);
1787                 if (!l && dataType == REG_SZ)
1788                 {
1789                     TRACE("found instance ID %s\n", debugstr_w(deviceInst));
1790                     if (!enumstr || !lstrcmpiW(enumstr, deviceInst))
1791                     {
1792                         HKEY deviceKey;
1793
1794                         l = RegOpenKeyExW(enumKey, deviceInst, 0, KEY_READ,
1795                                 &deviceKey);
1796                         if (!l)
1797                         {
1798                             WCHAR deviceClassStr[40];
1799
1800                             len = sizeof(deviceClassStr);
1801                             l = RegQueryValueExW(deviceKey, ClassGUID, NULL,
1802                                     &dataType, (BYTE *)deviceClassStr, &len);
1803                             if (!l && dataType == REG_SZ &&
1804                                     deviceClassStr[0] == '{' &&
1805                                     deviceClassStr[37] == '}')
1806                             {
1807                                 GUID deviceClass;
1808                                 SP_DEVINFO_DATA *dev;
1809
1810                                 deviceClassStr[37] = 0;
1811                                 UuidFromStringW(&deviceClassStr[1],
1812                                         &deviceClass);
1813                                 if (SETUPDI_AddDeviceToSet(set, &deviceClass,
1814                                         0 /* FIXME: DevInst */, deviceInst,
1815                                         FALSE, &dev))
1816                                     SETUPDI_AddDeviceInterfaces(dev, subKey,
1817                                             interface);
1818                             }
1819                             RegCloseKey(deviceKey);
1820                         }
1821                     }
1822                 }
1823                 RegCloseKey(subKey);
1824             }
1825         }
1826     }
1827     if (enumKey != INVALID_HANDLE_VALUE)
1828         RegCloseKey(enumKey);
1829 }
1830
1831 static void SETUPDI_EnumerateInterfaces(HDEVINFO DeviceInfoSet,
1832         const GUID *interface, LPCWSTR enumstr, DWORD flags)
1833 {
1834     HKEY interfacesKey = SetupDiOpenClassRegKeyExW(interface, KEY_READ,
1835             DIOCR_INTERFACE, NULL, NULL);
1836
1837     TRACE("%p, %s, %s, %08x\n", DeviceInfoSet, debugstr_guid(interface),
1838             debugstr_w(enumstr), flags);
1839
1840     if (interfacesKey != INVALID_HANDLE_VALUE)
1841     {
1842         if (flags & DIGCF_ALLCLASSES)
1843         {
1844             DWORD i, len;
1845             WCHAR interfaceGuidStr[40];
1846             LONG l = ERROR_SUCCESS;
1847
1848             for (i = 0; !l; i++)
1849             {
1850                 len = sizeof(interfaceGuidStr) / sizeof(interfaceGuidStr[0]);
1851                 l = RegEnumKeyExW(interfacesKey, i, interfaceGuidStr, &len,
1852                         NULL, NULL, NULL, NULL);
1853                 if (!l)
1854                 {
1855                     if (interfaceGuidStr[0] == '{' &&
1856                             interfaceGuidStr[37] == '}')
1857                     {
1858                         HKEY interfaceKey;
1859                         GUID interfaceGuid;
1860
1861                         interfaceGuidStr[37] = 0;
1862                         UuidFromStringW(&interfaceGuidStr[1], &interfaceGuid);
1863                         l = RegOpenKeyExW(interfacesKey, interfaceGuidStr, 0,
1864                                 KEY_READ, &interfaceKey);
1865                         if (!l)
1866                         {
1867                             SETUPDI_EnumerateMatchingInterfaces(DeviceInfoSet,
1868                                     interfaceKey, &interfaceGuid, enumstr);
1869                             RegCloseKey(interfaceKey);
1870                         }
1871                     }
1872                 }
1873             }
1874         }
1875         else
1876         {
1877             /* In this case, SetupDiOpenClassRegKeyExW opened the specific
1878              * interface's key, so just pass that long
1879              */
1880             SETUPDI_EnumerateMatchingInterfaces(DeviceInfoSet,
1881                     interfacesKey, interface, enumstr);
1882         }
1883         RegCloseKey(interfacesKey);
1884     }
1885 }
1886
1887 static void SETUPDI_EnumerateMatchingDevices(HDEVINFO DeviceInfoSet,
1888         LPCWSTR parent, HKEY key, const GUID *class, DWORD flags)
1889 {
1890     struct DeviceInfoSet *set = (struct DeviceInfoSet *)set;
1891     DWORD i, len;
1892     WCHAR subKeyName[MAX_PATH];
1893     LONG l = ERROR_SUCCESS;
1894
1895     TRACE("%s\n", debugstr_w(parent));
1896
1897     for (i = 0; !l; i++)
1898     {
1899         len = sizeof(subKeyName) / sizeof(subKeyName[0]);
1900         l = RegEnumKeyExW(key, i, subKeyName, &len, NULL, NULL, NULL, NULL);
1901         if (!l)
1902         {
1903             HKEY subKey;
1904
1905             l = RegOpenKeyExW(key, subKeyName, 0, KEY_READ, &subKey);
1906             if (!l)
1907             {
1908                 WCHAR classGuid[40];
1909                 DWORD dataType;
1910
1911                 len = sizeof(classGuid);
1912                 l = RegQueryValueExW(subKey, ClassGUID, NULL, &dataType,
1913                         (BYTE *)classGuid, &len);
1914                 if (!l && dataType == REG_SZ)
1915                 {
1916                     if (classGuid[0] == '{' && classGuid[37] == '}')
1917                     {
1918                         GUID deviceClass;
1919
1920                         classGuid[37] = 0;
1921                         UuidFromStringW(&classGuid[1], &deviceClass);
1922                         if ((flags & DIGCF_ALLCLASSES) ||
1923                                 IsEqualGUID(class, &deviceClass))
1924                         {
1925                             static const WCHAR fmt[] = {'%','s','\\','%','s',0};
1926                             LPWSTR instanceId;
1927
1928                             instanceId = HeapAlloc(GetProcessHeap(), 0,
1929                                 (lstrlenW(parent) + lstrlenW(subKeyName) + 2)
1930                                 * sizeof(WCHAR));
1931                             if (instanceId)
1932                             {
1933                                 SP_DEVINFO_DATA *dev;
1934
1935                                 sprintfW(instanceId, fmt, parent, subKeyName);
1936                                 SETUPDI_AddDeviceToSet(set, &deviceClass,
1937                                         0 /* FIXME: DevInst */, instanceId,
1938                                         FALSE, &dev);
1939                                 HeapFree(GetProcessHeap(), 0, instanceId);
1940                             }
1941                         }
1942                     }
1943                 }
1944                 RegCloseKey(subKey);
1945             }
1946         }
1947     }
1948 }
1949
1950 static void SETUPDI_EnumerateDevices(HDEVINFO DeviceInfoSet, const GUID *class,
1951         LPCWSTR enumstr, DWORD flags)
1952 {
1953     HKEY classesKey = SetupDiOpenClassRegKeyExW(class, KEY_READ,
1954             DIOCR_INSTALLER, NULL, NULL);
1955
1956     TRACE("%p, %s, %s, %08x\n", DeviceInfoSet, debugstr_guid(class),
1957             debugstr_w(enumstr), flags);
1958
1959     if (classesKey != INVALID_HANDLE_VALUE)
1960     {
1961         if (enumstr)
1962         {
1963             HKEY enumKey;
1964             LONG l = RegOpenKeyExW(classesKey, enumstr, 0, KEY_READ,
1965                     &enumKey);
1966
1967             if (!l)
1968             {
1969                 SETUPDI_EnumerateMatchingDevices(DeviceInfoSet, enumstr,
1970                         enumKey, class, flags);
1971                 RegCloseKey(enumKey);
1972             }
1973         }
1974         else
1975         {
1976             DWORD i, len;
1977             WCHAR subKeyName[MAX_PATH];
1978             LONG l = ERROR_SUCCESS;
1979
1980             for (i = 0; !l; i++)
1981             {
1982                 len = sizeof(subKeyName) / sizeof(subKeyName[0]);
1983                 l = RegEnumKeyExW(classesKey, i, subKeyName, &len, NULL,
1984                         NULL, NULL, NULL);
1985                 if (!l)
1986                 {
1987                     HKEY subKey;
1988
1989                     l = RegOpenKeyExW(classesKey, subKeyName, 0, KEY_READ,
1990                             &subKey);
1991                     if (!l)
1992                     {
1993                         SETUPDI_EnumerateMatchingDevices(DeviceInfoSet,
1994                                 subKeyName, subKey, class, flags);
1995                         RegCloseKey(subKey);
1996                     }
1997                 }
1998             }
1999         }
2000         RegCloseKey(classesKey);
2001     }
2002 }
2003
2004 /***********************************************************************
2005  *              SetupDiGetClassDevsW (SETUPAPI.@)
2006  */
2007 HDEVINFO WINAPI SetupDiGetClassDevsW(
2008        CONST GUID *class,
2009        LPCWSTR enumstr,
2010        HWND parent,
2011        DWORD flags)
2012 {
2013     static const DWORD unsupportedFlags = DIGCF_DEFAULT | DIGCF_PRESENT |
2014         DIGCF_PROFILE;
2015     HDEVINFO set;
2016
2017     TRACE("%s %s %p 0x%08x\n", debugstr_guid(class), debugstr_w(enumstr), parent, flags);
2018
2019     if (!(flags & DIGCF_ALLCLASSES) && !class)
2020     {
2021         SetLastError(ERROR_INVALID_PARAMETER);
2022         return NULL;
2023     }
2024     if (flags & unsupportedFlags)
2025         WARN("unsupported flags %08x\n", flags & unsupportedFlags);
2026     /* WinXP always succeeds, returns empty list for unknown classes */
2027     set = SetupDiCreateDeviceInfoList(class, parent);
2028     if (set)
2029     {
2030         if (flags & DIGCF_DEVICEINTERFACE)
2031             SETUPDI_EnumerateInterfaces(set, class, enumstr, flags);
2032         else
2033             SETUPDI_EnumerateDevices(set, class, enumstr, flags);
2034     }
2035     return set;
2036 }
2037
2038 /***********************************************************************
2039  *              SetupDiGetClassDevsExW (SETUPAPI.@)
2040  */
2041 HDEVINFO WINAPI SetupDiGetClassDevsExW(
2042         CONST GUID *class,
2043         PCWSTR enumstr,
2044         HWND parent,
2045         DWORD flags,
2046         HDEVINFO deviceset,
2047         PCWSTR machine,
2048         PVOID reserved)
2049 {
2050     FIXME("stub\n");
2051     return NULL;
2052 }
2053
2054 /***********************************************************************
2055  *              SetupDiCreateDeviceInterfaceA (SETUPAPI.@)
2056  */
2057 BOOL WINAPI SetupDiCreateDeviceInterfaceA(
2058         HDEVINFO DeviceInfoSet,
2059         PSP_DEVINFO_DATA DeviceInfoData,
2060         const GUID *InterfaceClassGuid,
2061         PCSTR ReferenceString,
2062         DWORD CreationFlags,
2063         PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
2064 {
2065     BOOL ret;
2066     LPWSTR ReferenceStringW = NULL;
2067
2068     TRACE("%p %p %s %s %08x %p\n", DeviceInfoSet, DeviceInfoData,
2069             debugstr_guid(InterfaceClassGuid), debugstr_a(ReferenceString),
2070             CreationFlags, DeviceInterfaceData);
2071
2072     if (ReferenceString)
2073     {
2074         ReferenceStringW = MultiByteToUnicode(ReferenceString, CP_ACP);
2075         if (ReferenceStringW == NULL) return FALSE;
2076     }
2077
2078     ret = SetupDiCreateDeviceInterfaceW(DeviceInfoSet, DeviceInfoData,
2079             InterfaceClassGuid, ReferenceStringW, CreationFlags,
2080             DeviceInterfaceData);
2081
2082     MyFree(ReferenceStringW);
2083
2084     return ret;
2085 }
2086
2087 /***********************************************************************
2088  *              SetupDiCreateDeviceInterfaceW (SETUPAPI.@)
2089  */
2090 BOOL WINAPI SetupDiCreateDeviceInterfaceW(
2091         HDEVINFO DeviceInfoSet,
2092         PSP_DEVINFO_DATA DeviceInfoData,
2093         const GUID *InterfaceClassGuid,
2094         PCWSTR ReferenceString,
2095         DWORD CreationFlags,
2096         PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
2097 {
2098     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2099     struct DeviceInfo *devInfo;
2100     SP_DEVICE_INTERFACE_DATA *iface = NULL;
2101     BOOL ret;
2102
2103     TRACE("%p %p %s %s %08x %p\n", DeviceInfoSet, DeviceInfoData,
2104             debugstr_guid(InterfaceClassGuid), debugstr_w(ReferenceString),
2105             CreationFlags, DeviceInterfaceData);
2106
2107     if (!DeviceInfoSet || DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
2108     {
2109         SetLastError(ERROR_INVALID_HANDLE);
2110         return FALSE;
2111     }
2112     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2113     {
2114         SetLastError(ERROR_INVALID_HANDLE);
2115         return FALSE;
2116     }
2117     if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
2118             || !DeviceInfoData->Reserved)
2119     {
2120         SetLastError(ERROR_INVALID_PARAMETER);
2121         return FALSE;
2122     }
2123     if (!InterfaceClassGuid)
2124     {
2125         SetLastError(ERROR_INVALID_USER_BUFFER);
2126         return FALSE;
2127     }
2128     devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
2129     if ((ret = SETUPDI_AddInterfaceInstance(devInfo, InterfaceClassGuid,
2130                     ReferenceString, &iface)))
2131     {
2132         if (DeviceInterfaceData)
2133         {
2134             if (DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA))
2135             {
2136                 SetLastError(ERROR_INVALID_USER_BUFFER);
2137                 ret = FALSE;
2138             }
2139             else
2140                 memcpy(DeviceInterfaceData, iface, sizeof(*iface));
2141         }
2142     }
2143     return ret;
2144 }
2145
2146 /***********************************************************************
2147  *              SetupDiEnumDeviceInterfaces (SETUPAPI.@)
2148  *
2149  * PARAMS
2150  *   DeviceInfoSet      [I]    Set of devices from which to enumerate
2151  *                             interfaces
2152  *   DeviceInfoData     [I]    (Optional) If specified, a specific device
2153  *                             instance from which to enumerate interfaces.
2154  *                             If it isn't specified, all interfaces for all
2155  *                             devices in the set are enumerated.
2156  *   InterfaceClassGuid [I]    The interface class to enumerate.
2157  *   MemberIndex        [I]    An index of the interface instance to enumerate.
2158  *                             A caller should start with MemberIndex set to 0,
2159  *                             and continue until the function fails with
2160  *                             ERROR_NO_MORE_ITEMS.
2161  *   DeviceInterfaceData [I/O] Returns an enumerated interface.  Its cbSize
2162  *                             member must be set to
2163  *                             sizeof(SP_DEVICE_INTERFACE_DATA).
2164  *
2165  * RETURNS
2166  *   Success: non-zero value.
2167  *   Failure: FALSE.  Call GetLastError() for more info.
2168  */
2169 BOOL WINAPI SetupDiEnumDeviceInterfaces(
2170        HDEVINFO DeviceInfoSet,
2171        PSP_DEVINFO_DATA DeviceInfoData,
2172        CONST GUID * InterfaceClassGuid,
2173        DWORD MemberIndex,
2174        PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
2175 {
2176     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2177     BOOL ret = FALSE;
2178
2179     TRACE("%p, %p, %s, %d, %p\n", DeviceInfoSet, DeviceInfoData,
2180      debugstr_guid(InterfaceClassGuid), MemberIndex, DeviceInterfaceData);
2181
2182     if (!DeviceInfoSet || DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE ||
2183             set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2184     {
2185         SetLastError(ERROR_INVALID_HANDLE);
2186         return FALSE;
2187     }
2188     if (DeviceInfoData && (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA) ||
2189                 !DeviceInfoData->Reserved))
2190     {
2191         SetLastError(ERROR_INVALID_PARAMETER);
2192         return FALSE;
2193     }
2194     if (!DeviceInterfaceData ||
2195             DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA))
2196     {
2197         SetLastError(ERROR_INVALID_PARAMETER);
2198         return FALSE;
2199     }
2200     if (DeviceInfoData)
2201     {
2202         struct DeviceInfo *devInfo =
2203             (struct DeviceInfo *)DeviceInfoData->Reserved;
2204         DWORD i;
2205
2206         if ((ret = SETUPDI_FindInterface(devInfo, InterfaceClassGuid, &i)))
2207         {
2208             if (MemberIndex < devInfo->interfaces[i].cInstances)
2209                 memcpy(DeviceInterfaceData,
2210                     &devInfo->interfaces[i].instances[MemberIndex],
2211                     sizeof(SP_DEVICE_INTERFACE_DATA));
2212             else
2213             {
2214                 SetLastError(ERROR_NO_MORE_ITEMS);
2215                 ret = FALSE;
2216             }
2217         }
2218         else
2219             SetLastError(ERROR_NO_MORE_ITEMS);
2220     }
2221     else
2222     {
2223         DWORD i, cEnumerated = 0;
2224         BOOL found = FALSE;
2225
2226         for (i = 0; !found && cEnumerated < MemberIndex + 1 &&
2227                 i < set->cDevices; i++)
2228         {
2229             struct DeviceInfo *devInfo =
2230                 (struct DeviceInfo *)set->devices[i].Reserved;
2231             DWORD interfaceIndex;
2232
2233             if (SETUPDI_FindInterface(devInfo, InterfaceClassGuid,
2234                         &interfaceIndex))
2235             {
2236                 struct InterfaceInstances *interface =
2237                     &devInfo->interfaces[interfaceIndex];
2238
2239                 if (cEnumerated + interface->cInstances < MemberIndex + 1)
2240                     cEnumerated += interface->cInstances;
2241                 else
2242                 {
2243                     DWORD instanceIndex = MemberIndex - cEnumerated;
2244
2245                     memcpy(DeviceInterfaceData,
2246                             &interface->instances[instanceIndex],
2247                             sizeof(SP_DEVICE_INTERFACE_DATA));
2248                     cEnumerated += instanceIndex + 1;
2249                     found = TRUE;
2250                     ret = TRUE;
2251                 }
2252             }
2253         }
2254         if (!found)
2255             SetLastError(ERROR_NO_MORE_ITEMS);
2256     }
2257     return ret;
2258 }
2259
2260 /***********************************************************************
2261  *              SetupDiDestroyDeviceInfoList (SETUPAPI.@)
2262   *
2263  * Destroy a DeviceInfoList and free all used memory of the list.
2264  *
2265  * PARAMS
2266  *   devinfo [I] DeviceInfoList pointer to list to destroy
2267  *
2268  * RETURNS
2269  *   Success: non zero value.
2270  *   Failure: zero value.
2271  */
2272 BOOL WINAPI SetupDiDestroyDeviceInfoList(HDEVINFO devinfo)
2273 {
2274     BOOL ret = FALSE;
2275
2276     TRACE("%p\n", devinfo);
2277     if (devinfo && devinfo != (HDEVINFO)INVALID_HANDLE_VALUE)
2278     {
2279         struct DeviceInfoSet *list = (struct DeviceInfoSet *)devinfo;
2280
2281         if (list->magic == SETUP_DEVICE_INFO_SET_MAGIC)
2282         {
2283             DWORD i;
2284
2285             for (i = 0; i < list->cDevices; i++)
2286                 SETUPDI_FreeDeviceInfo(
2287                         (struct DeviceInfo *)list->devices[i].Reserved);
2288             HeapFree(GetProcessHeap(), 0, list->devices);
2289             HeapFree(GetProcessHeap(), 0, list);
2290             ret = TRUE;
2291         }
2292     }
2293
2294     if (ret == FALSE)
2295         SetLastError(ERROR_INVALID_HANDLE);
2296
2297     return ret;
2298 }
2299
2300 /***********************************************************************
2301  *              SetupDiGetDeviceInterfaceDetailA (SETUPAPI.@)
2302  */
2303 BOOL WINAPI SetupDiGetDeviceInterfaceDetailA(
2304       HDEVINFO DeviceInfoSet,
2305       PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
2306       PSP_DEVICE_INTERFACE_DETAIL_DATA_A DeviceInterfaceDetailData,
2307       DWORD DeviceInterfaceDetailDataSize,
2308       PDWORD RequiredSize,
2309       PSP_DEVINFO_DATA DeviceInfoData)
2310 {
2311     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2312     struct InterfaceInfo *info;
2313     DWORD bytesNeeded = offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath)
2314         + 1;
2315     BOOL ret = FALSE;
2316
2317     TRACE("(%p, %p, %p, %d, %p, %p)\n", DeviceInfoSet,
2318      DeviceInterfaceData, DeviceInterfaceDetailData,
2319      DeviceInterfaceDetailDataSize, RequiredSize, DeviceInfoData);
2320
2321     if (!DeviceInfoSet || DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE ||
2322             set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2323     {
2324         SetLastError(ERROR_INVALID_HANDLE);
2325         return FALSE;
2326     }
2327     if (!DeviceInterfaceData ||
2328             DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA) ||
2329             !DeviceInterfaceData->Reserved)
2330     {
2331         SetLastError(ERROR_INVALID_PARAMETER);
2332         return FALSE;
2333     }
2334     if (DeviceInterfaceDetailData && (DeviceInterfaceDetailData->cbSize <
2335             offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath) + sizeof(char) ||
2336             DeviceInterfaceDetailData->cbSize > sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A)))
2337     {
2338         SetLastError(ERROR_INVALID_USER_BUFFER);
2339         return FALSE;
2340     }
2341     if (!DeviceInterfaceDetailData && DeviceInterfaceDetailDataSize)
2342     {
2343         SetLastError(ERROR_INVALID_USER_BUFFER);
2344         return FALSE;
2345     }
2346     info = (struct InterfaceInfo *)DeviceInterfaceData->Reserved;
2347     if (info->symbolicLink)
2348         bytesNeeded += WideCharToMultiByte(CP_ACP, 0, info->symbolicLink, -1,
2349                 NULL, 0, NULL, NULL);
2350     if (DeviceInterfaceDetailDataSize >= bytesNeeded)
2351     {
2352         if (info->symbolicLink)
2353             WideCharToMultiByte(CP_ACP, 0, info->symbolicLink, -1,
2354                     DeviceInterfaceDetailData->DevicePath,
2355                     DeviceInterfaceDetailDataSize -
2356                     offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath),
2357                     NULL, NULL);
2358         else
2359             DeviceInterfaceDetailData->DevicePath[0] = '\0';
2360         ret = TRUE;
2361     }
2362     else
2363     {
2364         if (RequiredSize)
2365             *RequiredSize = bytesNeeded;
2366         SetLastError(ERROR_INSUFFICIENT_BUFFER);
2367     }
2368     return ret;
2369 }
2370
2371 /***********************************************************************
2372  *              SetupDiGetDeviceInterfaceDetailW (SETUPAPI.@)
2373  */
2374 BOOL WINAPI SetupDiGetDeviceInterfaceDetailW(
2375       HDEVINFO DeviceInfoSet,
2376       PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
2377       PSP_DEVICE_INTERFACE_DETAIL_DATA_W DeviceInterfaceDetailData,
2378       DWORD DeviceInterfaceDetailDataSize,
2379       PDWORD RequiredSize,
2380       PSP_DEVINFO_DATA DeviceInfoData)
2381 {
2382     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2383     struct InterfaceInfo *info;
2384     DWORD bytesNeeded = offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath)
2385         + sizeof(WCHAR); /* include NULL terminator */
2386     BOOL ret = FALSE;
2387
2388     TRACE("(%p, %p, %p, %d, %p, %p)\n", DeviceInfoSet,
2389      DeviceInterfaceData, DeviceInterfaceDetailData,
2390      DeviceInterfaceDetailDataSize, RequiredSize, DeviceInfoData);
2391
2392     if (!DeviceInfoSet || DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE ||
2393             set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2394     {
2395         SetLastError(ERROR_INVALID_HANDLE);
2396         return FALSE;
2397     }
2398     if (!DeviceInterfaceData ||
2399             DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA) ||
2400             !DeviceInterfaceData->Reserved)
2401     {
2402         SetLastError(ERROR_INVALID_PARAMETER);
2403         return FALSE;
2404     }
2405     if (DeviceInterfaceDetailData && (DeviceInterfaceDetailData->cbSize <
2406             offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath) + sizeof(WCHAR) ||
2407             DeviceInterfaceDetailData->cbSize > sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W)))
2408     {
2409         SetLastError(ERROR_INVALID_USER_BUFFER);
2410         return FALSE;
2411     }
2412     if (!DeviceInterfaceDetailData && DeviceInterfaceDetailDataSize)
2413     {
2414         SetLastError(ERROR_INVALID_USER_BUFFER);
2415         return FALSE;
2416     }
2417     info = (struct InterfaceInfo *)DeviceInterfaceData->Reserved;
2418     if (info->symbolicLink)
2419         bytesNeeded += lstrlenW(info->symbolicLink);
2420     if (DeviceInterfaceDetailDataSize >= bytesNeeded)
2421     {
2422         if (info->symbolicLink)
2423             lstrcpyW(DeviceInterfaceDetailData->DevicePath, info->symbolicLink);
2424         else
2425             DeviceInterfaceDetailData->DevicePath[0] = '\0';
2426         ret = TRUE;
2427     }
2428     else
2429     {
2430         if (RequiredSize)
2431             *RequiredSize = bytesNeeded;
2432         SetLastError(ERROR_INSUFFICIENT_BUFFER);
2433     }
2434     return ret;
2435 }
2436
2437 struct PropertyMapEntry
2438 {
2439     DWORD   regType;
2440     LPCSTR  nameA;
2441     LPCWSTR nameW;
2442 };
2443
2444 static struct PropertyMapEntry PropertyMap[] = {
2445     { REG_SZ, "DeviceDesc", DeviceDesc },
2446     { REG_MULTI_SZ, "HardwareId", HardwareId },
2447     { REG_MULTI_SZ, "CompatibleIDs", CompatibleIDs },
2448     { 0, NULL, NULL }, /* SPDRP_UNUSED0 */
2449     { REG_SZ, "Service", Service },
2450     { 0, NULL, NULL }, /* SPDRP_UNUSED1 */
2451     { 0, NULL, NULL }, /* SPDRP_UNUSED2 */
2452     { REG_SZ, "Class", Class },
2453     { REG_SZ, "ClassGUID", ClassGUID },
2454     { REG_SZ, "Driver", Driver },
2455     { REG_DWORD, "ConfigFlags", ConfigFlags },
2456     { REG_SZ, "Mfg", Mfg },
2457     { REG_SZ, "FriendlyName", FriendlyName },
2458     { REG_SZ, "LocationInformation", LocationInformation },
2459     { 0, NULL, NULL }, /* SPDRP_PHYSICAL_DEVICE_OBJECT_NAME */
2460     { REG_DWORD, "Capabilities", Capabilities },
2461     { REG_DWORD, "UINumber", UINumber },
2462     { REG_MULTI_SZ, "UpperFilters", UpperFilters },
2463     { REG_MULTI_SZ, "LowerFilters", LowerFilters },
2464 };
2465
2466 /***********************************************************************
2467  *              SetupDiGetDeviceRegistryPropertyA (SETUPAPI.@)
2468  */
2469 BOOL WINAPI SetupDiGetDeviceRegistryPropertyA(
2470         HDEVINFO  DeviceInfoSet,
2471         PSP_DEVINFO_DATA  DeviceInfoData,
2472         DWORD   Property,
2473         PDWORD  PropertyRegDataType,
2474         PBYTE   PropertyBuffer,
2475         DWORD   PropertyBufferSize,
2476         PDWORD  RequiredSize)
2477 {
2478     BOOL ret = FALSE;
2479     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2480     struct DeviceInfo *devInfo;
2481
2482     TRACE("%04x %p %d %p %p %d %p\n", (DWORD)DeviceInfoSet, DeviceInfoData,
2483         Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize,
2484         RequiredSize);
2485
2486     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
2487     {
2488         SetLastError(ERROR_INVALID_HANDLE);
2489         return FALSE;
2490     }
2491     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2492     {
2493         SetLastError(ERROR_INVALID_HANDLE);
2494         return FALSE;
2495     }
2496     if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
2497             || !DeviceInfoData->Reserved)
2498     {
2499         SetLastError(ERROR_INVALID_PARAMETER);
2500         return FALSE;
2501     }
2502     devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
2503     if (Property < sizeof(PropertyMap) / sizeof(PropertyMap[0])
2504         && PropertyMap[Property].nameA)
2505     {
2506         DWORD size = PropertyBufferSize;
2507         LONG l = RegQueryValueExA(devInfo->key, PropertyMap[Property].nameA,
2508                 NULL, PropertyRegDataType, PropertyBuffer, &size);
2509
2510         if (RequiredSize)
2511             *RequiredSize = size;
2512         if (!l)
2513             ret = TRUE;
2514         else
2515             SetLastError(l);
2516     }
2517     return ret;
2518 }
2519
2520 /***********************************************************************
2521  *              SetupDiGetDeviceRegistryPropertyW (SETUPAPI.@)
2522  */
2523 BOOL WINAPI SetupDiGetDeviceRegistryPropertyW(
2524         HDEVINFO  DeviceInfoSet,
2525         PSP_DEVINFO_DATA  DeviceInfoData,
2526         DWORD   Property,
2527         PDWORD  PropertyRegDataType,
2528         PBYTE   PropertyBuffer,
2529         DWORD   PropertyBufferSize,
2530         PDWORD  RequiredSize)
2531 {
2532     BOOL ret = FALSE;
2533     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2534     struct DeviceInfo *devInfo;
2535
2536     TRACE("%04x %p %d %p %p %d %p\n", (DWORD)DeviceInfoSet, DeviceInfoData,
2537         Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize,
2538         RequiredSize);
2539
2540     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
2541     {
2542         SetLastError(ERROR_INVALID_HANDLE);
2543         return FALSE;
2544     }
2545     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2546     {
2547         SetLastError(ERROR_INVALID_HANDLE);
2548         return FALSE;
2549     }
2550     if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
2551             || !DeviceInfoData->Reserved)
2552     {
2553         SetLastError(ERROR_INVALID_PARAMETER);
2554         return FALSE;
2555     }
2556     devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
2557     if (Property < sizeof(PropertyMap) / sizeof(PropertyMap[0])
2558         && PropertyMap[Property].nameW)
2559     {
2560         DWORD size = PropertyBufferSize;
2561         LONG l = RegQueryValueExW(devInfo->key, PropertyMap[Property].nameW,
2562                 NULL, PropertyRegDataType, PropertyBuffer, &size);
2563
2564         if (RequiredSize)
2565             *RequiredSize = size;
2566         if (!l)
2567             ret = TRUE;
2568         else
2569             SetLastError(l);
2570     }
2571     return ret;
2572 }
2573
2574 /***********************************************************************
2575  *              SetupDiSetDeviceRegistryPropertyA (SETUPAPI.@)
2576  */
2577 BOOL WINAPI SetupDiSetDeviceRegistryPropertyA(
2578         HDEVINFO DeviceInfoSet,
2579         PSP_DEVINFO_DATA DeviceInfoData,
2580         DWORD Property,
2581         const BYTE *PropertyBuffer,
2582         DWORD PropertyBufferSize)
2583 {
2584     BOOL ret = FALSE;
2585     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2586     struct DeviceInfo *devInfo;
2587
2588     TRACE("%p %p %d %p %d\n", DeviceInfoSet, DeviceInfoData, Property,
2589         PropertyBuffer, PropertyBufferSize);
2590
2591     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
2592     {
2593         SetLastError(ERROR_INVALID_HANDLE);
2594         return FALSE;
2595     }
2596     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2597     {
2598         SetLastError(ERROR_INVALID_HANDLE);
2599         return FALSE;
2600     }
2601     if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
2602             || !DeviceInfoData->Reserved)
2603     {
2604         SetLastError(ERROR_INVALID_PARAMETER);
2605         return FALSE;
2606     }
2607     devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
2608     if (Property < sizeof(PropertyMap) / sizeof(PropertyMap[0])
2609         && PropertyMap[Property].nameA)
2610     {
2611         LONG l = RegSetValueExA(devInfo->key, PropertyMap[Property].nameA, 0,
2612                 PropertyMap[Property].regType, PropertyBuffer,
2613                 PropertyBufferSize);
2614         if (!l)
2615             ret = TRUE;
2616         else
2617             SetLastError(l);
2618     }
2619     return ret;
2620 }
2621
2622 /***********************************************************************
2623  *              SetupDiSetDeviceRegistryPropertyW (SETUPAPI.@)
2624  */
2625 BOOL WINAPI SetupDiSetDeviceRegistryPropertyW(
2626         HDEVINFO DeviceInfoSet,
2627         PSP_DEVINFO_DATA DeviceInfoData,
2628         DWORD Property,
2629         const BYTE *PropertyBuffer,
2630         DWORD PropertyBufferSize)
2631 {
2632     BOOL ret = FALSE;
2633     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2634     struct DeviceInfo *devInfo;
2635
2636     TRACE("%p %p %d %p %d\n", DeviceInfoSet, DeviceInfoData, Property,
2637         PropertyBuffer, PropertyBufferSize);
2638
2639     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
2640     {
2641         SetLastError(ERROR_INVALID_HANDLE);
2642         return FALSE;
2643     }
2644     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2645     {
2646         SetLastError(ERROR_INVALID_HANDLE);
2647         return FALSE;
2648     }
2649     if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
2650             || !DeviceInfoData->Reserved)
2651     {
2652         SetLastError(ERROR_INVALID_PARAMETER);
2653         return FALSE;
2654     }
2655     devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
2656     if (Property < sizeof(PropertyMap) / sizeof(PropertyMap[0])
2657         && PropertyMap[Property].nameW)
2658     {
2659         LONG l = RegSetValueExW(devInfo->key, PropertyMap[Property].nameW, 0,
2660                 PropertyMap[Property].regType, PropertyBuffer,
2661                 PropertyBufferSize);
2662         if (!l)
2663             ret = TRUE;
2664         else
2665             SetLastError(l);
2666     }
2667     return ret;
2668 }
2669
2670 /***********************************************************************
2671  *              SetupDiInstallClassA (SETUPAPI.@)
2672  */
2673 BOOL WINAPI SetupDiInstallClassA(
2674         HWND hwndParent,
2675         PCSTR InfFileName,
2676         DWORD Flags,
2677         HSPFILEQ FileQueue)
2678 {
2679     UNICODE_STRING FileNameW;
2680     BOOL Result;
2681
2682     if (!RtlCreateUnicodeStringFromAsciiz(&FileNameW, InfFileName))
2683     {
2684         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2685         return FALSE;
2686     }
2687
2688     Result = SetupDiInstallClassW(hwndParent, FileNameW.Buffer, Flags, FileQueue);
2689
2690     RtlFreeUnicodeString(&FileNameW);
2691
2692     return Result;
2693 }
2694
2695 static HKEY CreateClassKey(HINF hInf)
2696 {
2697     WCHAR FullBuffer[MAX_PATH];
2698     WCHAR Buffer[MAX_PATH];
2699     DWORD RequiredSize;
2700     HKEY hClassKey;
2701
2702     if (!SetupGetLineTextW(NULL,
2703                            hInf,
2704                            Version,
2705                            ClassGUID,
2706                            Buffer,
2707                            MAX_PATH,
2708                            &RequiredSize))
2709     {
2710         return INVALID_HANDLE_VALUE;
2711     }
2712
2713     lstrcpyW(FullBuffer, ControlClass);
2714     lstrcatW(FullBuffer, Buffer);
2715
2716     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
2717                       FullBuffer,
2718                       0,
2719                       KEY_ALL_ACCESS,
2720                       &hClassKey))
2721     {
2722         if (!SetupGetLineTextW(NULL,
2723                                hInf,
2724                                Version,
2725                                Class,
2726                                Buffer,
2727                                MAX_PATH,
2728                                &RequiredSize))
2729         {
2730             return INVALID_HANDLE_VALUE;
2731         }
2732
2733         if (RegCreateKeyExW(HKEY_LOCAL_MACHINE,
2734                             FullBuffer,
2735                             0,
2736                             NULL,
2737                             REG_OPTION_NON_VOLATILE,
2738                             KEY_ALL_ACCESS,
2739                             NULL,
2740                             &hClassKey,
2741                             NULL))
2742         {
2743             return INVALID_HANDLE_VALUE;
2744         }
2745
2746     }
2747
2748     if (RegSetValueExW(hClassKey,
2749                        Class,
2750                        0,
2751                        REG_SZ,
2752                        (LPBYTE)Buffer,
2753                        RequiredSize * sizeof(WCHAR)))
2754     {
2755         RegCloseKey(hClassKey);
2756         RegDeleteKeyW(HKEY_LOCAL_MACHINE,
2757                       FullBuffer);
2758         return INVALID_HANDLE_VALUE;
2759     }
2760
2761     return hClassKey;
2762 }
2763
2764 /***********************************************************************
2765  *              SetupDiInstallClassW (SETUPAPI.@)
2766  */
2767 BOOL WINAPI SetupDiInstallClassW(
2768         HWND hwndParent,
2769         PCWSTR InfFileName,
2770         DWORD Flags,
2771         HSPFILEQ FileQueue)
2772 {
2773     WCHAR SectionName[MAX_PATH];
2774     DWORD SectionNameLength = 0;
2775     HINF hInf;
2776     BOOL bFileQueueCreated = FALSE;
2777     HKEY hClassKey;
2778
2779
2780     FIXME("\n");
2781
2782     if ((Flags & DI_NOVCP) && (FileQueue == NULL || FileQueue == INVALID_HANDLE_VALUE))
2783     {
2784         SetLastError(ERROR_INVALID_PARAMETER);
2785         return FALSE;
2786     }
2787
2788     /* Open the .inf file */
2789     hInf = SetupOpenInfFileW(InfFileName,
2790                              NULL,
2791                              INF_STYLE_WIN4,
2792                              NULL);
2793     if (hInf == INVALID_HANDLE_VALUE)
2794     {
2795
2796         return FALSE;
2797     }
2798
2799     /* Create or open the class registry key 'HKLM\\CurrentControlSet\\Class\\{GUID}' */
2800     hClassKey = CreateClassKey(hInf);
2801     if (hClassKey == INVALID_HANDLE_VALUE)
2802     {
2803         SetupCloseInfFile(hInf);
2804         return FALSE;
2805     }
2806
2807
2808     /* Try to append a layout file */
2809 #if 0
2810     SetupOpenAppendInfFileW(NULL, hInf, NULL);
2811 #endif
2812
2813     /* Retrieve the actual section name */
2814     SetupDiGetActualSectionToInstallW(hInf,
2815                                       ClassInstall32,
2816                                       SectionName,
2817                                       MAX_PATH,
2818                                       &SectionNameLength,
2819                                       NULL);
2820
2821 #if 0
2822     if (!(Flags & DI_NOVCP))
2823     {
2824         FileQueue = SetupOpenFileQueue();
2825         if (FileQueue == INVALID_HANDLE_VALUE)
2826         {
2827             SetupCloseInfFile(hInf);
2828             return FALSE;
2829         }
2830
2831         bFileQueueCreated = TRUE;
2832
2833     }
2834 #endif
2835
2836     SetupInstallFromInfSectionW(NULL,
2837                                 hInf,
2838                                 SectionName,
2839                                 SPINST_REGISTRY,
2840                                 hClassKey,
2841                                 NULL,
2842                                 0,
2843                                 NULL,
2844                                 NULL,
2845                                 INVALID_HANDLE_VALUE,
2846                                 NULL);
2847
2848     /* FIXME: More code! */
2849
2850     if (bFileQueueCreated)
2851         SetupCloseFileQueue(FileQueue);
2852
2853     SetupCloseInfFile(hInf);
2854
2855     return TRUE;
2856 }
2857
2858
2859 /***********************************************************************
2860  *              SetupDiOpenClassRegKey  (SETUPAPI.@)
2861  */
2862 HKEY WINAPI SetupDiOpenClassRegKey(
2863         const GUID* ClassGuid,
2864         REGSAM samDesired)
2865 {
2866     return SetupDiOpenClassRegKeyExW(ClassGuid, samDesired,
2867                                      DIOCR_INSTALLER, NULL, NULL);
2868 }
2869
2870
2871 /***********************************************************************
2872  *              SetupDiOpenClassRegKeyExA  (SETUPAPI.@)
2873  */
2874 HKEY WINAPI SetupDiOpenClassRegKeyExA(
2875         const GUID* ClassGuid,
2876         REGSAM samDesired,
2877         DWORD Flags,
2878         PCSTR MachineName,
2879         PVOID Reserved)
2880 {
2881     PWSTR MachineNameW = NULL;
2882     HKEY hKey;
2883
2884     TRACE("\n");
2885
2886     if (MachineName)
2887     {
2888         MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
2889         if (MachineNameW == NULL)
2890             return INVALID_HANDLE_VALUE;
2891     }
2892
2893     hKey = SetupDiOpenClassRegKeyExW(ClassGuid, samDesired,
2894                                      Flags, MachineNameW, Reserved);
2895
2896     MyFree(MachineNameW);
2897
2898     return hKey;
2899 }
2900
2901
2902 /***********************************************************************
2903  *              SetupDiOpenClassRegKeyExW  (SETUPAPI.@)
2904  */
2905 HKEY WINAPI SetupDiOpenClassRegKeyExW(
2906         const GUID* ClassGuid,
2907         REGSAM samDesired,
2908         DWORD Flags,
2909         PCWSTR MachineName,
2910         PVOID Reserved)
2911 {
2912     HKEY hClassesKey;
2913     HKEY key;
2914     LPCWSTR lpKeyName;
2915     LONG l;
2916
2917     if (MachineName != NULL)
2918     {
2919         FIXME("Remote access not supported yet!\n");
2920         return INVALID_HANDLE_VALUE;
2921     }
2922
2923     if (Flags == DIOCR_INSTALLER)
2924     {
2925         lpKeyName = ControlClass;
2926     }
2927     else if (Flags == DIOCR_INTERFACE)
2928     {
2929         lpKeyName = DeviceClasses;
2930     }
2931     else
2932     {
2933         ERR("Invalid Flags parameter!\n");
2934         SetLastError(ERROR_INVALID_PARAMETER);
2935         return INVALID_HANDLE_VALUE;
2936     }
2937
2938     if (!ClassGuid)
2939     {
2940         if ((l = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
2941                           lpKeyName,
2942                           0,
2943                           samDesired,
2944                           &hClassesKey)))
2945         {
2946             SetLastError(l);
2947             hClassesKey = INVALID_HANDLE_VALUE;
2948         }
2949         key = hClassesKey;
2950     }
2951     else
2952     {
2953         WCHAR bracedGuidString[39];
2954
2955         SETUPDI_GuidToString(ClassGuid, bracedGuidString);
2956
2957         if (!(l = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
2958                           lpKeyName,
2959                           0,
2960                           samDesired,
2961                           &hClassesKey)))
2962         {
2963             if ((l = RegOpenKeyExW(hClassesKey,
2964                               bracedGuidString,
2965                               0,
2966                               samDesired,
2967                               &key)))
2968             {
2969                 SetLastError(l);
2970                 key = INVALID_HANDLE_VALUE;
2971             }
2972             RegCloseKey(hClassesKey);
2973         }
2974         else
2975         {
2976             SetLastError(l);
2977             key = INVALID_HANDLE_VALUE;
2978         }
2979     }
2980     return key;
2981 }
2982
2983 /***********************************************************************
2984  *              SetupDiOpenDeviceInterfaceW (SETUPAPI.@)
2985  */
2986 BOOL WINAPI SetupDiOpenDeviceInterfaceW(
2987        HDEVINFO DeviceInfoSet,
2988        PCWSTR DevicePath,
2989        DWORD OpenFlags,
2990        PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
2991 {
2992     FIXME("%p %s %08x %p\n",
2993         DeviceInfoSet, debugstr_w(DevicePath), OpenFlags, DeviceInterfaceData);
2994     return FALSE;
2995 }
2996
2997 /***********************************************************************
2998  *              SetupDiOpenDeviceInterfaceA (SETUPAPI.@)
2999  */
3000 BOOL WINAPI SetupDiOpenDeviceInterfaceA(
3001        HDEVINFO DeviceInfoSet,
3002        PCSTR DevicePath,
3003        DWORD OpenFlags,
3004        PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
3005 {
3006     FIXME("%p %s %08x %p\n", DeviceInfoSet,
3007         debugstr_a(DevicePath), OpenFlags, DeviceInterfaceData);
3008     return FALSE;
3009 }
3010
3011 /***********************************************************************
3012  *              SetupDiSetClassInstallParamsA (SETUPAPI.@)
3013  */
3014 BOOL WINAPI SetupDiSetClassInstallParamsA(
3015        HDEVINFO  DeviceInfoSet,
3016        PSP_DEVINFO_DATA DeviceInfoData,
3017        PSP_CLASSINSTALL_HEADER ClassInstallParams,
3018        DWORD ClassInstallParamsSize)
3019 {
3020     FIXME("%p %p %x %u\n",DeviceInfoSet, DeviceInfoData,
3021           ClassInstallParams->InstallFunction, ClassInstallParamsSize);
3022     return FALSE;
3023 }
3024
3025 /***********************************************************************
3026  *              SetupDiCallClassInstaller (SETUPAPI.@)
3027  */
3028 BOOL WINAPI SetupDiCallClassInstaller(
3029        DI_FUNCTION InstallFunction,
3030        HDEVINFO DeviceInfoSet,
3031        PSP_DEVINFO_DATA DeviceInfoData)
3032 {
3033     FIXME("%d %p %p\n", InstallFunction, DeviceInfoSet, DeviceInfoData);
3034     return FALSE;
3035 }
3036
3037 /***********************************************************************
3038  *              SetupDiGetDeviceInstallParamsA (SETUPAPI.@)
3039  */
3040 BOOL WINAPI SetupDiGetDeviceInstallParamsA(
3041        HDEVINFO DeviceInfoSet,
3042        PSP_DEVINFO_DATA DeviceInfoData,
3043        PSP_DEVINSTALL_PARAMS_A DeviceInstallParams)
3044 {
3045     FIXME("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstallParams);
3046     return FALSE;
3047 }
3048
3049 /***********************************************************************
3050  *              SetupDiOpenDevRegKey (SETUPAPI.@)
3051  */
3052 HKEY WINAPI SetupDiOpenDevRegKey(
3053        HDEVINFO DeviceInfoSet,
3054        PSP_DEVINFO_DATA DeviceInfoData,
3055        DWORD Scope,
3056        DWORD HwProfile,
3057        DWORD KeyType,
3058        REGSAM samDesired)
3059 {
3060     FIXME("%p %p %d %d %d %x\n", DeviceInfoSet, DeviceInfoData,
3061           Scope, HwProfile, KeyType, samDesired);
3062     return INVALID_HANDLE_VALUE;
3063 }