shell32: Send directories and non-regular files to the trash.
[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 "ddk/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','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
71 /* is used to identify if a DeviceInfoSet pointer is
72 valid or not */
73 #define SETUP_DEVICE_INFO_SET_MAGIC 0xd00ff056
74
75 struct DeviceInfoSet
76 {
77     DWORD magic;        /* if is equal to SETUP_DEVICE_INFO_SET_MAGIC struct is okay */
78     GUID ClassGuid;
79     HWND hwndParent;
80 };
81
82 /***********************************************************************
83  *              SetupDiBuildClassInfoList  (SETUPAPI.@)
84  *
85  * Returns a list of setup class GUIDs that identify the classes
86  * that are installed on a local machine.
87  *
88  * PARAMS
89  *   Flags [I] control exclusion of classes from the list.
90  *   ClassGuidList [O] pointer to a GUID-typed array that receives a list of setup class GUIDs.
91  *   ClassGuidListSize [I] The number of GUIDs in the array (ClassGuidList).
92  *   RequiredSize [O] pointer, which receives the number of GUIDs that are returned.
93  *
94  * RETURNS
95  *   Success: TRUE.
96  *   Failure: FALSE.
97  */
98 BOOL WINAPI SetupDiBuildClassInfoList(
99         DWORD Flags,
100         LPGUID ClassGuidList,
101         DWORD ClassGuidListSize,
102         PDWORD RequiredSize)
103 {
104     TRACE("\n");
105     return SetupDiBuildClassInfoListExW(Flags, ClassGuidList,
106                                         ClassGuidListSize, RequiredSize,
107                                         NULL, NULL);
108 }
109
110 /***********************************************************************
111  *              SetupDiBuildClassInfoListExA  (SETUPAPI.@)
112  *
113  * Returns a list of setup class GUIDs that identify the classes
114  * that are installed on a local or remote macine.
115  *
116  * PARAMS
117  *   Flags [I] control exclusion of classes from the list.
118  *   ClassGuidList [O] pointer to a GUID-typed array that receives a list of setup class GUIDs.
119  *   ClassGuidListSize [I] The number of GUIDs in the array (ClassGuidList).
120  *   RequiredSize [O] pointer, which receives the number of GUIDs that are returned.
121  *   MachineName [I] name of a remote machine.
122  *   Reserved [I] must be NULL.
123  *
124  * RETURNS
125  *   Success: TRUE.
126  *   Failure: FALSE.
127  */
128 BOOL WINAPI SetupDiBuildClassInfoListExA(
129         DWORD Flags,
130         LPGUID ClassGuidList,
131         DWORD ClassGuidListSize,
132         PDWORD RequiredSize,
133         LPCSTR MachineName,
134         PVOID Reserved)
135 {
136     LPWSTR MachineNameW = NULL;
137     BOOL bResult;
138
139     TRACE("\n");
140
141     if (MachineName)
142     {
143         MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
144         if (MachineNameW == NULL) return FALSE;
145     }
146
147     bResult = SetupDiBuildClassInfoListExW(Flags, ClassGuidList,
148                                            ClassGuidListSize, RequiredSize,
149                                            MachineNameW, Reserved);
150
151     MyFree(MachineNameW);
152
153     return bResult;
154 }
155
156 /***********************************************************************
157  *              SetupDiBuildClassInfoListExW  (SETUPAPI.@)
158  *
159  * Returns a list of setup class GUIDs that identify the classes
160  * that are installed on a local or remote macine.
161  *
162  * PARAMS
163  *   Flags [I] control exclusion of classes from the list.
164  *   ClassGuidList [O] pointer to a GUID-typed array that receives a list of setup class GUIDs.
165  *   ClassGuidListSize [I] The number of GUIDs in the array (ClassGuidList).
166  *   RequiredSize [O] pointer, which receives the number of GUIDs that are returned.
167  *   MachineName [I] name of a remote machine.
168  *   Reserved [I] must be NULL.
169  *
170  * RETURNS
171  *   Success: TRUE.
172  *   Failure: FALSE.
173  */
174 BOOL WINAPI SetupDiBuildClassInfoListExW(
175         DWORD Flags,
176         LPGUID ClassGuidList,
177         DWORD ClassGuidListSize,
178         PDWORD RequiredSize,
179         LPCWSTR MachineName,
180         PVOID Reserved)
181 {
182     WCHAR szKeyName[40];
183     HKEY hClassesKey;
184     HKEY hClassKey;
185     DWORD dwLength;
186     DWORD dwIndex;
187     LONG lError;
188     DWORD dwGuidListIndex = 0;
189
190     TRACE("\n");
191
192     if (RequiredSize != NULL)
193         *RequiredSize = 0;
194
195     hClassesKey = SetupDiOpenClassRegKeyExW(NULL,
196                                             KEY_ALL_ACCESS,
197                                             DIOCR_INSTALLER,
198                                             MachineName,
199                                             Reserved);
200     if (hClassesKey == INVALID_HANDLE_VALUE)
201     {
202         return FALSE;
203     }
204
205     for (dwIndex = 0; ; dwIndex++)
206     {
207         dwLength = 40;
208         lError = RegEnumKeyExW(hClassesKey,
209                                dwIndex,
210                                szKeyName,
211                                &dwLength,
212                                NULL,
213                                NULL,
214                                NULL,
215                                NULL);
216         TRACE("RegEnumKeyExW() returns %ld\n", lError);
217         if (lError == ERROR_SUCCESS || lError == ERROR_MORE_DATA)
218         {
219             TRACE("Key name: %p\n", szKeyName);
220
221             if (RegOpenKeyExW(hClassesKey,
222                               szKeyName,
223                               0,
224                               KEY_ALL_ACCESS,
225                               &hClassKey))
226             {
227                 RegCloseKey(hClassesKey);
228                 return FALSE;
229             }
230
231             if (!RegQueryValueExW(hClassKey,
232                                   NoUseClass,
233                                   NULL,
234                                   NULL,
235                                   NULL,
236                                   NULL))
237             {
238                 TRACE("'NoUseClass' value found!\n");
239                 RegCloseKey(hClassKey);
240                 continue;
241             }
242
243             if ((Flags & DIBCI_NOINSTALLCLASS) &&
244                 (!RegQueryValueExW(hClassKey,
245                                    NoInstallClass,
246                                    NULL,
247                                    NULL,
248                                    NULL,
249                                    NULL)))
250             {
251                 TRACE("'NoInstallClass' value found!\n");
252                 RegCloseKey(hClassKey);
253                 continue;
254             }
255
256             if ((Flags & DIBCI_NODISPLAYCLASS) &&
257                 (!RegQueryValueExW(hClassKey,
258                                    NoDisplayClass,
259                                    NULL,
260                                    NULL,
261                                    NULL,
262                                    NULL)))
263             {
264                 TRACE("'NoDisplayClass' value found!\n");
265                 RegCloseKey(hClassKey);
266                 continue;
267             }
268
269             RegCloseKey(hClassKey);
270
271             TRACE("Guid: %p\n", szKeyName);
272             if (dwGuidListIndex < ClassGuidListSize)
273             {
274                 if (szKeyName[0] == L'{' && szKeyName[37] == L'}')
275                 {
276                     szKeyName[37] = 0;
277                 }
278                 TRACE("Guid: %p\n", &szKeyName[1]);
279
280                 UuidFromStringW(&szKeyName[1],
281                                 &ClassGuidList[dwGuidListIndex]);
282             }
283
284             dwGuidListIndex++;
285         }
286
287         if (lError != ERROR_SUCCESS)
288             break;
289     }
290
291     RegCloseKey(hClassesKey);
292
293     if (RequiredSize != NULL)
294         *RequiredSize = dwGuidListIndex;
295
296     if (ClassGuidListSize < dwGuidListIndex)
297     {
298         SetLastError(ERROR_INSUFFICIENT_BUFFER);
299         return FALSE;
300     }
301
302     return TRUE;
303 }
304
305 /***********************************************************************
306  *              SetupDiClassGuidsFromNameA  (SETUPAPI.@)
307  */
308 BOOL WINAPI SetupDiClassGuidsFromNameA(
309         LPCSTR ClassName,
310         LPGUID ClassGuidList,
311         DWORD ClassGuidListSize,
312         PDWORD RequiredSize)
313 {
314   return SetupDiClassGuidsFromNameExA(ClassName, ClassGuidList,
315                                       ClassGuidListSize, RequiredSize,
316                                       NULL, NULL);
317 }
318
319 /***********************************************************************
320  *              SetupDiClassGuidsFromNameW  (SETUPAPI.@)
321  */
322 BOOL WINAPI SetupDiClassGuidsFromNameW(
323         LPCWSTR ClassName,
324         LPGUID ClassGuidList,
325         DWORD ClassGuidListSize,
326         PDWORD RequiredSize)
327 {
328   return SetupDiClassGuidsFromNameExW(ClassName, ClassGuidList,
329                                       ClassGuidListSize, RequiredSize,
330                                       NULL, NULL);
331 }
332
333 /***********************************************************************
334  *              SetupDiClassGuidsFromNameExA  (SETUPAPI.@)
335  */
336 BOOL WINAPI SetupDiClassGuidsFromNameExA(
337         LPCSTR ClassName,
338         LPGUID ClassGuidList,
339         DWORD ClassGuidListSize,
340         PDWORD RequiredSize,
341         LPCSTR MachineName,
342         PVOID Reserved)
343 {
344     LPWSTR ClassNameW = NULL;
345     LPWSTR MachineNameW = NULL;
346     BOOL bResult;
347
348     FIXME("\n");
349
350     ClassNameW = MultiByteToUnicode(ClassName, CP_ACP);
351     if (ClassNameW == NULL)
352         return FALSE;
353
354     if (MachineNameW)
355     {
356         MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
357         if (MachineNameW == NULL)
358         {
359             MyFree(ClassNameW);
360             return FALSE;
361         }
362     }
363
364     bResult = SetupDiClassGuidsFromNameExW(ClassNameW, ClassGuidList,
365                                            ClassGuidListSize, RequiredSize,
366                                            MachineNameW, Reserved);
367
368     MyFree(MachineNameW);
369     MyFree(ClassNameW);
370
371     return bResult;
372 }
373
374 /***********************************************************************
375  *              SetupDiClassGuidsFromNameExW  (SETUPAPI.@)
376  */
377 BOOL WINAPI SetupDiClassGuidsFromNameExW(
378         LPCWSTR ClassName,
379         LPGUID ClassGuidList,
380         DWORD ClassGuidListSize,
381         PDWORD RequiredSize,
382         LPCWSTR MachineName,
383         PVOID Reserved)
384 {
385     WCHAR szKeyName[40];
386     WCHAR szClassName[256];
387     HKEY hClassesKey;
388     HKEY hClassKey;
389     DWORD dwLength;
390     DWORD dwIndex;
391     LONG lError;
392     DWORD dwGuidListIndex = 0;
393
394     if (RequiredSize != NULL)
395         *RequiredSize = 0;
396
397     hClassesKey = SetupDiOpenClassRegKeyExW(NULL,
398                                             KEY_ALL_ACCESS,
399                                             DIOCR_INSTALLER,
400                                             MachineName,
401                                             Reserved);
402     if (hClassesKey == INVALID_HANDLE_VALUE)
403     {
404         return FALSE;
405     }
406
407     for (dwIndex = 0; ; dwIndex++)
408     {
409         dwLength = 40;
410         lError = RegEnumKeyExW(hClassesKey,
411                                dwIndex,
412                                szKeyName,
413                                &dwLength,
414                                NULL,
415                                NULL,
416                                NULL,
417                                NULL);
418         TRACE("RegEnumKeyExW() returns %ld\n", lError);
419         if (lError == ERROR_SUCCESS || lError == ERROR_MORE_DATA)
420         {
421             TRACE("Key name: %p\n", szKeyName);
422
423             if (RegOpenKeyExW(hClassesKey,
424                               szKeyName,
425                               0,
426                               KEY_ALL_ACCESS,
427                               &hClassKey))
428             {
429                 RegCloseKey(hClassesKey);
430                 return FALSE;
431             }
432
433             dwLength = 256 * sizeof(WCHAR);
434             if (!RegQueryValueExW(hClassKey,
435                                   Class,
436                                   NULL,
437                                   NULL,
438                                   (LPBYTE)szClassName,
439                                   &dwLength))
440             {
441                 TRACE("Class name: %p\n", szClassName);
442
443                 if (strcmpiW(szClassName, ClassName) == 0)
444                 {
445                     TRACE("Found matching class name\n");
446
447                     TRACE("Guid: %p\n", szKeyName);
448                     if (dwGuidListIndex < ClassGuidListSize)
449                     {
450                         if (szKeyName[0] == L'{' && szKeyName[37] == L'}')
451                         {
452                             szKeyName[37] = 0;
453                         }
454                         TRACE("Guid: %p\n", &szKeyName[1]);
455
456                         UuidFromStringW(&szKeyName[1],
457                                         &ClassGuidList[dwGuidListIndex]);
458                     }
459
460                     dwGuidListIndex++;
461                 }
462             }
463
464             RegCloseKey(hClassKey);
465         }
466
467         if (lError != ERROR_SUCCESS)
468             break;
469     }
470
471     RegCloseKey(hClassesKey);
472
473     if (RequiredSize != NULL)
474         *RequiredSize = dwGuidListIndex;
475
476     if (ClassGuidListSize < dwGuidListIndex)
477     {
478         SetLastError(ERROR_INSUFFICIENT_BUFFER);
479         return FALSE;
480     }
481
482     return TRUE;
483 }
484
485 /***********************************************************************
486  *              SetupDiClassNameFromGuidA  (SETUPAPI.@)
487  */
488 BOOL WINAPI SetupDiClassNameFromGuidA(
489         const GUID* ClassGuid,
490         PSTR ClassName,
491         DWORD ClassNameSize,
492         PDWORD RequiredSize)
493 {
494   return SetupDiClassNameFromGuidExA(ClassGuid, ClassName,
495                                      ClassNameSize, RequiredSize,
496                                      NULL, NULL);
497 }
498
499 /***********************************************************************
500  *              SetupDiClassNameFromGuidW  (SETUPAPI.@)
501  */
502 BOOL WINAPI SetupDiClassNameFromGuidW(
503         const GUID* ClassGuid,
504         PWSTR ClassName,
505         DWORD ClassNameSize,
506         PDWORD RequiredSize)
507 {
508   return SetupDiClassNameFromGuidExW(ClassGuid, ClassName,
509                                      ClassNameSize, RequiredSize,
510                                      NULL, NULL);
511 }
512
513 /***********************************************************************
514  *              SetupDiClassNameFromGuidExA  (SETUPAPI.@)
515  */
516 BOOL WINAPI SetupDiClassNameFromGuidExA(
517         const GUID* ClassGuid,
518         PSTR ClassName,
519         DWORD ClassNameSize,
520         PDWORD RequiredSize,
521         PCSTR MachineName,
522         PVOID Reserved)
523 {
524     WCHAR ClassNameW[MAX_CLASS_NAME_LEN];
525     LPWSTR MachineNameW = NULL;
526     BOOL ret;
527
528     if (MachineName)
529         MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
530     ret = SetupDiClassNameFromGuidExW(ClassGuid, ClassNameW, MAX_CLASS_NAME_LEN,
531      NULL, MachineNameW, Reserved);
532     if (ret)
533     {
534         int len = WideCharToMultiByte(CP_ACP, 0, ClassNameW, -1, ClassName,
535          ClassNameSize, NULL, NULL);
536
537         if (!ClassNameSize && RequiredSize)
538             *RequiredSize = len;
539     }
540     MyFree(MachineNameW);
541     return ret;
542 }
543
544 /***********************************************************************
545  *              SetupDiClassNameFromGuidExW  (SETUPAPI.@)
546  */
547 BOOL WINAPI SetupDiClassNameFromGuidExW(
548         const GUID* ClassGuid,
549         PWSTR ClassName,
550         DWORD ClassNameSize,
551         PDWORD RequiredSize,
552         PCWSTR MachineName,
553         PVOID Reserved)
554 {
555     HKEY hKey;
556     DWORD dwLength;
557
558     hKey = SetupDiOpenClassRegKeyExW(ClassGuid,
559                                      KEY_ALL_ACCESS,
560                                      DIOCR_INSTALLER,
561                                      MachineName,
562                                      Reserved);
563     if (hKey == INVALID_HANDLE_VALUE)
564     {
565         return FALSE;
566     }
567
568     if (RequiredSize != NULL)
569     {
570         dwLength = 0;
571         if (RegQueryValueExW(hKey,
572                              Class,
573                              NULL,
574                              NULL,
575                              NULL,
576                              &dwLength))
577         {
578             RegCloseKey(hKey);
579             return FALSE;
580         }
581
582         *RequiredSize = dwLength / sizeof(WCHAR);
583     }
584
585     dwLength = ClassNameSize * sizeof(WCHAR);
586     if (RegQueryValueExW(hKey,
587                          Class,
588                          NULL,
589                          NULL,
590                          (LPBYTE)ClassName,
591                          &dwLength))
592     {
593         RegCloseKey(hKey);
594         return FALSE;
595     }
596
597     RegCloseKey(hKey);
598
599     return TRUE;
600 }
601
602 /***********************************************************************
603  *              SetupDiCreateDeviceInfoList (SETUPAPI.@)
604  */
605 HDEVINFO WINAPI
606 SetupDiCreateDeviceInfoList(const GUID *ClassGuid,
607                             HWND hwndParent)
608 {
609   return SetupDiCreateDeviceInfoListExW(ClassGuid, hwndParent, NULL, NULL);
610 }
611
612 /***********************************************************************
613  *              SetupDiCreateDeviceInfoListExA (SETUPAPI.@)
614  */
615 HDEVINFO WINAPI
616 SetupDiCreateDeviceInfoListExA(const GUID *ClassGuid,
617                                HWND hwndParent,
618                                PCSTR MachineName,
619                                PVOID Reserved)
620 {
621     LPWSTR MachineNameW = NULL;
622     HDEVINFO hDevInfo;
623
624     TRACE("\n");
625
626     if (MachineName)
627     {
628         MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
629         if (MachineNameW == NULL)
630             return (HDEVINFO)INVALID_HANDLE_VALUE;
631     }
632
633     hDevInfo = SetupDiCreateDeviceInfoListExW(ClassGuid, hwndParent,
634                                               MachineNameW, Reserved);
635
636     MyFree(MachineNameW);
637
638     return hDevInfo;
639 }
640
641 /***********************************************************************
642  *              SetupDiCreateDeviceInfoListExW (SETUPAPI.@)
643  *
644  * Create an empty DeviceInfoSet list.
645  *
646  * PARAMS
647  *   ClassGuid [I] if not NULL only devices with GUID ClcassGuid are associated
648  *                 with this list.
649  *   hwndParent [I] hwnd needed for interface related actions.
650  *   MachineName [I] name of machine to create emtpy DeviceInfoSet list, if NULL
651  *                   local regestry will be used.
652  *   Reserved [I] must be NULL
653  *
654  * RETURNS
655  *   Success: empty list.
656  *   Failure: INVALID_HANDLE_VALUE.
657  */
658 HDEVINFO WINAPI
659 SetupDiCreateDeviceInfoListExW(const GUID *ClassGuid,
660                                HWND hwndParent,
661                                PCWSTR MachineName,
662                                PVOID Reserved)
663 {
664     struct DeviceInfoSet *list = NULL;
665     DWORD size = sizeof(struct DeviceInfoSet);
666
667     TRACE("%s %p %s %p\n", debugstr_guid(ClassGuid), hwndParent,
668       debugstr_w(MachineName), Reserved);
669
670     if (MachineName != NULL)
671     {
672         FIXME("remote support is not implemented");
673         SetLastError(ERROR_INVALID_MACHINENAME);
674         return (HDEVINFO)INVALID_HANDLE_VALUE;
675     }
676
677     if (Reserved != NULL)
678     {
679         SetLastError(ERROR_INVALID_PARAMETER);
680         return (HDEVINFO)INVALID_HANDLE_VALUE;
681     }
682
683     list = HeapAlloc(GetProcessHeap(), 0, size);
684     if (!list)
685     {
686         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
687         return (HDEVINFO)INVALID_HANDLE_VALUE;
688     }
689
690     list->magic = SETUP_DEVICE_INFO_SET_MAGIC;
691     list->hwndParent = hwndParent;
692     memcpy(&list->ClassGuid,
693             ClassGuid ? ClassGuid : &GUID_NULL,
694             sizeof(list->ClassGuid));
695
696     return (HDEVINFO)list;
697 }
698
699 /***********************************************************************
700  *              SetupDiCreateDeviceInfoA (SETUPAPI.@)
701  */
702 BOOL WINAPI SetupDiCreateDeviceInfoA(
703        HDEVINFO DeviceInfoSet,
704        PCSTR DeviceName,
705        CONST GUID *ClassGuid,
706        PCSTR DeviceDescription,
707        HWND hwndParent,
708        DWORD CreationFlags,
709        PSP_DEVINFO_DATA DeviceInfoData)
710 {
711     BOOL ret = FALSE;
712     LPWSTR DeviceNameW = NULL;
713     LPWSTR DeviceDescriptionW = NULL;
714
715     if (DeviceName)
716     {
717         DeviceNameW = MultiByteToUnicode(DeviceName, CP_ACP);
718         if (DeviceNameW == NULL) return FALSE;
719     }
720     if (DeviceDescription)
721     {
722         DeviceDescriptionW = MultiByteToUnicode(DeviceDescription, CP_ACP);
723         if (DeviceDescriptionW == NULL)
724         {
725             MyFree(DeviceNameW);
726             return FALSE;
727         }
728     }
729
730     ret = SetupDiCreateDeviceInfoW(DeviceInfoSet, DeviceNameW, ClassGuid, DeviceDescriptionW,
731             hwndParent, CreationFlags, DeviceInfoData);
732
733     MyFree(DeviceNameW);
734     MyFree(DeviceDescriptionW);
735
736     return ret;
737 }
738
739 /***********************************************************************
740  *              SetupDiCreateDeviceInfoW (SETUPAPI.@)
741  */
742 BOOL WINAPI SetupDiCreateDeviceInfoW(
743        HDEVINFO DeviceInfoSet,
744        PCWSTR DeviceName,
745        CONST GUID *ClassGuid,
746        PCWSTR DeviceDescription,
747        HWND hwndParent,
748        DWORD CreationFlags,
749        PSP_DEVINFO_DATA DeviceInfoData)
750 {
751     TRACE("%p %s %s %s %p %lx %p\n", DeviceInfoSet, debugstr_w(DeviceName),
752         debugstr_guid(ClassGuid), debugstr_w(DeviceDescription),
753         hwndParent, CreationFlags, DeviceInfoData);
754
755     FIXME("stub");
756
757     return FALSE;
758 }
759
760 /***********************************************************************
761  *              SetupDiEnumDeviceInfo (SETUPAPI.@)
762  */
763 BOOL WINAPI SetupDiEnumDeviceInfo(
764         HDEVINFO  devinfo,
765         DWORD  index,
766         PSP_DEVINFO_DATA info)
767 {
768     FIXME("%p %ld %p\n", devinfo, index, info);
769
770     if(info==NULL)
771         return FALSE;
772     if(info->cbSize < sizeof(*info))
773         return FALSE;
774
775     return FALSE;
776 }
777
778 /***********************************************************************
779  *              SetupDiGetActualSectionToInstallA (SETUPAPI.@)
780  */
781 BOOL WINAPI SetupDiGetActualSectionToInstallA(
782         HINF InfHandle,
783         PCSTR InfSectionName,
784         PSTR InfSectionWithExt,
785         DWORD InfSectionWithExtSize,
786         PDWORD RequiredSize,
787         PSTR *Extension)
788 {
789     FIXME("\n");
790     return FALSE;
791 }
792
793 /***********************************************************************
794  *              SetupDiGetActualSectionToInstallW (SETUPAPI.@)
795  */
796 BOOL WINAPI SetupDiGetActualSectionToInstallW(
797         HINF InfHandle,
798         PCWSTR InfSectionName,
799         PWSTR InfSectionWithExt,
800         DWORD InfSectionWithExtSize,
801         PDWORD RequiredSize,
802         PWSTR *Extension)
803 {
804     WCHAR szBuffer[MAX_PATH];
805     DWORD dwLength;
806     DWORD dwFullLength;
807     LONG lLineCount = -1;
808
809     lstrcpyW(szBuffer, InfSectionName);
810     dwLength = lstrlenW(szBuffer);
811
812     if (OsVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
813     {
814         /* Test section name with '.NTx86' extension */
815         lstrcpyW(&szBuffer[dwLength], NtPlatformExtension);
816         lLineCount = SetupGetLineCountW(InfHandle, szBuffer);
817
818         if (lLineCount == -1)
819         {
820             /* Test section name with '.NT' extension */
821             lstrcpyW(&szBuffer[dwLength], NtExtension);
822             lLineCount = SetupGetLineCountW(InfHandle, szBuffer);
823         }
824     }
825     else
826     {
827         /* Test section name with '.Win' extension */
828         lstrcpyW(&szBuffer[dwLength], WinExtension);
829         lLineCount = SetupGetLineCountW(InfHandle, szBuffer);
830     }
831
832     if (lLineCount == -1)
833     {
834         /* Test section name without extension */
835         szBuffer[dwLength] = 0;
836         lLineCount = SetupGetLineCountW(InfHandle, szBuffer);
837     }
838
839     if (lLineCount == -1)
840     {
841         SetLastError(ERROR_INVALID_PARAMETER);
842         return FALSE;
843     }
844
845     dwFullLength = lstrlenW(szBuffer);
846
847     if (InfSectionWithExt != NULL && InfSectionWithExtSize != 0)
848     {
849         if (InfSectionWithExtSize < (dwFullLength + 1))
850         {
851             SetLastError(ERROR_INSUFFICIENT_BUFFER);
852             return FALSE;
853         }
854
855         lstrcpyW(InfSectionWithExt, szBuffer);
856         if (Extension != NULL)
857         {
858             *Extension = (dwLength == dwFullLength) ? NULL : &InfSectionWithExt[dwLength];
859         }
860     }
861
862     if (RequiredSize != NULL)
863     {
864         *RequiredSize = dwFullLength + 1;
865     }
866
867     return TRUE;
868 }
869
870 /***********************************************************************
871  *              SetupDiGetClassDescriptionA  (SETUPAPI.@)
872  */
873 BOOL WINAPI SetupDiGetClassDescriptionA(
874         const GUID* ClassGuid,
875         PSTR ClassDescription,
876         DWORD ClassDescriptionSize,
877         PDWORD RequiredSize)
878 {
879   return SetupDiGetClassDescriptionExA(ClassGuid, ClassDescription,
880                                        ClassDescriptionSize,
881                                        RequiredSize, NULL, NULL);
882 }
883
884 /***********************************************************************
885  *              SetupDiGetClassDescriptionW  (SETUPAPI.@)
886  */
887 BOOL WINAPI SetupDiGetClassDescriptionW(
888         const GUID* ClassGuid,
889         PWSTR ClassDescription,
890         DWORD ClassDescriptionSize,
891         PDWORD RequiredSize)
892 {
893   return SetupDiGetClassDescriptionExW(ClassGuid, ClassDescription,
894                                        ClassDescriptionSize,
895                                        RequiredSize, NULL, NULL);
896 }
897
898 /***********************************************************************
899  *              SetupDiGetClassDescriptionExA  (SETUPAPI.@)
900  */
901 BOOL WINAPI SetupDiGetClassDescriptionExA(
902         const GUID* ClassGuid,
903         PSTR ClassDescription,
904         DWORD ClassDescriptionSize,
905         PDWORD RequiredSize,
906         PCSTR MachineName,
907         PVOID Reserved)
908 {
909   FIXME("\n");
910   return FALSE;
911 }
912
913 /***********************************************************************
914  *              SetupDiGetClassDescriptionExW  (SETUPAPI.@)
915  */
916 BOOL WINAPI SetupDiGetClassDescriptionExW(
917         const GUID* ClassGuid,
918         PWSTR ClassDescription,
919         DWORD ClassDescriptionSize,
920         PDWORD RequiredSize,
921         PCWSTR MachineName,
922         PVOID Reserved)
923 {
924     HKEY hKey;
925     DWORD dwLength;
926
927     hKey = SetupDiOpenClassRegKeyExW(ClassGuid,
928                                      KEY_ALL_ACCESS,
929                                      DIOCR_INSTALLER,
930                                      MachineName,
931                                      Reserved);
932     if (hKey == INVALID_HANDLE_VALUE)
933     {
934         WARN("SetupDiOpenClassRegKeyExW() failed (Error %lu)\n", GetLastError());
935         return FALSE;
936     }
937
938     if (RequiredSize != NULL)
939     {
940         dwLength = 0;
941         if (RegQueryValueExW(hKey,
942                              NULL,
943                              NULL,
944                              NULL,
945                              NULL,
946                              &dwLength))
947         {
948             RegCloseKey(hKey);
949             return FALSE;
950         }
951
952         *RequiredSize = dwLength / sizeof(WCHAR);
953     }
954
955     dwLength = ClassDescriptionSize * sizeof(WCHAR);
956     if (RegQueryValueExW(hKey,
957                          NULL,
958                          NULL,
959                          NULL,
960                          (LPBYTE)ClassDescription,
961                          &dwLength))
962     {
963         RegCloseKey(hKey);
964         return FALSE;
965     }
966
967     RegCloseKey(hKey);
968
969     return TRUE;
970 }
971
972 /***********************************************************************
973  *              SetupDiGetClassDevsA (SETUPAPI.@)
974  */
975 HDEVINFO WINAPI SetupDiGetClassDevsA(
976        CONST GUID *class,
977        LPCSTR enumstr,
978        HWND parent,
979        DWORD flags)
980 {
981     HDEVINFO ret;
982     LPWSTR enumstrW = NULL;
983
984     if (enumstr)
985     {
986         int len = MultiByteToWideChar(CP_ACP, 0, enumstr, -1, NULL, 0);
987         enumstrW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
988         if (!enumstrW)
989         {
990             ret = (HDEVINFO)INVALID_HANDLE_VALUE;
991             goto end;
992         }
993         MultiByteToWideChar(CP_ACP, 0, enumstr, -1, enumstrW, len);
994     }
995     ret = SetupDiGetClassDevsW(class, enumstrW, parent, flags);
996     HeapFree(GetProcessHeap(), 0, enumstrW);
997
998 end:
999     return ret;
1000 }
1001
1002 /***********************************************************************
1003  *              SetupDiGetClassDevsW (SETUPAPI.@)
1004  */
1005 HDEVINFO WINAPI SetupDiGetClassDevsW(
1006        CONST GUID *class,
1007        LPCWSTR enumstr,
1008        HWND parent,
1009        DWORD flags)
1010 {
1011     HDEVINFO ret = (HDEVINFO)INVALID_HANDLE_VALUE;
1012
1013     TRACE("%s %s %p 0x%08lx\n", debugstr_guid(class), debugstr_w(enumstr),
1014      parent, flags);
1015
1016     if (enumstr)
1017         FIXME(": unimplemented for enumerator strings (%s)\n",
1018          debugstr_w(enumstr));
1019     else if (flags & DIGCF_ALLCLASSES)
1020         FIXME(": unimplemented for DIGCF_ALLCLASSES\n");
1021     else
1022     {
1023         FIXME("(%s): stub\n", debugstr_guid(class));
1024     }
1025     return ret;
1026 }
1027
1028 /***********************************************************************
1029  *              SetupDiGetClassDevsExW (SETUPAPI.@)
1030  */
1031 HDEVINFO WINAPI SetupDiGetClassDevsExW(
1032         CONST GUID *class,
1033         PCWSTR enumstr,
1034         HWND parent,
1035         DWORD flags,
1036         HDEVINFO deviceset,
1037         PCWSTR machine,
1038         PVOID reserved)
1039 {
1040     FIXME("stub");
1041     return FALSE;
1042 }
1043
1044 /***********************************************************************
1045  *              SetupDiEnumDeviceInterfaces (SETUPAPI.@)
1046  */
1047 BOOL WINAPI SetupDiEnumDeviceInterfaces(
1048        HDEVINFO DeviceInfoSet,
1049        PSP_DEVINFO_DATA DeviceInfoData,
1050        CONST GUID * InterfaceClassGuid,
1051        DWORD MemberIndex,
1052        PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
1053 {
1054     BOOL ret = FALSE;
1055
1056     FIXME("%p, %p, %s, 0x%08lx, %p\n", DeviceInfoSet, DeviceInfoData,
1057      debugstr_guid(InterfaceClassGuid), MemberIndex, DeviceInterfaceData);
1058
1059     SetLastError(ERROR_INVALID_HANDLE);
1060     return ret;
1061 }
1062
1063 /***********************************************************************
1064  *              SetupDiDestroyDeviceInfoList (SETUPAPI.@)
1065   *
1066  * Destroy a DeviceInfoList and free all used memory of the list.
1067  *
1068  * PARAMS
1069  *   devinfo [I] DeviceInfoList pointer to list to destroy
1070  *
1071  * RETURNS
1072  *   Success: non zero value.
1073  *   Failure: zero value.
1074  */
1075 BOOL WINAPI SetupDiDestroyDeviceInfoList(HDEVINFO devinfo)
1076 {
1077     BOOL ret = FALSE;
1078
1079     TRACE("%p\n", devinfo);
1080     if (devinfo && devinfo != (HDEVINFO)INVALID_HANDLE_VALUE)
1081     {
1082         struct DeviceInfoSet *list = (struct DeviceInfoSet *)devinfo;
1083
1084         if (list->magic == SETUP_DEVICE_INFO_SET_MAGIC)
1085         {
1086             HeapFree(GetProcessHeap(), 0, list);
1087             ret = TRUE;
1088         }
1089     }
1090
1091     if (ret == FALSE)
1092         SetLastError(ERROR_INVALID_HANDLE);
1093
1094     return ret;
1095 }
1096
1097 /***********************************************************************
1098  *              SetupDiGetDeviceInterfaceDetailA (SETUPAPI.@)
1099  */
1100 BOOL WINAPI SetupDiGetDeviceInterfaceDetailA(
1101       HDEVINFO DeviceInfoSet,
1102       PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
1103       PSP_DEVICE_INTERFACE_DETAIL_DATA_A DeviceInterfaceDetailData,
1104       DWORD DeviceInterfaceDetailDataSize,
1105       PDWORD RequiredSize,
1106       PSP_DEVINFO_DATA DeviceInfoData)
1107 {
1108     BOOL ret = FALSE;
1109
1110     FIXME("(%p, %p, %p, %ld, %p, %p)\n", DeviceInfoSet,
1111      DeviceInterfaceData, DeviceInterfaceDetailData,
1112      DeviceInterfaceDetailDataSize, RequiredSize, DeviceInfoData);
1113
1114     SetLastError(ERROR_INVALID_HANDLE);
1115     return ret;
1116 }
1117
1118 /***********************************************************************
1119  *              SetupDiGetDeviceInterfaceDetailW (SETUPAPI.@)
1120  */
1121 BOOL WINAPI SetupDiGetDeviceInterfaceDetailW(
1122       HDEVINFO DeviceInfoSet,
1123       PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
1124       PSP_DEVICE_INTERFACE_DETAIL_DATA_W DeviceInterfaceDetailData,
1125       DWORD DeviceInterfaceDetailDataSize,
1126       PDWORD RequiredSize,
1127       PSP_DEVINFO_DATA DeviceInfoData)
1128 {
1129     FIXME("(%p, %p, %p, %ld, %p, %p): stub\n", DeviceInfoSet,
1130      DeviceInterfaceData, DeviceInterfaceDetailData,
1131      DeviceInterfaceDetailDataSize, RequiredSize, DeviceInfoData);
1132     return FALSE;
1133 }
1134
1135 /***********************************************************************
1136  *              SetupDiGetDeviceRegistryPropertyA (SETUPAPI.@)
1137  */
1138 BOOL WINAPI SetupDiGetDeviceRegistryPropertyA(
1139         HDEVINFO  devinfo,
1140         PSP_DEVINFO_DATA  DeviceInfoData,
1141         DWORD   Property,
1142         PDWORD  PropertyRegDataType,
1143         PBYTE   PropertyBuffer,
1144         DWORD   PropertyBufferSize,
1145         PDWORD  RequiredSize)
1146 {
1147     FIXME("%04lx %p %ld %p %p %ld %p\n", (DWORD)devinfo, DeviceInfoData,
1148         Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize,
1149         RequiredSize);
1150     return FALSE;
1151 }
1152
1153 /***********************************************************************
1154  *              SetupDiInstallClassA (SETUPAPI.@)
1155  */
1156 BOOL WINAPI SetupDiInstallClassA(
1157         HWND hwndParent,
1158         PCSTR InfFileName,
1159         DWORD Flags,
1160         HSPFILEQ FileQueue)
1161 {
1162     UNICODE_STRING FileNameW;
1163     BOOL Result;
1164
1165     if (!RtlCreateUnicodeStringFromAsciiz(&FileNameW, InfFileName))
1166     {
1167         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1168         return FALSE;
1169     }
1170
1171     Result = SetupDiInstallClassW(hwndParent, FileNameW.Buffer, Flags, FileQueue);
1172
1173     RtlFreeUnicodeString(&FileNameW);
1174
1175     return Result;
1176 }
1177
1178 static HKEY CreateClassKey(HINF hInf)
1179 {
1180     WCHAR FullBuffer[MAX_PATH];
1181     WCHAR Buffer[MAX_PATH];
1182     DWORD RequiredSize;
1183     HKEY hClassKey;
1184
1185     if (!SetupGetLineTextW(NULL,
1186                            hInf,
1187                            Version,
1188                            ClassGUID,
1189                            Buffer,
1190                            MAX_PATH,
1191                            &RequiredSize))
1192     {
1193         return INVALID_HANDLE_VALUE;
1194     }
1195
1196     lstrcpyW(FullBuffer, ControlClass);
1197     lstrcatW(FullBuffer, Buffer);
1198
1199     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1200                       FullBuffer,
1201                       0,
1202                       KEY_ALL_ACCESS,
1203                       &hClassKey))
1204     {
1205         if (!SetupGetLineTextW(NULL,
1206                                hInf,
1207                                Version,
1208                                Class,
1209                                Buffer,
1210                                MAX_PATH,
1211                                &RequiredSize))
1212         {
1213             return INVALID_HANDLE_VALUE;
1214         }
1215
1216         if (RegCreateKeyExW(HKEY_LOCAL_MACHINE,
1217                             FullBuffer,
1218                             0,
1219                             NULL,
1220                             REG_OPTION_NON_VOLATILE,
1221                             KEY_ALL_ACCESS,
1222                             NULL,
1223                             &hClassKey,
1224                             NULL))
1225         {
1226             return INVALID_HANDLE_VALUE;
1227         }
1228
1229     }
1230
1231     if (RegSetValueExW(hClassKey,
1232                        Class,
1233                        0,
1234                        REG_SZ,
1235                        (LPBYTE)Buffer,
1236                        RequiredSize * sizeof(WCHAR)))
1237     {
1238         RegCloseKey(hClassKey);
1239         RegDeleteKeyW(HKEY_LOCAL_MACHINE,
1240                       FullBuffer);
1241         return INVALID_HANDLE_VALUE;
1242     }
1243
1244     return hClassKey;
1245 }
1246
1247 /***********************************************************************
1248  *              SetupDiInstallClassW (SETUPAPI.@)
1249  */
1250 BOOL WINAPI SetupDiInstallClassW(
1251         HWND hwndParent,
1252         PCWSTR InfFileName,
1253         DWORD Flags,
1254         HSPFILEQ FileQueue)
1255 {
1256     WCHAR SectionName[MAX_PATH];
1257     DWORD SectionNameLength = 0;
1258     HINF hInf;
1259     BOOL bFileQueueCreated = FALSE;
1260     HKEY hClassKey;
1261
1262
1263     FIXME("\n");
1264
1265     if ((Flags & DI_NOVCP) && (FileQueue == NULL || FileQueue == INVALID_HANDLE_VALUE))
1266     {
1267         SetLastError(ERROR_INVALID_PARAMETER);
1268         return FALSE;
1269     }
1270
1271     /* Open the .inf file */
1272     hInf = SetupOpenInfFileW(InfFileName,
1273                              NULL,
1274                              INF_STYLE_WIN4,
1275                              NULL);
1276     if (hInf == INVALID_HANDLE_VALUE)
1277     {
1278
1279         return FALSE;
1280     }
1281
1282     /* Create or open the class registry key 'HKLM\\CurrentControlSet\\Class\\{GUID}' */
1283     hClassKey = CreateClassKey(hInf);
1284     if (hClassKey == INVALID_HANDLE_VALUE)
1285     {
1286         SetupCloseInfFile(hInf);
1287         return FALSE;
1288     }
1289
1290
1291     /* Try to append a layout file */
1292 #if 0
1293     SetupOpenAppendInfFileW(NULL, hInf, NULL);
1294 #endif
1295
1296     /* Retrieve the actual section name */
1297     SetupDiGetActualSectionToInstallW(hInf,
1298                                       ClassInstall32,
1299                                       SectionName,
1300                                       MAX_PATH,
1301                                       &SectionNameLength,
1302                                       NULL);
1303
1304 #if 0
1305     if (!(Flags & DI_NOVCP))
1306     {
1307         FileQueue = SetupOpenFileQueue();
1308         if (FileQueue == INVALID_HANDLE_VALUE)
1309         {
1310             SetupCloseInfFile(hInf);
1311             return FALSE;
1312         }
1313
1314         bFileQueueCreated = TRUE;
1315
1316     }
1317 #endif
1318
1319     SetupInstallFromInfSectionW(NULL,
1320                                 hInf,
1321                                 SectionName,
1322                                 SPINST_REGISTRY,
1323                                 hClassKey,
1324                                 NULL,
1325                                 0,
1326                                 NULL,
1327                                 NULL,
1328                                 INVALID_HANDLE_VALUE,
1329                                 NULL);
1330
1331     /* FIXME: More code! */
1332
1333     if (bFileQueueCreated)
1334         SetupCloseFileQueue(FileQueue);
1335
1336     SetupCloseInfFile(hInf);
1337
1338     return TRUE;
1339 }
1340
1341
1342 /***********************************************************************
1343  *              SetupDiOpenClassRegKey  (SETUPAPI.@)
1344  */
1345 HKEY WINAPI SetupDiOpenClassRegKey(
1346         const GUID* ClassGuid,
1347         REGSAM samDesired)
1348 {
1349     return SetupDiOpenClassRegKeyExW(ClassGuid, samDesired,
1350                                      DIOCR_INSTALLER, NULL, NULL);
1351 }
1352
1353
1354 /***********************************************************************
1355  *              SetupDiOpenClassRegKeyExA  (SETUPAPI.@)
1356  */
1357 HKEY WINAPI SetupDiOpenClassRegKeyExA(
1358         const GUID* ClassGuid,
1359         REGSAM samDesired,
1360         DWORD Flags,
1361         PCSTR MachineName,
1362         PVOID Reserved)
1363 {
1364     PWSTR MachineNameW = NULL;
1365     HKEY hKey;
1366
1367     TRACE("\n");
1368
1369     if (MachineName)
1370     {
1371         MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
1372         if (MachineNameW == NULL)
1373             return INVALID_HANDLE_VALUE;
1374     }
1375
1376     hKey = SetupDiOpenClassRegKeyExW(ClassGuid, samDesired,
1377                                      Flags, MachineNameW, Reserved);
1378
1379     MyFree(MachineNameW);
1380
1381     return hKey;
1382 }
1383
1384
1385 /***********************************************************************
1386  *              SetupDiOpenClassRegKeyExW  (SETUPAPI.@)
1387  */
1388 HKEY WINAPI SetupDiOpenClassRegKeyExW(
1389         const GUID* ClassGuid,
1390         REGSAM samDesired,
1391         DWORD Flags,
1392         PCWSTR MachineName,
1393         PVOID Reserved)
1394 {
1395     LPWSTR lpGuidString;
1396     HKEY hClassesKey;
1397     HKEY hClassKey;
1398     LPCWSTR lpKeyName;
1399
1400     if (MachineName != NULL)
1401     {
1402         FIXME("Remote access not supported yet!\n");
1403         return INVALID_HANDLE_VALUE;
1404     }
1405
1406     if (Flags == DIOCR_INSTALLER)
1407     {
1408         lpKeyName = ControlClass;
1409     }
1410     else if (Flags == DIOCR_INTERFACE)
1411     {
1412         lpKeyName = DeviceClasses;
1413     }
1414     else
1415     {
1416         ERR("Invalid Flags parameter!\n");
1417         SetLastError(ERROR_INVALID_PARAMETER);
1418         return INVALID_HANDLE_VALUE;
1419     }
1420
1421     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1422                       lpKeyName,
1423                       0,
1424                       KEY_ALL_ACCESS,
1425                       &hClassesKey))
1426     {
1427         return INVALID_HANDLE_VALUE;
1428     }
1429
1430     if (ClassGuid == NULL)
1431         return hClassesKey;
1432
1433     if (UuidToStringW((UUID*)ClassGuid, &lpGuidString) != RPC_S_OK)
1434     {
1435         RegCloseKey(hClassesKey);
1436         return FALSE;
1437     }
1438
1439     if (RegOpenKeyExW(hClassesKey,
1440                       lpGuidString,
1441                       0,
1442                       KEY_ALL_ACCESS,
1443                       &hClassKey))
1444     {
1445         RpcStringFreeW(&lpGuidString);
1446         RegCloseKey(hClassesKey);
1447         return FALSE;
1448     }
1449
1450     RpcStringFreeW(&lpGuidString);
1451     RegCloseKey(hClassesKey);
1452
1453     return hClassKey;
1454 }
1455
1456 /***********************************************************************
1457  *              SetupDiOpenDeviceInterfaceW (SETUPAPI.@)
1458  */
1459 BOOL WINAPI SetupDiOpenDeviceInterfaceW(
1460        HDEVINFO DeviceInfoSet,
1461        PCWSTR DevicePath,
1462        DWORD OpenFlags,
1463        PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
1464 {
1465     FIXME("%p %s %08lx %p\n",
1466         DeviceInfoSet, debugstr_w(DevicePath), OpenFlags, DeviceInterfaceData);
1467     return FALSE;
1468 }
1469
1470 /***********************************************************************
1471  *              SetupDiOpenDeviceInterfaceA (SETUPAPI.@)
1472  */
1473 BOOL WINAPI SetupDiOpenDeviceInterfaceA(
1474        HDEVINFO DeviceInfoSet,
1475        PCSTR DevicePath,
1476        DWORD OpenFlags,
1477        PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
1478 {
1479     FIXME("%p %s %08lx %p\n", DeviceInfoSet,
1480         debugstr_a(DevicePath), OpenFlags, DeviceInterfaceData);
1481     return FALSE;
1482 }
1483
1484 /***********************************************************************
1485  *              SetupDiSetClassInstallParamsA (SETUPAPI.@)
1486  */
1487 BOOL WINAPI SetupDiSetClassInstallParamsA(
1488        HDEVINFO  DeviceInfoSet,
1489        PSP_DEVINFO_DATA DeviceInfoData,
1490        PSP_CLASSINSTALL_HEADER ClassInstallParams,
1491        DWORD ClassInstallParamsSize)
1492 {
1493     FIXME("%p %p %x %lu\n",DeviceInfoSet, DeviceInfoData,
1494           ClassInstallParams->InstallFunction, ClassInstallParamsSize);
1495     return FALSE;
1496 }
1497
1498 /***********************************************************************
1499  *              SetupDiCallClassInstaller (SETUPAPI.@)
1500  */
1501 BOOL WINAPI SetupDiCallClassInstaller(
1502        DI_FUNCTION InstallFunction,
1503        HDEVINFO DeviceInfoSet,
1504        PSP_DEVINFO_DATA DeviceInfoData)
1505 {
1506     FIXME("%d %p %p\n", InstallFunction, DeviceInfoSet, DeviceInfoData);
1507     return FALSE;
1508 }
1509
1510 /***********************************************************************
1511  *              SetupDiGetDeviceInstallParamsA (SETUPAPI.@)
1512  */
1513 BOOL WINAPI SetupDiGetDeviceInstallParamsA(
1514        HDEVINFO DeviceInfoSet,
1515        PSP_DEVINFO_DATA DeviceInfoData,
1516        PSP_DEVINSTALL_PARAMS_A DeviceInstallParams)
1517 {
1518     FIXME("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstallParams);
1519     return FALSE;
1520 }
1521
1522 /***********************************************************************
1523  *              SetupDiOpenDevRegKey (SETUPAPI.@)
1524  */
1525 HKEY WINAPI SetupDiOpenDevRegKey(
1526        HDEVINFO DeviceInfoSet,
1527        PSP_DEVINFO_DATA DeviceInfoData,
1528        DWORD Scope,
1529        DWORD HwProfile,
1530        DWORD KeyType,
1531        REGSAM samDesired)
1532 {
1533     FIXME("%p %p %ld %ld %ld %lx\n", DeviceInfoSet, DeviceInfoData,
1534           Scope, HwProfile, KeyType, samDesired);
1535     return INVALID_HANDLE_VALUE;
1536 }