fixed uninitialized variable warning
[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)