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