Partial merge of condrv_restructure branch r65657.
[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 return ret;
556 }
557
558
559 /***********************************************************************
560 * SetupDiGetClassImageListExW(SETUPAPI.@)
561 */
562 BOOL WINAPI
563 SetupDiGetClassImageListExW(
564 OUT PSP_CLASSIMAGELIST_DATA ClassImageListData,
565 IN PCWSTR MachineName OPTIONAL,
566 IN PVOID Reserved)
567 {
568 BOOL ret = FALSE;
569
570 TRACE("%p %p %p\n", ClassImageListData, debugstr_w(MachineName), Reserved);
571
572 if (!ClassImageListData)
573 SetLastError(ERROR_INVALID_PARAMETER);
574 else if (ClassImageListData->cbSize != sizeof(SP_CLASSIMAGELIST_DATA))
575 SetLastError(ERROR_INVALID_USER_BUFFER);
576 else if (Reserved)
577 SetLastError(ERROR_INVALID_PARAMETER);
578 else
579 {
580 struct ClassImageList *list = NULL;
581 HDC hDC;
582 DWORD RequiredSize;
583 DWORD ilMask, bkColor;
584 HICON hIcon;
585 DWORD size;
586 INT i, bpp;
587 UINT idx;
588
589 /* Get list of all class GUIDs in given computer */
590 ret = SetupDiBuildClassInfoListExW(
591 0,
592 NULL,
593 0,
594 &RequiredSize,
595 MachineName,
596 NULL);
597 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
598 goto cleanup;
599
600 size = sizeof(struct ClassImageList)
601 + (sizeof(GUID) + sizeof(INT)) * RequiredSize;
602 list = HeapAlloc(GetProcessHeap(), 0, size);
603 if (!list)
604 {
605 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
606 goto cleanup;
607 }
608 list->magic = SETUP_CLASS_IMAGE_LIST_MAGIC;
609 list->NumberOfGuids = RequiredSize;
610 list->Guids = (GUID*)(list + 1);
611 list->IconIndexes = (INT*)((ULONG_PTR)(list + 1) + sizeof(GUID) * RequiredSize);
612
613 ret = SetupDiBuildClassInfoListExW(
614 0,
615 list->Guids,
616 list->NumberOfGuids,
617 &RequiredSize,
618 MachineName,
619 NULL);
620 if (!ret)
621 goto cleanup;
622 else if (RequiredSize != list->NumberOfGuids)
623 {
624 /* Hm. Class list changed since last call. Ignore
625 * this case as it should be very rare */
626 SetLastError(ERROR_GEN_FAILURE);
627 ret = FALSE;
628 goto cleanup;
629 }
630
631 /* Prepare a HIMAGELIST */
632 InitCommonControls();
633
634 hDC = GetDC(NULL);
635 if (!hDC)
636 goto cleanup;
637
638 bpp = GetDeviceCaps(hDC, BITSPIXEL);
639 ReleaseDC(NULL, hDC);
640
641 if (bpp <= 4)
642 ilMask = ILC_COLOR4;
643 else if (bpp <= 8)
644 ilMask = ILC_COLOR8;
645 else if (bpp <= 16)
646 ilMask = ILC_COLOR16;
647 else if (bpp <= 24)
648 ilMask = ILC_COLOR24;
649 else if (bpp <= 32)
650 ilMask = ILC_COLOR32;
651 else
652 ilMask = ILC_COLOR;
653
654 ilMask |= ILC_MASK;
655
656 ClassImageListData->ImageList = ImageList_Create(16, 16, ilMask, 100, 10);
657 if (!ClassImageListData->ImageList)
658 goto cleanup;
659
660 ClassImageListData->Reserved = (ULONG_PTR)list;
661
662 /* For some reason, Windows sets the list background to COLOR_WINDOW */
663 bkColor = GetSysColor(COLOR_WINDOW);
664 ImageList_SetBkColor(ClassImageListData->ImageList, bkColor);
665
666 /* Now, we "simply" need to load icons associated with all class guids,
667 * and put their index in the image list in the IconIndexes array */
668 for (i = 0; i < list->NumberOfGuids; i++)
669 {
670 INT miniIconIndex;
671 LPWSTR DllName = NULL;
672
673 if (SETUP_GetClassIconInfo(&list->Guids[i], &miniIconIndex, &DllName))
674 {
675 if (DllName && ExtractIconExW(DllName, -miniIconIndex, NULL, &hIcon, 1) == 1)
676 {
677 list->IconIndexes[i] = ImageList_AddIcon(ClassImageListData->ImageList, hIcon);
678 }
679 else if(!DllName)
680 {
681 hIcon = LoadImage(hInstance, MAKEINTRESOURCE(miniIconIndex), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
682 list->IconIndexes[i] = ImageList_AddIcon(ClassImageListData->ImageList, hIcon);
683 }
684
685 if(hIcon)
686 DestroyIcon(hIcon);
687 else
688 list->IconIndexes[i] = -1;
689
690 if(DllName)
691 MyFree(DllName);
692 }
693 else
694 {
695 list->IconIndexes[i] = -1; /* Special value to indicate that the icon is unavailable */
696 }
697 }
698
699 /* Finally, add the overlay icons to the image list */
700 for (i = 0; i < 2; i++)
701 {
702 hIcon = LoadImage(hInstance, MAKEINTRESOURCE(500 + i), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
703 if (hIcon)
704 {
705 idx = ImageList_AddIcon(ClassImageListData->ImageList, hIcon);
706 if (idx != -1)
707 ImageList_SetOverlayImage(ClassImageListData->ImageList, idx, i);
708 DestroyIcon(hIcon);
709 }
710 }
711
712 ret = TRUE;
713
714 cleanup:
715 if (!ret)
716 {
717 if (ClassImageListData->Reserved)
718 SetupDiDestroyClassImageList(ClassImageListData);
719 else if (list)
720 MyFree(list);
721 }
722 }
723
724 TRACE("Returning %d\n", ret);
725 return ret;
726 }
727
728 /***********************************************************************
729 * SetupDiGetClassInstallParamsA(SETUPAPI.@)
730 */
731 BOOL WINAPI
732 SetupDiGetClassInstallParamsA(
733 IN HDEVINFO DeviceInfoSet,
734 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
735 OUT PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL,
736 IN DWORD ClassInstallParamsSize,
737 OUT PDWORD RequiredSize OPTIONAL)
738 {
739 FIXME("SetupDiGetClassInstallParamsA(%p %p %p %lu %p) Stub\n",
740 DeviceInfoSet, DeviceInfoData, ClassInstallParams, ClassInstallParamsSize, RequiredSize);
741 return FALSE;
742 }
743
744 /***********************************************************************
745 * SetupDiGetClassInstallParamsW(SETUPAPI.@)
746 */
747 BOOL WINAPI
748 SetupDiGetClassInstallParamsW(
749 IN HDEVINFO DeviceInfoSet,
750 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
751 OUT PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL,
752 IN DWORD ClassInstallParamsSize,
753 OUT PDWORD RequiredSize OPTIONAL)
754 {
755 FIXME("SetupDiGetClassInstallParamsW(%p %p %p %lu %p) Stub\n",
756 DeviceInfoSet, DeviceInfoData, ClassInstallParams, ClassInstallParamsSize, RequiredSize);
757 return FALSE;
758 }
759
760 /***********************************************************************
761 * SetupDiLoadClassIcon(SETUPAPI.@)
762 */
763 BOOL WINAPI
764 SetupDiLoadClassIcon(
765 IN CONST GUID *ClassGuid,
766 OUT HICON *LargeIcon OPTIONAL,
767 OUT PINT MiniIconIndex OPTIONAL)
768 {
769 INT iconIndex = 0;
770 LPWSTR DllName = NULL;
771 BOOL ret = FALSE;
772 HICON hIcon = NULL;
773
774 if (LargeIcon)
775 {
776 if(!SETUP_GetClassIconInfo(ClassGuid, &iconIndex, &DllName))
777 return FALSE;
778
779 if (DllName && ExtractIconExW(DllName, -iconIndex, &hIcon, NULL, 1) == 1 && hIcon != NULL)
780 {
781 ret = TRUE;
782 }
783 else
784 {
785 /* load the default unknown device icon if ExtractIcon failed */
786 if(DllName)
787 iconIndex = UNKNOWN_ICON_INDEX;
788
789 hIcon = LoadImage(hInstance, MAKEINTRESOURCE(iconIndex), IMAGE_ICON, 32, 32, LR_DEFAULTCOLOR);
790
791 if(!LargeIcon)
792 goto cleanup;
793 }
794 }
795
796 if (MiniIconIndex)
797 *MiniIconIndex = iconIndex;
798
799 ret = TRUE;
800 *LargeIcon = hIcon;
801
802 cleanup:
803
804 if(DllName)
805 MyFree(DllName);
806
807 TRACE("Returning %d\n", ret);
808 return ret;
809 }
810
811 /***********************************************************************
812 * SetupDiInstallClassExW (SETUPAPI.@)
813 */
814 HKEY
815 SETUP_CreateClassKey(HINF hInf);
816 BOOL WINAPI
817 SetupDiInstallClassExW(
818 IN HWND hwndParent OPTIONAL,
819 IN PCWSTR InfFileName OPTIONAL,
820 IN DWORD Flags,
821 IN HSPFILEQ FileQueue OPTIONAL,
822 IN CONST GUID *InterfaceClassGuid OPTIONAL,
823 IN PVOID Reserved1,
824 IN PVOID Reserved2)
825 {
826 BOOL ret = FALSE;
827
828 TRACE("%p %s 0x%lx %p %s %p %p\n", hwndParent, debugstr_w(InfFileName), Flags,
829 FileQueue, debugstr_guid(InterfaceClassGuid), Reserved1, Reserved2);
830
831 if (!InfFileName)
832 {
833 FIXME("Case not implemented: InfFileName NULL\n");
834 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
835 }
836 else if (Flags & ~(DI_NOVCP | DI_NOBROWSE | DI_FORCECOPY | DI_QUIETINSTALL))
837 {
838 TRACE("Unknown flags: 0x%08lx\n", Flags & ~(DI_NOVCP | DI_NOBROWSE | DI_FORCECOPY | DI_QUIETINSTALL));
839 SetLastError(ERROR_INVALID_FLAGS);
840 }
841 else if ((Flags & DI_NOVCP) && FileQueue == NULL)
842 SetLastError(ERROR_INVALID_PARAMETER);
843 else if (Reserved1 != NULL)
844 SetLastError(ERROR_INVALID_PARAMETER);
845 else if (Reserved2 != NULL)
846 SetLastError(ERROR_INVALID_PARAMETER);
847 else
848 {
849 HDEVINFO hDeviceInfo = INVALID_HANDLE_VALUE;
850 SP_DEVINSTALL_PARAMS_W InstallParams;
851 WCHAR SectionName[MAX_PATH];
852 HINF hInf = INVALID_HANDLE_VALUE;
853 HKEY hRootKey = INVALID_HANDLE_VALUE;
854 PVOID callback_context = NULL;
855
856 hDeviceInfo = SetupDiCreateDeviceInfoList(NULL, NULL);
857 if (hDeviceInfo == INVALID_HANDLE_VALUE)
858 goto cleanup;
859
860 InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
861 if (!SetupDiGetDeviceInstallParamsW(hDeviceInfo, NULL, &InstallParams))
862 goto cleanup;
863 InstallParams.Flags &= ~(DI_NOVCP | DI_NOBROWSE | DI_QUIETINSTALL);
864 InstallParams.Flags |= Flags & (DI_NOVCP | DI_NOBROWSE | DI_QUIETINSTALL);
865 if (Flags & DI_NOVCP)
866 InstallParams.FileQueue = FileQueue;
867 if (!SetupDiSetDeviceInstallParamsW(hDeviceInfo, NULL, &InstallParams))
868 goto cleanup;
869
870 /* Open the .inf file */
871 hInf = SetupOpenInfFileW(
872 InfFileName,
873 NULL,
874 INF_STYLE_WIN4,
875 NULL);
876 if (hInf == INVALID_HANDLE_VALUE)
877 goto cleanup;
878
879 /* Try to append a layout file */
880 SetupOpenAppendInfFileW(NULL, hInf, NULL);
881
882 if (InterfaceClassGuid)
883 {
884 /* Retrieve the actual section name */
885 ret = SetupDiGetActualSectionToInstallW(
886 hInf,
887 InterfaceInstall32,
888 SectionName,
889 MAX_PATH,
890 NULL,
891 NULL);
892 if (!ret)
893 goto cleanup;
894
895 /* Open registry key related to this interface */
896 /* FIXME: What happens if the key doesn't exist? */
897 hRootKey = SetupDiOpenClassRegKeyExW(InterfaceClassGuid, KEY_ENUMERATE_SUB_KEYS, DIOCR_INTERFACE, NULL, NULL);
898 if (hRootKey == INVALID_HANDLE_VALUE)
899 goto cleanup;
900
901 /* SetupDiCreateDeviceInterface??? */
902 FIXME("Installing an interface is not implemented\n");
903 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
904 }
905 else
906 {
907 /* Create or open the class registry key 'HKLM\CurrentControlSet\Class\{GUID}' */
908 hRootKey = SETUP_CreateClassKey(hInf);
909 if (hRootKey == INVALID_HANDLE_VALUE)
910 goto cleanup;
911
912 /* Retrieve the actual section name */
913 ret = SetupDiGetActualSectionToInstallW(
914 hInf,
915 ClassInstall32,
916 SectionName,
917 MAX_PATH - strlenW(DotServices),
918 NULL,
919 NULL);
920 if (!ret)
921 goto cleanup;
922
923 callback_context = SetupInitDefaultQueueCallback(hwndParent);
924 if (!callback_context)
925 goto cleanup;
926
927 ret = SetupInstallFromInfSectionW(
928 hwndParent,
929 hInf,
930 SectionName,
931 SPINST_REGISTRY | SPINST_FILES | SPINST_BITREG | SPINST_INIFILES | SPINST_INI2REG,
932 hRootKey,
933 NULL, /* FIXME: SourceRootPath */
934 !(Flags & DI_NOVCP) && (Flags & DI_FORCECOPY) ? SP_COPY_FORCE_IN_USE : 0, /* CopyFlags */
935 SetupDefaultQueueCallbackW,
936 callback_context,
937 hDeviceInfo,
938 NULL);
939 if (!ret)
940 goto cleanup;
941
942 /* Install .Services section */
943 lstrcatW(SectionName, DotServices);
944 ret = SetupInstallServicesFromInfSectionExW(
945 hInf,
946 SectionName,
947 0,
948 hDeviceInfo,
949 NULL,
950 NULL,
951 NULL);
952 if (!ret)
953 goto cleanup;
954
955 ret = TRUE;
956 }
957
958 cleanup:
959 if (hDeviceInfo != INVALID_HANDLE_VALUE)
960 SetupDiDestroyDeviceInfoList(hDeviceInfo);
961 if (hInf != INVALID_HANDLE_VALUE)
962 SetupCloseInfFile(hInf);
963 if (hRootKey != INVALID_HANDLE_VALUE)
964 RegCloseKey(hRootKey);
965 SetupTermDefaultQueueCallback(callback_context);
966 }
967
968 TRACE("Returning %d\n", ret);
969 return ret;
970 }
971
972 /***********************************************************************
973 * Helper functions for SetupDiSetClassInstallParamsW
974 */
975 static BOOL
976 SETUP_PropertyChangeHandler(
977 IN HDEVINFO DeviceInfoSet,
978 IN PSP_DEVINFO_DATA DeviceInfoData,
979 IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL,
980 IN DWORD ClassInstallParamsSize)
981 {
982 PSP_PROPCHANGE_PARAMS PropChangeParams = (PSP_PROPCHANGE_PARAMS)ClassInstallParams;
983 BOOL ret = FALSE;
984
985 if (!DeviceInfoData)
986 SetLastError(ERROR_INVALID_PARAMETER);
987 else if (ClassInstallParamsSize != sizeof(SP_PROPCHANGE_PARAMS))
988 SetLastError(ERROR_INVALID_PARAMETER);
989 else if (PropChangeParams && PropChangeParams->StateChange != DICS_ENABLE
990 && PropChangeParams->StateChange != DICS_DISABLE && PropChangeParams->StateChange != DICS_PROPCHANGE
991 && PropChangeParams->StateChange != DICS_START && PropChangeParams->StateChange != DICS_STOP)
992 SetLastError(ERROR_INVALID_FLAGS);
993 else if (PropChangeParams && PropChangeParams->Scope != DICS_FLAG_GLOBAL
994 && PropChangeParams->Scope != DICS_FLAG_CONFIGSPECIFIC)
995 SetLastError(ERROR_INVALID_FLAGS);
996 else if (PropChangeParams
997 && (PropChangeParams->StateChange == DICS_START || PropChangeParams->StateChange == DICS_STOP)
998 && PropChangeParams->Scope != DICS_FLAG_CONFIGSPECIFIC)
999 SetLastError(ERROR_INVALID_USER_BUFFER);
1000 else
1001 {
1002 PSP_PROPCHANGE_PARAMS *CurrentPropChangeParams;
1003 struct DeviceInfo *deviceInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
1004 CurrentPropChangeParams = &deviceInfo->ClassInstallParams.PropChangeParams;
1005
1006 if (*CurrentPropChangeParams)
1007 {
1008 MyFree(*CurrentPropChangeParams);
1009 *CurrentPropChangeParams = NULL;
1010 }
1011 if (PropChangeParams)
1012 {
1013 *CurrentPropChangeParams = MyMalloc(ClassInstallParamsSize);
1014 if (!*CurrentPropChangeParams)
1015 {
1016 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1017 goto done;
1018 }
1019 memcpy(*CurrentPropChangeParams, PropChangeParams, ClassInstallParamsSize);
1020 }
1021 ret = TRUE;
1022 }
1023
1024 done:
1025 return ret;
1026 }
1027
1028 static BOOL
1029 SETUP_PropertyAddPropertyAdvancedHandler(
1030 IN HDEVINFO DeviceInfoSet,
1031 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
1032 IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL,
1033 IN DWORD ClassInstallParamsSize)
1034 {
1035 PSP_ADDPROPERTYPAGE_DATA AddPropertyPageData = (PSP_ADDPROPERTYPAGE_DATA)ClassInstallParams;
1036 BOOL ret = FALSE;
1037
1038 if (ClassInstallParamsSize != sizeof(SP_PROPCHANGE_PARAMS))
1039 SetLastError(ERROR_INVALID_PARAMETER);
1040 else if (AddPropertyPageData && AddPropertyPageData->Flags != 0)
1041 SetLastError(ERROR_INVALID_FLAGS);
1042 else if (AddPropertyPageData && AddPropertyPageData->NumDynamicPages >= MAX_INSTALLWIZARD_DYNAPAGES)
1043 SetLastError(ERROR_INVALID_USER_BUFFER);
1044 else
1045 {
1046 PSP_ADDPROPERTYPAGE_DATA *CurrentAddPropertyPageData;
1047 if (!DeviceInfoData)
1048 {
1049 struct DeviceInfoSet *list = (struct DeviceInfoSet *)DeviceInfoSet;
1050 CurrentAddPropertyPageData = &list->ClassInstallParams.AddPropertyPageData;
1051 }
1052 else
1053 {
1054 struct DeviceInfo *deviceInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
1055 CurrentAddPropertyPageData = &deviceInfo->ClassInstallParams.AddPropertyPageData;
1056 }
1057 if (*CurrentAddPropertyPageData)
1058 {
1059 MyFree(*CurrentAddPropertyPageData);
1060 *CurrentAddPropertyPageData = NULL;
1061 }
1062 if (AddPropertyPageData)
1063 {
1064 *CurrentAddPropertyPageData = MyMalloc(ClassInstallParamsSize);
1065 if (!*CurrentAddPropertyPageData)
1066 {
1067 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1068 goto done;
1069 }
1070 memcpy(*CurrentAddPropertyPageData, AddPropertyPageData, ClassInstallParamsSize);
1071 }
1072 ret = TRUE;
1073 }
1074
1075 done:
1076 return ret;
1077 }
1078
1079 /***********************************************************************
1080 * SetupDiSetClassInstallParamsW (SETUPAPI.@)
1081 */
1082 BOOL WINAPI
1083 SetupDiSetClassInstallParamsW(
1084 IN HDEVINFO DeviceInfoSet,
1085 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
1086 IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL,
1087 IN DWORD ClassInstallParamsSize)
1088 {
1089 struct DeviceInfoSet *list;
1090 BOOL ret = FALSE;
1091
1092 TRACE("%p %p %p %lu\n", DeviceInfoSet, DeviceInfoData,
1093 ClassInstallParams, ClassInstallParamsSize);
1094
1095 if (!DeviceInfoSet)
1096 SetLastError(ERROR_INVALID_PARAMETER);
1097 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
1098 SetLastError(ERROR_INVALID_HANDLE);
1099 else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
1100 SetLastError(ERROR_INVALID_HANDLE);
1101 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
1102 SetLastError(ERROR_INVALID_USER_BUFFER);
1103 else if (ClassInstallParams && ClassInstallParams->cbSize != sizeof(SP_CLASSINSTALL_HEADER))
1104 SetLastError(ERROR_INVALID_USER_BUFFER);
1105 else if (ClassInstallParams && ClassInstallParamsSize < sizeof(SP_CLASSINSTALL_HEADER))
1106 SetLastError(ERROR_INVALID_PARAMETER);
1107 else if (!ClassInstallParams && ClassInstallParamsSize != 0)
1108 SetLastError(ERROR_INVALID_PARAMETER);
1109 else
1110 {
1111 SP_DEVINSTALL_PARAMS_W InstallParams;
1112 BOOL Result;
1113
1114 InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
1115 Result = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
1116 if (!Result)
1117 goto done;
1118
1119 if (ClassInstallParams)
1120 {
1121 DWORD i;
1122 /* Check parameters in ClassInstallParams */
1123 for (i = 0; i < sizeof(InstallParamsData) / sizeof(InstallParamsData[0]); i++)
1124 {
1125 if (InstallParamsData[i].Function == ClassInstallParams->InstallFunction)
1126 {
1127 ret = InstallParamsData[i].UpdateHandler(
1128 DeviceInfoSet,
1129 DeviceInfoData,
1130 ClassInstallParams,
1131 ClassInstallParamsSize);
1132 if (ret)
1133 {
1134 InstallParams.Flags |= DI_CLASSINSTALLPARAMS;
1135 ret = SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
1136 }
1137 goto done;
1138 }
1139 }
1140 ERR("InstallFunction %u has no associated update handler\n", ClassInstallParams->InstallFunction);
1141 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1142 goto done;
1143 }
1144 else
1145 {
1146 InstallParams.Flags &= ~DI_CLASSINSTALLPARAMS;
1147 ret = SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
1148 }
1149 }
1150
1151 done:
1152 TRACE("Returning %d\n", ret);
1153 return ret;
1154 }
1155
1156 /***********************************************************************
1157 * SetupDiGetClassDevPropertySheetsA(SETUPAPI.@)
1158 */
1159 BOOL WINAPI
1160 SetupDiGetClassDevPropertySheetsA(
1161 IN HDEVINFO DeviceInfoSet,
1162 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
1163 IN LPPROPSHEETHEADERA PropertySheetHeader,
1164 IN DWORD PropertySheetHeaderPageListSize,
1165 OUT PDWORD RequiredSize OPTIONAL,
1166 IN DWORD PropertySheetType)
1167 {
1168 PROPSHEETHEADERW psh;
1169 BOOL ret = FALSE;
1170
1171 TRACE("%p %p %p 0%lx %p 0x%lx\n", DeviceInfoSet, DeviceInfoData,
1172 PropertySheetHeader, PropertySheetHeaderPageListSize,
1173 RequiredSize, PropertySheetType);
1174
1175 psh.dwFlags = PropertySheetHeader->dwFlags;
1176 psh.phpage = PropertySheetHeader->phpage;
1177 psh.nPages = PropertySheetHeader->nPages;
1178
1179 ret = SetupDiGetClassDevPropertySheetsW(DeviceInfoSet, DeviceInfoData, PropertySheetHeader ? &psh : NULL,
1180 PropertySheetHeaderPageListSize, RequiredSize,
1181 PropertySheetType);
1182 if (ret)
1183 {
1184 PropertySheetHeader->nPages = psh.nPages;
1185 }
1186
1187 TRACE("Returning %d\n", ret);
1188 return ret;
1189 }
1190
1191 struct ClassDevPropertySheetsData
1192 {
1193 LPPROPSHEETHEADERW PropertySheetHeader;
1194 DWORD PropertySheetHeaderPageListSize;
1195 DWORD NumberOfPages;
1196 BOOL DontCancel;
1197 };
1198
1199 static BOOL WINAPI
1200 SETUP_GetClassDevPropertySheetsCallback(
1201 IN HPROPSHEETPAGE hPropSheetPage,
1202 IN OUT LPARAM lParam)
1203 {
1204 struct ClassDevPropertySheetsData *PropPageData;
1205
1206 PropPageData = (struct ClassDevPropertySheetsData *)lParam;
1207
1208 PropPageData->NumberOfPages++;
1209
1210 if (PropPageData->PropertySheetHeader->nPages < PropPageData->PropertySheetHeaderPageListSize)
1211 {
1212 PropPageData->PropertySheetHeader->phpage[PropPageData->PropertySheetHeader->nPages] = hPropSheetPage;
1213 PropPageData->PropertySheetHeader->nPages++;
1214 return TRUE;
1215 }
1216
1217 return PropPageData->DontCancel;
1218 }
1219
1220 /***********************************************************************
1221 * SetupDiGetClassDevPropertySheetsW(SETUPAPI.@)
1222 */
1223 BOOL WINAPI
1224 SetupDiGetClassDevPropertySheetsW(
1225 IN HDEVINFO DeviceInfoSet,
1226 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
1227 IN OUT LPPROPSHEETHEADERW PropertySheetHeader,
1228 IN DWORD PropertySheetHeaderPageListSize,
1229 OUT PDWORD RequiredSize OPTIONAL,
1230 IN DWORD PropertySheetType)
1231 {
1232 struct DeviceInfoSet *list;
1233 BOOL ret = FALSE;
1234
1235 TRACE("%p %p %p 0%lx %p 0x%lx\n", DeviceInfoSet, DeviceInfoData,
1236 PropertySheetHeader, PropertySheetHeaderPageListSize,
1237 RequiredSize, PropertySheetType);
1238
1239 if (!DeviceInfoSet)
1240 SetLastError(ERROR_INVALID_HANDLE);
1241 else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
1242 SetLastError(ERROR_INVALID_HANDLE);
1243 else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
1244 SetLastError(ERROR_INVALID_HANDLE);
1245 else if (!PropertySheetHeader)
1246 SetLastError(ERROR_INVALID_PARAMETER);
1247 else if (PropertySheetHeader->dwFlags & PSH_PROPSHEETPAGE)
1248 SetLastError(ERROR_INVALID_FLAGS);
1249 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
1250 SetLastError(ERROR_INVALID_USER_BUFFER);
1251 else if (!DeviceInfoData && IsEqualIID(&list->ClassGuid, &GUID_NULL))
1252 SetLastError(ERROR_INVALID_PARAMETER);
1253 else if (PropertySheetType != DIGCDP_FLAG_ADVANCED
1254 && PropertySheetType != DIGCDP_FLAG_BASIC
1255 && PropertySheetType != DIGCDP_FLAG_REMOTE_ADVANCED
1256 && PropertySheetType != DIGCDP_FLAG_REMOTE_BASIC)
1257 SetLastError(ERROR_INVALID_PARAMETER);
1258 else
1259 {
1260 HKEY hKey = INVALID_HANDLE_VALUE;
1261 SP_PROPSHEETPAGE_REQUEST Request;
1262 LPWSTR PropPageProvider = NULL;
1263 HMODULE hModule = NULL;
1264 PROPERTY_PAGE_PROVIDER pPropPageProvider = NULL;
1265 struct ClassDevPropertySheetsData PropPageData;
1266 DWORD dwLength, dwRegType;
1267 DWORD InitialNumberOfPages;
1268 DWORD rc;
1269
1270 if (DeviceInfoData)
1271 hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_QUERY_VALUE);
1272 else
1273 {
1274 hKey = SetupDiOpenClassRegKeyExW(&list->ClassGuid, KEY_QUERY_VALUE,
1275 DIOCR_INSTALLER, list->MachineName + 2, NULL);
1276 }
1277 if (hKey == INVALID_HANDLE_VALUE)
1278 goto cleanup;
1279
1280 rc = RegQueryValueExW(hKey, REGSTR_VAL_ENUMPROPPAGES_32, NULL, &dwRegType, NULL, &dwLength);
1281 if (rc == ERROR_FILE_NOT_FOUND)
1282 {
1283 /* No registry key. As it is optional, don't say it's a bad error */
1284 if (RequiredSize)
1285 *RequiredSize = 0;
1286 ret = TRUE;
1287 goto cleanup;
1288 }
1289 else if (rc != ERROR_SUCCESS && dwRegType != REG_SZ)
1290 {
1291 SetLastError(rc);
1292 goto cleanup;
1293 }
1294
1295 PropPageProvider = HeapAlloc(GetProcessHeap(), 0, dwLength + sizeof(WCHAR));
1296 if (!PropPageProvider)
1297 {
1298 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1299 goto cleanup;
1300 }
1301 rc = RegQueryValueExW(hKey, REGSTR_VAL_ENUMPROPPAGES_32, NULL, NULL, (LPBYTE)PropPageProvider, &dwLength);
1302 if (rc != ERROR_SUCCESS)
1303 {
1304 SetLastError(rc);
1305 goto cleanup;
1306 }
1307 PropPageProvider[dwLength / sizeof(WCHAR)] = 0;
1308
1309 rc = GetFunctionPointer(PropPageProvider, &hModule, (PVOID*)&pPropPageProvider);
1310 if (rc != ERROR_SUCCESS)
1311 {
1312 SetLastError(ERROR_INVALID_PROPPAGE_PROVIDER);
1313 goto cleanup;
1314 }
1315
1316 if (DeviceInfoData)
1317 {
1318 struct DeviceInfo *devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
1319
1320 if (devInfo->hmodDevicePropPageProvider == NULL)
1321 {
1322 devInfo->hmodDevicePropPageProvider = hModule;
1323 devInfo->pDevicePropPageProvider = pPropPageProvider;
1324 }
1325 }
1326 else
1327 {
1328 struct DeviceInfoSet *devInfoSet = (struct DeviceInfoSet *)DeviceInfoSet;
1329
1330 if (devInfoSet->hmodClassPropPageProvider == NULL)
1331 {
1332 devInfoSet->hmodClassPropPageProvider = hModule;
1333 devInfoSet->pClassPropPageProvider = pPropPageProvider;
1334 }
1335 }
1336
1337 InitialNumberOfPages = PropertySheetHeader->nPages;
1338
1339 Request.cbSize = sizeof(SP_PROPSHEETPAGE_REQUEST);
1340 Request.PageRequested = SPPSR_ENUM_ADV_DEVICE_PROPERTIES;
1341 Request.DeviceInfoSet = DeviceInfoSet;
1342 Request.DeviceInfoData = DeviceInfoData;
1343
1344 PropPageData.PropertySheetHeader = PropertySheetHeader;
1345 PropPageData.PropertySheetHeaderPageListSize = PropertySheetHeaderPageListSize;
1346 PropPageData.NumberOfPages = 0;
1347 PropPageData.DontCancel = (RequiredSize != NULL) ? TRUE : FALSE;
1348
1349 pPropPageProvider(&Request, SETUP_GetClassDevPropertySheetsCallback, (LPARAM)&PropPageData);
1350
1351 if (RequiredSize)
1352 *RequiredSize = PropPageData.NumberOfPages;
1353
1354 if (InitialNumberOfPages + PropPageData.NumberOfPages <= PropertySheetHeaderPageListSize)
1355 {
1356 ret = TRUE;
1357 }
1358 else
1359 {
1360 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1361 }
1362
1363 cleanup:
1364 if (hKey != INVALID_HANDLE_VALUE)
1365 RegCloseKey(hKey);
1366 HeapFree(GetProcessHeap(), 0, PropPageProvider);
1367 }
1368
1369 TRACE("Returning %d\n", ret);
1370 return ret;
1371 }