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