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