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