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