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