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