9b59c64c6b07d4a22b7f8b35923d56b73dcbdfbb
[reactos.git] / reactos / lib / setupapi / devinst.c
1 /*
2 * SetupAPI device installer
3 *
4 * Copyright 2000 Andreas Mohr for CodeWeavers
5 * 2005 Hervé Poussineau (hpoussin@reactos.com)
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22 #include "config.h"
23 #include "wine/port.h"
24
25 #include <stdarg.h>
26
27 #include <windows.h>
28 #include "setupapi.h"
29 #include "wine/debug.h"
30 #include "wine/unicode.h"
31 #include "cfgmgr32.h"
32 #include "initguid.h"
33 #define NTOS_MODE_USER
34 #include <ndk/ntndk.h>
35
36 #include "setupapi_private.h"
37
38
39 WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
40
41 /* Unicode constants */
42 static const WCHAR ClassGUID[] = {'C','l','a','s','s','G','U','I','D',0};
43 static const WCHAR Class[] = {'C','l','a','s','s',0};
44 static const WCHAR ClassInstall32[] = {'C','l','a','s','s','I','n','s','t','a','l','l','3','2',0};
45 static const WCHAR DeviceInstance[] = {'D','e','v','i','c','e','I','n','s','t','a','n','c','e',0};
46 static const WCHAR NoDisplayClass[] = {'N','o','D','i','s','p','l','a','y','C','l','a','s','s',0};
47 static const WCHAR NoInstallClass[] = {'N','o','I','s','t','a','l','l','C','l','a','s','s',0};
48 static const WCHAR NoUseClass[] = {'N','o','U','s','e','C','l','a','s','s',0};
49 static const WCHAR NtExtension[] = {'.','N','T',0};
50 static const WCHAR NtPlatformExtension[] = {'.','N','T','x','8','6',0};
51 static const WCHAR SymbolicLink[] = {'S','y','m','b','o','l','i','c','L','i','n','k',0};
52 static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
53 static const WCHAR WinExtension[] = {'.','W','i','n',0};
54
55 /* Registry key and value names */
56 static const WCHAR ControlClass[] = {'S','y','s','t','e','m','\\',
57 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
58 'C','o','n','t','r','o','l','\\',
59 'C','l','a','s','s',0};
60
61 static const WCHAR DeviceClasses[] = {'S','y','s','t','e','m','\\',
62 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
63 'C','o','n','t','r','o','l','\\',
64 'D','e','v','i','c','e','C','l','a','s','s','e','s',0};
65
66 static const WCHAR EnumKeyName[] = {'S','y','s','t','e','m','\\',
67 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
68 'E','n','u','m',0};
69
70
71 /* FIXME: header mess */
72 DEFINE_GUID(GUID_NULL,
73 0x00000000L, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
74 typedef DWORD
75 (CALLBACK* CLASS_INSTALL_PROC) (
76 IN DI_FUNCTION InstallFunction,
77 IN HDEVINFO DeviceInfoSet,
78 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL);
79 typedef BOOL
80 (WINAPI* DEFAULT_CLASS_INSTALL_PROC) (
81 IN HDEVINFO DeviceInfoSet,
82 IN OUT PSP_DEVINFO_DATA DeviceInfoData);
83 typedef DWORD
84 (CALLBACK* COINSTALLER_PROC) (
85 IN DI_FUNCTION InstallFunction,
86 IN HDEVINFO DeviceInfoSet,
87 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
88 IN OUT PCOINSTALLER_CONTEXT_DATA Context);
89
90 #define SETUP_DEV_INFO_SET_MAGIC 0xd00ff057
91
92 struct CoInstallerElement
93 {
94 LIST_ENTRY ListEntry;
95
96 HMODULE Module;
97 COINSTALLER_PROC Function;
98 BOOL DoPostProcessing;
99 PVOID PrivateData;
100 };
101
102 struct DeviceInterface /* Element of DeviceInfoElement.InterfaceListHead */
103 {
104 LIST_ENTRY ListEntry;
105
106 struct DeviceInfoElement* DeviceInfo;
107 GUID InterfaceClassGuid;
108
109
110 /* SPINT_ACTIVE : the interface is active/enabled
111 * SPINT_DEFAULT: the interface is the default interface for the device class FIXME???
112 * SPINT_REMOVED: the interface is removed
113 */
114 DWORD Flags;
115
116 WCHAR SymbolicLink[0]; /* \\?\ACPI#PNP0501#4&2658d0a0&0#{GUID} */
117 };
118
119 struct DriverInfoElement /* Element of DeviceInfoSet.DriverListHead and DeviceInfoElement.DriverListHead */
120 {
121 LIST_ENTRY ListEntry;
122
123 DWORD DriverRank;
124 SP_DRVINFO_DATA_V2_W Info;
125 GUID ClassGuid;
126 LPWSTR InfPath;
127 LPWSTR InfSection;
128 LPWSTR MatchingId;
129 };
130
131 struct DeviceInfoElement /* Element of DeviceInfoSet.ListHead */
132 {
133 LIST_ENTRY ListEntry;
134
135 /* Information about devnode:
136 * - DeviceName:
137 * "Root\*PNP0501" for example.
138 * It doesn't contain the unique ID for the device
139 * (points into the Data field at the end of the structure)
140 * WARNING: no NULL char exist between DeviceName and UniqueId
141 * in Data field!
142 * - UniqueId
143 * "5&1be2108e&0" or "0000"
144 * If DICD_GENERATE_ID is specified in creation flags,
145 * this unique ID is autogenerated using 4 digits, base 10
146 * (points into the Data field at the end of the structure)
147 * - DeviceDescription
148 * String which identifies the device. Can be NULL. If not NULL,
149 * points into the Data field at the end of the structure
150 * - ClassGuid
151 * Identifies the class of this device. FIXME: can it be GUID_NULL?
152 * - CreationFlags
153 * Is a combination of:
154 * - DICD_GENERATE_ID
155 * the unique ID needs to be generated
156 * - DICD_INHERIT_CLASSDRVS
157 * inherit driver of the device info set (== same pointer)
158 * - hwndParent
159 * Used when doing device-specific actions. Can be NULL
160 */
161 PCWSTR DeviceName;
162 PCWSTR UniqueId;
163 PCWSTR DeviceDescription;
164 GUID ClassGuid;
165 DWORD CreationFlags;
166 HWND hwndParent;
167
168 /* Flags is a combination of:
169 * - DI_DIDCOMPAT
170 * Set when the device driver list is created
171 * FlagsEx is a combination of:
172 */
173 DWORD Flags;
174 DWORD FlagsEx;
175
176 /* If CreationFlags contains DICD_INHERIT_CLASSDRVS, this list is invalid */
177 /* If the driver is not searched/detected, this list is empty */
178 LIST_ENTRY DriverListHead; /* List of struct DriverInfoElement */
179 /* Points into DriverListHead list. The pointer is NULL if no driver is
180 * currently chosen. */
181 struct DriverInfoElement *SelectedDriver;
182
183 /* List of interfaces implemented by this device */
184 LIST_ENTRY InterfaceListHead; /* List of struct DeviceInterface */
185
186 WCHAR Data[0];
187 };
188
189 struct DeviceInfoSet /* HDEVINFO */
190 {
191 DWORD magic; /* SETUP_DEV_INFO_SET_MAGIC */
192 GUID ClassGuid; /* If != GUID_NULL, only devices of this class can be in the device info set */
193 HWND hwndParent; /* only used on non-device-specific actions, like as a select-device dialog using the global class driver list */
194 HKEY HKLM; /* Local or distant HKEY_LOCAL_MACHINE registry key */
195
196 /* Flags is a combination of:
197 * - DI_DIDCLASS
198 * Set when the class driver list is created
199 * - DI_COMPAT_FROM_CLASS (FIXME: not supported)
200 * Forces SetupDiBuildDriverInfoList to build a class drivers list
201 * FlagsEx is a combination of:
202 */
203 DWORD Flags;
204 DWORD FlagsEx;
205
206 /* If the driver is not searched/detected, this list is empty */
207 LIST_ENTRY DriverListHead; /* List of struct DriverInfoElement */
208 /* Points into DriverListHead list. The pointer is NULL if no driver is
209 * currently chosen. */
210 struct DriverInfoElement *SelectedDriver;
211
212 LIST_ENTRY ListHead; /* List of struct DeviceInfoElement */
213 };
214
215 /***********************************************************************
216 * SetupDiBuildClassInfoList (SETUPAPI.@)
217 */
218 BOOL WINAPI SetupDiBuildClassInfoList(
219 DWORD Flags,
220 LPGUID ClassGuidList,
221 DWORD ClassGuidListSize,
222 PDWORD RequiredSize)
223 {
224 TRACE("\n");
225 return SetupDiBuildClassInfoListExW(Flags, ClassGuidList,
226 ClassGuidListSize, RequiredSize,
227 NULL, NULL);
228 }
229
230 /***********************************************************************
231 * SetupDiBuildClassInfoListExA (SETUPAPI.@)
232 */
233 BOOL WINAPI SetupDiBuildClassInfoListExA(
234 DWORD Flags,
235 LPGUID ClassGuidList,
236 DWORD ClassGuidListSize,
237 PDWORD RequiredSize,
238 LPCSTR MachineName,
239 PVOID Reserved)
240 {
241 LPWSTR MachineNameW = NULL;
242 BOOL bResult;
243
244 TRACE("\n");
245
246 if (MachineName)
247 {
248 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
249 if (MachineNameW == NULL) return FALSE;
250 }
251
252 bResult = SetupDiBuildClassInfoListExW(Flags, ClassGuidList,
253 ClassGuidListSize, RequiredSize,
254 MachineNameW, Reserved);
255
256 if (MachineNameW)
257 MyFree(MachineNameW);
258
259 return bResult;
260 }
261
262 /***********************************************************************
263 * SetupDiBuildClassInfoListExW (SETUPAPI.@)
264 */
265 BOOL WINAPI SetupDiBuildClassInfoListExW(
266 DWORD Flags,
267 LPGUID ClassGuidList,
268 DWORD ClassGuidListSize,
269 PDWORD RequiredSize,
270 LPCWSTR MachineName,
271 PVOID Reserved)
272 {
273 WCHAR szKeyName[MAX_GUID_STRING_LEN + 1];
274 HKEY hClassesKey;
275 HKEY hClassKey;
276 DWORD dwLength;
277 DWORD dwIndex;
278 LONG lError;
279 DWORD dwGuidListIndex = 0;
280
281 TRACE("\n");
282
283 if (RequiredSize != NULL)
284 *RequiredSize = 0;
285
286 hClassesKey = SetupDiOpenClassRegKeyExW(NULL,
287 KEY_ALL_ACCESS,
288 DIOCR_INSTALLER,
289 MachineName,
290 Reserved);
291 if (hClassesKey == INVALID_HANDLE_VALUE)
292 {
293 return FALSE;
294 }
295
296 for (dwIndex = 0; ; dwIndex++)
297 {
298 dwLength = MAX_GUID_STRING_LEN + 1;
299 lError = RegEnumKeyExW(hClassesKey,
300 dwIndex,
301 szKeyName,
302 &dwLength,
303 NULL,
304 NULL,
305 NULL,
306 NULL);
307 TRACE("RegEnumKeyExW() returns %ld\n", lError);
308 if (lError == ERROR_SUCCESS || lError == ERROR_MORE_DATA)
309 {
310 TRACE("Key name: %p\n", szKeyName);
311
312 if (RegOpenKeyExW(hClassesKey,
313 szKeyName,
314 0,
315 KEY_ALL_ACCESS,
316 &hClassKey))
317 {
318 RegCloseKey(hClassesKey);
319 return FALSE;
320 }
321
322 if (!RegQueryValueExW(hClassKey,
323 NoUseClass,
324 NULL,
325 NULL,
326 NULL,
327 NULL))
328 {
329 TRACE("'NoUseClass' value found!\n");
330 RegCloseKey(hClassKey);
331 continue;
332 }
333
334 if ((Flags & DIBCI_NOINSTALLCLASS) &&
335 (!RegQueryValueExW(hClassKey,
336 NoInstallClass,
337 NULL,
338 NULL,
339 NULL,
340 NULL)))
341 {
342 TRACE("'NoInstallClass' value found!\n");
343 RegCloseKey(hClassKey);
344 continue;
345 }
346
347 if ((Flags & DIBCI_NODISPLAYCLASS) &&
348 (!RegQueryValueExW(hClassKey,
349 NoDisplayClass,
350 NULL,
351 NULL,
352 NULL,
353 NULL)))
354 {
355 TRACE("'NoDisplayClass' value found!\n");
356 RegCloseKey(hClassKey);
357 continue;
358 }
359
360 RegCloseKey(hClassKey);
361
362 TRACE("Guid: %p\n", szKeyName);
363 if (dwGuidListIndex < ClassGuidListSize)
364 {
365 if (szKeyName[0] == L'{' && szKeyName[37] == L'}')
366 {
367 szKeyName[37] = 0;
368 }
369 TRACE("Guid: %p\n", &szKeyName[1]);
370
371 UuidFromStringW(&szKeyName[1],
372 &ClassGuidList[dwGuidListIndex]);
373 }
374
375 dwGuidListIndex++;
376 }
377
378 if (lError != ERROR_SUCCESS)
379 break;
380 }
381
382 RegCloseKey(hClassesKey);
383
384 if (RequiredSize != NULL)
385 *RequiredSize = dwGuidListIndex;
386
387 if (ClassGuidListSize < dwGuidListIndex)
388 {
389 SetLastError(ERROR_INSUFFICIENT_BUFFER);
390 return FALSE;
391 }
392
393 return TRUE;
394 }
395
396 /***********************************************************************
397 * SetupDiClassGuidsFromNameA (SETUPAPI.@)
398 */
399 BOOL WINAPI SetupDiClassGuidsFromNameA(
400 LPCSTR ClassName,
401 LPGUID ClassGuidList,
402 DWORD ClassGuidListSize,
403 PDWORD RequiredSize)
404 {
405 return SetupDiClassGuidsFromNameExA(ClassName, ClassGuidList,
406 ClassGuidListSize, RequiredSize,
407 NULL, NULL);
408 }
409
410 /***********************************************************************
411 * SetupDiClassGuidsFromNameW (SETUPAPI.@)
412 */
413 BOOL WINAPI SetupDiClassGuidsFromNameW(
414 LPCWSTR ClassName,
415 LPGUID ClassGuidList,
416 DWORD ClassGuidListSize,
417 PDWORD RequiredSize)
418 {
419 return SetupDiClassGuidsFromNameExW(ClassName, ClassGuidList,
420 ClassGuidListSize, RequiredSize,
421 NULL, NULL);
422 }
423
424 /***********************************************************************
425 * SetupDiClassGuidsFromNameExA (SETUPAPI.@)
426 */
427 BOOL WINAPI SetupDiClassGuidsFromNameExA(
428 LPCSTR ClassName,
429 LPGUID ClassGuidList,
430 DWORD ClassGuidListSize,
431 PDWORD RequiredSize,
432 LPCSTR MachineName,
433 PVOID Reserved)
434 {
435 LPWSTR ClassNameW = NULL;
436 LPWSTR MachineNameW = NULL;
437 BOOL bResult;
438
439 TRACE("\n");
440
441 ClassNameW = MultiByteToUnicode(ClassName, CP_ACP);
442 if (ClassNameW == NULL)
443 return FALSE;
444
445 if (MachineNameW)
446 {
447 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
448 if (MachineNameW == NULL)
449 {
450 MyFree(ClassNameW);
451 return FALSE;
452 }
453 }
454
455 bResult = SetupDiClassGuidsFromNameExW(ClassNameW, ClassGuidList,
456 ClassGuidListSize, RequiredSize,
457 MachineNameW, Reserved);
458
459 if (MachineNameW)
460 MyFree(MachineNameW);
461
462 MyFree(ClassNameW);
463
464 return bResult;
465 }
466
467 /***********************************************************************
468 * SetupDiClassGuidsFromNameExW (SETUPAPI.@)
469 */
470 BOOL WINAPI SetupDiClassGuidsFromNameExW(
471 LPCWSTR ClassName,
472 LPGUID ClassGuidList,
473 DWORD ClassGuidListSize,
474 PDWORD RequiredSize,
475 LPCWSTR MachineName,
476 PVOID Reserved)
477 {
478 WCHAR szKeyName[MAX_GUID_STRING_LEN + 1];
479 WCHAR szClassName[256];
480 HKEY hClassesKey;
481 HKEY hClassKey;
482 DWORD dwLength;
483 DWORD dwIndex;
484 LONG lError;
485 DWORD dwGuidListIndex = 0;
486
487 if (RequiredSize != NULL)
488 *RequiredSize = 0;
489
490 hClassesKey = SetupDiOpenClassRegKeyExW(NULL,
491 KEY_ENUMERATE_SUB_KEYS,
492 DIOCR_INSTALLER,
493 MachineName,
494 Reserved);
495 if (hClassesKey == INVALID_HANDLE_VALUE)
496 {
497 return FALSE;
498 }
499
500 for (dwIndex = 0; ; dwIndex++)
501 {
502 dwLength = MAX_GUID_STRING_LEN + 1;
503 lError = RegEnumKeyExW(hClassesKey,
504 dwIndex,
505 szKeyName,
506 &dwLength,
507 NULL,
508 NULL,
509 NULL,
510 NULL);
511 TRACE("RegEnumKeyExW() returns %ld\n", lError);
512 if (lError == ERROR_SUCCESS || lError == ERROR_MORE_DATA)
513 {
514 TRACE("Key name: %p\n", szKeyName);
515
516 if (RegOpenKeyExW(hClassesKey,
517 szKeyName,
518 0,
519 KEY_QUERY_VALUE,
520 &hClassKey))
521 {
522 RegCloseKey(hClassesKey);
523 return FALSE;
524 }
525
526 dwLength = 256 * sizeof(WCHAR);
527 if (!RegQueryValueExW(hClassKey,
528 Class,
529 NULL,
530 NULL,
531 (LPBYTE)szClassName,
532 &dwLength))
533 {
534 TRACE("Class name: %p\n", szClassName);
535
536 if (strcmpiW(szClassName, ClassName) == 0)
537 {
538 TRACE("Found matching class name\n");
539
540 TRACE("Guid: %p\n", szKeyName);
541 if (dwGuidListIndex < ClassGuidListSize)
542 {
543 if (szKeyName[0] == L'{' && szKeyName[37] == L'}')
544 {
545 szKeyName[37] = 0;
546 }
547 TRACE("Guid: %p\n", &szKeyName[1]);
548
549 UuidFromStringW(&szKeyName[1],
550 &ClassGuidList[dwGuidListIndex]);
551 }
552
553 dwGuidListIndex++;
554 }
555 }
556
557 RegCloseKey(hClassKey);
558 }
559
560 if (lError != ERROR_SUCCESS)
561 break;
562 }
563
564 RegCloseKey(hClassesKey);
565
566 if (RequiredSize != NULL)
567 *RequiredSize = dwGuidListIndex;
568
569 if (ClassGuidListSize < dwGuidListIndex)
570 {
571 SetLastError(ERROR_INSUFFICIENT_BUFFER);
572 return FALSE;
573 }
574
575 return TRUE;
576 }
577
578 /***********************************************************************
579 * SetupDiClassNameFromGuidA (SETUPAPI.@)
580 */
581 BOOL WINAPI SetupDiClassNameFromGuidA(
582 const GUID* ClassGuid,
583 PSTR ClassName,
584 DWORD ClassNameSize,
585 PDWORD RequiredSize)
586 {
587 return SetupDiClassNameFromGuidExA(ClassGuid, ClassName,
588 ClassNameSize, RequiredSize,
589 NULL, NULL);
590 }
591
592 /***********************************************************************
593 * SetupDiClassNameFromGuidW (SETUPAPI.@)
594 */
595 BOOL WINAPI SetupDiClassNameFromGuidW(
596 const GUID* ClassGuid,
597 PWSTR ClassName,
598 DWORD ClassNameSize,
599 PDWORD RequiredSize)
600 {
601 return SetupDiClassNameFromGuidExW(ClassGuid, ClassName,
602 ClassNameSize, RequiredSize,
603 NULL, NULL);
604 }
605
606 /***********************************************************************
607 * SetupDiClassNameFromGuidExA (SETUPAPI.@)
608 */
609 BOOL WINAPI SetupDiClassNameFromGuidExA(
610 const GUID* ClassGuid,
611 PSTR ClassName,
612 DWORD ClassNameSize,
613 PDWORD RequiredSize,
614 PCSTR MachineName,
615 PVOID Reserved)
616 {
617 WCHAR ClassNameW[MAX_CLASS_NAME_LEN];
618 LPWSTR MachineNameW = NULL;
619 BOOL ret;
620
621 if (MachineName)
622 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
623 ret = SetupDiClassNameFromGuidExW(ClassGuid, ClassNameW, MAX_CLASS_NAME_LEN,
624 NULL, MachineNameW, Reserved);
625 if (ret)
626 {
627 int len = WideCharToMultiByte(CP_ACP, 0, ClassNameW, -1, ClassName,
628 ClassNameSize, NULL, NULL);
629
630 if (!ClassNameSize && RequiredSize)
631 *RequiredSize = len;
632 }
633 MyFree(MachineNameW);
634 return ret;
635 }
636
637 /***********************************************************************
638 * SetupDiClassNameFromGuidExW (SETUPAPI.@)
639 */
640 BOOL WINAPI SetupDiClassNameFromGuidExW(
641 const GUID* ClassGuid,
642 PWSTR ClassName,
643 DWORD ClassNameSize,
644 PDWORD RequiredSize,
645 PCWSTR MachineName,
646 PVOID Reserved)
647 {
648 HKEY hKey;
649 DWORD dwLength;
650 LONG rc;
651
652 hKey = SetupDiOpenClassRegKeyExW(ClassGuid,
653 KEY_QUERY_VALUE,
654 DIOCR_INSTALLER,
655 MachineName,
656 Reserved);
657 if (hKey == INVALID_HANDLE_VALUE)
658 {
659 return FALSE;
660 }
661
662 if (RequiredSize != NULL)
663 {
664 dwLength = 0;
665 rc = RegQueryValueExW(hKey,
666 Class,
667 NULL,
668 NULL,
669 NULL,
670 &dwLength);
671 if (rc != ERROR_SUCCESS)
672 {
673 SetLastError(rc);
674 RegCloseKey(hKey);
675 return FALSE;
676 }
677
678 *RequiredSize = dwLength / sizeof(WCHAR);
679 }
680
681 dwLength = ClassNameSize * sizeof(WCHAR);
682 rc = RegQueryValueExW(hKey,
683 Class,
684 NULL,
685 NULL,
686 (LPBYTE)ClassName,
687 &dwLength);
688 if (rc != ERROR_SUCCESS)
689 {
690 SetLastError(rc);
691 RegCloseKey(hKey);
692 return FALSE;
693 }
694
695 RegCloseKey(hKey);
696
697 return TRUE;
698 }
699
700 /***********************************************************************
701 * SetupDiCreateDeviceInfoList (SETUPAPI.@)
702 */
703 HDEVINFO WINAPI
704 SetupDiCreateDeviceInfoList(const GUID *ClassGuid,
705 HWND hwndParent)
706 {
707 return SetupDiCreateDeviceInfoListExW(ClassGuid, hwndParent, NULL, NULL);
708 }
709
710 /***********************************************************************
711 * SetupDiCreateDeviceInfoListExA (SETUPAPI.@)
712 */
713 HDEVINFO WINAPI
714 SetupDiCreateDeviceInfoListExA(const GUID *ClassGuid,
715 HWND hwndParent,
716 PCSTR MachineName,
717 PVOID Reserved)
718 {
719 LPWSTR MachineNameW = NULL;
720 HDEVINFO hDevInfo;
721
722 TRACE("%p %p %s %p\n", ClassGuid, hwndParent, MachineName, Reserved);
723
724 if (MachineName)
725 {
726 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
727 if (MachineNameW == NULL)
728 return (HDEVINFO)INVALID_HANDLE_VALUE;
729 }
730
731 hDevInfo = SetupDiCreateDeviceInfoListExW(ClassGuid, hwndParent,
732 MachineNameW, Reserved);
733
734 if (MachineNameW)
735 MyFree(MachineNameW);
736
737 return hDevInfo;
738 }
739
740 /***********************************************************************
741 * SetupDiCreateDeviceInfoListExW (SETUPAPI.@)
742 */
743 HDEVINFO WINAPI
744 SetupDiCreateDeviceInfoListExW(const GUID *ClassGuid,
745 HWND hwndParent,
746 PCWSTR MachineName,
747 PVOID Reserved)
748 {
749 struct DeviceInfoSet *list;
750 DWORD rc;
751
752 TRACE("%p %p %S %p\n", ClassGuid, hwndParent, MachineName, Reserved);
753
754 list = HeapAlloc(GetProcessHeap(), 0, sizeof(struct DeviceInfoSet));
755 if (!list)
756 {
757 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
758 return (HDEVINFO)INVALID_HANDLE_VALUE;
759 }
760
761 list->magic = SETUP_DEV_INFO_SET_MAGIC;
762 memcpy(
763 &list->ClassGuid,
764 ClassGuid ? ClassGuid : &GUID_NULL,
765 sizeof(list->ClassGuid));
766 list->hwndParent = hwndParent;
767 if (MachineName)
768 {
769 rc = RegConnectRegistryW(MachineName, HKEY_LOCAL_MACHINE, &list->HKLM);
770 if (rc != ERROR_SUCCESS)
771 {
772 SetLastError(rc);
773 HeapFree(GetProcessHeap(), 0, list);
774 return (HDEVINFO)INVALID_HANDLE_VALUE;
775 }
776 }
777 else
778 {
779 list->HKLM = HKEY_LOCAL_MACHINE;
780 }
781 list->Flags = 0; /* FIXME */
782 list->FlagsEx = 0; /* FIXME */
783 InitializeListHead(&list->DriverListHead);
784 InitializeListHead(&list->ListHead);
785 return (HDEVINFO)list;
786 }
787
788 /***********************************************************************
789 * SetupDiEnumDeviceInfo (SETUPAPI.@)
790 */
791 BOOL WINAPI SetupDiEnumDeviceInfo(
792 HDEVINFO DeviceInfoSet,
793 DWORD MemberIndex,
794 PSP_DEVINFO_DATA DeviceInfoData)
795 {
796 BOOL ret = FALSE;
797
798 TRACE("%p, 0x%08lx, %p\n", DeviceInfoSet, MemberIndex, DeviceInfoData);
799 if (!DeviceInfoData)
800 SetLastError(ERROR_INVALID_PARAMETER);
801 else if (DeviceInfoSet && DeviceInfoSet != (HDEVINFO)INVALID_HANDLE_VALUE)
802 {
803 struct DeviceInfoSet *list = (struct DeviceInfoSet *)DeviceInfoSet;
804
805 if (list->magic != SETUP_DEV_INFO_SET_MAGIC)
806 SetLastError(ERROR_INVALID_HANDLE);
807 else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
808 SetLastError(ERROR_INVALID_USER_BUFFER);
809 else
810 {
811 PLIST_ENTRY ItemList = list->ListHead.Flink;
812 while (ItemList != &list->ListHead && MemberIndex-- > 0)
813 ItemList = ItemList->Flink;
814 if (ItemList == &list->ListHead)
815 SetLastError(ERROR_NO_MORE_ITEMS);
816 else
817 {
818 struct DeviceInfoElement *DevInfo = (struct DeviceInfoElement *)ItemList;
819 memcpy(&DeviceInfoData->ClassGuid,
820 &DevInfo->ClassGuid,
821 sizeof(GUID));
822 DeviceInfoData->DevInst = 0; /* FIXME */
823 /* Note: this appears to be dangerous, passing a private
824 * pointer a heap-allocated datum to the caller. However, the
825 * expected lifetime of the device data is the same as the
826 * HDEVINFO; once that is closed, the data are no longer valid.
827 */
828 DeviceInfoData->Reserved = (ULONG_PTR)DevInfo;
829 ret = TRUE;
830 }
831 }
832 }
833 else
834 SetLastError(ERROR_INVALID_HANDLE);
835 return ret;
836 }
837
838 /***********************************************************************
839 * SetupDiGetActualSectionToInstallA (SETUPAPI.@)
840 */
841 BOOL WINAPI SetupDiGetActualSectionToInstallA(
842 HINF InfHandle,
843 PCSTR InfSectionName,
844 PSTR InfSectionWithExt,
845 DWORD InfSectionWithExtSize,
846 PDWORD RequiredSize,
847 PSTR *Extension)
848 {
849 LPWSTR InfSectionNameW = NULL;
850 PWSTR InfSectionWithExtW = NULL;
851 PWSTR ExtensionW;
852 BOOL bResult = FALSE;
853
854 TRACE("\n");
855
856 if (InfSectionName)
857 {
858 InfSectionNameW = MultiByteToUnicode(InfSectionName, CP_ACP);
859 if (InfSectionNameW == NULL) goto end;
860 }
861 if (InfSectionWithExt)
862 {
863 InfSectionWithExtW = HeapAlloc(GetProcessHeap(), 0, InfSectionWithExtSize * sizeof(WCHAR));
864 if (InfSectionWithExtW == NULL) goto end;
865 }
866
867 bResult = SetupDiGetActualSectionToInstallW(InfHandle, InfSectionNameW,
868 InfSectionWithExt ? InfSectionNameW : NULL,
869 InfSectionWithExtSize, RequiredSize,
870 Extension ? &ExtensionW : NULL);
871
872 if (bResult && InfSectionWithExt)
873 {
874 bResult = WideCharToMultiByte(CP_ACP, 0, InfSectionWithExtW, -1, InfSectionWithExt,
875 InfSectionWithExtSize, NULL, NULL) != 0;
876 }
877 if (bResult && Extension)
878 {
879 if (ExtensionW == NULL)
880 *Extension = NULL;
881 else
882 *Extension = &InfSectionWithExt[ExtensionW - InfSectionWithExtW];
883 }
884
885 end:
886 if (InfSectionNameW) MyFree(InfSectionNameW);
887 if (InfSectionWithExtW) HeapFree(GetProcessHeap(), 0, InfSectionWithExtW);
888
889 return bResult;
890 }
891
892 /***********************************************************************
893 * SetupDiGetActualSectionToInstallW (SETUPAPI.@)
894 */
895 BOOL WINAPI SetupDiGetActualSectionToInstallW(
896 HINF InfHandle,
897 PCWSTR InfSectionName,
898 PWSTR InfSectionWithExt,
899 DWORD InfSectionWithExtSize,
900 PDWORD RequiredSize,
901 PWSTR *Extension)
902 {
903 WCHAR szBuffer[MAX_PATH];
904 DWORD dwLength;
905 DWORD dwFullLength;
906 LONG lLineCount = -1;
907
908 lstrcpyW(szBuffer, InfSectionName);
909 dwLength = lstrlenW(szBuffer);
910
911 if (OsVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
912 {
913 /* Test section name with '.NTx86' extension */
914 lstrcpyW(&szBuffer[dwLength], NtPlatformExtension);
915 lLineCount = SetupGetLineCountW(InfHandle, szBuffer);
916
917 if (lLineCount == -1)
918 {
919 /* Test section name with '.NT' extension */
920 lstrcpyW(&szBuffer[dwLength], NtExtension);
921 lLineCount = SetupGetLineCountW(InfHandle, szBuffer);
922 }
923 }
924 else
925 {
926 /* Test section name with '.Win' extension */
927 lstrcpyW(&szBuffer[dwLength], WinExtension);
928 lLineCount = SetupGetLineCountW(InfHandle, szBuffer);
929 }
930
931 if (lLineCount == -1)
932 {
933 /* Test section name without extension */
934 szBuffer[dwLength] = 0;
935 lLineCount = SetupGetLineCountW(InfHandle, szBuffer);
936 }
937
938 if (lLineCount == -1)
939 {
940 SetLastError(ERROR_INVALID_PARAMETER);
941 return FALSE;
942 }
943
944 dwFullLength = lstrlenW(szBuffer);
945
946 if (InfSectionWithExt != NULL && InfSectionWithExtSize != 0)
947 {
948 if (InfSectionWithExtSize < (dwFullLength + 1))
949 {
950 SetLastError(ERROR_INSUFFICIENT_BUFFER);
951 return FALSE;
952 }
953
954 lstrcpyW(InfSectionWithExt, szBuffer);
955 if (Extension != NULL)
956 {
957 *Extension = (dwLength == dwFullLength) ? NULL : &InfSectionWithExt[dwLength];
958 }
959 }
960
961 if (RequiredSize != NULL)
962 {
963 *RequiredSize = dwFullLength + 1;
964 }
965
966 return TRUE;
967 }
968
969 /***********************************************************************
970 * SetupDiGetClassDescriptionA (SETUPAPI.@)
971 */
972 BOOL WINAPI SetupDiGetClassDescriptionA(
973 const GUID* ClassGuid,
974 PSTR ClassDescription,
975 DWORD ClassDescriptionSize,
976 PDWORD RequiredSize)
977 {
978 return SetupDiGetClassDescriptionExA(ClassGuid, ClassDescription,
979 ClassDescriptionSize,
980 RequiredSize, NULL, NULL);
981 }
982
983 /***********************************************************************
984 * SetupDiGetClassDescriptionW (SETUPAPI.@)
985 */
986 BOOL WINAPI SetupDiGetClassDescriptionW(
987 const GUID* ClassGuid,
988 PWSTR ClassDescription,
989 DWORD ClassDescriptionSize,
990 PDWORD RequiredSize)
991 {
992 return SetupDiGetClassDescriptionExW(ClassGuid, ClassDescription,
993 ClassDescriptionSize,
994 RequiredSize, NULL, NULL);
995 }
996
997 /***********************************************************************
998 * SetupDiGetClassDescriptionExA (SETUPAPI.@)
999 */
1000 BOOL WINAPI SetupDiGetClassDescriptionExA(
1001 const GUID* ClassGuid,
1002 PSTR ClassDescription,
1003 DWORD ClassDescriptionSize,
1004 PDWORD RequiredSize,
1005 PCSTR MachineName,
1006 PVOID Reserved)
1007 {
1008 PWCHAR ClassDescriptionW;
1009 LPWSTR MachineNameW = NULL;
1010 BOOL ret;
1011
1012 TRACE("\n");
1013 if (ClassDescriptionSize > 0)
1014 {
1015 ClassDescriptionW = HeapAlloc(GetProcessHeap(), 0, ClassDescriptionSize * sizeof(WCHAR));
1016 if (!ClassDescriptionW)
1017 {
1018 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1019 ret = FALSE;
1020 goto end;
1021 }
1022 }
1023 else
1024 ClassDescriptionW = NULL;
1025
1026 if (MachineName)
1027 {
1028 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
1029 if (!MachineNameW)
1030 {
1031 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1032 ret = FALSE;
1033 goto end;
1034 }
1035 }
1036
1037 ret = SetupDiGetClassDescriptionExW(ClassGuid, ClassDescriptionW, ClassDescriptionSize * sizeof(WCHAR),
1038 NULL, MachineNameW, Reserved);
1039 if (ret)
1040 {
1041 int len = WideCharToMultiByte(CP_ACP, 0, ClassDescriptionW, -1, ClassDescription,
1042 ClassDescriptionSize, NULL, NULL);
1043
1044 if (!ClassDescriptionSize && RequiredSize)
1045 *RequiredSize = len;
1046 }
1047
1048 end:
1049 HeapFree(GetProcessHeap(), 0, ClassDescriptionW);
1050 MyFree(MachineNameW);
1051 return ret;
1052 }
1053
1054 /***********************************************************************
1055 * SetupDiGetClassDescriptionExW (SETUPAPI.@)
1056 */
1057 BOOL WINAPI SetupDiGetClassDescriptionExW(
1058 const GUID* ClassGuid,
1059 PWSTR ClassDescription,
1060 DWORD ClassDescriptionSize,
1061 PDWORD RequiredSize,
1062 PCWSTR MachineName,
1063 PVOID Reserved)
1064 {
1065 HKEY hKey;
1066 DWORD dwLength;
1067
1068 hKey = SetupDiOpenClassRegKeyExW(ClassGuid,
1069 KEY_ALL_ACCESS,
1070 DIOCR_INSTALLER,
1071 MachineName,
1072 Reserved);
1073 if (hKey == INVALID_HANDLE_VALUE)
1074 {
1075 WARN("SetupDiOpenClassRegKeyExW() failed (Error %lu)\n", GetLastError());
1076 return FALSE;
1077 }
1078
1079 if (RequiredSize != NULL)
1080 {
1081 dwLength = 0;
1082 if (RegQueryValueExW(hKey,
1083 NULL,
1084 NULL,
1085 NULL,
1086 NULL,
1087 &dwLength))
1088 {
1089 RegCloseKey(hKey);
1090 return FALSE;
1091 }
1092
1093 *RequiredSize = dwLength / sizeof(WCHAR);
1094 }
1095
1096 dwLength = ClassDescriptionSize * sizeof(WCHAR);
1097 if (RegQueryValueExW(hKey,
1098 NULL,
1099 NULL,
1100 NULL,
1101 (LPBYTE)ClassDescription,
1102 &dwLength))
1103 {
1104 RegCloseKey(hKey);
1105 return FALSE;
1106 }
1107
1108 RegCloseKey(hKey);
1109
1110 return TRUE;
1111 }
1112
1113 /***********************************************************************
1114 * SetupDiGetClassDevsA (SETUPAPI.@)
1115 */
1116 HDEVINFO WINAPI SetupDiGetClassDevsA(
1117 CONST GUID *class,
1118 LPCSTR enumstr,
1119 HWND parent,
1120 DWORD flags)
1121 {
1122 return SetupDiGetClassDevsExA(class, enumstr, parent,
1123 flags, NULL, NULL, NULL);
1124 }
1125
1126 /***********************************************************************
1127 * SetupDiGetClassDevsW (SETUPAPI.@)
1128 */
1129 HDEVINFO WINAPI SetupDiGetClassDevsW(
1130 CONST GUID *class,
1131 LPCWSTR enumstr,
1132 HWND parent,
1133 DWORD flags)
1134 {
1135 return SetupDiGetClassDevsExW(class, enumstr, parent,
1136 flags, NULL, NULL, NULL);
1137 }
1138
1139 /***********************************************************************
1140 * SetupDiGetClassDevsExA (SETUPAPI.@)
1141 */
1142 HDEVINFO WINAPI SetupDiGetClassDevsExA(
1143 CONST GUID *class,
1144 LPCSTR enumstr,
1145 HWND parent,
1146 DWORD flags,
1147 HDEVINFO deviceset,
1148 LPCSTR machine,
1149 PVOID reserved)
1150 {
1151 HDEVINFO ret;
1152 LPWSTR enumstrW = NULL;
1153 LPWSTR machineW = NULL;
1154
1155 if (enumstr)
1156 {
1157 int len = MultiByteToWideChar(CP_ACP, 0, enumstr, -1, NULL, 0);
1158 enumstrW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1159 if (!enumstrW)
1160 {
1161 ret = (HDEVINFO)INVALID_HANDLE_VALUE;
1162 goto end;
1163 }
1164 MultiByteToWideChar(CP_ACP, 0, enumstr, -1, enumstrW, len);
1165 }
1166 if (machine)
1167 {
1168 int len = MultiByteToWideChar(CP_ACP, 0, machine, -1, NULL, 0);
1169 machineW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1170 if (!machineW)
1171 {
1172 ret = (HDEVINFO)INVALID_HANDLE_VALUE;
1173 goto end;
1174 }
1175 MultiByteToWideChar(CP_ACP, 0, machine, -1, machineW, len);
1176 }
1177 ret = SetupDiGetClassDevsExW(class, enumstrW, parent, flags, deviceset, machineW, reserved);
1178
1179 end:
1180 HeapFree(GetProcessHeap(), 0, enumstrW);
1181 HeapFree(GetProcessHeap(), 0, machineW);
1182 return ret;
1183 }
1184
1185 static BOOL
1186 CreateDeviceInfoElement(
1187 IN LPCWSTR InstancePath,
1188 IN LPCGUID pClassGuid,
1189 OUT struct DeviceInfoElement **pDeviceInfo)
1190 {
1191 struct DeviceInfoElement *deviceInfo;
1192
1193 *pDeviceInfo = NULL;
1194
1195 deviceInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(struct DeviceInfoElement) + (wcslen(InstancePath) + 1) * sizeof(WCHAR));
1196 if (!deviceInfo)
1197 {
1198 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1199 return FALSE;
1200 }
1201 wcscpy(deviceInfo->Data, InstancePath);
1202 deviceInfo->DeviceName = deviceInfo->Data;
1203 deviceInfo->UniqueId = wcsrchr(deviceInfo->Data, '\\');
1204 deviceInfo->DeviceDescription = NULL;
1205 memcpy(&deviceInfo->ClassGuid, pClassGuid, sizeof(GUID));
1206 deviceInfo->CreationFlags = 0;
1207 deviceInfo->hwndParent = NULL;
1208 deviceInfo->Flags = 0; /* FIXME */
1209 deviceInfo->FlagsEx = 0; /* FIXME */
1210 deviceInfo->SelectedDriver = NULL;
1211 InitializeListHead(&deviceInfo->DriverListHead);
1212 InitializeListHead(&deviceInfo->InterfaceListHead);
1213
1214 *pDeviceInfo = deviceInfo;
1215 return TRUE;
1216 }
1217
1218 static BOOL
1219 CreateDeviceInterface(
1220 IN struct DeviceInfoElement* deviceInfo,
1221 IN LPCWSTR SymbolicLink,
1222 IN LPCGUID pInterfaceGuid,
1223 OUT struct DeviceInterface **pDeviceInterface)
1224 {
1225 struct DeviceInterface *deviceInterface;
1226
1227 *pDeviceInterface = NULL;
1228
1229 deviceInterface = HeapAlloc(GetProcessHeap(), 0, sizeof(struct DeviceInterface) + (wcslen(SymbolicLink) + 1) * sizeof(WCHAR));
1230 if (!deviceInterface)
1231 {
1232 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1233 return FALSE;
1234 }
1235 deviceInterface->DeviceInfo = deviceInfo;
1236 wcscpy(deviceInterface->SymbolicLink, SymbolicLink);
1237 deviceInterface->Flags = 0; /* FIXME */
1238 memcpy(&deviceInterface->InterfaceClassGuid, pInterfaceGuid, sizeof(GUID));
1239
1240 *pDeviceInterface = deviceInterface;
1241 return TRUE;
1242 }
1243
1244 static LONG SETUP_CreateDevListFromEnumerator(
1245 struct DeviceInfoSet *list,
1246 LPCGUID pClassGuid OPTIONAL,
1247 LPCWSTR Enumerator,
1248 HKEY hEnumeratorKey) /* handle to Enumerator registry key */
1249 {
1250 HKEY hDeviceIdKey, hInstanceIdKey;
1251 WCHAR KeyBuffer[MAX_PATH];
1252 WCHAR InstancePath[MAX_PATH];
1253 LPWSTR pEndOfInstancePath; /* Pointer into InstancePath buffer */
1254 struct DeviceInfoElement *deviceInfo;
1255 DWORD i = 0, j;
1256 DWORD dwLength, dwRegType;
1257 DWORD rc;
1258
1259 /* Enumerate device IDs (subkeys of hEnumeratorKey) */
1260 while (TRUE)
1261 {
1262 dwLength = sizeof(KeyBuffer) / sizeof(KeyBuffer[0]);
1263 rc = RegEnumKeyExW(hEnumeratorKey, i, KeyBuffer, &dwLength, NULL, NULL, NULL, NULL);
1264 if (rc == ERROR_NO_MORE_ITEMS)
1265 break;
1266 if (rc != ERROR_SUCCESS)
1267 return rc;
1268 i++;
1269
1270 /* Open device id sub key */
1271 rc = RegOpenKeyExW(hEnumeratorKey, KeyBuffer, 0, KEY_ENUMERATE_SUB_KEYS, &hDeviceIdKey);
1272 if (rc != ERROR_SUCCESS)
1273 return rc;
1274 wcscpy(InstancePath, Enumerator);
1275 wcscat(InstancePath, L"\\");
1276 wcscat(InstancePath, KeyBuffer);
1277 wcscat(InstancePath, L"\\");
1278 pEndOfInstancePath = &InstancePath[wcslen(InstancePath)];
1279
1280 /* Enumerate instance IDs (subkeys of hDeviceIdKey) */
1281 j = 0;
1282 while (TRUE)
1283 {
1284 GUID KeyGuid;
1285
1286 dwLength = sizeof(KeyBuffer) / sizeof(KeyBuffer[0]);
1287 rc = RegEnumKeyExW(hDeviceIdKey, j, KeyBuffer, &dwLength, NULL, NULL, NULL, NULL);
1288 if (rc == ERROR_NO_MORE_ITEMS)
1289 break;
1290 if (rc != ERROR_SUCCESS)
1291 {
1292 RegCloseKey(hDeviceIdKey);
1293 return rc;
1294 }
1295 j++;
1296
1297 /* Open instance id sub key */
1298 rc = RegOpenKeyExW(hDeviceIdKey, KeyBuffer, 0, KEY_QUERY_VALUE, &hInstanceIdKey);
1299 if (rc != ERROR_SUCCESS)
1300 {
1301 RegCloseKey(hDeviceIdKey);
1302 return rc;
1303 }
1304 *pEndOfInstancePath = '\0';
1305 wcscat(InstancePath, KeyBuffer);
1306
1307 /* Read ClassGUID value */
1308 dwLength = sizeof(KeyBuffer) - sizeof(WCHAR);
1309 rc = RegQueryValueExW(hInstanceIdKey, ClassGUID, NULL, &dwRegType, (LPBYTE)KeyBuffer, &dwLength);
1310 RegCloseKey(hInstanceIdKey);
1311 if (rc == ERROR_FILE_NOT_FOUND)
1312 {
1313 if (pClassGuid)
1314 /* Skip this bad entry as we can't verify it */
1315 continue;
1316 }
1317 else if (rc != ERROR_SUCCESS)
1318 {
1319 RegCloseKey(hDeviceIdKey);
1320 return rc;
1321 }
1322 else if (dwRegType != REG_SZ)
1323 {
1324 RegCloseKey(hDeviceIdKey);
1325 return ERROR_GEN_FAILURE;
1326 }
1327
1328 KeyBuffer[37] = '\0'; /* Replace the } by a NULL character */
1329 if (UuidFromStringW(&KeyBuffer[1], &KeyGuid) != RPC_S_OK)
1330 {
1331 RegCloseKey(hDeviceIdKey);
1332 return GetLastError();
1333 }
1334 if (pClassGuid && !IsEqualIID(&KeyGuid, pClassGuid))
1335 {
1336 /* Skip this entry as it is not the right device class */
1337 continue;
1338 }
1339
1340 /* Add the entry to the list */
1341 if (!CreateDeviceInfoElement(InstancePath, &KeyGuid, &deviceInfo))
1342 {
1343 RegCloseKey(hDeviceIdKey);
1344 return GetLastError();
1345 }
1346 TRACE("Adding '%S' to device info set %p\n", InstancePath, list);
1347 InsertTailList(&list->ListHead, &deviceInfo->ListEntry);
1348 }
1349 RegCloseKey(hDeviceIdKey);
1350 }
1351
1352 return ERROR_SUCCESS;
1353 }
1354
1355 static LONG SETUP_CreateDevList(
1356 struct DeviceInfoSet *list,
1357 PCWSTR MachineName OPTIONAL,
1358 LPGUID class OPTIONAL,
1359 PCWSTR Enumerator OPTIONAL)
1360 {
1361 HKEY HKLM, hEnumKey, hEnumeratorKey;
1362 WCHAR KeyBuffer[MAX_PATH];
1363 DWORD i;
1364 DWORD dwLength;
1365 DWORD rc;
1366
1367 if (IsEqualIID(class, &GUID_NULL))
1368 class = NULL;
1369
1370 /* Open Enum key */
1371 if (MachineName != NULL)
1372 {
1373 rc = RegConnectRegistryW(MachineName, HKEY_LOCAL_MACHINE, &HKLM);
1374 if (rc != ERROR_SUCCESS)
1375 return rc;
1376 }
1377 else
1378 HKLM = HKEY_LOCAL_MACHINE;
1379
1380 rc = RegOpenKeyExW(HKLM,
1381 EnumKeyName,
1382 0,
1383 KEY_ENUMERATE_SUB_KEYS,
1384 &hEnumKey);
1385 if (MachineName != NULL) RegCloseKey(HKLM);
1386 if (rc != ERROR_SUCCESS)
1387 return rc;
1388
1389 /* If enumerator is provided, call directly SETUP_CreateDevListFromEnumerator.
1390 * Else, enumerate all enumerators all call SETUP_CreateDevListFromEnumerator
1391 * for each one.
1392 */
1393 if (Enumerator)
1394 {
1395 rc = RegOpenKeyExW(
1396 hEnumKey,
1397 Enumerator,
1398 0,
1399 KEY_ENUMERATE_SUB_KEYS,
1400 &hEnumeratorKey);
1401 RegCloseKey(hEnumKey);
1402 if (rc != ERROR_SUCCESS)
1403 return rc;
1404 rc = SETUP_CreateDevListFromEnumerator(list, class, Enumerator, hEnumeratorKey);
1405 RegCloseKey(hEnumeratorKey);
1406 return rc;
1407 }
1408 else
1409 {
1410 /* Enumerate enumerators */
1411 i = 0;
1412 while (TRUE)
1413 {
1414 dwLength = sizeof(KeyBuffer) / sizeof(KeyBuffer[0]);
1415 rc = RegEnumKeyExW(hEnumKey, i, KeyBuffer, &dwLength, NULL, NULL, NULL, NULL);
1416 if (rc == ERROR_NO_MORE_ITEMS)
1417 break;
1418 if (rc != ERROR_SUCCESS)
1419 {
1420 RegCloseKey(hEnumKey);
1421 return rc;
1422 }
1423 i++;
1424
1425 /* Open sub key */
1426 rc = RegOpenKeyExW(hEnumKey, KeyBuffer, 0, KEY_ENUMERATE_SUB_KEYS, &hEnumeratorKey);
1427 if (rc != ERROR_SUCCESS)
1428 {
1429 RegCloseKey(hEnumKey);
1430 return rc;
1431 }
1432
1433 /* Call SETUP_CreateDevListFromEnumerator */
1434 rc = SETUP_CreateDevListFromEnumerator(list, class, KeyBuffer, hEnumeratorKey);
1435 RegCloseKey(hEnumeratorKey);
1436 if (rc != ERROR_SUCCESS)
1437 {
1438 RegCloseKey(hEnumKey);
1439 return rc;
1440 }
1441 }
1442 RegCloseKey(hEnumKey);
1443 return ERROR_SUCCESS;
1444 }
1445 }
1446
1447 #ifndef __REACTOS__
1448 static LONG SETUP_CreateSerialDeviceList(
1449 struct DeviceInfoSet *list,
1450 PCWSTR MachineName,
1451 LPGUID InterfaceGuid,
1452 PCWSTR DeviceInstanceW)
1453 {
1454 static const size_t initialSize = 100;
1455 size_t size;
1456 WCHAR buf[initialSize];
1457 LPWSTR devices;
1458 static const WCHAR devicePrefixW[] = { 'C','O','M',0 };
1459 LPWSTR ptr;
1460 struct DeviceInfoElement *deviceInfo;
1461
1462 if (MachineName)
1463 WARN("'MachineName' is ignored on Wine!\n");
1464 if (DeviceInstanceW)
1465 WARN("'DeviceInstanceW' can't be set on Wine!\n");
1466
1467 devices = buf;
1468 size = initialSize;
1469 while (TRUE)
1470 {
1471 if (QueryDosDeviceW(NULL, devices, size) != 0)
1472 break;
1473 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
1474 {
1475 size *= 2;
1476 if (devices != buf)
1477 HeapFree(GetProcessHeap(), 0, devices);
1478 devices = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
1479 if (!devices)
1480 return ERROR_NOT_ENOUGH_MEMORY;
1481 *devices = '\0';
1482 }
1483 else
1484 {
1485 if (devices != buf)
1486 HeapFree(GetProcessHeap(), 0, devices);
1487 return GetLastError();
1488 }
1489 }
1490
1491 /* 'devices' is a MULTI_SZ string */
1492 for (ptr = devices; *ptr; ptr += strlenW(ptr) + 1)
1493 {
1494 if (strncmpW(devicePrefixW, ptr, sizeof(devicePrefixW) / sizeof(devicePrefixW[0]) - 1) == 0)
1495 {
1496 /* We have found a device */
1497 struct DeviceInterface *interfaceInfo;
1498 TRACE("Adding %s to list\n", debugstr_w(ptr));
1499 /* Step 1. Create a device info element */
1500 if (!CreateDeviceInfoElement(ptr, &GUID_SERENUM_BUS_ENUMERATOR, &deviceInfo))
1501 {
1502 if (devices != buf)
1503 HeapFree(GetProcessHeap(), 0, devices);
1504 return GetLastError();
1505 }
1506 InsertTailList(&list->ListHead, &deviceInfo->ListEntry);
1507
1508 /* Step 2. Create an interface list for this element */
1509 if (!CreateDeviceInterface(deviceInfo, ptr, InterfaceGuid, &interfaceInfo))
1510 {
1511 if (devices != buf)
1512 HeapFree(GetProcessHeap(), 0, devices);
1513 return GetLastError();
1514 }
1515 InsertTailList(&deviceInfo->InterfaceListHead, &interfaceInfo->ListEntry);
1516 }
1517 }
1518 if (devices != buf)
1519 HeapFree(GetProcessHeap(), 0, devices);
1520 return ERROR_SUCCESS;
1521 }
1522
1523 #else /* __REACTOS__ */
1524
1525 static LONG SETUP_CreateInterfaceList(
1526 struct DeviceInfoSet *list,
1527 PCWSTR MachineName,
1528 LPGUID InterfaceGuid,
1529 PCWSTR DeviceInstanceW /* OPTIONAL */)
1530 {
1531 HKEY hInterfaceKey; /* HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{GUID} */
1532 HKEY hDeviceInstanceKey; /* HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{GUID}\##?#{InstancePath} */
1533 HKEY hReferenceKey; /* HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{GUID}\##?#{InstancePath}\#{ReferenceString} */
1534 HKEY hEnumKey; /* HKLM\SYSTEM\CurrentControlSet\Enum */
1535 HKEY hKey; /* HKLM\SYSTEM\CurrentControlSet\Enum\{Instance\Path} */
1536 LONG rc;
1537 WCHAR KeyBuffer[max(MAX_PATH, MAX_GUID_STRING_LEN) + 1];
1538 PWSTR InstancePath;
1539 DWORD i, j;
1540 DWORD dwLength, dwInstancePathLength;
1541 DWORD dwRegType;
1542 GUID ClassGuid;
1543 struct DeviceInfoElement *deviceInfo;
1544
1545 /* Open registry key related to this interface */
1546 hInterfaceKey = SetupDiOpenClassRegKeyExW(InterfaceGuid, KEY_ENUMERATE_SUB_KEYS, DIOCR_INTERFACE, MachineName, NULL);
1547 if (hInterfaceKey == INVALID_HANDLE_VALUE)
1548 return GetLastError();
1549
1550 /* Enumerate sub keys of hInterfaceKey */
1551 i = 0;
1552 while (TRUE)
1553 {
1554 dwLength = sizeof(KeyBuffer) / sizeof(KeyBuffer[0]);
1555 rc = RegEnumKeyExW(hInterfaceKey, i, KeyBuffer, &dwLength, NULL, NULL, NULL, NULL);
1556 if (rc == ERROR_NO_MORE_ITEMS)
1557 break;
1558 if (rc != ERROR_SUCCESS)
1559 {
1560 RegCloseKey(hInterfaceKey);
1561 return rc;
1562 }
1563 i++;
1564
1565 /* Open sub key */
1566 rc = RegOpenKeyExW(hInterfaceKey, KeyBuffer, 0, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, &hDeviceInstanceKey);
1567 if (rc != ERROR_SUCCESS)
1568 {
1569 RegCloseKey(hInterfaceKey);
1570 return rc;
1571 }
1572
1573 /* Read DeviceInstance */
1574 rc = RegQueryValueExW(hDeviceInstanceKey, DeviceInstance, NULL, &dwRegType, NULL, &dwInstancePathLength);
1575 if (rc != ERROR_SUCCESS )
1576 {
1577 RegCloseKey(hDeviceInstanceKey);
1578 RegCloseKey(hInterfaceKey);
1579 return rc;
1580 }
1581 if (dwRegType != REG_SZ)
1582 {
1583 RegCloseKey(hDeviceInstanceKey);
1584 RegCloseKey(hInterfaceKey);
1585 return ERROR_GEN_FAILURE;
1586 }
1587 InstancePath = HeapAlloc(GetProcessHeap(), 0, dwInstancePathLength + sizeof(WCHAR));
1588 if (!InstancePath)
1589 {
1590 RegCloseKey(hDeviceInstanceKey);
1591 RegCloseKey(hInterfaceKey);
1592 return ERROR_NOT_ENOUGH_MEMORY;
1593 }
1594 rc = RegQueryValueExW(hDeviceInstanceKey, DeviceInstance, NULL, NULL, (LPBYTE)InstancePath, &dwInstancePathLength);
1595 if (rc != ERROR_SUCCESS)
1596 {
1597 HeapFree(GetProcessHeap(), 0, InstancePath);
1598 RegCloseKey(hDeviceInstanceKey);
1599 RegCloseKey(hInterfaceKey);
1600 return rc;
1601 }
1602 InstancePath[dwInstancePathLength / sizeof(WCHAR)] = '\0';
1603 TRACE("DeviceInstance %s\n", debugstr_w(InstancePath));
1604
1605 if (DeviceInstanceW)
1606 {
1607 /* Check if device enumerator is not the right one */
1608 if (wcscmp(DeviceInstanceW, InstancePath) != 0)
1609 {
1610 HeapFree(GetProcessHeap(), 0, InstancePath);
1611 RegCloseKey(hDeviceInstanceKey);
1612 continue;
1613 }
1614 }
1615
1616 /* Find class GUID associated to the device instance */
1617 rc = RegOpenKeyExW(
1618 HKEY_LOCAL_MACHINE,
1619 EnumKeyName,
1620 0, /* Options */
1621 KEY_ENUMERATE_SUB_KEYS,
1622 &hEnumKey);
1623 if (rc != ERROR_SUCCESS)
1624 {
1625 HeapFree(GetProcessHeap(), 0, InstancePath);
1626 RegCloseKey(hDeviceInstanceKey);
1627 RegCloseKey(hInterfaceKey);
1628 return rc;
1629 }
1630 rc = RegOpenKeyExW(
1631 hEnumKey,
1632 InstancePath,
1633 0, /* Options */
1634 KEY_QUERY_VALUE,
1635 &hKey);
1636 RegCloseKey(hEnumKey);
1637 if (rc != ERROR_SUCCESS)
1638 {
1639 HeapFree(GetProcessHeap(), 0, InstancePath);
1640 RegCloseKey(hDeviceInstanceKey);
1641 RegCloseKey(hInterfaceKey);
1642 return rc;
1643 }
1644 dwLength = sizeof(KeyBuffer) - sizeof(WCHAR);
1645 rc = RegQueryValueExW(hKey, ClassGUID, NULL, NULL, (LPBYTE)KeyBuffer, &dwLength);
1646 RegCloseKey(hKey);
1647 if (rc != ERROR_SUCCESS)
1648 {
1649 HeapFree(GetProcessHeap(), 0, InstancePath);
1650 RegCloseKey(hDeviceInstanceKey);
1651 RegCloseKey(hInterfaceKey);
1652 return rc;
1653 }
1654 KeyBuffer[dwLength / sizeof(WCHAR)] = '\0';
1655 KeyBuffer[37] = '\0'; /* Replace the } by a NULL character */
1656 if (UuidFromStringW(&KeyBuffer[1], &ClassGuid) != RPC_S_OK)
1657 {
1658 HeapFree(GetProcessHeap(), 0, InstancePath);
1659 RegCloseKey(hDeviceInstanceKey);
1660 RegCloseKey(hInterfaceKey);
1661 return ERROR_GEN_FAILURE;
1662 }
1663 TRACE("ClassGUID %s\n", debugstr_guid(&ClassGuid));
1664
1665 /* If current device doesn't match the list GUID (if any), skip this entry */
1666 if (!IsEqualIID(&list->ClassGuid, &GUID_NULL) && !IsEqualIID(&list->ClassGuid, &ClassGuid))
1667 {
1668 HeapFree(GetProcessHeap(), 0, InstancePath);
1669 RegCloseKey(hDeviceInstanceKey);
1670 continue;
1671 }
1672
1673 /* Enumerate subkeys of hDeviceInstanceKey (ie "#ReferenceString" in IoRegisterDeviceInterface). Skip entries that don't start with '#' */
1674 j = 0;
1675 while (TRUE)
1676 {
1677 LPWSTR pSymbolicLink;
1678 struct DeviceInterface *interfaceInfo;
1679
1680 dwLength = sizeof(KeyBuffer) / sizeof(KeyBuffer[0]);
1681 rc = RegEnumKeyExW(hDeviceInstanceKey, j, KeyBuffer, &dwLength, NULL, NULL, NULL, NULL);
1682 if (rc == ERROR_NO_MORE_ITEMS)
1683 break;
1684 if (rc != ERROR_SUCCESS)
1685 {
1686 HeapFree(GetProcessHeap(), 0, InstancePath);
1687 RegCloseKey(hDeviceInstanceKey);
1688 RegCloseKey(hInterfaceKey);
1689 return rc;
1690 }
1691 j++;
1692 if (KeyBuffer[0] != '#')
1693 /* This entry doesn't represent an interesting entry */
1694 continue;
1695
1696 /* Open sub key */
1697 rc = RegOpenKeyExW(hDeviceInstanceKey, KeyBuffer, 0, KEY_QUERY_VALUE, &hReferenceKey);
1698 if (rc != ERROR_SUCCESS)
1699 {
1700 RegCloseKey(hDeviceInstanceKey);
1701 RegCloseKey(hInterfaceKey);
1702 return rc;
1703 }
1704
1705 /* Read SymbolicLink value */
1706 rc = RegQueryValueExW(hReferenceKey, SymbolicLink, NULL, &dwRegType, NULL, &dwLength);
1707 if (rc != ERROR_SUCCESS )
1708 {
1709 RegCloseKey(hReferenceKey);
1710 RegCloseKey(hDeviceInstanceKey);
1711 RegCloseKey(hInterfaceKey);
1712 return rc;
1713 }
1714 if (dwRegType != REG_SZ)
1715 {
1716 RegCloseKey(hReferenceKey);
1717 RegCloseKey(hDeviceInstanceKey);
1718 RegCloseKey(hInterfaceKey);
1719 return ERROR_GEN_FAILURE;
1720 }
1721
1722 /* We have found a device */
1723 /* Step 1. Create a device info element */
1724 if (!CreateDeviceInfoElement(InstancePath, &ClassGuid, &deviceInfo))
1725 {
1726 RegCloseKey(hReferenceKey);
1727 RegCloseKey(hDeviceInstanceKey);
1728 RegCloseKey(hInterfaceKey);
1729 return GetLastError();
1730 }
1731 TRACE("Adding device %s to list\n", debugstr_w(InstancePath));
1732 InsertTailList(&list->ListHead, &deviceInfo->ListEntry);
1733
1734 /* Step 2. Create an interface list for this element */
1735 pSymbolicLink = HeapAlloc(GetProcessHeap(), 0, (dwLength + 1) * sizeof(WCHAR));
1736 if (!pSymbolicLink)
1737 {
1738 RegCloseKey(hReferenceKey);
1739 RegCloseKey(hDeviceInstanceKey);
1740 RegCloseKey(hInterfaceKey);
1741 return ERROR_NOT_ENOUGH_MEMORY;
1742 }
1743 rc = RegQueryValueExW(hReferenceKey, SymbolicLink, NULL, NULL, (LPBYTE)pSymbolicLink, &dwLength);
1744 pSymbolicLink[dwLength / sizeof(WCHAR)] = '\0';
1745 RegCloseKey(hReferenceKey);
1746 if (rc != ERROR_SUCCESS)
1747 {
1748 HeapFree(GetProcessHeap(), 0, pSymbolicLink);
1749 RegCloseKey(hDeviceInstanceKey);
1750 RegCloseKey(hInterfaceKey);
1751 return rc;
1752 }
1753 if (!CreateDeviceInterface(deviceInfo, pSymbolicLink, InterfaceGuid, &interfaceInfo))
1754 {
1755 HeapFree(GetProcessHeap(), 0, pSymbolicLink);
1756 RegCloseKey(hDeviceInstanceKey);
1757 RegCloseKey(hInterfaceKey);
1758 return GetLastError();
1759 }
1760 TRACE("Adding interface %s to list\n", debugstr_w(pSymbolicLink));
1761 HeapFree(GetProcessHeap(), 0, pSymbolicLink);
1762 InsertTailList(&deviceInfo->InterfaceListHead, &interfaceInfo->ListEntry);
1763 }
1764 RegCloseKey(hDeviceInstanceKey);
1765 }
1766 RegCloseKey(hInterfaceKey);
1767 return ERROR_SUCCESS;
1768 }
1769 #endif /* __REACTOS__ */
1770
1771 /***********************************************************************
1772 * SetupDiGetClassDevsExW (SETUPAPI.@)
1773 */
1774 HDEVINFO WINAPI SetupDiGetClassDevsExW(
1775 CONST GUID *class,
1776 LPCWSTR enumstr,
1777 HWND parent,
1778 DWORD flags,
1779 HDEVINFO deviceset,
1780 LPCWSTR machine,
1781 PVOID reserved)
1782 {
1783 HDEVINFO hDeviceInfo = INVALID_HANDLE_VALUE;
1784 struct DeviceInfoSet *list;
1785 LPGUID pClassGuid;
1786 LONG rc;
1787
1788 TRACE("%s %s %p 0x%08lx %p %s %p\n", debugstr_guid(class), debugstr_w(enumstr),
1789 parent, flags, deviceset, debugstr_w(machine), reserved);
1790
1791 /* Create the deviceset if not set */
1792 if (deviceset)
1793 {
1794 list = (struct DeviceInfoSet *)deviceset;
1795 if (list->magic != SETUP_DEV_INFO_SET_MAGIC)
1796 {
1797 SetLastError(ERROR_INVALID_HANDLE);
1798 return INVALID_HANDLE_VALUE;
1799 }
1800 hDeviceInfo = deviceset;
1801 }
1802 else
1803 {
1804 hDeviceInfo = SetupDiCreateDeviceInfoListExW(
1805 flags & DIGCF_DEVICEINTERFACE ? NULL : class,
1806 NULL, machine, NULL);
1807 if (hDeviceInfo == INVALID_HANDLE_VALUE)
1808 return INVALID_HANDLE_VALUE;
1809 list = (struct DeviceInfoSet *)hDeviceInfo;
1810 }
1811
1812 if (IsEqualIID(&list->ClassGuid, &GUID_NULL))
1813 pClassGuid = NULL;
1814 else
1815 pClassGuid = &list->ClassGuid;
1816
1817 if (flags & DIGCF_PRESENT)
1818 FIXME(": flag DIGCF_PRESENT ignored\n");
1819 if (flags & DIGCF_PROFILE)
1820 FIXME(": flag DIGCF_PROFILE ignored\n");
1821
1822 if (flags & DIGCF_ALLCLASSES)
1823 {
1824 rc = SETUP_CreateDevList(list, machine, pClassGuid, enumstr);
1825 if (rc != ERROR_SUCCESS)
1826 {
1827 SetLastError(rc);
1828 if (!deviceset)
1829 SetupDiDestroyDeviceInfoList(hDeviceInfo);
1830 return INVALID_HANDLE_VALUE;
1831 }
1832 return hDeviceInfo;
1833 }
1834 else if (flags & DIGCF_DEVICEINTERFACE)
1835 {
1836 if (class == NULL)
1837 {
1838 SetLastError(ERROR_INVALID_PARAMETER);
1839 if (!deviceset)
1840 SetupDiDestroyDeviceInfoList(hDeviceInfo);
1841 return INVALID_HANDLE_VALUE;
1842 }
1843
1844 #ifndef __REACTOS__
1845 /* Special case: find serial ports by calling QueryDosDevice */
1846 if (IsEqualIID(class, &GUID_DEVINTERFACE_COMPORT))
1847 rc = SETUP_CreateSerialDeviceList(list, machine, (LPGUID)class, enumstr);
1848 if (IsEqualIID(class, &GUID_DEVINTERFACE_SERENUM_BUS_ENUMERATOR))
1849 rc = SETUP_CreateSerialDeviceList(list, machine, (LPGUID)class, enumstr);
1850 else
1851 {
1852 ERR("Wine can only enumerate serial devices at the moment!\n");
1853 rc = ERROR_INVALID_PARAMETER;
1854 }
1855 #else /* __REACTOS__ */
1856 rc = SETUP_CreateInterfaceList(list, machine, (LPGUID)class, enumstr);
1857 #endif /* __REACTOS__ */
1858 if (rc != ERROR_SUCCESS)
1859 {
1860 SetLastError(rc);
1861 if (!deviceset)
1862 SetupDiDestroyDeviceInfoList(hDeviceInfo);
1863 return INVALID_HANDLE_VALUE;
1864 }
1865 return hDeviceInfo;
1866 }
1867 else
1868 {
1869 rc = SETUP_CreateDevList(list, machine, (LPGUID)class, enumstr);
1870 if (rc != ERROR_SUCCESS)
1871 {
1872 SetLastError(rc);
1873 if (!deviceset)
1874 SetupDiDestroyDeviceInfoList(hDeviceInfo);
1875 return INVALID_HANDLE_VALUE;
1876 }
1877 return hDeviceInfo;
1878 }
1879 }
1880
1881 /***********************************************************************
1882 * SetupDiEnumDeviceInterfaces (SETUPAPI.@)
1883 */
1884 BOOL WINAPI SetupDiEnumDeviceInterfaces(
1885 HDEVINFO DeviceInfoSet,
1886 PSP_DEVINFO_DATA DeviceInfoData,
1887 CONST GUID * InterfaceClassGuid,
1888 DWORD MemberIndex,
1889 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
1890 {
1891 BOOL ret = FALSE;
1892
1893 TRACE("%p, %p, %s, %ld, %p\n", DeviceInfoSet, DeviceInfoData,
1894 debugstr_guid(InterfaceClassGuid), MemberIndex, DeviceInterfaceData);
1895
1896 if (!DeviceInterfaceData)
1897 SetLastError(ERROR_INVALID_PARAMETER);
1898 else if (DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA))
1899 SetLastError(ERROR_INVALID_USER_BUFFER);
1900 else if (DeviceInfoSet && DeviceInfoSet != (HDEVINFO)INVALID_HANDLE_VALUE)
1901 {
1902 struct DeviceInfoSet *list = (struct DeviceInfoSet *)DeviceInfoSet;
1903
1904 if (list->magic == SETUP_DEV_INFO_SET_MAGIC)
1905 {
1906 PLIST_ENTRY ItemList = list->ListHead.Flink;
1907 BOOL Found = FALSE;
1908 while (ItemList != &list->ListHead && !Found)
1909 {
1910 PLIST_ENTRY InterfaceListEntry;
1911 struct DeviceInfoElement *DevInfo = (struct DeviceInfoElement *)ItemList;
1912 if (DeviceInfoData && (struct DeviceInfoElement *)DeviceInfoData->Reserved != DevInfo)
1913 {
1914 /* We are not searching for this element */
1915 ItemList = ItemList->Flink;
1916 continue;
1917 }
1918 InterfaceListEntry = DevInfo->InterfaceListHead.Flink;
1919 while (InterfaceListEntry != &DevInfo->InterfaceListHead && !Found)
1920 {
1921 struct DeviceInterface *DevItf = (struct DeviceInterface *)InterfaceListEntry;
1922 if (!IsEqualIID(&DevItf->InterfaceClassGuid, InterfaceClassGuid))
1923 {
1924 InterfaceListEntry = InterfaceListEntry->Flink;
1925 continue;
1926 }
1927 if (MemberIndex-- == 0)
1928 {
1929 /* return this item */
1930 memcpy(&DeviceInterfaceData->InterfaceClassGuid,
1931 &DevItf->InterfaceClassGuid,
1932 sizeof(GUID));
1933 DeviceInterfaceData->Flags = 0; /* FIXME */
1934 /* Note: this appears to be dangerous, passing a private
1935 * pointer a heap-allocated datum to the caller. However, the
1936 * expected lifetime of the device data is the same as the
1937 * HDEVINFO; once that is closed, the data are no longer valid.
1938 */
1939 DeviceInterfaceData->Reserved = (ULONG_PTR)DevItf;
1940 Found = TRUE;
1941 }
1942 InterfaceListEntry = InterfaceListEntry->Flink;
1943 }
1944 ItemList = ItemList->Flink;
1945 }
1946 if (!Found)
1947 SetLastError(ERROR_NO_MORE_ITEMS);
1948 else
1949 ret = TRUE;
1950 }
1951 else
1952 SetLastError(ERROR_INVALID_HANDLE);
1953 }
1954 else
1955 SetLastError(ERROR_INVALID_HANDLE);
1956 return ret;
1957 }
1958
1959 /***********************************************************************
1960 * SetupDiDestroyDeviceInfoList (SETUPAPI.@)
1961 */
1962 BOOL WINAPI SetupDiDestroyDeviceInfoList(HDEVINFO devinfo)
1963 {
1964 BOOL ret = FALSE;
1965
1966 TRACE("%p\n", devinfo);
1967 if (devinfo && devinfo != (HDEVINFO)INVALID_HANDLE_VALUE)
1968 {
1969 struct DeviceInfoSet *list = (struct DeviceInfoSet *)devinfo;
1970
1971 if (list->magic == SETUP_DEV_INFO_SET_MAGIC)
1972 {
1973 PLIST_ENTRY ListEntry, InterfaceEntry;
1974 struct DeviceInfoElement *deviceInfo;
1975 while (!IsListEmpty(&list->ListHead))
1976 {
1977 ListEntry = RemoveHeadList(&list->ListHead);
1978 deviceInfo = (struct DeviceInfoElement *)ListEntry;
1979 while (!IsListEmpty(&deviceInfo->InterfaceListHead))
1980 {
1981 InterfaceEntry = RemoveHeadList(&deviceInfo->InterfaceListHead);
1982 HeapFree(GetProcessHeap(), 0, InterfaceEntry);
1983 }
1984 HeapFree(GetProcessHeap(), 0, ListEntry);
1985 }
1986 if (list->HKLM != HKEY_LOCAL_MACHINE)
1987 RegCloseKey(list->HKLM);
1988 HeapFree(GetProcessHeap(), 0, list);
1989 ret = TRUE;
1990 }
1991 else
1992 SetLastError(ERROR_INVALID_HANDLE);
1993 }
1994 else
1995 SetLastError(ERROR_INVALID_HANDLE);
1996
1997 TRACE("Returning %d\n", ret);
1998 return ret;
1999 }
2000
2001 /***********************************************************************
2002 * SetupDiGetDeviceInterfaceDetailA (SETUPAPI.@)
2003 */
2004 BOOL WINAPI SetupDiGetDeviceInterfaceDetailA(
2005 HDEVINFO DeviceInfoSet,
2006 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
2007 PSP_DEVICE_INTERFACE_DETAIL_DATA_A DeviceInterfaceDetailData,
2008 DWORD DeviceInterfaceDetailDataSize,
2009 PDWORD RequiredSize,
2010 PSP_DEVINFO_DATA DeviceInfoData)
2011 {
2012 PSP_DEVICE_INTERFACE_DETAIL_DATA_W DeviceInterfaceDetailDataW = NULL;
2013 DWORD sizeW = 0, sizeA;
2014 BOOL ret = FALSE;
2015
2016 TRACE("(%p, %p, %p, %ld, %p, %p)\n", DeviceInfoSet,
2017 DeviceInterfaceData, DeviceInterfaceDetailData,
2018 DeviceInterfaceDetailDataSize, RequiredSize, DeviceInfoData);
2019
2020 if (DeviceInterfaceDetailData->cbSize != sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A))
2021 SetLastError(ERROR_INVALID_USER_BUFFER);
2022 else if (DeviceInterfaceDetailData == NULL && DeviceInterfaceDetailDataSize != 0)
2023 SetLastError(ERROR_INVALID_PARAMETER);
2024 else if (DeviceInterfaceDetailData != NULL && DeviceInterfaceDetailDataSize < FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath) + 1)
2025 SetLastError(ERROR_INVALID_PARAMETER);
2026 else
2027 {
2028 if (DeviceInterfaceDetailData != NULL)
2029 {
2030 sizeW = FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath)
2031 + (DeviceInterfaceDetailDataSize - FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath)) * sizeof(WCHAR);
2032 DeviceInterfaceDetailDataW = (PSP_DEVICE_INTERFACE_DETAIL_DATA_W)HeapAlloc(GetProcessHeap(), 0, sizeW);
2033 if (!DeviceInterfaceDetailDataW)
2034 {
2035 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2036 }
2037 }
2038 if (!DeviceInterfaceDetailData || (DeviceInterfaceDetailData && DeviceInterfaceDetailDataW))
2039 {
2040 DeviceInterfaceDetailDataW->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W);
2041 ret = SetupDiGetDeviceInterfaceDetailW(
2042 DeviceInfoSet,
2043 DeviceInterfaceData,
2044 DeviceInterfaceDetailDataW,
2045 sizeW,
2046 &sizeW,
2047 DeviceInfoData);
2048 sizeA = (sizeW - FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath)) / sizeof(WCHAR)
2049 + FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath);
2050 if (RequiredSize)
2051 *RequiredSize = sizeA;
2052 if (ret && DeviceInterfaceDetailData && DeviceInterfaceDetailDataSize <= sizeA)
2053 {
2054 if (!WideCharToMultiByte(
2055 CP_ACP, 0,
2056 DeviceInterfaceDetailDataW->DevicePath, -1,
2057 DeviceInterfaceDetailData->DevicePath, DeviceInterfaceDetailDataSize - FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath),
2058 NULL, NULL))
2059 {
2060 ret = FALSE;
2061 }
2062 }
2063 }
2064 HeapFree(GetProcessHeap(), 0, DeviceInterfaceDetailDataW);
2065 }
2066
2067 TRACE("Returning %d\n", ret);
2068 return ret;
2069 }
2070
2071 /***********************************************************************
2072 * SetupDiGetDeviceInterfaceDetailW (SETUPAPI.@)
2073 */
2074 BOOL WINAPI SetupDiGetDeviceInterfaceDetailW(
2075 HDEVINFO DeviceInfoSet,
2076 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
2077 PSP_DEVICE_INTERFACE_DETAIL_DATA_W DeviceInterfaceDetailData,
2078 DWORD DeviceInterfaceDetailDataSize,
2079 PDWORD RequiredSize,
2080 PSP_DEVINFO_DATA DeviceInfoData)
2081 {
2082 BOOL ret = FALSE;
2083
2084 TRACE("(%p, %p, %p, %ld, %p, %p): stub\n", DeviceInfoSet,
2085 DeviceInterfaceData, DeviceInterfaceDetailData,
2086 DeviceInterfaceDetailDataSize, RequiredSize, DeviceInfoData);
2087
2088 if (!DeviceInfoSet || !DeviceInterfaceData)
2089 SetLastError(ERROR_INVALID_PARAMETER);
2090 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
2091 SetLastError(ERROR_INVALID_HANDLE);
2092 else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
2093 SetLastError(ERROR_INVALID_HANDLE);
2094 else if (DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA))
2095 SetLastError(ERROR_INVALID_USER_BUFFER);
2096 else if (DeviceInterfaceDetailData->cbSize != sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W))
2097 SetLastError(ERROR_INVALID_USER_BUFFER);
2098 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
2099 SetLastError(ERROR_INVALID_USER_BUFFER);
2100 else if (DeviceInterfaceDetailData == NULL && DeviceInterfaceDetailDataSize != 0)
2101 SetLastError(ERROR_INVALID_PARAMETER);
2102 else if (DeviceInterfaceDetailData != NULL && DeviceInterfaceDetailDataSize < FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath) + sizeof(WCHAR))
2103 SetLastError(ERROR_INVALID_PARAMETER);
2104 else
2105 {
2106 struct DeviceInterface *deviceInterface = (struct DeviceInterface *)DeviceInterfaceData->Reserved;
2107 LPCWSTR devName = deviceInterface->SymbolicLink;
2108 DWORD sizeRequired = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W) +
2109 (lstrlenW(devName) + 1) * sizeof(WCHAR);
2110
2111 if (sizeRequired > DeviceInterfaceDetailDataSize)
2112 {
2113 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2114 if (RequiredSize)
2115 *RequiredSize = sizeRequired;
2116 }
2117 else
2118 {
2119 wcscpy(DeviceInterfaceDetailData->DevicePath, devName);
2120 TRACE("DevicePath is %s\n", debugstr_w(DeviceInterfaceDetailData->DevicePath));
2121 if (DeviceInfoData)
2122 {
2123 memcpy(&DeviceInfoData->ClassGuid,
2124 &deviceInterface->DeviceInfo->ClassGuid,
2125 sizeof(GUID));
2126 DeviceInfoData->DevInst = 0; /* FIXME */
2127 /* Note: this appears to be dangerous, passing a private
2128 * pointer a heap-allocated datum to the caller. However, the
2129 * expected lifetime of the device data is the same as the
2130 * HDEVINFO; once that is closed, the data are no longer valid.
2131 */
2132 DeviceInfoData->Reserved = (ULONG_PTR)deviceInterface->DeviceInfo;
2133 }
2134 ret = TRUE;
2135 }
2136 }
2137
2138 TRACE("Returning %d\n", ret);
2139 return ret;
2140 }
2141
2142 /***********************************************************************
2143 * SetupDiGetDeviceRegistryPropertyA (SETUPAPI.@)
2144 */
2145 BOOL WINAPI SetupDiGetDeviceRegistryPropertyA(
2146 HDEVINFO devinfo,
2147 PSP_DEVINFO_DATA DeviceInfoData,
2148 DWORD Property,
2149 PDWORD PropertyRegDataType,
2150 PBYTE PropertyBuffer,
2151 DWORD PropertyBufferSize,
2152 PDWORD RequiredSize)
2153 {
2154 BOOL bResult;
2155 BOOL bIsStringProperty;
2156 DWORD RegType;
2157 DWORD RequiredSizeA, RequiredSizeW;
2158 DWORD PropertyBufferSizeW;
2159 PBYTE PropertyBufferW;
2160
2161 TRACE("%p %p %ld %p %p %ld %p\n", devinfo, DeviceInfoData,
2162 Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize,
2163 RequiredSize);
2164
2165 PropertyBufferSizeW = PropertyBufferSize * 2;
2166 PropertyBufferW = HeapAlloc(GetProcessHeap(), 0, PropertyBufferSizeW);
2167
2168 bResult = SetupDiGetDeviceRegistryPropertyW(
2169 devinfo,
2170 DeviceInfoData,
2171 Property,
2172 &RegType,
2173 PropertyBufferW,
2174 PropertyBufferSizeW,
2175 &RequiredSizeW);
2176
2177 if (bResult || GetLastError() == ERROR_MORE_DATA)
2178 {
2179 bIsStringProperty = (RegType == REG_SZ || RegType == REG_MULTI_SZ || RegType == REG_EXPAND_SZ);
2180
2181 if (bIsStringProperty)
2182 RequiredSizeA = RequiredSizeW / sizeof(WCHAR);
2183 else
2184 RequiredSizeA = RequiredSizeW;
2185 if (RequiredSize)
2186 *RequiredSize = RequiredSizeA;
2187 if (PropertyRegDataType)
2188 *PropertyRegDataType = RegType;
2189 }
2190
2191 if (!bResult)
2192 {
2193 HeapFree(GetProcessHeap(), 0, PropertyBufferW);
2194 return bResult;
2195 }
2196
2197 if (RequiredSizeA <= PropertyBufferSize)
2198 {
2199 if (bIsStringProperty && PropertyBufferSize > 0)
2200 {
2201 if (WideCharToMultiByte(CP_ACP, 0, (LPWSTR)PropertyBufferW, RequiredSizeW / sizeof(WCHAR), (LPSTR)PropertyBuffer, PropertyBufferSize, NULL, NULL) == 0)
2202 {
2203 /* Last error is already set by WideCharToMultiByte */
2204 bResult = FALSE;
2205 }
2206 }
2207 else
2208 memcpy(PropertyBuffer, PropertyBufferW, RequiredSizeA);
2209 }
2210 else
2211 {
2212 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2213 bResult = FALSE;
2214 }
2215
2216 HeapFree(GetProcessHeap(), 0, PropertyBufferW);
2217 return bResult;
2218 }
2219
2220 /***********************************************************************
2221 * SetupDiGetDeviceRegistryPropertyW (SETUPAPI.@)
2222 */
2223 BOOL WINAPI SetupDiGetDeviceRegistryPropertyW(
2224 HDEVINFO DeviceInfoSet,
2225 PSP_DEVINFO_DATA DeviceInfoData,
2226 DWORD Property,
2227 PDWORD PropertyRegDataType,
2228 PBYTE PropertyBuffer,
2229 DWORD PropertyBufferSize,
2230 PDWORD RequiredSize)
2231 {
2232 HKEY hEnumKey, hKey;
2233 DWORD rc;
2234 BOOL ret = FALSE;
2235
2236 TRACE("%p %p %ld %p %p %ld %p\n", DeviceInfoSet, DeviceInfoData,
2237 Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize,
2238 RequiredSize);
2239
2240 if (!DeviceInfoSet || DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
2241 SetLastError(ERROR_INVALID_HANDLE);
2242 else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
2243 SetLastError(ERROR_INVALID_HANDLE);
2244 else if (!DeviceInfoData)
2245 SetLastError(ERROR_INVALID_PARAMETER);
2246 else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
2247 SetLastError(ERROR_INVALID_USER_BUFFER);
2248 else if (Property >= SPDRP_MAXIMUM_PROPERTY)
2249 SetLastError(ERROR_INVALID_PARAMETER);
2250 else
2251 {
2252 struct DeviceInfoSet *list = (struct DeviceInfoSet *)DeviceInfoSet;
2253 struct DeviceInfoElement *DevInfo = (struct DeviceInfoElement *)DeviceInfoData->Reserved;
2254
2255 switch (Property)
2256 {
2257 case SPDRP_CAPABILITIES:
2258 case SPDRP_CLASS:
2259 case SPDRP_CLASSGUID:
2260 case SPDRP_COMPATIBLEIDS:
2261 case SPDRP_CONFIGFLAGS:
2262 case SPDRP_DEVICEDESC:
2263 case SPDRP_DRIVER:
2264 case SPDRP_FRIENDLYNAME:
2265 case SPDRP_HARDWAREID:
2266 case SPDRP_LOCATION_INFORMATION:
2267 case SPDRP_LOWERFILTERS:
2268 case SPDRP_MFG:
2269 case SPDRP_SECURITY:
2270 case SPDRP_SERVICE:
2271 case SPDRP_UI_NUMBER:
2272 case SPDRP_UPPERFILTERS:
2273 {
2274 LPCWSTR RegistryPropertyName;
2275 DWORD BufferSize;
2276
2277 switch (Property)
2278 {
2279 case SPDRP_CAPABILITIES:
2280 RegistryPropertyName = L"Capabilities"; break;
2281 case SPDRP_CLASS:
2282 RegistryPropertyName = L"Class"; break;
2283 case SPDRP_CLASSGUID:
2284 RegistryPropertyName = L"ClassGUID"; break;
2285 case SPDRP_COMPATIBLEIDS:
2286 RegistryPropertyName = L"CompatibleIDs"; break;
2287 case SPDRP_CONFIGFLAGS:
2288 RegistryPropertyName = L"ConfigFlags"; break;
2289 case SPDRP_DEVICEDESC:
2290 RegistryPropertyName = L"DeviceDesc"; break;
2291 case SPDRP_DRIVER:
2292 RegistryPropertyName = L"Driver"; break;
2293 case SPDRP_FRIENDLYNAME:
2294 RegistryPropertyName = L"FriendlyName"; break;
2295 case SPDRP_HARDWAREID:
2296 RegistryPropertyName = L"HardwareID"; break;
2297 case SPDRP_LOCATION_INFORMATION:
2298 RegistryPropertyName = L"LocationInformation"; break;
2299 case SPDRP_LOWERFILTERS:
2300 RegistryPropertyName = L"LowerFilters"; break;
2301 case SPDRP_MFG:
2302 RegistryPropertyName = L"Mfg"; break;
2303 case SPDRP_SECURITY:
2304 RegistryPropertyName = L"Security"; break;
2305 case SPDRP_SERVICE:
2306 RegistryPropertyName = L"Service"; break;
2307 case SPDRP_UI_NUMBER:
2308 RegistryPropertyName = L"UINumber"; break;
2309 case SPDRP_UPPERFILTERS:
2310 RegistryPropertyName = L"UpperFilters"; break;
2311 default:
2312 /* Should not happen */
2313 RegistryPropertyName = NULL; break;
2314 }
2315
2316 /* Open registry key name */
2317 rc = RegOpenKeyExW(
2318 list->HKLM,
2319 EnumKeyName,
2320 0, /* Options */
2321 KEY_ENUMERATE_SUB_KEYS,
2322 &hEnumKey);
2323 if (rc != ERROR_SUCCESS)
2324 {
2325 SetLastError(rc);
2326 break;
2327 }
2328 rc = RegOpenKeyExW(
2329 hEnumKey,
2330 DevInfo->Data,
2331 0, /* Options */
2332 KEY_QUERY_VALUE,
2333 &hKey);
2334 RegCloseKey(hEnumKey);
2335 if (rc != ERROR_SUCCESS)
2336 {
2337 SetLastError(rc);
2338 break;
2339 }
2340 /* Read registry entry */
2341 BufferSize = PropertyBufferSize;
2342 rc = RegQueryValueExW(
2343 hKey,
2344 RegistryPropertyName,
2345 NULL, /* Reserved */
2346 PropertyRegDataType,
2347 PropertyBuffer,
2348 &BufferSize);
2349 if (RequiredSize)
2350 *RequiredSize = BufferSize;
2351 if (rc == ERROR_SUCCESS)
2352 ret = TRUE;
2353 else
2354 SetLastError(rc);
2355 RegCloseKey(hKey);
2356 break;
2357 }
2358
2359 case SPDRP_PHYSICAL_DEVICE_OBJECT_NAME:
2360 {
2361 DWORD required = (wcslen(DevInfo->Data) + 1) * sizeof(WCHAR);
2362
2363 if (PropertyRegDataType)
2364 *PropertyRegDataType = REG_SZ;
2365 if (RequiredSize)
2366 *RequiredSize = required;
2367 if (PropertyBufferSize >= required)
2368 {
2369 wcscpy((LPWSTR)PropertyBuffer, DevInfo->Data);
2370 ret = TRUE;
2371 }
2372 else
2373 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2374 break;
2375 }
2376
2377 /*case SPDRP_BUSTYPEGUID:
2378 case SPDRP_LEGACYBUSTYPE:
2379 case SPDRP_BUSNUMBER:
2380 case SPDRP_ENUMERATOR_NAME:
2381 case SPDRP_SECURITY_SDS:
2382 case SPDRP_DEVTYPE:
2383 case SPDRP_EXCLUSIVE:
2384 case SPDRP_CHARACTERISTICS:
2385 case SPDRP_ADDRESS:
2386 case SPDRP_UI_NUMBER_DESC_FORMAT:
2387 case SPDRP_DEVICE_POWER_DATA:*/
2388 #if (WINVER >= 0x501)
2389 /*case SPDRP_REMOVAL_POLICY:
2390 case SPDRP_REMOVAL_POLICY_HW_DEFAULT:
2391 case SPDRP_REMOVAL_POLICY_OVERRIDE:
2392 case SPDRP_INSTALL_STATE:*/
2393 #endif
2394
2395 default:
2396 {
2397 FIXME("Property 0x%lx not implemented\n", Property);
2398 SetLastError(ERROR_NOT_SUPPORTED);
2399 }
2400 }
2401 }
2402
2403 TRACE("Returning %d\n", ret);
2404 return ret;
2405 }
2406
2407
2408 /***********************************************************************
2409 * SetupDiInstallClassA (SETUPAPI.@)
2410 */
2411 BOOL WINAPI SetupDiInstallClassA(
2412 HWND hwndParent,
2413 PCSTR InfFileName,
2414 DWORD Flags,
2415 HSPFILEQ FileQueue)
2416 {
2417 UNICODE_STRING FileNameW;
2418 BOOL Result;
2419
2420 if (!RtlCreateUnicodeStringFromAsciiz(&FileNameW, InfFileName))
2421 {
2422 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2423 return FALSE;
2424 }
2425
2426 Result = SetupDiInstallClassW(hwndParent, FileNameW.Buffer, Flags, FileQueue);
2427
2428 RtlFreeUnicodeString(&FileNameW);
2429
2430 return Result;
2431 }
2432
2433 static HKEY CreateClassKey(HINF hInf)
2434 {
2435 WCHAR FullBuffer[MAX_PATH];
2436 WCHAR Buffer[MAX_PATH];
2437 DWORD RequiredSize;
2438 HKEY hClassKey;
2439
2440 Buffer[0] = '\\';
2441 if (!SetupGetLineTextW(NULL,
2442 hInf,
2443 Version,
2444 ClassGUID,
2445 &Buffer[1],
2446 MAX_PATH - 1,
2447 &RequiredSize))
2448 {
2449 return INVALID_HANDLE_VALUE;
2450 }
2451
2452 lstrcpyW(FullBuffer, ControlClass);
2453 lstrcatW(FullBuffer, Buffer);
2454
2455
2456 if (!SetupGetLineTextW(NULL,
2457 hInf,
2458 Version,
2459 Class,
2460 Buffer,
2461 MAX_PATH,
2462 &RequiredSize))
2463 {
2464 RegDeleteKeyW(HKEY_LOCAL_MACHINE, FullBuffer);
2465 return INVALID_HANDLE_VALUE;
2466 }
2467
2468 if (ERROR_SUCCESS != RegCreateKeyExW(HKEY_LOCAL_MACHINE,
2469 FullBuffer,
2470 0,
2471 NULL,
2472 REG_OPTION_NON_VOLATILE,
2473 KEY_ALL_ACCESS,
2474 NULL,
2475 &hClassKey,
2476 NULL))
2477 {
2478 RegDeleteKeyW(HKEY_LOCAL_MACHINE, FullBuffer);
2479 return INVALID_HANDLE_VALUE;
2480 }
2481
2482 if (ERROR_SUCCESS != RegSetValueExW(hClassKey,
2483 Class,
2484 0,
2485 REG_SZ,
2486 (LPBYTE)Buffer,
2487 RequiredSize * sizeof(WCHAR)))
2488 {
2489 RegCloseKey(hClassKey);
2490 RegDeleteKeyW(HKEY_LOCAL_MACHINE, FullBuffer);
2491 return INVALID_HANDLE_VALUE;
2492 }
2493
2494 return hClassKey;
2495 }
2496
2497 /***********************************************************************
2498 * SetupDiInstallClassW (SETUPAPI.@)
2499 */
2500 BOOL WINAPI SetupDiInstallClassW(
2501 HWND hwndParent,
2502 PCWSTR InfFileName,
2503 DWORD Flags,
2504 HSPFILEQ FileQueue)
2505 {
2506 WCHAR SectionName[MAX_PATH];
2507 DWORD SectionNameLength = 0;
2508 HINF hInf;
2509 BOOL bFileQueueCreated = FALSE;
2510 HKEY hClassKey;
2511
2512 FIXME("not fully implemented\n");
2513
2514 if ((Flags & DI_NOVCP) && (FileQueue == NULL || FileQueue == INVALID_HANDLE_VALUE))
2515 {
2516 SetLastError(ERROR_INVALID_PARAMETER);
2517 return FALSE;
2518 }
2519
2520 /* Open the .inf file */
2521 hInf = SetupOpenInfFileW(InfFileName,
2522 NULL,
2523 INF_STYLE_WIN4,
2524 NULL);
2525 if (hInf == INVALID_HANDLE_VALUE)
2526 {
2527
2528 return FALSE;
2529 }
2530
2531 /* Create or open the class registry key 'HKLM\\CurrentControlSet\\Class\\{GUID}' */
2532 hClassKey = CreateClassKey(hInf);
2533 if (hClassKey == INVALID_HANDLE_VALUE)
2534 {
2535 SetupCloseInfFile(hInf);
2536 return FALSE;
2537 }
2538
2539
2540
2541 /* Try to append a layout file */
2542 #if 0
2543 SetupOpenAppendInfFileW(NULL, hInf, NULL);
2544 #endif
2545
2546 /* Retrieve the actual section name */
2547 SetupDiGetActualSectionToInstallW(hInf,
2548 ClassInstall32,
2549 SectionName,
2550 MAX_PATH,
2551 &SectionNameLength,
2552 NULL);
2553
2554 #if 0
2555 if (!(Flags & DI_NOVCP))
2556 {
2557 FileQueue = SetupOpenFileQueue();
2558 if (FileQueue == INVALID_HANDLE_VALUE)
2559 {
2560 SetupCloseInfFile(hInf);
2561 RegCloseKey(hClassKey);
2562 return FALSE;
2563 }
2564
2565 bFileQueueCreated = TRUE;
2566
2567 }
2568 #endif
2569
2570 SetupInstallFromInfSectionW(NULL,
2571 hInf,
2572 SectionName,
2573 SPINST_REGISTRY,
2574 hClassKey,
2575 NULL,
2576 0,
2577 NULL,
2578 NULL,
2579 INVALID_HANDLE_VALUE,
2580 NULL);
2581
2582 /* FIXME: More code! */
2583
2584 if (bFileQueueCreated)
2585 SetupCloseFileQueue(FileQueue);
2586
2587 SetupCloseInfFile(hInf);
2588
2589 RegCloseKey(hClassKey);
2590 return TRUE;
2591 }
2592
2593
2594 /***********************************************************************
2595 * SetupDiOpenClassRegKey (SETUPAPI.@)
2596 */
2597 HKEY WINAPI SetupDiOpenClassRegKey(
2598 const GUID* ClassGuid,
2599 REGSAM samDesired)
2600 {
2601 return SetupDiOpenClassRegKeyExW(ClassGuid, samDesired,
2602 DIOCR_INSTALLER, NULL, NULL);
2603 }
2604
2605
2606 /***********************************************************************
2607 * SetupDiOpenClassRegKeyExA (SETUPAPI.@)
2608 */
2609 HKEY WINAPI SetupDiOpenClassRegKeyExA(
2610 const GUID* ClassGuid,
2611 REGSAM samDesired,
2612 DWORD Flags,
2613 PCSTR MachineName,
2614 PVOID Reserved)
2615 {
2616 PWSTR MachineNameW = NULL;
2617 HKEY hKey;
2618
2619 TRACE("\n");
2620
2621 if (MachineName)
2622 {
2623 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
2624 if (MachineNameW == NULL)
2625 return INVALID_HANDLE_VALUE;
2626 }
2627
2628 hKey = SetupDiOpenClassRegKeyExW(ClassGuid, samDesired,
2629 Flags, MachineNameW, Reserved);
2630
2631 if (MachineNameW)
2632 MyFree(MachineNameW);
2633
2634 return hKey;
2635 }
2636
2637
2638 /***********************************************************************
2639 * SetupDiOpenClassRegKeyExW (SETUPAPI.@)
2640 */
2641 HKEY WINAPI SetupDiOpenClassRegKeyExW(
2642 const GUID* ClassGuid,
2643 REGSAM samDesired,
2644 DWORD Flags,
2645 PCWSTR MachineName,
2646 PVOID Reserved)
2647 {
2648 LPWSTR lpGuidString;
2649 LPWSTR lpFullGuidString;
2650 DWORD dwLength;
2651 HKEY HKLM;
2652 HKEY hClassesKey;
2653 HKEY hClassKey;
2654 DWORD rc;
2655 LPCWSTR lpKeyName;
2656
2657 if (Flags == DIOCR_INSTALLER)
2658 {
2659 lpKeyName = ControlClass;
2660 }
2661 else if (Flags == DIOCR_INTERFACE)
2662 {
2663 lpKeyName = DeviceClasses;
2664 }
2665 else
2666 {
2667 ERR("Invalid Flags parameter!\n");
2668 SetLastError(ERROR_INVALID_PARAMETER);
2669 return INVALID_HANDLE_VALUE;
2670 }
2671
2672 if (MachineName != NULL)
2673 {
2674 rc = RegConnectRegistryW(MachineName, HKEY_LOCAL_MACHINE, &HKLM);
2675 if (rc != ERROR_SUCCESS)
2676 {
2677 SetLastError(rc);
2678 return INVALID_HANDLE_VALUE;
2679 }
2680 }
2681 else
2682 HKLM = HKEY_LOCAL_MACHINE;
2683
2684 rc = RegOpenKeyExW(HKLM,
2685 lpKeyName,
2686 0,
2687 KEY_ALL_ACCESS,
2688 &hClassesKey);
2689 if (MachineName != NULL) RegCloseKey(HKLM);
2690 if (rc != ERROR_SUCCESS)
2691 {
2692 SetLastError(rc);
2693 return INVALID_HANDLE_VALUE;
2694 }
2695
2696 if (ClassGuid == NULL)
2697 return hClassesKey;
2698
2699 if (UuidToStringW((UUID*)ClassGuid, &lpGuidString) != RPC_S_OK)
2700 {
2701 SetLastError(ERROR_GEN_FAILURE);
2702 RegCloseKey(hClassesKey);
2703 return INVALID_HANDLE_VALUE;
2704 }
2705
2706 dwLength = lstrlenW(lpGuidString);
2707 lpFullGuidString = HeapAlloc(GetProcessHeap(), 0, (dwLength + 3) * sizeof(WCHAR));
2708 if (!lpFullGuidString)
2709 {
2710 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2711 RpcStringFreeW(&lpGuidString);
2712 return INVALID_HANDLE_VALUE;
2713 }
2714 lpFullGuidString[0] = '{';
2715 memcpy(&lpFullGuidString[1], lpGuidString, dwLength * sizeof(WCHAR));
2716 lpFullGuidString[dwLength + 1] = '}';
2717 lpFullGuidString[dwLength + 2] = '\0';
2718 RpcStringFreeW(&lpGuidString);
2719
2720 rc = RegOpenKeyExW(hClassesKey,
2721 lpFullGuidString,
2722 0,
2723 KEY_ALL_ACCESS,
2724 &hClassKey);
2725 if (rc != ERROR_SUCCESS)
2726 {
2727 SetLastError(rc);
2728 HeapFree(GetProcessHeap(), 0, lpFullGuidString);
2729 RegCloseKey(hClassesKey);
2730 return INVALID_HANDLE_VALUE;
2731 }
2732
2733 HeapFree(GetProcessHeap(), 0, lpFullGuidString);
2734 RegCloseKey(hClassesKey);
2735
2736 return hClassKey;
2737 }
2738
2739 /***********************************************************************
2740 * SetupDiOpenDeviceInterfaceW (SETUPAPI.@)
2741 */
2742 BOOL WINAPI SetupDiOpenDeviceInterfaceW(
2743 HDEVINFO DeviceInfoSet,
2744 PCWSTR DevicePath,
2745 DWORD OpenFlags,
2746 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
2747 {
2748 FIXME("%p %s %08lx %p\n",
2749 DeviceInfoSet, debugstr_w(DevicePath), OpenFlags, DeviceInterfaceData);
2750 return FALSE;
2751 }
2752
2753 /***********************************************************************
2754 * SetupDiOpenDeviceInterfaceA (SETUPAPI.@)
2755 */
2756 BOOL WINAPI SetupDiOpenDeviceInterfaceA(
2757 HDEVINFO DeviceInfoSet,
2758 PCSTR DevicePath,
2759 DWORD OpenFlags,
2760 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
2761 {
2762 LPWSTR DevicePathW = NULL;
2763 BOOL bResult;
2764
2765 TRACE("%p %s %08lx %p\n", DeviceInfoSet, debugstr_a(DevicePath), OpenFlags, DeviceInterfaceData);
2766
2767 DevicePathW = MultiByteToUnicode(DevicePath, CP_ACP);
2768 if (DevicePathW == NULL)
2769 return FALSE;
2770
2771 bResult = SetupDiOpenDeviceInterfaceW(DeviceInfoSet,
2772 DevicePathW, OpenFlags, DeviceInterfaceData);
2773
2774 MyFree(DevicePathW);
2775
2776 return bResult;
2777 }
2778
2779 /***********************************************************************
2780 * SetupDiSetClassInstallParamsA (SETUPAPI.@)
2781 */
2782 BOOL WINAPI SetupDiSetClassInstallParamsA(
2783 HDEVINFO DeviceInfoSet,
2784 PSP_DEVINFO_DATA DeviceInfoData,
2785 PSP_CLASSINSTALL_HEADER ClassInstallParams,
2786 DWORD ClassInstallParamsSize)
2787 {
2788 FIXME("%p %p %x %lu\n",DeviceInfoSet, DeviceInfoData,
2789 ClassInstallParams->InstallFunction, ClassInstallParamsSize);
2790 return FALSE;
2791 }
2792
2793 static DWORD
2794 GetFunctionPointer(
2795 IN PWSTR InstallerName,
2796 OUT HMODULE* ModulePointer,
2797 OUT PVOID* FunctionPointer)
2798 {
2799 HMODULE hModule = NULL;
2800 LPSTR FunctionNameA = NULL;
2801 PWCHAR Comma;
2802 DWORD rc;
2803
2804 *ModulePointer = NULL;
2805 *FunctionPointer = NULL;
2806
2807 Comma = strchrW(InstallerName, ',');
2808 if (!Comma)
2809 {
2810 rc = ERROR_INVALID_PARAMETER;
2811 goto cleanup;
2812 }
2813
2814 /* W->A conversion for function name */
2815 FunctionNameA = UnicodeToMultiByte(Comma + 1, CP_ACP);
2816 if (!FunctionNameA)
2817 {
2818 rc = GetLastError();
2819 goto cleanup;
2820 }
2821
2822 /* Load library */
2823 *Comma = '\0';
2824 hModule = LoadLibraryW(InstallerName);
2825 *Comma = ',';
2826 if (!hModule)
2827 {
2828 rc = GetLastError();
2829 goto cleanup;
2830 }
2831
2832 /* Search function */
2833 *FunctionPointer = GetProcAddress(hModule, FunctionNameA);
2834 if (!*FunctionPointer)
2835 {
2836 rc = GetLastError();
2837 goto cleanup;
2838 }
2839
2840 *ModulePointer = hModule;
2841 rc = ERROR_SUCCESS;
2842
2843 cleanup:
2844 if (rc != ERROR_SUCCESS && hModule)
2845 FreeLibrary(hModule);
2846 MyFree(FunctionNameA);
2847 return rc;
2848 }
2849
2850 static DWORD
2851 FreeFunctionPointer(
2852 IN HMODULE ModulePointer,
2853 IN PVOID FunctionPointer)
2854 {
2855 if (ModulePointer == NULL)
2856 return ERROR_SUCCESS;
2857 if (FreeLibrary(ModulePointer))
2858 return ERROR_SUCCESS;
2859 else
2860 return GetLastError();
2861 }
2862
2863 /***********************************************************************
2864 * SetupDiCallClassInstaller (SETUPAPI.@)
2865 */
2866 BOOL WINAPI SetupDiCallClassInstaller(
2867 IN DI_FUNCTION InstallFunction,
2868 IN HDEVINFO DeviceInfoSet,
2869 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
2870 {
2871 BOOL ret = FALSE;
2872
2873 TRACE("%ld %p %p\n", InstallFunction, DeviceInfoSet, DeviceInfoData);
2874
2875 if (!DeviceInfoSet)
2876 SetLastError(ERROR_INVALID_PARAMETER);
2877 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
2878 SetLastError(ERROR_INVALID_HANDLE);
2879 else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
2880 SetLastError(ERROR_INVALID_HANDLE);
2881 else if (((struct DeviceInfoSet *)DeviceInfoSet)->HKLM != HKEY_LOCAL_MACHINE)
2882 SetLastError(ERROR_INVALID_HANDLE);
2883 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
2884 SetLastError(ERROR_INVALID_USER_BUFFER);
2885 else
2886 {
2887 #define CLASS_COINSTALLER 0x1
2888 #define DEVICE_COINSTALLER 0x2
2889 #define CLASS_INSTALLER 0x4
2890 UCHAR CanHandle = 0;
2891 DEFAULT_CLASS_INSTALL_PROC DefaultHandler = NULL;
2892
2893 switch (InstallFunction)
2894 {
2895 case DIF_ALLOW_INSTALL:
2896 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
2897 break;
2898 case DIF_DESTROYPRIVATEDATA:
2899 CanHandle = CLASS_INSTALLER;
2900 break;
2901 case DIF_INSTALLDEVICE:
2902 CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
2903 DefaultHandler = SetupDiInstallDevice;
2904 break;
2905 case DIF_INSTALLDEVICEFILES:
2906 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
2907 DefaultHandler = SetupDiInstallDriverFiles;
2908 break;
2909 case DIF_INSTALLINTERFACES:
2910 CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
2911 DefaultHandler = SetupDiInstallDeviceInterfaces;
2912 break;
2913 case DIF_NEWDEVICEWIZARD_FINISHINSTALL:
2914 CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
2915 break;
2916 case DIF_NEWDEVICEWIZARD_POSTANALYZE:
2917 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
2918 break;
2919 case DIF_NEWDEVICEWIZARD_PREANALYZE:
2920 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
2921 break;
2922 case DIF_REGISTER_COINSTALLERS:
2923 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
2924 DefaultHandler = SetupDiRegisterCoDeviceInstallers;
2925 break;
2926 case DIF_SELECTBESTCOMPATDRV:
2927 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
2928 DefaultHandler = SetupDiSelectBestCompatDrv;
2929 break;
2930 default:
2931 FIXME("Install function %ld not implemented\n", InstallFunction);
2932 SetLastError(ERROR_INVALID_PARAMETER);
2933 }
2934
2935 if (CanHandle != 0)
2936 {
2937 LIST_ENTRY ClassCoInstallersListHead;
2938 LIST_ENTRY DeviceCoInstallersListHead;
2939 HMODULE ClassInstallerLibrary;
2940 CLASS_INSTALL_PROC ClassInstaller = NULL;
2941 COINSTALLER_CONTEXT_DATA Context;
2942 PLIST_ENTRY ListEntry;
2943 HKEY hKey;
2944 DWORD dwRegType, dwLength;
2945 DWORD rc = NO_ERROR;
2946
2947 InitializeListHead(&ClassCoInstallersListHead);
2948 InitializeListHead(&DeviceCoInstallersListHead);
2949
2950 if (CanHandle & DEVICE_COINSTALLER)
2951 {
2952 FIXME("Doesn't use Device co-installers at the moment\n");
2953 }
2954 if (CanHandle & CLASS_COINSTALLER)
2955 {
2956 rc = RegOpenKeyEx(
2957 HKEY_LOCAL_MACHINE,
2958 L"SYSTEM\\CurrentControlSet\\Control\\CoDeviceInstallers",
2959 0, /* Options */
2960 KEY_QUERY_VALUE,
2961 &hKey);
2962 if (rc == ERROR_SUCCESS)
2963 {
2964 LPWSTR lpGuidString;
2965 if (UuidToStringW((UUID*)&DeviceInfoData->ClassGuid, &lpGuidString) == RPC_S_OK)
2966 {
2967 rc = RegQueryValueExW(hKey, lpGuidString, NULL, &dwRegType, NULL, &dwLength);
2968 if (rc == ERROR_SUCCESS && dwRegType == REG_SZ)
2969 {
2970 LPWSTR KeyBuffer = HeapAlloc(GetProcessHeap(), 0, dwLength);
2971 if (KeyBuffer != NULL)
2972 {
2973 rc = RegQueryValueExW(hKey, lpGuidString, NULL, NULL, (LPBYTE)KeyBuffer, &dwLength);
2974 if (rc == ERROR_SUCCESS)
2975 {
2976 LPCWSTR ptr;
2977 for (ptr = KeyBuffer; *ptr; ptr += strlenW(ptr) + 1)
2978 {
2979 /* Add coinstaller to ClassCoInstallersListHead list */
2980 FIXME("Class coinstaller is '%S'. UNIMPLEMENTED!\n", ptr);
2981 }
2982 }
2983 HeapFree(GetProcessHeap(), 0, KeyBuffer);
2984 }
2985 }
2986 RpcStringFreeW(&lpGuidString);
2987 }
2988 RegCloseKey(hKey);
2989 }
2990 }
2991 if (CanHandle & CLASS_INSTALLER)
2992 {
2993 hKey = SetupDiOpenClassRegKey(&DeviceInfoData->ClassGuid, KEY_QUERY_VALUE);
2994 if (hKey != INVALID_HANDLE_VALUE)
2995 {
2996 rc = RegQueryValueExW(hKey, L"Installer32", NULL, &dwRegType, NULL, &dwLength);
2997 if (rc == ERROR_SUCCESS && dwRegType == REG_SZ)
2998 {
2999 LPWSTR KeyBuffer = HeapAlloc(GetProcessHeap(), 0, dwLength);
3000 if (KeyBuffer != NULL)
3001 {
3002 rc = RegQueryValueExW(hKey, L"Installer32", NULL, NULL, (LPBYTE)KeyBuffer, &dwLength);
3003 if (rc == ERROR_SUCCESS)
3004 {
3005 /* Get ClassInstaller function pointer */
3006 rc = GetFunctionPointer(KeyBuffer, &ClassInstallerLibrary, (PVOID*)&ClassInstaller);
3007 }
3008 HeapFree(GetProcessHeap(), 0, KeyBuffer);
3009 }
3010 }
3011 RegCloseKey(hKey);
3012 }
3013 }
3014
3015 /* Call Class co-installers */
3016 Context.PostProcessing = FALSE;
3017 rc = NO_ERROR;
3018 ListEntry = ClassCoInstallersListHead.Flink;
3019 while (rc == NO_ERROR && ListEntry != &ClassCoInstallersListHead)
3020 {
3021 struct CoInstallerElement *coinstaller = (struct CoInstallerElement *)ListEntry;
3022 rc = (*coinstaller->Function)(InstallFunction, DeviceInfoSet, DeviceInfoData, &Context);
3023 coinstaller->PrivateData = Context.PrivateData;
3024 if (rc == ERROR_DI_POSTPROCESSING_REQUIRED)
3025 {
3026 coinstaller->DoPostProcessing = TRUE;
3027 rc = NO_ERROR;
3028 }
3029 ListEntry = ListEntry->Flink;
3030 }
3031
3032 /* Call Device co-installers */
3033 ListEntry = DeviceCoInstallersListHead.Flink;
3034 while (rc == NO_ERROR && ListEntry != &DeviceCoInstallersListHead)
3035 {
3036 struct CoInstallerElement *coinstaller = (struct CoInstallerElement *)ListEntry;
3037 rc = (*coinstaller->Function)(InstallFunction, DeviceInfoSet, DeviceInfoData, &Context);
3038 coinstaller->PrivateData = Context.PrivateData;
3039 if (rc == ERROR_DI_POSTPROCESSING_REQUIRED)
3040 {
3041 coinstaller->DoPostProcessing = TRUE;
3042 rc = NO_ERROR;
3043 }
3044 ListEntry = ListEntry->Flink;
3045 }
3046
3047 /* Call Class installer */
3048 if (ClassInstaller)
3049 {
3050 rc = (*ClassInstaller)(InstallFunction, DeviceInfoSet, DeviceInfoData);
3051 FreeFunctionPointer(ClassInstallerLibrary, ClassInstaller);
3052 }
3053 else
3054 rc = ERROR_DI_DO_DEFAULT;
3055
3056 /* Call default handler */
3057 if (rc == ERROR_DI_DO_DEFAULT)
3058 {
3059 if (DefaultHandler /*FIXME && DI_NODI_DEFAULTACTION not set */)
3060 {
3061 if ((*DefaultHandler)(DeviceInfoSet, DeviceInfoData))
3062 rc = NO_ERROR;
3063 else
3064 rc = GetLastError();
3065 }
3066 else
3067 rc = NO_ERROR;
3068 }
3069
3070 /* Call Class co-installers that required postprocessing */
3071 Context.PostProcessing = TRUE;
3072 ListEntry = ClassCoInstallersListHead.Flink;
3073 while (ListEntry != &ClassCoInstallersListHead)
3074 {
3075 struct CoInstallerElement *coinstaller = (struct CoInstallerElement *)ListEntry;
3076 if (coinstaller->DoPostProcessing)
3077 {
3078 Context.InstallResult = rc;
3079 Context.PrivateData = coinstaller->PrivateData;
3080 rc = (*coinstaller->Function)(InstallFunction, DeviceInfoSet, DeviceInfoData, &Context);
3081 }
3082 FreeFunctionPointer(coinstaller->Module, coinstaller->Function);
3083 ListEntry = ListEntry->Flink;
3084 }
3085
3086 /* Call Device co-installers that required postprocessing */
3087 ListEntry = DeviceCoInstallersListHead.Flink;
3088 while (ListEntry != &DeviceCoInstallersListHead)
3089 {
3090 struct CoInstallerElement *coinstaller = (struct CoInstallerElement *)ListEntry;
3091 if (coinstaller->DoPostProcessing)
3092 {
3093 Context.InstallResult = rc;
3094 Context.PrivateData = coinstaller->PrivateData;
3095 rc = (*coinstaller->Function)(InstallFunction, DeviceInfoSet, DeviceInfoData, &Context);
3096 }
3097 FreeFunctionPointer(coinstaller->Module, coinstaller->Function);
3098 ListEntry = ListEntry->Flink;
3099 }
3100
3101 /* Free allocated memory */
3102 while (!IsListEmpty(&ClassCoInstallersListHead))
3103 {
3104 ListEntry = RemoveHeadList(&ClassCoInstallersListHead);
3105 HeapFree(GetProcessHeap(), 0, ListEntry);
3106 }
3107 while (!IsListEmpty(&DeviceCoInstallersListHead))
3108 {
3109 ListEntry = RemoveHeadList(&DeviceCoInstallersListHead);
3110 HeapFree(GetProcessHeap(), 0, ListEntry);
3111 }
3112
3113 ret = (rc == NO_ERROR);
3114 }
3115 }
3116
3117 TRACE("Returning %d\n", ret);
3118 return ret;
3119 }
3120
3121 /***********************************************************************
3122 * SetupDiGetDeviceInstallParamsA (SETUPAPI.@)
3123 */
3124 BOOL WINAPI SetupDiGetDeviceInstallParamsA(
3125 IN HDEVINFO DeviceInfoSet,
3126 IN PSP_DEVINFO_DATA DeviceInfoData,
3127 OUT PSP_DEVINSTALL_PARAMS_A DeviceInstallParams)
3128 {
3129 SP_DEVINSTALL_PARAMS_W deviceInstallParamsW;
3130 BOOL ret = FALSE;
3131
3132 TRACE("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstallParams);
3133
3134 if (DeviceInstallParams == NULL)
3135 SetLastError(ERROR_INVALID_PARAMETER);
3136 else if (DeviceInstallParams->cbSize != sizeof(SP_DEVINSTALL_PARAMS_A))
3137 SetLastError(ERROR_INVALID_USER_BUFFER);
3138 else
3139 {
3140 deviceInstallParamsW.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
3141 ret = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &deviceInstallParamsW);
3142
3143 if (ret)
3144 {
3145 /* Do W->A conversion */
3146 memcpy(
3147 DeviceInstallParams,
3148 &deviceInstallParamsW,
3149 FIELD_OFFSET(SP_DEVINSTALL_PARAMS_W, DriverPath));
3150 if (WideCharToMultiByte(CP_ACP, 0, deviceInstallParamsW.DriverPath, -1,
3151 DeviceInstallParams->DriverPath, MAX_PATH, NULL, NULL) == 0)
3152 {
3153 DeviceInstallParams->DriverPath[0] = '\0';
3154 ret = FALSE;
3155 }
3156 }
3157 }
3158
3159 TRACE("Returning %d\n", ret);
3160 return ret;
3161 }
3162
3163 /***********************************************************************
3164 * SetupDiGetDeviceInstallParamsW (SETUPAPI.@)
3165 */
3166 BOOL WINAPI SetupDiGetDeviceInstallParamsW(
3167 IN HDEVINFO DeviceInfoSet,
3168 IN PSP_DEVINFO_DATA DeviceInfoData,
3169 OUT PSP_DEVINSTALL_PARAMS_W DeviceInstallParams)
3170 {
3171 FIXME("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstallParams);
3172 return FALSE;
3173 }
3174
3175 /***********************************************************************
3176 * SetupDiCreateDevRegKey (SETUPAPI.@)
3177 */
3178 HKEY WINAPI SetupDiCreateDevRegKeyW(
3179 IN HDEVINFO DeviceInfoSet,
3180 IN PSP_DEVINFO_DATA DeviceInfoData,
3181 IN DWORD Scope,
3182 IN DWORD HwProfile,
3183 IN DWORD KeyType,
3184 IN HINF InfHandle OPTIONAL,
3185 IN PCWSTR InfSectionName OPTIONAL)
3186 {
3187 struct DeviceInfoSet *list;
3188 HKEY ret = INVALID_HANDLE_VALUE;
3189
3190 TRACE("%p %p %lu %lu %lu %p %s\n", DeviceInfoSet, DeviceInfoData,
3191 Scope, HwProfile, KeyType, InfHandle, debugstr_w(InfSectionName));
3192
3193 if (!DeviceInfoSet)
3194 SetLastError(ERROR_INVALID_HANDLE);
3195 else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
3196 SetLastError(ERROR_INVALID_HANDLE);
3197 else if (!DeviceInfoData)
3198 SetLastError(ERROR_INVALID_PARAMETER);
3199 else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
3200 SetLastError(ERROR_INVALID_USER_BUFFER);
3201 else if (Scope != DICS_FLAG_GLOBAL && Scope != DICS_FLAG_CONFIGSPECIFIC)
3202 SetLastError(ERROR_INVALID_PARAMETER);
3203 else if (KeyType != DIREG_DEV && KeyType != DIREG_DRV)
3204 SetLastError(ERROR_INVALID_PARAMETER);
3205 else if (InfHandle && !InfSectionName)
3206 SetLastError(ERROR_INVALID_PARAMETER);
3207 else if (!InfHandle && InfSectionName)
3208 SetLastError(ERROR_INVALID_PARAMETER);
3209 else
3210 {
3211 LPWSTR lpGuidString = NULL;
3212 LPWSTR DriverKey = NULL; /* {GUID}\Index */
3213 LPWSTR pDeviceInstance; /* Points into DriverKey, on the Index field */
3214 DWORD Index; /* Index used in the DriverKey name */
3215 DWORD rc;
3216 HKEY hClassKey = INVALID_HANDLE_VALUE;
3217 HKEY hDeviceKey = INVALID_HANDLE_VALUE;
3218 HKEY hKey = INVALID_HANDLE_VALUE;
3219
3220 if (Scope == DICS_FLAG_CONFIGSPECIFIC)
3221 {
3222 FIXME("DICS_FLAG_CONFIGSPECIFIC case unimplemented\n");
3223 goto cleanup;
3224 }
3225
3226 if (KeyType == DIREG_DEV)
3227 {
3228 FIXME("DIREG_DEV case unimplemented\n");
3229 }
3230 else /* KeyType == DIREG_DRV */
3231 {
3232 if (UuidToStringW((UUID*)&DeviceInfoData->ClassGuid, &lpGuidString) != RPC_S_OK)
3233 goto cleanup;
3234 /* The driver key is in HKLM\System\CurrentControlSet\Control\Class\{GUID}\Index */
3235 DriverKey = HeapAlloc(GetProcessHeap(), 0, (wcslen(lpGuidString) + 7) * sizeof(WCHAR) + sizeof(UNICODE_STRING));
3236 if (!DriverKey)
3237 {
3238 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3239 goto cleanup;
3240 }
3241 wcscpy(DriverKey, L"{");
3242 wcscat(DriverKey, lpGuidString);
3243 wcscat(DriverKey, L"}\\");
3244 pDeviceInstance = &DriverKey[wcslen(DriverKey)];
3245 rc = RegOpenKeyExW(list->HKLM,
3246 ControlClass,
3247 0,
3248 KEY_CREATE_SUB_KEY,
3249 &hClassKey);
3250 if (rc != ERROR_SUCCESS)
3251 {
3252 SetLastError(rc);
3253 goto cleanup;
3254 }
3255
3256 /* Try all values for Index between 0 and 9999 */
3257 Index = 0;
3258 while (Index <= 9999)
3259 {
3260 DWORD Disposition;
3261 wsprintf(pDeviceInstance, L"%04lu", Index);
3262 rc = RegCreateKeyEx(hClassKey,
3263 DriverKey,
3264 0,
3265 NULL,
3266 REG_OPTION_NON_VOLATILE,
3267 KEY_READ | KEY_WRITE,
3268 NULL,
3269 &hKey,
3270 &Disposition);
3271 if (rc != ERROR_SUCCESS)
3272 {
3273 SetLastError(rc);
3274 goto cleanup;
3275 }
3276 if (Disposition == REG_CREATED_NEW_KEY)
3277 break;
3278 RegCloseKey(hKey);
3279 hKey = INVALID_HANDLE_VALUE;
3280 Index++;
3281 }
3282 if (Index > 9999)
3283 {
3284 /* Unable to create more than 9999 devices within the same class */
3285 SetLastError(ERROR_GEN_FAILURE);
3286 goto cleanup;
3287 }
3288
3289 /* Open device key, to write Driver value */
3290 hDeviceKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, Scope, HwProfile, DIREG_DEV, KEY_SET_VALUE);
3291 if (hDeviceKey == INVALID_HANDLE_VALUE)
3292 goto cleanup;
3293 rc = RegSetValueEx(hDeviceKey, L"Driver", 0, REG_SZ, (const BYTE *)DriverKey, (wcslen(DriverKey) + 1) * sizeof(WCHAR));
3294 if (rc != ERROR_SUCCESS)
3295 {
3296 SetLastError(rc);
3297 goto cleanup;
3298 }
3299 }
3300
3301 /* Do installation of the specified section */
3302 if (InfHandle)
3303 {
3304 FIXME("Need to install section %s in file %p\n",
3305 debugstr_w(InfSectionName), InfHandle);
3306 }
3307 ret = hKey;
3308
3309 cleanup:
3310 if (lpGuidString)
3311 RpcStringFreeW(&lpGuidString);
3312 HeapFree(GetProcessHeap(), 0, DriverKey);
3313 if (hClassKey != INVALID_HANDLE_VALUE)
3314 RegCloseKey(hClassKey);
3315 if (hDeviceKey != INVALID_HANDLE_VALUE)
3316 RegCloseKey(hDeviceKey);
3317 if (hKey != INVALID_HANDLE_VALUE && hKey != ret)
3318 RegCloseKey(hKey);
3319 }
3320
3321 TRACE("Returning 0x%p\n", ret);
3322 return ret;
3323 }
3324
3325 /***********************************************************************
3326 * SetupDiOpenDevRegKey (SETUPAPI.@)
3327 */
3328 HKEY WINAPI SetupDiOpenDevRegKey(
3329 HDEVINFO DeviceInfoSet,
3330 PSP_DEVINFO_DATA DeviceInfoData,
3331 DWORD Scope,
3332 DWORD HwProfile,
3333 DWORD KeyType,
3334 REGSAM samDesired)
3335 {
3336 struct DeviceInfoSet *list;
3337 HKEY ret = INVALID_HANDLE_VALUE;
3338
3339 TRACE("%p %p %lu %lu %lu 0x%lx\n", DeviceInfoSet, DeviceInfoData,
3340 Scope, HwProfile, KeyType, samDesired);
3341
3342 if (!DeviceInfoSet)
3343 SetLastError(ERROR_INVALID_HANDLE);
3344 else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
3345 SetLastError(ERROR_INVALID_HANDLE);
3346 else if (!DeviceInfoData)
3347 SetLastError(ERROR_INVALID_PARAMETER);
3348 else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
3349 SetLastError(ERROR_INVALID_USER_BUFFER);
3350 else if (Scope != DICS_FLAG_GLOBAL && Scope != DICS_FLAG_CONFIGSPECIFIC)
3351 SetLastError(ERROR_INVALID_PARAMETER);
3352 else if (KeyType != DIREG_DEV && KeyType != DIREG_DRV)
3353 SetLastError(ERROR_INVALID_PARAMETER);
3354 else
3355 {
3356 HKEY hKey = INVALID_HANDLE_VALUE;
3357 HKEY hRootKey = INVALID_HANDLE_VALUE;
3358 struct DeviceInfoElement *deviceInfo = (struct DeviceInfoElement *)DeviceInfoData->Reserved;
3359 LPWSTR DriverKey = NULL;
3360 DWORD dwLength = 0;
3361 DWORD dwRegType;
3362 DWORD rc;
3363
3364 if (Scope == DICS_FLAG_CONFIGSPECIFIC)
3365 {
3366 FIXME("DICS_FLAG_CONFIGSPECIFIC case unimplemented\n");
3367 }
3368 else /* Scope == DICS_FLAG_GLOBAL */
3369 {
3370 rc = RegOpenKeyExW(
3371 list->HKLM,
3372 EnumKeyName,
3373 0, /* Options */
3374 KEY_ENUMERATE_SUB_KEYS,
3375 &hRootKey);
3376 if (rc != ERROR_SUCCESS)
3377 {
3378 SetLastError(rc);
3379 goto cleanup;
3380 }
3381 rc = RegOpenKeyExW(
3382 hRootKey,
3383 deviceInfo->DeviceName,
3384 0, /* Options */
3385 KeyType == DIREG_DEV ? samDesired : KEY_QUERY_VALUE,
3386 &hKey);
3387 RegCloseKey(hRootKey);
3388 hRootKey = INVALID_HANDLE_VALUE;
3389 if (rc != ERROR_SUCCESS)
3390 {
3391 SetLastError(rc);
3392 goto cleanup;
3393 }
3394 if (KeyType == DIREG_DEV)
3395 {
3396 /* We're done. Just return the hKey handle */
3397 ret = hKey;
3398 goto cleanup;
3399 }
3400 /* Read the 'Driver' key */
3401 rc = RegQueryValueExW(hKey, L"Driver", NULL, &dwRegType, NULL, &dwLength);
3402 if (rc != ERROR_SUCCESS)
3403 {
3404 SetLastError(rc);
3405 goto cleanup;
3406 }
3407 if (dwRegType != REG_SZ)
3408 {
3409 SetLastError(ERROR_GEN_FAILURE);
3410 goto cleanup;
3411 }
3412 DriverKey = HeapAlloc(GetProcessHeap(), 0, dwLength);
3413 if (!DriverKey)
3414 {
3415 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3416 goto cleanup;
3417 }
3418 rc = RegQueryValueExW(hKey, L"Driver", NULL, &dwRegType, (LPBYTE)DriverKey, &dwLength);
3419 if (rc != ERROR_SUCCESS)
3420 {
3421 SetLastError(rc);
3422 goto cleanup;
3423 }
3424 RegCloseKey(hKey);
3425 hKey = INVALID_HANDLE_VALUE;
3426 /* Need to open the driver key */
3427 rc = RegOpenKeyExW(
3428 list->HKLM,
3429 ControlClass,
3430 0, /* Options */
3431 KEY_ENUMERATE_SUB_KEYS,
3432 &hRootKey);
3433 if (rc != ERROR_SUCCESS)
3434 {
3435 SetLastError(rc);
3436 goto cleanup;
3437 }
3438 rc = RegOpenKeyExW(
3439 hRootKey,
3440 DriverKey,
3441 0, /* Options */
3442 samDesired,
3443 &hKey);
3444 if (rc != ERROR_SUCCESS)
3445 {
3446 SetLastError(rc);
3447 goto cleanup;
3448 }
3449 ret = hKey;
3450 }
3451 cleanup:
3452 if (hRootKey != INVALID_HANDLE_VALUE)
3453 RegCloseKey(hRootKey);
3454 if (hKey != INVALID_HANDLE_VALUE && hKey != ret)
3455 RegCloseKey(hKey);
3456 }
3457
3458 TRACE("Returning 0x%p\n", ret);
3459 return ret;
3460 }
3461
3462 /***********************************************************************
3463 * SetupDiCreateDeviceInfoA (SETUPAPI.@)
3464 */
3465 BOOL WINAPI SetupDiCreateDeviceInfoA(
3466 HDEVINFO DeviceInfoSet,
3467 PCSTR DeviceName,
3468 CONST GUID *ClassGuid,
3469 PCSTR DeviceDescription,
3470 HWND hwndParent,
3471 DWORD CreationFlags,
3472 PSP_DEVINFO_DATA DeviceInfoData)
3473 {
3474 LPWSTR DeviceNameW = NULL;
3475 LPWSTR DeviceDescriptionW = NULL;
3476 BOOL bResult;
3477
3478 TRACE("\n");
3479
3480 if (DeviceName)
3481 {
3482 DeviceNameW = MultiByteToUnicode(DeviceName, CP_ACP);
3483 if (DeviceNameW == NULL) return FALSE;
3484 }
3485 if (DeviceDescription)
3486 {
3487 DeviceDescriptionW = MultiByteToUnicode(DeviceDescription, CP_ACP);
3488 if (DeviceDescriptionW == NULL)
3489 {
3490 if (DeviceNameW) MyFree(DeviceNameW);
3491 return FALSE;
3492 }
3493 }
3494
3495 bResult = SetupDiCreateDeviceInfoW(DeviceInfoSet, DeviceNameW,
3496 ClassGuid, DeviceDescriptionW,
3497 hwndParent, CreationFlags,
3498 DeviceInfoData);
3499
3500 if (DeviceNameW) MyFree(DeviceNameW);
3501 if (DeviceDescriptionW) MyFree(DeviceDescriptionW);
3502
3503 return bResult;
3504 }
3505
3506 /***********************************************************************
3507 * SetupDiCreateDeviceInfoW (SETUPAPI.@)
3508 */
3509 BOOL WINAPI SetupDiCreateDeviceInfoW(
3510 HDEVINFO DeviceInfoSet,
3511 PCWSTR DeviceName,
3512 CONST GUID *ClassGuid,
3513 PCWSTR DeviceDescription,
3514 HWND hwndParent,
3515 DWORD CreationFlags,
3516 PSP_DEVINFO_DATA DeviceInfoData)
3517 {
3518 struct DeviceInfoSet *list;
3519 BOOL ret = FALSE;
3520
3521 TRACE("%p %S %s %S %p %lx %p\n", DeviceInfoSet, DeviceName,
3522 debugstr_guid(ClassGuid), DeviceDescription,
3523 hwndParent, CreationFlags, DeviceInfoData);
3524
3525 if (!DeviceInfoSet)
3526 SetLastError(ERROR_INVALID_HANDLE);
3527 else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
3528 SetLastError(ERROR_INVALID_HANDLE);
3529 else if (!ClassGuid)
3530 SetLastError(ERROR_INVALID_PARAMETER);
3531 else if (!IsEqualIID(&list->ClassGuid, &GUID_NULL) && !IsEqualIID(&list->ClassGuid, ClassGuid))
3532 SetLastError(ERROR_CLASS_MISMATCH);
3533 else if (CreationFlags & ~(DICD_GENERATE_ID | DICD_INHERIT_CLASSDRVS))
3534 {
3535 TRACE("Unknown flags: 0x%08lx\n", CreationFlags & ~(DICD_GENERATE_ID | DICD_INHERIT_CLASSDRVS));
3536 SetLastError(ERROR_INVALID_PARAMETER);
3537 }
3538 else
3539 {
3540 SP_DEVINFO_DATA DevInfo;
3541
3542 if (CreationFlags & DICD_GENERATE_ID)
3543 {
3544 /* Generate a new unique ID for this device */
3545 SetLastError(ERROR_GEN_FAILURE);
3546 FIXME("not implemented\n");
3547 }
3548 else
3549 {
3550 /* Device name is fully qualified. Try to open it */
3551 BOOL rc;
3552
3553 DevInfo.cbSize = sizeof(SP_DEVINFO_DATA);
3554 rc = SetupDiOpenDeviceInfoW(
3555 DeviceInfoSet,
3556 DeviceName,
3557 NULL, /* hwndParent */
3558 CreationFlags & DICD_INHERIT_CLASSDRVS ? DIOD_INHERIT_CLASSDRVS : 0,
3559 &DevInfo);
3560
3561 if (rc)
3562 {
3563 /* SetupDiOpenDeviceInfoW has already added
3564 * the device info to the device info set
3565 */
3566 SetLastError(ERROR_DEVINST_ALREADY_EXISTS);
3567 }
3568 else if (GetLastError() == ERROR_FILE_NOT_FOUND)
3569 {
3570 struct DeviceInfoElement *deviceInfo;
3571
3572 /* FIXME: ClassGuid can be NULL */
3573 if (CreateDeviceInfoElement(DeviceName, ClassGuid, &deviceInfo))
3574 {
3575 InsertTailList(&list->ListHead, &deviceInfo->ListEntry);
3576
3577 if (!DeviceInfoData)
3578 ret = TRUE;
3579 else
3580 {
3581 if (DeviceInfoData->cbSize != sizeof(PSP_DEVINFO_DATA))
3582 {
3583 SetLastError(ERROR_INVALID_USER_BUFFER);
3584 }
3585 else
3586 {
3587 memcpy(&DeviceInfoData->ClassGuid, ClassGuid, sizeof(GUID));
3588 DeviceInfoData->DevInst = 0; /* FIXME */
3589 DeviceInfoData->Reserved = (ULONG_PTR)deviceInfo;
3590 ret = TRUE;
3591 }
3592 }
3593 }
3594 }
3595 }
3596 }
3597
3598 TRACE("Returning %d\n", ret);
3599 return ret;
3600 }
3601
3602 /***********************************************************************
3603 * Helper functions for SetupDiBuildDriverInfoList
3604 */
3605 static BOOL
3606 AddDriverToList(
3607 IN PLIST_ENTRY DriverListHead,
3608 IN DWORD DriverType, /* SPDIT_CLASSDRIVER or SPDIT_COMPATDRIVER */
3609 IN LPGUID ClassGuid,
3610 IN INFCONTEXT ContextDevice,
3611 IN LPCWSTR InfFile,
3612 IN LPCWSTR ProviderName,
3613 IN LPCWSTR ManufacturerName,
3614 IN LPCWSTR MatchingId,
3615 FILETIME DriverDate,
3616 DWORDLONG DriverVersion,
3617 IN DWORD Rank)
3618 {
3619 struct DriverInfoElement *driverInfo = NULL;
3620 DWORD RequiredSize = 128; /* Initial buffer size */
3621 BOOL Result = FALSE;
3622 PLIST_ENTRY PreviousEntry;
3623 LPWSTR DeviceDescription = NULL;
3624 LPWSTR InfInstallSection = NULL;
3625 BOOL ret = FALSE;
3626
3627 driverInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(struct DriverInfoElement));
3628 if (!driverInfo)
3629 {
3630 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3631 goto cleanup;
3632 }
3633 memset(driverInfo, 0, sizeof(struct DriverInfoElement));
3634
3635 /* Fill InfSection field */
3636 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3637 while (!Result && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
3638 {
3639 HeapFree(GetProcessHeap(), 0, driverInfo->InfSection);
3640 driverInfo->InfSection = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
3641 if (!driverInfo->InfSection)
3642 {
3643 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3644 goto cleanup;
3645 }
3646 Result = SetupGetStringFieldW(
3647 &ContextDevice,
3648 1,
3649 driverInfo->InfSection, RequiredSize,
3650 &RequiredSize);
3651 }
3652 if (!Result)
3653 goto cleanup;
3654
3655 /* Copy InfFile information */
3656 driverInfo->InfPath = HeapAlloc(GetProcessHeap(), 0, (wcslen(InfFile) + 1) * sizeof(WCHAR));
3657 if (!driverInfo->InfPath)
3658 {
3659 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3660 goto cleanup;
3661 }
3662 RtlCopyMemory(driverInfo->InfPath, InfFile, (wcslen(InfFile) + 1) * sizeof(WCHAR));
3663
3664 /* Copy MatchingId information */
3665 driverInfo->MatchingId = HeapAlloc(GetProcessHeap(), 0, (wcslen(MatchingId) + 1) * sizeof(WCHAR));
3666 if (!driverInfo->MatchingId)
3667 {
3668 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3669 goto cleanup;
3670 }
3671 RtlCopyMemory(driverInfo->MatchingId, MatchingId, (wcslen(MatchingId) + 1) * sizeof(WCHAR));
3672
3673 /* Get device description */
3674 Result = FALSE;
3675 RequiredSize = 128; /* Initial buffer size */
3676 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3677 while (!Result && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
3678 {
3679 HeapFree(GetProcessHeap(), 0, DeviceDescription);
3680 DeviceDescription = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
3681 if (!DeviceDescription)
3682 goto cleanup;
3683 Result = SetupGetStringFieldW(
3684 &ContextDevice,
3685 0, /* Field index */
3686 DeviceDescription, RequiredSize,
3687 &RequiredSize);
3688 }
3689 if (!Result)
3690 goto cleanup;
3691
3692 /* Get inf install section */
3693 Result = FALSE;
3694 RequiredSize = 128; /* Initial buffer size */
3695 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3696 while (!Result && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
3697 {
3698 HeapFree(GetProcessHeap(), 0, InfInstallSection);
3699 InfInstallSection = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
3700 if (!InfInstallSection)
3701 goto cleanup;
3702 Result = SetupGetStringFieldW(
3703 &ContextDevice,
3704 1, /* Field index */
3705 InfInstallSection, RequiredSize,
3706 &RequiredSize);
3707 }
3708 if (!Result)
3709 goto cleanup;
3710
3711 TRACE("Adding driver '%S' [%S/%S] (Rank 0x%lx)\n",
3712 DeviceDescription, InfFile, InfInstallSection, Rank);
3713
3714 driverInfo->DriverRank = Rank;
3715 memcpy(&driverInfo->ClassGuid, ClassGuid, sizeof(GUID));
3716 driverInfo->Info.DriverType = DriverType;
3717 driverInfo->Info.Reserved = (ULONG_PTR)driverInfo;
3718 wcsncpy(driverInfo->Info.Description, DeviceDescription, LINE_LEN - 1);
3719 driverInfo->Info.Description[LINE_LEN - 1] = '\0';
3720 wcsncpy(driverInfo->Info.MfgName, ManufacturerName, LINE_LEN - 1);
3721 driverInfo->Info.MfgName[LINE_LEN - 1] = '\0';
3722 if (ProviderName)
3723 {
3724 wcsncpy(driverInfo->Info.ProviderName, ProviderName, LINE_LEN - 1);
3725 driverInfo->Info.ProviderName[LINE_LEN - 1] = '\0';
3726 }
3727 else
3728 driverInfo->Info.ProviderName[0] = '\0';
3729 driverInfo->Info.DriverDate = DriverDate;
3730 driverInfo->Info.DriverVersion = DriverVersion;
3731
3732 /* Insert current driver in driver list, according to its rank */
3733 PreviousEntry = DriverListHead->Flink;
3734 while (PreviousEntry != DriverListHead)
3735 {
3736 if (((struct DriverInfoElement *)PreviousEntry)->DriverRank >= Rank)
3737 {
3738 /* Insert before the current item */
3739 InsertHeadList(PreviousEntry, &driverInfo->ListEntry);
3740 break;
3741 }
3742 }
3743 if (PreviousEntry == DriverListHead)
3744 {
3745 /* Insert at the end of the list */
3746 InsertTailList(DriverListHead, &driverInfo->ListEntry);
3747 }
3748
3749 ret = TRUE;
3750
3751 cleanup:
3752 if (!ret)
3753 {
3754 if (driverInfo)
3755 {
3756 HeapFree(GetProcessHeap(), 0, driverInfo->InfPath);
3757 HeapFree(GetProcessHeap(), 0, driverInfo->InfSection);
3758 HeapFree(GetProcessHeap(), 0, driverInfo->MatchingId);
3759 }
3760 HeapFree(GetProcessHeap(), 0, driverInfo);
3761 }
3762 HeapFree(GetProcessHeap(), 0, DeviceDescription);
3763 HeapFree(GetProcessHeap(), 0, InfInstallSection);
3764
3765 return ret;
3766 }
3767
3768 static BOOL
3769 GetVersionInformationFromInfFile(
3770 IN HINF hInf,
3771 OUT LPGUID ClassGuid,
3772 OUT LPWSTR* pProviderName,
3773 OUT FILETIME* DriverDate,
3774 OUT DWORDLONG* DriverVersion)
3775 {
3776 DWORD RequiredSize;
3777 WCHAR guidW[MAX_GUID_STRING_LEN + 1];
3778 LPWSTR DriverVer = NULL;
3779 LPWSTR ProviderName = NULL;
3780 LPWSTR pComma; /* Points into DriverVer */
3781 LPWSTR pVersion = NULL; /* Points into DriverVer */
3782 SYSTEMTIME SystemTime;
3783 BOOL Result;
3784 BOOL ret = FALSE; /* Final result */
3785
3786 /* Get class Guid */
3787 if (!SetupGetLineTextW(
3788 NULL, /* Context */
3789 hInf,
3790 L"Version", L"ClassGUID",
3791 guidW, sizeof(guidW),
3792 NULL /* Required size */))
3793 {
3794 goto cleanup;
3795 }
3796 guidW[37] = '\0'; /* Replace the } by a NULL character */
3797 if (UuidFromStringW(&guidW[1], ClassGuid) != RPC_S_OK)
3798 {
3799 SetLastError(ERROR_GEN_FAILURE);
3800 goto cleanup;
3801 }
3802
3803 /* Get provider name */
3804 Result = SetupGetLineTextW(
3805 NULL, /* Context */
3806 hInf, L"Version", L"Provider",
3807 NULL, 0,
3808 &RequiredSize);
3809 if (Result)
3810 {
3811 /* We know know the needed buffer size */
3812 ProviderName = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
3813 if (!ProviderName)
3814 {
3815 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3816 goto cleanup;
3817 }
3818 Result = SetupGetLineTextW(
3819 NULL, /* Context */
3820 hInf, L"Version", L"Provider",
3821 ProviderName, RequiredSize,
3822 &RequiredSize);
3823 }
3824 if (!Result)
3825 goto cleanup;
3826 *pProviderName = ProviderName;
3827
3828 /* Read the "DriverVer" value */
3829 Result = SetupGetLineTextW(
3830 NULL, /* Context */
3831 hInf, L"Version", L"DriverVer",
3832 NULL, 0,
3833 &RequiredSize);
3834 if (Result)
3835 {
3836 /* We know know the needed buffer size */
3837 DriverVer = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
3838 if (!DriverVer)
3839 {
3840 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3841 goto cleanup;
3842 }
3843 Result = SetupGetLineTextW(
3844 NULL, /* Context */
3845 hInf, L"Version", L"DriverVer",
3846 DriverVer, RequiredSize,
3847 &RequiredSize);
3848 }
3849 if (!Result)
3850 goto cleanup;
3851
3852 /* Get driver date and driver version, by analyzing the "DriverVer" value */
3853 pComma = wcschr(DriverVer, ',');
3854 if (pComma != NULL)
3855 {
3856 *pComma = UNICODE_NULL;
3857 pVersion = pComma + 1;
3858 }
3859 /* Get driver date version. Invalid date = 00/00/00 */
3860 memset(DriverDate, 0, sizeof(FILETIME));
3861 if (wcslen(DriverVer) == 10
3862 && (DriverVer[2] == '-' || DriverVer[2] == '/')
3863 && (DriverVer[5] == '-' || DriverVer[5] == '/'))
3864 {
3865 memset(&SystemTime, 0, sizeof(SYSTEMTIME));
3866 DriverVer[2] = DriverVer[5] = UNICODE_NULL;
3867 SystemTime.wMonth = ((DriverVer[0] - '0') * 10) + DriverVer[1] - '0';
3868 SystemTime.wDay = ((DriverVer[3] - '0') * 10) + DriverVer[4] - '0';
3869 SystemTime.wYear = ((DriverVer[6] - '0') * 1000) + ((DriverVer[7] - '0') * 100) + ((DriverVer[8] - '0') * 10) + DriverVer[9] - '0';
3870 SystemTimeToFileTime(&SystemTime, DriverDate);
3871 }
3872 /* Get driver version. Invalid version = 0.0.0.0 */
3873 *DriverVersion = 0;
3874 /* FIXME: use pVersion to fill DriverVersion variable */
3875
3876 ret = TRUE;
3877
3878 cleanup:
3879 if (!ret)
3880 HeapFree(GetProcessHeap(), 0, ProviderName);
3881 HeapFree(GetProcessHeap(), 0, DriverVer);
3882
3883 TRACE("Returning %d\n", ret);
3884 return ret;
3885 }
3886
3887 /***********************************************************************
3888 * SetupDiBuildDriverInfoList (SETUPAPI.@)
3889 */
3890 BOOL WINAPI
3891 SetupDiBuildDriverInfoList(
3892 IN HDEVINFO DeviceInfoSet,
3893 IN OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
3894 IN DWORD DriverType)
3895 {
3896 struct DeviceInfoSet *list;
3897 PVOID Buffer = NULL;
3898 HINF hInf = INVALID_HANDLE_VALUE;
3899 LPWSTR ProviderName = NULL;
3900 LPWSTR ManufacturerName = NULL;
3901 LPWSTR ManufacturerSection = NULL;
3902 LPWSTR HardwareIDs = NULL;
3903 LPWSTR CompatibleIDs = NULL;
3904 FILETIME DriverDate;
3905 DWORDLONG DriverVersion = 0;
3906 DWORD RequiredSize;
3907 BOOL ret = FALSE;
3908
3909 TRACE("%p %p %ld\n", DeviceInfoSet, DeviceInfoData, DriverType);
3910
3911 if (!DeviceInfoSet)
3912 SetLastError(ERROR_INVALID_HANDLE);
3913 else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
3914 SetLastError(ERROR_INVALID_HANDLE);
3915 else if (list->HKLM != HKEY_LOCAL_MACHINE)
3916 SetLastError(ERROR_INVALID_HANDLE);
3917 else if (DriverType != SPDIT_CLASSDRIVER && DriverType != SPDIT_COMPATDRIVER)
3918 SetLastError(ERROR_INVALID_PARAMETER);
3919 else if (DriverType == SPDIT_CLASSDRIVER && DeviceInfoData)
3920 SetLastError(ERROR_INVALID_PARAMETER);
3921 else if (DriverType == SPDIT_COMPATDRIVER && !DeviceInfoData)
3922 SetLastError(ERROR_INVALID_PARAMETER);
3923 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
3924 SetLastError(ERROR_INVALID_USER_BUFFER);
3925 else
3926 {
3927 BOOL Result = FALSE;
3928
3929 if (DriverType == SPDIT_COMPATDRIVER)
3930 {
3931 /* Get hardware IDs list */
3932 Result = FALSE;
3933 RequiredSize = 512; /* Initial buffer size */
3934 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3935 while (!Result && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
3936 {
3937 HeapFree(GetProcessHeap(), 0, HardwareIDs);
3938 HardwareIDs = HeapAlloc(GetProcessHeap(), 0, RequiredSize);
3939 if (!HardwareIDs)
3940 {
3941 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3942 goto done;
3943 }
3944 Result = SetupDiGetDeviceRegistryPropertyW(
3945 DeviceInfoSet,
3946 DeviceInfoData,
3947 SPDRP_HARDWAREID,
3948 NULL,
3949 (PBYTE)HardwareIDs,
3950 RequiredSize,
3951 &RequiredSize);
3952 }
3953 if (!Result)
3954 goto done;
3955
3956 /* Get compatible IDs list */
3957 Result = FALSE;
3958 RequiredSize = 512; /* Initial buffer size */
3959 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3960 while (!Result && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
3961 {
3962 HeapFree(GetProcessHeap(), 0, CompatibleIDs);
3963 CompatibleIDs = HeapAlloc(GetProcessHeap(), 0, RequiredSize);
3964 if (!CompatibleIDs)
3965 {
3966 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3967 goto done;
3968 }
3969 Result = SetupDiGetDeviceRegistryPropertyW(
3970 DeviceInfoSet,
3971 DeviceInfoData,
3972 SPDRP_COMPATIBLEIDS,
3973 NULL,
3974 (PBYTE)CompatibleIDs,
3975 RequiredSize,
3976 &RequiredSize);
3977 if (!Result && GetLastError() == ERROR_FILE_NOT_FOUND)
3978 {
3979 /* No compatible ID for this device */
3980 HeapFree(GetProcessHeap(), 0, CompatibleIDs);
3981 CompatibleIDs = NULL;
3982 Result = TRUE;
3983 }
3984 }
3985 if (!Result)
3986 goto done;
3987 }
3988
3989 /* Enumerate .inf files */
3990 Result = FALSE;
3991 RequiredSize = 32768; /* Initial buffer size */
3992 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3993 while (!Result && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
3994 {
3995 HeapFree(GetProcessHeap(), 0, Buffer);
3996 Buffer = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
3997 if (!Buffer)
3998 {
3999 Result = FALSE;
4000 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
4001 break;
4002 }
4003 Result = SetupGetInfFileListW(
4004 NULL, /* Directory path */
4005 INF_STYLE_WIN4,
4006 Buffer, RequiredSize,
4007 &RequiredSize);
4008 }
4009 if (Result)
4010 {
4011 LPCWSTR filename;
4012
4013 for (filename = (LPCWSTR)Buffer; *filename; filename += wcslen(filename) + 1)
4014 {
4015 INFCONTEXT ContextManufacturer, ContextDevice;
4016 GUID ClassGuid;
4017 TRACE("Opening file %S\n", filename);
4018
4019 hInf = SetupOpenInfFileW(filename, NULL, INF_STYLE_WIN4, NULL);
4020 if (hInf == INVALID_HANDLE_VALUE)
4021 continue;
4022
4023 if (!GetVersionInformationFromInfFile(
4024 hInf,
4025 &ClassGuid,
4026 &ProviderName,
4027 &DriverDate,
4028 &DriverVersion))
4029 {
4030 SetupCloseInfFile(hInf);
4031 hInf = INVALID_HANDLE_VALUE;
4032 continue;
4033 }
4034
4035 if (DriverType == SPDIT_CLASSDRIVER)
4036 {
4037 /* Check if the ClassGuid in this .inf file is corresponding with our needs */
4038 if (!IsEqualIID(&list->ClassGuid, &GUID_NULL) && !IsEqualIID(&list->ClassGuid, &ClassGuid))
4039 {
4040 goto next;
4041 }
4042 }
4043
4044 /* Get the manufacturers list */
4045 Result = SetupFindFirstLineW(hInf, L"Manufacturer", NULL, &ContextManufacturer);
4046 while (Result)
4047 {
4048 Result = SetupGetStringFieldW(
4049 &ContextManufacturer,
4050 0, /* Field index */
4051 NULL, 0,
4052 &RequiredSize);
4053 if (Result)
4054 {
4055 /* We got the needed size for the buffer */
4056 ManufacturerName = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
4057 if (!ManufacturerName)
4058 {
4059 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
4060 goto done;
4061 }
4062 Result = SetupGetStringFieldW(
4063 &ContextManufacturer,
4064 0, /* Field index */
4065 ManufacturerName, RequiredSize,
4066 &RequiredSize);
4067 }
4068 Result = SetupGetStringFieldW(
4069 &ContextManufacturer,
4070 1, /* Field index */
4071 NULL, 0,
4072 &RequiredSize);
4073 if (Result)
4074 {
4075 /* We got the needed size for the buffer */
4076 ManufacturerSection = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
4077 if (!ManufacturerSection)
4078 {
4079 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
4080 goto done;
4081 }
4082 Result = SetupGetStringFieldW(
4083 &ContextManufacturer,
4084 1, /* Field index */
4085 ManufacturerSection, RequiredSize,
4086 &RequiredSize);
4087 }
4088
4089 TRACE("Enumerating devices in manufacturer %S\n", ManufacturerSection);
4090 Result = SetupFindFirstLineW(hInf, ManufacturerSection, NULL, &ContextDevice);
4091 while (Result)
4092 {
4093 if (DriverType == SPDIT_CLASSDRIVER)
4094 {
4095 /* FIXME: read [ControlFlags] / ExcludeFromSelect */
4096 if (!AddDriverToList(
4097 &list->DriverListHead,
4098 DriverType,
4099 &ClassGuid,
4100 ContextDevice,
4101 filename,
4102 ProviderName,
4103 ManufacturerName,
4104 NULL,
4105 DriverDate, DriverVersion,
4106 0))
4107 {
4108 break;
4109 }
4110 }
4111 else /* DriverType = SPDIT_COMPATDRIVER */
4112 {
4113 /* 1. Get all fields */
4114 DWORD FieldCount = SetupGetFieldCount(&ContextDevice);
4115 DWORD DriverRank;
4116 DWORD i;
4117 LPCWSTR currentId;
4118 BOOL DriverAlreadyAdded;
4119
4120 for (i = 2; i <= FieldCount; i++)
4121 {
4122 LPWSTR DeviceId = NULL;
4123 Result = FALSE;
4124 RequiredSize = 128; /* Initial buffer size */
4125 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4126 while (!Result && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
4127 {
4128 HeapFree(GetProcessHeap(), 0, DeviceId);
4129 DeviceId = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
4130 if (!DeviceId)
4131 {
4132 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
4133 goto done;
4134 }
4135 Result = SetupGetStringFieldW(
4136 &ContextDevice,
4137 i,
4138 DeviceId, RequiredSize,
4139 &RequiredSize);
4140 }
4141 if (!Result)
4142 {
4143 HeapFree(GetProcessHeap(), 0, DeviceId);
4144 goto done;
4145 }
4146 DriverAlreadyAdded = FALSE;
4147 for (DriverRank = 0, currentId = (LPCWSTR)HardwareIDs; !DriverAlreadyAdded && *currentId; currentId += wcslen(currentId) + 1, DriverRank++)
4148 {
4149 if (wcscmp(DeviceId, currentId) == 0)
4150 {
4151 AddDriverToList(
4152 &((struct DeviceInfoElement *)DeviceInfoData->Reserved)->DriverListHead,
4153 DriverType,
4154 &ClassGuid,
4155 ContextDevice,
4156 filename,
4157 ProviderName,
4158 ManufacturerName,
4159 currentId,
4160 DriverDate, DriverVersion,
4161 DriverRank + (i == 2 ? 0 : 0x1000 + i - 3));
4162 DriverAlreadyAdded = TRUE;
4163 }
4164 }
4165 if (CompatibleIDs)
4166 {
4167 for (DriverRank = 0, currentId = (LPCWSTR)CompatibleIDs; !DriverAlreadyAdded && *currentId; currentId += wcslen(currentId) + 1, DriverRank++)
4168 {
4169 if (wcscmp(DeviceId, currentId) == 0)
4170 {
4171 AddDriverToList(
4172 &((struct DeviceInfoElement *)DeviceInfoData->Reserved)->DriverListHead,
4173 DriverType,
4174 &ClassGuid,
4175 ContextDevice,
4176 filename,
4177 ProviderName,
4178 ManufacturerName,
4179 currentId,
4180 DriverDate, DriverVersion,
4181 DriverRank + (i == 2 ? 0x2000 : 0x3000 + i - 3));
4182 DriverAlreadyAdded = TRUE;
4183 }
4184 }
4185 }
4186 HeapFree(GetProcessHeap(), 0, DeviceId);
4187 }
4188 }
4189 Result = SetupFindNextLine(&ContextDevice, &ContextDevice);
4190 }
4191
4192 HeapFree(GetProcessHeap(), 0, ManufacturerName);
4193 HeapFree(GetProcessHeap(), 0, ManufacturerSection);
4194 ManufacturerName = ManufacturerSection = NULL;
4195 Result = SetupFindNextLine(&ContextManufacturer, &ContextManufacturer);
4196 }
4197
4198 ret = TRUE;
4199 next:
4200 HeapFree(GetProcessHeap(), 0, ProviderName);
4201 ProviderName = NULL;
4202
4203 SetupCloseInfFile(hInf);
4204 hInf = INVALID_HANDLE_VALUE;
4205 }
4206 ret = TRUE;
4207 }
4208 }
4209
4210 done:
4211 if (ret)
4212 {
4213 if (DeviceInfoData)
4214 {
4215 struct DeviceInfoElement *deviceInfo = (struct DeviceInfoElement *)DeviceInfoData->Reserved;
4216 deviceInfo->Flags |= DI_DIDCOMPAT;
4217 }
4218 else
4219 list->Flags |= DI_DIDCLASS;
4220 }
4221
4222 HeapFree(GetProcessHeap(), 0, ProviderName);
4223 HeapFree(GetProcessHeap(), 0, ManufacturerName);
4224 HeapFree(GetProcessHeap(), 0, ManufacturerSection);
4225 HeapFree(GetProcessHeap(), 0, HardwareIDs);
4226 HeapFree(GetProcessHeap(), 0, CompatibleIDs);
4227 if (hInf != INVALID_HANDLE_VALUE)
4228 SetupCloseInfFile(hInf);
4229 HeapFree(GetProcessHeap(), 0, Buffer);
4230
4231 TRACE("Returning %d\n", ret);
4232 return ret;
4233 }
4234
4235 /***********************************************************************
4236 * SetupDiDeleteDeviceInfo (SETUPAPI.@)
4237 */
4238 BOOL WINAPI
4239 SetupDiDeleteDeviceInfo(
4240 IN HDEVINFO DeviceInfoSet,
4241 IN PSP_DEVINFO_DATA DeviceInfoData)
4242 {
4243 TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
4244
4245 FIXME("not implemented\n");
4246 SetLastError(ERROR_GEN_FAILURE);
4247 return FALSE;
4248 }
4249
4250
4251 /***********************************************************************
4252 * SetupDiDestroyDriverInfoList (SETUPAPI.@)
4253 */
4254 BOOL WINAPI
4255 SetupDiDestroyDriverInfoList(
4256 IN HDEVINFO DeviceInfoSet,
4257 IN PSP_DEVINFO_DATA DeviceInfoData,
4258 IN DWORD DriverType)
4259 {
4260 TRACE("%p %p 0x%lx\n", DeviceInfoSet, DeviceInfoData, DriverType);
4261
4262 FIXME("not implemented\n");
4263 SetLastError(ERROR_GEN_FAILURE);
4264 return FALSE;
4265 }
4266
4267
4268 /***********************************************************************
4269 * SetupDiOpenDeviceInfoA (SETUPAPI.@)
4270 */
4271 BOOL WINAPI
4272 SetupDiOpenDeviceInfoA(
4273 IN HDEVINFO DeviceInfoSet,
4274 IN PCSTR DeviceInstanceId,
4275 IN HWND hwndParent OPTIONAL,
4276 IN DWORD OpenFlags,
4277 OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
4278 {
4279 LPWSTR DeviceInstanceIdW = NULL;
4280 BOOL bResult;
4281
4282 TRACE("%p %s %p %lx %p\n", DeviceInfoSet, DeviceInstanceId, hwndParent, OpenFlags, DeviceInfoData);
4283
4284 DeviceInstanceIdW = MultiByteToUnicode(DeviceInstanceId, CP_ACP);
4285 if (DeviceInstanceIdW == NULL)
4286 return FALSE;
4287
4288 bResult = SetupDiOpenDeviceInfoW(DeviceInfoSet,
4289 DeviceInstanceIdW, hwndParent, OpenFlags, DeviceInfoData);
4290
4291 MyFree(DeviceInstanceIdW);
4292
4293 return bResult;
4294 }
4295
4296
4297 /***********************************************************************
4298 * SetupDiOpenDeviceInfoW (SETUPAPI.@)
4299 */
4300 BOOL WINAPI
4301 SetupDiOpenDeviceInfoW(
4302 IN HDEVINFO DeviceInfoSet,
4303 IN PCWSTR DeviceInstanceId,
4304 IN HWND hwndParent OPTIONAL,
4305 IN DWORD OpenFlags,
4306 OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
4307 {
4308 struct DeviceInfoSet *list;
4309 HKEY hEnumKey, hKey;
4310 DWORD rc;
4311 BOOL ret = FALSE;
4312
4313 TRACE("%p %S %p %lx %p\n", DeviceInfoSet, DeviceInstanceId, hwndParent, OpenFlags, DeviceInfoData);
4314
4315 if (OpenFlags & DIOD_CANCEL_REMOVE)
4316 FIXME("DIOD_CANCEL_REMOVE flag not implemented\n");
4317
4318 if (!DeviceInfoSet)
4319 SetLastError(ERROR_INVALID_HANDLE);
4320 else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
4321 SetLastError(ERROR_INVALID_HANDLE);
4322 else if (!DeviceInstanceId)
4323 SetLastError(ERROR_INVALID_PARAMETER);
4324 else if (OpenFlags & ~(DIOD_CANCEL_REMOVE | DIOD_INHERIT_CLASSDRVS))
4325 {
4326 TRACE("Unknown flags: 0x%08lx\n", OpenFlags & ~(DIOD_CANCEL_REMOVE | DIOD_INHERIT_CLASSDRVS));
4327 SetLastError(ERROR_INVALID_PARAMETER);
4328 }
4329 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
4330 SetLastError(ERROR_INVALID_USER_BUFFER);
4331 else
4332 {
4333 struct DeviceInfoElement *deviceInfo = NULL;
4334 /* Search if device already exists in DeviceInfoSet.
4335 * If yes, return the existing element
4336 * If no, create a new element using informations in registry
4337 */
4338 PLIST_ENTRY ItemList = list->ListHead.Flink;
4339 while (ItemList != &list->ListHead)
4340 {
4341 // TODO
4342 //if (good one)
4343 // break;
4344 FIXME("not implemented\n");
4345 ItemList = ItemList->Flink;
4346 }
4347
4348 if (deviceInfo)
4349 {
4350 /* good one found */
4351 ret = TRUE;
4352 }
4353 else
4354 {
4355 /* Open supposed registry key */
4356 rc = RegOpenKeyExW(
4357 list->HKLM,
4358 EnumKeyName,
4359 0, /* Options */
4360 KEY_ENUMERATE_SUB_KEYS,
4361 &hEnumKey);
4362 if (rc != ERROR_SUCCESS)
4363 {
4364 SetLastError(rc);
4365 return FALSE;
4366 }
4367 rc = RegOpenKeyExW(
4368 hEnumKey,
4369 DeviceInstanceId,
4370 0, /* Options */
4371 KEY_QUERY_VALUE,
4372 &hKey);
4373 RegCloseKey(hEnumKey);
4374 if (rc != ERROR_SUCCESS)
4375 {
4376 SetLastError(rc);
4377 return FALSE;
4378 }
4379
4380 /* FIXME: GUID_NULL is not allowed */
4381 if (!CreateDeviceInfoElement(DeviceInstanceId, &GUID_NULL /* FIXME */, &deviceInfo))
4382 {
4383 RegCloseKey(hKey);
4384 return FALSE;
4385 }
4386 InsertTailList(&list->ListHead, &deviceInfo->ListEntry);
4387
4388 RegCloseKey(hKey);
4389 ret = TRUE;
4390 }
4391
4392 if (ret && deviceInfo && DeviceInfoData)
4393 {
4394 memcpy(&DeviceInfoData->ClassGuid, &deviceInfo->ClassGuid, sizeof(GUID));
4395 DeviceInfoData->DevInst = 0; /* FIXME */
4396 DeviceInfoData->Reserved = (ULONG_PTR)deviceInfo;
4397 }
4398 }
4399
4400 return ret;
4401 }
4402
4403
4404 /***********************************************************************
4405 * SetupDiEnumDriverInfoA (SETUPAPI.@)
4406 */
4407 BOOL WINAPI
4408 SetupDiEnumDriverInfoA(
4409 IN HDEVINFO DeviceInfoSet,
4410 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
4411 IN DWORD DriverType,
4412 IN DWORD MemberIndex,
4413 OUT PSP_DRVINFO_DATA_A DriverInfoData)
4414 {
4415 SP_DRVINFO_DATA_V2_W driverInfoData2W;
4416 BOOL ret = FALSE;
4417
4418 TRACE("%p %p 0x%lx %ld %p\n", DeviceInfoSet, DeviceInfoData,
4419 DriverType, MemberIndex, DriverInfoData);
4420
4421 if (DriverInfoData == NULL)
4422 SetLastError(ERROR_INVALID_PARAMETER);
4423 else if (DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V1_A) && DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V2_A))
4424 SetLastError(ERROR_INVALID_USER_BUFFER);
4425 else
4426 {
4427 driverInfoData2W.cbSize = sizeof(SP_DRVINFO_DATA_V2_W);
4428 ret = SetupDiEnumDriverInfoW(DeviceInfoSet, DeviceInfoData,
4429 DriverType, MemberIndex, &driverInfoData2W);
4430
4431 if (ret)
4432 {
4433 /* Do W->A conversion */
4434 DriverInfoData->DriverType = driverInfoData2W.DriverType;
4435 DriverInfoData->Reserved = driverInfoData2W.Reserved;
4436 if (WideCharToMultiByte(CP_ACP, 0, driverInfoData2W.Description, -1,
4437 DriverInfoData->Description, LINE_LEN, NULL, NULL) == 0)
4438 {
4439 DriverInfoData->Description[0] = '\0';
4440 ret = FALSE;
4441 }
4442 if (WideCharToMultiByte(CP_ACP, 0, driverInfoData2W.MfgName, -1,
4443 DriverInfoData->MfgName, LINE_LEN, NULL, NULL) == 0)
4444 {
4445 DriverInfoData->MfgName[0] = '\0';
4446 ret = FALSE;
4447 }
4448 if (WideCharToMultiByte(CP_ACP, 0, driverInfoData2W.ProviderName, -1,
4449 DriverInfoData->ProviderName, LINE_LEN, NULL, NULL) == 0)
4450 {
4451 DriverInfoData->ProviderName[0] = '\0';
4452 ret = FALSE;
4453 }
4454 if (DriverInfoData->cbSize == sizeof(SP_DRVINFO_DATA_V2_A))
4455 {
4456 /* Copy more fields */
4457 DriverInfoData->DriverDate = driverInfoData2W.DriverDate;
4458 DriverInfoData->DriverVersion = driverInfoData2W.DriverVersion;
4459 }
4460 }
4461 }
4462
4463 TRACE("Returning %d\n", ret);
4464 return ret;
4465 }
4466
4467
4468 /***********************************************************************
4469 * SetupDiEnumDriverInfoW (SETUPAPI.@)
4470 */
4471 BOOL WINAPI
4472 SetupDiEnumDriverInfoW(
4473 IN HDEVINFO DeviceInfoSet,
4474 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
4475 IN DWORD DriverType,
4476 IN DWORD MemberIndex,
4477 OUT PSP_DRVINFO_DATA_W DriverInfoData)
4478 {
4479 PLIST_ENTRY ListHead;
4480 BOOL ret = FALSE;
4481
4482 TRACE("%p %p 0x%lx %ld %p\n", DeviceInfoSet, DeviceInfoData,
4483 DriverType, MemberIndex, DriverInfoData);
4484
4485 if (!DeviceInfoSet || !DriverInfoData)
4486 SetLastError(ERROR_INVALID_PARAMETER);
4487 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
4488 SetLastError(ERROR_INVALID_HANDLE);
4489 else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
4490 SetLastError(ERROR_INVALID_HANDLE);
4491 else if (DriverType != SPDIT_CLASSDRIVER && DriverType != SPDIT_COMPATDRIVER)
4492 SetLastError(ERROR_INVALID_PARAMETER);
4493 else if (DriverType == SPDIT_CLASSDRIVER && DeviceInfoData)
4494 SetLastError(ERROR_INVALID_PARAMETER);
4495 else if (DriverType == SPDIT_COMPATDRIVER && !DeviceInfoData)
4496 SetLastError(ERROR_INVALID_PARAMETER);
4497 else if (DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V1_W) && DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V2_W))
4498 SetLastError(ERROR_INVALID_USER_BUFFER);
4499 else
4500 {
4501 struct DeviceInfoElement *devInfo = (struct DeviceInfoElement *)DeviceInfoData->Reserved;
4502 PLIST_ENTRY ItemList;
4503 if (DriverType == SPDIT_CLASSDRIVER ||
4504 devInfo->CreationFlags & DICD_INHERIT_CLASSDRVS)
4505 {
4506 ListHead = &((struct DeviceInfoSet *)DeviceInfoSet)->DriverListHead;
4507 }
4508 else
4509 {
4510 ListHead = &devInfo->DriverListHead;
4511 }
4512
4513 ItemList = ListHead->Flink;
4514 while (ItemList != ListHead && MemberIndex-- > 0)
4515 ItemList = ItemList->Flink;
4516 if (ItemList == ListHead)
4517 SetLastError(ERROR_NO_MORE_ITEMS);
4518 else
4519 {
4520 struct DriverInfoElement *DrvInfo = (struct DriverInfoElement *)ItemList;
4521
4522 memcpy(
4523 &DriverInfoData->DriverType,
4524 &DrvInfo->Info.DriverType,
4525 DriverInfoData->cbSize - FIELD_OFFSET(SP_DRVINFO_DATA_W, DriverType));
4526 ret = TRUE;
4527 }
4528 }
4529
4530 TRACE("Returning %d\n", ret);
4531 return ret;
4532 }
4533
4534 /***********************************************************************
4535 * SetupDiGetSelectedDriverW (SETUPAPI.@)
4536 */
4537 BOOL WINAPI
4538 SetupDiGetSelectedDriverW(
4539 IN HDEVINFO DeviceInfoSet,
4540 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
4541 OUT PSP_DRVINFO_DATA_W DriverInfoData)
4542 {
4543 BOOL ret = FALSE;
4544
4545 TRACE("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DriverInfoData);
4546
4547 if (!DeviceInfoSet || !DriverInfoData)
4548 SetLastError(ERROR_INVALID_PARAMETER);
4549 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
4550 SetLastError(ERROR_INVALID_HANDLE);
4551 else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
4552 SetLastError(ERROR_INVALID_HANDLE);
4553 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
4554 SetLastError(ERROR_INVALID_USER_BUFFER);
4555 else if (DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V1_W) && DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V2_W))
4556 SetLastError(ERROR_INVALID_USER_BUFFER);
4557 else
4558 {
4559 struct DriverInfoElement *driverInfo;
4560
4561 if (DeviceInfoData)
4562 driverInfo = ((struct DeviceInfoElement *)DeviceInfoData->Reserved)->SelectedDriver;
4563 else
4564 driverInfo = ((struct DeviceInfoSet *)DeviceInfoSet)->SelectedDriver;
4565
4566 if (driverInfo == NULL)
4567 SetLastError(ERROR_NO_DRIVER_SELECTED);
4568 else
4569 {
4570 memcpy(
4571 &DriverInfoData->DriverType,
4572 &driverInfo->Info.DriverType,
4573 DriverInfoData->cbSize - FIELD_OFFSET(SP_DRVINFO_DATA_W, DriverType));
4574 ret = TRUE;
4575 }
4576 }
4577
4578 TRACE("Returning %d\n", ret);
4579 return ret;
4580 }
4581
4582 /***********************************************************************
4583 * SetupDiSetSelectedDriverW (SETUPAPI.@)
4584 */
4585 BOOL WINAPI
4586 SetupDiSetSelectedDriverW(
4587 IN HDEVINFO DeviceInfoSet,
4588 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
4589 IN OUT PSP_DRVINFO_DATA_W DriverInfoData OPTIONAL)
4590 {
4591 BOOL ret = FALSE;
4592
4593 TRACE("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DriverInfoData);
4594
4595 if (!DeviceInfoSet)
4596 SetLastError(ERROR_INVALID_PARAMETER);
4597 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
4598 SetLastError(ERROR_INVALID_HANDLE);
4599 else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
4600 SetLastError(ERROR_INVALID_HANDLE);
4601 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
4602 SetLastError(ERROR_INVALID_USER_BUFFER);
4603 else if (DriverInfoData && DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V1_W) && DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V2_W))
4604 SetLastError(ERROR_INVALID_USER_BUFFER);
4605 else
4606 {
4607 struct DriverInfoElement **pDriverInfo;
4608 PLIST_ENTRY ListHead, ItemList;
4609
4610 if (DeviceInfoData)
4611 {
4612 pDriverInfo = &((struct DeviceInfoElement *)DeviceInfoData->Reserved)->SelectedDriver;
4613 ListHead = &((struct DeviceInfoElement *)DeviceInfoData->Reserved)->DriverListHead;
4614 }
4615 else
4616 {
4617 pDriverInfo = &((struct DeviceInfoSet *)DeviceInfoSet)->SelectedDriver;
4618 ListHead = &((struct DeviceInfoSet *)DeviceInfoSet)->DriverListHead;
4619 }
4620
4621 if (!DriverInfoData)
4622 {
4623 *pDriverInfo = NULL;
4624 ret = TRUE;
4625 }
4626 else
4627 {
4628 /* Search selected driver in list */
4629 ItemList = ListHead->Flink;
4630 while (ItemList != ListHead)
4631 {
4632 if (DriverInfoData->Reserved != 0)
4633 {
4634 if (DriverInfoData->Reserved == (ULONG_PTR)ItemList)
4635 break;
4636 }
4637 else
4638 {
4639 /* The caller wants to compare only DriverType, Description and ProviderName fields */
4640 struct DriverInfoElement *driverInfo = (struct DriverInfoElement *)ItemList;
4641 if (driverInfo->Info.DriverType == DriverInfoData->DriverType
4642 && wcscmp(driverInfo->Info.Description, DriverInfoData->Description) == 0
4643 && wcscmp(driverInfo->Info.ProviderName, DriverInfoData->ProviderName) == 0)
4644 {
4645 break;
4646 }
4647 }
4648 }
4649 if (ItemList == ListHead)
4650 SetLastError(ERROR_INVALID_PARAMETER);
4651 else
4652 {
4653 *pDriverInfo = (struct DriverInfoElement *)ItemList;
4654 DriverInfoData->Reserved = (ULONG_PTR)ItemList;
4655 ret = TRUE;
4656 TRACE("Choosing driver whose rank is 0x%lx\n",
4657 ((struct DriverInfoElement *)ItemList)->DriverRank);
4658 if (DeviceInfoData)
4659 memcpy(&DeviceInfoData->ClassGuid, &(*pDriverInfo)->ClassGuid, sizeof(GUID));
4660 }
4661 }
4662 }
4663
4664 TRACE("Returning %d\n", ret);
4665 return ret;
4666 }
4667
4668 /***********************************************************************
4669 * SetupDiSelectBestCompatDrv (SETUPAPI.@)
4670 */
4671 BOOL WINAPI
4672 SetupDiSelectBestCompatDrv(
4673 IN HDEVINFO DeviceInfoSet,
4674 IN PSP_DEVINFO_DATA DeviceInfoData)
4675 {
4676 SP_DRVINFO_DATA_W drvInfoData;
4677 BOOL ret;
4678
4679 TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
4680
4681 /* Drivers are sorted by rank in the driver list, so
4682 * the first driver in the list is the best one.
4683 */
4684 drvInfoData.cbSize = sizeof(SP_DRVINFO_DATA_W);
4685 ret = SetupDiEnumDriverInfoW(
4686 DeviceInfoSet,
4687 DeviceInfoData,
4688 SPDIT_COMPATDRIVER,
4689 0, /* Member index */
4690 &drvInfoData);
4691
4692 if (ret)
4693 {
4694 ret = SetupDiSetSelectedDriverW(
4695 DeviceInfoSet,
4696 DeviceInfoData,
4697 &drvInfoData);
4698 }
4699
4700 TRACE("Returning %d\n", ret);
4701 return ret;
4702 }
4703
4704 /***********************************************************************
4705 * SetupDiInstallDriverFiles (SETUPAPI.@)
4706 */
4707 BOOL WINAPI
4708 SetupDiInstallDriverFiles(
4709 IN HDEVINFO DeviceInfoSet,
4710 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
4711 {
4712 BOOL ret = FALSE;
4713
4714 TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
4715
4716 if (!DeviceInfoSet)
4717 SetLastError(ERROR_INVALID_PARAMETER);
4718 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
4719 SetLastError(ERROR_INVALID_HANDLE);
4720 else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
4721 SetLastError(ERROR_INVALID_HANDLE);
4722 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
4723 SetLastError(ERROR_INVALID_USER_BUFFER);
4724 else if (DeviceInfoData && ((struct DeviceInfoElement *)DeviceInfoData->Reserved)->SelectedDriver == NULL)
4725 SetLastError(ERROR_INVALID_PARAMETER);
4726 else if (!DeviceInfoData && ((struct DeviceInfoSet *)DeviceInfoSet)->SelectedDriver == NULL)
4727 SetLastError(ERROR_INVALID_PARAMETER);
4728 else
4729 {
4730 struct DriverInfoElement *DriverInfo;
4731 HWND hWnd;
4732 HINF hInf;
4733
4734 if (DeviceInfoData)
4735 {
4736 DriverInfo = ((struct DeviceInfoElement *)DeviceInfoData->Reserved)->SelectedDriver;
4737 hWnd = ((struct DeviceInfoElement *)DeviceInfoData->Reserved)->hwndParent;
4738 }
4739 else
4740 {
4741 DriverInfo = ((struct DeviceInfoSet *)DeviceInfoSet)->SelectedDriver;
4742 hWnd = ((struct DeviceInfoSet *)DeviceInfoSet)->hwndParent;
4743 }
4744
4745 hInf = SetupOpenInfFileW(DriverInfo->InfPath, NULL, INF_STYLE_WIN4, NULL);
4746 if (hInf != INVALID_HANDLE_VALUE)
4747 {
4748 WCHAR SectionName[MAX_PATH];
4749 DWORD SectionNameLength = 0;
4750
4751 ret = SetupDiGetActualSectionToInstallW(hInf, DriverInfo->InfSection,
4752 SectionName, MAX_PATH, &SectionNameLength, NULL);
4753 if (ret)
4754 {
4755 PVOID callback_context = SetupInitDefaultQueueCallback(hWnd);
4756 ret = SetupInstallFromInfSectionW(hWnd, hInf, SectionName,
4757 SPINST_FILES, NULL, NULL, SP_COPY_NEWER,
4758 SetupDefaultQueueCallbackW, callback_context,
4759 NULL, NULL);
4760 SetupTermDefaultQueueCallback(callback_context);
4761 }
4762 SetupCloseInfFile(hInf);
4763 }
4764 }
4765
4766 TRACE("Returning %d\n", ret);
4767 return ret;
4768 }
4769
4770 /***********************************************************************
4771 * SetupDiRegisterCoDeviceInstallers (SETUPAPI.@)
4772 */
4773 BOOL WINAPI
4774 SetupDiRegisterCoDeviceInstallers(
4775 IN HDEVINFO DeviceInfoSet,
4776 IN PSP_DEVINFO_DATA DeviceInfoData)
4777 {
4778 TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
4779
4780 FIXME("SetupDiRegisterCoDeviceInstallers not implemented. Doing nothing\n");
4781 //SetLastError(ERROR_GEN_FAILURE);
4782 //return FALSE;
4783 return TRUE;
4784 }
4785
4786 /***********************************************************************
4787 * SetupDiInstallDeviceInterfaces (SETUPAPI.@)
4788 */
4789 BOOL WINAPI
4790 SetupDiInstallDeviceInterfaces(
4791 IN HDEVINFO DeviceInfoSet,
4792 IN PSP_DEVINFO_DATA DeviceInfoData)
4793 {
4794 TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
4795
4796 FIXME("SetupDiInstallDeviceInterfaces not implemented. Doing nothing\n");
4797 //SetLastError(ERROR_GEN_FAILURE);
4798 //return FALSE;
4799 return TRUE;
4800 }
4801
4802 /***********************************************************************
4803 * SetupDiInstallDevice (SETUPAPI.@)
4804 */
4805 BOOL WINAPI
4806 SetupDiInstallDevice(
4807 IN HDEVINFO DeviceInfoSet,
4808 IN PSP_DEVINFO_DATA DeviceInfoData)
4809 {
4810 struct DriverInfoElement *DriverInfo;
4811 struct DeviceInfoElement *DevInfo = (struct DeviceInfoElement *)DeviceInfoData->Reserved;
4812 SYSTEMTIME DriverDate;
4813 WCHAR SectionName[MAX_PATH];
4814 WCHAR Buffer[32];
4815 DWORD SectionNameLength = 0;
4816 BOOL Result = FALSE;
4817 INFCONTEXT ContextService;
4818 INT Flags;
4819 DWORD RequiredSize;
4820 HINF hInf = INVALID_HANDLE_VALUE;
4821 LPCWSTR AssociatedService = NULL;
4822 LPWSTR pSectionName = NULL;
4823 LPWSTR ClassName = NULL;
4824 GUID ClassGuid;
4825 LPWSTR lpGuidString = NULL, lpFullGuidString = NULL;
4826 BOOL RebootRequired = FALSE;
4827 HKEY hKey = INVALID_HANDLE_VALUE;
4828 HKEY hClassKey = INVALID_HANDLE_VALUE;
4829 LONG rc;
4830 HWND hWnd;
4831 PVOID callback_context;
4832 BOOL ret = FALSE; /* Return value */
4833
4834 TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
4835
4836 if (!DeviceInfoSet)
4837 SetLastError(ERROR_INVALID_PARAMETER);
4838 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
4839 SetLastError(ERROR_INVALID_HANDLE);
4840 else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
4841 SetLastError(ERROR_INVALID_HANDLE);
4842 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
4843 SetLastError(ERROR_INVALID_USER_BUFFER);
4844 else if (DeviceInfoData && ((struct DeviceInfoElement *)DeviceInfoData->Reserved)->SelectedDriver == NULL)
4845 SetLastError(ERROR_INVALID_PARAMETER);
4846 else if (!DeviceInfoData && ((struct DeviceInfoSet *)DeviceInfoSet)->SelectedDriver == NULL)
4847 SetLastError(ERROR_INVALID_PARAMETER);
4848 else
4849 Result = TRUE;
4850
4851 if (!Result)
4852 {
4853 /* One parameter is bad */
4854 goto cleanup;
4855 }
4856
4857 /* FIXME: If DI_FLAGSEX_SETFAILEDINSTALL is set, set FAILEDINSTALL flag in ConfigFlags registry and exit */
4858
4859 if (DeviceInfoData)
4860 {
4861 DriverInfo = ((struct DeviceInfoElement *)DeviceInfoData->Reserved)->SelectedDriver;
4862 hWnd = ((struct DeviceInfoElement *)DeviceInfoData->Reserved)->hwndParent;
4863 }
4864 else
4865 {
4866 DriverInfo = ((struct DeviceInfoSet *)DeviceInfoSet)->SelectedDriver;
4867 hWnd = ((struct DeviceInfoSet *)DeviceInfoSet)->hwndParent;
4868 }
4869 FileTimeToSystemTime(&DriverInfo->Info.DriverDate, &DriverDate);
4870
4871 hInf = SetupOpenInfFileW(DriverInfo->InfPath, NULL, INF_STYLE_WIN4, NULL);
4872 if (hInf == INVALID_HANDLE_VALUE)
4873 goto cleanup;
4874
4875 Result = SetupDiGetActualSectionToInstallW(hInf, DriverInfo->InfSection,
4876 SectionName, MAX_PATH, &SectionNameLength, NULL);
4877 if (!Result || SectionNameLength > MAX_PATH - 9)
4878 goto cleanup;
4879 pSectionName = &SectionName[wcslen(SectionName)];
4880
4881 /* Get information from [Version] section */
4882 ClassName = NULL;
4883 RequiredSize = 0;
4884 if (!SetupDiGetINFClassW(DriverInfo->InfPath, &ClassGuid, ClassName, RequiredSize, &RequiredSize))
4885 {
4886 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
4887 goto cleanup;
4888 ClassName = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
4889 if (!ClassName)
4890 {
4891 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
4892 goto cleanup;
4893 }
4894 if (!SetupDiGetINFClassW(DriverInfo->InfPath, &ClassGuid, ClassName, RequiredSize, &RequiredSize))
4895 goto cleanup;
4896 }
4897 /* Format ClassGuid to a string */
4898 if (UuidToStringW((UUID*)&ClassGuid, &lpGuidString) != RPC_S_OK)
4899 goto cleanup;
4900 RequiredSize = lstrlenW(lpGuidString);
4901 lpFullGuidString = HeapAlloc(GetProcessHeap(), 0, (RequiredSize + 3) * sizeof(WCHAR));
4902 if (!lpFullGuidString)
4903 {
4904 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
4905 goto cleanup;
4906 }
4907 lpFullGuidString[0] = '{';
4908 memcpy(&lpFullGuidString[1], lpGuidString, RequiredSize * sizeof(WCHAR));
4909 lpFullGuidString[RequiredSize + 1] = '}';
4910 lpFullGuidString[RequiredSize + 2] = '\0';
4911
4912 /* Open/Create driver key information */
4913 hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_SET_VALUE);
4914 if (hKey == INVALID_HANDLE_VALUE && GetLastError() == ERROR_FILE_NOT_FOUND)
4915 hKey = SetupDiCreateDevRegKeyW(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, NULL, NULL);
4916 if (hKey == INVALID_HANDLE_VALUE)
4917 goto cleanup;
4918
4919 /* Write information to driver key */
4920 *pSectionName = UNICODE_NULL;
4921 TRACE("Write information to driver key\n");
4922 TRACE("DriverDate : '%u-%u-%u'\n", DriverDate.wMonth, DriverDate.wDay, DriverDate.wYear);
4923 TRACE("DriverDesc : '%S'\n", DriverInfo->Info.Description);
4924 TRACE("DriverVersion : '%u.%u.%u.%u'\n", DriverInfo->Info.DriverVersion & 0xff, (DriverInfo->Info.DriverVersion >> 8) & 0xff, (DriverInfo->Info.DriverVersion >> 16) & 0xff, (DriverInfo->Info.DriverVersion >> 24) & 0xff);
4925 TRACE("InfPath : '%S'\n", DriverInfo->InfPath);
4926 TRACE("InfSection : '%S'\n", DriverInfo->InfSection);
4927 TRACE("InfSectionExt : '%S'\n", &SectionName[wcslen(DriverInfo->InfSection)]); /* FIXME */
4928 TRACE("MatchingDeviceId: '%S'\n", DriverInfo->MatchingId);
4929 TRACE("ProviderName : '%S'\n", DriverInfo->Info.ProviderName);
4930 swprintf(Buffer, L"%u-%u-%u", DriverDate.wMonth, DriverDate.wDay, DriverDate.wYear);
4931 rc = RegSetValueEx(hKey, L"DriverDate", 0, REG_SZ, (const BYTE *)Buffer, (wcslen(Buffer) + 1) * sizeof(WCHAR));
4932 if (rc == ERROR_SUCCESS)
4933 rc = RegSetValueEx(hKey, L"DriverDateData", 0, REG_BINARY, (const BYTE *)&DriverInfo->Info.DriverDate, sizeof(FILETIME));
4934 if (rc == ERROR_SUCCESS)
4935 rc = RegSetValueEx(hKey, L"DriverDesc", 0, REG_SZ, (const BYTE *)DriverInfo->Info.Description, (wcslen(DriverInfo->Info.Description) + 1) * sizeof(WCHAR));
4936 if (rc == ERROR_SUCCESS)
4937 {
4938 swprintf(Buffer, L"%u.%u.%u.%u", DriverInfo->Info.DriverVersion & 0xff, (DriverInfo->Info.DriverVersion >> 8) & 0xff, (DriverInfo->Info.DriverVersion >> 16) & 0xff, (DriverInfo->Info.DriverVersion >> 24) & 0xff);
4939 rc = RegSetValueEx(hKey, L"DriverVersion", 0, REG_SZ, (const BYTE *)Buffer, (wcslen(Buffer) + 1) * sizeof(WCHAR));
4940 }
4941 if (rc == ERROR_SUCCESS)
4942 rc = RegSetValueEx(hKey, L"InfPath", 0, REG_SZ, (const BYTE *)DriverInfo->InfPath, (wcslen(DriverInfo->InfPath) + 1) * sizeof(WCHAR));
4943 if (rc == ERROR_SUCCESS)
4944 rc = RegSetValueEx(hKey, L"InfSection", 0, REG_SZ, (const BYTE *)DriverInfo->InfSection, (wcslen(DriverInfo->InfSection) + 1) * sizeof(WCHAR));
4945 if (rc == ERROR_SUCCESS)
4946 rc = RegSetValueEx(hKey, L"InfSectionExt", 0, REG_SZ, (const BYTE *)&SectionName[wcslen(DriverInfo->InfSection)], (wcslen(SectionName) - wcslen(DriverInfo->InfSection) + 1) * sizeof(WCHAR));
4947 if (rc == ERROR_SUCCESS)
4948 rc = RegSetValueEx(hKey, L"MatchingDeviceId", 0, REG_SZ, (const BYTE *)DriverInfo->MatchingId, (wcslen(DriverInfo->MatchingId) + 1) * sizeof(WCHAR));
4949 if (rc == ERROR_SUCCESS)
4950 rc = RegSetValueEx(hKey, L"ProviderName", 0, REG_SZ, (const BYTE *)DriverInfo->Info.ProviderName, (wcslen(DriverInfo->Info.ProviderName) + 1) * sizeof(WCHAR));
4951 if (rc != ERROR_SUCCESS)
4952 {
4953 SetLastError(rc);
4954 goto cleanup;
4955 }
4956 RegCloseKey(hKey);
4957 hKey = INVALID_HANDLE_VALUE;
4958
4959 /* Install .Services section */
4960 wcscpy(pSectionName, L".Services");
4961 Result = SetupFindFirstLineW(hInf, SectionName, NULL, &ContextService);
4962 while (Result)
4963 {
4964 LPWSTR ServiceName = NULL;
4965 LPWSTR ServiceSection = NULL;
4966
4967 Result = SetupGetStringFieldW(
4968 &ContextService,
4969 1, /* Field index */
4970 NULL, 0,
4971 &RequiredSize);
4972 if (!Result)
4973 goto nextfile;
4974 if (RequiredSize > 0)
4975 {
4976 /* We got the needed size for the buffer */
4977 ServiceName = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
4978 if (!ServiceName)
4979 {
4980 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
4981 goto nextfile;
4982 }
4983 Result = SetupGetStringFieldW(
4984 &ContextService,
4985 1, /* Field index */
4986 ServiceName, RequiredSize,
4987 &RequiredSize);
4988 if (!Result)
4989 goto nextfile;
4990 }
4991 Result = SetupGetIntField(
4992 &ContextService,
4993 2, /* Field index */
4994 &Flags);
4995 if (!Result)
4996 {
4997 /* The field may be empty. Ignore the error */
4998 Flags = 0;
4999 }
5000 Result = SetupGetStringFieldW(
5001 &ContextService,
5002 3, /* Field index */
5003 NULL, 0,
5004 &RequiredSize);
5005 if (!Result)
5006 goto nextfile;
5007 if (RequiredSize > 0)
5008 {
5009 /* We got the needed size for the buffer */
5010 ServiceSection = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
5011 if (!ServiceSection)
5012 {
5013 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
5014 goto nextfile;
5015 }
5016 Result = SetupGetStringFieldW(
5017 &ContextService,
5018 3, /* Field index */
5019 ServiceSection, RequiredSize,
5020 &RequiredSize);
5021 if (!Result)
5022 goto nextfile;
5023 }
5024 SetLastError(ERROR_SUCCESS);
5025 Result = SetupInstallServicesFromInfSectionExW(hInf, ServiceSection, Flags, DeviceInfoSet, DeviceInfoData, ServiceName, NULL);
5026 if (Result && (Flags & SPSVCINST_ASSOCSERVICE))
5027 {
5028 AssociatedService = ServiceName;
5029 ServiceName = NULL;
5030 if (GetLastError() == ERROR_SUCCESS_REBOOT_REQUIRED)
5031 RebootRequired = TRUE;
5032 }
5033 nextfile:
5034 HeapFree(GetProcessHeap(), 0, ServiceName);
5035 HeapFree(GetProcessHeap(), 0, ServiceSection);
5036 if (!Result)
5037 goto cleanup;
5038 Result = SetupFindNextLine(&ContextService, &ContextService);
5039 }
5040
5041 /* Copy .inf file to Inf\ directory */
5042 FIXME("FIXME: Copy .inf file to Inf\\ directory\n"); /* SetupCopyOEMInf */
5043
5044 /* Open device registry key */
5045 hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_SET_VALUE);
5046 if (hKey == INVALID_HANDLE_VALUE)
5047 goto cleanup;
5048
5049 /* Install .HW section */
5050 wcscpy(pSectionName, L".HW");
5051 callback_context = SetupInitDefaultQueueCallback(hWnd);
5052 Result = SetupInstallFromInfSectionW(hWnd, hInf, SectionName,
5053 SPINST_REGISTRY, hKey, NULL, 0,
5054 SetupDefaultQueueCallbackW, callback_context,
5055 NULL, NULL);
5056 SetupTermDefaultQueueCallback(callback_context);
5057 if (!Result)
5058 goto cleanup;
5059
5060 /* Write information to enum key */
5061 TRACE("Write information to enum key\n");
5062 TRACE("Service : '%S'\n", AssociatedService);
5063 TRACE("Class : '%S'\n", ClassName);
5064 TRACE("ClassGUID : '%S'\n", lpFullGuidString);
5065 TRACE("DeviceDesc : '%S'\n", DriverInfo->Info.Description);
5066 TRACE("Mfg : '%S'\n", DriverInfo->Info.MfgName);
5067 rc = RegSetValueEx(hKey, L"Service", 0, REG_SZ, (const BYTE *)AssociatedService, (wcslen(AssociatedService) + 1) * sizeof(WCHAR));
5068 if (rc == ERROR_SUCCESS)
5069 rc = RegSetValueEx(hKey, L"Class", 0, REG_SZ, (const BYTE *)ClassName, (wcslen(ClassName) + 1) * sizeof(WCHAR));
5070 if (rc == ERROR_SUCCESS)
5071 rc = RegSetValueEx(hKey, L"ClassGUID", 0, REG_SZ, (const BYTE *)lpFullGuidString, (wcslen(lpFullGuidString) + 1) * sizeof(WCHAR));
5072 if (rc == ERROR_SUCCESS)
5073 rc = RegSetValueEx(hKey, L"DeviceDesc", 0, REG_SZ, (const BYTE *)DriverInfo->Info.Description, (wcslen(DriverInfo->Info.Description) + 1) * sizeof(WCHAR));
5074 if (rc == ERROR_SUCCESS)
5075 rc = RegSetValueEx(hKey, L"Mfg", 0, REG_SZ, (const BYTE *)DriverInfo->Info.MfgName, (wcslen(DriverInfo->Info.MfgName) + 1) * sizeof(WCHAR));
5076 if (rc != ERROR_SUCCESS)
5077 {
5078 SetLastError(rc);
5079 goto cleanup;
5080 }
5081
5082 /* Start the device */
5083 if (!RebootRequired && !(Flags & (DI_NEEDRESTART | DI_NEEDREBOOT | DI_DONOTCALLCONFIGMG)))
5084 {
5085 PLUGPLAY_CONTROL_RESET_DEVICE_DATA ResetDeviceData;
5086 NTSTATUS Status;
5087 RtlInitUnicodeString(&ResetDeviceData.DeviceInstance, DevInfo->DeviceName);
5088 Status = NtPlugPlayControl(PlugPlayControlResetDevice, &ResetDeviceData, sizeof(PLUGPLAY_CONTROL_RESET_DEVICE_DATA));
5089 ret = NT_SUCCESS(Status);
5090 }
5091 else
5092 ret = TRUE;
5093
5094 cleanup:
5095 /* End of installation */
5096 if (hClassKey != INVALID_HANDLE_VALUE)
5097 RegCloseKey(hClassKey);
5098 if (hKey != INVALID_HANDLE_VALUE)
5099 RegCloseKey(hKey);
5100 if (lpGuidString)
5101 RpcStringFreeW(&lpGuidString);
5102 HeapFree(GetProcessHeap(), 0, (LPWSTR)AssociatedService);
5103 HeapFree(GetProcessHeap(), 0, ClassName);
5104 HeapFree(GetProcessHeap(), 0, lpFullGuidString);
5105 if (hInf != INVALID_HANDLE_VALUE)
5106 SetupCloseInfFile(hInf);
5107
5108 TRACE("Returning %d\n", ret);
5109 return ret;
5110 }