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