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