xref: /reactos/dll/win32/setupapi/devclass.c (revision c10c5224)
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
SetupDiDestroyClassImageList(IN PSP_CLASSIMAGELIST_DATA ClassImageListData)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
SETUP_CreateDevicesList(IN OUT struct DeviceInfoSet * list,IN PCWSTR MachineName OPTIONAL,IN CONST GUID * Class OPTIONAL,IN PCWSTR Enumerator OPTIONAL)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 (cr == CR_REGISTRY_ERROR) ? ERROR_INVALID_DATA : 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
SETUP_GetIconIndex(IN HKEY hClassKey,OUT PINT ImageIndex)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
SetupDiGetClassImageIndex(IN PSP_CLASSIMAGELIST_DATA ClassImageListData,IN CONST GUID * ClassGuid,OUT PINT ImageIndex)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
SetupDiGetClassImageList(OUT PSP_CLASSIMAGELIST_DATA ClassImageListData)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
SetupDiGetClassImageListExA(OUT PSP_CLASSIMAGELIST_DATA ClassImageListData,IN PCSTR MachineName OPTIONAL,IN PVOID Reserved)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
SETUP_GetClassIconInfo(IN CONST GUID * ClassGuid,OUT PINT OutIndex,OUT LPWSTR * OutDllName)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
SetupDiGetClassImageListExW(OUT PSP_CLASSIMAGELIST_DATA ClassImageListData,IN PCWSTR MachineName OPTIONAL,IN PVOID Reserved)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
SetupDiGetClassInstallParamsA(IN HDEVINFO DeviceInfoSet,IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,OUT PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL,IN DWORD ClassInstallParamsSize,OUT PDWORD RequiredSize OPTIONAL)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
SetupDiGetClassInstallParamsW(IN HDEVINFO DeviceInfoSet,IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,OUT PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL,IN DWORD ClassInstallParamsSize,OUT PDWORD RequiredSize OPTIONAL)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
SetupDiLoadClassIcon(IN CONST GUID * ClassGuid,OUT HICON * LargeIcon OPTIONAL,OUT PINT MiniIconIndex OPTIONAL)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
SetupDiInstallClassExW(IN HWND hwndParent OPTIONAL,IN PCWSTR InfFileName OPTIONAL,IN DWORD Flags,IN HSPFILEQ FileQueue OPTIONAL,IN CONST GUID * InterfaceClassGuid OPTIONAL,IN PVOID Reserved1,IN PVOID Reserved2)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
SETUP_PropertyChangeHandler(IN HDEVINFO DeviceInfoSet,IN PSP_DEVINFO_DATA DeviceInfoData,IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL,IN DWORD ClassInstallParamsSize)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
SETUP_PropertyAddPropertyAdvancedHandler(IN HDEVINFO DeviceInfoSet,IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL,IN DWORD ClassInstallParamsSize)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
SetupDiSetClassInstallParamsW(IN HDEVINFO DeviceInfoSet,IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL,IN DWORD ClassInstallParamsSize)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
SetupDiGetClassDevPropertySheetsA(IN HDEVINFO DeviceInfoSet,IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,IN LPPROPSHEETHEADERA PropertySheetHeader,IN DWORD PropertySheetHeaderPageListSize,OUT PDWORD RequiredSize OPTIONAL,IN DWORD PropertySheetType)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
SETUP_GetClassDevPropertySheetsCallback(IN HPROPSHEETPAGE hPropSheetPage,IN OUT LPARAM lParam)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
SETUP_GetValueString(IN HKEY hKey,IN LPWSTR lpValueName,OUT LPWSTR * lpString)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
SETUP_CallInstaller(IN DI_FUNCTION InstallFunction,IN HDEVINFO DeviceInfoSet,IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,IN PSP_ADDPROPERTYPAGE_DATA PageData)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
SetupDiGetClassDevPropertySheetsW(IN HDEVINFO DeviceInfoSet,IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,IN OUT LPPROPSHEETHEADERW PropertySheetHeader,IN DWORD PropertySheetHeaderPageListSize,OUT PDWORD RequiredSize OPTIONAL,IN DWORD PropertySheetType)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 
1423 /***********************************************************************
1424  *		SetupDiGetClassRegistryPropertyA(SETUPAPI.@)
1425  */
1426 BOOL WINAPI
SetupDiGetClassRegistryPropertyA(IN CONST GUID * ClassGuid,IN DWORD Property,OUT PDWORD PropertyRegDataType OPTIONAL,OUT PBYTE PropertyBuffer,IN DWORD PropertyBufferSize,OUT PDWORD RequiredSize OPTIONAL,IN PCSTR MachineName OPTIONAL,IN PVOID Reserved)1427 SetupDiGetClassRegistryPropertyA(
1428     IN CONST GUID *ClassGuid,
1429     IN DWORD Property,
1430     OUT PDWORD PropertyRegDataType OPTIONAL,
1431     OUT PBYTE PropertyBuffer,
1432     IN  DWORD PropertyBufferSize,
1433     OUT PDWORD RequiredSize OPTIONAL,
1434     IN PCSTR MachineName OPTIONAL,
1435     IN PVOID Reserved)
1436 {
1437     HMACHINE hMachine = NULL;
1438     DWORD PropLength = 0;
1439     DWORD Error = ERROR_SUCCESS;
1440     CONFIGRET cr;
1441 
1442     TRACE("%s %lu %p %p %lu %p %s %p\n",
1443           debugstr_guid(ClassGuid), Property, PropertyRegDataType, PropertyBuffer,
1444           PropertyBufferSize, RequiredSize, MachineName, Reserved);
1445 
1446     if (Reserved != NULL)
1447     {
1448         SetLastError(ERROR_INVALID_PARAMETER);
1449         return FALSE;
1450     }
1451 
1452     if (MachineName)
1453     {
1454         cr = CM_Connect_MachineA(MachineName, &hMachine);
1455         if (cr != CR_SUCCESS)
1456             goto done;
1457     }
1458 
1459     if (Property >= SPCRP_MAXIMUM_PROPERTY)
1460     {
1461         cr = CR_INVALID_PROPERTY;
1462         goto done;
1463     }
1464 
1465     PropLength = PropertyBufferSize;
1466     cr = CM_Get_Class_Registry_PropertyA((LPGUID)ClassGuid,
1467                                          Property + (CM_DRP_DEVICEDESC - SPDRP_DEVICEDESC),
1468                                          PropertyRegDataType,
1469                                          PropertyBuffer,
1470                                          &PropLength,
1471                                          0,
1472                                          hMachine);
1473     if ((cr == CR_SUCCESS) || (cr == CR_BUFFER_SMALL))
1474     {
1475         if (RequiredSize)
1476             *RequiredSize = PropLength;
1477     }
1478 
1479 done:
1480     if (cr != CR_SUCCESS)
1481     {
1482         switch (cr)
1483         {
1484                 case CR_INVALID_DEVINST :
1485                     Error = ERROR_NO_SUCH_DEVINST;
1486                     break;
1487 
1488                 case CR_INVALID_PROPERTY :
1489                     Error = ERROR_INVALID_REG_PROPERTY;
1490                     break;
1491 
1492                 case CR_BUFFER_SMALL :
1493                     Error = ERROR_INSUFFICIENT_BUFFER;
1494                     break;
1495 
1496                 default :
1497                     Error = GetErrorCodeFromCrCode(cr);
1498         }
1499     }
1500 
1501     if (hMachine != NULL)
1502         CM_Disconnect_Machine(hMachine);
1503 
1504     SetLastError(Error);
1505     return (cr == CR_SUCCESS);
1506 }
1507 
1508 /***********************************************************************
1509  *		SetupDiGetClassRegistryPropertyW(SETUPAPI.@)
1510  */
1511 BOOL WINAPI
SetupDiGetClassRegistryPropertyW(IN CONST GUID * ClassGuid,IN DWORD Property,OUT PDWORD PropertyRegDataType OPTIONAL,OUT PBYTE PropertyBuffer,IN DWORD PropertyBufferSize,OUT PDWORD RequiredSize OPTIONAL,IN PCWSTR MachineName OPTIONAL,IN PVOID Reserved)1512 SetupDiGetClassRegistryPropertyW(
1513     IN CONST GUID *ClassGuid,
1514     IN DWORD Property,
1515     OUT PDWORD PropertyRegDataType OPTIONAL,
1516     OUT PBYTE PropertyBuffer,
1517     IN  DWORD PropertyBufferSize,
1518     OUT PDWORD RequiredSize OPTIONAL,
1519     IN PCWSTR MachineName OPTIONAL,
1520     IN PVOID Reserved)
1521 {
1522     HMACHINE hMachine = NULL;
1523     DWORD PropLength = 0;
1524     DWORD Error = ERROR_SUCCESS;
1525     CONFIGRET cr;
1526 
1527     TRACE("%s %lu %p %p %lu %p %s %p\n",
1528           debugstr_guid(ClassGuid), Property, PropertyRegDataType, PropertyBuffer,
1529           PropertyBufferSize, RequiredSize, debugstr_w(MachineName), Reserved);
1530 
1531     if (Reserved != NULL)
1532     {
1533         SetLastError(ERROR_INVALID_PARAMETER);
1534         return FALSE;
1535     }
1536 
1537     if (MachineName)
1538     {
1539         cr = CM_Connect_MachineW(MachineName, &hMachine);
1540         if (cr != CR_SUCCESS)
1541             goto done;
1542     }
1543 
1544     if (Property >= SPCRP_MAXIMUM_PROPERTY)
1545     {
1546         cr = CR_INVALID_PROPERTY;
1547         goto done;
1548     }
1549 
1550     PropLength = PropertyBufferSize;
1551     cr = CM_Get_Class_Registry_PropertyW((LPGUID)ClassGuid,
1552                                          Property + (CM_DRP_DEVICEDESC - SPDRP_DEVICEDESC),
1553                                          PropertyRegDataType,
1554                                          PropertyBuffer,
1555                                          &PropLength,
1556                                          0,
1557                                          hMachine);
1558     if ((cr == CR_SUCCESS) || (cr == CR_BUFFER_SMALL))
1559     {
1560         if (RequiredSize)
1561             *RequiredSize = PropLength;
1562     }
1563 
1564 done:
1565     if (cr != CR_SUCCESS)
1566     {
1567         switch (cr)
1568         {
1569                 case CR_INVALID_DEVINST :
1570                     Error = ERROR_NO_SUCH_DEVINST;
1571                     break;
1572 
1573                 case CR_INVALID_PROPERTY :
1574                     Error = ERROR_INVALID_REG_PROPERTY;
1575                     break;
1576 
1577                 case CR_BUFFER_SMALL :
1578                     Error = ERROR_INSUFFICIENT_BUFFER;
1579                     break;
1580 
1581                 default :
1582                     Error = GetErrorCodeFromCrCode(cr);
1583         }
1584     }
1585 
1586     if (hMachine != NULL)
1587         CM_Disconnect_Machine(hMachine);
1588 
1589     SetLastError(Error);
1590     return (cr == CR_SUCCESS);
1591 }
1592 
1593 /***********************************************************************
1594  *		SetupDiSetClassRegistryPropertyA(SETUPAPI.@)
1595  */
1596 BOOL WINAPI
SetupDiSetClassRegistryPropertyA(IN CONST GUID * ClassGuid,IN DWORD Property,IN CONST BYTE * PropertyBuffer OPTIONAL,IN DWORD PropertyBufferSize,IN PCSTR MachineName OPTIONAL,IN PVOID Reserved)1597 SetupDiSetClassRegistryPropertyA(
1598     IN CONST GUID *ClassGuid,
1599     IN DWORD Property,
1600     IN CONST BYTE *PropertyBuffer OPTIONAL,
1601     IN DWORD PropertyBufferSize,
1602     IN PCSTR MachineName OPTIONAL,
1603     IN PVOID Reserved)
1604 {
1605     HMACHINE hMachine = NULL;
1606     DWORD Error = ERROR_SUCCESS;
1607     CONFIGRET cr;
1608 
1609     TRACE("%s %lu %p %lu %s %p\n",
1610           debugstr_guid(ClassGuid), Property, PropertyBuffer,
1611           PropertyBufferSize, MachineName, Reserved);
1612 
1613     if (Reserved != NULL)
1614     {
1615         SetLastError(ERROR_INVALID_PARAMETER);
1616         return FALSE;
1617     }
1618 
1619     if (MachineName)
1620     {
1621         cr = CM_Connect_MachineA(MachineName, &hMachine);
1622         if (cr != CR_SUCCESS)
1623            goto done;
1624     }
1625 
1626     if (Property >= SPCRP_MAXIMUM_PROPERTY)
1627     {
1628         cr = CR_INVALID_PROPERTY;
1629         goto done;
1630     }
1631 
1632     cr = CM_Set_Class_Registry_PropertyA((LPGUID)ClassGuid,
1633                                          Property + (CM_DRP_DEVICEDESC - SPDRP_DEVICEDESC),
1634                                          PropertyBuffer,
1635                                          PropertyBufferSize,
1636                                          0,
1637                                          hMachine);
1638 
1639 done:
1640     if (cr != CR_SUCCESS)
1641     {
1642         switch (cr)
1643         {
1644                 case CR_INVALID_DEVINST:
1645                     Error = ERROR_NO_SUCH_DEVINST;
1646                     break;
1647 
1648                 case CR_INVALID_PROPERTY:
1649                     Error = ERROR_INVALID_REG_PROPERTY;
1650                     break;
1651 
1652                 case CR_BUFFER_SMALL:
1653                     Error = ERROR_INSUFFICIENT_BUFFER;
1654                     break;
1655 
1656                 default :
1657                     Error = GetErrorCodeFromCrCode(cr);
1658         }
1659     }
1660 
1661     if (hMachine != NULL)
1662         CM_Disconnect_Machine(hMachine);
1663 
1664     SetLastError(Error);
1665     return (cr == CR_SUCCESS);
1666 }
1667 
1668 /***********************************************************************
1669  *		SetupDiSetClassRegistryPropertyW(SETUPAPI.@)
1670  */
1671 BOOL WINAPI
SetupDiSetClassRegistryPropertyW(IN CONST GUID * ClassGuid,IN DWORD Property,IN CONST BYTE * PropertyBuffer OPTIONAL,IN DWORD PropertyBufferSize,IN PCWSTR MachineName OPTIONAL,IN PVOID Reserved)1672 SetupDiSetClassRegistryPropertyW(
1673     IN CONST GUID *ClassGuid,
1674     IN DWORD Property,
1675     IN CONST BYTE *PropertyBuffer OPTIONAL,
1676     IN DWORD PropertyBufferSize,
1677     IN PCWSTR MachineName OPTIONAL,
1678     IN PVOID Reserved)
1679 {
1680     HMACHINE hMachine = NULL;
1681     DWORD Error = ERROR_SUCCESS;
1682     CONFIGRET cr;
1683 
1684     TRACE("%s %lu %p %lu %s %p\n",
1685           debugstr_guid(ClassGuid), Property, PropertyBuffer,
1686           PropertyBufferSize, debugstr_w(MachineName), Reserved);
1687 
1688     if (Reserved != NULL)
1689     {
1690         SetLastError(ERROR_INVALID_PARAMETER);
1691         return FALSE;
1692     }
1693 
1694     if (MachineName)
1695     {
1696         cr = CM_Connect_MachineW(MachineName, &hMachine);
1697         if (cr != CR_SUCCESS)
1698            goto done;
1699     }
1700 
1701     if (Property >= SPCRP_MAXIMUM_PROPERTY)
1702     {
1703         cr = CR_INVALID_PROPERTY;
1704         goto done;
1705     }
1706 
1707     cr = CM_Set_Class_Registry_PropertyW((LPGUID)ClassGuid,
1708                                          Property + (CM_DRP_DEVICEDESC - SPDRP_DEVICEDESC),
1709                                          PropertyBuffer,
1710                                          PropertyBufferSize,
1711                                          0,
1712                                          hMachine);
1713 
1714 done:
1715     if (cr != CR_SUCCESS)
1716     {
1717         switch (cr)
1718         {
1719                 case CR_INVALID_DEVINST:
1720                     Error = ERROR_NO_SUCH_DEVINST;
1721                     break;
1722 
1723                 case CR_INVALID_PROPERTY:
1724                     Error = ERROR_INVALID_REG_PROPERTY;
1725                     break;
1726 
1727                 case CR_BUFFER_SMALL:
1728                     Error = ERROR_INSUFFICIENT_BUFFER;
1729                     break;
1730 
1731                 default :
1732                     Error = GetErrorCodeFromCrCode(cr);
1733         }
1734     }
1735 
1736     if (hMachine != NULL)
1737         CM_Disconnect_Machine(hMachine);
1738 
1739     SetLastError(Error);
1740     return (cr == CR_SUCCESS);
1741 }
1742