7b5c024ac690564ba1f220a3c7495c01d74326f6
[reactos.git] / 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 #include <wingdi.h>
25 #include <shellapi.h>
26 #include <strsafe.h>
27
28 /* Unicode constants */
29 static const WCHAR BackSlash[] = {'\\',0};
30 static const WCHAR Class[] = {'C','l','a','s','s',0};
31 static const WCHAR ClassGUID[] = {'C','l','a','s','s','G','U','I','D',0};
32 static const WCHAR ClassInstall32[] = {'C','l','a','s','s','I','n','s','t','a','l','l','3','2',0};
33 static const WCHAR DotServices[] = {'.','S','e','r','v','i','c','e','s',0};
34 static const WCHAR InterfaceInstall32[] = {'I','n','t','e','r','f','a','c','e','I','n','s','t','a','l','l','3','2',0};
35 static const WCHAR SetupapiDll[] = {'s','e','t','u','p','a','p','i','.','d','l','l',0};
36 static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
37
38 typedef BOOL
39 (WINAPI* PROPERTY_PAGE_PROVIDER) (
40 IN PSP_PROPSHEETPAGE_REQUEST PropPageRequest,
41 IN LPFNADDPROPSHEETPAGE fAddFunc,
42 IN LPARAM lParam);
43 typedef BOOL
44 (*UPDATE_CLASS_PARAM_HANDLER) (
45 IN HDEVINFO DeviceInfoSet,
46 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
47 IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL,
48 IN DWORD ClassInstallParamsSize);
49
50 static BOOL
51 SETUP_PropertyChangeHandler(
52 IN HDEVINFO DeviceInfoSet,
53 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
54 IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL,
55 IN DWORD ClassInstallParamsSize);
56
57 static BOOL
58 SETUP_PropertyAddPropertyAdvancedHandler(
59 IN HDEVINFO DeviceInfoSet,
60 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
61 IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL,
62 IN DWORD ClassInstallParamsSize);
63
64 typedef struct _INSTALL_PARAMS_DATA
65 {
66 DI_FUNCTION Function;
67 UPDATE_CLASS_PARAM_HANDLER UpdateHandler;
68 ULONG ParamsSize;
69 LONG FieldOffset;
70 } INSTALL_PARAMS_DATA;
71
72 #define ADD_PARAM_HANDLER(Function, UpdateHandler, ParamsType, ParamsField) \
73 { Function, UpdateHandler, sizeof(ParamsType), FIELD_OFFSET(struct ClassInstallParams, ParamsField) },
74
75 static const INSTALL_PARAMS_DATA InstallParamsData[] = {
76 ADD_PARAM_HANDLER(DIF_PROPERTYCHANGE, SETUP_PropertyChangeHandler, SP_PROPCHANGE_PARAMS, PropChangeParams)
77 ADD_PARAM_HANDLER(DIF_ADDPROPERTYPAGE_ADVANCED, SETUP_PropertyAddPropertyAdvancedHandler, SP_ADDPROPERTYPAGE_DATA, AddPropertyPageData)
78 };
79 #undef ADD_PARAM_HANDLER
80
81 #define UNKNOWN_ICON_INDEX 18
82
83 /***********************************************************************
84 * SetupDiDestroyClassImageList(SETUPAPI.@)
85 */
86 BOOL WINAPI
87 SetupDiDestroyClassImageList(
88 IN PSP_CLASSIMAGELIST_DATA ClassImageListData)
89 {
90 struct ClassImageList *list;
91 BOOL ret = FALSE;
92
93 TRACE("%p\n", ClassImageListData);
94
95 if (!ClassImageListData)
96 SetLastError(ERROR_INVALID_PARAMETER);
97 else if (ClassImageListData->cbSize != sizeof(SP_CLASSIMAGELIST_DATA))
98 SetLastError(ERROR_INVALID_USER_BUFFER);
99 else if ((list = (struct ClassImageList *)ClassImageListData->Reserved) == NULL)
100 SetLastError(ERROR_INVALID_USER_BUFFER);
101 else if (list->magic != SETUP_CLASS_IMAGE_LIST_MAGIC)
102 SetLastError(ERROR_INVALID_USER_BUFFER);
103 else
104 {
105 /* If Reserved wasn't NULL, then this is valid too */
106 if (ClassImageListData->ImageList)
107 {
108 ImageList_Destroy(ClassImageListData->ImageList);
109 ClassImageListData->ImageList = NULL;
110 }
111
112 MyFree(list);
113 ClassImageListData->Reserved = 0;
114
115 ret = TRUE;
116 }
117
118 TRACE("Returning %d\n", ret);
119 return ret;
120 }
121
122 /***********************************************************************
123 * SETUP_CreateDevicesListFromEnumerator
124 *
125 * PARAMS
126 * list [IO] Device info set to fill with discovered devices.
127 * pClassGuid [I] If specified, only devices which belong to this class will be added.
128 * Enumerator [I] Location to search devices to add.
129 * hEnumeratorKey [I] Registry key corresponding to Enumerator key. Must have KEY_ENUMERATE_SUB_KEYS right.
130 *
131 * RETURNS
132 * Success: ERROR_SUCCESS.
133 * Failure: an error code.
134 */
135 static LONG
136 SETUP_CreateDevicesListFromEnumerator(
137 IN OUT struct DeviceInfoSet *list,
138 IN CONST GUID *pClassGuid OPTIONAL,
139 IN LPCWSTR Enumerator,
140 IN HKEY hEnumeratorKey) /* handle to Enumerator registry key */
141 {
142 HKEY hDeviceIdKey = NULL, hInstanceIdKey;
143 WCHAR KeyBuffer[MAX_PATH];
144 WCHAR InstancePath[MAX_PATH];
145 LPWSTR pEndOfInstancePath; /* Pointer into InstancePath buffer */
146 struct DeviceInfo *deviceInfo;
147 DWORD i = 0, j;
148 DWORD dwLength, dwRegType;
149 DWORD rc;
150
151 /* Enumerate device IDs (subkeys of hEnumeratorKey) */
152 while (TRUE)
153 {
154 dwLength = sizeof(KeyBuffer) / sizeof(KeyBuffer[0]);
155 rc = RegEnumKeyExW(hEnumeratorKey, i, KeyBuffer, &dwLength, NULL, NULL, NULL, NULL);
156 if (rc == ERROR_NO_MORE_ITEMS)
157 break;
158 if (rc != ERROR_SUCCESS)
159 goto cleanup;
160 i++;
161
162 /* Open device id sub key */
163 if (hDeviceIdKey != NULL)
164 RegCloseKey(hDeviceIdKey);
165 rc = RegOpenKeyExW(hEnumeratorKey, KeyBuffer, 0, KEY_ENUMERATE_SUB_KEYS, &hDeviceIdKey);
166 if (rc != ERROR_SUCCESS)
167 goto cleanup;
168
169 if (FAILED(StringCchCopyW(InstancePath, _countof(InstancePath), Enumerator)) ||
170 FAILED(StringCchCatW(InstancePath, _countof(InstancePath), BackSlash)) ||
171 FAILED(StringCchCatW(InstancePath, _countof(InstancePath), KeyBuffer)) ||
172 FAILED(StringCchCatW(InstancePath, _countof(InstancePath), BackSlash)))
173 {
174 rc = ERROR_GEN_FAILURE;
175 goto cleanup;
176 }
177
178 pEndOfInstancePath = &InstancePath[strlenW(InstancePath)];
179
180 /* Enumerate instance IDs (subkeys of hDeviceIdKey) */
181 j = 0;
182 while (TRUE)
183 {
184 GUID KeyGuid;
185
186 dwLength = sizeof(KeyBuffer) / sizeof(KeyBuffer[0]);
187 rc = RegEnumKeyExW(hDeviceIdKey, j, KeyBuffer, &dwLength, NULL, NULL, NULL, NULL);
188 if (rc == ERROR_NO_MORE_ITEMS)
189 break;
190 if (rc != ERROR_SUCCESS)
191 goto cleanup;
192 j++;
193
194 /* Open instance id sub key */
195 rc = RegOpenKeyExW(hDeviceIdKey, KeyBuffer, 0, KEY_QUERY_VALUE, &hInstanceIdKey);
196 if (rc != ERROR_SUCCESS)
197 goto cleanup;
198 *pEndOfInstancePath = '\0';
199 strcatW(InstancePath, KeyBuffer);
200
201 /* Read ClassGUID value */
202 dwLength = sizeof(KeyBuffer) - sizeof(WCHAR);
203 rc = RegQueryValueExW(hInstanceIdKey, ClassGUID, NULL, &dwRegType, (LPBYTE)KeyBuffer, &dwLength);
204 RegCloseKey(hInstanceIdKey);
205 if (rc == ERROR_FILE_NOT_FOUND)
206 {
207 if (pClassGuid)
208 /* Skip this bad entry as we can't verify it */
209 continue;
210 /* Set a default GUID for this device */
211 memcpy(&KeyGuid, &GUID_NULL, sizeof(GUID));
212 }
213 else if (rc != ERROR_SUCCESS)
214 {
215 goto cleanup;
216 }
217 else if (dwRegType != REG_SZ || dwLength < MAX_GUID_STRING_LEN * sizeof(WCHAR))
218 {
219 rc = ERROR_GEN_FAILURE;
220 goto cleanup;
221 }
222 else
223 {
224 KeyBuffer[MAX_GUID_STRING_LEN - 2] = '\0'; /* Replace the } by a NULL character */
225 if (UuidFromStringW(&KeyBuffer[1], &KeyGuid) != RPC_S_OK)
226 /* Bad GUID, skip the entry */
227 continue;
228 }
229
230 if (pClassGuid && !IsEqualIID(&KeyGuid, pClassGuid))
231 {
232 /* Skip this entry as it is not the right device class */
233 continue;
234 }
235
236 /* Add the entry to the list */
237 if (!CreateDeviceInfo(list, InstancePath, &KeyGuid, &deviceInfo))
238 {
239 rc = GetLastError();
240 goto cleanup;
241 }
242 TRACE("Adding '%s' to device info set %p\n", debugstr_w(InstancePath), list);
243 InsertTailList(&list->ListHead, &deviceInfo->ListEntry);
244 }
245 }
246
247 rc = ERROR_SUCCESS;
248
249 cleanup:
250 if (hDeviceIdKey != NULL)
251 RegCloseKey(hDeviceIdKey);
252 return rc;
253 }
254
255 LONG
256 SETUP_CreateDevicesList(
257 IN OUT struct DeviceInfoSet *list,
258 IN PCWSTR MachineName OPTIONAL,
259 IN CONST GUID *Class OPTIONAL,
260 IN PCWSTR Enumerator OPTIONAL)
261 {
262 HKEY HKLM = HKEY_LOCAL_MACHINE;
263 HKEY hEnumKey = NULL;
264 HKEY hEnumeratorKey = NULL;
265 WCHAR KeyBuffer[MAX_PATH];
266 DWORD i;
267 DWORD dwLength;
268 DWORD rc;
269
270 if (Class && IsEqualIID(Class, &GUID_NULL))
271 Class = NULL;
272
273 /* Open Enum key (if applicable) */
274 if (MachineName != NULL)
275 {
276 rc = RegConnectRegistryW(MachineName, HKEY_LOCAL_MACHINE, &HKLM);
277 if (rc != ERROR_SUCCESS)
278 goto cleanup;
279 }
280
281 rc = RegOpenKeyExW(
282 HKLM,
283 REGSTR_PATH_SYSTEMENUM,
284 0,
285 KEY_ENUMERATE_SUB_KEYS,
286 &hEnumKey);
287 if (rc != ERROR_SUCCESS)
288 goto cleanup;
289
290 /* If enumerator is provided, call directly SETUP_CreateDevicesListFromEnumerator.
291 * Else, enumerate all enumerators and call SETUP_CreateDevicesListFromEnumerator
292 * for each one.
293 */
294 if (Enumerator)
295 {
296 rc = RegOpenKeyExW(
297 hEnumKey,
298 Enumerator,
299 0,
300 KEY_ENUMERATE_SUB_KEYS,
301 &hEnumeratorKey);
302 if (rc != ERROR_SUCCESS)
303 {
304 if (rc == ERROR_FILE_NOT_FOUND)
305 rc = ERROR_INVALID_DATA;
306 goto cleanup;
307 }
308 rc = SETUP_CreateDevicesListFromEnumerator(list, Class, Enumerator, hEnumeratorKey);
309 }
310 else
311 {
312 /* Enumerate enumerators */
313 i = 0;
314 while (TRUE)
315 {
316 dwLength = sizeof(KeyBuffer) / sizeof(KeyBuffer[0]);
317 rc = RegEnumKeyExW(hEnumKey, i, KeyBuffer, &dwLength, NULL, NULL, NULL, NULL);
318 if (rc == ERROR_NO_MORE_ITEMS)
319 break;
320 else if (rc != ERROR_SUCCESS)
321 goto cleanup;
322 i++;
323
324 /* Open sub key */
325 if (hEnumeratorKey != NULL)
326 RegCloseKey(hEnumeratorKey);
327 rc = RegOpenKeyExW(hEnumKey, KeyBuffer, 0, KEY_ENUMERATE_SUB_KEYS, &hEnumeratorKey);
328 if (rc != ERROR_SUCCESS)
329 goto cleanup;
330
331 /* Call SETUP_CreateDevicesListFromEnumerator */
332 rc = SETUP_CreateDevicesListFromEnumerator(list, Class, KeyBuffer, hEnumeratorKey);
333 if (rc != ERROR_SUCCESS)
334 goto cleanup;
335 }
336 rc = ERROR_SUCCESS;
337 }
338
339 cleanup:
340 if (HKLM != HKEY_LOCAL_MACHINE)
341 RegCloseKey(HKLM);
342 if (hEnumKey != NULL)
343 RegCloseKey(hEnumKey);
344 if (hEnumeratorKey != NULL)
345 RegCloseKey(hEnumeratorKey);
346 return rc;
347 }
348
349 static BOOL
350 SETUP_GetIconIndex(
351 IN HKEY hClassKey,
352 OUT PINT ImageIndex)
353 {
354 LPWSTR Buffer = NULL;
355 DWORD dwRegType, dwLength;
356 LONG rc;
357 BOOL ret = FALSE;
358
359 /* Read icon registry key */
360 rc = RegQueryValueExW(hClassKey, REGSTR_VAL_INSICON, NULL, &dwRegType, NULL, &dwLength);
361 if (rc != ERROR_SUCCESS)
362 {
363 SetLastError(rc);
364 goto cleanup;
365 } else if (dwRegType != REG_SZ)
366 {
367 SetLastError(ERROR_INVALID_INDEX);
368 goto cleanup;
369 }
370 Buffer = MyMalloc(dwLength + sizeof(WCHAR));
371 if (!Buffer)
372 {
373 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
374 goto cleanup;
375 }
376 rc = RegQueryValueExW(hClassKey, REGSTR_VAL_INSICON, NULL, NULL, (LPBYTE)Buffer, &dwLength);
377 if (rc != ERROR_SUCCESS)
378 {
379 SetLastError(rc);
380 goto cleanup;
381 }
382 /* make sure the returned buffer is NULL-terminated */
383 Buffer[dwLength / sizeof(WCHAR)] = 0;
384
385 /* Transform icon value to a INT */
386 *ImageIndex = atoiW(Buffer);
387 ret = TRUE;
388
389 cleanup:
390 MyFree(Buffer);
391 return ret;
392 }
393
394 /***********************************************************************
395 * SetupDiGetClassImageIndex (SETUPAPI.@)
396 */
397 BOOL WINAPI
398 SetupDiGetClassImageIndex(
399 IN PSP_CLASSIMAGELIST_DATA ClassImageListData,
400 IN CONST GUID *ClassGuid,
401 OUT PINT ImageIndex)
402 {
403 struct ClassImageList *list;
404 BOOL ret = FALSE;
405
406 TRACE("%p %s %p\n", ClassImageListData, debugstr_guid(ClassGuid), ImageIndex);
407
408 if (!ClassImageListData || !ClassGuid || !ImageIndex)
409 SetLastError(ERROR_INVALID_PARAMETER);
410 else if (ClassImageListData->cbSize != sizeof(SP_CLASSIMAGELIST_DATA))
411 SetLastError(ERROR_INVALID_USER_BUFFER);
412 else if ((list = (struct ClassImageList *)ClassImageListData->Reserved) == NULL)
413 SetLastError(ERROR_INVALID_USER_BUFFER);
414 else if (list->magic != SETUP_CLASS_IMAGE_LIST_MAGIC)
415 SetLastError(ERROR_INVALID_USER_BUFFER);
416 else
417 {
418 DWORD i;
419
420 for (i = 0; i < list->NumberOfGuids; i++)
421 {
422 if (IsEqualIID(ClassGuid, &list->Guids[i]))
423 break;
424 }
425
426 if (i == list->NumberOfGuids || list->IconIndexes[i] < 0)
427 SetLastError(ERROR_FILE_NOT_FOUND);
428 else
429 {
430 *ImageIndex = list->IconIndexes[i];
431 ret = TRUE;
432 }
433 }
434
435 TRACE("Returning %d\n", ret);
436 return ret;
437 }
438
439 /***********************************************************************
440 * SetupDiGetClassImageList(SETUPAPI.@)
441 */
442 BOOL WINAPI
443 SetupDiGetClassImageList(
444 OUT PSP_CLASSIMAGELIST_DATA ClassImageListData)
445 {
446 return SetupDiGetClassImageListExW(ClassImageListData, NULL, NULL);
447 }
448
449 /***********************************************************************
450 * SetupDiGetClassImageListExA(SETUPAPI.@)
451 */
452 BOOL WINAPI
453 SetupDiGetClassImageListExA(
454 OUT PSP_CLASSIMAGELIST_DATA ClassImageListData,
455 IN PCSTR MachineName OPTIONAL,
456 IN PVOID Reserved)
457 {
458 PWSTR MachineNameW = NULL;
459 BOOL ret;
460
461 if (MachineName)
462 {
463 MachineNameW = pSetupMultiByteToUnicode(MachineName, CP_ACP);
464 if (MachineNameW == NULL)
465 return FALSE;
466 }
467
468 ret = SetupDiGetClassImageListExW(ClassImageListData, MachineNameW, Reserved);
469
470 MyFree(MachineNameW);
471
472 return ret;
473 }
474
475 static BOOL WINAPI
476 SETUP_GetClassIconInfo(IN CONST GUID *ClassGuid, OUT PINT OutIndex, OUT LPWSTR *OutDllName)
477 {
478 LPWSTR Buffer = NULL;
479 INT iconIndex = -UNKNOWN_ICON_INDEX;
480 HKEY hKey = INVALID_HANDLE_VALUE;
481 BOOL ret = FALSE;
482
483 if (ClassGuid)
484 {
485 hKey = SetupDiOpenClassRegKey(ClassGuid, KEY_QUERY_VALUE);
486 if (hKey != INVALID_HANDLE_VALUE)
487 {
488 SETUP_GetIconIndex(hKey, &iconIndex);
489 }
490 }
491
492 if (iconIndex > 0)
493 {
494 /* Look up icon in dll specified by Installer32 or EnumPropPages32 key */
495 PWCHAR Comma;
496 LONG rc;
497 DWORD dwRegType, dwLength;
498 rc = RegQueryValueExW(hKey, REGSTR_VAL_INSTALLER_32, NULL, &dwRegType, NULL, &dwLength);
499 if (rc == ERROR_SUCCESS && dwRegType == REG_SZ)
500 {
501 Buffer = MyMalloc(dwLength + sizeof(WCHAR));
502 if (Buffer == NULL)
503 {
504 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
505 goto cleanup;
506 }
507 rc = RegQueryValueExW(hKey, REGSTR_VAL_INSTALLER_32, NULL, NULL, (LPBYTE)Buffer, &dwLength);
508 if (rc != ERROR_SUCCESS)
509 {
510 SetLastError(rc);
511 goto cleanup;
512 }
513 /* make sure the returned buffer is NULL-terminated */
514 Buffer[dwLength / sizeof(WCHAR)] = 0;
515 }
516 else if
517 (ERROR_SUCCESS == (rc = RegQueryValueExW(hKey, REGSTR_VAL_ENUMPROPPAGES_32, NULL, &dwRegType, NULL, &dwLength))
518 && dwRegType == REG_SZ)
519 {
520 Buffer = MyMalloc(dwLength + sizeof(WCHAR));
521 if (Buffer == NULL)
522 {
523 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
524 goto cleanup;
525 }
526 rc = RegQueryValueExW(hKey, REGSTR_VAL_ENUMPROPPAGES_32, NULL, NULL, (LPBYTE)Buffer, &dwLength);
527 if (rc != ERROR_SUCCESS)
528 {
529 SetLastError(rc);
530 goto cleanup;
531 }
532 /* make sure the returned buffer is NULL-terminated */
533 Buffer[dwLength / sizeof(WCHAR)] = 0;
534 }
535 else
536 {
537 /* Unable to find where to load the icon */
538 SetLastError(ERROR_FILE_NOT_FOUND);
539 goto cleanup;
540 }
541 Comma = strchrW(Buffer, ',');
542 if (!Comma)
543 {
544 SetLastError(ERROR_GEN_FAILURE);
545 goto cleanup;
546 }
547 *Comma = '\0';
548 *OutDllName = Buffer;
549 }
550 else
551 {
552 /* Look up icon in setupapi.dll */
553 iconIndex = -iconIndex;
554 *OutDllName = NULL;
555 }
556
557 *OutIndex = iconIndex;
558 ret = TRUE;
559
560 TRACE("Icon index %d, dll name %s\n", iconIndex, debugstr_w(*OutDllName ? *OutDllName : SetupapiDll));
561
562 cleanup:
563
564 if (hKey != INVALID_HANDLE_VALUE)
565 RegCloseKey(hKey);
566
567 if (Buffer && !ret)
568 MyFree(Buffer);
569
570 return ret;
571 }
572
573
574 /***********************************************************************
575 * SetupDiGetClassImageListExW(SETUPAPI.@)
576 */
577 BOOL WINAPI
578 SetupDiGetClassImageListExW(
579 OUT PSP_CLASSIMAGELIST_DATA ClassImageListData,
580 IN PCWSTR MachineName OPTIONAL,
581 IN PVOID Reserved)
582 {
583 BOOL ret = FALSE;
584
585 TRACE("%p %p %p\n", ClassImageListData, debugstr_w(MachineName), Reserved);
586
587 if (!ClassImageListData)
588 SetLastError(ERROR_INVALID_PARAMETER);
589 else if (ClassImageListData->cbSize != sizeof(SP_CLASSIMAGELIST_DATA))
590 SetLastError(ERROR_INVALID_USER_BUFFER);
591 else if (Reserved)
592 SetLastError(ERROR_INVALID_PARAMETER);
593 else
594 {
595 struct ClassImageList *list = NULL;
596 HDC hDC;
597 DWORD RequiredSize;
598 DWORD ilMask, bkColor;
599 HICON hIcon;
600 DWORD size;
601 INT i, bpp;
602 UINT idx;
603
604 /* Get list of all class GUIDs in given computer */
605 ret = SetupDiBuildClassInfoListExW(
606 0,
607 NULL,
608 0,
609 &RequiredSize,
610 MachineName,
611 NULL);
612 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
613 goto cleanup;
614
615 size = sizeof(struct ClassImageList)
616 + (sizeof(GUID) + sizeof(INT)) * RequiredSize;
617 list = HeapAlloc(GetProcessHeap(), 0, size);
618 if (!list)
619 {
620 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
621 goto cleanup;
622 }
623 list->magic = SETUP_CLASS_IMAGE_LIST_MAGIC;
624 list->NumberOfGuids = RequiredSize;
625 list->Guids = (GUID*)(list + 1);
626 list->IconIndexes = (INT*)((ULONG_PTR)(list + 1) + sizeof(GUID) * RequiredSize);
627
628 ret = SetupDiBuildClassInfoListExW(
629 0,
630 list->Guids,
631 list->NumberOfGuids,
632 &RequiredSize,
633 MachineName,
634 NULL);
635 if (!ret)
636 goto cleanup;
637 else if (RequiredSize != list->NumberOfGuids)
638 {
639 /* Hm. Class list changed since last call. Ignore
640 * this case as it should be very rare */
641 SetLastError(ERROR_GEN_FAILURE);
642 ret = FALSE;
643 goto cleanup;
644 }
645
646 /* Prepare a HIMAGELIST */
647 InitCommonControls();
648
649 hDC = GetDC(NULL);
650 if (!hDC)
651 goto cleanup;
652
653 bpp = GetDeviceCaps(hDC, BITSPIXEL);
654 ReleaseDC(NULL, hDC);
655
656 if (bpp <= 4)
657 ilMask = ILC_COLOR4;
658 else if (bpp <= 8)
659 ilMask = ILC_COLOR8;
660 else if (bpp <= 16)
661 ilMask = ILC_COLOR16;
662 else if (bpp <= 24)
663 ilMask = ILC_COLOR24;
664 else if (bpp <= 32)
665 ilMask = ILC_COLOR32;
666 else
667 ilMask = ILC_COLOR;
668
669 ilMask |= ILC_MASK;
670
671 ClassImageListData->ImageList = ImageList_Create(16, 16, ilMask, 100, 10);
672 if (!ClassImageListData->ImageList)
673 goto cleanup;
674
675 ClassImageListData->Reserved = (ULONG_PTR)list;
676
677 /* For some reason, Windows sets the list background to COLOR_WINDOW */
678 bkColor = GetSysColor(COLOR_WINDOW);
679 ImageList_SetBkColor(ClassImageListData->ImageList, bkColor);
680
681 /* Now, we "simply" need to load icons associated with all class guids,
682 * and put their index in the image list in the IconIndexes array */
683 for (i = 0; i < list->NumberOfGuids; i++)
684 {
685 INT miniIconIndex;
686 LPWSTR DllName = NULL;
687
688 if (SETUP_GetClassIconInfo(&list->Guids[i], &miniIconIndex, &DllName))
689 {
690 if (DllName && ExtractIconExW(DllName, -miniIconIndex, NULL, &hIcon, 1) == 1)
691 {
692 list->IconIndexes[i] = ImageList_AddIcon(ClassImageListData->ImageList, hIcon);
693 }
694 else if(!DllName)
695 {
696 hIcon = LoadImage(hInstance, MAKEINTRESOURCE(miniIconIndex), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
697 list->IconIndexes[i] = ImageList_AddIcon(ClassImageListData->ImageList, hIcon);
698 }
699
700 if(hIcon)
701 DestroyIcon(hIcon);
702 else
703 list->IconIndexes[i] = -1;
704
705 if(DllName)
706 MyFree(DllName);
707 }
708 else
709 {
710 list->IconIndexes[i] = -1; /* Special value to indicate that the icon is unavailable */
711 }
712 }
713
714 /* Finally, add the overlay icons to the image list */
715 for (i = 0; i <= 2; i++)
716 {
717 hIcon = LoadImage(hInstance, MAKEINTRESOURCE(500 + i), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
718 if (hIcon)
719 {
720 idx = ImageList_AddIcon(ClassImageListData->ImageList, hIcon);
721 if (idx != -1)
722 ImageList_SetOverlayImage(ClassImageListData->ImageList, idx, i + 1);
723 DestroyIcon(hIcon);
724 }
725 }
726
727 ret = TRUE;
728
729 cleanup:
730 if (!ret)
731 {
732 if (ClassImageListData->Reserved)
733 SetupDiDestroyClassImageList(ClassImageListData);
734 else if (list)
735 MyFree(list);
736 }
737 }
738
739 TRACE("Returning %d\n", ret);
740 return ret;
741 }
742
743 /***********************************************************************
744 * SetupDiGetClassInstallParamsA(SETUPAPI.@)
745 */
746 BOOL WINAPI
747 SetupDiGetClassInstallParamsA(
748 IN HDEVINFO DeviceInfoSet,
749 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
750 OUT PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL,
751 IN DWORD ClassInstallParamsSize,
752 OUT PDWORD RequiredSize OPTIONAL)
753 {
754 FIXME("SetupDiGetClassInstallParamsA(%p %p %p %lu %p) Stub\n",
755 DeviceInfoSet, DeviceInfoData, ClassInstallParams, ClassInstallParamsSize, RequiredSize);
756 return FALSE;
757 }
758
759 /***********************************************************************
760 * SetupDiGetClassInstallParamsW(SETUPAPI.@)
761 */
762 BOOL WINAPI
763 SetupDiGetClassInstallParamsW(
764 IN HDEVINFO DeviceInfoSet,
765 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
766 OUT PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL,
767 IN DWORD ClassInstallParamsSize,
768 OUT PDWORD RequiredSize OPTIONAL)
769 {
770 FIXME("SetupDiGetClassInstallParamsW(%p %p %p %lu %p) Stub\n",
771 DeviceInfoSet, DeviceInfoData, ClassInstallParams, ClassInstallParamsSize, RequiredSize);
772 return FALSE;
773 }
774
775 /***********************************************************************
776 * SetupDiLoadClassIcon(SETUPAPI.@)
777 */
778 BOOL WINAPI
779 SetupDiLoadClassIcon(
780 IN CONST GUID *ClassGuid,
781 OUT HICON *LargeIcon OPTIONAL,
782 OUT PINT MiniIconIndex OPTIONAL)
783 {
784 INT iconIndex = 0;
785 LPWSTR DllName = NULL;
786 BOOL ret = FALSE;
787 HICON hIcon = NULL;
788
789 if (LargeIcon)
790 {
791 if(!SETUP_GetClassIconInfo(ClassGuid, &iconIndex, &DllName))
792 goto cleanup;
793
794 if (!DllName || ExtractIconExW(DllName, -iconIndex, &hIcon, NULL, 1) != 1 || hIcon == NULL)
795 {
796 /* load the default unknown device icon if ExtractIcon failed */
797 if(DllName)
798 iconIndex = UNKNOWN_ICON_INDEX;
799
800 hIcon = LoadImage(hInstance, MAKEINTRESOURCE(iconIndex), IMAGE_ICON, 32, 32, LR_DEFAULTCOLOR);
801
802 if(!hIcon)
803 goto cleanup;
804 }
805
806 *LargeIcon = hIcon;
807 }
808
809 if (MiniIconIndex)
810 *MiniIconIndex = iconIndex;
811
812 ret = TRUE;
813
814 cleanup:
815
816 if(DllName)
817 MyFree(DllName);
818
819 TRACE("Returning %d\n", ret);
820 return ret;
821 }
822
823 /***********************************************************************
824 * SetupDiInstallClassExW (SETUPAPI.@)
825 */
826 HKEY
827 SETUP_CreateClassKey(HINF hInf);
828 BOOL WINAPI
829 SetupDiInstallClassExW(
830 IN HWND hwndParent OPTIONAL,
831 IN PCWSTR InfFileName OPTIONAL,
832 IN DWORD Flags,
833 IN HSPFILEQ FileQueue OPTIONAL,
834 IN CONST GUID *InterfaceClassGuid OPTIONAL,
835 IN PVOID Reserved1,
836 IN PVOID Reserved2)
837 {
838 BOOL ret = FALSE;
839
840 TRACE("%p %s 0x%lx %p %s %p %p\n", hwndParent, debugstr_w(InfFileName), Flags,
841 FileQueue, debugstr_guid(InterfaceClassGuid), Reserved1, Reserved2);
842
843 if (!InfFileName)
844 {
845 FIXME("Case not implemented: InfFileName NULL\n");
846 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
847 }
848 else if (Flags & ~(DI_NOVCP | DI_NOBROWSE | DI_FORCECOPY | DI_QUIETINSTALL))
849 {
850 TRACE("Unknown flags: 0x%08lx\n", Flags & ~(DI_NOVCP | DI_NOBROWSE | DI_FORCECOPY | DI_QUIETINSTALL));
851 SetLastError(ERROR_INVALID_FLAGS);
852 }
853 else if ((Flags & DI_NOVCP) && FileQueue == NULL)
854 SetLastError(ERROR_INVALID_PARAMETER);
855 else if (Reserved1 != NULL)
856 SetLastError(ERROR_INVALID_PARAMETER);
857 else if (Reserved2 != NULL)
858 SetLastError(ERROR_INVALID_PARAMETER);
859 else
860 {
861 HDEVINFO hDeviceInfo = INVALID_HANDLE_VALUE;
862 SP_DEVINSTALL_PARAMS_W InstallParams;
863 WCHAR SectionName[MAX_PATH];
864 HINF hInf = INVALID_HANDLE_VALUE;
865 HKEY hRootKey = INVALID_HANDLE_VALUE;
866 PVOID callback_context = NULL;
867
868 hDeviceInfo = SetupDiCreateDeviceInfoList(NULL, NULL);
869 if (hDeviceInfo == INVALID_HANDLE_VALUE)
870 goto cleanup;
871
872 InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
873 if (!SetupDiGetDeviceInstallParamsW(hDeviceInfo, NULL, &InstallParams))
874 goto cleanup;
875
876 InstallParams.Flags &= ~(DI_NOVCP | DI_NOBROWSE | DI_QUIETINSTALL);
877 InstallParams.Flags |= Flags & (DI_NOVCP | DI_NOBROWSE | DI_QUIETINSTALL);
878 if (Flags & DI_NOVCP)
879 InstallParams.FileQueue = FileQueue;
880 if (!SetupDiSetDeviceInstallParamsW(hDeviceInfo, NULL, &InstallParams))
881 goto cleanup;
882
883 /* Open the .inf file */
884 hInf = SetupOpenInfFileW(
885 InfFileName,
886 NULL,
887 INF_STYLE_WIN4,
888 NULL);
889 if (hInf == INVALID_HANDLE_VALUE)
890 goto cleanup;
891
892 /* Try to append a layout file */
893 SetupOpenAppendInfFileW(NULL, hInf, NULL);
894
895 if (InterfaceClassGuid)
896 {
897 /* Retrieve the actual section name */
898 ret = SetupDiGetActualSectionToInstallW(
899 hInf,
900 InterfaceInstall32,
901 SectionName,
902 MAX_PATH,
903 NULL,
904 NULL);
905 if (!ret)
906 goto cleanup;
907
908 /* Open registry key related to this interface */
909 /* FIXME: What happens if the key doesn't exist? */
910 hRootKey = SetupDiOpenClassRegKeyExW(InterfaceClassGuid, KEY_ENUMERATE_SUB_KEYS, DIOCR_INTERFACE, NULL, NULL);
911 if (hRootKey == INVALID_HANDLE_VALUE)
912 goto cleanup;
913
914 /* SetupDiCreateDeviceInterface??? */
915 FIXME("Installing an interface is not implemented\n");
916 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
917 }
918 else
919 {
920 /* Create or open the class registry key 'HKLM\CurrentControlSet\Class\{GUID}' */
921 hRootKey = SETUP_CreateClassKey(hInf);
922 if (hRootKey == INVALID_HANDLE_VALUE)
923 goto cleanup;
924
925 /* Retrieve the actual section name */
926 ret = SetupDiGetActualSectionToInstallW(
927 hInf,
928 ClassInstall32,
929 SectionName,
930 MAX_PATH - strlenW(DotServices),
931 NULL,
932 NULL);
933 if (!ret)
934 goto cleanup;
935
936 callback_context = SetupInitDefaultQueueCallback(hwndParent);
937 if (!callback_context)
938 goto cleanup;
939
940 ret = SetupInstallFromInfSectionW(
941 hwndParent,
942 hInf,
943 SectionName,
944 SPINST_REGISTRY | SPINST_FILES | SPINST_BITREG | SPINST_INIFILES | SPINST_INI2REG,
945 hRootKey,
946 NULL, /* FIXME: SourceRootPath */
947 !(Flags & DI_NOVCP) && (Flags & DI_FORCECOPY) ? SP_COPY_FORCE_IN_USE : 0, /* CopyFlags */
948 SetupDefaultQueueCallbackW,
949 callback_context,
950 hDeviceInfo,
951 NULL);
952 if (!ret)
953 goto cleanup;
954
955 /* OPTIONAL: Install .Services section */
956 lstrcatW(SectionName, DotServices);
957 SetupInstallServicesFromInfSectionExW(
958 hInf,
959 SectionName,
960 0,
961 hDeviceInfo,
962 NULL,
963 NULL,
964 NULL);
965 ret = TRUE;
966 }
967
968 cleanup:
969 if (hDeviceInfo != INVALID_HANDLE_VALUE)
970 SetupDiDestroyDeviceInfoList(hDeviceInfo);
971 if (hInf != INVALID_HANDLE_VALUE)
972 SetupCloseInfFile(hInf);
973 if (hRootKey != INVALID_HANDLE_VALUE)
974 RegCloseKey(hRootKey);
975 SetupTermDefaultQueueCallback(callback_context);
976 }
977
978 TRACE("Returning %d\n", ret);
979 return ret;
980 }
981
982 /***********************************************************************
983 * Helper functions for SetupDiSetClassInstallParamsW
984 */
985 static BOOL
986 SETUP_PropertyChangeHandler(
987 IN HDEVINFO DeviceInfoSet,
988 IN PSP_DEVINFO_DATA DeviceInfoData,
989 IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL,
990 IN DWORD ClassInstallParamsSize)
991 {
992 PSP_PROPCHANGE_PARAMS PropChangeParams = (PSP_PROPCHANGE_PARAMS)ClassInstallParams;
993 BOOL ret = FALSE;
994
995 if (!DeviceInfoData)
996 SetLastError(ERROR_INVALID_PARAMETER);
997 else if (ClassInstallParamsSize != sizeof(SP_PROPCHANGE_PARAMS))
998 SetLastError(ERROR_INVALID_PARAMETER);
999 else if (PropChangeParams && PropChangeParams->StateChange != DICS_ENABLE
1000 && PropChangeParams->StateChange != DICS_DISABLE && PropChangeParams->StateChange != DICS_PROPCHANGE
1001 && PropChangeParams->StateChange != DICS_START && PropChangeParams->StateChange != DICS_STOP)
1002 SetLastError(ERROR_INVALID_FLAGS);
1003 else if (PropChangeParams && PropChangeParams->Scope != DICS_FLAG_GLOBAL
1004 && PropChangeParams->Scope != DICS_FLAG_CONFIGSPECIFIC)
1005 SetLastError(ERROR_INVALID_FLAGS);
1006 else if (PropChangeParams
1007 && (PropChangeParams->StateChange == DICS_START || PropChangeParams->StateChange == DICS_STOP)
1008 && PropChangeParams->Scope != DICS_FLAG_CONFIGSPECIFIC)
1009 SetLastError(ERROR_INVALID_USER_BUFFER);
1010 else
1011 {
1012 PSP_PROPCHANGE_PARAMS *CurrentPropChangeParams;
1013 struct DeviceInfo *deviceInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
1014 CurrentPropChangeParams = &deviceInfo->ClassInstallParams.PropChangeParams;
1015
1016 if (*CurrentPropChangeParams)
1017 {
1018 MyFree(*CurrentPropChangeParams);
1019 *CurrentPropChangeParams = NULL;
1020 }
1021 if (PropChangeParams)
1022 {
1023 *CurrentPropChangeParams = MyMalloc(ClassInstallParamsSize);
1024 if (!*CurrentPropChangeParams)
1025 {
1026 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1027 goto done;
1028 }
1029 memcpy(*CurrentPropChangeParams, PropChangeParams, ClassInstallParamsSize);
1030 }
1031 ret = TRUE;
1032 }
1033
1034 done:
1035 return ret;
1036 }
1037
1038 static BOOL
1039 SETUP_PropertyAddPropertyAdvancedHandler(
1040 IN HDEVINFO DeviceInfoSet,
1041 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
1042 IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL,
1043 IN DWORD ClassInstallParamsSize)
1044 {
1045 PSP_ADDPROPERTYPAGE_DATA AddPropertyPageData = (PSP_ADDPROPERTYPAGE_DATA)ClassInstallParams;
1046 BOOL ret = FALSE;
1047
1048 if (ClassInstallParamsSize != sizeof(SP_PROPCHANGE_PARAMS))
1049 SetLastError(ERROR_INVALID_PARAMETER);
1050 else if (AddPropertyPageData && AddPropertyPageData->Flags != 0)
1051 SetLastError(ERROR_INVALID_FLAGS);
1052 else if (AddPropertyPageData && AddPropertyPageData->NumDynamicPages >= MAX_INSTALLWIZARD_DYNAPAGES)
1053 SetLastError(ERROR_INVALID_USER_BUFFER);
1054 else
1055 {
1056 PSP_ADDPROPERTYPAGE_DATA *CurrentAddPropertyPageData;
1057 if (!DeviceInfoData)
1058 {
1059 struct DeviceInfoSet *list = (struct DeviceInfoSet *)DeviceInfoSet;
1060 CurrentAddPropertyPageData = &list->ClassInstallParams.AddPropertyPageData;
1061 }
1062 else
1063 {
1064 struct DeviceInfo *deviceInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
1065 CurrentAddPropertyPageData = &deviceInfo->ClassInstallParams.AddPropertyPageData;
1066 }
1067 if (*CurrentAddPropertyPageData)
1068 {
1069 MyFree(*CurrentAddPropertyPageData);
1070 *CurrentAddPropertyPageData = NULL;
1071 }
1072 if (AddPropertyPageData)
1073 {
1074 *CurrentAddPropertyPageData = MyMalloc(ClassInstallParamsSize);
1075 if (!*CurrentAddPropertyPageData)
1076 {
1077 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1078 goto done;
1079 }
1080 memcpy(*CurrentAddPropertyPageData, AddPropertyPageData, ClassInstallParamsSize);
1081 }
1082 ret = TRUE;
1083 }
1084
1085 done:
1086 return ret;
1087 }
1088
1089 /***********************************************************************
1090 * SetupDiSetClassInstallParamsW (SETUPAPI.@)
1091 */
1092 BOOL WINAPI
1093 SetupDiSetClassInstallParamsW(
1094 IN HDEVINFO DeviceInfoSet,
1095 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
1096 IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL,
1097 IN DWORD ClassInstallParamsSize)
1098 {
1099 struct DeviceInfoSet *list;
1100 BOOL ret = FALSE;
1101
1102 TRACE("%p %p %p %lu\n", DeviceInfoSet, DeviceInfoData,
1103 ClassInstallParams, ClassInstallParamsSize);
1104
1105 if (!DeviceInfoSet)
1106 SetLastError(ERROR_INVALID_PARAMETER);
1107 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
1108 SetLastError(ERROR_INVALID_HANDLE);
1109 else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
1110 SetLastError(ERROR_INVALID_HANDLE);
1111 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
1112 SetLastError(ERROR_INVALID_USER_BUFFER);
1113 else if (ClassInstallParams && ClassInstallParams->cbSize != sizeof(SP_CLASSINSTALL_HEADER))
1114 SetLastError(ERROR_INVALID_USER_BUFFER);
1115 else if (ClassInstallParams && ClassInstallParamsSize < sizeof(SP_CLASSINSTALL_HEADER))
1116 SetLastError(ERROR_INVALID_PARAMETER);
1117 else if (!ClassInstallParams && ClassInstallParamsSize != 0)
1118 SetLastError(ERROR_INVALID_PARAMETER);
1119 else
1120 {
1121 SP_DEVINSTALL_PARAMS_W InstallParams;
1122 BOOL Result;
1123
1124 InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
1125 Result = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
1126 if (!Result)
1127 goto done;
1128
1129 if (ClassInstallParams)
1130 {
1131 DWORD i;
1132 /* Check parameters in ClassInstallParams */
1133 for (i = 0; i < sizeof(InstallParamsData) / sizeof(InstallParamsData[0]); i++)
1134 {
1135 if (InstallParamsData[i].Function == ClassInstallParams->InstallFunction)
1136 {
1137 ret = InstallParamsData[i].UpdateHandler(
1138 DeviceInfoSet,
1139 DeviceInfoData,
1140 ClassInstallParams,
1141 ClassInstallParamsSize);
1142 if (ret)
1143 {
1144 InstallParams.Flags |= DI_CLASSINSTALLPARAMS;
1145 ret = SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
1146 }
1147 goto done;
1148 }
1149 }
1150 ERR("InstallFunction %u has no associated update handler\n", ClassInstallParams->InstallFunction);
1151 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1152 goto done;
1153 }
1154 else
1155 {
1156 InstallParams.Flags &= ~DI_CLASSINSTALLPARAMS;
1157 ret = SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
1158 }
1159 }
1160
1161 done:
1162 TRACE("Returning %d\n", ret);
1163 return ret;
1164 }
1165
1166 /***********************************************************************
1167 * SetupDiGetClassDevPropertySheetsA(SETUPAPI.@)
1168 */
1169 BOOL WINAPI
1170 SetupDiGetClassDevPropertySheetsA(
1171 IN HDEVINFO DeviceInfoSet,
1172 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
1173 IN LPPROPSHEETHEADERA PropertySheetHeader,
1174 IN DWORD PropertySheetHeaderPageListSize,
1175 OUT PDWORD RequiredSize OPTIONAL,
1176 IN DWORD PropertySheetType)
1177 {
1178 PROPSHEETHEADERW psh;
1179 BOOL ret = FALSE;
1180
1181 TRACE("%p %p %p 0%lx %p 0x%lx\n", DeviceInfoSet, DeviceInfoData,
1182 PropertySheetHeader, PropertySheetHeaderPageListSize,
1183 RequiredSize, PropertySheetType);
1184
1185 if(PropertySheetHeader)
1186 {
1187 psh.dwFlags = PropertySheetHeader->dwFlags;
1188 psh.phpage = PropertySheetHeader->phpage;
1189 psh.nPages = PropertySheetHeader->nPages;
1190 }
1191
1192 ret = SetupDiGetClassDevPropertySheetsW(DeviceInfoSet, DeviceInfoData, PropertySheetHeader ? &psh : NULL,
1193 PropertySheetHeaderPageListSize, RequiredSize,
1194 PropertySheetType);
1195 if (ret)
1196 {
1197 PropertySheetHeader->nPages = psh.nPages;
1198 }
1199
1200 TRACE("Returning %d\n", ret);
1201 return ret;
1202 }
1203
1204 struct ClassDevPropertySheetsData
1205 {
1206 LPPROPSHEETHEADERW PropertySheetHeader;
1207 DWORD PropertySheetHeaderPageListSize;
1208 DWORD NumberOfPages;
1209 BOOL DontCancel;
1210 };
1211
1212 static BOOL WINAPI
1213 SETUP_GetClassDevPropertySheetsCallback(
1214 IN HPROPSHEETPAGE hPropSheetPage,
1215 IN OUT LPARAM lParam)
1216 {
1217 struct ClassDevPropertySheetsData *PropPageData;
1218
1219 PropPageData = (struct ClassDevPropertySheetsData *)lParam;
1220
1221 PropPageData->NumberOfPages++;
1222
1223 if (PropPageData->PropertySheetHeader->nPages < PropPageData->PropertySheetHeaderPageListSize)
1224 {
1225 PropPageData->PropertySheetHeader->phpage[PropPageData->PropertySheetHeader->nPages] = hPropSheetPage;
1226 PropPageData->PropertySheetHeader->nPages++;
1227 return TRUE;
1228 }
1229
1230 return PropPageData->DontCancel;
1231 }
1232
1233 /***********************************************************************
1234 * SetupDiGetClassDevPropertySheetsW(SETUPAPI.@)
1235 */
1236 BOOL WINAPI
1237 SetupDiGetClassDevPropertySheetsW(
1238 IN HDEVINFO DeviceInfoSet,
1239 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
1240 IN OUT LPPROPSHEETHEADERW PropertySheetHeader,
1241 IN DWORD PropertySheetHeaderPageListSize,
1242 OUT PDWORD RequiredSize OPTIONAL,
1243 IN DWORD PropertySheetType)
1244 {
1245 struct DeviceInfoSet *list;
1246 BOOL ret = FALSE;
1247
1248 TRACE("%p %p %p 0%lx %p 0x%lx\n", DeviceInfoSet, DeviceInfoData,
1249 PropertySheetHeader, PropertySheetHeaderPageListSize,
1250 RequiredSize, PropertySheetType);
1251
1252 if (!DeviceInfoSet)
1253 SetLastError(ERROR_INVALID_HANDLE);
1254 else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
1255 SetLastError(ERROR_INVALID_HANDLE);
1256 else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
1257 SetLastError(ERROR_INVALID_HANDLE);
1258 else if (!PropertySheetHeader)
1259 SetLastError(ERROR_INVALID_PARAMETER);
1260 else if (PropertySheetHeader->dwFlags & PSH_PROPSHEETPAGE)
1261 SetLastError(ERROR_INVALID_FLAGS);
1262 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
1263 SetLastError(ERROR_INVALID_USER_BUFFER);
1264 else if (!DeviceInfoData && IsEqualIID(&list->ClassGuid, &GUID_NULL))
1265 SetLastError(ERROR_INVALID_PARAMETER);
1266 else if (PropertySheetType != DIGCDP_FLAG_ADVANCED
1267 && PropertySheetType != DIGCDP_FLAG_BASIC
1268 && PropertySheetType != DIGCDP_FLAG_REMOTE_ADVANCED
1269 && PropertySheetType != DIGCDP_FLAG_REMOTE_BASIC)
1270 SetLastError(ERROR_INVALID_PARAMETER);
1271 else
1272 {
1273 HKEY hKey = INVALID_HANDLE_VALUE;
1274 SP_PROPSHEETPAGE_REQUEST Request;
1275 LPWSTR PropPageProvider = NULL;
1276 HMODULE hModule = NULL;
1277 PROPERTY_PAGE_PROVIDER pPropPageProvider = NULL;
1278 struct ClassDevPropertySheetsData PropPageData;
1279 DWORD dwLength, dwRegType;
1280 DWORD InitialNumberOfPages;
1281 DWORD rc;
1282
1283 if (DeviceInfoData)
1284 hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_QUERY_VALUE);
1285 else
1286 {
1287 hKey = SetupDiOpenClassRegKeyExW(&list->ClassGuid, KEY_QUERY_VALUE,
1288 DIOCR_INSTALLER, list->MachineName + 2, NULL);
1289 }
1290 if (hKey == INVALID_HANDLE_VALUE)
1291 goto cleanup;
1292
1293 rc = RegQueryValueExW(hKey, REGSTR_VAL_ENUMPROPPAGES_32, NULL, &dwRegType, NULL, &dwLength);
1294 if (rc == ERROR_FILE_NOT_FOUND)
1295 {
1296 /* No registry key. As it is optional, don't say it's a bad error */
1297 if (RequiredSize)
1298 *RequiredSize = 0;
1299 ret = TRUE;
1300 goto cleanup;
1301 }
1302 else if (rc != ERROR_SUCCESS && dwRegType != REG_SZ)
1303 {
1304 SetLastError(rc);
1305 goto cleanup;
1306 }
1307
1308 PropPageProvider = HeapAlloc(GetProcessHeap(), 0, dwLength + sizeof(WCHAR));
1309 if (!PropPageProvider)
1310 {
1311 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1312 goto cleanup;
1313 }
1314 rc = RegQueryValueExW(hKey, REGSTR_VAL_ENUMPROPPAGES_32, NULL, NULL, (LPBYTE)PropPageProvider, &dwLength);
1315 if (rc != ERROR_SUCCESS)
1316 {
1317 SetLastError(rc);
1318 goto cleanup;
1319 }
1320 PropPageProvider[dwLength / sizeof(WCHAR)] = 0;
1321
1322 rc = GetFunctionPointer(PropPageProvider, &hModule, (PVOID*)&pPropPageProvider);
1323 if (rc != ERROR_SUCCESS)
1324 {
1325 SetLastError(ERROR_INVALID_PROPPAGE_PROVIDER);
1326 goto cleanup;
1327 }
1328
1329 if (DeviceInfoData)
1330 {
1331 struct DeviceInfo *devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
1332
1333 if (devInfo->hmodDevicePropPageProvider == NULL)
1334 {
1335 devInfo->hmodDevicePropPageProvider = hModule;
1336 devInfo->pDevicePropPageProvider = pPropPageProvider;
1337 }
1338 }
1339 else
1340 {
1341 struct DeviceInfoSet *devInfoSet = (struct DeviceInfoSet *)DeviceInfoSet;
1342
1343 if (devInfoSet->hmodClassPropPageProvider == NULL)
1344 {
1345 devInfoSet->hmodClassPropPageProvider = hModule;
1346 devInfoSet->pClassPropPageProvider = pPropPageProvider;
1347 }
1348 }
1349
1350 InitialNumberOfPages = PropertySheetHeader->nPages;
1351
1352 Request.cbSize = sizeof(SP_PROPSHEETPAGE_REQUEST);
1353 Request.PageRequested = SPPSR_ENUM_ADV_DEVICE_PROPERTIES;
1354 Request.DeviceInfoSet = DeviceInfoSet;
1355 Request.DeviceInfoData = DeviceInfoData;
1356
1357 PropPageData.PropertySheetHeader = PropertySheetHeader;
1358 PropPageData.PropertySheetHeaderPageListSize = PropertySheetHeaderPageListSize;
1359 PropPageData.NumberOfPages = 0;
1360 PropPageData.DontCancel = (RequiredSize != NULL) ? TRUE : FALSE;
1361
1362 pPropPageProvider(&Request, SETUP_GetClassDevPropertySheetsCallback, (LPARAM)&PropPageData);
1363
1364 if (RequiredSize)
1365 *RequiredSize = PropPageData.NumberOfPages;
1366
1367 if (InitialNumberOfPages + PropPageData.NumberOfPages <= PropertySheetHeaderPageListSize)
1368 {
1369 ret = TRUE;
1370 }
1371 else
1372 {
1373 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1374 }
1375
1376 cleanup:
1377 if (hKey != INVALID_HANDLE_VALUE)
1378 RegCloseKey(hKey);
1379 HeapFree(GetProcessHeap(), 0, PropPageProvider);
1380 }
1381
1382 TRACE("Returning %d\n", ret);
1383 return ret;
1384 }