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