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