Use LPSTORAGE to better match the PSDK.
[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 "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 /***********************************************************************
72  *              SetupDiBuildClassInfoList  (SETUPAPI.@)
73  */
74 BOOL WINAPI SetupDiBuildClassInfoList(
75         DWORD Flags,
76         LPGUID ClassGuidList,
77         DWORD ClassGuidListSize,
78         PDWORD RequiredSize)
79 {
80     TRACE("\n");
81     return SetupDiBuildClassInfoListExW(Flags, ClassGuidList,
82                                         ClassGuidListSize, RequiredSize,
83                                         NULL, NULL);
84 }
85
86 /***********************************************************************
87  *              SetupDiBuildClassInfoListExA  (SETUPAPI.@)
88  */
89 BOOL WINAPI SetupDiBuildClassInfoListExA(
90         DWORD Flags,
91         LPGUID ClassGuidList,
92         DWORD ClassGuidListSize,
93         PDWORD RequiredSize,
94         LPCSTR MachineName,
95         PVOID Reserved)
96 {
97     LPWSTR MachineNameW = NULL;
98     BOOL bResult;
99
100     TRACE("\n");
101
102     if (MachineName)
103     {
104         MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
105         if (MachineNameW == NULL) return FALSE;
106     }
107
108     bResult = SetupDiBuildClassInfoListExW(Flags, ClassGuidList,
109                                            ClassGuidListSize, RequiredSize,
110                                            MachineNameW, Reserved);
111
112     if (MachineNameW)
113         MyFree(MachineNameW);
114
115     return bResult;
116 }
117
118 /***********************************************************************
119  *              SetupDiBuildClassInfoListExW  (SETUPAPI.@)
120  */
121 BOOL WINAPI SetupDiBuildClassInfoListExW(
122         DWORD Flags,
123         LPGUID ClassGuidList,
124         DWORD ClassGuidListSize,
125         PDWORD RequiredSize,
126         LPCWSTR MachineName,
127         PVOID Reserved)
128 {
129     WCHAR szKeyName[40];
130     HKEY hClassesKey;
131     HKEY hClassKey;
132     DWORD dwLength;
133     DWORD dwIndex;
134     LONG lError;
135     DWORD dwGuidListIndex = 0;
136
137     TRACE("\n");
138
139     if (RequiredSize != NULL)
140         *RequiredSize = 0;
141
142     hClassesKey = SetupDiOpenClassRegKeyExW(NULL,
143                                             KEY_ALL_ACCESS,
144                                             DIOCR_INSTALLER,
145                                             MachineName,
146                                             Reserved);
147     if (hClassesKey == INVALID_HANDLE_VALUE)
148     {
149         return FALSE;
150     }
151
152     for (dwIndex = 0; ; dwIndex++)
153     {
154         dwLength = 40;
155         lError = RegEnumKeyExW(hClassesKey,
156                                dwIndex,
157                                szKeyName,
158                                &dwLength,
159                                NULL,
160                                NULL,
161                                NULL,
162                                NULL);
163         TRACE("RegEnumKeyExW() returns %ld\n", lError);
164         if (lError == ERROR_SUCCESS || lError == ERROR_MORE_DATA)
165         {
166             TRACE("Key name: %p\n", szKeyName);
167
168             if (RegOpenKeyExW(hClassesKey,
169                               szKeyName,
170                               0,
171                               KEY_ALL_ACCESS,
172                               &hClassKey))
173             {
174                 RegCloseKey(hClassesKey);
175                 return FALSE;
176             }
177
178             if (!RegQueryValueExW(hClassKey,
179                                   NoUseClass,
180                                   NULL,
181                                   NULL,
182                                   NULL,
183                                   NULL))
184             {
185                 TRACE("'NoUseClass' value found!\n");
186                 RegCloseKey(hClassKey);
187                 continue;
188             }
189
190             if ((Flags & DIBCI_NOINSTALLCLASS) &&
191                 (!RegQueryValueExW(hClassKey,
192                                    NoInstallClass,
193                                    NULL,
194                                    NULL,
195                                    NULL,
196                                    NULL)))
197             {
198                 TRACE("'NoInstallClass' value found!\n");
199                 RegCloseKey(hClassKey);
200                 continue;
201             }
202
203             if ((Flags & DIBCI_NODISPLAYCLASS) &&
204                 (!RegQueryValueExW(hClassKey,
205                                    NoDisplayClass,
206                                    NULL,
207                                    NULL,
208                                    NULL,
209                                    NULL)))
210             {
211                 TRACE("'NoDisplayClass' value found!\n");
212                 RegCloseKey(hClassKey);
213                 continue;
214             }
215
216             RegCloseKey(hClassKey);
217
218             TRACE("Guid: %p\n", szKeyName);
219             if (dwGuidListIndex < ClassGuidListSize)
220             {
221                 if (szKeyName[0] == L'{' && szKeyName[37] == L'}')
222                 {
223                     szKeyName[37] = 0;
224                 }
225                 TRACE("Guid: %p\n", &szKeyName[1]);
226
227                 UuidFromStringW(&szKeyName[1],
228                                 &ClassGuidList[dwGuidListIndex]);
229             }
230
231             dwGuidListIndex++;
232         }
233
234         if (lError != ERROR_SUCCESS)
235             break;
236     }
237
238     RegCloseKey(hClassesKey);
239
240     if (RequiredSize != NULL)
241         *RequiredSize = dwGuidListIndex;
242
243     if (ClassGuidListSize < dwGuidListIndex)
244     {
245         SetLastError(ERROR_INSUFFICIENT_BUFFER);
246         return FALSE;
247     }
248
249     return TRUE;
250 }
251
252 /***********************************************************************
253  *              SetupDiClassGuidsFromNameA  (SETUPAPI.@)
254  */
255 BOOL WINAPI SetupDiClassGuidsFromNameA(
256         LPCSTR ClassName,
257         LPGUID ClassGuidList,
258         DWORD ClassGuidListSize,
259         PDWORD RequiredSize)
260 {
261   return SetupDiClassGuidsFromNameExA(ClassName, ClassGuidList,
262                                       ClassGuidListSize, RequiredSize,
263                                       NULL, NULL);
264 }
265
266 /***********************************************************************
267  *              SetupDiClassGuidsFromNameW  (SETUPAPI.@)
268  */
269 BOOL WINAPI SetupDiClassGuidsFromNameW(
270         LPCWSTR ClassName,
271         LPGUID ClassGuidList,
272         DWORD ClassGuidListSize,
273         PDWORD RequiredSize)
274 {
275   return SetupDiClassGuidsFromNameExW(ClassName, ClassGuidList,
276                                       ClassGuidListSize, RequiredSize,
277                                       NULL, NULL);
278 }
279
280 /***********************************************************************
281  *              SetupDiClassGuidsFromNameExA  (SETUPAPI.@)
282  */
283 BOOL WINAPI SetupDiClassGuidsFromNameExA(
284         LPCSTR ClassName,
285         LPGUID ClassGuidList,
286         DWORD ClassGuidListSize,
287         PDWORD RequiredSize,
288         LPCSTR MachineName,
289         PVOID Reserved)
290 {
291     LPWSTR ClassNameW = NULL;
292     LPWSTR MachineNameW = NULL;
293     BOOL bResult;
294
295     FIXME("\n");
296
297     ClassNameW = MultiByteToUnicode(ClassName, CP_ACP);
298     if (ClassNameW == NULL)
299         return FALSE;
300
301     if (MachineNameW)
302     {
303         MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
304         if (MachineNameW == NULL)
305         {
306             MyFree(ClassNameW);
307             return FALSE;
308         }
309     }
310
311     bResult = SetupDiClassGuidsFromNameExW(ClassNameW, ClassGuidList,
312                                            ClassGuidListSize, RequiredSize,
313                                            MachineNameW, Reserved);
314
315     if (MachineNameW)
316         MyFree(MachineNameW);
317
318     MyFree(ClassNameW);
319
320     return bResult;
321 }
322
323 /***********************************************************************
324  *              SetupDiClassGuidsFromNameExW  (SETUPAPI.@)
325  */
326 BOOL WINAPI SetupDiClassGuidsFromNameExW(
327         LPCWSTR ClassName,
328         LPGUID ClassGuidList,
329         DWORD ClassGuidListSize,
330         PDWORD RequiredSize,
331         LPCWSTR MachineName,
332         PVOID Reserved)
333 {
334     WCHAR szKeyName[40];
335     WCHAR szClassName[256];
336     HKEY hClassesKey;
337     HKEY hClassKey;
338     DWORD dwLength;
339     DWORD dwIndex;
340     LONG lError;
341     DWORD dwGuidListIndex = 0;
342
343     if (RequiredSize != NULL)
344         *RequiredSize = 0;
345
346     hClassesKey = SetupDiOpenClassRegKeyExW(NULL,
347                                             KEY_ALL_ACCESS,
348                                             DIOCR_INSTALLER,
349                                             MachineName,
350                                             Reserved);
351     if (hClassesKey == INVALID_HANDLE_VALUE)
352     {
353         return FALSE;
354     }
355
356     for (dwIndex = 0; ; dwIndex++)
357     {
358         dwLength = 40;
359         lError = RegEnumKeyExW(hClassesKey,
360                                dwIndex,
361                                szKeyName,
362                                &dwLength,
363                                NULL,
364                                NULL,
365                                NULL,
366                                NULL);
367         TRACE("RegEnumKeyExW() returns %ld\n", lError);
368         if (lError == ERROR_SUCCESS || lError == ERROR_MORE_DATA)
369         {
370             TRACE("Key name: %p\n", szKeyName);
371
372             if (RegOpenKeyExW(hClassesKey,
373                               szKeyName,
374                               0,
375                               KEY_ALL_ACCESS,
376                               &hClassKey))
377             {
378                 RegCloseKey(hClassesKey);
379                 return FALSE;
380             }
381
382             dwLength = 256 * sizeof(WCHAR);
383             if (!RegQueryValueExW(hClassKey,
384                                   Class,
385                                   NULL,
386                                   NULL,
387                                   (LPBYTE)szClassName,
388                                   &dwLength))
389             {
390                 TRACE("Class name: %p\n", szClassName);
391
392                 if (strcmpiW(szClassName, ClassName) == 0)
393                 {
394                     TRACE("Found matching class name\n");
395
396                     TRACE("Guid: %p\n", szKeyName);
397                     if (dwGuidListIndex < ClassGuidListSize)
398                     {
399                         if (szKeyName[0] == L'{' && szKeyName[37] == L'}')
400                         {
401                             szKeyName[37] = 0;
402                         }
403                         TRACE("Guid: %p\n", &szKeyName[1]);
404
405                         UuidFromStringW(&szKeyName[1],
406                                         &ClassGuidList[dwGuidListIndex]);
407                     }
408
409                     dwGuidListIndex++;
410                 }
411             }
412
413             RegCloseKey(hClassKey);
414         }
415
416         if (lError != ERROR_SUCCESS)
417             break;
418     }
419
420     RegCloseKey(hClassesKey);
421
422     if (RequiredSize != NULL)
423         *RequiredSize = dwGuidListIndex;
424
425     if (ClassGuidListSize < dwGuidListIndex)
426     {
427         SetLastError(ERROR_INSUFFICIENT_BUFFER);
428         return FALSE;
429     }
430
431     return TRUE;
432 }
433
434 /***********************************************************************
435  *              SetupDiClassNameFromGuidA  (SETUPAPI.@)
436  */
437 BOOL WINAPI SetupDiClassNameFromGuidA(
438         const GUID* ClassGuid,
439         PSTR ClassName,
440         DWORD ClassNameSize,
441         PDWORD RequiredSize)
442 {
443   return SetupDiClassNameFromGuidExA(ClassGuid, ClassName,
444                                      ClassNameSize, RequiredSize,
445                                      NULL, NULL);
446 }
447
448 /***********************************************************************
449  *              SetupDiClassNameFromGuidW  (SETUPAPI.@)
450  */
451 BOOL WINAPI SetupDiClassNameFromGuidW(
452         const GUID* ClassGuid,
453         PWSTR ClassName,
454         DWORD ClassNameSize,
455         PDWORD RequiredSize)
456 {
457   return SetupDiClassNameFromGuidExW(ClassGuid, ClassName,
458                                      ClassNameSize, RequiredSize,
459                                      NULL, NULL);
460 }
461
462 /***********************************************************************
463  *              SetupDiClassNameFromGuidExA  (SETUPAPI.@)
464  */
465 BOOL WINAPI SetupDiClassNameFromGuidExA(
466         const GUID* ClassGuid,
467         PSTR ClassName,
468         DWORD ClassNameSize,
469         PDWORD RequiredSize,
470         PCSTR MachineName,
471         PVOID Reserved)
472 {
473     WCHAR ClassNameW[MAX_CLASS_NAME_LEN];
474     LPWSTR MachineNameW = NULL;
475     BOOL ret;
476
477     if (MachineName)
478         MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
479     ret = SetupDiClassNameFromGuidExW(ClassGuid, ClassNameW, MAX_CLASS_NAME_LEN,
480      NULL, MachineNameW, Reserved);
481     if (ret)
482     {
483         int len = WideCharToMultiByte(CP_ACP, 0, ClassNameW, -1, ClassName,
484          ClassNameSize, NULL, NULL);
485
486         if (!ClassNameSize && RequiredSize)
487             *RequiredSize = len;
488     }
489     MyFree(MachineNameW);
490     return ret;
491 }
492
493 /***********************************************************************
494  *              SetupDiClassNameFromGuidExW  (SETUPAPI.@)
495  */
496 BOOL WINAPI SetupDiClassNameFromGuidExW(
497         const GUID* ClassGuid,
498         PWSTR ClassName,
499         DWORD ClassNameSize,
500         PDWORD RequiredSize,
501         PCWSTR MachineName,
502         PVOID Reserved)
503 {
504     HKEY hKey;
505     DWORD dwLength;
506
507     hKey = SetupDiOpenClassRegKeyExW(ClassGuid,
508                                      KEY_ALL_ACCESS,
509                                      DIOCR_INSTALLER,
510                                      MachineName,
511                                      Reserved);
512     if (hKey == INVALID_HANDLE_VALUE)
513     {
514         return FALSE;
515     }
516
517     if (RequiredSize != NULL)
518     {
519         dwLength = 0;
520         if (RegQueryValueExW(hKey,
521                              Class,
522                              NULL,
523                              NULL,
524                              NULL,
525                              &dwLength))
526         {
527             RegCloseKey(hKey);
528             return FALSE;
529         }
530
531         *RequiredSize = dwLength / sizeof(WCHAR);
532     }
533
534     dwLength = ClassNameSize * sizeof(WCHAR);
535     if (RegQueryValueExW(hKey,
536                          Class,
537                          NULL,
538                          NULL,
539                          (LPBYTE)ClassName,
540                          &dwLength))
541     {
542         RegCloseKey(hKey);
543         return FALSE;
544     }
545
546     RegCloseKey(hKey);
547
548     return TRUE;
549 }
550
551 /***********************************************************************
552  *              SetupDiCreateDeviceInfoList (SETUPAPI.@)
553  */
554 HDEVINFO WINAPI
555 SetupDiCreateDeviceInfoList(const GUID *ClassGuid,
556                             HWND hwndParent)
557 {
558   return SetupDiCreateDeviceInfoListExW(ClassGuid, hwndParent, NULL, NULL);
559 }
560
561 /***********************************************************************
562  *              SetupDiCreateDeviceInfoListExA (SETUPAPI.@)
563  */
564 HDEVINFO WINAPI
565 SetupDiCreateDeviceInfoListExA(const GUID *ClassGuid,
566                                HWND hwndParent,
567                                PCSTR MachineName,
568                                PVOID Reserved)
569 {
570     LPWSTR MachineNameW = NULL;
571     HDEVINFO hDevInfo;
572
573     TRACE("\n");
574
575     if (MachineName)
576     {
577         MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
578         if (MachineNameW == NULL)
579             return (HDEVINFO)INVALID_HANDLE_VALUE;
580     }
581
582     hDevInfo = SetupDiCreateDeviceInfoListExW(ClassGuid, hwndParent,
583                                               MachineNameW, Reserved);
584
585     if (MachineNameW)
586         MyFree(MachineNameW);
587
588     return hDevInfo;
589 }
590
591 /***********************************************************************
592  *              SetupDiCreateDeviceInfoListExW (SETUPAPI.@)
593  */
594 HDEVINFO WINAPI
595 SetupDiCreateDeviceInfoListExW(const GUID *ClassGuid,
596                                HWND hwndParent,
597                                PCWSTR MachineName,
598                                PVOID Reserved)
599 {
600   FIXME("\n");
601   return (HDEVINFO)INVALID_HANDLE_VALUE;
602 }
603
604 /***********************************************************************
605  *              SetupDiEnumDeviceInfo (SETUPAPI.@)
606  */
607 BOOL WINAPI SetupDiEnumDeviceInfo(
608         HDEVINFO  devinfo,
609         DWORD  index,
610         PSP_DEVINFO_DATA info)
611 {
612     FIXME("%p %ld %p\n", devinfo, index, info);
613
614     if(info==NULL)
615         return FALSE;
616     if(info->cbSize < sizeof(*info))
617         return FALSE;
618
619     return FALSE;
620 }
621
622 /***********************************************************************
623  *              SetupDiGetActualSectionToInstallA (SETUPAPI.@)
624  */
625 BOOL WINAPI SetupDiGetActualSectionToInstallA(
626         HINF InfHandle,
627         PCSTR InfSectionName,
628         PSTR InfSectionWithExt,
629         DWORD InfSectionWithExtSize,
630         PDWORD RequiredSize,
631         PSTR *Extension)
632 {
633     FIXME("\n");
634     return FALSE;
635 }
636
637 /***********************************************************************
638  *              SetupDiGetActualSectionToInstallW (SETUPAPI.@)
639  */
640 BOOL WINAPI SetupDiGetActualSectionToInstallW(
641         HINF InfHandle,
642         PCWSTR InfSectionName,
643         PWSTR InfSectionWithExt,
644         DWORD InfSectionWithExtSize,
645         PDWORD RequiredSize,
646         PWSTR *Extension)
647 {
648     WCHAR szBuffer[MAX_PATH];
649     DWORD dwLength;
650     DWORD dwFullLength;
651     LONG lLineCount = -1;
652
653     lstrcpyW(szBuffer, InfSectionName);
654     dwLength = lstrlenW(szBuffer);
655
656     if (OsVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
657     {
658         /* Test section name with '.NTx86' extension */
659         lstrcpyW(&szBuffer[dwLength], NtPlatformExtension);
660         lLineCount = SetupGetLineCountW(InfHandle, szBuffer);
661
662         if (lLineCount == -1)
663         {
664             /* Test section name with '.NT' extension */
665             lstrcpyW(&szBuffer[dwLength], NtExtension);
666             lLineCount = SetupGetLineCountW(InfHandle, szBuffer);
667         }
668     }
669     else
670     {
671         /* Test section name with '.Win' extension */
672         lstrcpyW(&szBuffer[dwLength], WinExtension);
673         lLineCount = SetupGetLineCountW(InfHandle, szBuffer);
674     }
675
676     if (lLineCount == -1)
677     {
678         /* Test section name without extension */
679         szBuffer[dwLength] = 0;
680         lLineCount = SetupGetLineCountW(InfHandle, szBuffer);
681     }
682
683     if (lLineCount == -1)
684     {
685         SetLastError(ERROR_INVALID_PARAMETER);
686         return FALSE;
687     }
688
689     dwFullLength = lstrlenW(szBuffer);
690
691     if (InfSectionWithExt != NULL && InfSectionWithExtSize != 0)
692     {
693         if (InfSectionWithExtSize < (dwFullLength + 1))
694         {
695             SetLastError(ERROR_INSUFFICIENT_BUFFER);
696             return FALSE;
697         }
698
699         lstrcpyW(InfSectionWithExt, szBuffer);
700         if (Extension != NULL)
701         {
702             *Extension = (dwLength == dwFullLength) ? NULL : &InfSectionWithExt[dwLength];
703         }
704     }
705
706     if (RequiredSize != NULL)
707     {
708         *RequiredSize = dwFullLength + 1;
709     }
710
711     return TRUE;
712 }
713
714 /***********************************************************************
715  *              SetupDiGetClassDescriptionA  (SETUPAPI.@)
716  */
717 BOOL WINAPI SetupDiGetClassDescriptionA(
718         const GUID* ClassGuid,
719         PSTR ClassDescription,
720         DWORD ClassDescriptionSize,
721         PDWORD RequiredSize)
722 {
723   return SetupDiGetClassDescriptionExA(ClassGuid, ClassDescription,
724                                        ClassDescriptionSize,
725                                        RequiredSize, NULL, NULL);
726 }
727
728 /***********************************************************************
729  *              SetupDiGetClassDescriptionW  (SETUPAPI.@)
730  */
731 BOOL WINAPI SetupDiGetClassDescriptionW(
732         const GUID* ClassGuid,
733         PWSTR ClassDescription,
734         DWORD ClassDescriptionSize,
735         PDWORD RequiredSize)
736 {
737   return SetupDiGetClassDescriptionExW(ClassGuid, ClassDescription,
738                                        ClassDescriptionSize,
739                                        RequiredSize, NULL, NULL);
740 }
741
742 /***********************************************************************
743  *              SetupDiGetClassDescriptionExA  (SETUPAPI.@)
744  */
745 BOOL WINAPI SetupDiGetClassDescriptionExA(
746         const GUID* ClassGuid,
747         PSTR ClassDescription,
748         DWORD ClassDescriptionSize,
749         PDWORD RequiredSize,
750         PCSTR MachineName,
751         PVOID Reserved)
752 {
753   FIXME("\n");
754   return FALSE;
755 }
756
757 /***********************************************************************
758  *              SetupDiGetClassDescriptionExW  (SETUPAPI.@)
759  */
760 BOOL WINAPI SetupDiGetClassDescriptionExW(
761         const GUID* ClassGuid,
762         PWSTR ClassDescription,
763         DWORD ClassDescriptionSize,
764         PDWORD RequiredSize,
765         PCWSTR MachineName,
766         PVOID Reserved)
767 {
768     HKEY hKey;
769     DWORD dwLength;
770
771     hKey = SetupDiOpenClassRegKeyExW(ClassGuid,
772                                      KEY_ALL_ACCESS,
773                                      DIOCR_INSTALLER,
774                                      MachineName,
775                                      Reserved);
776     if (hKey == INVALID_HANDLE_VALUE)
777     {
778         WARN("SetupDiOpenClassRegKeyExW() failed (Error %lu)\n", GetLastError());
779         return FALSE;
780     }
781
782     if (RequiredSize != NULL)
783     {
784         dwLength = 0;
785         if (RegQueryValueExW(hKey,
786                              NULL,
787                              NULL,
788                              NULL,
789                              NULL,
790                              &dwLength))
791         {
792             RegCloseKey(hKey);
793             return FALSE;
794         }
795
796         *RequiredSize = dwLength / sizeof(WCHAR);
797     }
798
799     dwLength = ClassDescriptionSize * sizeof(WCHAR);
800     if (RegQueryValueExW(hKey,
801                          NULL,
802                          NULL,
803                          NULL,
804                          (LPBYTE)ClassDescription,
805                          &dwLength))
806     {
807         RegCloseKey(hKey);
808         return FALSE;
809     }
810
811     RegCloseKey(hKey);
812
813     return TRUE;
814 }
815
816 /***********************************************************************
817  *              SetupDiGetClassDevsA (SETUPAPI.@)
818  */
819 HDEVINFO WINAPI SetupDiGetClassDevsA(
820        CONST GUID *class,
821        LPCSTR enumstr,
822        HWND parent,
823        DWORD flags)
824 {
825     HDEVINFO ret;
826     LPWSTR enumstrW = NULL;
827
828     if (enumstr)
829     {
830         int len = MultiByteToWideChar(CP_ACP, 0, enumstr, -1, NULL, 0);
831         enumstrW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
832         if (!enumstrW)
833         {
834             ret = (HDEVINFO)INVALID_HANDLE_VALUE;
835             goto end;
836         }
837         MultiByteToWideChar(CP_ACP, 0, enumstr, -1, enumstrW, len);
838     }
839     ret = SetupDiGetClassDevsW(class, enumstrW, parent, flags);
840     HeapFree(GetProcessHeap(), 0, enumstrW);
841
842 end:
843     return ret;
844 }
845
846 #define SETUP_SERIAL_PORT_MAGIC 0xd00ff055
847
848 typedef struct _SerialPortName
849 {
850     WCHAR name[5];
851 } SerialPortName;
852
853 typedef struct _SerialPortList
854 {
855     DWORD magic;
856     UINT  numPorts;
857     SerialPortName names[1];
858 } SerialPortList;
859
860 static HDEVINFO SETUP_CreateSerialDeviceList(void)
861 {
862     static const size_t initialSize = 100;
863     size_t size;
864     WCHAR buf[initialSize];
865     LPWSTR devices;
866     HDEVINFO ret;
867     BOOL failed = FALSE;
868
869     devices = buf;
870     size = initialSize;
871     do {
872         if (QueryDosDeviceW(NULL, devices, size) == 0)
873         {
874             if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
875             {
876                 size *= 2;
877                 if (devices != buf)
878                     HeapFree(GetProcessHeap(), 0, devices);
879                 devices = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
880                 if (!devices)
881                     failed = TRUE;
882                 else
883                     *devices = 0;
884             }
885             else
886                 failed = TRUE;
887         }
888     } while (!*devices && !failed);
889     if (!failed)
890     {
891         static const WCHAR comW[] = { 'C','O','M',0 };
892         LPWSTR ptr;
893         UINT numSerialPorts = 0;
894         SerialPortList *list;
895
896         for (ptr = devices; *ptr; ptr += strlenW(ptr) + 1)
897         {
898             if (!strncmpW(comW, ptr, sizeof(comW) / sizeof(comW[0]) - 1))
899                 numSerialPorts++;
900         }
901         list = HeapAlloc(GetProcessHeap(), 0, sizeof(SerialPortList) +
902          numSerialPorts ? (numSerialPorts - 1) * sizeof(SerialPortName) : 0);
903         if (list)
904         {
905             list->magic = SETUP_SERIAL_PORT_MAGIC;
906             list->numPorts = 0;
907             for (ptr = devices; *ptr; ptr += strlenW(ptr) + 1)
908             {
909                 if (!strncmpW(comW, ptr, sizeof(comW) / sizeof(comW[0]) - 1))
910                 {
911                     lstrcpynW(list->names[list->numPorts].name, ptr,
912                      sizeof(list->names[list->numPorts].name) /
913                      sizeof(list->names[list->numPorts].name[0]));
914                     TRACE("Adding %s to list\n",
915                      debugstr_w(list->names[list->numPorts].name));
916                     list->numPorts++;
917                 }
918             }
919             TRACE("list->numPorts is %d\n", list->numPorts);
920         }
921         ret = (HDEVINFO)list;
922     }
923     else
924         ret = (HDEVINFO)INVALID_HANDLE_VALUE;
925     if (devices != buf)
926         HeapFree(GetProcessHeap(), 0, devices);
927     TRACE("returning %p\n", ret);
928     return ret;
929 }
930
931 /***********************************************************************
932  *              SetupDiGetClassDevsW (SETUPAPI.@)
933  */
934 HDEVINFO WINAPI SetupDiGetClassDevsW(
935        CONST GUID *class,
936        LPCWSTR enumstr,
937        HWND parent,
938        DWORD flags)
939 {
940     HDEVINFO ret = (HDEVINFO)INVALID_HANDLE_VALUE;
941
942     TRACE("%s %s %p 0x%08lx\n", debugstr_guid(class), debugstr_w(enumstr),
943      parent, flags);
944
945     if (enumstr)
946         FIXME(": unimplemented for enumerator strings (%s)\n",
947          debugstr_w(enumstr));
948     else if (flags & DIGCF_ALLCLASSES)
949         FIXME(": unimplemented for DIGCF_ALLCLASSES\n");
950     else
951     {
952         if (IsEqualIID(class, &GUID_DEVINTERFACE_COMPORT))
953             ret = SETUP_CreateSerialDeviceList();
954         else if (IsEqualIID(class, &GUID_DEVINTERFACE_SERENUM_BUS_ENUMERATOR))
955             ret = SETUP_CreateSerialDeviceList();
956         else
957             FIXME("(%s): stub\n", debugstr_guid(class));
958     }
959     return ret;
960 }
961
962 /***********************************************************************
963  *              SetupDiEnumDeviceInterfaces (SETUPAPI.@)
964  */
965 BOOL WINAPI SetupDiEnumDeviceInterfaces(
966        HDEVINFO DeviceInfoSet,
967        PSP_DEVINFO_DATA DeviceInfoData,
968        CONST GUID * InterfaceClassGuid,
969        DWORD MemberIndex,
970        PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
971 {
972     BOOL ret = FALSE;
973
974     TRACE("%p, %p, %s, 0x%08lx, %p\n", DeviceInfoSet, DeviceInfoData,
975      debugstr_guid(InterfaceClassGuid), MemberIndex, DeviceInterfaceData);
976     if (!DeviceInterfaceData)
977         SetLastError(ERROR_INVALID_PARAMETER);
978     else if (DeviceInfoData)
979         FIXME(": unimplemented with PSP_DEVINFO_DATA set\n");
980     else if (DeviceInfoSet && DeviceInfoSet != (HDEVINFO)INVALID_HANDLE_VALUE)
981     {
982         /* FIXME: this assumes the only possible enumeration is of serial
983          * ports.
984          */
985         SerialPortList *list = (SerialPortList *)DeviceInfoSet;
986
987         if (list->magic == SETUP_SERIAL_PORT_MAGIC)
988         {
989             if (MemberIndex >= list->numPorts)
990                 SetLastError(ERROR_NO_MORE_ITEMS);
991             else
992             {
993                 DeviceInterfaceData->cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
994                 memcpy(&DeviceInterfaceData->InterfaceClassGuid,
995                  &GUID_DEVINTERFACE_SERENUM_BUS_ENUMERATOR,
996                  sizeof(DeviceInterfaceData->InterfaceClassGuid));
997                 DeviceInterfaceData->Flags = 0;
998                 /* Note: this appears to be dangerous, passing a private
999                  * pointer a heap-allocated datum to the caller.  However, the
1000                  * expected lifetime of the device data is the same as the
1001                  * HDEVINFO; once that is closed, the data are no longer valid.
1002                  */
1003                 DeviceInterfaceData->Reserved =
1004                  (ULONG_PTR)&list->names[MemberIndex].name;
1005                 ret = TRUE;
1006             }
1007         }
1008         else
1009             SetLastError(ERROR_INVALID_HANDLE);
1010     }
1011     else
1012         SetLastError(ERROR_INVALID_HANDLE);
1013     return ret;
1014 }
1015
1016 /***********************************************************************
1017  *              SetupDiDestroyDeviceInfoList (SETUPAPI.@)
1018  */
1019 BOOL WINAPI SetupDiDestroyDeviceInfoList(HDEVINFO devinfo)
1020 {
1021     BOOL ret = FALSE;
1022
1023     TRACE("%p\n", devinfo);
1024     if (devinfo && devinfo != (HDEVINFO)INVALID_HANDLE_VALUE)
1025     {
1026         /* FIXME: this assumes the only possible enumeration is of serial
1027          * ports.
1028          */
1029         SerialPortList *list = (SerialPortList *)devinfo;
1030
1031         if (list->magic == SETUP_SERIAL_PORT_MAGIC)
1032         {
1033             HeapFree(GetProcessHeap(), 0, list);
1034             ret = TRUE;
1035         }
1036         else
1037             SetLastError(ERROR_INVALID_HANDLE);
1038     }
1039     else
1040         SetLastError(ERROR_INVALID_HANDLE);
1041     return ret;
1042 }
1043
1044 /***********************************************************************
1045  *              SetupDiGetDeviceInterfaceDetailA (SETUPAPI.@)
1046  */
1047 BOOL WINAPI SetupDiGetDeviceInterfaceDetailA(
1048       HDEVINFO DeviceInfoSet,
1049       PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
1050       PSP_DEVICE_INTERFACE_DETAIL_DATA_A DeviceInterfaceDetailData,
1051       DWORD DeviceInterfaceDetailDataSize,
1052       PDWORD RequiredSize,
1053       PSP_DEVINFO_DATA DeviceInfoData)
1054 {
1055     BOOL ret = FALSE;
1056
1057     TRACE("(%p, %p, %p, %ld, %p, %p)\n", DeviceInfoSet,
1058      DeviceInterfaceData, DeviceInterfaceDetailData,
1059      DeviceInterfaceDetailDataSize, RequiredSize, DeviceInfoData);
1060     if (!DeviceInterfaceData)
1061         SetLastError(ERROR_INVALID_PARAMETER);
1062     else if ((DeviceInterfaceDetailDataSize && !DeviceInterfaceDetailData) ||
1063      (DeviceInterfaceDetailData && !DeviceInterfaceDetailDataSize))
1064         SetLastError(ERROR_INVALID_PARAMETER);
1065     else if (DeviceInfoSet && DeviceInfoSet != (HDEVINFO)INVALID_HANDLE_VALUE)
1066     {
1067         /* FIXME: this assumes the only possible enumeration is of serial
1068          * ports.
1069          */
1070         SerialPortList *list = (SerialPortList *)DeviceInfoSet;
1071
1072         if (list->magic == SETUP_SERIAL_PORT_MAGIC)
1073         {
1074             LPCWSTR devName = (LPCWSTR)DeviceInterfaceData->Reserved;
1075             DWORD sizeRequired = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A) +
1076              lstrlenW(devName);
1077
1078             if (sizeRequired > DeviceInterfaceDetailDataSize)
1079             {
1080                 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1081                 if (RequiredSize)
1082                     *RequiredSize = sizeRequired;
1083             }
1084             else
1085             {
1086                 LPSTR dst = DeviceInterfaceDetailData->DevicePath;
1087                 LPCWSTR src = devName;
1088
1089                 /* MSDN claims cbSize must be set by the caller, but it lies */
1090                 DeviceInterfaceDetailData->cbSize =
1091                  sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A);
1092                 for ( ; *src; src++, dst++)
1093                     *dst = *src;
1094                 *dst = '\0';
1095                 TRACE("DevicePath is %s\n",
1096                  debugstr_a(DeviceInterfaceDetailData->DevicePath));
1097                 if (DeviceInfoData)
1098                 {
1099                     DeviceInfoData->cbSize = sizeof(SP_DEVINFO_DATA);
1100                     memcpy(&DeviceInfoData->ClassGuid,
1101                      &GUID_DEVINTERFACE_SERENUM_BUS_ENUMERATOR,
1102                      sizeof(DeviceInfoData->ClassGuid));
1103                     DeviceInfoData->DevInst = 0;
1104                     DeviceInfoData->Reserved = (ULONG_PTR)devName;
1105                 }
1106                 ret = TRUE;
1107             }
1108         }
1109         else
1110             SetLastError(ERROR_INVALID_HANDLE);
1111     }
1112     else
1113         SetLastError(ERROR_INVALID_HANDLE);
1114     TRACE("Returning %d\n", ret);
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     if (MachineNameW)
1380         MyFree(MachineNameW);
1381
1382     return hKey;
1383 }
1384
1385
1386 /***********************************************************************
1387  *              SetupDiOpenClassRegKeyExW  (SETUPAPI.@)
1388  */
1389 HKEY WINAPI SetupDiOpenClassRegKeyExW(
1390         const GUID* ClassGuid,
1391         REGSAM samDesired,
1392         DWORD Flags,
1393         PCWSTR MachineName,
1394         PVOID Reserved)
1395 {
1396     LPWSTR lpGuidString;
1397     HKEY hClassesKey;
1398     HKEY hClassKey;
1399     LPCWSTR lpKeyName;
1400
1401     if (MachineName != NULL)
1402     {
1403         FIXME("Remote access not supported yet!\n");
1404         return INVALID_HANDLE_VALUE;
1405     }
1406
1407     if (Flags == DIOCR_INSTALLER)
1408     {
1409         lpKeyName = ControlClass;
1410     }
1411     else if (Flags == DIOCR_INTERFACE)
1412     {
1413         lpKeyName = DeviceClasses;
1414     }
1415     else
1416     {
1417         ERR("Invalid Flags parameter!\n");
1418         SetLastError(ERROR_INVALID_PARAMETER);
1419         return INVALID_HANDLE_VALUE;
1420     }
1421
1422     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1423                       lpKeyName,
1424                       0,
1425                       KEY_ALL_ACCESS,
1426                       &hClassesKey))
1427     {
1428         return INVALID_HANDLE_VALUE;
1429     }
1430
1431     if (ClassGuid == NULL)
1432         return hClassesKey;
1433
1434     if (UuidToStringW((UUID*)ClassGuid, &lpGuidString) != RPC_S_OK)
1435     {
1436         RegCloseKey(hClassesKey);
1437         return FALSE;
1438     }
1439
1440     if (RegOpenKeyExW(hClassesKey,
1441                       lpGuidString,
1442                       0,
1443                       KEY_ALL_ACCESS,
1444                       &hClassKey))
1445     {
1446         RpcStringFreeW(&lpGuidString);
1447         RegCloseKey(hClassesKey);
1448         return FALSE;
1449     }
1450
1451     RpcStringFreeW(&lpGuidString);
1452     RegCloseKey(hClassesKey);
1453
1454     return hClassKey;
1455 }
1456
1457 /***********************************************************************
1458  *              SetupDiOpenDeviceInterfaceW (SETUPAPI.@)
1459  */
1460 BOOL WINAPI SetupDiOpenDeviceInterfaceW(
1461        HDEVINFO DeviceInfoSet,
1462        PCWSTR DevicePath,
1463        DWORD OpenFlags,
1464        PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
1465 {
1466     FIXME("%p %s %08lx %p\n",
1467         DeviceInfoSet, debugstr_w(DevicePath), OpenFlags, DeviceInterfaceData);
1468     return FALSE;
1469 }
1470
1471 /***********************************************************************
1472  *              SetupDiOpenDeviceInterfaceA (SETUPAPI.@)
1473  */
1474 BOOL WINAPI SetupDiOpenDeviceInterfaceA(
1475        HDEVINFO DeviceInfoSet,
1476        PCSTR DevicePath,
1477        DWORD OpenFlags,
1478        PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
1479 {
1480     FIXME("%p %s %08lx %p\n", DeviceInfoSet,
1481         debugstr_a(DevicePath), OpenFlags, DeviceInterfaceData);
1482     return FALSE;
1483 }
1484
1485 /***********************************************************************
1486  *              SetupDiSetClassInstallParamsA (SETUPAPI.@)
1487  */
1488 BOOL WINAPI SetupDiSetClassInstallParamsA(
1489        HDEVINFO  DeviceInfoSet,
1490        PSP_DEVINFO_DATA DeviceInfoData,
1491        PSP_CLASSINSTALL_HEADER ClassInstallParams,
1492        DWORD ClassInstallParamsSize)
1493 {
1494     FIXME("%p %p %x %lu\n",DeviceInfoSet, DeviceInfoData,
1495           ClassInstallParams->InstallFunction, ClassInstallParamsSize);
1496     return FALSE;
1497 }
1498
1499 /***********************************************************************
1500  *              SetupDiCallClassInstaller (SETUPAPI.@)
1501  */
1502 BOOL WINAPI SetupDiCallClassInstaller(
1503        DI_FUNCTION InstallFunction,
1504        HDEVINFO DeviceInfoSet,
1505        PSP_DEVINFO_DATA DeviceInfoData)
1506 {
1507     FIXME("%d %p %p\n", InstallFunction, DeviceInfoSet, DeviceInfoData);
1508     return FALSE;
1509 }
1510
1511 /***********************************************************************
1512  *              SetupDiGetDeviceInstallParamsA (SETUPAPI.@)
1513  */
1514 BOOL WINAPI SetupDiGetDeviceInstallParamsA(
1515        HDEVINFO DeviceInfoSet,
1516        PSP_DEVINFO_DATA DeviceInfoData,
1517        PSP_DEVINSTALL_PARAMS_A DeviceInstallParams)
1518 {
1519     FIXME("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstallParams);
1520     return FALSE;
1521 }
1522
1523 /***********************************************************************
1524  *              SetupDiOpenDevRegKey (SETUPAPI.@)
1525  */
1526 HKEY WINAPI SetupDiOpenDevRegKey(
1527        HDEVINFO DeviceInfoSet,
1528        PSP_DEVINFO_DATA DeviceInfoData,
1529        DWORD Scope,
1530        DWORD HwProfile,
1531        DWORD KeyType,
1532        REGSAM samDesired)
1533 {
1534     FIXME("%p %p %ld %ld %ld %lx\n", DeviceInfoSet, DeviceInfoData,
1535           Scope, HwProfile, KeyType, samDesired);
1536     return INVALID_HANDLE_VALUE;
1537 }