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