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