Active functions related to interfaces enumeration: SETUP_CreateSerialDeviceList...
[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 /* FIXME: header mess */
80 DEFINE_GUID(GUID_NULL,
81 0x00000000L, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
82
83 #define SETUP_DEV_INFO_SET_MAGIC 0xd00ff057
84
85 struct DeviceInterface /* Element of DeviceInfoElement.InterfaceListHead */
86 {
87 LIST_ENTRY ListEntry;
88
89 struct DeviceInfoElement* DeviceInfo;
90 GUID InterfaceClassGuid;
91
92
93 /* SPINT_ACTIVE : the interface is active/enabled
94 * SPINT_DEFAULT: the interface is the default interface for the device class FIXME???
95 * SPINT_REMOVED: the interface is removed
96 */
97 DWORD Flags;
98
99 WCHAR SymbolicLink[0]; /* \\?\ACPI#PNP0501#4&2658d0a0&0#{GUID} */
100 };
101
102 struct DriverInfoElement /* Element of DeviceInfoSet.DriverListHead and DeviceInfoElement.DriverListHead */
103 {
104 LIST_ENTRY ListEntry;
105
106 SP_DRVINFO_DATA_V2_W Info;
107 };
108
109 struct DeviceInfoElement /* Element of DeviceInfoSet.ListHead */
110 {
111 LIST_ENTRY ListEntry;
112
113 /* Information about devnode:
114 * - DeviceName:
115 * "Root\*PNP0501" for example.
116 * It doesn't contain the unique ID for the device
117 * (points into the Data field at the end of the structure)
118 * WARNING: no NULL char exist between DeviceName and UniqueId
119 * in Data field!
120 * - UniqueId
121 * "5&1be2108e&0" or "0000"
122 * If DICD_GENERATE_ID is specified in creation flags,
123 * this unique ID is autogenerated using 4 digits, base 10
124 * (points into the Data field at the end of the structure)
125 * - DeviceDescription
126 * String which identifies the device. Can be NULL. If not NULL,
127 * points into the Data field at the end of the structure
128 * - ClassGuid
129 * Identifies the class of this device. FIXME: can it be GUID_NULL?
130 * - CreationFlags
131 * Is a combination of:
132 * - DICD_GENERATE_ID
133 * the unique ID needs to be generated
134 * - DICD_INHERIT_CLASSDRVS
135 * inherit driver of the device info set (== same pointer)
136 * - hwndParent
137 * Used when doing device-specific actions. Can be NULL
138 */
139 PCWSTR DeviceName;
140 PCWSTR UniqueId;
141 PCWSTR DeviceDescription;
142 GUID ClassGuid;
143 DWORD CreationFlags;
144 HWND hwndParent;
145
146 /* Flags is a combination of:
147 * - DI_DIDCOMPAT
148 * Set when the device driver list is created
149 * FlagsEx is a combination of:
150 */
151 DWORD Flags;
152 DWORD FlagsEx;
153
154 /* If CreationFlags contains DICD_INHERIT_CLASSDRVS, this list is invalid */
155 /* If the driver is not searched/detected, this list is empty */
156 LIST_ENTRY DriverListHead; /* List of struct DriverInfoElement */
157 /* Points into DriverListHead list. The pointer is NULL if no driver is
158 * currently chosen. */
159 struct DriverInfoElement *SelectedDriver;
160
161 /* List of interfaces implemented by this device */
162 LIST_ENTRY InterfaceListHead; /* List of struct DeviceInterface */
163
164 WCHAR Data[0];
165 };
166
167 struct DeviceInfoSet /* HDEVINFO */
168 {
169 DWORD magic; /* SETUP_DEV_INFO_SET_MAGIC */
170 GUID ClassGuid; /* If != GUID_NULL, only devices of this class can be in the device info set */
171 HWND hwndParent; /* only used on non-device-specific actions, like as a select-device dialog using the global class driver list */
172 HKEY HKLM; /* Local or distant HKEY_LOCAL_MACHINE registry key */
173
174 /* Flags is a combination of:
175 * - DI_DIDCLASS
176 * Set when the class driver list is created
177 * - DI_COMPAT_FROM_CLASS (FIXME: not supported)
178 * Forces SetupDiBuildDriverInfoList to build a class drivers list
179 * FlagsEx is a combination of:
180 */
181 DWORD Flags;
182 DWORD FlagsEx;
183
184 /* If the driver is not searched/detected, this list is empty */
185 LIST_ENTRY DriverListHead; /* List of struct DriverInfoElement */
186 /* Points into DriverListHead list. The pointer is NULL if no driver is
187 * currently chosen. */
188 struct DriverInfoElement *SelectedDriver;
189
190 LIST_ENTRY ListHead; /* List of struct DeviceInfoElement */
191 };
192
193 /***********************************************************************
194 * SetupDiBuildClassInfoList (SETUPAPI.@)
195 */
196 BOOL WINAPI SetupDiBuildClassInfoList(
197 DWORD Flags,
198 LPGUID ClassGuidList,
199 DWORD ClassGuidListSize,
200 PDWORD RequiredSize)
201 {
202 TRACE("\n");
203 return SetupDiBuildClassInfoListExW(Flags, ClassGuidList,
204 ClassGuidListSize, RequiredSize,
205 NULL, NULL);
206 }
207
208 /***********************************************************************
209 * SetupDiBuildClassInfoListExA (SETUPAPI.@)
210 */
211 BOOL WINAPI SetupDiBuildClassInfoListExA(
212 DWORD Flags,
213 LPGUID ClassGuidList,
214 DWORD ClassGuidListSize,
215 PDWORD RequiredSize,
216 LPCSTR MachineName,
217 PVOID Reserved)
218 {
219 LPWSTR MachineNameW = NULL;
220 BOOL bResult;
221
222 TRACE("\n");
223
224 if (MachineName)
225 {
226 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
227 if (MachineNameW == NULL) return FALSE;
228 }
229
230 bResult = SetupDiBuildClassInfoListExW(Flags, ClassGuidList,
231 ClassGuidListSize, RequiredSize,
232 MachineNameW, Reserved);
233
234 if (MachineNameW)
235 MyFree(MachineNameW);
236
237 return bResult;
238 }
239
240 /***********************************************************************
241 * SetupDiBuildClassInfoListExW (SETUPAPI.@)
242 */
243 BOOL WINAPI SetupDiBuildClassInfoListExW(
244 DWORD Flags,
245 LPGUID ClassGuidList,
246 DWORD ClassGuidListSize,
247 PDWORD RequiredSize,
248 LPCWSTR MachineName,
249 PVOID Reserved)
250 {
251 WCHAR szKeyName[MAX_GUID_STRING_LEN + 1];
252 HKEY hClassesKey;
253 HKEY hClassKey;
254 DWORD dwLength;
255 DWORD dwIndex;
256 LONG lError;
257 DWORD dwGuidListIndex = 0;
258
259 TRACE("\n");
260
261 if (RequiredSize != NULL)
262 *RequiredSize = 0;
263
264 hClassesKey = SetupDiOpenClassRegKeyExW(NULL,
265 KEY_ALL_ACCESS,
266 DIOCR_INSTALLER,
267 MachineName,
268 Reserved);
269 if (hClassesKey == INVALID_HANDLE_VALUE)
270 {
271 return FALSE;
272 }
273
274 for (dwIndex = 0; ; dwIndex++)
275 {
276 dwLength = MAX_GUID_STRING_LEN + 1;
277 lError = RegEnumKeyExW(hClassesKey,
278 dwIndex,
279 szKeyName,
280 &dwLength,
281 NULL,
282 NULL,
283 NULL,
284 NULL);
285 TRACE("RegEnumKeyExW() returns %ld\n", lError);
286 if (lError == ERROR_SUCCESS || lError == ERROR_MORE_DATA)
287 {
288 TRACE("Key name: %p\n", szKeyName);
289
290 if (RegOpenKeyExW(hClassesKey,
291 szKeyName,
292 0,
293 KEY_ALL_ACCESS,
294 &hClassKey))
295 {
296 RegCloseKey(hClassesKey);
297 return FALSE;
298 }
299
300 if (!RegQueryValueExW(hClassKey,
301 NoUseClass,
302 NULL,
303 NULL,
304 NULL,
305 NULL))
306 {
307 TRACE("'NoUseClass' value found!\n");
308 RegCloseKey(hClassKey);
309 continue;
310 }
311
312 if ((Flags & DIBCI_NOINSTALLCLASS) &&
313 (!RegQueryValueExW(hClassKey,
314 NoInstallClass,
315 NULL,
316 NULL,
317 NULL,
318 NULL)))
319 {
320 TRACE("'NoInstallClass' value found!\n");
321 RegCloseKey(hClassKey);
322 continue;
323 }
324
325 if ((Flags & DIBCI_NODISPLAYCLASS) &&
326 (!RegQueryValueExW(hClassKey,
327 NoDisplayClass,
328 NULL,
329 NULL,
330 NULL,
331 NULL)))
332 {
333 TRACE("'NoDisplayClass' value found!\n");
334 RegCloseKey(hClassKey);
335 continue;
336 }
337
338 RegCloseKey(hClassKey);
339
340 TRACE("Guid: %p\n", szKeyName);
341 if (dwGuidListIndex < ClassGuidListSize)
342 {
343 if (szKeyName[0] == L'{' && szKeyName[37] == L'}')
344 {
345 szKeyName[37] = 0;
346 }
347 TRACE("Guid: %p\n", &szKeyName[1]);
348
349 UuidFromStringW(&szKeyName[1],
350 &ClassGuidList[dwGuidListIndex]);
351 }
352
353 dwGuidListIndex++;
354 }
355
356 if (lError != ERROR_SUCCESS)
357 break;
358 }
359
360 RegCloseKey(hClassesKey);
361
362 if (RequiredSize != NULL)
363 *RequiredSize = dwGuidListIndex;
364
365 if (ClassGuidListSize < dwGuidListIndex)
366 {
367 SetLastError(ERROR_INSUFFICIENT_BUFFER);
368 return FALSE;
369 }
370
371 return TRUE;
372 }
373
374 /***********************************************************************
375 * SetupDiClassGuidsFromNameA (SETUPAPI.@)
376 */
377 BOOL WINAPI SetupDiClassGuidsFromNameA(
378 LPCSTR ClassName,
379 LPGUID ClassGuidList,
380 DWORD ClassGuidListSize,
381 PDWORD RequiredSize)
382 {
383 return SetupDiClassGuidsFromNameExA(ClassName, ClassGuidList,
384 ClassGuidListSize, RequiredSize,
385 NULL, NULL);
386 }
387
388 /***********************************************************************
389 * SetupDiClassGuidsFromNameW (SETUPAPI.@)
390 */
391 BOOL WINAPI SetupDiClassGuidsFromNameW(
392 LPCWSTR ClassName,
393 LPGUID ClassGuidList,
394 DWORD ClassGuidListSize,
395 PDWORD RequiredSize)
396 {
397 return SetupDiClassGuidsFromNameExW(ClassName, ClassGuidList,
398 ClassGuidListSize, RequiredSize,
399 NULL, NULL);
400 }
401
402 /***********************************************************************
403 * SetupDiClassGuidsFromNameExA (SETUPAPI.@)
404 */
405 BOOL WINAPI SetupDiClassGuidsFromNameExA(
406 LPCSTR ClassName,
407 LPGUID ClassGuidList,
408 DWORD ClassGuidListSize,
409 PDWORD RequiredSize,
410 LPCSTR MachineName,
411 PVOID Reserved)
412 {
413 LPWSTR ClassNameW = NULL;
414 LPWSTR MachineNameW = NULL;
415 BOOL bResult;
416
417 TRACE("\n");
418
419 ClassNameW = MultiByteToUnicode(ClassName, CP_ACP);
420 if (ClassNameW == NULL)
421 return FALSE;
422
423 if (MachineNameW)
424 {
425 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
426 if (MachineNameW == NULL)
427 {
428 MyFree(ClassNameW);
429 return FALSE;
430 }
431 }
432
433 bResult = SetupDiClassGuidsFromNameExW(ClassNameW, ClassGuidList,
434 ClassGuidListSize, RequiredSize,
435 MachineNameW, Reserved);
436
437 if (MachineNameW)
438 MyFree(MachineNameW);
439
440 MyFree(ClassNameW);
441
442 return bResult;
443 }
444
445 /***********************************************************************
446 * SetupDiClassGuidsFromNameExW (SETUPAPI.@)
447 */
448 BOOL WINAPI SetupDiClassGuidsFromNameExW(
449 LPCWSTR ClassName,
450 LPGUID ClassGuidList,
451 DWORD ClassGuidListSize,
452 PDWORD RequiredSize,
453 LPCWSTR MachineName,
454 PVOID Reserved)
455 {
456 WCHAR szKeyName[MAX_GUID_STRING_LEN + 1];
457 WCHAR szClassName[256];
458 HKEY hClassesKey;
459 HKEY hClassKey;
460 DWORD dwLength;
461 DWORD dwIndex;
462 LONG lError;
463 DWORD dwGuidListIndex = 0;
464
465 if (RequiredSize != NULL)
466 *RequiredSize = 0;
467
468 hClassesKey = SetupDiOpenClassRegKeyExW(NULL,
469 KEY_ENUMERATE_SUB_KEYS,
470 DIOCR_INSTALLER,
471 MachineName,
472 Reserved);
473 if (hClassesKey == INVALID_HANDLE_VALUE)
474 {
475 return FALSE;
476 }
477
478 for (dwIndex = 0; ; dwIndex++)
479 {
480 dwLength = MAX_GUID_STRING_LEN + 1;
481 lError = RegEnumKeyExW(hClassesKey,
482 dwIndex,
483 szKeyName,
484 &dwLength,
485 NULL,
486 NULL,
487 NULL,
488 NULL);
489 TRACE("RegEnumKeyExW() returns %ld\n", lError);
490 if (lError == ERROR_SUCCESS || lError == ERROR_MORE_DATA)
491 {
492 TRACE("Key name: %p\n", szKeyName);
493
494 if (RegOpenKeyExW(hClassesKey,
495 szKeyName,
496 0,
497 KEY_QUERY_VALUE,
498 &hClassKey))
499 {
500 RegCloseKey(hClassesKey);
501 return FALSE;
502 }
503
504 dwLength = 256 * sizeof(WCHAR);
505 if (!RegQueryValueExW(hClassKey,
506 Class,
507 NULL,
508 NULL,
509 (LPBYTE)szClassName,
510 &dwLength))
511 {
512 TRACE("Class name: %p\n", szClassName);
513
514 if (strcmpiW(szClassName, ClassName) == 0)
515 {
516 TRACE("Found matching class name\n");
517
518 TRACE("Guid: %p\n", szKeyName);
519 if (dwGuidListIndex < ClassGuidListSize)
520 {
521 if (szKeyName[0] == L'{' && szKeyName[37] == L'}')
522 {
523 szKeyName[37] = 0;
524 }
525 TRACE("Guid: %p\n", &szKeyName[1]);
526
527 UuidFromStringW(&szKeyName[1],
528 &ClassGuidList[dwGuidListIndex]);
529 }
530
531 dwGuidListIndex++;
532 }
533 }
534
535 RegCloseKey(hClassKey);
536 }
537
538 if (lError != ERROR_SUCCESS)
539 break;
540 }
541
542 RegCloseKey(hClassesKey);
543
544 if (RequiredSize != NULL)
545 *RequiredSize = dwGuidListIndex;
546
547 if (ClassGuidListSize < dwGuidListIndex)
548 {
549 SetLastError(ERROR_INSUFFICIENT_BUFFER);
550 return FALSE;
551 }
552
553 return TRUE;
554 }
555
556 /***********************************************************************
557 * SetupDiClassNameFromGuidA (SETUPAPI.@)
558 */
559 BOOL WINAPI SetupDiClassNameFromGuidA(
560 const GUID* ClassGuid,
561 PSTR ClassName,
562 DWORD ClassNameSize,
563 PDWORD RequiredSize)
564 {
565 return SetupDiClassNameFromGuidExA(ClassGuid, ClassName,
566 ClassNameSize, RequiredSize,
567 NULL, NULL);
568 }
569
570 /***********************************************************************
571 * SetupDiClassNameFromGuidW (SETUPAPI.@)
572 */
573 BOOL WINAPI SetupDiClassNameFromGuidW(
574 const GUID* ClassGuid,
575 PWSTR ClassName,
576 DWORD ClassNameSize,
577 PDWORD RequiredSize)
578 {
579 return SetupDiClassNameFromGuidExW(ClassGuid, ClassName,
580 ClassNameSize, RequiredSize,
581 NULL, NULL);
582 }
583
584 /***********************************************************************
585 * SetupDiClassNameFromGuidExA (SETUPAPI.@)
586 */
587 BOOL WINAPI SetupDiClassNameFromGuidExA(
588 const GUID* ClassGuid,
589 PSTR ClassName,
590 DWORD ClassNameSize,
591 PDWORD RequiredSize,
592 PCSTR MachineName,
593 PVOID Reserved)
594 {
595 WCHAR ClassNameW[MAX_CLASS_NAME_LEN];
596 LPWSTR MachineNameW = NULL;
597 BOOL ret;
598
599 if (MachineName)
600 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
601 ret = SetupDiClassNameFromGuidExW(ClassGuid, ClassNameW, MAX_CLASS_NAME_LEN,
602 NULL, MachineNameW, Reserved);
603 if (ret)
604 {
605 int len = WideCharToMultiByte(CP_ACP, 0, ClassNameW, -1, ClassName,
606 ClassNameSize, NULL, NULL);
607
608 if (!ClassNameSize && RequiredSize)
609 *RequiredSize = len;
610 }
611 MyFree(MachineNameW);
612 return ret;
613 }
614
615 /***********************************************************************
616 * SetupDiClassNameFromGuidExW (SETUPAPI.@)
617 */
618 BOOL WINAPI SetupDiClassNameFromGuidExW(
619 const GUID* ClassGuid,
620 PWSTR ClassName,
621 DWORD ClassNameSize,
622 PDWORD RequiredSize,
623 PCWSTR MachineName,
624 PVOID Reserved)
625 {
626 HKEY hKey;
627 DWORD dwLength;
628 LONG rc;
629
630 hKey = SetupDiOpenClassRegKeyExW(ClassGuid,
631 KEY_QUERY_VALUE,
632 DIOCR_INSTALLER,
633 MachineName,
634 Reserved);
635 if (hKey == INVALID_HANDLE_VALUE)
636 {
637 return FALSE;
638 }
639
640 if (RequiredSize != NULL)
641 {
642 dwLength = 0;
643 rc = RegQueryValueExW(hKey,
644 Class,
645 NULL,
646 NULL,
647 NULL,
648 &dwLength);
649 if (rc != ERROR_SUCCESS)
650 {
651 SetLastError(rc);
652 RegCloseKey(hKey);
653 return FALSE;
654 }
655
656 *RequiredSize = dwLength / sizeof(WCHAR);
657 }
658
659 dwLength = ClassNameSize * sizeof(WCHAR);
660 rc = RegQueryValueExW(hKey,
661 Class,
662 NULL,
663 NULL,
664 (LPBYTE)ClassName,
665 &dwLength);
666 if (rc != ERROR_SUCCESS)
667 {
668 SetLastError(rc);
669 RegCloseKey(hKey);
670 return FALSE;
671 }
672
673 RegCloseKey(hKey);
674
675 return TRUE;
676 }
677
678 /***********************************************************************
679 * SetupDiCreateDeviceInfoList (SETUPAPI.@)
680 */
681 HDEVINFO WINAPI
682 SetupDiCreateDeviceInfoList(const GUID *ClassGuid,
683 HWND hwndParent)
684 {
685 return SetupDiCreateDeviceInfoListExW(ClassGuid, hwndParent, NULL, NULL);
686 }
687
688 /***********************************************************************
689 * SetupDiCreateDeviceInfoListExA (SETUPAPI.@)
690 */
691 HDEVINFO WINAPI
692 SetupDiCreateDeviceInfoListExA(const GUID *ClassGuid,
693 HWND hwndParent,
694 PCSTR MachineName,
695 PVOID Reserved)
696 {
697 LPWSTR MachineNameW = NULL;
698 HDEVINFO hDevInfo;
699
700 TRACE("%p %p %s %p\n", ClassGuid, hwndParent, MachineName, Reserved);
701
702 if (MachineName)
703 {
704 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
705 if (MachineNameW == NULL)
706 return (HDEVINFO)INVALID_HANDLE_VALUE;
707 }
708
709 hDevInfo = SetupDiCreateDeviceInfoListExW(ClassGuid, hwndParent,
710 MachineNameW, Reserved);
711
712 if (MachineNameW)
713 MyFree(MachineNameW);
714
715 return hDevInfo;
716 }
717
718 /***********************************************************************
719 * SetupDiCreateDeviceInfoListExW (SETUPAPI.@)
720 */
721 HDEVINFO WINAPI
722 SetupDiCreateDeviceInfoListExW(const GUID *ClassGuid,
723 HWND hwndParent,
724 PCWSTR MachineName,
725 PVOID Reserved)
726 {
727 struct DeviceInfoSet *list;
728 DWORD rc;
729
730 TRACE("%p %p %S %p\n", ClassGuid, hwndParent, MachineName, Reserved);
731
732 list = HeapAlloc(GetProcessHeap(), 0, sizeof(struct DeviceInfoSet));
733 if (!list)
734 {
735 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
736 return (HDEVINFO)INVALID_HANDLE_VALUE;
737 }
738
739 list->magic = SETUP_DEV_INFO_SET_MAGIC;
740 memcpy(
741 &list->ClassGuid,
742 ClassGuid ? ClassGuid : &GUID_NULL,
743 sizeof(list->ClassGuid));
744 list->hwndParent = hwndParent;
745 if (MachineName)
746 {
747 rc = RegConnectRegistryW(MachineName, HKEY_LOCAL_MACHINE, &list->HKLM);
748 if (rc != ERROR_SUCCESS)
749 {
750 SetLastError(rc);
751 HeapFree(GetProcessHeap(), 0, list);
752 return (HDEVINFO)INVALID_HANDLE_VALUE;
753 }
754 }
755 else
756 {
757 list->HKLM = HKEY_LOCAL_MACHINE;
758 }
759 list->Flags = 0; /* FIXME */
760 list->FlagsEx = 0; /* FIXME */
761 InitializeListHead(&list->DriverListHead);
762 InitializeListHead(&list->ListHead);
763 return (HDEVINFO)list;
764 }
765
766 /***********************************************************************
767 * SetupDiEnumDeviceInfo (SETUPAPI.@)
768 */
769 BOOL WINAPI SetupDiEnumDeviceInfo(
770 HDEVINFO DeviceInfoSet,
771 DWORD MemberIndex,
772 PSP_DEVINFO_DATA DeviceInfoData)
773 {
774 BOOL ret = FALSE;
775
776 TRACE("%p, 0x%08lx, %p\n", DeviceInfoSet, MemberIndex, DeviceInfoData);
777 if (!DeviceInfoData)
778 SetLastError(ERROR_INVALID_PARAMETER);
779 else if (DeviceInfoSet && DeviceInfoSet != (HDEVINFO)INVALID_HANDLE_VALUE)
780 {
781 struct DeviceInfoSet *list = (struct DeviceInfoSet *)DeviceInfoSet;
782
783 if (list->magic != SETUP_DEV_INFO_SET_MAGIC)
784 SetLastError(ERROR_INVALID_HANDLE);
785 else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
786 SetLastError(ERROR_INVALID_USER_BUFFER);
787 else
788 {
789 PLIST_ENTRY ItemList = list->ListHead.Flink;
790 while (ItemList != &list->ListHead && MemberIndex-- > 0)
791 ItemList = ItemList->Flink;
792 if (ItemList == &list->ListHead)
793 SetLastError(ERROR_NO_MORE_ITEMS);
794 else
795 {
796 struct DeviceInfoElement *DevInfo = (struct DeviceInfoElement *)ItemList;
797 memcpy(&DeviceInfoData->ClassGuid,
798 &DevInfo->ClassGuid,
799 sizeof(GUID));
800 DeviceInfoData->DevInst = 0; /* FIXME */
801 /* Note: this appears to be dangerous, passing a private
802 * pointer a heap-allocated datum to the caller. However, the
803 * expected lifetime of the device data is the same as the
804 * HDEVINFO; once that is closed, the data are no longer valid.
805 */
806 DeviceInfoData->Reserved = (ULONG_PTR)DevInfo;
807 ret = TRUE;
808 }
809 }
810 }
811 else
812 SetLastError(ERROR_INVALID_HANDLE);
813 return ret;
814 }
815
816 /***********************************************************************
817 * SetupDiGetActualSectionToInstallA (SETUPAPI.@)
818 */
819 BOOL WINAPI SetupDiGetActualSectionToInstallA(
820 HINF InfHandle,
821 PCSTR InfSectionName,
822 PSTR InfSectionWithExt,
823 DWORD InfSectionWithExtSize,
824 PDWORD RequiredSize,
825 PSTR *Extension)
826 {
827 LPWSTR InfSectionNameW = NULL;
828 PWSTR InfSectionWithExtW = NULL;
829 PWSTR ExtensionW;
830 BOOL bResult = FALSE;
831
832 TRACE("\n");
833
834 if (InfSectionName)
835 {
836 InfSectionNameW = MultiByteToUnicode(InfSectionName, CP_ACP);
837 if (InfSectionNameW == NULL) goto end;
838 }
839 if (InfSectionWithExt)
840 {
841 InfSectionWithExtW = HeapAlloc(GetProcessHeap(), 0, InfSectionWithExtSize * sizeof(WCHAR));
842 if (InfSectionWithExtW == NULL) goto end;
843 }
844
845 bResult = SetupDiGetActualSectionToInstallW(InfHandle, InfSectionNameW,
846 InfSectionWithExt ? InfSectionNameW : NULL,
847 InfSectionWithExtSize, RequiredSize,
848 Extension ? &ExtensionW : NULL);
849
850 if (bResult && InfSectionWithExt)
851 {
852 bResult = WideCharToMultiByte(CP_ACP, 0, InfSectionWithExtW, -1, InfSectionWithExt,
853 InfSectionWithExtSize, NULL, NULL) != 0;
854 }
855 if (bResult && Extension)
856 {
857 if (ExtensionW == NULL)
858 *Extension = NULL;
859 else
860 *Extension = &InfSectionWithExt[ExtensionW - InfSectionWithExtW];
861 }
862
863 end:
864 if (InfSectionNameW) MyFree(InfSectionNameW);
865 if (InfSectionWithExtW) HeapFree(GetProcessHeap(), 0, InfSectionWithExtW);
866
867 return bResult;
868 }
869
870 /***********************************************************************
871 * SetupDiGetActualSectionToInstallW (SETUPAPI.@)
872 */
873 BOOL WINAPI SetupDiGetActualSectionToInstallW(
874 HINF InfHandle,
875 PCWSTR InfSectionName,
876 PWSTR InfSectionWithExt,
877 DWORD InfSectionWithExtSize,
878 PDWORD RequiredSize,
879 PWSTR *Extension)
880 {
881 WCHAR szBuffer[MAX_PATH];
882 DWORD dwLength;
883 DWORD dwFullLength;
884 LONG lLineCount = -1;
885
886 lstrcpyW(szBuffer, InfSectionName);
887 dwLength = lstrlenW(szBuffer);
888
889 if (OsVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
890 {
891 /* Test section name with '.NTx86' extension */
892 lstrcpyW(&szBuffer[dwLength], NtPlatformExtension);
893 lLineCount = SetupGetLineCountW(InfHandle, szBuffer);
894
895 if (lLineCount == -1)
896 {
897 /* Test section name with '.NT' extension */
898 lstrcpyW(&szBuffer[dwLength], NtExtension);
899 lLineCount = SetupGetLineCountW(InfHandle, szBuffer);
900 }
901 }
902 else
903 {
904 /* Test section name with '.Win' extension */
905 lstrcpyW(&szBuffer[dwLength], WinExtension);
906 lLineCount = SetupGetLineCountW(InfHandle, szBuffer);
907 }
908
909 if (lLineCount == -1)
910 {
911 /* Test section name without extension */
912 szBuffer[dwLength] = 0;
913 lLineCount = SetupGetLineCountW(InfHandle, szBuffer);
914 }
915
916 if (lLineCount == -1)
917 {
918 SetLastError(ERROR_INVALID_PARAMETER);
919 return FALSE;
920 }
921
922 dwFullLength = lstrlenW(szBuffer);
923
924 if (InfSectionWithExt != NULL && InfSectionWithExtSize != 0)
925 {
926 if (InfSectionWithExtSize < (dwFullLength + 1))
927 {
928 SetLastError(ERROR_INSUFFICIENT_BUFFER);
929 return FALSE;
930 }
931
932 lstrcpyW(InfSectionWithExt, szBuffer);
933 if (Extension != NULL)
934 {
935 *Extension = (dwLength == dwFullLength) ? NULL : &InfSectionWithExt[dwLength];
936 }
937 }
938
939 if (RequiredSize != NULL)
940 {
941 *RequiredSize = dwFullLength + 1;
942 }
943
944 return TRUE;
945 }
946
947 /***********************************************************************
948 * SetupDiGetClassDescriptionA (SETUPAPI.@)
949 */
950 BOOL WINAPI SetupDiGetClassDescriptionA(
951 const GUID* ClassGuid,
952 PSTR ClassDescription,
953 DWORD ClassDescriptionSize,
954 PDWORD RequiredSize)
955 {
956 return SetupDiGetClassDescriptionExA(ClassGuid, ClassDescription,
957 ClassDescriptionSize,
958 RequiredSize, NULL, NULL);
959 }
960
961 /***********************************************************************
962 * SetupDiGetClassDescriptionW (SETUPAPI.@)
963 */
964 BOOL WINAPI SetupDiGetClassDescriptionW(
965 const GUID* ClassGuid,
966 PWSTR ClassDescription,
967 DWORD ClassDescriptionSize,
968 PDWORD RequiredSize)
969 {
970 return SetupDiGetClassDescriptionExW(ClassGuid, ClassDescription,
971 ClassDescriptionSize,
972 RequiredSize, NULL, NULL);
973 }
974
975 /***********************************************************************
976 * SetupDiGetClassDescriptionExA (SETUPAPI.@)
977 */
978 BOOL WINAPI SetupDiGetClassDescriptionExA(
979 const GUID* ClassGuid,
980 PSTR ClassDescription,
981 DWORD ClassDescriptionSize,
982 PDWORD RequiredSize,
983 PCSTR MachineName,
984 PVOID Reserved)
985 {
986 PWCHAR ClassDescriptionW;
987 LPWSTR MachineNameW = NULL;
988 BOOL ret;
989
990 TRACE("\n");
991 if (ClassDescriptionSize > 0)
992 {
993 ClassDescriptionW = HeapAlloc(GetProcessHeap(), 0, ClassDescriptionSize * sizeof(WCHAR));
994 if (!ClassDescriptionW)
995 {
996 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
997 ret = FALSE;
998 goto end;
999 }
1000 }
1001 else
1002 ClassDescriptionW = NULL;
1003
1004 if (MachineName)
1005 {
1006 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
1007 if (!MachineNameW)
1008 {
1009 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1010 ret = FALSE;
1011 goto end;
1012 }
1013 }
1014
1015 ret = SetupDiGetClassDescriptionExW(ClassGuid, ClassDescriptionW, ClassDescriptionSize * sizeof(WCHAR),
1016 NULL, MachineNameW, Reserved);
1017 if (ret)
1018 {
1019 int len = WideCharToMultiByte(CP_ACP, 0, ClassDescriptionW, -1, ClassDescription,
1020 ClassDescriptionSize, NULL, NULL);
1021
1022 if (!ClassDescriptionSize && RequiredSize)
1023 *RequiredSize = len;
1024 }
1025
1026 end:
1027 HeapFree(GetProcessHeap(), 0, ClassDescriptionW);
1028 MyFree(MachineNameW);
1029 return ret;
1030 }
1031
1032 /***********************************************************************
1033 * SetupDiGetClassDescriptionExW (SETUPAPI.@)
1034 */
1035 BOOL WINAPI SetupDiGetClassDescriptionExW(
1036 const GUID* ClassGuid,
1037 PWSTR ClassDescription,
1038 DWORD ClassDescriptionSize,
1039 PDWORD RequiredSize,
1040 PCWSTR MachineName,
1041 PVOID Reserved)
1042 {
1043 HKEY hKey;
1044 DWORD dwLength;
1045
1046 hKey = SetupDiOpenClassRegKeyExW(ClassGuid,
1047 KEY_ALL_ACCESS,
1048 DIOCR_INSTALLER,
1049 MachineName,
1050 Reserved);
1051 if (hKey == INVALID_HANDLE_VALUE)
1052 {
1053 WARN("SetupDiOpenClassRegKeyExW() failed (Error %lu)\n", GetLastError());
1054 return FALSE;
1055 }
1056
1057 if (RequiredSize != NULL)
1058 {
1059 dwLength = 0;
1060 if (RegQueryValueExW(hKey,
1061 NULL,
1062 NULL,
1063 NULL,
1064 NULL,
1065 &dwLength))
1066 {
1067 RegCloseKey(hKey);
1068 return FALSE;
1069 }
1070
1071 *RequiredSize = dwLength / sizeof(WCHAR);
1072 }
1073
1074 dwLength = ClassDescriptionSize * sizeof(WCHAR);
1075 if (RegQueryValueExW(hKey,
1076 NULL,
1077 NULL,
1078 NULL,
1079 (LPBYTE)ClassDescription,
1080 &dwLength))
1081 {
1082 RegCloseKey(hKey);
1083 return FALSE;
1084 }
1085
1086 RegCloseKey(hKey);
1087
1088 return TRUE;
1089 }
1090
1091 /***********************************************************************
1092 * SetupDiGetClassDevsA (SETUPAPI.@)
1093 */
1094 HDEVINFO WINAPI SetupDiGetClassDevsA(
1095 CONST GUID *class,
1096 LPCSTR enumstr,
1097 HWND parent,
1098 DWORD flags)
1099 {
1100 return SetupDiGetClassDevsExA(class, enumstr, parent,
1101 flags, NULL, NULL, NULL);
1102 }
1103
1104 /***********************************************************************
1105 * SetupDiGetClassDevsW (SETUPAPI.@)
1106 */
1107 HDEVINFO WINAPI SetupDiGetClassDevsW(
1108 CONST GUID *class,
1109 LPCWSTR enumstr,
1110 HWND parent,
1111 DWORD flags)
1112 {
1113 return SetupDiGetClassDevsExW(class, enumstr, parent,
1114 flags, NULL, NULL, NULL);
1115 }
1116
1117 /***********************************************************************
1118 * SetupDiGetClassDevsExA (SETUPAPI.@)
1119 */
1120 HDEVINFO WINAPI SetupDiGetClassDevsExA(
1121 CONST GUID *class,
1122 LPCSTR enumstr,
1123 HWND parent,
1124 DWORD flags,
1125 HDEVINFO deviceset,
1126 LPCSTR machine,
1127 PVOID reserved)
1128 {
1129 HDEVINFO ret;
1130 LPWSTR enumstrW = NULL;
1131 LPWSTR machineW = NULL;
1132
1133 if (enumstr)
1134 {
1135 int len = MultiByteToWideChar(CP_ACP, 0, enumstr, -1, NULL, 0);
1136 enumstrW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1137 if (!enumstrW)
1138 {
1139 ret = (HDEVINFO)INVALID_HANDLE_VALUE;
1140 goto end;
1141 }
1142 MultiByteToWideChar(CP_ACP, 0, enumstr, -1, enumstrW, len);
1143 }
1144 if (machine)
1145 {
1146 int len = MultiByteToWideChar(CP_ACP, 0, machine, -1, NULL, 0);
1147 machineW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1148 if (!machineW)
1149 {
1150 ret = (HDEVINFO)INVALID_HANDLE_VALUE;
1151 goto end;
1152 }
1153 MultiByteToWideChar(CP_ACP, 0, machine, -1, machineW, len);
1154 }
1155 ret = SetupDiGetClassDevsExW(class, enumstrW, parent, flags, deviceset, machineW, reserved);
1156
1157 end:
1158 HeapFree(GetProcessHeap(), 0, enumstrW);
1159 HeapFree(GetProcessHeap(), 0, machineW);
1160 return ret;
1161 }
1162
1163 static BOOL
1164 CreateDeviceInfoElement(
1165 IN LPCWSTR InstancePath,
1166 LPCGUID pClassGuid,
1167 OUT struct DeviceInfoElement **pDeviceInfo)
1168 {
1169 struct DeviceInfoElement *deviceInfo;
1170
1171 *pDeviceInfo = NULL;
1172 if (IsEqualIID(&pClassGuid, &GUID_NULL)) { FIXME("Bad argument!!!"); return FALSE; }/* FIXME: remove */
1173
1174 deviceInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(struct DeviceInfoElement) + (wcslen(InstancePath) + 1) * sizeof(WCHAR));
1175 if (!deviceInfo)
1176 {
1177 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1178 return FALSE;
1179 }
1180 wcscpy(deviceInfo->Data, InstancePath);
1181 deviceInfo->DeviceName = deviceInfo->Data;
1182 deviceInfo->UniqueId = wcsrchr(deviceInfo->Data, '\\');
1183 deviceInfo->DeviceDescription = NULL;
1184 memcpy(&deviceInfo->ClassGuid, pClassGuid, sizeof(GUID));
1185 deviceInfo->CreationFlags = 0;
1186 deviceInfo->hwndParent = NULL;
1187 deviceInfo->Flags = 0; /* FIXME */
1188 deviceInfo->FlagsEx = 0; /* FIXME */
1189 deviceInfo->SelectedDriver = NULL;
1190 InitializeListHead(&deviceInfo->DriverListHead);
1191 InitializeListHead(&deviceInfo->InterfaceListHead);
1192
1193 *pDeviceInfo = deviceInfo;
1194 return TRUE;
1195 }
1196
1197 static BOOL
1198 CreateDeviceInterface(
1199 IN struct DeviceInfoElement* deviceInfo,
1200 IN LPCWSTR SymbolicLink,
1201 IN LPCGUID pInterfaceGuid,
1202 OUT struct DeviceInterface **pDeviceInterface)
1203 {
1204 struct DeviceInterface *deviceInterface;
1205
1206 *pDeviceInterface = NULL;
1207 if (IsEqualIID(&pInterfaceGuid, &GUID_NULL)) { FIXME("Bad argument!!!"); return FALSE; }/* FIXME: remove */
1208
1209 deviceInterface = HeapAlloc(GetProcessHeap(), 0, sizeof(struct DeviceInterface) + (wcslen(SymbolicLink) + 1) * sizeof(WCHAR));
1210 if (!deviceInterface)
1211 {
1212 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1213 return FALSE;
1214 }
1215 deviceInterface->DeviceInfo = deviceInfo;
1216 wcscpy(deviceInterface->SymbolicLink, SymbolicLink);
1217 deviceInterface->Flags = 0; /* FIXME */
1218 memcpy(&deviceInterface->InterfaceClassGuid, pInterfaceGuid, sizeof(GUID));
1219
1220 *pDeviceInterface = deviceInterface;
1221 return TRUE;
1222 }
1223
1224 static LONG SETUP_CreateDevListFromEnumerator(
1225 struct DeviceInfoSet *list,
1226 LPCGUID pClassGuid OPTIONAL,
1227 LPCWSTR Enumerator,
1228 HKEY hEnumeratorKey) /* handle to Enumerator registry key */
1229 {
1230 HKEY hDeviceIdKey, hInstanceIdKey;
1231 WCHAR KeyBuffer[MAX_PATH];
1232 WCHAR InstancePath[MAX_PATH];
1233 LPWSTR pEndOfInstancePath; /* Pointer into InstancePath buffer */
1234 struct DeviceInfoElement *deviceInfo;
1235 DWORD i = 0, j;
1236 DWORD dwLength, dwRegType;
1237 DWORD rc;
1238
1239 /* Enumerate device IDs (subkeys of hEnumeratorKey) */
1240 while (TRUE)
1241 {
1242 dwLength = sizeof(KeyBuffer) / sizeof(KeyBuffer[0]);
1243 rc = RegEnumKeyExW(hEnumeratorKey, i, KeyBuffer, &dwLength, NULL, NULL, NULL, NULL);
1244 if (rc == ERROR_NO_MORE_ITEMS)
1245 break;
1246 if (rc != ERROR_SUCCESS)
1247 return rc;
1248 i++;
1249
1250 /* Open device id sub key */
1251 rc = RegOpenKeyExW(hEnumeratorKey, KeyBuffer, 0, KEY_ENUMERATE_SUB_KEYS, &hDeviceIdKey);
1252 if (rc != ERROR_SUCCESS)
1253 return rc;
1254 wcscpy(InstancePath, Enumerator);
1255 wcscat(InstancePath, L"\\");
1256 wcscat(InstancePath, KeyBuffer);
1257 wcscat(InstancePath, L"\\");
1258 pEndOfInstancePath = &InstancePath[wcslen(InstancePath)];
1259
1260 /* Enumerate instance IDs (subkeys of hDeviceIdKey) */
1261 j = 0;
1262 while (TRUE)
1263 {
1264 dwLength = sizeof(KeyBuffer) / sizeof(KeyBuffer[0]);
1265 rc = RegEnumKeyExW(hDeviceIdKey, j, KeyBuffer, &dwLength, NULL, NULL, NULL, NULL);
1266 if (rc == ERROR_NO_MORE_ITEMS)
1267 break;
1268 if (rc != ERROR_SUCCESS)
1269 {
1270 RegCloseKey(hDeviceIdKey);
1271 return rc;
1272 }
1273 j++;
1274
1275 /* Open instance id sub key */
1276 rc = RegOpenKeyExW(hDeviceIdKey, KeyBuffer, 0, KEY_QUERY_VALUE, &hInstanceIdKey);
1277 if (rc != ERROR_SUCCESS)
1278 {
1279 RegCloseKey(hDeviceIdKey);
1280 return rc;
1281 }
1282 *pEndOfInstancePath = '\0';
1283 wcscat(InstancePath, KeyBuffer);
1284
1285 /* Read ClassGUID value */
1286 dwLength = sizeof(KeyBuffer) - sizeof(WCHAR);
1287 rc = RegQueryValueExW(hInstanceIdKey, ClassGUID, NULL, &dwRegType, (LPBYTE)KeyBuffer, &dwLength);
1288 RegCloseKey(hInstanceIdKey);
1289 if (rc == ERROR_FILE_NOT_FOUND)
1290 {
1291 if (pClassGuid)
1292 /* Skip this bad entry as we can't verify it */
1293 continue;
1294 }
1295 else if (rc != ERROR_SUCCESS)
1296 {
1297 RegCloseKey(hDeviceIdKey);
1298 return rc;
1299 }
1300 else if (dwRegType != REG_SZ)
1301 {
1302 RegCloseKey(hDeviceIdKey);
1303 return ERROR_GEN_FAILURE;
1304 }
1305 else if (pClassGuid)
1306 {
1307 GUID KeyGuid;
1308 KeyBuffer[37] = '\0'; /* Replace the } by a NULL character */
1309 if (UuidFromStringW(&KeyBuffer[1], &KeyGuid) != RPC_S_OK)
1310 {
1311 RegCloseKey(hDeviceIdKey);
1312 return GetLastError();
1313 }
1314 if (!IsEqualIID(&KeyGuid, pClassGuid))
1315 /* Skip this entry as it is not the right device class */
1316 continue;
1317 }
1318
1319 /* Add the entry to the list */
1320 if (!CreateDeviceInfoElement(InstancePath, pClassGuid, &deviceInfo))
1321 {
1322 RegCloseKey(hDeviceIdKey);
1323 return GetLastError();
1324 }
1325 TRACE("Adding '%S' to device info set %p\n", InstancePath, list);
1326 InsertTailList(&list->ListHead, &deviceInfo->ListEntry);
1327 }
1328 RegCloseKey(hDeviceIdKey);
1329 }
1330
1331 return ERROR_SUCCESS;
1332 }
1333
1334 static LONG SETUP_CreateDevList(
1335 struct DeviceInfoSet *list,
1336 PCWSTR MachineName OPTIONAL,
1337 LPGUID class OPTIONAL,
1338 PCWSTR Enumerator OPTIONAL)
1339 {
1340 HKEY HKLM, hEnumKey, hEnumeratorKey;
1341 WCHAR KeyBuffer[MAX_PATH];
1342 DWORD i;
1343 DWORD dwLength;
1344 DWORD rc;
1345
1346 if (IsEqualIID(class, &GUID_NULL))
1347 class = NULL;
1348
1349 /* Open Enum key */
1350 if (MachineName != NULL)
1351 {
1352 rc = RegConnectRegistryW(MachineName, HKEY_LOCAL_MACHINE, &HKLM);
1353 if (rc != ERROR_SUCCESS)
1354 return rc;
1355 }
1356 else
1357 HKLM = HKEY_LOCAL_MACHINE;
1358
1359 rc = RegOpenKeyExW(HKLM,
1360 EnumKeyName,
1361 0,
1362 KEY_ENUMERATE_SUB_KEYS,
1363 &hEnumKey);
1364 if (MachineName != NULL) RegCloseKey(HKLM);
1365 if (rc != ERROR_SUCCESS)
1366 return rc;
1367
1368 /* If enumerator is provided, call directly SETUP_CreateDevListFromEnumerator.
1369 * Else, enumerate all enumerators all call SETUP_CreateDevListFromEnumerator
1370 * for each one.
1371 */
1372 if (Enumerator)
1373 {
1374 rc = RegOpenKeyExW(
1375 hEnumKey,
1376 Enumerator,
1377 0,
1378 KEY_ENUMERATE_SUB_KEYS,
1379 &hEnumeratorKey);
1380 RegCloseKey(hEnumKey);
1381 if (rc != ERROR_SUCCESS)
1382 return rc;
1383 rc = SETUP_CreateDevListFromEnumerator(list, class, Enumerator, hEnumeratorKey);
1384 RegCloseKey(hEnumeratorKey);
1385 return rc;
1386 }
1387 else
1388 {
1389 /* Enumerate enumerators */
1390 i = 0;
1391 while (TRUE)
1392 {
1393 dwLength = sizeof(KeyBuffer) / sizeof(KeyBuffer[0]);
1394 rc = RegEnumKeyExW(hEnumKey, i, KeyBuffer, &dwLength, NULL, NULL, NULL, NULL);
1395 if (rc == ERROR_NO_MORE_ITEMS)
1396 break;
1397 if (rc != ERROR_SUCCESS)
1398 {
1399 RegCloseKey(hEnumKey);
1400 return rc;
1401 }
1402 i++;
1403
1404 /* Open sub key */
1405 rc = RegOpenKeyExW(hEnumKey, KeyBuffer, 0, KEY_ENUMERATE_SUB_KEYS, &hEnumeratorKey);
1406 if (rc != ERROR_SUCCESS)
1407 {
1408 RegCloseKey(hEnumKey);
1409 return rc;
1410 }
1411
1412 /* Call SETUP_CreateDevListFromEnumerator */
1413 rc = SETUP_CreateDevListFromEnumerator(list, class, KeyBuffer, hEnumeratorKey);
1414 RegCloseKey(hEnumeratorKey);
1415 if (rc != ERROR_SUCCESS)
1416 {
1417 RegCloseKey(hEnumKey);
1418 return rc;
1419 }
1420 }
1421 RegCloseKey(hEnumKey);
1422 return ERROR_SUCCESS;
1423 }
1424 }
1425
1426 #ifndef __REACTOS__
1427 static LONG SETUP_CreateSerialDeviceList(
1428 struct DeviceInfoSet *list,
1429 PCWSTR MachineName,
1430 LPGUID InterfaceGuid,
1431 PCWSTR DeviceInstanceW)
1432 {
1433 static const size_t initialSize = 100;
1434 size_t size;
1435 WCHAR buf[initialSize];
1436 LPWSTR devices;
1437 static const WCHAR devicePrefixW[] = { 'C','O','M',0 };
1438 LPWSTR ptr;
1439 struct DeviceInfoElement *deviceInfo;
1440
1441 if (MachineName)
1442 WARN("'MachineName' is ignored on Wine!\n");
1443 if (DeviceInstanceW)
1444 WARN("'DeviceInstanceW' can't be set on Wine!\n");
1445
1446 devices = buf;
1447 size = initialSize;
1448 while (TRUE)
1449 {
1450 if (QueryDosDeviceW(NULL, devices, size) != 0)
1451 break;
1452 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
1453 {
1454 size *= 2;
1455 if (devices != buf)
1456 HeapFree(GetProcessHeap(), 0, devices);
1457 devices = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
1458 if (!devices)
1459 return ERROR_NOT_ENOUGH_MEMORY;
1460 *devices = '\0';
1461 }
1462 else
1463 {
1464 if (devices != buf)
1465 HeapFree(GetProcessHeap(), 0, devices);
1466 return GetLastError();
1467 }
1468 }
1469
1470 /* 'devices' is a MULTI_SZ string */
1471 for (ptr = devices; *ptr; ptr += strlenW(ptr) + 1)
1472 {
1473 if (strncmpW(devicePrefixW, ptr, sizeof(devicePrefixW) / sizeof(devicePrefixW[0]) - 1) == 0)
1474 {
1475 /* We have found a device */
1476 struct DeviceInterface *interfaceInfo;
1477 TRACE("Adding %s to list\n", debugstr_w(ptr));
1478 /* Step 1. Create a device info element */
1479 if (!CreateDeviceInfoElement(ptr, &GUID_SERENUM_BUS_ENUMERATOR, &deviceInfo))
1480 {
1481 if (devices != buf)
1482 HeapFree(GetProcessHeap(), 0, devices);
1483 return GetLastError();
1484 }
1485 InsertTailList(&list->ListHead, &deviceInfo->ListEntry);
1486
1487 /* Step 2. Create an interface list for this element */
1488 if (!CreateDeviceInterface(deviceInfo, ptr, InterfaceGuid, &interfaceInfo))
1489 {
1490 if (devices != buf)
1491 HeapFree(GetProcessHeap(), 0, devices);
1492 return GetLastError();
1493 }
1494 InsertTailList(&deviceInfo->InterfaceListHead, &interfaceInfo->ListEntry);
1495 }
1496 }
1497 if (devices != buf)
1498 HeapFree(GetProcessHeap(), 0, devices);
1499 return ERROR_SUCCESS;
1500 }
1501
1502 #else /* __REACTOS__ */
1503
1504 static LONG SETUP_CreateInterfaceList(
1505 struct DeviceInfoSet *list,
1506 PCWSTR MachineName,
1507 LPGUID InterfaceGuid,
1508 PCWSTR DeviceInstanceW /* OPTIONAL */)
1509 {
1510 HKEY hInterfaceKey; /* HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{GUID} */
1511 HKEY hDeviceInstanceKey; /* HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{GUID}\##?#{InstancePath} */
1512 HKEY hReferenceKey; /* HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{GUID}\##?#{InstancePath}\#{ReferenceString} */
1513 HKEY hEnumKey; /* HKLM\SYSTEM\CurrentControlSet\Enum */
1514 HKEY hKey; /* HKLM\SYSTEM\CurrentControlSet\Enum\{Instance\Path} */
1515 LONG rc;
1516 WCHAR KeyBuffer[max(MAX_PATH, MAX_GUID_STRING_LEN) + 1];
1517 PWSTR InstancePath;
1518 DWORD i, j;
1519 DWORD dwLength, dwInstancePathLength;
1520 DWORD dwRegType;
1521 GUID ClassGuid;
1522 struct DeviceInfoElement *deviceInfo;
1523
1524 /* Open registry key related to this interface */
1525 hInterfaceKey = SetupDiOpenClassRegKeyExW(InterfaceGuid, KEY_ENUMERATE_SUB_KEYS, DIOCR_INTERFACE, MachineName, NULL);
1526 if (hInterfaceKey == INVALID_HANDLE_VALUE)
1527 return GetLastError();
1528
1529 /* Enumerate sub keys of hInterfaceKey */
1530 i = 0;
1531 while (TRUE)
1532 {
1533 dwLength = sizeof(KeyBuffer) / sizeof(KeyBuffer[0]);
1534 rc = RegEnumKeyExW(hInterfaceKey, i, KeyBuffer, &dwLength, NULL, NULL, NULL, NULL);
1535 if (rc == ERROR_NO_MORE_ITEMS)
1536 break;
1537 if (rc != ERROR_SUCCESS)
1538 {
1539 RegCloseKey(hInterfaceKey);
1540 return rc;
1541 }
1542 i++;
1543
1544 /* Open sub key */
1545 rc = RegOpenKeyExW(hInterfaceKey, KeyBuffer, 0, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, &hDeviceInstanceKey);
1546 if (rc != ERROR_SUCCESS)
1547 {
1548 RegCloseKey(hInterfaceKey);
1549 return rc;
1550 }
1551
1552 /* Read DeviceInstance */
1553 rc = RegQueryValueExW(hDeviceInstanceKey, DeviceInstance, NULL, &dwRegType, NULL, &dwInstancePathLength);
1554 if (rc != ERROR_SUCCESS )
1555 {
1556 RegCloseKey(hDeviceInstanceKey);
1557 RegCloseKey(hInterfaceKey);
1558 return rc;
1559 }
1560 if (dwRegType != REG_SZ)
1561 {
1562 RegCloseKey(hDeviceInstanceKey);
1563 RegCloseKey(hInterfaceKey);
1564 return ERROR_GEN_FAILURE;
1565 }
1566 InstancePath = HeapAlloc(GetProcessHeap(), 0, dwInstancePathLength + sizeof(WCHAR));
1567 if (!InstancePath)
1568 {
1569 RegCloseKey(hDeviceInstanceKey);
1570 RegCloseKey(hInterfaceKey);
1571 return ERROR_NOT_ENOUGH_MEMORY;
1572 }
1573 rc = RegQueryValueExW(hDeviceInstanceKey, DeviceInstance, NULL, NULL, (LPBYTE)InstancePath, &dwInstancePathLength);
1574 if (rc != ERROR_SUCCESS)
1575 {
1576 HeapFree(GetProcessHeap(), 0, InstancePath);
1577 RegCloseKey(hDeviceInstanceKey);
1578 RegCloseKey(hInterfaceKey);
1579 return rc;
1580 }
1581 InstancePath[dwInstancePathLength / sizeof(WCHAR)] = '\0';
1582 TRACE("DeviceInstance %s\n", debugstr_w(InstancePath));
1583
1584 if (DeviceInstanceW)
1585 {
1586 /* Check if device enumerator is not the right one */
1587 if (wcscmp(DeviceInstanceW, InstancePath) != 0)
1588 {
1589 HeapFree(GetProcessHeap(), 0, InstancePath);
1590 RegCloseKey(hDeviceInstanceKey);
1591 continue;
1592 }
1593 }
1594
1595 /* Find class GUID associated to the device instance */
1596 rc = RegOpenKeyExW(
1597 HKEY_LOCAL_MACHINE,
1598 EnumKeyName,
1599 0, /* Options */
1600 KEY_ENUMERATE_SUB_KEYS,
1601 &hEnumKey);
1602 if (rc != ERROR_SUCCESS)
1603 {
1604 HeapFree(GetProcessHeap(), 0, InstancePath);
1605 RegCloseKey(hDeviceInstanceKey);
1606 RegCloseKey(hInterfaceKey);
1607 return rc;
1608 }
1609 rc = RegOpenKeyExW(
1610 hEnumKey,
1611 InstancePath,
1612 0, /* Options */
1613 KEY_QUERY_VALUE,
1614 &hKey);
1615 RegCloseKey(hEnumKey);
1616 if (rc != ERROR_SUCCESS)
1617 {
1618 HeapFree(GetProcessHeap(), 0, InstancePath);
1619 RegCloseKey(hDeviceInstanceKey);
1620 RegCloseKey(hInterfaceKey);
1621 return rc;
1622 }
1623 dwLength = sizeof(KeyBuffer) - sizeof(WCHAR);
1624 rc = RegQueryValueExW(hKey, ClassGUID, NULL, NULL, (LPBYTE)KeyBuffer, &dwLength);
1625 RegCloseKey(hKey);
1626 if (rc != ERROR_SUCCESS)
1627 {
1628 HeapFree(GetProcessHeap(), 0, InstancePath);
1629 RegCloseKey(hDeviceInstanceKey);
1630 RegCloseKey(hInterfaceKey);
1631 return rc;
1632 }
1633 KeyBuffer[dwLength / sizeof(WCHAR)] = '\0';
1634 KeyBuffer[37] = '\0'; /* Replace the } by a NULL character */
1635 if (UuidFromStringW(&KeyBuffer[1], &ClassGuid) != RPC_S_OK)
1636 {
1637 HeapFree(GetProcessHeap(), 0, InstancePath);
1638 RegCloseKey(hDeviceInstanceKey);
1639 RegCloseKey(hInterfaceKey);
1640 return ERROR_GEN_FAILURE;
1641 }
1642 TRACE("ClassGUID %s\n", debugstr_guid(&ClassGuid));
1643
1644 /* If current device doesn't match the list GUID (if any), skip this entry */
1645 if (!IsEqualIID(&list->ClassGuid, &GUID_NULL) && !IsEqualIID(&list->ClassGuid, &ClassGuid))
1646 {
1647 HeapFree(GetProcessHeap(), 0, InstancePath);
1648 RegCloseKey(hDeviceInstanceKey);
1649 continue;
1650 }
1651
1652 /* Enumerate subkeys of hDeviceInstanceKey (ie "#ReferenceString" in IoRegisterDeviceInterface). Skip entries that don't start with '#' */
1653 j = 0;
1654 while (TRUE)
1655 {
1656 LPWSTR pSymbolicLink;
1657 struct DeviceInterface *interfaceInfo;
1658
1659 dwLength = sizeof(KeyBuffer) / sizeof(KeyBuffer[0]);
1660 rc = RegEnumKeyExW(hDeviceInstanceKey, j, KeyBuffer, &dwLength, NULL, NULL, NULL, NULL);
1661 if (rc == ERROR_NO_MORE_ITEMS)
1662 break;
1663 if (rc != ERROR_SUCCESS)
1664 {
1665 HeapFree(GetProcessHeap(), 0, InstancePath);
1666 RegCloseKey(hDeviceInstanceKey);
1667 RegCloseKey(hInterfaceKey);
1668 return rc;
1669 }
1670 j++;
1671 if (KeyBuffer[0] != '#')
1672 /* This entry doesn't represent an interesting entry */
1673 continue;
1674
1675 /* Open sub key */
1676 rc = RegOpenKeyExW(hDeviceInstanceKey, KeyBuffer, 0, KEY_QUERY_VALUE, &hReferenceKey);
1677 if (rc != ERROR_SUCCESS)
1678 {
1679 RegCloseKey(hDeviceInstanceKey);
1680 RegCloseKey(hInterfaceKey);
1681 return rc;
1682 }
1683
1684 /* Read SymbolicLink value */
1685 rc = RegQueryValueExW(hReferenceKey, SymbolicLink, NULL, &dwRegType, NULL, &dwLength);
1686 if (rc != ERROR_SUCCESS )
1687 {
1688 RegCloseKey(hReferenceKey);
1689 RegCloseKey(hDeviceInstanceKey);
1690 RegCloseKey(hInterfaceKey);
1691 return rc;
1692 }
1693 if (dwRegType != REG_SZ)
1694 {
1695 RegCloseKey(hReferenceKey);
1696 RegCloseKey(hDeviceInstanceKey);
1697 RegCloseKey(hInterfaceKey);
1698 return ERROR_GEN_FAILURE;
1699 }
1700
1701 /* We have found a device */
1702 /* Step 1. Create a device info element */
1703 if (!CreateDeviceInfoElement(InstancePath, &ClassGuid, &deviceInfo))
1704 {
1705 RegCloseKey(hReferenceKey);
1706 RegCloseKey(hDeviceInstanceKey);
1707 RegCloseKey(hInterfaceKey);
1708 return GetLastError();
1709 }
1710 TRACE("Adding device %s to list\n", debugstr_w(InstancePath));
1711 InsertTailList(&list->ListHead, &deviceInfo->ListEntry);
1712
1713 /* Step 2. Create an interface list for this element */
1714 pSymbolicLink = HeapAlloc(GetProcessHeap(), 0, (dwLength + 1) * sizeof(WCHAR));
1715 if (!pSymbolicLink)
1716 {
1717 RegCloseKey(hReferenceKey);
1718 RegCloseKey(hDeviceInstanceKey);
1719 RegCloseKey(hInterfaceKey);
1720 return ERROR_NOT_ENOUGH_MEMORY;
1721 }
1722 rc = RegQueryValueExW(hReferenceKey, SymbolicLink, NULL, NULL, (LPBYTE)pSymbolicLink, &dwLength);
1723 pSymbolicLink[dwLength / sizeof(WCHAR)] = '\0';
1724 RegCloseKey(hReferenceKey);
1725 if (rc != ERROR_SUCCESS)
1726 {
1727 HeapFree(GetProcessHeap(), 0, pSymbolicLink);
1728 RegCloseKey(hDeviceInstanceKey);
1729 RegCloseKey(hInterfaceKey);
1730 return rc;
1731 }
1732 if (!CreateDeviceInterface(deviceInfo, pSymbolicLink, InterfaceGuid, &interfaceInfo))
1733 {
1734 HeapFree(GetProcessHeap(), 0, pSymbolicLink);
1735 RegCloseKey(hDeviceInstanceKey);
1736 RegCloseKey(hInterfaceKey);
1737 return GetLastError();
1738 }
1739 TRACE("Adding interface %s to list\n", debugstr_w(pSymbolicLink));
1740 HeapFree(GetProcessHeap(), 0, pSymbolicLink);
1741 InsertTailList(&deviceInfo->InterfaceListHead, &interfaceInfo->ListEntry);
1742 }
1743 RegCloseKey(hDeviceInstanceKey);
1744 }
1745 RegCloseKey(hInterfaceKey);
1746 return ERROR_SUCCESS;
1747 }
1748 #endif /* __REACTOS__ */
1749
1750 /***********************************************************************
1751 * SetupDiGetClassDevsExW (SETUPAPI.@)
1752 */
1753 HDEVINFO WINAPI SetupDiGetClassDevsExW(
1754 CONST GUID *class,
1755 LPCWSTR enumstr,
1756 HWND parent,
1757 DWORD flags,
1758 HDEVINFO deviceset,
1759 LPCWSTR machine,
1760 PVOID reserved)
1761 {
1762 HDEVINFO hDeviceInfo = INVALID_HANDLE_VALUE;
1763 struct DeviceInfoSet *list;
1764 LPGUID pClassGuid;
1765 LONG rc;
1766
1767 TRACE("%s %s %p 0x%08lx %p %s %p\n", debugstr_guid(class), debugstr_w(enumstr),
1768 parent, flags, deviceset, debugstr_w(machine), reserved);
1769
1770 /* Create the deviceset if not set */
1771 if (deviceset)
1772 {
1773 list = (struct DeviceInfoSet *)deviceset;
1774 if (list->magic != SETUP_DEV_INFO_SET_MAGIC)
1775 {
1776 SetLastError(ERROR_INVALID_HANDLE);
1777 return INVALID_HANDLE_VALUE;
1778 }
1779 hDeviceInfo = deviceset;
1780 }
1781 else
1782 {
1783 hDeviceInfo = SetupDiCreateDeviceInfoListExW(
1784 flags & DIGCF_DEVICEINTERFACE ? NULL : class,
1785 NULL, machine, NULL);
1786 if (hDeviceInfo == INVALID_HANDLE_VALUE)
1787 return INVALID_HANDLE_VALUE;
1788 list = (struct DeviceInfoSet *)hDeviceInfo;
1789 }
1790
1791 if (IsEqualIID(&list->ClassGuid, &GUID_NULL))
1792 pClassGuid = NULL;
1793 else
1794 pClassGuid = &list->ClassGuid;
1795
1796 if (flags & DIGCF_PRESENT)
1797 FIXME(": flag DIGCF_PRESENT ignored\n");
1798 if (flags & DIGCF_PROFILE)
1799 FIXME(": flag DIGCF_PROFILE ignored\n");
1800
1801 if (flags & DIGCF_ALLCLASSES)
1802 {
1803 rc = SETUP_CreateDevList(list, machine, pClassGuid, enumstr);
1804 if (rc != ERROR_SUCCESS)
1805 {
1806 SetLastError(rc);
1807 if (!deviceset)
1808 SetupDiDestroyDeviceInfoList(hDeviceInfo);
1809 return INVALID_HANDLE_VALUE;
1810 }
1811 return hDeviceInfo;
1812 }
1813 else if (flags & DIGCF_DEVICEINTERFACE)
1814 {
1815 if (class == NULL)
1816 {
1817 SetLastError(ERROR_INVALID_PARAMETER);
1818 if (!deviceset)
1819 SetupDiDestroyDeviceInfoList(hDeviceInfo);
1820 return INVALID_HANDLE_VALUE;
1821 }
1822
1823 #ifndef __REACTOS__
1824 /* Special case: find serial ports by calling QueryDosDevice */
1825 if (IsEqualIID(class, &GUID_DEVINTERFACE_COMPORT))
1826 rc = SETUP_CreateSerialDeviceList(list, machine, (LPGUID)class, enumstr);
1827 if (IsEqualIID(class, &GUID_DEVINTERFACE_SERENUM_BUS_ENUMERATOR))
1828 rc = SETUP_CreateSerialDeviceList(list, machine, (LPGUID)class, enumstr);
1829 else
1830 {
1831 ERR("Wine can only enumerate serial devices at the moment!\n");
1832 rc = ERROR_INVALID_PARAMETER;
1833 }
1834 #else /* __REACTOS__ */
1835 rc = SETUP_CreateInterfaceList(list, machine, (LPGUID)class, enumstr);
1836 #endif /* __REACTOS__ */
1837 if (rc != ERROR_SUCCESS)
1838 {
1839 SetLastError(rc);
1840 if (!deviceset)
1841 SetupDiDestroyDeviceInfoList(hDeviceInfo);
1842 return INVALID_HANDLE_VALUE;
1843 }
1844 return hDeviceInfo;
1845 }
1846 else
1847 {
1848 rc = SETUP_CreateDevList(list, machine, (LPGUID)class, enumstr);
1849 if (rc != ERROR_SUCCESS)
1850 {
1851 SetLastError(rc);
1852 if (!deviceset)
1853 SetupDiDestroyDeviceInfoList(hDeviceInfo);
1854 return INVALID_HANDLE_VALUE;
1855 }
1856 return hDeviceInfo;
1857 }
1858 }
1859
1860 /***********************************************************************
1861 * SetupDiEnumDeviceInterfaces (SETUPAPI.@)
1862 */
1863 BOOL WINAPI SetupDiEnumDeviceInterfaces(
1864 HDEVINFO DeviceInfoSet,
1865 PSP_DEVINFO_DATA DeviceInfoData,
1866 CONST GUID * InterfaceClassGuid,
1867 DWORD MemberIndex,
1868 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
1869 {
1870 BOOL ret = FALSE;
1871
1872 TRACE("%p, %p, %s, %ld, %p\n", DeviceInfoSet, DeviceInfoData,
1873 debugstr_guid(InterfaceClassGuid), MemberIndex, DeviceInterfaceData);
1874
1875 if (!DeviceInterfaceData)
1876 SetLastError(ERROR_INVALID_PARAMETER);
1877 else if (DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA))
1878 SetLastError(ERROR_INVALID_USER_BUFFER);
1879 else if (DeviceInfoSet && DeviceInfoSet != (HDEVINFO)INVALID_HANDLE_VALUE)
1880 {
1881 struct DeviceInfoSet *list = (struct DeviceInfoSet *)DeviceInfoSet;
1882
1883 if (list->magic == SETUP_DEV_INFO_SET_MAGIC)
1884 {
1885 PLIST_ENTRY ItemList = list->ListHead.Flink;
1886 BOOL Found = FALSE;
1887 while (ItemList != &list->ListHead && !Found)
1888 {
1889 PLIST_ENTRY InterfaceListEntry;
1890 struct DeviceInfoElement *DevInfo = (struct DeviceInfoElement *)ItemList;
1891 if (DeviceInfoData && (struct DeviceInfoElement *)DeviceInfoData->Reserved != DevInfo)
1892 {
1893 /* We are not searching for this element */
1894 ItemList = ItemList->Flink;
1895 continue;
1896 }
1897 InterfaceListEntry = DevInfo->InterfaceListHead.Flink;
1898 while (InterfaceListEntry != &DevInfo->InterfaceListHead && !Found)
1899 {
1900 struct DeviceInterface *DevItf = (struct DeviceInterface *)InterfaceListEntry;
1901 if (!IsEqualIID(&DevItf->InterfaceClassGuid, InterfaceClassGuid))
1902 {
1903 InterfaceListEntry = InterfaceListEntry->Flink;
1904 continue;
1905 }
1906 if (MemberIndex-- == 0)
1907 {
1908 /* return this item */
1909 memcpy(&DeviceInterfaceData->InterfaceClassGuid,
1910 &DevItf->InterfaceClassGuid,
1911 sizeof(GUID));
1912 DeviceInterfaceData->Flags = 0; /* FIXME */
1913 /* Note: this appears to be dangerous, passing a private
1914 * pointer a heap-allocated datum to the caller. However, the
1915 * expected lifetime of the device data is the same as the
1916 * HDEVINFO; once that is closed, the data are no longer valid.
1917 */
1918 DeviceInterfaceData->Reserved = (ULONG_PTR)DevItf;
1919 Found = TRUE;
1920 }
1921 InterfaceListEntry = InterfaceListEntry->Flink;
1922 }
1923 ItemList = ItemList->Flink;
1924 }
1925 if (!Found)
1926 SetLastError(ERROR_NO_MORE_ITEMS);
1927 else
1928 ret = TRUE;
1929 }
1930 else
1931 SetLastError(ERROR_INVALID_HANDLE);
1932 }
1933 else
1934 SetLastError(ERROR_INVALID_HANDLE);
1935 return ret;
1936 }
1937
1938 /***********************************************************************
1939 * SetupDiDestroyDeviceInfoList (SETUPAPI.@)
1940 */
1941 BOOL WINAPI SetupDiDestroyDeviceInfoList(HDEVINFO devinfo)
1942 {
1943 BOOL ret = FALSE;
1944
1945 TRACE("%p\n", devinfo);
1946 if (devinfo && devinfo != (HDEVINFO)INVALID_HANDLE_VALUE)
1947 {
1948 struct DeviceInfoSet *list = (struct DeviceInfoSet *)devinfo;
1949
1950 if (list->magic == SETUP_DEV_INFO_SET_MAGIC)
1951 {
1952 PLIST_ENTRY ListEntry, InterfaceEntry;
1953 struct DeviceInfoElement *deviceInfo;
1954 while (!IsListEmpty(&list->ListHead))
1955 {
1956 ListEntry = RemoveHeadList(&list->ListHead);
1957 deviceInfo = (struct DeviceInfoElement *)ListEntry;
1958 while (!IsListEmpty(&deviceInfo->InterfaceListHead))
1959 {
1960 InterfaceEntry = RemoveHeadList(&deviceInfo->InterfaceListHead);
1961 HeapFree(GetProcessHeap(), 0, InterfaceEntry);
1962 }
1963 HeapFree(GetProcessHeap(), 0, ListEntry);
1964 }
1965 if (list->HKLM != HKEY_LOCAL_MACHINE)
1966 RegCloseKey(list->HKLM);
1967 HeapFree(GetProcessHeap(), 0, list);
1968 ret = TRUE;
1969 }
1970 else
1971 SetLastError(ERROR_INVALID_HANDLE);
1972 }
1973 else
1974 SetLastError(ERROR_INVALID_HANDLE);
1975
1976 TRACE("Returning %d\n", ret);
1977 return ret;
1978 }
1979
1980 /***********************************************************************
1981 * SetupDiGetDeviceInterfaceDetailA (SETUPAPI.@)
1982 */
1983 BOOL WINAPI SetupDiGetDeviceInterfaceDetailA(
1984 HDEVINFO DeviceInfoSet,
1985 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
1986 PSP_DEVICE_INTERFACE_DETAIL_DATA_A DeviceInterfaceDetailData,
1987 DWORD DeviceInterfaceDetailDataSize,
1988 PDWORD RequiredSize,
1989 PSP_DEVINFO_DATA DeviceInfoData)
1990 {
1991 PSP_DEVICE_INTERFACE_DETAIL_DATA_W DeviceInterfaceDetailDataW = NULL;
1992 DWORD sizeW = 0, sizeA;
1993 BOOL ret = FALSE;
1994
1995 TRACE("(%p, %p, %p, %ld, %p, %p)\n", DeviceInfoSet,
1996 DeviceInterfaceData, DeviceInterfaceDetailData,
1997 DeviceInterfaceDetailDataSize, RequiredSize, DeviceInfoData);
1998
1999 if (DeviceInterfaceDetailData->cbSize != sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A))
2000 SetLastError(ERROR_INVALID_USER_BUFFER);
2001 else if (DeviceInterfaceDetailData == NULL && DeviceInterfaceDetailDataSize != 0)
2002 SetLastError(ERROR_INVALID_PARAMETER);
2003 else if (DeviceInterfaceDetailData != NULL && DeviceInterfaceDetailDataSize < FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath) + 1)
2004 SetLastError(ERROR_INVALID_PARAMETER);
2005 else
2006 {
2007 if (DeviceInterfaceDetailData != NULL)
2008 {
2009 sizeW = FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath)
2010 + (DeviceInterfaceDetailDataSize - FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath)) * sizeof(WCHAR);
2011 DeviceInterfaceDetailDataW = (PSP_DEVICE_INTERFACE_DETAIL_DATA_W)HeapAlloc(GetProcessHeap(), 0, sizeW);
2012 if (!DeviceInterfaceDetailDataW)
2013 {
2014 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2015 }
2016 }
2017 if (!DeviceInterfaceDetailData || (DeviceInterfaceDetailData && DeviceInterfaceDetailDataW))
2018 {
2019 DeviceInterfaceDetailDataW->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W);
2020 ret = SetupDiGetDeviceInterfaceDetailW(
2021 DeviceInfoSet,
2022 DeviceInterfaceData,
2023 DeviceInterfaceDetailDataW,
2024 sizeW,
2025 &sizeW,
2026 DeviceInfoData);
2027 sizeA = (sizeW - FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath)) / sizeof(WCHAR)
2028 + FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath);
2029 if (RequiredSize)
2030 *RequiredSize = sizeA;
2031 if (ret && DeviceInterfaceDetailData && DeviceInterfaceDetailDataSize <= sizeA)
2032 {
2033 if (!WideCharToMultiByte(
2034 CP_ACP, 0,
2035 DeviceInterfaceDetailDataW->DevicePath, -1,
2036 DeviceInterfaceDetailData->DevicePath, DeviceInterfaceDetailDataSize - FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath),
2037 NULL, NULL))
2038 {
2039 ret = FALSE;
2040 }
2041 }
2042 }
2043 HeapFree(GetProcessHeap(), 0, DeviceInterfaceDetailDataW);
2044 }
2045
2046 TRACE("Returning %d\n", ret);
2047 return ret;
2048 }
2049
2050 /***********************************************************************
2051 * SetupDiGetDeviceInterfaceDetailW (SETUPAPI.@)
2052 */
2053 BOOL WINAPI SetupDiGetDeviceInterfaceDetailW(
2054 HDEVINFO DeviceInfoSet,
2055 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
2056 PSP_DEVICE_INTERFACE_DETAIL_DATA_W DeviceInterfaceDetailData,
2057 DWORD DeviceInterfaceDetailDataSize,
2058 PDWORD RequiredSize,
2059 PSP_DEVINFO_DATA DeviceInfoData)
2060 {
2061 BOOL ret = FALSE;
2062
2063 TRACE("(%p, %p, %p, %ld, %p, %p): stub\n", DeviceInfoSet,
2064 DeviceInterfaceData, DeviceInterfaceDetailData,
2065 DeviceInterfaceDetailDataSize, RequiredSize, DeviceInfoData);
2066
2067 if (!DeviceInfoSet || !DeviceInterfaceData)
2068 SetLastError(ERROR_INVALID_PARAMETER);
2069 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
2070 SetLastError(ERROR_INVALID_HANDLE);
2071 else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
2072 SetLastError(ERROR_INVALID_HANDLE);
2073 else if (DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA))
2074 SetLastError(ERROR_INVALID_USER_BUFFER);
2075 else if (DeviceInterfaceDetailData->cbSize != sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W))
2076 SetLastError(ERROR_INVALID_USER_BUFFER);
2077 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
2078 SetLastError(ERROR_INVALID_USER_BUFFER);
2079 else if (DeviceInterfaceDetailData == NULL && DeviceInterfaceDetailDataSize != 0)
2080 SetLastError(ERROR_INVALID_PARAMETER);
2081 else if (DeviceInterfaceDetailData != NULL && DeviceInterfaceDetailDataSize < FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath) + sizeof(WCHAR))
2082 SetLastError(ERROR_INVALID_PARAMETER);
2083 else
2084 {
2085 struct DeviceInterface *deviceInterface = (struct DeviceInterface *)DeviceInterfaceData->Reserved;
2086 LPCWSTR devName = deviceInterface->SymbolicLink;
2087 DWORD sizeRequired = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W) +
2088 (lstrlenW(devName) + 1) * sizeof(WCHAR);
2089
2090 if (sizeRequired > DeviceInterfaceDetailDataSize)
2091 {
2092 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2093 if (RequiredSize)
2094 *RequiredSize = sizeRequired;
2095 }
2096 else
2097 {
2098 wcscpy(DeviceInterfaceDetailData->DevicePath, devName);
2099 TRACE("DevicePath is %s\n", debugstr_w(DeviceInterfaceDetailData->DevicePath));
2100 if (DeviceInfoData)
2101 {
2102 memcpy(&DeviceInfoData->ClassGuid,
2103 &deviceInterface->DeviceInfo->ClassGuid,
2104 sizeof(GUID));
2105 DeviceInfoData->DevInst = 0; /* FIXME */
2106 /* Note: this appears to be dangerous, passing a private
2107 * pointer a heap-allocated datum to the caller. However, the
2108 * expected lifetime of the device data is the same as the
2109 * HDEVINFO; once that is closed, the data are no longer valid.
2110 */
2111 DeviceInfoData->Reserved = (ULONG_PTR)deviceInterface->DeviceInfo;
2112 }
2113 ret = TRUE;
2114 }
2115 }
2116
2117 TRACE("Returning %d\n", ret);
2118 return ret;
2119 }
2120
2121 /***********************************************************************
2122 * SetupDiGetDeviceRegistryPropertyA (SETUPAPI.@)
2123 */
2124 BOOL WINAPI SetupDiGetDeviceRegistryPropertyA(
2125 HDEVINFO devinfo,
2126 PSP_DEVINFO_DATA DeviceInfoData,
2127 DWORD Property,
2128 PDWORD PropertyRegDataType,
2129 PBYTE PropertyBuffer,
2130 DWORD PropertyBufferSize,
2131 PDWORD RequiredSize)
2132 {
2133 BOOL bResult;
2134 BOOL bIsStringProperty;
2135 DWORD RegType;
2136 DWORD RequiredSizeA, RequiredSizeW;
2137 DWORD PropertyBufferSizeW;
2138 PBYTE PropertyBufferW;
2139
2140 TRACE("%04lx %p %ld %p %p %ld %p\n", (DWORD)devinfo, DeviceInfoData,
2141 Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize,
2142 RequiredSize);
2143
2144 PropertyBufferSizeW = PropertyBufferSize * 2;
2145 PropertyBufferW = HeapAlloc(GetProcessHeap(), 0, PropertyBufferSizeW);
2146
2147 bResult = SetupDiGetDeviceRegistryPropertyW(
2148 devinfo,
2149 DeviceInfoData,
2150 Property,
2151 &RegType,
2152 PropertyBufferW,
2153 PropertyBufferSizeW,
2154 &RequiredSizeW);
2155
2156 if (!bResult)
2157 {
2158 HeapFree(GetProcessHeap(), 0, PropertyBufferW);
2159 return bResult;
2160 }
2161
2162 bIsStringProperty = (RegType == REG_SZ || RegType == REG_MULTI_SZ || RegType == REG_EXPAND_SZ);
2163
2164 if (bIsStringProperty)
2165 RequiredSizeA = RequiredSizeW / sizeof(WCHAR);
2166 else
2167 RequiredSizeA = RequiredSizeW;
2168
2169 if (RequiredSizeA <= PropertyBufferSize)
2170 {
2171 if (bIsStringProperty && PropertyBufferSize > 0)
2172 {
2173 if (WideCharToMultiByte(CP_ACP, 0, (LPWSTR)PropertyBufferW, RequiredSizeW / sizeof(WCHAR), (LPSTR)PropertyBuffer, PropertyBufferSize, NULL, NULL) == 0)
2174 {
2175 /* Last error is already set by WideCharToMultiByte */
2176 bResult = FALSE;
2177 }
2178 }
2179 else
2180 memcpy(PropertyBuffer, PropertyBufferW, RequiredSizeA);
2181 }
2182 else
2183 {
2184 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2185 bResult = FALSE;
2186 }
2187
2188 HeapFree(GetProcessHeap(), 0, PropertyBufferW);
2189 if (PropertyRegDataType)
2190 *PropertyRegDataType = RegType;
2191 if (RequiredSize)
2192 *RequiredSize = RequiredSizeA;
2193 return bResult;
2194 }
2195
2196 /***********************************************************************
2197 * SetupDiGetDeviceRegistryPropertyW (SETUPAPI.@)
2198 */
2199 BOOL WINAPI SetupDiGetDeviceRegistryPropertyW(
2200 HDEVINFO DeviceInfoSet,
2201 PSP_DEVINFO_DATA DeviceInfoData,
2202 DWORD Property,
2203 PDWORD PropertyRegDataType,
2204 PBYTE PropertyBuffer,
2205 DWORD PropertyBufferSize,
2206 PDWORD RequiredSize)
2207 {
2208 HKEY hEnumKey, hKey;
2209 DWORD rc;
2210 BOOL ret = FALSE;
2211
2212 TRACE("%p %p %ld %p %p %ld %p\n", DeviceInfoSet, DeviceInfoData,
2213 Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize,
2214 RequiredSize);
2215
2216 if (!DeviceInfoSet || DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
2217 SetLastError(ERROR_INVALID_HANDLE);
2218 else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
2219 SetLastError(ERROR_INVALID_HANDLE);
2220 else if (!DeviceInfoData)
2221 SetLastError(ERROR_INVALID_PARAMETER);
2222 else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
2223 SetLastError(ERROR_INVALID_USER_BUFFER);
2224 else if (Property >= SPDRP_MAXIMUM_PROPERTY)
2225 SetLastError(ERROR_INVALID_PARAMETER);
2226 else
2227 {
2228 struct DeviceInfoSet *list = (struct DeviceInfoSet *)DeviceInfoSet;
2229 struct DeviceInfoElement *DevInfo = (struct DeviceInfoElement *)DeviceInfoData->Reserved;
2230
2231 switch (Property)
2232 {
2233 case SPDRP_CAPABILITIES:
2234 case SPDRP_CLASS:
2235 case SPDRP_CLASSGUID:
2236 case SPDRP_COMPATIBLEIDS:
2237 case SPDRP_CONFIGFLAGS:
2238 case SPDRP_DEVICEDESC:
2239 case SPDRP_DRIVER:
2240 case SPDRP_FRIENDLYNAME:
2241 case SPDRP_HARDWAREID:
2242 case SPDRP_LOCATION_INFORMATION:
2243 case SPDRP_LOWERFILTERS:
2244 case SPDRP_MFG:
2245 case SPDRP_SECURITY:
2246 case SPDRP_SERVICE:
2247 case SPDRP_UI_NUMBER:
2248 case SPDRP_UPPERFILTERS:
2249 {
2250 LPCWSTR RegistryPropertyName;
2251 DWORD BufferSize;
2252
2253 switch (Property)
2254 {
2255 case SPDRP_CAPABILITIES:
2256 RegistryPropertyName = L"Capabilities"; break;
2257 case SPDRP_CLASS:
2258 RegistryPropertyName = L"Class"; break;
2259 case SPDRP_CLASSGUID:
2260 RegistryPropertyName = L"ClassGUID"; break;
2261 case SPDRP_COMPATIBLEIDS:
2262 RegistryPropertyName = L"CompatibleIDs"; break;
2263 case SPDRP_CONFIGFLAGS:
2264 RegistryPropertyName = L"ConfigFlags"; break;
2265 case SPDRP_DEVICEDESC:
2266 RegistryPropertyName = L"DeviceDesc"; break;
2267 case SPDRP_DRIVER:
2268 RegistryPropertyName = L"Driver"; break;
2269 case SPDRP_FRIENDLYNAME:
2270 RegistryPropertyName = L"FriendlyName"; break;
2271 case SPDRP_HARDWAREID:
2272 RegistryPropertyName = L"HardwareID"; break;
2273 case SPDRP_LOCATION_INFORMATION:
2274 RegistryPropertyName = L"LocationInformation"; break;
2275 case SPDRP_LOWERFILTERS:
2276 RegistryPropertyName = L"LowerFilters"; break;
2277 case SPDRP_MFG:
2278 RegistryPropertyName = L"Mfg"; break;
2279 case SPDRP_SECURITY:
2280 RegistryPropertyName = L"Security"; break;
2281 case SPDRP_SERVICE:
2282 RegistryPropertyName = L"Service"; break;
2283 case SPDRP_UI_NUMBER:
2284 RegistryPropertyName = L"UINumber"; break;
2285 case SPDRP_UPPERFILTERS:
2286 RegistryPropertyName = L"UpperFilters"; break;
2287 default:
2288 /* Should not happen */
2289 RegistryPropertyName = NULL; break;
2290 }
2291
2292 /* Open registry key name */
2293 rc = RegOpenKeyExW(
2294 list->HKLM,
2295 EnumKeyName,
2296 0, /* Options */
2297 KEY_ENUMERATE_SUB_KEYS,
2298 &hEnumKey);
2299 if (rc != ERROR_SUCCESS)
2300 {
2301 SetLastError(rc);
2302 break;
2303 }
2304 rc = RegOpenKeyExW(
2305 hEnumKey,
2306 DevInfo->Data,
2307 0, /* Options */
2308 KEY_QUERY_VALUE,
2309 &hKey);
2310 RegCloseKey(hEnumKey);
2311 if (rc != ERROR_SUCCESS)
2312 {
2313 SetLastError(rc);
2314 break;
2315 }
2316 /* Read registry entry */
2317 BufferSize = PropertyBufferSize;
2318 rc = RegQueryValueExW(
2319 hKey,
2320 RegistryPropertyName,
2321 NULL, /* Reserved */
2322 PropertyRegDataType,
2323 PropertyBuffer,
2324 &BufferSize);
2325 if (RequiredSize)
2326 *RequiredSize = BufferSize;
2327 if (rc == ERROR_SUCCESS)
2328 ret = TRUE;
2329 else
2330 SetLastError(rc);
2331 RegCloseKey(hKey);
2332 break;
2333 }
2334
2335 case SPDRP_PHYSICAL_DEVICE_OBJECT_NAME:
2336 {
2337 DWORD required = (wcslen(DevInfo->Data) + 1) * sizeof(WCHAR);
2338
2339 if (PropertyRegDataType)
2340 *PropertyRegDataType = REG_SZ;
2341 if (RequiredSize)
2342 *RequiredSize = required;
2343 if (PropertyBufferSize >= required)
2344 {
2345 wcscpy((LPWSTR)PropertyBuffer, DevInfo->Data);
2346 ret = TRUE;
2347 }
2348 else
2349 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2350 break;
2351 }
2352
2353 /*case SPDRP_BUSTYPEGUID:
2354 case SPDRP_LEGACYBUSTYPE:
2355 case SPDRP_BUSNUMBER:
2356 case SPDRP_ENUMERATOR_NAME:
2357 case SPDRP_SECURITY_SDS:
2358 case SPDRP_DEVTYPE:
2359 case SPDRP_EXCLUSIVE:
2360 case SPDRP_CHARACTERISTICS:
2361 case SPDRP_ADDRESS:
2362 case SPDRP_UI_NUMBER_DESC_FORMAT:
2363 case SPDRP_DEVICE_POWER_DATA:*/
2364 #if (WINVER >= 0x501)
2365 /*case SPDRP_REMOVAL_POLICY:
2366 case SPDRP_REMOVAL_POLICY_HW_DEFAULT:
2367 case SPDRP_REMOVAL_POLICY_OVERRIDE:
2368 case SPDRP_INSTALL_STATE:*/
2369 #endif
2370
2371 default:
2372 {
2373 FIXME("Property 0x%lx not implemented\n", Property);
2374 SetLastError(ERROR_NOT_SUPPORTED);
2375 }
2376 }
2377 }
2378
2379 TRACE("Returning %d\n", ret);
2380 return ret;
2381 }
2382
2383
2384 /***********************************************************************
2385 * SetupDiInstallClassA (SETUPAPI.@)
2386 */
2387 BOOL WINAPI SetupDiInstallClassA(
2388 HWND hwndParent,
2389 PCSTR InfFileName,
2390 DWORD Flags,
2391 HSPFILEQ FileQueue)
2392 {
2393 UNICODE_STRING FileNameW;
2394 BOOL Result;
2395
2396 if (!RtlCreateUnicodeStringFromAsciiz(&FileNameW, InfFileName))
2397 {
2398 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2399 return FALSE;
2400 }
2401
2402 Result = SetupDiInstallClassW(hwndParent, FileNameW.Buffer, Flags, FileQueue);
2403
2404 RtlFreeUnicodeString(&FileNameW);
2405
2406 return Result;
2407 }
2408
2409 static HKEY CreateClassKey(HINF hInf)
2410 {
2411 WCHAR FullBuffer[MAX_PATH];
2412 WCHAR Buffer[MAX_PATH];
2413 DWORD RequiredSize;
2414 HKEY hClassKey;
2415
2416 Buffer[0] = '\\';
2417 if (!SetupGetLineTextW(NULL,
2418 hInf,
2419 Version,
2420 ClassGUID,
2421 &Buffer[1],
2422 MAX_PATH - 1,
2423 &RequiredSize))
2424 {
2425 return INVALID_HANDLE_VALUE;
2426 }
2427
2428 lstrcpyW(FullBuffer, ControlClass);
2429 lstrcatW(FullBuffer, Buffer);
2430
2431
2432 if (!SetupGetLineTextW(NULL,
2433 hInf,
2434 Version,
2435 Class,
2436 Buffer,
2437 MAX_PATH,
2438 &RequiredSize))
2439 {
2440 RegDeleteKeyW(HKEY_LOCAL_MACHINE, FullBuffer);
2441 return INVALID_HANDLE_VALUE;
2442 }
2443
2444 if (ERROR_SUCCESS != RegCreateKeyExW(HKEY_LOCAL_MACHINE,
2445 FullBuffer,
2446 0,
2447 NULL,
2448 REG_OPTION_NON_VOLATILE,
2449 KEY_ALL_ACCESS,
2450 NULL,
2451 &hClassKey,
2452 NULL))
2453 {
2454 RegDeleteKeyW(HKEY_LOCAL_MACHINE, FullBuffer);
2455 return INVALID_HANDLE_VALUE;
2456 }
2457
2458 if (ERROR_SUCCESS != RegSetValueExW(hClassKey,
2459 Class,
2460 0,
2461 REG_SZ,
2462 (LPBYTE)Buffer,
2463 RequiredSize * sizeof(WCHAR)))
2464 {
2465 RegCloseKey(hClassKey);
2466 RegDeleteKeyW(HKEY_LOCAL_MACHINE, FullBuffer);
2467 return INVALID_HANDLE_VALUE;
2468 }
2469
2470 return hClassKey;
2471 }
2472
2473 /***********************************************************************
2474 * SetupDiInstallClassW (SETUPAPI.@)
2475 */
2476 BOOL WINAPI SetupDiInstallClassW(
2477 HWND hwndParent,
2478 PCWSTR InfFileName,
2479 DWORD Flags,
2480 HSPFILEQ FileQueue)
2481 {
2482 WCHAR SectionName[MAX_PATH];
2483 DWORD SectionNameLength = 0;
2484 HINF hInf;
2485 BOOL bFileQueueCreated = FALSE;
2486 HKEY hClassKey;
2487
2488 FIXME("not fully implemented\n");
2489
2490 if ((Flags & DI_NOVCP) && (FileQueue == NULL || FileQueue == INVALID_HANDLE_VALUE))
2491 {
2492 SetLastError(ERROR_INVALID_PARAMETER);
2493 return FALSE;
2494 }
2495
2496 /* Open the .inf file */
2497 hInf = SetupOpenInfFileW(InfFileName,
2498 NULL,
2499 INF_STYLE_WIN4,
2500 NULL);
2501 if (hInf == INVALID_HANDLE_VALUE)
2502 {
2503
2504 return FALSE;
2505 }
2506
2507 /* Create or open the class registry key 'HKLM\\CurrentControlSet\\Class\\{GUID}' */
2508 hClassKey = CreateClassKey(hInf);
2509 if (hClassKey == INVALID_HANDLE_VALUE)
2510 {
2511 SetupCloseInfFile(hInf);
2512 return FALSE;
2513 }
2514
2515
2516
2517 /* Try to append a layout file */
2518 #if 0
2519 SetupOpenAppendInfFileW(NULL, hInf, NULL);
2520 #endif
2521
2522 /* Retrieve the actual section name */
2523 SetupDiGetActualSectionToInstallW(hInf,
2524 ClassInstall32,
2525 SectionName,
2526 MAX_PATH,
2527 &SectionNameLength,
2528 NULL);
2529
2530 #if 0
2531 if (!(Flags & DI_NOVCP))
2532 {
2533 FileQueue = SetupOpenFileQueue();
2534 if (FileQueue == INVALID_HANDLE_VALUE)
2535 {
2536 SetupCloseInfFile(hInf);
2537 RegCloseKey(hClassKey);
2538 return FALSE;
2539 }
2540
2541 bFileQueueCreated = TRUE;
2542
2543 }
2544 #endif
2545
2546 SetupInstallFromInfSectionW(NULL,
2547 hInf,
2548 SectionName,
2549 SPINST_REGISTRY,
2550 hClassKey,
2551 NULL,
2552 0,
2553 NULL,
2554 NULL,
2555 INVALID_HANDLE_VALUE,
2556 NULL);
2557
2558 /* FIXME: More code! */
2559
2560 if (bFileQueueCreated)
2561 SetupCloseFileQueue(FileQueue);
2562
2563 SetupCloseInfFile(hInf);
2564
2565 RegCloseKey(hClassKey);
2566 return TRUE;
2567 }
2568
2569
2570 /***********************************************************************
2571 * SetupDiOpenClassRegKey (SETUPAPI.@)
2572 */
2573 HKEY WINAPI SetupDiOpenClassRegKey(
2574 const GUID* ClassGuid,
2575 REGSAM samDesired)
2576 {
2577 return SetupDiOpenClassRegKeyExW(ClassGuid, samDesired,
2578 DIOCR_INSTALLER, NULL, NULL);
2579 }
2580
2581
2582 /***********************************************************************
2583 * SetupDiOpenClassRegKeyExA (SETUPAPI.@)
2584 */
2585 HKEY WINAPI SetupDiOpenClassRegKeyExA(
2586 const GUID* ClassGuid,
2587 REGSAM samDesired,
2588 DWORD Flags,
2589 PCSTR MachineName,
2590 PVOID Reserved)
2591 {
2592 PWSTR MachineNameW = NULL;
2593 HKEY hKey;
2594
2595 TRACE("\n");
2596
2597 if (MachineName)
2598 {
2599 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
2600 if (MachineNameW == NULL)
2601 return INVALID_HANDLE_VALUE;
2602 }
2603
2604 hKey = SetupDiOpenClassRegKeyExW(ClassGuid, samDesired,
2605 Flags, MachineNameW, Reserved);
2606
2607 if (MachineNameW)
2608 MyFree(MachineNameW);
2609
2610 return hKey;
2611 }
2612
2613
2614 /***********************************************************************
2615 * SetupDiOpenClassRegKeyExW (SETUPAPI.@)
2616 */
2617 HKEY WINAPI SetupDiOpenClassRegKeyExW(
2618 const GUID* ClassGuid,
2619 REGSAM samDesired,
2620 DWORD Flags,
2621 PCWSTR MachineName,
2622 PVOID Reserved)
2623 {
2624 LPWSTR lpGuidString;
2625 LPWSTR lpFullGuidString;
2626 DWORD dwLength;
2627 HKEY HKLM;
2628 HKEY hClassesKey;
2629 HKEY hClassKey;
2630 DWORD rc;
2631 LPCWSTR lpKeyName;
2632
2633 if (Flags == DIOCR_INSTALLER)
2634 {
2635 lpKeyName = ControlClass;
2636 }
2637 else if (Flags == DIOCR_INTERFACE)
2638 {
2639 lpKeyName = DeviceClasses;
2640 }
2641 else
2642 {
2643 ERR("Invalid Flags parameter!\n");
2644 SetLastError(ERROR_INVALID_PARAMETER);
2645 return INVALID_HANDLE_VALUE;
2646 }
2647
2648 if (MachineName != NULL)
2649 {
2650 rc = RegConnectRegistryW(MachineName, HKEY_LOCAL_MACHINE, &HKLM);
2651 if (rc != ERROR_SUCCESS)
2652 {
2653 SetLastError(rc);
2654 return INVALID_HANDLE_VALUE;
2655 }
2656 }
2657 else
2658 HKLM = HKEY_LOCAL_MACHINE;
2659
2660 rc = RegOpenKeyExW(HKLM,
2661 lpKeyName,
2662 0,
2663 KEY_ALL_ACCESS,
2664 &hClassesKey);
2665 if (MachineName != NULL) RegCloseKey(HKLM);
2666 if (rc != ERROR_SUCCESS)
2667 {
2668 SetLastError(rc);
2669 return INVALID_HANDLE_VALUE;
2670 }
2671
2672 if (ClassGuid == NULL)
2673 return hClassesKey;
2674
2675 if (UuidToStringW((UUID*)ClassGuid, &lpGuidString) != RPC_S_OK)
2676 {
2677 SetLastError(ERROR_GEN_FAILURE);
2678 RegCloseKey(hClassesKey);
2679 return INVALID_HANDLE_VALUE;
2680 }
2681
2682 dwLength = lstrlenW(lpGuidString);
2683 lpFullGuidString = HeapAlloc(GetProcessHeap(), 0, (dwLength + 3) * sizeof(WCHAR));
2684 if (!lpFullGuidString)
2685 {
2686 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2687 RpcStringFreeW(&lpGuidString);
2688 return INVALID_HANDLE_VALUE;
2689 }
2690 lpFullGuidString[0] = '{';
2691 memcpy(&lpFullGuidString[1], lpGuidString, dwLength * sizeof(WCHAR));
2692 lpFullGuidString[dwLength + 1] = '}';
2693 lpFullGuidString[dwLength + 2] = '\0';
2694 RpcStringFreeW(&lpGuidString);
2695
2696 rc = RegOpenKeyExW(hClassesKey,
2697 lpFullGuidString,
2698 0,
2699 KEY_ALL_ACCESS,
2700 &hClassKey);
2701 if (rc != ERROR_SUCCESS)
2702 {
2703 SetLastError(rc);
2704 HeapFree(GetProcessHeap(), 0, lpFullGuidString);
2705 RegCloseKey(hClassesKey);
2706 return INVALID_HANDLE_VALUE;
2707 }
2708
2709 HeapFree(GetProcessHeap(), 0, lpFullGuidString);
2710 RegCloseKey(hClassesKey);
2711
2712 return hClassKey;
2713 }
2714
2715 /***********************************************************************
2716 * SetupDiOpenDeviceInterfaceW (SETUPAPI.@)
2717 */
2718 BOOL WINAPI SetupDiOpenDeviceInterfaceW(
2719 HDEVINFO DeviceInfoSet,
2720 PCWSTR DevicePath,
2721 DWORD OpenFlags,
2722 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
2723 {
2724 FIXME("%p %s %08lx %p\n",
2725 DeviceInfoSet, debugstr_w(DevicePath), OpenFlags, DeviceInterfaceData);
2726 return FALSE;
2727 }
2728
2729 /***********************************************************************
2730 * SetupDiOpenDeviceInterfaceA (SETUPAPI.@)
2731 */
2732 BOOL WINAPI SetupDiOpenDeviceInterfaceA(
2733 HDEVINFO DeviceInfoSet,
2734 PCSTR DevicePath,
2735 DWORD OpenFlags,
2736 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
2737 {
2738 FIXME("%p %s %08lx %p\n", DeviceInfoSet,
2739 debugstr_a(DevicePath), OpenFlags, DeviceInterfaceData);
2740 return FALSE;
2741 }
2742
2743 /***********************************************************************
2744 * SetupDiSetClassInstallParamsA (SETUPAPI.@)
2745 */
2746 BOOL WINAPI SetupDiSetClassInstallParamsA(
2747 HDEVINFO DeviceInfoSet,
2748 PSP_DEVINFO_DATA DeviceInfoData,
2749 PSP_CLASSINSTALL_HEADER ClassInstallParams,
2750 DWORD ClassInstallParamsSize)
2751 {
2752 FIXME("%p %p %x %lu\n",DeviceInfoSet, DeviceInfoData,
2753 ClassInstallParams->InstallFunction, ClassInstallParamsSize);
2754 return FALSE;
2755 }
2756
2757 /***********************************************************************
2758 * SetupDiCallClassInstaller (SETUPAPI.@)
2759 */
2760 BOOL WINAPI SetupDiCallClassInstaller(
2761 DI_FUNCTION InstallFunction,
2762 HDEVINFO DeviceInfoSet,
2763 PSP_DEVINFO_DATA DeviceInfoData)
2764 {
2765 FIXME("%ld %p %p\n", InstallFunction, DeviceInfoSet, DeviceInfoData);
2766 return FALSE;
2767 }
2768
2769 /***********************************************************************
2770 * SetupDiGetDeviceInstallParamsA (SETUPAPI.@)
2771 */
2772 BOOL WINAPI SetupDiGetDeviceInstallParamsA(
2773 HDEVINFO DeviceInfoSet,
2774 PSP_DEVINFO_DATA DeviceInfoData,
2775 PSP_DEVINSTALL_PARAMS_A DeviceInstallParams)
2776 {
2777 FIXME("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstallParams);
2778 return FALSE;
2779 }
2780
2781 /***********************************************************************
2782 * SetupDiOpenDevRegKey (SETUPAPI.@)
2783 */
2784 HKEY WINAPI SetupDiOpenDevRegKey(
2785 HDEVINFO DeviceInfoSet,
2786 PSP_DEVINFO_DATA DeviceInfoData,
2787 DWORD Scope,
2788 DWORD HwProfile,
2789 DWORD KeyType,
2790 REGSAM samDesired)
2791 {
2792 FIXME("%p %p %ld %ld %ld %lx\n", DeviceInfoSet, DeviceInfoData,
2793 Scope, HwProfile, KeyType, samDesired);
2794 return INVALID_HANDLE_VALUE;
2795 }
2796
2797 /***********************************************************************
2798 * SetupDiCreateDeviceInfoA (SETUPAPI.@)
2799 */
2800 BOOL WINAPI SetupDiCreateDeviceInfoA(
2801 HDEVINFO DeviceInfoSet,
2802 PCSTR DeviceName,
2803 CONST GUID *ClassGuid,
2804 PCSTR DeviceDescription,
2805 HWND hwndParent,
2806 DWORD CreationFlags,
2807 PSP_DEVINFO_DATA DeviceInfoData)
2808 {
2809 LPWSTR DeviceNameW = NULL;
2810 LPWSTR DeviceDescriptionW = NULL;
2811 BOOL bResult;
2812
2813 TRACE("\n");
2814
2815 if (DeviceName)
2816 {
2817 DeviceNameW = MultiByteToUnicode(DeviceName, CP_ACP);
2818 if (DeviceNameW == NULL) return FALSE;
2819 }
2820 if (DeviceDescription)
2821 {
2822 DeviceDescriptionW = MultiByteToUnicode(DeviceDescription, CP_ACP);
2823 if (DeviceDescriptionW == NULL)
2824 {
2825 if (DeviceNameW) MyFree(DeviceNameW);
2826 return FALSE;
2827 }
2828 }
2829
2830 bResult = SetupDiCreateDeviceInfoW(DeviceInfoSet, DeviceNameW,
2831 ClassGuid, DeviceDescriptionW,
2832 hwndParent, CreationFlags,
2833 DeviceInfoData);
2834
2835 if (DeviceNameW) MyFree(DeviceNameW);
2836 if (DeviceDescriptionW) MyFree(DeviceDescriptionW);
2837
2838 return bResult;
2839 }
2840
2841 /***********************************************************************
2842 * SetupDiCreateDeviceInfoW (SETUPAPI.@)
2843 */
2844 BOOL WINAPI SetupDiCreateDeviceInfoW(
2845 HDEVINFO DeviceInfoSet,
2846 PCWSTR DeviceName,
2847 CONST GUID *ClassGuid,
2848 PCWSTR DeviceDescription,
2849 HWND hwndParent,
2850 DWORD CreationFlags,
2851 PSP_DEVINFO_DATA DeviceInfoData)
2852 {
2853 struct DeviceInfoSet *list;
2854 BOOL ret = FALSE;
2855
2856 TRACE("%p %S %s %S %p %lx %p\n", DeviceInfoSet, DeviceName,
2857 debugstr_guid(ClassGuid), DeviceDescription,
2858 hwndParent, CreationFlags, DeviceInfoData);
2859
2860 if (!DeviceInfoSet)
2861 SetLastError(ERROR_INVALID_HANDLE);
2862 else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
2863 SetLastError(ERROR_INVALID_HANDLE);
2864 else if (!ClassGuid)
2865 SetLastError(ERROR_INVALID_PARAMETER);
2866 else if (!IsEqualIID(&list->ClassGuid, &GUID_NULL) && !IsEqualIID(&list->ClassGuid, ClassGuid))
2867 SetLastError(ERROR_CLASS_MISMATCH);
2868 else if (CreationFlags & ~(DICD_GENERATE_ID | DICD_INHERIT_CLASSDRVS))
2869 {
2870 TRACE("Unknown flags: 0x%08lx\n", CreationFlags & ~(DICD_GENERATE_ID | DICD_INHERIT_CLASSDRVS));
2871 SetLastError(ERROR_INVALID_PARAMETER);
2872 }
2873 else
2874 {
2875 SP_DEVINFO_DATA DevInfo;
2876
2877 if (CreationFlags & DICD_GENERATE_ID)
2878 {
2879 /* Generate a new unique ID for this device */
2880 SetLastError(ERROR_GEN_FAILURE);
2881 FIXME("not implemented\n");
2882 }
2883 else
2884 {
2885 /* Device name is fully qualified. Try to open it */
2886 BOOL rc;
2887
2888 DevInfo.cbSize = sizeof(SP_DEVINFO_DATA);
2889 rc = SetupDiOpenDeviceInfoW(
2890 DeviceInfoSet,
2891 DeviceName,
2892 NULL, /* hwndParent */
2893 CreationFlags & DICD_INHERIT_CLASSDRVS ? DIOD_INHERIT_CLASSDRVS : 0,
2894 &DevInfo);
2895
2896 if (rc)
2897 {
2898 /* SetupDiOpenDeviceInfoW has already added
2899 * the device info to the device info set
2900 */
2901 SetLastError(ERROR_DEVINST_ALREADY_EXISTS);
2902 }
2903 else if (GetLastError() == ERROR_FILE_NOT_FOUND)
2904 {
2905 struct DeviceInfoElement *deviceInfo;
2906
2907 if (CreateDeviceInfoElement(DeviceName, ClassGuid, &deviceInfo))
2908 {
2909 InsertTailList(&list->ListHead, &deviceInfo->ListEntry);
2910
2911 if (!DeviceInfoData)
2912 ret = TRUE;
2913 else
2914 {
2915 if (DeviceInfoData->cbSize != sizeof(PSP_DEVINFO_DATA))
2916 {
2917 SetLastError(ERROR_INVALID_USER_BUFFER);
2918 }
2919 else
2920 {
2921 memcpy(&DeviceInfoData->ClassGuid, ClassGuid, sizeof(GUID));
2922 DeviceInfoData->DevInst = 0; /* FIXME */
2923 DeviceInfoData->Reserved = (ULONG_PTR)deviceInfo;
2924 ret = TRUE;
2925 }
2926 }
2927 }
2928 }
2929 }
2930 }
2931
2932 TRACE("Returning %d\n", ret);
2933 return ret;
2934 }
2935
2936 /***********************************************************************
2937 * Helper functions for SetupDiBuildDriverInfoList
2938 */
2939 static BOOL
2940 AddDriverToList(
2941 IN PLIST_ENTRY DriverListHead,
2942 IN DWORD DriverType, /* SPDIT_CLASSDRIVER or SPDIT_COMPATDRIVER */
2943 IN INFCONTEXT ContextDevice,
2944 IN LPCWSTR InfFile,
2945 IN LPCWSTR ProviderName,
2946 IN LPCWSTR ManufacturerName,
2947 FILETIME DriverDate,
2948 DWORDLONG DriverVersion,
2949 IN DWORD Rank)
2950 {
2951 struct DriverInfoElement *driverInfo;
2952 DWORD RequiredSize = 128; /* Initial buffer size */
2953 BOOL Result = FALSE;
2954 LPWSTR DeviceDescription = NULL;
2955 LPWSTR InfInstallSection = NULL;
2956
2957 driverInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(struct DriverInfoElement));
2958 if (!driverInfo)
2959 {
2960 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2961 return FALSE;
2962 }
2963
2964 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2965 while (!Result && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
2966 {
2967 HeapFree(GetProcessHeap(), 0, DeviceDescription);
2968 DeviceDescription = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
2969 if (!DeviceDescription)
2970 return FALSE;
2971 Result = SetupGetStringFieldW(
2972 &ContextDevice,
2973 0, /* Field index */
2974 DeviceDescription, RequiredSize,
2975 &RequiredSize);
2976 }
2977 if (!Result)
2978 {
2979 HeapFree(GetProcessHeap(), 0, driverInfo);
2980 HeapFree(GetProcessHeap(), 0, DeviceDescription);
2981 return FALSE;
2982 }
2983
2984 Result = FALSE;
2985 RequiredSize = 128; /* Initial buffer size */
2986 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2987 while (!Result && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
2988 {
2989 HeapFree(GetProcessHeap(), 0, InfInstallSection);
2990 InfInstallSection = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
2991 if (!InfInstallSection)
2992 {
2993 HeapFree(GetProcessHeap(), 0, driverInfo);
2994 HeapFree(GetProcessHeap(), 0, DeviceDescription);
2995 return FALSE;
2996 }
2997 Result = SetupGetStringFieldW(
2998 &ContextDevice,
2999 1, /* Field index */
3000 InfInstallSection, RequiredSize,
3001 &RequiredSize);
3002 }
3003 if (!Result)
3004 {
3005 HeapFree(GetProcessHeap(), 0, driverInfo);
3006 HeapFree(GetProcessHeap(), 0, DeviceDescription);
3007 HeapFree(GetProcessHeap(), 0, InfInstallSection);
3008 return FALSE;
3009 }
3010
3011 TRACE("Adding driver '%S' [%S/%S] (Rank 0x%lx)\n",
3012 DeviceDescription, InfFile, InfInstallSection, Rank);
3013
3014 driverInfo->Info.DriverType = DriverType;
3015 driverInfo->Info.Reserved = (ULONG_PTR)driverInfo;
3016 wcsncpy(driverInfo->Info.Description, DeviceDescription, LINE_LEN - 1);
3017 driverInfo->Info.Description[LINE_LEN - 1] = '\0';
3018 wcsncpy(driverInfo->Info.MfgName, ManufacturerName, LINE_LEN - 1);
3019 driverInfo->Info.MfgName[LINE_LEN - 1] = '\0';
3020 if (ProviderName)
3021 {
3022 wcsncpy(driverInfo->Info.ProviderName, ProviderName, LINE_LEN - 1);
3023 driverInfo->Info.ProviderName[LINE_LEN - 1] = '\0';
3024 }
3025 else
3026 driverInfo->Info.ProviderName[0] = '\0';
3027 driverInfo->Info.DriverDate = DriverDate;
3028 driverInfo->Info.DriverVersion = DriverVersion;
3029 InsertTailList(DriverListHead, &driverInfo->ListEntry);
3030
3031 HeapFree(GetProcessHeap(), 0, DeviceDescription);
3032 HeapFree(GetProcessHeap(), 0, InfInstallSection);
3033 return TRUE;
3034 }
3035
3036 static BOOL
3037 GetVersionInformationFromInfFile(
3038 IN HINF hInf,
3039 OUT LPGUID ClassGuid,
3040 OUT LPWSTR* pProviderName,
3041 OUT FILETIME* DriverDate,
3042 OUT DWORDLONG* DriverVersion)
3043 {
3044 DWORD RequiredSize;
3045 WCHAR guidW[MAX_GUID_STRING_LEN + 1];
3046 LPWSTR ProviderName = NULL;
3047 BOOL Result;
3048
3049 if (!SetupGetLineTextW(
3050 NULL, /* Context */
3051 hInf,
3052 L"Version", L"ClassGUID",
3053 guidW, sizeof(guidW),
3054 NULL /* Required size */))
3055 {
3056 return FALSE;
3057 }
3058
3059 /* Get Provider name, driver date, and driver version */
3060
3061 guidW[37] = '\0'; /* Replace the } by a NULL character */
3062 if (UuidFromStringW(&guidW[1], ClassGuid) != RPC_S_OK)
3063 {
3064 return FALSE;
3065 }
3066 Result = SetupGetLineTextW(
3067 NULL, /* Context */
3068 hInf, L"Version", L"Provider",
3069 NULL, 0,
3070 &RequiredSize);
3071 if (!Result && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
3072 {
3073 ProviderName = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
3074 if (!ProviderName)
3075 {
3076 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3077 return FALSE;
3078 }
3079 Result = SetupGetLineTextW(
3080 NULL, /* Context */
3081 hInf, L"Version", L"Provider",
3082 ProviderName, RequiredSize,
3083 &RequiredSize);
3084 }
3085 //FIXME: DriverDate = Version.DriverVer => invalid date = 00/00/00
3086 //FIXME: DriverVersion = Version.DriverVer => invalid = 0
3087
3088 *pProviderName = ProviderName;
3089 return TRUE;
3090 }
3091
3092 /***********************************************************************
3093 * SetupDiBuildDriverInfoList (SETUPAPI.@)
3094 */
3095 BOOL WINAPI
3096 SetupDiBuildDriverInfoList(
3097 IN HDEVINFO DeviceInfoSet,
3098 IN OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
3099 IN DWORD DriverType)
3100 {
3101 struct DeviceInfoSet *list;
3102 PVOID Buffer = NULL;
3103 HINF hInf = INVALID_HANDLE_VALUE;
3104 LPWSTR ProviderName = NULL;
3105 LPWSTR ManufacturerName = NULL;
3106 LPWSTR ManufacturerSection = NULL;
3107 LPWSTR HardwareIDs = NULL;
3108 LPWSTR CompatibleIDs = NULL;
3109 FILETIME DriverDate;
3110 DWORDLONG DriverVersion;
3111 DWORD RequiredSize;
3112 BOOL ret = FALSE;
3113
3114 TRACE("%p %p %ld\n", DeviceInfoSet, DeviceInfoData, DriverType);
3115
3116 if (!DeviceInfoSet)
3117 SetLastError(ERROR_INVALID_HANDLE);
3118 else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
3119 SetLastError(ERROR_INVALID_HANDLE);
3120 else if (list->HKLM != HKEY_LOCAL_MACHINE)
3121 SetLastError(ERROR_INVALID_HANDLE);
3122 else if (DriverType != SPDIT_CLASSDRIVER && DriverType != SPDIT_COMPATDRIVER)
3123 SetLastError(ERROR_INVALID_PARAMETER);
3124 else if (DriverType == SPDIT_CLASSDRIVER && DeviceInfoData)
3125 SetLastError(ERROR_INVALID_PARAMETER);
3126 else if (DriverType == SPDIT_COMPATDRIVER && !DeviceInfoData)
3127 SetLastError(ERROR_INVALID_PARAMETER);
3128 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
3129 SetLastError(ERROR_INVALID_USER_BUFFER);
3130 else
3131 {
3132 BOOL Result = FALSE;
3133
3134 if (DriverType == SPDIT_COMPATDRIVER)
3135 {
3136 /* Get hardware IDs list */
3137 Result = FALSE;
3138 RequiredSize = 512; /* Initial buffer size */
3139 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3140 while (!Result && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
3141 {
3142 HeapFree(GetProcessHeap(), 0, HardwareIDs);
3143 HardwareIDs = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
3144 if (!HardwareIDs)
3145 {
3146 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3147 goto done;
3148 }
3149 Result = SetupDiGetDeviceRegistryPropertyW(
3150 DeviceInfoSet,
3151 DeviceInfoData,
3152 SPDRP_HARDWAREID,
3153 NULL,
3154 (PBYTE)HardwareIDs,
3155 RequiredSize,
3156 &RequiredSize);
3157 }
3158 if (!Result)
3159 goto done;
3160
3161 /* Get compatible IDs list */
3162 Result = FALSE;
3163 RequiredSize = 512; /* Initial buffer size */
3164 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3165 while (!Result && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
3166 {
3167 HeapFree(GetProcessHeap(), 0, CompatibleIDs);
3168 CompatibleIDs = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
3169 if (!CompatibleIDs)
3170 {
3171 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3172 goto done;
3173 }
3174 Result = SetupDiGetDeviceRegistryPropertyW(
3175 DeviceInfoSet,
3176 DeviceInfoData,
3177 SPDRP_COMPATIBLEIDS,
3178 NULL,
3179 (PBYTE)CompatibleIDs,
3180 RequiredSize,
3181 &RequiredSize);
3182 if (!Result && GetLastError() == ERROR_FILE_NOT_FOUND)
3183 {
3184 /* No compatible ID for this device */
3185 HeapFree(GetProcessHeap(), 0, CompatibleIDs);
3186 CompatibleIDs = NULL;
3187 Result = TRUE;
3188 }
3189 }
3190 if (!Result)
3191 goto done;
3192 }
3193
3194 /* Enumerate .inf files */
3195 Result = FALSE;
3196 RequiredSize = 32768; /* Initial buffer size */
3197 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3198 while (!Result && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
3199 {
3200 HeapFree(GetProcessHeap(), 0, Buffer);
3201 Buffer = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
3202 if (!Buffer)
3203 {
3204 Result = FALSE;
3205 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3206 break;
3207 }
3208 Result = SetupGetInfFileListW(
3209 NULL, /* Directory path */
3210 INF_STYLE_WIN4,
3211 Buffer, RequiredSize,
3212 &RequiredSize);
3213 }
3214 if (Result)
3215 {
3216 LPCWSTR filename;
3217
3218 for (filename = (LPCWSTR)Buffer; *filename; filename += wcslen(filename) + 1)
3219 {
3220 INFCONTEXT ContextManufacturer, ContextDevice;
3221 GUID ClassGuid;
3222 TRACE("Opening file %S\n", filename);
3223
3224 hInf = SetupOpenInfFileW(filename, NULL, INF_STYLE_WIN4, NULL);
3225 if (hInf == INVALID_HANDLE_VALUE)
3226 continue;
3227
3228 if (!GetVersionInformationFromInfFile(
3229 hInf,
3230 &ClassGuid,
3231 &ProviderName,
3232 &DriverDate,
3233 &DriverVersion))
3234 {
3235 SetupCloseInfFile(hInf);
3236 hInf = INVALID_HANDLE_VALUE;
3237 continue;
3238 }
3239
3240 if (DriverType == SPDIT_CLASSDRIVER)
3241 {
3242 /* Check if the ClassGuid in this .inf file is corresponding with our needs */
3243 if (!IsEqualIID(&list->ClassGuid, &GUID_NULL) && !IsEqualIID(&list->ClassGuid, &ClassGuid))
3244 {
3245 SetupCloseInfFile(hInf);
3246 hInf = INVALID_HANDLE_VALUE;
3247 continue;
3248 }
3249 }
3250
3251 /* Get the manufacturers list */
3252 Result = SetupFindFirstLineW(hInf, L"Manufacturer", NULL, &ContextManufacturer);
3253 while (Result)
3254 {
3255 Result = SetupGetStringFieldW(
3256 &ContextManufacturer,
3257 0, /* Field index */
3258 NULL, 0,
3259 &RequiredSize);
3260 if (!Result && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
3261 {
3262 ManufacturerName = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
3263 if (!ManufacturerName)
3264 {
3265 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3266 goto done;
3267 }
3268 Result = SetupGetStringFieldW(
3269 &ContextManufacturer,
3270 0, /* Field index */
3271 ManufacturerName, RequiredSize,
3272 &RequiredSize);
3273 }
3274 Result = SetupGetStringFieldW(
3275 &ContextManufacturer,
3276 1, /* Field index */
3277 NULL, 0,
3278 &RequiredSize);
3279 if (!Result && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
3280 {
3281 ManufacturerSection = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
3282 if (!ManufacturerSection)
3283 {
3284 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3285 goto done;
3286 }
3287 Result = SetupGetStringFieldW(
3288 &ContextManufacturer,
3289 1, /* Field index */
3290 ManufacturerSection, RequiredSize,
3291 &RequiredSize);
3292 }
3293
3294 TRACE("Enumerating devices in manufacturer %S\n", ManufacturerSection);
3295 Result = SetupFindFirstLineW(hInf, ManufacturerSection, NULL, &ContextDevice);
3296 while (Result)
3297 {
3298 if (DriverType == SPDIT_CLASSDRIVER)
3299 {
3300 /* FIXME: read [ControlFlags] / ExcludeFromSelect */
3301 if (!AddDriverToList(
3302 &list->DriverListHead,
3303 DriverType,
3304 ContextDevice,
3305 filename,
3306 ProviderName,
3307 ManufacturerName,
3308 DriverDate, DriverVersion,
3309 0))
3310 {
3311 break;
3312 }
3313 }
3314 else /* DriverType = SPDIT_COMPATDRIVER */
3315 {
3316 /* 1. Get all fields */
3317 DWORD FieldCount = SetupGetFieldCount(&ContextDevice);
3318 DWORD DriverRank;
3319 DWORD i;
3320 LPCWSTR currentId;
3321 BOOL DriverAlreadyAdded;
3322
3323 for (i = 2; i <= FieldCount; i++)
3324 {
3325 LPWSTR DeviceId = NULL;
3326 Result = FALSE;
3327 RequiredSize = 128; /* Initial buffer size */
3328 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3329 while (!Result && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
3330 {
3331 HeapFree(GetProcessHeap(), 0, DeviceId);
3332 DeviceId = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
3333 if (!DeviceId)
3334 {
3335 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3336 goto done;
3337 }
3338 Result = SetupGetStringFieldW(
3339 &ContextDevice,
3340 i,
3341 DeviceId, RequiredSize,
3342 &RequiredSize);
3343 }
3344 if (!Result)
3345 {
3346 HeapFree(GetProcessHeap(), 0, DeviceId);
3347 goto done;
3348 }
3349 DriverAlreadyAdded = FALSE;
3350 for (DriverRank = 0, currentId = (LPCWSTR)HardwareIDs; !DriverAlreadyAdded && *currentId; currentId += wcslen(currentId) + 1, DriverRank++)
3351 {
3352 if (wcscmp(DeviceId, currentId) == 0)
3353 {
3354 AddDriverToList(
3355 &((struct DeviceInfoElement *)DeviceInfoData->Reserved)->DriverListHead,
3356 DriverType,
3357 ContextDevice,
3358 filename,
3359 ProviderName,
3360 ManufacturerName,
3361 DriverDate, DriverVersion,
3362 DriverRank + (i == 2 ? 0 : 0x1000 + i - 3));
3363 DriverAlreadyAdded = TRUE;
3364 }
3365 }
3366 if (CompatibleIDs)
3367 {
3368 for (DriverRank = 0, currentId = (LPCWSTR)CompatibleIDs; !DriverAlreadyAdded && *currentId; currentId += wcslen(currentId) + 1, DriverRank++)
3369 {
3370 if (wcscmp(DeviceId, currentId) == 0)
3371 {
3372 AddDriverToList(
3373 &((struct DeviceInfoElement *)DeviceInfoData->Reserved)->DriverListHead,
3374 DriverType,
3375 ContextDevice,
3376 filename,
3377 ProviderName,
3378 ManufacturerName,
3379 DriverDate, DriverVersion,
3380 DriverRank + (i == 2 ? 0x2000 : 0x3000 + i - 3));
3381 DriverAlreadyAdded = TRUE;
3382 }
3383 }
3384 }
3385 HeapFree(GetProcessHeap(), 0, DeviceId);
3386 }
3387 }
3388 Result = SetupFindNextLine(&ContextDevice, &ContextDevice);
3389 }
3390
3391 HeapFree(GetProcessHeap(), 0, ManufacturerName);
3392 HeapFree(GetProcessHeap(), 0, ManufacturerSection);
3393 ManufacturerName = ManufacturerSection = NULL;
3394 Result = SetupFindNextLine(&ContextManufacturer, &ContextManufacturer);
3395 }
3396 HeapFree(GetProcessHeap(), 0, ProviderName);
3397 ProviderName = NULL;
3398 ret = TRUE;
3399
3400 SetupCloseInfFile(hInf);
3401 hInf = INVALID_HANDLE_VALUE;
3402 }
3403 ret = TRUE;
3404 }
3405 }
3406
3407 done:
3408 if (ret)
3409 {
3410 if (DeviceInfoData)
3411 {
3412 struct DeviceInfoElement *deviceInfo = (struct DeviceInfoElement *)DeviceInfoData;
3413 deviceInfo->Flags |= DI_DIDCOMPAT;
3414 }
3415 else
3416 list->Flags |= DI_DIDCLASS;
3417 }
3418
3419 HeapFree(GetProcessHeap(), 0, ProviderName);
3420 HeapFree(GetProcessHeap(), 0, ManufacturerName);
3421 HeapFree(GetProcessHeap(), 0, ManufacturerSection);
3422 HeapFree(GetProcessHeap(), 0, HardwareIDs);
3423 HeapFree(GetProcessHeap(), 0, CompatibleIDs);
3424 if (hInf != INVALID_HANDLE_VALUE)
3425 SetupCloseInfFile(hInf);
3426 HeapFree(GetProcessHeap(), 0, Buffer);
3427
3428 TRACE("Returning %d\n", ret);
3429 return ret;
3430 }
3431
3432 /***********************************************************************
3433 * SetupDiDeleteDeviceInfo (SETUPAPI.@)
3434 */
3435 BOOL WINAPI
3436 SetupDiDeleteDeviceInfo(
3437 IN HDEVINFO DeviceInfoSet,
3438 IN PSP_DEVINFO_DATA DeviceInfoData)
3439 {
3440 TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
3441
3442 FIXME("not implemented\n");
3443 SetLastError(ERROR_GEN_FAILURE);
3444 return FALSE;
3445 }
3446
3447
3448 /***********************************************************************
3449 * SetupDiDestroyDriverInfoList (SETUPAPI.@)
3450 */
3451 BOOL WINAPI
3452 SetupDiDestroyDriverInfoList(
3453 IN HDEVINFO DeviceInfoSet,
3454 IN PSP_DEVINFO_DATA DeviceInfoData,
3455 IN DWORD DriverType)
3456 {
3457 TRACE("%p %p 0x%lx\n", DeviceInfoSet, DeviceInfoData, DriverType);
3458
3459 FIXME("not implemented\n");
3460 SetLastError(ERROR_GEN_FAILURE);
3461 return FALSE;
3462 }
3463
3464
3465 /***********************************************************************
3466 * SetupDiOpenDeviceInfoA (SETUPAPI.@)
3467 */
3468 BOOL WINAPI
3469 SetupDiOpenDeviceInfoA(
3470 IN HDEVINFO DeviceInfoSet,
3471 IN PCSTR DeviceInstanceId,
3472 IN HWND hwndParent OPTIONAL,
3473 IN DWORD OpenFlags,
3474 OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
3475 {
3476 LPWSTR DeviceInstanceIdW = NULL;
3477 BOOL bResult;
3478
3479 TRACE("%p %s %p %lx %p\n", DeviceInfoSet, DeviceInstanceId, hwndParent, OpenFlags, DeviceInfoData);
3480
3481 DeviceInstanceIdW = MultiByteToUnicode(DeviceInstanceId, CP_ACP);
3482 if (DeviceInstanceIdW == NULL)
3483 return FALSE;
3484
3485 bResult = SetupDiOpenDeviceInfoW(DeviceInfoSet,
3486 DeviceInstanceIdW, hwndParent, OpenFlags, DeviceInfoData);
3487
3488 MyFree(DeviceInstanceIdW);
3489
3490 return bResult;
3491 }
3492
3493
3494 /***********************************************************************
3495 * SetupDiOpenDeviceInfoW (SETUPAPI.@)
3496 */
3497 BOOL WINAPI
3498 SetupDiOpenDeviceInfoW(
3499 IN HDEVINFO DeviceInfoSet,
3500 IN PCWSTR DeviceInstanceId,
3501 IN HWND hwndParent OPTIONAL,
3502 IN DWORD OpenFlags,
3503 OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
3504 {
3505 struct DeviceInfoSet *list;
3506 HKEY hEnumKey, hKey;
3507 DWORD rc;
3508 BOOL ret = FALSE;
3509
3510 TRACE("%p %S %p %lx %p\n", DeviceInfoSet, DeviceInstanceId, hwndParent, OpenFlags, DeviceInfoData);
3511
3512 if (OpenFlags & DIOD_CANCEL_REMOVE)
3513 FIXME("DIOD_CANCEL_REMOVE flag not implemented\n");
3514
3515 if (!DeviceInfoSet)
3516 SetLastError(ERROR_INVALID_HANDLE);
3517 else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
3518 SetLastError(ERROR_INVALID_HANDLE);
3519 else if (!DeviceInstanceId)
3520 SetLastError(ERROR_INVALID_PARAMETER);
3521 else if (OpenFlags & ~(DIOD_CANCEL_REMOVE | DIOD_INHERIT_CLASSDRVS))
3522 {
3523 TRACE("Unknown flags: 0x%08lx\n", OpenFlags & ~(DIOD_CANCEL_REMOVE | DIOD_INHERIT_CLASSDRVS));
3524 SetLastError(ERROR_INVALID_PARAMETER);
3525 }
3526 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
3527 SetLastError(ERROR_INVALID_USER_BUFFER);
3528 else
3529 {
3530 struct DeviceInfoElement *deviceInfo = NULL;
3531 /* Search if device already exists in DeviceInfoSet.
3532 * If yes, return the existing element
3533 * If no, create a new element using informations in registry
3534 */
3535 PLIST_ENTRY ItemList = list->ListHead.Flink;
3536 while (ItemList != &list->ListHead)
3537 {
3538 // TODO
3539 //if (good one)
3540 // break;
3541 FIXME("not implemented\n");
3542 ItemList = ItemList->Flink;
3543 }
3544
3545 if (deviceInfo)
3546 {
3547 // good one found
3548 if (DeviceInfoData)
3549 {
3550 memcpy(&DeviceInfoData->ClassGuid, &deviceInfo->ClassGuid, sizeof(GUID));
3551 DeviceInfoData->DevInst = 0; /* FIXME */
3552 DeviceInfoData->Reserved = (ULONG_PTR)deviceInfo;
3553 }
3554 ret = TRUE;
3555 }
3556 else
3557 {
3558 /* Open supposed registry key */
3559 rc = RegOpenKeyExW(
3560 list->HKLM,
3561 EnumKeyName,
3562 0, /* Options */
3563 KEY_ENUMERATE_SUB_KEYS,
3564 &hEnumKey);
3565 if (rc != ERROR_SUCCESS)
3566 {
3567 SetLastError(rc);
3568 return FALSE;
3569 }
3570 rc = RegOpenKeyExW(
3571 hEnumKey,
3572 DeviceInstanceId,
3573 0, /* Options */
3574 KEY_QUERY_VALUE,
3575 &hKey);
3576 RegCloseKey(hEnumKey);
3577 if (rc != ERROR_SUCCESS)
3578 {
3579 SetLastError(rc);
3580 return FALSE;
3581 }
3582
3583 if (!CreateDeviceInfoElement(DeviceInstanceId, &GUID_NULL /* FIXME */, &deviceInfo))
3584 {
3585 RegCloseKey(hKey);
3586 return FALSE;
3587 }
3588 InsertTailList(&list->ListHead, &deviceInfo->ListEntry);
3589
3590 RegCloseKey(hKey);
3591 ret = TRUE;
3592 }
3593
3594 if (ret && deviceInfo && DeviceInfoData)
3595 {
3596 memcpy(&DeviceInfoData->ClassGuid, &deviceInfo->ClassGuid, sizeof(GUID));
3597 DeviceInfoData->DevInst = 0; /* FIXME */
3598 DeviceInfoData->Reserved = (ULONG_PTR)deviceInfo;
3599 }
3600 }
3601
3602 return ret;
3603 }
3604
3605
3606 /***********************************************************************
3607 * SetupDiEnumDriverInfoA (SETUPAPI.@)
3608 */
3609 BOOL WINAPI
3610 SetupDiEnumDriverInfoA(
3611 IN HDEVINFO DeviceInfoSet,
3612 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
3613 IN DWORD DriverType,
3614 IN DWORD MemberIndex,
3615 OUT PSP_DRVINFO_DATA_A DriverInfoData)
3616 {
3617 SP_DRVINFO_DATA_V2_W driverInfoData2W;
3618 BOOL ret = FALSE;
3619
3620 TRACE("%p %p 0x%lx %ld %p\n", DeviceInfoSet, DeviceInfoData,
3621 DriverType, MemberIndex, DriverInfoData);
3622
3623 if (DriverInfoData == NULL)
3624 SetLastError(ERROR_INVALID_PARAMETER);
3625 else if (DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V1_A) && DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V2_A))
3626 SetLastError(ERROR_INVALID_USER_BUFFER);
3627 else
3628 {
3629 driverInfoData2W.cbSize = sizeof(SP_DRVINFO_DATA_V2_W);
3630 ret = SetupDiEnumDriverInfoW(DeviceInfoSet, DeviceInfoData,
3631 DriverType, MemberIndex, &driverInfoData2W);
3632
3633 if (ret)
3634 {
3635 /* Do W->A conversion */
3636 DriverInfoData->DriverType = driverInfoData2W.DriverType;
3637 DriverInfoData->Reserved = driverInfoData2W.Reserved;
3638 if (WideCharToMultiByte(CP_ACP, 0, driverInfoData2W.Description, -1,
3639 DriverInfoData->Description, LINE_LEN, NULL, NULL) == 0)
3640 {
3641 DriverInfoData->Description[0] = '\0';
3642 ret = FALSE;
3643 }
3644 if (WideCharToMultiByte(CP_ACP, 0, driverInfoData2W.MfgName, -1,
3645 DriverInfoData->MfgName, LINE_LEN, NULL, NULL) == 0)
3646 {
3647 DriverInfoData->MfgName[0] = '\0';
3648 ret = FALSE;
3649 }
3650 if (WideCharToMultiByte(CP_ACP, 0, driverInfoData2W.ProviderName, -1,
3651 DriverInfoData->ProviderName, LINE_LEN, NULL, NULL) == 0)
3652 {
3653 DriverInfoData->ProviderName[0] = '\0';
3654 ret = FALSE;
3655 }
3656 if (DriverInfoData->cbSize == sizeof(SP_DRVINFO_DATA_V2_A))
3657 {
3658 /* Copy more fields */
3659 DriverInfoData->DriverDate = driverInfoData2W.DriverDate;
3660 DriverInfoData->DriverVersion = driverInfoData2W.DriverVersion;
3661 }
3662 }
3663 }
3664
3665 TRACE("Returning %d\n", ret);
3666 return ret;
3667 }
3668
3669
3670 /***********************************************************************
3671 * SetupDiEnumDriverInfoW (SETUPAPI.@)
3672 */
3673 BOOL WINAPI
3674 SetupDiEnumDriverInfoW(
3675 IN HDEVINFO DeviceInfoSet,
3676 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
3677 IN DWORD DriverType,
3678 IN DWORD MemberIndex,
3679 OUT PSP_DRVINFO_DATA_W DriverInfoData)
3680 {
3681 PLIST_ENTRY ListHead;
3682 BOOL ret = FALSE;
3683
3684 TRACE("%p %p 0x%lx %ld %p\n", DeviceInfoSet, DeviceInfoData,
3685 DriverType, MemberIndex, DriverInfoData);
3686
3687 if (!DeviceInfoSet || !DriverInfoData)
3688 SetLastError(ERROR_INVALID_PARAMETER);
3689 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
3690 SetLastError(ERROR_INVALID_HANDLE);
3691 else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
3692 SetLastError(ERROR_INVALID_HANDLE);
3693 else if (DriverType != SPDIT_CLASSDRIVER && DriverType != SPDIT_COMPATDRIVER)
3694 SetLastError(ERROR_INVALID_PARAMETER);
3695 else if (DriverType == SPDIT_CLASSDRIVER && DeviceInfoData)
3696 SetLastError(ERROR_INVALID_PARAMETER);
3697 else if (DriverType == SPDIT_COMPATDRIVER && !DeviceInfoData)
3698 SetLastError(ERROR_INVALID_PARAMETER);
3699 else if (DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V1_W) && DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V2_W))
3700 SetLastError(ERROR_INVALID_USER_BUFFER);
3701 else
3702 {
3703 struct DeviceInfoElement *devInfo = (struct DeviceInfoElement *)DeviceInfoData->Reserved;
3704 PLIST_ENTRY ItemList;
3705 if (DriverType == SPDIT_CLASSDRIVER ||
3706 devInfo->CreationFlags & DICD_INHERIT_CLASSDRVS)
3707 {
3708 ListHead = &((struct DeviceInfoSet *)DeviceInfoSet)->DriverListHead;
3709 }
3710 else
3711 {
3712 ListHead = &devInfo->DriverListHead;
3713 }
3714
3715 ItemList = ListHead->Flink;
3716 while (ItemList != ListHead && MemberIndex-- > 0)
3717 ItemList = ItemList->Flink;
3718 if (ItemList == ListHead)
3719 SetLastError(ERROR_NO_MORE_ITEMS);
3720 else
3721 {
3722 struct DriverInfoElement *DrvInfo = (struct DriverInfoElement *)ItemList;
3723
3724 memcpy(
3725 DriverInfoData,
3726 &DrvInfo->Info,
3727 DriverInfoData->cbSize);
3728 ret = TRUE;
3729 }
3730 }
3731
3732 TRACE("Returning %d\n", ret);
3733 return ret;
3734 }
3735
3736 /***********************************************************************
3737 * SetupDiGetSelectedDriverW (SETUPAPI.@)
3738 */
3739 BOOL WINAPI
3740 SetupDiGetSelectedDriverW(
3741 IN HDEVINFO DeviceInfoSet,
3742 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
3743 OUT PSP_DRVINFO_DATA_W DriverInfoData)
3744 {
3745 BOOL ret = FALSE;
3746
3747 TRACE("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DriverInfoData);
3748
3749 if (!DeviceInfoSet || !DriverInfoData)
3750 SetLastError(ERROR_INVALID_PARAMETER);
3751 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
3752 SetLastError(ERROR_INVALID_HANDLE);
3753 else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
3754 SetLastError(ERROR_INVALID_HANDLE);
3755 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
3756 SetLastError(ERROR_INVALID_USER_BUFFER);
3757 else if (DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V1_W) && DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V2_W))
3758 SetLastError(ERROR_INVALID_USER_BUFFER);
3759 else
3760 {
3761 struct DriverInfoElement *driverInfo;
3762
3763 if (DeviceInfoData)
3764 driverInfo = ((struct DeviceInfoElement *)DeviceInfoData->Reserved)->SelectedDriver;
3765 else
3766 driverInfo = ((struct DeviceInfoSet *)DeviceInfoSet)->SelectedDriver;
3767
3768 if (driverInfo == NULL)
3769 SetLastError(ERROR_NO_DRIVER_SELECTED);
3770 else
3771 {
3772 memcpy(
3773 DriverInfoData,
3774 &driverInfo->Info,
3775 DriverInfoData->cbSize);
3776 ret = TRUE;
3777 }
3778 }
3779
3780 TRACE("Returning %d\n", ret);
3781 return ret;
3782 }
3783
3784 /***********************************************************************
3785 * SetupDiSetSelectedDriverW (SETUPAPI.@)
3786 */
3787 BOOL WINAPI
3788 SetupDiSetSelectedDriverW(
3789 IN HDEVINFO DeviceInfoSet,
3790 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
3791 IN OUT PSP_DRVINFO_DATA_W DriverInfoData OPTIONAL)
3792 {
3793 BOOL ret = FALSE;
3794
3795 TRACE("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DriverInfoData);
3796
3797 if (!DeviceInfoSet)
3798 SetLastError(ERROR_INVALID_PARAMETER);
3799 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
3800 SetLastError(ERROR_INVALID_HANDLE);
3801 else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
3802 SetLastError(ERROR_INVALID_HANDLE);
3803 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
3804 SetLastError(ERROR_INVALID_USER_BUFFER);
3805 else if (DriverInfoData && DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V1_W) && DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V2_W))
3806 SetLastError(ERROR_INVALID_USER_BUFFER);
3807 else
3808 {
3809 struct DriverInfoElement **pDriverInfo;
3810 PLIST_ENTRY ListHead, ItemList;
3811
3812 if (DeviceInfoData)
3813 {
3814 pDriverInfo = &((struct DeviceInfoElement *)DeviceInfoData->Reserved)->SelectedDriver;
3815 ListHead = &((struct DeviceInfoElement *)DeviceInfoData->Reserved)->DriverListHead;
3816 }
3817 else
3818 {
3819 pDriverInfo = &((struct DeviceInfoSet *)DeviceInfoSet)->SelectedDriver;
3820 ListHead = &((struct DeviceInfoSet *)DeviceInfoSet)->DriverListHead;
3821 }
3822
3823 if (!DriverInfoData)
3824 {
3825 *pDriverInfo = NULL;
3826 ret = TRUE;
3827 }
3828 else
3829 {
3830 /* Search selected driver in list */
3831 ItemList = ListHead->Flink;
3832 while (ItemList != ListHead)
3833 {
3834 if (DriverInfoData->Reserved != 0)
3835 {
3836 if (DriverInfoData->Reserved == (ULONG_PTR)ItemList)
3837 break;
3838 }
3839 else
3840 {
3841 /* The caller wants to compare only DriverType, Description and ProviderName fields */
3842 struct DriverInfoElement *driverInfo = (struct DriverInfoElement *)ItemList;
3843 if (driverInfo->Info.DriverType == DriverInfoData->DriverType
3844 && wcscmp(driverInfo->Info.Description, DriverInfoData->Description) == 0
3845 && wcscmp(driverInfo->Info.ProviderName, DriverInfoData->ProviderName) == 0)
3846 {
3847 break;
3848 }
3849 }
3850 }
3851 if (ItemList == ListHead)
3852 SetLastError(ERROR_INVALID_PARAMETER);
3853 else
3854 {
3855 *pDriverInfo = (struct DriverInfoElement *)ItemList;
3856 DriverInfoData->Reserved = (ULONG_PTR)ItemList;
3857 ret = TRUE;
3858 }
3859 }
3860 }
3861
3862 TRACE("Returning %d\n", ret);
3863 return ret;
3864 }