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