e29bbc075d1c81ae8382eaa9a327aff95c9281bd
[reactos.git] / reactos / dll / win32 / setupapi / devclass.c
1 /*
2 * SetupAPI device class-related functions
3 *
4 * Copyright 2000 Andreas Mohr for CodeWeavers
5 * 2005-2006 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 */
21
22 #include "setupapi_private.h"
23
24 WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
25
26 /* Unicode constants */
27 static const WCHAR BackSlash[] = {'\\',0};
28 static const WCHAR Class[] = {'C','l','a','s','s',0};
29 static const WCHAR ClassGUID[] = {'C','l','a','s','s','G','U','I','D',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 DotServices[] = {'.','S','e','r','v','i','c','e','s',0};
32 static const WCHAR InterfaceInstall32[] = {'I','n','t','e','r','f','a','c','e','I','n','s','t','a','l','l','3','2',0};
33 static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
34
35 typedef BOOL
36 (WINAPI* PROPERTY_PAGE_PROVIDER) (
37 IN PSP_PROPSHEETPAGE_REQUEST PropPageRequest,
38 IN LPFNADDPROPSHEETPAGE fAddFunc,
39 IN LPARAM lParam);
40 typedef BOOL
41 (*UPDATE_CLASS_PARAM_HANDLER) (
42 IN HDEVINFO DeviceInfoSet,
43 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
44 IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL,
45 IN DWORD ClassInstallParamsSize);
46
47 static BOOL
48 SETUP_PropertyChangeHandler(
49 IN HDEVINFO DeviceInfoSet,
50 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
51 IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL,
52 IN DWORD ClassInstallParamsSize);
53
54 static const UPDATE_CLASS_PARAM_HANDLER UpdateClassInstallParamHandlers[] = {
55 NULL, /* DIF_SELECTDEVICE */
56 NULL, /* DIF_INSTALLDEVICE */
57 NULL, /* DIF_ASSIGNRESOURCES */
58 NULL, /* DIF_PROPERTIES */
59 NULL, /* DIF_REMOVE */
60 NULL, /* DIF_FIRSTTIMESETUP */
61 NULL, /* DIF_FOUNDDEVICE */
62 NULL, /* DIF_SELECTCLASSDRIVERS */
63 NULL, /* DIF_VALIDATECLASSDRIVERS */
64 NULL, /* DIF_INSTALLCLASSDRIVERS */
65 NULL, /* DIF_CALCDISKSPACE */
66 NULL, /* DIF_DESTROYPRIVATEDATA */
67 NULL, /* DIF_VALIDATEDRIVER */
68 NULL, /* DIF_MOVEDEVICE */
69 NULL, /* DIF_DETECT */
70 NULL, /* DIF_INSTALLWIZARD */
71 NULL, /* DIF_DESTROYWIZARDDATA */
72 SETUP_PropertyChangeHandler, /* DIF_PROPERTYCHANGE */
73 NULL, /* DIF_ENABLECLASS */
74 NULL, /* DIF_DETECTVERIFY */
75 NULL, /* DIF_INSTALLDEVICEFILES */
76 NULL, /* DIF_UNREMOVE */
77 NULL, /* DIF_SELECTBESTCOMPATDRV */
78 NULL, /* DIF_ALLOW_INSTALL */
79 NULL, /* DIF_REGISTERDEVICE */
80 NULL, /* DIF_NEWDEVICEWIZARD_PRESELECT */
81 NULL, /* DIF_NEWDEVICEWIZARD_SELECT */
82 NULL, /* DIF_NEWDEVICEWIZARD_PREANALYZE */
83 NULL, /* DIF_NEWDEVICEWIZARD_POSTANALYZE */
84 NULL, /* DIF_NEWDEVICEWIZARD_FINISHINSTALL */
85 NULL, /* DIF_UNUSED1 */
86 NULL, /* DIF_INSTALLINTERFACES */
87 NULL, /* DIF_DETECTCANCEL */
88 NULL, /* DIF_REGISTER_COINSTALLERS */
89 NULL, /* DIF_ADDPROPERTYPAGE_ADVANCED */
90 NULL, /* DIF_ADDPROPERTYPAGE_BASIC */
91 NULL, /* DIF_RESERVED1 */
92 NULL, /* DIF_TROUBLESHOOTER */
93 NULL, /* DIF_POWERMESSAGEWAKE */
94 NULL, /* DIF_ADDREMOTEPROPERTYPAGE_ADVANCED */
95 NULL, /* DIF_UPDATEDRIVER_UI */
96 NULL /* DIF_RESERVED2 */
97 };
98
99
100 /***********************************************************************
101 * SetupDiBuildClassInfoList (SETUPAPI.@)
102 *
103 * Returns a list of setup class GUIDs that identify the classes
104 * that are installed on a local machine.
105 *
106 * PARAMS
107 * Flags [I] control exclusion of classes from the list.
108 * ClassGuidList [O] pointer to a GUID-typed array that receives a list of setup class GUIDs.
109 * ClassGuidListSize [I] The number of GUIDs in the array (ClassGuidList).
110 * RequiredSize [O] pointer, which receives the number of GUIDs that are returned.
111 *
112 * RETURNS
113 * Success: TRUE.
114 * Failure: FALSE.
115 */
116 BOOL WINAPI
117 SetupDiBuildClassInfoList(
118 IN DWORD Flags,
119 OUT LPGUID ClassGuidList OPTIONAL,
120 IN DWORD ClassGuidListSize,
121 OUT PDWORD RequiredSize)
122 {
123 TRACE("\n");
124 return SetupDiBuildClassInfoListExW(Flags, ClassGuidList,
125 ClassGuidListSize, RequiredSize,
126 NULL, NULL);
127 }
128
129 /***********************************************************************
130 * SetupDiBuildClassInfoListExA (SETUPAPI.@)
131 *
132 * Returns a list of setup class GUIDs that identify the classes
133 * that are installed on a local or remote macine.
134 *
135 * PARAMS
136 * Flags [I] control exclusion of classes from the list.
137 * ClassGuidList [O] pointer to a GUID-typed array that receives a list of setup class GUIDs.
138 * ClassGuidListSize [I] The number of GUIDs in the array (ClassGuidList).
139 * RequiredSize [O] pointer, which receives the number of GUIDs that are returned.
140 * MachineName [I] name of a remote machine.
141 * Reserved [I] must be NULL.
142 *
143 * RETURNS
144 * Success: TRUE.
145 * Failure: FALSE.
146 */
147 BOOL WINAPI
148 SetupDiBuildClassInfoListExA(
149 IN DWORD Flags,
150 OUT LPGUID ClassGuidList OPTIONAL,
151 IN DWORD ClassGuidListSize,
152 OUT PDWORD RequiredSize,
153 IN PCSTR MachineName OPTIONAL,
154 IN PVOID Reserved)
155 {
156 LPWSTR MachineNameW = NULL;
157 BOOL bResult;
158
159 TRACE("0x%lx %p %lu %p %s %p\n", Flags, ClassGuidList,
160 ClassGuidListSize, RequiredSize, debugstr_a(MachineName), Reserved);
161
162 if (MachineName)
163 {
164 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
165 if (MachineNameW == NULL) return FALSE;
166 }
167
168 bResult = SetupDiBuildClassInfoListExW(Flags, ClassGuidList,
169 ClassGuidListSize, RequiredSize,
170 MachineNameW, Reserved);
171
172 MyFree(MachineNameW);
173
174 return bResult;
175 }
176
177 /***********************************************************************
178 * SetupDiBuildClassInfoListExW (SETUPAPI.@)
179 *
180 * Returns a list of setup class GUIDs that identify the classes
181 * that are installed on a local or remote macine.
182 *
183 * PARAMS
184 * Flags [I] control exclusion of classes from the list.
185 * ClassGuidList [O] pointer to a GUID-typed array that receives a list of setup class GUIDs.
186 * ClassGuidListSize [I] The number of GUIDs in the array (ClassGuidList).
187 * RequiredSize [O] pointer, which receives the number of GUIDs that are returned.
188 * MachineName [I] name of a remote machine.
189 * Reserved [I] must be NULL.
190 *
191 * RETURNS
192 * Success: TRUE.
193 * Failure: FALSE.
194 */
195 BOOL WINAPI
196 SetupDiBuildClassInfoListExW(
197 IN DWORD Flags,
198 OUT LPGUID ClassGuidList OPTIONAL,
199 IN DWORD ClassGuidListSize,
200 OUT PDWORD RequiredSize,
201 IN PCWSTR MachineName OPTIONAL,
202 IN PVOID Reserved)
203 {
204 WCHAR szKeyName[MAX_GUID_STRING_LEN + 1];
205 HKEY hClassesKey = INVALID_HANDLE_VALUE;
206 HKEY hClassKey = NULL;
207 DWORD dwLength;
208 DWORD dwIndex;
209 LONG lError;
210 DWORD dwGuidListIndex = 0;
211 BOOL ret = FALSE;
212
213 TRACE("0x%lx %p %lu %p %s %p\n", Flags, ClassGuidList,
214 ClassGuidListSize, RequiredSize, debugstr_w(MachineName), Reserved);
215
216 if (!RequiredSize)
217 {
218 SetLastError(ERROR_INVALID_PARAMETER);
219 goto cleanup;
220 }
221 else if (!ClassGuidList && ClassGuidListSize > 0)
222 {
223 SetLastError(ERROR_INVALID_PARAMETER);
224 goto cleanup;
225 }
226
227 hClassesKey = SetupDiOpenClassRegKeyExW(NULL,
228 KEY_ENUMERATE_SUB_KEYS,
229 DIOCR_INSTALLER,
230 MachineName,
231 Reserved);
232 if (hClassesKey == INVALID_HANDLE_VALUE)
233 goto cleanup;
234
235 for (dwIndex = 0; ; dwIndex++)
236 {
237 dwLength = MAX_GUID_STRING_LEN + 1;
238 lError = RegEnumKeyExW(hClassesKey,
239 dwIndex,
240 szKeyName,
241 &dwLength,
242 NULL,
243 NULL,
244 NULL,
245 NULL);
246 if (lError == ERROR_SUCCESS || lError == ERROR_MORE_DATA)
247 {
248 TRACE("Key name: %s\n", debugstr_w(szKeyName));
249
250 if (hClassKey != NULL)
251 RegCloseKey(hClassKey);
252 if (RegOpenKeyExW(hClassesKey,
253 szKeyName,
254 0,
255 KEY_QUERY_VALUE,
256 &hClassKey) != ERROR_SUCCESS)
257 {
258 goto cleanup;
259 }
260
261 if (RegQueryValueExW(hClassKey,
262 REGSTR_VAL_NOUSECLASS,
263 NULL,
264 NULL,
265 NULL,
266 NULL) == ERROR_SUCCESS)
267 {
268 TRACE("'NoUseClass' value found!\n");
269 continue;
270 }
271
272 if ((Flags & DIBCI_NOINSTALLCLASS) &&
273 (!RegQueryValueExW(hClassKey,
274 REGSTR_VAL_NOINSTALLCLASS,
275 NULL,
276 NULL,
277 NULL,
278 NULL)))
279 {
280 TRACE("'NoInstallClass' value found!\n");
281 continue;
282 }
283
284 if ((Flags & DIBCI_NODISPLAYCLASS) &&
285 (!RegQueryValueExW(hClassKey,
286 REGSTR_VAL_NODISPLAYCLASS,
287 NULL,
288 NULL,
289 NULL,
290 NULL)))
291 {
292 TRACE("'NoDisplayClass' value found!\n");
293 continue;
294 }
295
296 TRACE("Guid: %s\n", debugstr_w(szKeyName));
297 if (dwGuidListIndex < ClassGuidListSize)
298 {
299 if (szKeyName[0] == L'{' && szKeyName[37] == L'}')
300 szKeyName[37] = 0;
301
302 UuidFromStringW(&szKeyName[1],
303 &ClassGuidList[dwGuidListIndex]);
304 }
305
306 dwGuidListIndex++;
307 }
308 else
309 TRACE("RegEnumKeyExW() returns 0x%lx\n", lError);
310
311 if (lError != ERROR_SUCCESS)
312 break;
313 }
314
315 if (RequiredSize != NULL)
316 *RequiredSize = dwGuidListIndex;
317
318 if (ClassGuidListSize < dwGuidListIndex)
319 SetLastError(ERROR_INSUFFICIENT_BUFFER);
320 else
321 ret = TRUE;
322
323 cleanup:
324 if (hClassesKey != INVALID_HANDLE_VALUE)
325 RegCloseKey(hClassesKey);
326 if (hClassKey != NULL)
327 RegCloseKey(hClassKey);
328 return ret;
329 }
330
331 /***********************************************************************
332 * SetupDiClassGuidsFromNameA (SETUPAPI.@)
333 */
334 BOOL WINAPI
335 SetupDiClassGuidsFromNameA(
336 IN PCSTR ClassName,
337 OUT LPGUID ClassGuidList,
338 IN DWORD ClassGuidListSize,
339 OUT PDWORD RequiredSize)
340 {
341 return SetupDiClassGuidsFromNameExA(ClassName, ClassGuidList,
342 ClassGuidListSize, RequiredSize,
343 NULL, NULL);
344 }
345
346 /***********************************************************************
347 * SetupDiClassGuidsFromNameW (SETUPAPI.@)
348 */
349 BOOL WINAPI SetupDiClassGuidsFromNameW(
350 IN PCWSTR ClassName,
351 OUT LPGUID ClassGuidList,
352 IN DWORD ClassGuidListSize,
353 OUT PDWORD RequiredSize)
354 {
355 return SetupDiClassGuidsFromNameExW(ClassName, ClassGuidList,
356 ClassGuidListSize, RequiredSize,
357 NULL, NULL);
358 }
359
360 /***********************************************************************
361 * SetupDiClassGuidsFromNameExA (SETUPAPI.@)
362 */
363 BOOL WINAPI
364 SetupDiClassGuidsFromNameExA(
365 IN PCSTR ClassName,
366 OUT LPGUID ClassGuidList,
367 IN DWORD ClassGuidListSize,
368 OUT PDWORD RequiredSize,
369 IN PCSTR MachineName OPTIONAL,
370 IN PVOID Reserved)
371 {
372 LPWSTR ClassNameW = NULL;
373 LPWSTR MachineNameW = NULL;
374 BOOL bResult = FALSE;
375
376 TRACE("%s %p %lu %p %s %p\n", debugstr_a(ClassName), ClassGuidList,
377 ClassGuidListSize, RequiredSize, debugstr_a(MachineName), Reserved);
378
379 if (!ClassName)
380 {
381 SetLastError(ERROR_INVALID_PARAMETER);
382 goto cleanup;
383 }
384
385 ClassNameW = MultiByteToUnicode(ClassName, CP_ACP);
386 if (ClassNameW == NULL)
387 goto cleanup;
388
389 if (MachineName)
390 {
391 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
392 if (MachineNameW == NULL)
393 goto cleanup;
394 }
395
396 bResult = SetupDiClassGuidsFromNameExW(ClassNameW, ClassGuidList,
397 ClassGuidListSize, RequiredSize,
398 MachineNameW, Reserved);
399
400 cleanup:
401 MyFree(MachineNameW);
402 MyFree(ClassNameW);
403
404 return bResult;
405 }
406
407 /***********************************************************************
408 * SetupDiClassGuidsFromNameExW (SETUPAPI.@)
409 */
410 BOOL WINAPI
411 SetupDiClassGuidsFromNameExW(
412 IN PCWSTR ClassName,
413 OUT LPGUID ClassGuidList,
414 IN DWORD ClassGuidListSize,
415 OUT PDWORD RequiredSize,
416 IN PCWSTR MachineName OPTIONAL,
417 IN PVOID Reserved)
418 {
419 WCHAR szKeyName[MAX_GUID_STRING_LEN + 1];
420 WCHAR szClassName[MAX_CLASS_NAME_LEN];
421 HKEY hClassesKey = INVALID_HANDLE_VALUE;
422 HKEY hClassKey = NULL;
423 DWORD dwLength;
424 DWORD dwIndex;
425 LONG lError;
426 DWORD dwGuidListIndex = 0;
427 BOOL ret = FALSE;
428
429 TRACE("%s %p %lu %p %s %p\n", debugstr_w(ClassName), ClassGuidList,
430 ClassGuidListSize, RequiredSize, debugstr_w(MachineName), Reserved);
431
432 if (!ClassName || !RequiredSize)
433 {
434 SetLastError(ERROR_INVALID_PARAMETER);
435 goto cleanup;
436 }
437 else if (!ClassGuidList && ClassGuidListSize > 0)
438 {
439 SetLastError(ERROR_INVALID_PARAMETER);
440 goto cleanup;
441 }
442 *RequiredSize = 0;
443
444 hClassesKey = SetupDiOpenClassRegKeyExW(NULL,
445 KEY_ENUMERATE_SUB_KEYS,
446 DIOCR_INSTALLER,
447 MachineName,
448 Reserved);
449 if (hClassesKey == INVALID_HANDLE_VALUE)
450 goto cleanup;
451
452 for (dwIndex = 0; ; dwIndex++)
453 {
454 dwLength = MAX_GUID_STRING_LEN + 1;
455 lError = RegEnumKeyExW(hClassesKey,
456 dwIndex,
457 szKeyName,
458 &dwLength,
459 NULL,
460 NULL,
461 NULL,
462 NULL);
463 if (lError == ERROR_SUCCESS || lError == ERROR_MORE_DATA)
464 {
465 TRACE("Key name: %s\n", debugstr_w(szKeyName));
466
467 if (hClassKey != NULL)
468 RegCloseKey(hClassKey);
469 if (RegOpenKeyExW(hClassesKey,
470 szKeyName,
471 0,
472 KEY_QUERY_VALUE,
473 &hClassKey) != ERROR_SUCCESS)
474 {
475 goto cleanup;
476 }
477
478 dwLength = MAX_CLASS_NAME_LEN * sizeof(WCHAR);
479 if (RegQueryValueExW(hClassKey,
480 Class,
481 NULL,
482 NULL,
483 (LPBYTE)szClassName,
484 &dwLength) == ERROR_SUCCESS)
485 {
486 TRACE("Class name: %s\n", debugstr_w(szClassName));
487
488 if (strcmpiW(szClassName, ClassName) == 0)
489 {
490 TRACE("Found matching class name\n");
491
492 TRACE("Guid: %s\n", debugstr_w(szKeyName));
493 if (dwGuidListIndex < ClassGuidListSize)
494 {
495 if (szKeyName[0] == L'{' && szKeyName[37] == L'}')
496 szKeyName[37] = 0;
497
498 UuidFromStringW(&szKeyName[1],
499 &ClassGuidList[dwGuidListIndex]);
500 }
501
502 dwGuidListIndex++;
503 }
504 }
505 }
506 else
507 TRACE("RegEnumKeyExW() returns 0x%lx\n", lError);
508
509 if (lError != ERROR_SUCCESS)
510 break;
511 }
512
513 if (RequiredSize != NULL)
514 *RequiredSize = dwGuidListIndex;
515
516 if (ClassGuidListSize < dwGuidListIndex)
517 SetLastError(ERROR_INSUFFICIENT_BUFFER);
518 else
519 ret = TRUE;
520
521 cleanup:
522 if (hClassesKey != INVALID_HANDLE_VALUE)
523 RegCloseKey(hClassesKey);
524 if (hClassKey != NULL)
525 RegCloseKey(hClassKey);
526 return ret;
527 }
528
529 /***********************************************************************
530 * SetupDiClassNameFromGuidA (SETUPAPI.@)
531 */
532 BOOL WINAPI
533 SetupDiClassNameFromGuidA(
534 IN CONST GUID* ClassGuid,
535 OUT PSTR ClassName,
536 IN DWORD ClassNameSize,
537 OUT PDWORD RequiredSize OPTIONAL)
538 {
539 return SetupDiClassNameFromGuidExA(ClassGuid, ClassName,
540 ClassNameSize, RequiredSize,
541 NULL, NULL);
542 }
543
544 /***********************************************************************
545 * SetupDiClassNameFromGuidW (SETUPAPI.@)
546 */
547 BOOL WINAPI
548 SetupDiClassNameFromGuidW(
549 IN CONST GUID* ClassGuid,
550 OUT PWSTR ClassName,
551 IN DWORD ClassNameSize,
552 OUT PDWORD RequiredSize OPTIONAL)
553 {
554 return SetupDiClassNameFromGuidExW(ClassGuid, ClassName,
555 ClassNameSize, RequiredSize,
556 NULL, NULL);
557 }
558
559 /***********************************************************************
560 * SetupDiClassNameFromGuidExA (SETUPAPI.@)
561 */
562 BOOL WINAPI
563 SetupDiClassNameFromGuidExA(
564 IN CONST GUID* ClassGuid,
565 OUT PSTR ClassName,
566 IN DWORD ClassNameSize,
567 OUT PDWORD RequiredSize OPTIONAL,
568 IN PCSTR MachineName OPTIONAL,
569 IN PVOID Reserved)
570 {
571 WCHAR ClassNameW[MAX_CLASS_NAME_LEN];
572 LPWSTR MachineNameW = NULL;
573 BOOL ret;
574
575 if (MachineName)
576 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
577 ret = SetupDiClassNameFromGuidExW(ClassGuid, ClassNameW, MAX_CLASS_NAME_LEN,
578 RequiredSize, MachineNameW, Reserved);
579 if (ret)
580 {
581 int len = WideCharToMultiByte(CP_ACP, 0, ClassNameW, -1, ClassName,
582 ClassNameSize, NULL, NULL);
583 if (len > ClassNameSize)
584 {
585 SetLastError(ERROR_INSUFFICIENT_BUFFER);
586 ret = FALSE;
587 }
588 }
589 MyFree(MachineNameW);
590 return ret;
591 }
592
593 /***********************************************************************
594 * SetupDiClassNameFromGuidExW (SETUPAPI.@)
595 */
596 BOOL WINAPI
597 SetupDiClassNameFromGuidExW(
598 IN CONST GUID* ClassGuid,
599 OUT PWSTR ClassName,
600 IN DWORD ClassNameSize,
601 OUT PDWORD RequiredSize OPTIONAL,
602 IN PCWSTR MachineName OPTIONAL,
603 IN PVOID Reserved)
604 {
605 HKEY hKey = INVALID_HANDLE_VALUE;
606 DWORD dwLength, dwRegType;
607 LONG rc;
608 BOOL ret = FALSE;
609
610 TRACE("%s %p %lu %p %s %p\n", debugstr_guid(ClassGuid), ClassName,
611 ClassNameSize, RequiredSize, debugstr_w(MachineName), Reserved);
612
613 if (!ClassGuid)
614 {
615 SetLastError(ERROR_INVALID_CLASS);
616 goto cleanup;
617 }
618 else if (!ClassName && ClassNameSize > 0)
619 {
620 SetLastError(ERROR_INVALID_PARAMETER);
621 goto cleanup;
622 }
623
624 hKey = SetupDiOpenClassRegKeyExW(ClassGuid,
625 KEY_QUERY_VALUE,
626 DIOCR_INSTALLER,
627 MachineName,
628 Reserved);
629 if (hKey == INVALID_HANDLE_VALUE)
630 goto cleanup;
631
632 if (ClassNameSize < sizeof(UNICODE_NULL) || !ClassName)
633 dwLength = 0;
634 else
635 dwLength = ClassNameSize * sizeof(WCHAR) - sizeof(UNICODE_NULL);
636
637 rc = RegQueryValueExW(hKey,
638 Class,
639 NULL,
640 &dwRegType,
641 (LPBYTE)ClassName,
642 &dwLength);
643 if (rc != ERROR_MORE_DATA && rc != ERROR_SUCCESS)
644 {
645 SetLastError(rc);
646 goto cleanup;
647 }
648 else if (dwRegType != REG_SZ)
649 {
650 SetLastError(ERROR_GEN_FAILURE);
651 goto cleanup;
652 }
653
654 if (RequiredSize)
655 *RequiredSize = dwLength / sizeof(WCHAR) + 1;
656
657 if (ClassNameSize * sizeof(WCHAR) >= dwLength + sizeof(UNICODE_STRING))
658 {
659 if (ClassNameSize > sizeof(UNICODE_NULL))
660 ClassName[ClassNameSize / sizeof(WCHAR)] = UNICODE_NULL;
661 ret = TRUE;
662 }
663 else
664 SetLastError(ERROR_INSUFFICIENT_BUFFER);
665
666 cleanup:
667 if (hKey != INVALID_HANDLE_VALUE)
668 RegCloseKey(hKey);
669 return ret;
670 }
671
672 /***********************************************************************
673 * SetupDiDestroyClassImageList(SETUPAPI.@)
674 */
675 BOOL WINAPI
676 SetupDiDestroyClassImageList(
677 IN PSP_CLASSIMAGELIST_DATA ClassImageListData)
678 {
679 struct ClassImageList *list;
680 BOOL ret = FALSE;
681
682 TRACE("%p\n", ClassImageListData);
683
684 if (!ClassImageListData)
685 SetLastError(ERROR_INVALID_PARAMETER);
686 else if (ClassImageListData->cbSize != sizeof(SP_CLASSIMAGELIST_DATA))
687 SetLastError(ERROR_INVALID_USER_BUFFER);
688 else if ((list = (struct ClassImageList *)ClassImageListData->Reserved) == NULL)
689 SetLastError(ERROR_INVALID_USER_BUFFER);
690 else if (list->magic != SETUP_CLASS_IMAGE_LIST_MAGIC)
691 SetLastError(ERROR_INVALID_USER_BUFFER);
692 else
693 {
694 //DestroyIcon()
695 //ImageList_Destroy();
696 FIXME("Stub %p\n", ClassImageListData);
697 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
698 }
699
700 TRACE("Returning %d\n", ret);
701 return ret;
702 }
703
704 /***********************************************************************
705 * SetupDiGetClassDescriptionA (SETUPAPI.@)
706 */
707 BOOL WINAPI
708 SetupDiGetClassDescriptionA(
709 IN CONST GUID *ClassGuid,
710 OUT PSTR ClassDescription,
711 IN DWORD ClassDescriptionSize,
712 OUT PDWORD RequiredSize OPTIONAL)
713 {
714 return SetupDiGetClassDescriptionExA(ClassGuid, ClassDescription,
715 ClassDescriptionSize,
716 RequiredSize, NULL, NULL);
717 }
718
719 /***********************************************************************
720 * SetupDiGetClassDescriptionW (SETUPAPI.@)
721 */
722 BOOL WINAPI
723 SetupDiGetClassDescriptionW(
724 IN CONST GUID *ClassGuid,
725 OUT PWSTR ClassDescription,
726 IN DWORD ClassDescriptionSize,
727 OUT PDWORD RequiredSize OPTIONAL)
728 {
729 return SetupDiGetClassDescriptionExW(ClassGuid, ClassDescription,
730 ClassDescriptionSize,
731 RequiredSize, NULL, NULL);
732 }
733
734 /***********************************************************************
735 * SetupDiGetClassDescriptionExA (SETUPAPI.@)
736 */
737 BOOL WINAPI
738 SetupDiGetClassDescriptionExA(
739 IN CONST GUID *ClassGuid,
740 OUT PSTR ClassDescription,
741 IN DWORD ClassDescriptionSize,
742 OUT PDWORD RequiredSize OPTIONAL,
743 IN PCSTR MachineName OPTIONAL,
744 IN PVOID Reserved)
745 {
746 PWCHAR ClassDescriptionW = NULL;
747 LPWSTR MachineNameW = NULL;
748 BOOL ret = FALSE;
749
750 TRACE("%s %p %lu %p %s %p\n", debugstr_guid(ClassGuid), ClassDescription,
751 ClassDescriptionSize, RequiredSize, debugstr_a(MachineName), Reserved);
752
753 if (ClassDescriptionSize > 0)
754 {
755 ClassDescriptionW = MyMalloc(ClassDescriptionSize * sizeof(WCHAR));
756 if (!ClassDescriptionW)
757 {
758 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
759 goto cleanup;
760 }
761 }
762
763 if (MachineName)
764 {
765 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
766 if (!MachineNameW)
767 {
768 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
769 goto cleanup;
770 }
771 }
772
773 ret = SetupDiGetClassDescriptionExW(ClassGuid, ClassDescriptionW,
774 ClassDescriptionSize * sizeof(WCHAR), RequiredSize, MachineNameW, Reserved);
775 if (ret)
776 {
777 int len = WideCharToMultiByte(CP_ACP, 0, ClassDescriptionW, -1, ClassDescription,
778 ClassDescriptionSize, NULL, NULL);
779 if (len > ClassDescriptionSize)
780 {
781 SetLastError(ERROR_INSUFFICIENT_BUFFER);
782 ret = FALSE;
783 }
784 }
785
786 cleanup:
787 MyFree(ClassDescriptionW);
788 MyFree(MachineNameW);
789 return ret;
790 }
791
792 /***********************************************************************
793 * SetupDiGetClassDescriptionExW (SETUPAPI.@)
794 */
795 BOOL WINAPI
796 SetupDiGetClassDescriptionExW(
797 IN CONST GUID *ClassGuid,
798 OUT PWSTR ClassDescription,
799 IN DWORD ClassDescriptionSize,
800 OUT PDWORD RequiredSize OPTIONAL,
801 IN PCWSTR MachineName OPTIONAL,
802 IN PVOID Reserved)
803 {
804 HKEY hKey = INVALID_HANDLE_VALUE;
805 DWORD dwLength, dwRegType;
806 LONG rc;
807 BOOL ret = FALSE;
808
809 TRACE("%s %p %lu %p %s %p\n", debugstr_guid(ClassGuid), ClassDescription,
810 ClassDescriptionSize, RequiredSize, debugstr_w(MachineName), Reserved);
811
812 if (!ClassGuid)
813 {
814 SetLastError(ERROR_INVALID_PARAMETER);
815 goto cleanup;
816 }
817 else if (!ClassDescription && ClassDescriptionSize > 0)
818 {
819 SetLastError(ERROR_INVALID_PARAMETER);
820 goto cleanup;
821 }
822
823 hKey = SetupDiOpenClassRegKeyExW(ClassGuid,
824 KEY_QUERY_VALUE,
825 DIOCR_INSTALLER,
826 MachineName,
827 Reserved);
828 if (hKey == INVALID_HANDLE_VALUE)
829 {
830 WARN("SetupDiOpenClassRegKeyExW() failed (Error %lu)\n", GetLastError());
831 goto cleanup;
832 }
833
834 if (ClassDescriptionSize < sizeof(UNICODE_NULL) || !ClassDescription)
835 dwLength = 0;
836 else
837 dwLength = ClassDescriptionSize * sizeof(WCHAR) - sizeof(UNICODE_NULL);
838
839 rc = RegQueryValueExW(hKey,
840 NULL,
841 NULL,
842 &dwRegType,
843 (LPBYTE)ClassDescription,
844 &dwLength);
845 if (rc != ERROR_MORE_DATA && rc != ERROR_SUCCESS)
846 {
847 SetLastError(rc);
848 goto cleanup;
849 }
850 else if (dwRegType != REG_SZ)
851 {
852 SetLastError(ERROR_GEN_FAILURE);
853 goto cleanup;
854 }
855
856 if (RequiredSize)
857 *RequiredSize = dwLength / sizeof(WCHAR) + 1;
858
859 if (ClassDescriptionSize * sizeof(WCHAR) >= dwLength + sizeof(UNICODE_STRING))
860 {
861 if (ClassDescriptionSize > sizeof(UNICODE_NULL))
862 ClassDescription[ClassDescriptionSize / sizeof(WCHAR)] = UNICODE_NULL;
863 ret = TRUE;
864 }
865 else
866 SetLastError(ERROR_INSUFFICIENT_BUFFER);
867
868 cleanup:
869 if (hKey != INVALID_HANDLE_VALUE)
870 RegCloseKey(hKey);
871 return ret;
872 }
873
874 /***********************************************************************
875 * SetupDiGetClassDevsA (SETUPAPI.@)
876 */
877 HDEVINFO WINAPI
878 SetupDiGetClassDevsA(
879 IN CONST GUID *ClassGuid OPTIONAL,
880 IN PCSTR Enumerator OPTIONAL,
881 IN HWND hwndParent OPTIONAL,
882 IN DWORD Flags)
883 {
884 return SetupDiGetClassDevsExA(ClassGuid, Enumerator, hwndParent,
885 Flags, NULL, NULL, NULL);
886 }
887
888 /***********************************************************************
889 * SetupDiGetClassDevsW (SETUPAPI.@)
890 */
891 HDEVINFO WINAPI
892 SetupDiGetClassDevsW(
893 IN CONST GUID *ClassGuid OPTIONAL,
894 IN PCWSTR Enumerator OPTIONAL,
895 IN HWND hwndParent OPTIONAL,
896 IN DWORD Flags)
897 {
898 return SetupDiGetClassDevsExW(ClassGuid, Enumerator, hwndParent,
899 Flags, NULL, NULL, NULL);
900 }
901
902 /***********************************************************************
903 * SetupDiGetClassDevsExA (SETUPAPI.@)
904 */
905 HDEVINFO WINAPI
906 SetupDiGetClassDevsExA(
907 IN CONST GUID *ClassGuid OPTIONAL,
908 IN PCSTR Enumerator OPTIONAL,
909 IN HWND hwndParent OPTIONAL,
910 IN DWORD Flags,
911 IN HDEVINFO DeviceInfoSet OPTIONAL,
912 IN PCSTR MachineName OPTIONAL,
913 IN PVOID Reserved)
914 {
915 LPWSTR EnumeratorW = NULL;
916 LPWSTR MachineNameW = NULL;
917 HDEVINFO ret = (HDEVINFO)INVALID_HANDLE_VALUE;
918
919 if (Enumerator)
920 {
921 EnumeratorW = MultiByteToUnicode(Enumerator, CP_ACP);
922 if (!EnumeratorW)
923 goto cleanup;
924 }
925 if (MachineName)
926 {
927 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
928 if (!MachineNameW)
929 goto cleanup;
930 }
931 ret = SetupDiGetClassDevsExW(ClassGuid, EnumeratorW, hwndParent,
932 Flags, DeviceInfoSet, MachineNameW, Reserved);
933
934 cleanup:
935 MyFree(EnumeratorW);
936 MyFree(MachineNameW);
937 return ret;
938 }
939
940 /***********************************************************************
941 * SETUP_CreateDevicesListFromEnumerator
942 *
943 * PARAMS
944 * list [IO] Device info set to fill with discovered devices.
945 * pClassGuid [I] If specified, only devices which belong to this class will be added.
946 * Enumerator [I] Location to search devices to add.
947 * hEnumeratorKey [I] Registry key corresponding to Enumerator key. Must have KEY_ENUMERATE_SUB_KEYS right.
948 *
949 * RETURNS
950 * Success: ERROR_SUCCESS.
951 * Failure: an error code.
952 */
953 static LONG
954 SETUP_CreateDevicesListFromEnumerator(
955 IN OUT struct DeviceInfoSet *list,
956 IN CONST GUID *pClassGuid OPTIONAL,
957 IN LPCWSTR Enumerator,
958 IN HKEY hEnumeratorKey) /* handle to Enumerator registry key */
959 {
960 HKEY hDeviceIdKey = NULL, hInstanceIdKey;
961 WCHAR KeyBuffer[MAX_PATH];
962 WCHAR InstancePath[MAX_PATH];
963 LPWSTR pEndOfInstancePath; /* Pointer into InstancePath buffer */
964 struct DeviceInfoElement *deviceInfo;
965 DWORD i = 0, j;
966 DWORD dwLength, dwRegType;
967 DWORD rc;
968
969 /* Enumerate device IDs (subkeys of hEnumeratorKey) */
970 while (TRUE)
971 {
972 dwLength = sizeof(KeyBuffer) / sizeof(KeyBuffer[0]);
973 rc = RegEnumKeyExW(hEnumeratorKey, i, KeyBuffer, &dwLength, NULL, NULL, NULL, NULL);
974 if (rc == ERROR_NO_MORE_ITEMS)
975 break;
976 if (rc != ERROR_SUCCESS)
977 goto cleanup;
978 i++;
979
980 /* Open device id sub key */
981 if (hDeviceIdKey != NULL)
982 RegCloseKey(hDeviceIdKey);
983 rc = RegOpenKeyExW(hEnumeratorKey, KeyBuffer, 0, KEY_ENUMERATE_SUB_KEYS, &hDeviceIdKey);
984 if (rc != ERROR_SUCCESS)
985 goto cleanup;
986 strcpyW(InstancePath, Enumerator);
987 strcatW(InstancePath, BackSlash);
988 strcatW(InstancePath, KeyBuffer);
989 strcatW(InstancePath, BackSlash);
990 pEndOfInstancePath = &InstancePath[strlenW(InstancePath)];
991
992 /* Enumerate instance IDs (subkeys of hDeviceIdKey) */
993 j = 0;
994 while (TRUE)
995 {
996 GUID KeyGuid;
997
998 dwLength = sizeof(KeyBuffer) / sizeof(KeyBuffer[0]);
999 rc = RegEnumKeyExW(hDeviceIdKey, j, KeyBuffer, &dwLength, NULL, NULL, NULL, NULL);
1000 if (rc == ERROR_NO_MORE_ITEMS)
1001 break;
1002 if (rc != ERROR_SUCCESS)
1003 goto cleanup;
1004 j++;
1005
1006 /* Open instance id sub key */
1007 rc = RegOpenKeyExW(hDeviceIdKey, KeyBuffer, 0, KEY_QUERY_VALUE, &hInstanceIdKey);
1008 if (rc != ERROR_SUCCESS)
1009 goto cleanup;
1010 *pEndOfInstancePath = '\0';
1011 strcatW(InstancePath, KeyBuffer);
1012
1013 /* Read ClassGUID value */
1014 dwLength = sizeof(KeyBuffer) - sizeof(WCHAR);
1015 rc = RegQueryValueExW(hInstanceIdKey, ClassGUID, NULL, &dwRegType, (LPBYTE)KeyBuffer, &dwLength);
1016 RegCloseKey(hInstanceIdKey);
1017 if (rc == ERROR_FILE_NOT_FOUND)
1018 {
1019 if (pClassGuid)
1020 /* Skip this bad entry as we can't verify it */
1021 continue;
1022 /* Set a default GUID for this device */
1023 memcpy(&KeyGuid, &GUID_NULL, sizeof(GUID));
1024 }
1025 else if (rc != ERROR_SUCCESS)
1026 {
1027 goto cleanup;
1028 }
1029 else if (dwRegType != REG_SZ || dwLength < MAX_GUID_STRING_LEN * sizeof(WCHAR))
1030 {
1031 rc = ERROR_GEN_FAILURE;
1032 goto cleanup;
1033 }
1034 else
1035 {
1036 KeyBuffer[MAX_GUID_STRING_LEN - 2] = '\0'; /* Replace the } by a NULL character */
1037 if (UuidFromStringW(&KeyBuffer[1], &KeyGuid) != RPC_S_OK)
1038 /* Bad GUID, skip the entry */
1039 continue;
1040 }
1041
1042 if (pClassGuid && !IsEqualIID(&KeyGuid, pClassGuid))
1043 {
1044 /* Skip this entry as it is not the right device class */
1045 continue;
1046 }
1047
1048 /* Add the entry to the list */
1049 if (!CreateDeviceInfoElement(list, InstancePath, &KeyGuid, &deviceInfo))
1050 {
1051 rc = GetLastError();
1052 goto cleanup;
1053 }
1054 TRACE("Adding '%s' to device info set %p\n", debugstr_w(InstancePath), list);
1055 InsertTailList(&list->ListHead, &deviceInfo->ListEntry);
1056 }
1057 }
1058
1059 rc = ERROR_SUCCESS;
1060
1061 cleanup:
1062 if (hDeviceIdKey != NULL)
1063 RegCloseKey(hDeviceIdKey);
1064 return rc;
1065 }
1066
1067 static LONG
1068 SETUP_CreateDevicesList(
1069 IN OUT struct DeviceInfoSet *list,
1070 IN PCWSTR MachineName OPTIONAL,
1071 IN CONST GUID *Class OPTIONAL,
1072 IN PCWSTR Enumerator OPTIONAL)
1073 {
1074 HKEY HKLM = HKEY_LOCAL_MACHINE;
1075 HKEY hEnumKey = NULL;
1076 HKEY hEnumeratorKey = NULL;
1077 WCHAR KeyBuffer[MAX_PATH];
1078 DWORD i;
1079 DWORD dwLength;
1080 DWORD rc;
1081
1082 if (Class && IsEqualIID(Class, &GUID_NULL))
1083 Class = NULL;
1084
1085 /* Open Enum key (if applicable) */
1086 if (MachineName != NULL)
1087 {
1088 rc = RegConnectRegistryW(MachineName, HKEY_LOCAL_MACHINE, &HKLM);
1089 if (rc != ERROR_SUCCESS)
1090 goto cleanup;
1091 }
1092
1093 rc = RegOpenKeyExW(
1094 HKLM,
1095 REGSTR_PATH_SYSTEMENUM,
1096 0,
1097 KEY_ENUMERATE_SUB_KEYS,
1098 &hEnumKey);
1099 if (rc != ERROR_SUCCESS)
1100 goto cleanup;
1101
1102 /* If enumerator is provided, call directly SETUP_CreateDevicesListFromEnumerator.
1103 * Else, enumerate all enumerators and call SETUP_CreateDevicesListFromEnumerator
1104 * for each one.
1105 */
1106 if (Enumerator)
1107 {
1108 rc = RegOpenKeyExW(
1109 hEnumKey,
1110 Enumerator,
1111 0,
1112 KEY_ENUMERATE_SUB_KEYS,
1113 &hEnumeratorKey);
1114 if (rc != ERROR_SUCCESS)
1115 {
1116 if (rc == ERROR_FILE_NOT_FOUND)
1117 rc = ERROR_INVALID_DATA;
1118 goto cleanup;
1119 }
1120 rc = SETUP_CreateDevicesListFromEnumerator(list, Class, Enumerator, hEnumeratorKey);
1121 }
1122 else
1123 {
1124 /* Enumerate enumerators */
1125 i = 0;
1126 while (TRUE)
1127 {
1128 dwLength = sizeof(KeyBuffer) / sizeof(KeyBuffer[0]);
1129 rc = RegEnumKeyExW(hEnumKey, i, KeyBuffer, &dwLength, NULL, NULL, NULL, NULL);
1130 if (rc == ERROR_NO_MORE_ITEMS)
1131 break;
1132 else if (rc != ERROR_SUCCESS)
1133 goto cleanup;
1134 i++;
1135
1136 /* Open sub key */
1137 if (hEnumeratorKey != NULL)
1138 RegCloseKey(hEnumeratorKey);
1139 rc = RegOpenKeyExW(hEnumKey, KeyBuffer, 0, KEY_ENUMERATE_SUB_KEYS, &hEnumeratorKey);
1140 if (rc != ERROR_SUCCESS)
1141 goto cleanup;
1142
1143 /* Call SETUP_CreateDevicesListFromEnumerator */
1144 rc = SETUP_CreateDevicesListFromEnumerator(list, Class, KeyBuffer, hEnumeratorKey);
1145 if (rc != ERROR_SUCCESS)
1146 goto cleanup;
1147 }
1148 rc = ERROR_SUCCESS;
1149 }
1150
1151 cleanup:
1152 if (HKLM != HKEY_LOCAL_MACHINE)
1153 RegCloseKey(HKLM);
1154 if (hEnumKey != NULL)
1155 RegCloseKey(hEnumKey);
1156 if (hEnumeratorKey != NULL)
1157 RegCloseKey(hEnumeratorKey);
1158 return rc;
1159 }
1160
1161 /***********************************************************************
1162 * SetupDiGetClassDevsExW (SETUPAPI.@)
1163 */
1164 HDEVINFO WINAPI
1165 SetupDiGetClassDevsExW(
1166 IN CONST GUID *ClassGuid OPTIONAL,
1167 IN PCWSTR Enumerator OPTIONAL,
1168 IN HWND hwndParent OPTIONAL,
1169 IN DWORD Flags,
1170 IN HDEVINFO DeviceInfoSet OPTIONAL,
1171 IN PCWSTR MachineName OPTIONAL,
1172 IN PVOID Reserved)
1173 {
1174 HDEVINFO hDeviceInfo = INVALID_HANDLE_VALUE;
1175 struct DeviceInfoSet *list;
1176 CONST GUID *pClassGuid;
1177 LONG rc;
1178 HDEVINFO ret = INVALID_HANDLE_VALUE;
1179
1180 TRACE("%s %s %p 0x%08lx %p %s %p\n", debugstr_guid(ClassGuid), debugstr_w(Enumerator),
1181 hwndParent, Flags, DeviceInfoSet, debugstr_w(MachineName), Reserved);
1182
1183 /* Create the deviceset if not set */
1184 if (DeviceInfoSet)
1185 {
1186 list = (struct DeviceInfoSet *)DeviceInfoSet;
1187 if (list->magic != SETUP_DEV_INFO_SET_MAGIC)
1188 {
1189 SetLastError(ERROR_INVALID_HANDLE);
1190 goto cleanup;
1191 }
1192 hDeviceInfo = DeviceInfoSet;
1193 }
1194 else
1195 {
1196 hDeviceInfo = SetupDiCreateDeviceInfoListExW(
1197 Flags & (DIGCF_DEVICEINTERFACE | DIGCF_ALLCLASSES) ? NULL : ClassGuid,
1198 NULL, MachineName, NULL);
1199 if (hDeviceInfo == INVALID_HANDLE_VALUE)
1200 goto cleanup;
1201 list = (struct DeviceInfoSet *)hDeviceInfo;
1202 }
1203
1204 if (Flags & DIGCF_PROFILE)
1205 FIXME(": flag DIGCF_PROFILE ignored\n");
1206
1207 if (Flags & DIGCF_DEVICEINTERFACE)
1208 rc = SETUP_CreateInterfaceList(list, MachineName, ClassGuid, Enumerator, Flags & DIGCF_PRESENT);
1209 else
1210 {
1211 /* Determine which class(es) should be included in the deviceset */
1212 if (Flags & DIGCF_ALLCLASSES)
1213 {
1214 /* The caller wants all classes. Check if
1215 * the deviceset limits us to one class */
1216 if (IsEqualIID(&list->ClassGuid, &GUID_NULL))
1217 pClassGuid = NULL;
1218 else
1219 pClassGuid = &list->ClassGuid;
1220 }
1221 else if (ClassGuid)
1222 {
1223 /* The caller wants one class. Check if it matches deviceset class */
1224 if (IsEqualIID(&list->ClassGuid, ClassGuid)
1225 || IsEqualIID(&list->ClassGuid, &GUID_NULL))
1226 {
1227 pClassGuid = ClassGuid;
1228 }
1229 else
1230 {
1231 SetLastError(ERROR_INVALID_PARAMETER);
1232 goto cleanup;
1233 }
1234 }
1235 else if (!IsEqualIID(&list->ClassGuid, &GUID_NULL))
1236 {
1237 /* No class specified. Try to use the one of the deviceset */
1238 if (IsEqualIID(&list->ClassGuid, &GUID_NULL))
1239 pClassGuid = &list->ClassGuid;
1240 else
1241 {
1242 SetLastError(ERROR_INVALID_PARAMETER);
1243 goto cleanup;
1244 }
1245 }
1246 else
1247 {
1248 SetLastError(ERROR_INVALID_PARAMETER);
1249 goto cleanup;
1250 }
1251 rc = SETUP_CreateDevicesList(list, MachineName, pClassGuid, Enumerator);
1252 }
1253 if (rc != ERROR_SUCCESS)
1254 {
1255 SetLastError(rc);
1256 goto cleanup;
1257 }
1258 ret = hDeviceInfo;
1259
1260 cleanup:
1261 if (!DeviceInfoSet && hDeviceInfo != INVALID_HANDLE_VALUE && hDeviceInfo != ret)
1262 SetupDiDestroyDeviceInfoList(hDeviceInfo);
1263 return ret;
1264 }
1265
1266 /***********************************************************************
1267 * SetupDiGetClassImageIndex (SETUPAPI.@)
1268 */
1269 static BOOL
1270 SETUP_GetIconIndex(
1271 IN HKEY hClassKey,
1272 OUT PINT ImageIndex)
1273 {
1274 LPWSTR Buffer = NULL;
1275 DWORD dwRegType, dwLength;
1276 LONG rc;
1277 BOOL ret = FALSE;
1278
1279 /* Read icon registry key */
1280 rc = RegQueryValueExW(hClassKey, REGSTR_VAL_INSICON, NULL, &dwRegType, NULL, &dwLength);
1281 if (rc != ERROR_SUCCESS)
1282 {
1283 SetLastError(rc);
1284 goto cleanup;
1285 } else if (dwRegType != REG_SZ)
1286 {
1287 SetLastError(ERROR_INVALID_INDEX);
1288 goto cleanup;
1289 }
1290 Buffer = MyMalloc(dwLength + sizeof(WCHAR));
1291 if (!Buffer)
1292 {
1293 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1294 goto cleanup;
1295 }
1296 rc = RegQueryValueExW(hClassKey, REGSTR_VAL_INSICON, NULL, NULL, (LPBYTE)Buffer, &dwLength);
1297 if (rc != ERROR_SUCCESS)
1298 {
1299 SetLastError(rc);
1300 goto cleanup;
1301 }
1302 /* make sure the returned buffer is NULL-terminated */
1303 Buffer[dwLength / sizeof(WCHAR)] = 0;
1304
1305 /* Transform icon value to a INT */
1306 *ImageIndex = atoiW(Buffer);
1307 ret = TRUE;
1308
1309 cleanup:
1310 MyFree(Buffer);
1311 return ret;
1312 }
1313
1314 BOOL WINAPI
1315 SetupDiGetClassImageIndex(
1316 IN PSP_CLASSIMAGELIST_DATA ClassImageListData,
1317 IN CONST GUID *ClassGuid,
1318 OUT PINT ImageIndex)
1319 {
1320 struct ClassImageList *list;
1321 BOOL ret = FALSE;
1322
1323 TRACE("%p %s %p\n", ClassImageListData, debugstr_guid(ClassGuid), ImageIndex);
1324
1325 if (!ClassImageListData || !ClassGuid || !ImageIndex)
1326 SetLastError(ERROR_INVALID_PARAMETER);
1327 else if (ClassImageListData->cbSize != sizeof(SP_CLASSIMAGELIST_DATA))
1328 SetLastError(ERROR_INVALID_USER_BUFFER);
1329 else if ((list = (struct ClassImageList *)ClassImageListData->Reserved) == NULL)
1330 SetLastError(ERROR_INVALID_USER_BUFFER);
1331 else if (list->magic != SETUP_CLASS_IMAGE_LIST_MAGIC)
1332 SetLastError(ERROR_INVALID_USER_BUFFER);
1333 else if (!ImageIndex)
1334 SetLastError(ERROR_INVALID_PARAMETER);
1335 else
1336 {
1337 DWORD i;
1338
1339 for (i = 0; i < list->NumberOfGuids; i++)
1340 {
1341 if (IsEqualIID(ClassGuid, &list->Guids[i]))
1342 break;
1343 }
1344
1345 if (i == list->NumberOfGuids || list->IconIndexes[i] < 0)
1346 SetLastError(ERROR_FILE_NOT_FOUND);
1347 else
1348 {
1349 *ImageIndex = list->IconIndexes[i];
1350 ret = TRUE;
1351 }
1352 }
1353
1354 TRACE("Returning %d\n", ret);
1355 return ret;
1356 }
1357
1358 /***********************************************************************
1359 * SetupDiGetClassImageList(SETUPAPI.@)
1360 */
1361 BOOL WINAPI
1362 SetupDiGetClassImageList(
1363 OUT PSP_CLASSIMAGELIST_DATA ClassImageListData)
1364 {
1365 return SetupDiGetClassImageListExW(ClassImageListData, NULL, NULL);
1366 }
1367
1368 /***********************************************************************
1369 * SetupDiGetClassImageListExA(SETUPAPI.@)
1370 */
1371 BOOL WINAPI
1372 SetupDiGetClassImageListExA(
1373 OUT PSP_CLASSIMAGELIST_DATA ClassImageListData,
1374 IN PCSTR MachineName OPTIONAL,
1375 IN PVOID Reserved)
1376 {
1377 PWSTR MachineNameW = NULL;
1378 BOOL ret;
1379
1380 if (MachineName)
1381 {
1382 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
1383 if (MachineNameW == NULL)
1384 return FALSE;
1385 }
1386
1387 ret = SetupDiGetClassImageListExW(ClassImageListData, MachineNameW, Reserved);
1388
1389 MyFree(MachineNameW);
1390
1391 return ret;
1392 }
1393
1394 /***********************************************************************
1395 * SetupDiGetClassImageListExW(SETUPAPI.@)
1396 */
1397 BOOL WINAPI
1398 SetupDiGetClassImageListExW(
1399 OUT PSP_CLASSIMAGELIST_DATA ClassImageListData,
1400 IN PCWSTR MachineName OPTIONAL,
1401 IN PVOID Reserved)
1402 {
1403 BOOL ret = FALSE;
1404
1405 TRACE("%p %p %p\n", ClassImageListData, debugstr_w(MachineName), Reserved);
1406
1407 if (!ClassImageListData)
1408 SetLastError(ERROR_INVALID_PARAMETER);
1409 else if (ClassImageListData->cbSize != sizeof(SP_CLASSIMAGELIST_DATA))
1410 SetLastError(ERROR_INVALID_USER_BUFFER);
1411 else if (Reserved)
1412 SetLastError(ERROR_INVALID_PARAMETER);
1413 else
1414 {
1415 struct ClassImageList *list = NULL;
1416 DWORD RequiredSize;
1417 HICON hIcon;
1418 DWORD size;
1419 INT i;
1420
1421 /* Get list of all class GUIDs in given computer */
1422 ret = SetupDiBuildClassInfoListExW(
1423 0,
1424 NULL,
1425 0,
1426 &RequiredSize,
1427 MachineName,
1428 NULL);
1429 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
1430 goto cleanup;
1431
1432 size = sizeof(struct ClassImageList)
1433 + (sizeof(GUID) + sizeof(INT)) * RequiredSize;
1434 list = HeapAlloc(GetProcessHeap(), 0, size);
1435 if (!list)
1436 {
1437 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1438 goto cleanup;
1439 }
1440 list->magic = SETUP_CLASS_IMAGE_LIST_MAGIC;
1441 list->NumberOfGuids = RequiredSize;
1442 list->Guids = (GUID*)(list + 1);
1443 list->IconIndexes = (INT*)((ULONG_PTR)(list + 1) + sizeof(GUID) * RequiredSize);
1444
1445 ret = SetupDiBuildClassInfoListExW(
1446 0,
1447 list->Guids,
1448 list->NumberOfGuids,
1449 &RequiredSize,
1450 MachineName,
1451 NULL);
1452 if (!ret)
1453 goto cleanup;
1454 else if (RequiredSize != list->NumberOfGuids)
1455 {
1456 /* Hm. Class list changed since last call. Ignore
1457 * this case as it should be very rare */
1458 SetLastError(ERROR_GEN_FAILURE);
1459 ret = FALSE;
1460 goto cleanup;
1461 }
1462
1463 /* Prepare a HIMAGELIST */
1464 InitCommonControls();
1465 ClassImageListData->ImageList = ImageList_Create(16, 16, ILC_COLOR, 100, 10);
1466 if (!ClassImageListData->ImageList)
1467 goto cleanup;
1468
1469 ClassImageListData->Reserved = (ULONG_PTR)list;
1470
1471 /* Now, we "simply" need to load icons associated with all class guids,
1472 * and put their index in the image list in the IconIndexes array */
1473 for (i = 0; i < list->NumberOfGuids; i++)
1474 {
1475 ret = SetupDiLoadClassIcon(
1476 &list->Guids[i],
1477 &hIcon,
1478 NULL);
1479 if (ret)
1480 list->IconIndexes[i] = ImageList_AddIcon(ClassImageListData->ImageList, hIcon);
1481 else
1482 list->IconIndexes[i] = -1; /* Special value to tell that icon is unavailable */
1483 }
1484
1485 ret = TRUE;
1486
1487 cleanup:
1488 if (!ret)
1489 {
1490 if (ClassImageListData->Reserved)
1491 SetupDiDestroyClassImageList(ClassImageListData);
1492 else if (list)
1493 MyFree(list);
1494 }
1495 }
1496
1497 TRACE("Returning %d\n", ret);
1498 return ret;
1499 }
1500
1501 /***********************************************************************
1502 * SetupDiLoadClassIcon(SETUPAPI.@)
1503 */
1504 BOOL WINAPI
1505 SetupDiLoadClassIcon(
1506 IN CONST GUID *ClassGuid,
1507 OUT HICON *LargeIcon OPTIONAL,
1508 OUT PINT MiniIconIndex OPTIONAL)
1509 {
1510 BOOL ret = FALSE;
1511
1512 if (!ClassGuid)
1513 SetLastError(ERROR_INVALID_PARAMETER);
1514 else
1515 {
1516 LPWSTR Buffer = NULL;
1517 LPCWSTR DllName;
1518 INT iconIndex;
1519 HKEY hKey = INVALID_HANDLE_VALUE;
1520
1521 hKey = SetupDiOpenClassRegKey(ClassGuid, KEY_QUERY_VALUE);
1522 if (hKey == INVALID_HANDLE_VALUE)
1523 goto cleanup;
1524
1525 if (!SETUP_GetIconIndex(hKey, &iconIndex))
1526 goto cleanup;
1527
1528 if (iconIndex > 0)
1529 {
1530 /* Look up icon in dll specified by Installer32 or EnumPropPages32 key */
1531 PWCHAR Comma;
1532 LONG rc;
1533 DWORD dwRegType, dwLength;
1534 rc = RegQueryValueExW(hKey, REGSTR_VAL_INSTALLER_32, NULL, &dwRegType, NULL, &dwLength);
1535 if (rc == ERROR_SUCCESS && dwRegType == REG_SZ)
1536 {
1537 Buffer = MyMalloc(dwLength + sizeof(WCHAR));
1538 if (Buffer == NULL)
1539 {
1540 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1541 goto cleanup;
1542 }
1543 rc = RegQueryValueExW(hKey, REGSTR_VAL_INSTALLER_32, NULL, NULL, (LPBYTE)Buffer, &dwLength);
1544 if (rc != ERROR_SUCCESS)
1545 {
1546 SetLastError(rc);
1547 goto cleanup;
1548 }
1549 /* make sure the returned buffer is NULL-terminated */
1550 Buffer[dwLength / sizeof(WCHAR)] = 0;
1551 }
1552 else if
1553 (ERROR_SUCCESS == (rc = RegQueryValueExW(hKey, REGSTR_VAL_ENUMPROPPAGES_32, NULL, &dwRegType, NULL, &dwLength))
1554 && dwRegType == REG_SZ)
1555 {
1556 Buffer = MyMalloc(dwLength + sizeof(WCHAR));
1557 if (Buffer == NULL)
1558 {
1559 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1560 goto cleanup;
1561 }
1562 rc = RegQueryValueExW(hKey, REGSTR_VAL_ENUMPROPPAGES_32, NULL, NULL, (LPBYTE)Buffer, &dwLength);
1563 if (rc != ERROR_SUCCESS)
1564 {
1565 SetLastError(rc);
1566 goto cleanup;
1567 }
1568 /* make sure the returned buffer is NULL-terminated */
1569 Buffer[dwLength / sizeof(WCHAR)] = 0;
1570 }
1571 else
1572 {
1573 /* Unable to find where to load the icon */
1574 SetLastError(ERROR_FILE_NOT_FOUND);
1575 goto cleanup;
1576 }
1577 Comma = strchrW(Buffer, ',');
1578 if (!Comma)
1579 {
1580 SetLastError(ERROR_GEN_FAILURE);
1581 goto cleanup;
1582 }
1583 *Comma = '\0';
1584 DllName = Buffer;
1585 }
1586 else
1587 {
1588 /* Look up icon in setupapi.dll */
1589 DllName = L"setupapi.dll";
1590 iconIndex = -iconIndex;
1591 }
1592
1593 TRACE("Icon index %d, dll name %s\n", iconIndex, debugstr_w(DllName));
1594 if (LargeIcon)
1595 {
1596 if (1 != ExtractIconEx(DllName, iconIndex, LargeIcon, NULL, 1))
1597 {
1598 SetLastError(ERROR_INVALID_INDEX);
1599 goto cleanup;
1600 }
1601 }
1602 if (MiniIconIndex)
1603 *MiniIconIndex = iconIndex;
1604 ret = TRUE;
1605
1606 cleanup:
1607 if (hKey != INVALID_HANDLE_VALUE)
1608 RegCloseKey(hKey);
1609 MyFree(Buffer);
1610 }
1611
1612 TRACE("Returning %d\n", ret);
1613 return ret;
1614 }
1615
1616 /***********************************************************************
1617 * SetupDiInstallClassA (SETUPAPI.@)
1618 */
1619 BOOL WINAPI
1620 SetupDiInstallClassA(
1621 IN HWND hwndParent OPTIONAL,
1622 IN PCSTR InfFileName,
1623 IN DWORD Flags,
1624 IN HSPFILEQ FileQueue OPTIONAL)
1625 {
1626 return SetupDiInstallClassExA(hwndParent, InfFileName, Flags, FileQueue, NULL, NULL, NULL);
1627 }
1628
1629 /***********************************************************************
1630 * SetupDiInstallClassW (SETUPAPI.@)
1631 */
1632 BOOL WINAPI
1633 SetupDiInstallClassW(
1634 IN HWND hwndParent OPTIONAL,
1635 IN PCWSTR InfFileName,
1636 IN DWORD Flags,
1637 IN HSPFILEQ FileQueue OPTIONAL)
1638 {
1639 return SetupDiInstallClassExW(hwndParent, InfFileName, Flags, FileQueue, NULL, NULL, NULL);
1640 }
1641
1642 /***********************************************************************
1643 * SetupDiInstallClassExA (SETUPAPI.@)
1644 */
1645 BOOL WINAPI
1646 SetupDiInstallClassExA(
1647 IN HWND hwndParent OPTIONAL,
1648 IN PCSTR InfFileName OPTIONAL,
1649 IN DWORD Flags,
1650 IN HSPFILEQ FileQueue OPTIONAL,
1651 IN CONST GUID *InterfaceClassGuid OPTIONAL,
1652 IN PVOID Reserved1,
1653 IN PVOID Reserved2)
1654 {
1655 PWSTR InfFileNameW = NULL;
1656 BOOL Result;
1657
1658 if (InfFileName)
1659 {
1660 InfFileNameW = MultiByteToUnicode(InfFileName, CP_ACP);
1661 if (InfFileNameW == NULL)
1662 {
1663 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1664 return FALSE;
1665 }
1666 }
1667
1668 Result = SetupDiInstallClassExW(hwndParent, InfFileNameW, Flags,
1669 FileQueue, InterfaceClassGuid, Reserved1, Reserved2);
1670
1671 MyFree(InfFileNameW);
1672
1673 return Result;
1674 }
1675
1676 /***********************************************************************
1677 * Helper function for SetupDiInstallClassExW
1678 */
1679 static HKEY
1680 SETUP_CreateClassKey(HINF hInf)
1681 {
1682 WCHAR FullBuffer[MAX_PATH];
1683 WCHAR Buffer[MAX_PATH];
1684 DWORD RequiredSize;
1685 HKEY hClassKey = NULL;
1686 HKEY ret = INVALID_HANDLE_VALUE;
1687
1688 FullBuffer[0] = '\0';
1689 Buffer[0] = '\\';
1690 if (!SetupGetLineTextW(NULL,
1691 hInf,
1692 Version,
1693 ClassGUID,
1694 &Buffer[1],
1695 MAX_PATH - 1,
1696 &RequiredSize))
1697 {
1698 goto cleanup;
1699 }
1700
1701 lstrcpyW(FullBuffer, REGSTR_PATH_CLASS_NT);
1702 lstrcatW(FullBuffer, Buffer);
1703
1704 if (!SetupGetLineTextW(NULL,
1705 hInf,
1706 Version,
1707 Class,
1708 Buffer,
1709 MAX_PATH,
1710 &RequiredSize))
1711 {
1712 RegDeleteKeyW(HKEY_LOCAL_MACHINE, FullBuffer);
1713 goto cleanup;
1714 }
1715
1716 if (ERROR_SUCCESS != RegCreateKeyExW(HKEY_LOCAL_MACHINE,
1717 FullBuffer,
1718 0,
1719 NULL,
1720 REG_OPTION_NON_VOLATILE,
1721 KEY_SET_VALUE,
1722 NULL,
1723 &hClassKey,
1724 NULL))
1725 {
1726 goto cleanup;
1727 }
1728
1729 if (ERROR_SUCCESS != RegSetValueExW(hClassKey,
1730 Class,
1731 0,
1732 REG_SZ,
1733 (LPBYTE)Buffer,
1734 RequiredSize * sizeof(WCHAR)))
1735 {
1736 goto cleanup;
1737 }
1738
1739 ret = hClassKey;
1740
1741 cleanup:
1742 if (hClassKey != NULL && hClassKey != ret)
1743 RegCloseKey(hClassKey);
1744 if (ret == INVALID_HANDLE_VALUE && FullBuffer[0] != '\0')
1745 RegDeleteKeyW(HKEY_LOCAL_MACHINE, FullBuffer);
1746 return ret;
1747 }
1748
1749 /***********************************************************************
1750 * SetupDiInstallClassExW (SETUPAPI.@)
1751 */
1752 BOOL WINAPI
1753 SetupDiInstallClassExW(
1754 IN HWND hwndParent OPTIONAL,
1755 IN PCWSTR InfFileName OPTIONAL,
1756 IN DWORD Flags,
1757 IN HSPFILEQ FileQueue OPTIONAL,
1758 IN CONST GUID *InterfaceClassGuid OPTIONAL,
1759 IN PVOID Reserved1,
1760 IN PVOID Reserved2)
1761 {
1762 BOOL ret = FALSE;
1763
1764 TRACE("%p %s 0x%lx %p %s %p %p\n", hwndParent, debugstr_w(InfFileName), Flags,
1765 FileQueue, debugstr_guid(InterfaceClassGuid), Reserved1, Reserved2);
1766
1767 if (!InfFileName)
1768 {
1769 FIXME("Case not implemented: InfFileName NULL\n");
1770 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1771 }
1772 else if (Flags & ~(DI_NOVCP | DI_NOBROWSE | DI_FORCECOPY | DI_QUIETINSTALL))
1773 {
1774 TRACE("Unknown flags: 0x%08lx\n", Flags & ~(DI_NOVCP | DI_NOBROWSE | DI_FORCECOPY | DI_QUIETINSTALL));
1775 SetLastError(ERROR_INVALID_FLAGS);
1776 }
1777 else if ((Flags & DI_NOVCP) && FileQueue == NULL)
1778 SetLastError(ERROR_INVALID_PARAMETER);
1779 else if (Reserved1 != NULL)
1780 SetLastError(ERROR_INVALID_PARAMETER);
1781 else if (Reserved2 != NULL)
1782 SetLastError(ERROR_INVALID_PARAMETER);
1783 else
1784 {
1785 HDEVINFO hDeviceInfo = INVALID_HANDLE_VALUE;
1786 SP_DEVINSTALL_PARAMS_W InstallParams;
1787 WCHAR SectionName[MAX_PATH];
1788 HINF hInf = INVALID_HANDLE_VALUE;
1789 HKEY hRootKey = INVALID_HANDLE_VALUE;
1790 PVOID callback_context = NULL;
1791
1792 hDeviceInfo = SetupDiCreateDeviceInfoList(NULL, NULL);
1793 if (hDeviceInfo == INVALID_HANDLE_VALUE)
1794 goto cleanup;
1795
1796 InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
1797 if (!SetupDiGetDeviceInstallParamsW(hDeviceInfo, NULL, &InstallParams))
1798 goto cleanup;
1799 InstallParams.Flags &= ~(DI_NOVCP | DI_NOBROWSE | DI_QUIETINSTALL);
1800 InstallParams.Flags |= Flags & (DI_NOVCP | DI_NOBROWSE | DI_QUIETINSTALL);
1801 if (Flags & DI_NOVCP)
1802 InstallParams.FileQueue = FileQueue;
1803 if (!SetupDiSetDeviceInstallParamsW(hDeviceInfo, NULL, &InstallParams))
1804 goto cleanup;
1805
1806 /* Open the .inf file */
1807 hInf = SetupOpenInfFileW(
1808 InfFileName,
1809 NULL,
1810 INF_STYLE_WIN4,
1811 NULL);
1812 if (hInf == INVALID_HANDLE_VALUE)
1813 goto cleanup;
1814
1815 /* Try to append a layout file */
1816 ret = SetupOpenAppendInfFileW(NULL, hInf, NULL);
1817 if (!ret)
1818 goto cleanup;
1819
1820 if (InterfaceClassGuid)
1821 {
1822 /* Retrieve the actual section name */
1823 ret = SetupDiGetActualSectionToInstallW(
1824 hInf,
1825 InterfaceInstall32,
1826 SectionName,
1827 MAX_PATH,
1828 NULL,
1829 NULL);
1830 if (!ret)
1831 goto cleanup;
1832
1833 /* Open registry key related to this interface */
1834 /* FIXME: What happens if the key doesn't exist? */
1835 hRootKey = SetupDiOpenClassRegKeyExW(InterfaceClassGuid, KEY_ENUMERATE_SUB_KEYS, DIOCR_INTERFACE, NULL, NULL);
1836 if (hRootKey == INVALID_HANDLE_VALUE)
1837 goto cleanup;
1838
1839 /* SetupDiCreateDeviceInterface??? */
1840 FIXME("Installing an interface is not implemented\n");
1841 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1842 }
1843 else
1844 {
1845 /* Create or open the class registry key 'HKLM\CurrentControlSet\Class\{GUID}' */
1846 hRootKey = SETUP_CreateClassKey(hInf);
1847 if (hRootKey == INVALID_HANDLE_VALUE)
1848 goto cleanup;
1849
1850 /* Retrieve the actual section name */
1851 ret = SetupDiGetActualSectionToInstallW(
1852 hInf,
1853 ClassInstall32,
1854 SectionName,
1855 MAX_PATH - strlenW(DotServices),
1856 NULL,
1857 NULL);
1858 if (!ret)
1859 goto cleanup;
1860
1861 callback_context = SetupInitDefaultQueueCallback(hwndParent);
1862 if (!callback_context)
1863 goto cleanup;
1864
1865 ret = SetupInstallFromInfSectionW(
1866 hwndParent,
1867 hInf,
1868 SectionName,
1869 SPINST_REGISTRY | SPINST_FILES | SPINST_BITREG | SPINST_INIFILES | SPINST_INI2REG,
1870 hRootKey,
1871 NULL, /* FIXME: SourceRootPath */
1872 !(Flags & DI_NOVCP) && (Flags & DI_FORCECOPY) ? SP_COPY_FORCE_IN_USE : 0, /* CopyFlags */
1873 SetupDefaultQueueCallbackW,
1874 callback_context,
1875 hDeviceInfo,
1876 NULL);
1877 if (!ret)
1878 goto cleanup;
1879
1880 /* Install .Services section */
1881 lstrcatW(SectionName, DotServices);
1882 ret = SetupInstallServicesFromInfSectionExW(
1883 hInf,
1884 SectionName,
1885 0,
1886 hDeviceInfo,
1887 NULL,
1888 NULL,
1889 NULL);
1890 if (!ret)
1891 goto cleanup;
1892
1893 ret = TRUE;
1894 }
1895
1896 cleanup:
1897 if (hDeviceInfo != INVALID_HANDLE_VALUE)
1898 SetupDiDestroyDeviceInfoList(hDeviceInfo);
1899 if (hInf != INVALID_HANDLE_VALUE)
1900 SetupCloseInfFile(hInf);
1901 if (hRootKey != INVALID_HANDLE_VALUE)
1902 RegCloseKey(hRootKey);
1903 SetupTermDefaultQueueCallback(callback_context);
1904 }
1905
1906 TRACE("Returning %d\n", ret);
1907 return ret;
1908 }
1909
1910 /***********************************************************************
1911 * SetupDiOpenClassRegKey (SETUPAPI.@)
1912 */
1913 HKEY WINAPI
1914 SetupDiOpenClassRegKey(
1915 IN CONST GUID *ClassGuid OPTIONAL,
1916 IN REGSAM samDesired)
1917 {
1918 return SetupDiOpenClassRegKeyExW(ClassGuid, samDesired,
1919 DIOCR_INSTALLER, NULL, NULL);
1920 }
1921
1922 /***********************************************************************
1923 * SetupDiOpenClassRegKeyExA (SETUPAPI.@)
1924 */
1925 HKEY WINAPI
1926 SetupDiOpenClassRegKeyExA(
1927 IN CONST GUID *ClassGuid OPTIONAL,
1928 IN REGSAM samDesired,
1929 IN DWORD Flags,
1930 IN PCSTR MachineName OPTIONAL,
1931 IN PVOID Reserved)
1932 {
1933 PWSTR MachineNameW = NULL;
1934 HKEY hKey;
1935
1936 TRACE("%s 0x%lx 0x%lx %s %p\n", debugstr_guid(ClassGuid), samDesired,
1937 Flags, debugstr_a(MachineName), Reserved);
1938
1939 if (MachineName)
1940 {
1941 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
1942 if (MachineNameW == NULL)
1943 return INVALID_HANDLE_VALUE;
1944 }
1945
1946 hKey = SetupDiOpenClassRegKeyExW(ClassGuid, samDesired,
1947 Flags, MachineNameW, Reserved);
1948
1949 MyFree(MachineNameW);
1950
1951 return hKey;
1952 }
1953
1954 /***********************************************************************
1955 * SetupDiOpenClassRegKeyExW (SETUPAPI.@)
1956 */
1957 HKEY WINAPI
1958 SetupDiOpenClassRegKeyExW(
1959 IN CONST GUID* ClassGuid OPTIONAL,
1960 IN REGSAM samDesired,
1961 IN DWORD Flags,
1962 IN PCWSTR MachineName OPTIONAL,
1963 IN PVOID Reserved)
1964 {
1965 LPWSTR lpGuidString = NULL;
1966 LPWSTR lpFullGuidString = NULL;
1967 DWORD dwLength;
1968 HKEY HKLM;
1969 HKEY hClassesKey = NULL;
1970 HKEY hClassKey = NULL;
1971 HKEY ret = INVALID_HANDLE_VALUE;
1972 DWORD rc;
1973 LPCWSTR lpKeyName;
1974
1975 TRACE("%s 0x%lx 0x%lx %s %p\n", debugstr_guid(ClassGuid), samDesired,
1976 Flags, debugstr_w(MachineName), Reserved);
1977
1978 if (Flags == DIOCR_INSTALLER)
1979 lpKeyName = REGSTR_PATH_CLASS_NT;
1980 else if (Flags == DIOCR_INTERFACE)
1981 lpKeyName = REGSTR_PATH_DEVICE_CLASSES;
1982 else
1983 {
1984 TRACE("Unknown flags: 0x%lx\n", Flags);
1985 SetLastError(ERROR_INVALID_FLAGS);
1986 goto cleanup;
1987 }
1988
1989 if (MachineName != NULL)
1990 {
1991 rc = RegConnectRegistryW(MachineName, HKEY_LOCAL_MACHINE, &HKLM);
1992 if (rc != ERROR_SUCCESS)
1993 {
1994 SetLastError(rc);
1995 goto cleanup;
1996 }
1997 }
1998 else
1999 HKLM = HKEY_LOCAL_MACHINE;
2000
2001 rc = RegOpenKeyExW(HKLM,
2002 lpKeyName,
2003 0,
2004 ClassGuid ? KEY_ENUMERATE_SUB_KEYS : samDesired,
2005 &hClassesKey);
2006 if (MachineName != NULL)
2007 RegCloseKey(HKLM);
2008 if (rc != ERROR_SUCCESS)
2009 {
2010 SetLastError(rc);
2011 goto cleanup;
2012 }
2013
2014 if (ClassGuid == NULL)
2015 {
2016 /* Stop here. We don't need to open a subkey */
2017 ret = hClassesKey;
2018 goto cleanup;
2019 }
2020
2021 if (UuidToStringW((UUID*)ClassGuid, &lpGuidString) != RPC_S_OK)
2022 {
2023 SetLastError(ERROR_GEN_FAILURE);
2024 goto cleanup;
2025 }
2026
2027 dwLength = lstrlenW(lpGuidString);
2028 lpFullGuidString = HeapAlloc(GetProcessHeap(), 0, (dwLength + 3) * sizeof(WCHAR));
2029 if (!lpFullGuidString)
2030 {
2031 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2032 goto cleanup;
2033 }
2034 lpFullGuidString[0] = '{';
2035 memcpy(&lpFullGuidString[1], lpGuidString, dwLength * sizeof(WCHAR));
2036 lpFullGuidString[dwLength + 1] = '}';
2037 lpFullGuidString[dwLength + 2] = '\0';
2038
2039 rc = RegOpenKeyExW(hClassesKey,
2040 lpFullGuidString,
2041 0,
2042 samDesired,
2043 &hClassKey);
2044 if (rc != ERROR_SUCCESS)
2045 {
2046 SetLastError(rc);
2047 goto cleanup;
2048 }
2049 ret = hClassKey;
2050
2051 cleanup:
2052 if (hClassKey != NULL && hClassKey != ret)
2053 RegCloseKey(hClassKey);
2054 if (hClassesKey != NULL && hClassesKey != ret)
2055 RegCloseKey(hClassesKey);
2056 if (lpGuidString)
2057 RpcStringFreeW(&lpGuidString);
2058 HeapFree(GetProcessHeap(), 0, lpFullGuidString);
2059
2060 return ret;
2061 }
2062
2063 /***********************************************************************
2064 * SetupDiSetClassInstallParamsA (SETUPAPI.@)
2065 */
2066 BOOL WINAPI
2067 SetupDiSetClassInstallParamsA(
2068 IN HDEVINFO DeviceInfoSet,
2069 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
2070 IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL,
2071 IN DWORD ClassInstallParamsSize)
2072 {
2073 FIXME("%p %p %x %lu\n",DeviceInfoSet, DeviceInfoData,
2074 ClassInstallParams->InstallFunction, ClassInstallParamsSize);
2075 return FALSE;
2076 }
2077
2078 /***********************************************************************
2079 * Helper functions for SetupDiSetClassInstallParamsW
2080 */
2081 static BOOL
2082 SETUP_PropertyChangeHandler(
2083 IN HDEVINFO DeviceInfoSet,
2084 IN PSP_DEVINFO_DATA DeviceInfoData,
2085 IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL,
2086 IN DWORD ClassInstallParamsSize)
2087 {
2088 PSP_PROPCHANGE_PARAMS PropChangeParams = (PSP_PROPCHANGE_PARAMS)ClassInstallParams;
2089 BOOL ret = FALSE;
2090
2091 if (!DeviceInfoData)
2092 SetLastError(ERROR_INVALID_PARAMETER);
2093 else if (ClassInstallParamsSize != sizeof(SP_PROPCHANGE_PARAMS))
2094 SetLastError(ERROR_INVALID_PARAMETER);
2095 else if (PropChangeParams && PropChangeParams->StateChange != DICS_ENABLE
2096 && PropChangeParams->StateChange != DICS_DISABLE && PropChangeParams->StateChange != DICS_PROPCHANGE
2097 && PropChangeParams->StateChange != DICS_START && PropChangeParams->StateChange != DICS_STOP)
2098 SetLastError(ERROR_INVALID_FLAGS);
2099 else if (PropChangeParams && PropChangeParams->Scope != DICS_FLAG_GLOBAL
2100 && PropChangeParams->Scope != DICS_FLAG_CONFIGSPECIFIC)
2101 SetLastError(ERROR_INVALID_FLAGS);
2102 else if (PropChangeParams
2103 && (PropChangeParams->StateChange == DICS_START || PropChangeParams->StateChange == DICS_STOP)
2104 && PropChangeParams->Scope != DICS_FLAG_CONFIGSPECIFIC)
2105 SetLastError(ERROR_INVALID_USER_BUFFER);
2106 else
2107 {
2108 PSP_PROPCHANGE_PARAMS *CurrentPropChangeParams;
2109 if (!DeviceInfoData)
2110 {
2111 struct DeviceInfoSet *list = (struct DeviceInfoSet *)DeviceInfoSet;
2112 CurrentPropChangeParams = &list->ClassInstallParams.PropChange;
2113 }
2114 else
2115 {
2116 struct DeviceInfoElement *deviceInfo = (struct DeviceInfoElement *)DeviceInfoData->Reserved;
2117 CurrentPropChangeParams = &deviceInfo->ClassInstallParams.PropChange;
2118 }
2119 if (*CurrentPropChangeParams)
2120 {
2121 MyFree(*CurrentPropChangeParams);
2122 *CurrentPropChangeParams = NULL;
2123 }
2124 if (PropChangeParams)
2125 {
2126 *CurrentPropChangeParams = MyMalloc(sizeof(SP_PROPCHANGE_PARAMS));
2127 if (!*CurrentPropChangeParams)
2128 {
2129 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2130 goto done;
2131 }
2132 memcpy(*CurrentPropChangeParams, PropChangeParams, sizeof(SP_PROPCHANGE_PARAMS));
2133 }
2134 ret = TRUE;
2135 }
2136
2137 done:
2138 return ret;
2139 }
2140
2141 /***********************************************************************
2142 * SetupDiSetClassInstallParamsW (SETUPAPI.@)
2143 */
2144 BOOL WINAPI
2145 SetupDiSetClassInstallParamsW(
2146 IN HDEVINFO DeviceInfoSet,
2147 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
2148 IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL,
2149 IN DWORD ClassInstallParamsSize)
2150 {
2151 struct DeviceInfoSet *list;
2152 BOOL ret = FALSE;
2153
2154 TRACE("%p %p %p %lu\n", DeviceInfoSet, DeviceInfoData,
2155 ClassInstallParams, ClassInstallParamsSize);
2156
2157 if (!DeviceInfoSet)
2158 SetLastError(ERROR_INVALID_PARAMETER);
2159 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
2160 SetLastError(ERROR_INVALID_HANDLE);
2161 else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
2162 SetLastError(ERROR_INVALID_HANDLE);
2163 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
2164 SetLastError(ERROR_INVALID_USER_BUFFER);
2165 else if (ClassInstallParams && ClassInstallParams->cbSize != sizeof(SP_CLASSINSTALL_HEADER))
2166 SetLastError(ERROR_INVALID_USER_BUFFER);
2167 else if (ClassInstallParams && ClassInstallParamsSize < sizeof(SP_CLASSINSTALL_HEADER))
2168 SetLastError(ERROR_INVALID_PARAMETER);
2169 else if (!ClassInstallParams && ClassInstallParamsSize != 0)
2170 SetLastError(ERROR_INVALID_PARAMETER);
2171 else
2172 {
2173 SP_DEVINSTALL_PARAMS_W InstallParams;
2174 BOOL Result;
2175
2176 InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
2177 Result = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
2178 if (!Result)
2179 goto done;
2180
2181 if (ClassInstallParams)
2182 {
2183 /* Check parameters in ClassInstallParams */
2184 if (ClassInstallParams->InstallFunction < DIF_SELECTDEVICE
2185 || ClassInstallParams->InstallFunction - DIF_SELECTDEVICE >= sizeof(UpdateClassInstallParamHandlers)/sizeof(UpdateClassInstallParamHandlers[0]))
2186 {
2187 SetLastError(ERROR_INVALID_USER_BUFFER);
2188 goto done;
2189 }
2190 else if (UpdateClassInstallParamHandlers[ClassInstallParams->InstallFunction - DIF_SELECTDEVICE] == NULL)
2191 {
2192 ERR("InstallFunction %u is valid, but has no associated update handler\n", ClassInstallParams->InstallFunction);
2193 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2194 goto done;
2195 }
2196 ret = UpdateClassInstallParamHandlers[ClassInstallParams->InstallFunction - DIF_SELECTDEVICE](DeviceInfoSet, DeviceInfoData, ClassInstallParams, ClassInstallParamsSize);
2197 if (!ret)
2198 goto done;
2199 InstallParams.Flags |= DI_CLASSINSTALLPARAMS;
2200 }
2201 else
2202 {
2203 InstallParams.Flags &= ~DI_CLASSINSTALLPARAMS;
2204 }
2205
2206 ret = SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
2207 }
2208
2209 done:
2210 TRACE("Returning %d\n", ret);
2211 return ret;
2212 }
2213
2214 /***********************************************************************
2215 * SetupDiGetClassDevPropertySheetsA(SETUPAPI.@)
2216 */
2217 BOOL WINAPI
2218 SetupDiGetClassDevPropertySheetsA(
2219 IN HDEVINFO DeviceInfoSet,
2220 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
2221 IN LPPROPSHEETHEADERA PropertySheetHeader,
2222 IN DWORD PropertySheetHeaderPageListSize,
2223 OUT PDWORD RequiredSize OPTIONAL,
2224 IN DWORD PropertySheetType)
2225 {
2226 PROPSHEETHEADERW psh;
2227 BOOL ret = FALSE;
2228
2229 TRACE("%p %p %p 0%lx %p 0x%lx\n", DeviceInfoSet, DeviceInfoData,
2230 PropertySheetHeader, PropertySheetHeaderPageListSize,
2231 RequiredSize, PropertySheetType);
2232
2233 psh.dwFlags = PropertySheetHeader->dwFlags;
2234 psh.phpage = PropertySheetHeader->phpage;
2235 psh.nPages = PropertySheetHeader->nPages;
2236
2237 ret = SetupDiGetClassDevPropertySheetsW(DeviceInfoSet, DeviceInfoData, PropertySheetHeader ? &psh : NULL,
2238 PropertySheetHeaderPageListSize, RequiredSize,
2239 PropertySheetType);
2240 if (ret)
2241 {
2242 PropertySheetHeader->nPages = psh.nPages;
2243 }
2244
2245 TRACE("Returning %d\n", ret);
2246 return ret;
2247 }
2248
2249 struct ClassDevPropertySheetsData
2250 {
2251 HPROPSHEETPAGE *PropertySheetPages;
2252 DWORD MaximumNumberOfPages;
2253 DWORD NumberOfPages;
2254 };
2255
2256 static BOOL WINAPI
2257 SETUP_GetClassDevPropertySheetsCallback(
2258 IN HPROPSHEETPAGE hPropSheetPage,
2259 IN OUT LPARAM lParam)
2260 {
2261 struct ClassDevPropertySheetsData *PropPageData;
2262
2263 PropPageData = (struct ClassDevPropertySheetsData *)lParam;
2264
2265 if (PropPageData->NumberOfPages < PropPageData->MaximumNumberOfPages)
2266 {
2267 *PropPageData->PropertySheetPages = hPropSheetPage;
2268 PropPageData->PropertySheetPages++;
2269 }
2270
2271 PropPageData->NumberOfPages++;
2272 return TRUE;
2273 }
2274
2275 /***********************************************************************
2276 * SetupDiGetClassDevPropertySheetsW(SETUPAPI.@)
2277 */
2278 BOOL WINAPI
2279 SetupDiGetClassDevPropertySheetsW(
2280 IN HDEVINFO DeviceInfoSet,
2281 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
2282 IN OUT LPPROPSHEETHEADERW PropertySheetHeader,
2283 IN DWORD PropertySheetHeaderPageListSize,
2284 OUT PDWORD RequiredSize OPTIONAL,
2285 IN DWORD PropertySheetType)
2286 {
2287 struct DeviceInfoSet *list;
2288 BOOL ret = FALSE;
2289
2290 TRACE("%p %p %p 0%lx %p 0x%lx\n", DeviceInfoSet, DeviceInfoData,
2291 PropertySheetHeader, PropertySheetHeaderPageListSize,
2292 RequiredSize, PropertySheetType);
2293
2294 if (!DeviceInfoSet)
2295 SetLastError(ERROR_INVALID_HANDLE);
2296 else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
2297 SetLastError(ERROR_INVALID_HANDLE);
2298 else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
2299 SetLastError(ERROR_INVALID_HANDLE);
2300 else if (!PropertySheetHeader)
2301 SetLastError(ERROR_INVALID_PARAMETER);
2302 else if (PropertySheetHeader->dwFlags & PSH_PROPSHEETPAGE)
2303 SetLastError(ERROR_INVALID_FLAGS);
2304 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
2305 SetLastError(ERROR_INVALID_USER_BUFFER);
2306 else if (!DeviceInfoData && IsEqualIID(&list->ClassGuid, &GUID_NULL))
2307 SetLastError(ERROR_INVALID_PARAMETER);
2308 else if (!PropertySheetHeader)
2309 SetLastError(ERROR_INVALID_PARAMETER);
2310 else if (PropertySheetType != DIGCDP_FLAG_ADVANCED
2311 && PropertySheetType != DIGCDP_FLAG_BASIC
2312 && PropertySheetType != DIGCDP_FLAG_REMOTE_ADVANCED
2313 && PropertySheetType != DIGCDP_FLAG_REMOTE_BASIC)
2314 SetLastError(ERROR_INVALID_PARAMETER);
2315 else
2316 {
2317 HKEY hKey = INVALID_HANDLE_VALUE;
2318 SP_PROPSHEETPAGE_REQUEST Request;
2319 LPWSTR PropPageProvider = NULL;
2320 HMODULE hModule = NULL;
2321 PROPERTY_PAGE_PROVIDER pPropPageProvider = NULL;
2322 struct ClassDevPropertySheetsData PropPageData;
2323 DWORD dwLength, dwRegType;
2324 DWORD rc;
2325
2326 if (DeviceInfoData)
2327 hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_QUERY_VALUE);
2328 else
2329 {
2330 hKey = SetupDiOpenClassRegKeyExW(&list->ClassGuid, KEY_QUERY_VALUE,
2331 DIOCR_INSTALLER, list->MachineName + 2, NULL);
2332 }
2333 if (hKey == INVALID_HANDLE_VALUE)
2334 goto cleanup;
2335
2336 rc = RegQueryValueExW(hKey, REGSTR_VAL_ENUMPROPPAGES_32, NULL, &dwRegType, NULL, &dwLength);
2337 if (rc == ERROR_FILE_NOT_FOUND)
2338 {
2339 /* No registry key. As it is optional, don't say it's a bad error */
2340 if (RequiredSize)
2341 *RequiredSize = 0;
2342 ret = TRUE;
2343 goto cleanup;
2344 }
2345 else if (rc != ERROR_SUCCESS && dwRegType != REG_SZ)
2346 {
2347 SetLastError(rc);
2348 goto cleanup;
2349 }
2350
2351 PropPageProvider = HeapAlloc(GetProcessHeap(), 0, dwLength + sizeof(WCHAR));
2352 if (!PropPageProvider)
2353 {
2354 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2355 goto cleanup;
2356 }
2357 rc = RegQueryValueExW(hKey, REGSTR_VAL_ENUMPROPPAGES_32, NULL, NULL, (LPBYTE)PropPageProvider, &dwLength);
2358 if (rc != ERROR_SUCCESS)
2359 {
2360 SetLastError(rc);
2361 goto cleanup;
2362 }
2363 PropPageProvider[dwLength / sizeof(WCHAR)] = 0;
2364
2365 rc = GetFunctionPointer(PropPageProvider, &hModule, (PVOID*)&pPropPageProvider);
2366 if (rc != ERROR_SUCCESS)
2367 {
2368 SetLastError(ERROR_INVALID_PROPPAGE_PROVIDER);
2369 goto cleanup;
2370 }
2371
2372 Request.cbSize = sizeof(SP_PROPSHEETPAGE_REQUEST);
2373 Request.PageRequested = SPPSR_ENUM_ADV_DEVICE_PROPERTIES;
2374 Request.DeviceInfoSet = DeviceInfoSet;
2375 Request.DeviceInfoData = DeviceInfoData;
2376 PropPageData.PropertySheetPages = &PropertySheetHeader->phpage[PropertySheetHeader->nPages];
2377 PropPageData.MaximumNumberOfPages = PropertySheetHeaderPageListSize - PropertySheetHeader->nPages;
2378 PropPageData.NumberOfPages = 0;
2379 ret = pPropPageProvider(&Request, SETUP_GetClassDevPropertySheetsCallback, (LPARAM)&PropPageData);
2380 if (!ret)
2381 goto cleanup;
2382
2383 if (RequiredSize)
2384 *RequiredSize = PropPageData.NumberOfPages + PropertySheetHeader->nPages;
2385 if (PropPageData.NumberOfPages <= PropPageData.MaximumNumberOfPages)
2386 {
2387 PropertySheetHeader->nPages += PropPageData.NumberOfPages;
2388 ret = TRUE;
2389 }
2390 else
2391 {
2392 PropertySheetHeader->nPages += PropPageData.MaximumNumberOfPages;
2393 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2394 }
2395
2396 cleanup:
2397 if (hKey != INVALID_HANDLE_VALUE)
2398 RegCloseKey(hKey);
2399 HeapFree(GetProcessHeap(), 0, PropPageProvider);
2400 FreeFunctionPointer(hModule, pPropPageProvider);
2401 }
2402
2403 TRACE("Returning %d\n", ret);
2404 return ret;
2405 }