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