[SETUPAPI] SetupDiGetClassDevPropertySheetsW: Support class property sheet providers.
[reactos.git] / dll / win32 / setupapi / devclass.c
index cae8b66..cc7446f 100644 (file)
 
 #include <wingdi.h>
 #include <shellapi.h>
+#include <strsafe.h>
 
 /* Unicode constants */
 static const WCHAR BackSlash[] = {'\\',0};
-static const WCHAR Class[]  = {'C','l','a','s','s',0};
 static const WCHAR ClassGUID[]  = {'C','l','a','s','s','G','U','I','D',0};
 static const WCHAR ClassInstall32[]  = {'C','l','a','s','s','I','n','s','t','a','l','l','3','2',0};
 static const WCHAR DotServices[]  = {'.','S','e','r','v','i','c','e','s',0};
 static const WCHAR InterfaceInstall32[]  = {'I','n','t','e','r','f','a','c','e','I','n','s','t','a','l','l','3','2',0};
 static const WCHAR SetupapiDll[]  = {'s','e','t','u','p','a','p','i','.','d','l','l',0};
-static const WCHAR Version[]  = {'V','e','r','s','i','o','n',0};
 
 typedef BOOL
 (WINAPI* PROPERTY_PAGE_PROVIDER) (
@@ -101,10 +100,17 @@ SetupDiDestroyClassImageList(
         SetLastError(ERROR_INVALID_USER_BUFFER);
     else
     {
-        //DestroyIcon()
-        //ImageList_Destroy();
-        FIXME("Stub %p\n", ClassImageListData);
-        SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+        /* If Reserved wasn't NULL, then this is valid too */
+        if (ClassImageListData->ImageList)
+        {
+            ImageList_Destroy(ClassImageListData->ImageList);
+            ClassImageListData->ImageList = NULL;
+        }
+
+        MyFree(list);
+        ClassImageListData->Reserved = 0;
+
+        ret = TRUE;
     }
 
     TRACE("Returning %d\n", ret);
@@ -157,10 +163,16 @@ SETUP_CreateDevicesListFromEnumerator(
         rc = RegOpenKeyExW(hEnumeratorKey, KeyBuffer, 0, KEY_ENUMERATE_SUB_KEYS, &hDeviceIdKey);
         if (rc != ERROR_SUCCESS)
             goto cleanup;
-        strcpyW(InstancePath, Enumerator);
-        strcatW(InstancePath, BackSlash);
-        strcatW(InstancePath, KeyBuffer);
-        strcatW(InstancePath, BackSlash);
+
+        if (FAILED(StringCchCopyW(InstancePath, _countof(InstancePath), Enumerator)) ||
+            FAILED(StringCchCatW(InstancePath, _countof(InstancePath), BackSlash))  ||
+            FAILED(StringCchCatW(InstancePath, _countof(InstancePath), KeyBuffer))  ||
+            FAILED(StringCchCatW(InstancePath, _countof(InstancePath), BackSlash)))
+        {
+            rc = ERROR_GEN_FAILURE;
+            goto cleanup;
+        }
+
         pEndOfInstancePath = &InstancePath[strlenW(InstancePath)];
 
         /* Enumerate instance IDs (subkeys of hDeviceIdKey) */
@@ -399,8 +411,6 @@ SetupDiGetClassImageIndex(
         SetLastError(ERROR_INVALID_USER_BUFFER);
     else if (list->magic != SETUP_CLASS_IMAGE_LIST_MAGIC)
         SetLastError(ERROR_INVALID_USER_BUFFER);
-    else if (!ImageIndex)
-        SetLastError(ERROR_INVALID_PARAMETER);
     else
     {
         DWORD i;
@@ -552,6 +562,9 @@ cleanup:
     if (hKey != INVALID_HANDLE_VALUE)
         RegCloseKey(hKey);
 
+    if (Buffer && !ret)
+        MyFree(Buffer);
+
     return ret;
 }
 
@@ -697,14 +710,14 @@ SetupDiGetClassImageListExW(
         }
 
         /* Finally, add the overlay icons to the image list */
-        for (i = 0; i < 2; i++)
+        for (i = 0; i <= 2; i++)
         {
             hIcon = LoadImage(hInstance, MAKEINTRESOURCE(500 + i), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
             if (hIcon)
             {
                 idx = ImageList_AddIcon(ClassImageListData->ImageList, hIcon);
                 if (idx != -1)
-                    ImageList_SetOverlayImage(ClassImageListData->ImageList, idx, i);
+                    ImageList_SetOverlayImage(ClassImageListData->ImageList, idx, i + 1);
                 DestroyIcon(hIcon);
             }
         }
@@ -774,13 +787,9 @@ SetupDiLoadClassIcon(
     if (LargeIcon)
     {
         if(!SETUP_GetClassIconInfo(ClassGuid, &iconIndex, &DllName))
-            return FALSE;
+            goto cleanup;
 
-        if (DllName && ExtractIconExW(DllName, -iconIndex, &hIcon, NULL, 1) == 1 && hIcon != NULL)
-        {
-            ret = TRUE;
-        }
-        else
+        if (!DllName || ExtractIconExW(DllName, -iconIndex, &hIcon, NULL, 1) != 1 || hIcon == NULL)
         {
             /* load the default unknown device icon if ExtractIcon failed */
             if(DllName)
@@ -788,16 +797,17 @@ SetupDiLoadClassIcon(
 
             hIcon = LoadImage(hInstance, MAKEINTRESOURCE(iconIndex), IMAGE_ICON, 32, 32, LR_DEFAULTCOLOR);
 
-            if(!LargeIcon)
+            if(!hIcon)
                 goto cleanup;
         }
+
+        *LargeIcon = hIcon;
     }
 
     if (MiniIconIndex)
         *MiniIconIndex = iconIndex;
 
     ret = TRUE;
-    *LargeIcon = hIcon;
 
 cleanup:
 
@@ -860,6 +870,7 @@ SetupDiInstallClassExW(
         InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
         if (!SetupDiGetDeviceInstallParamsW(hDeviceInfo, NULL, &InstallParams))
             goto cleanup;
+
         InstallParams.Flags &= ~(DI_NOVCP | DI_NOBROWSE | DI_QUIETINSTALL);
         InstallParams.Flags |= Flags & (DI_NOVCP | DI_NOBROWSE | DI_QUIETINSTALL);
         if (Flags & DI_NOVCP)
@@ -939,9 +950,9 @@ SetupDiInstallClassExW(
             if (!ret)
                 goto cleanup;
 
-            /* Install .Services section */
+            /* OPTIONAL: Install .Services section */
             lstrcatW(SectionName, DotServices);
-            ret = SetupInstallServicesFromInfSectionExW(
+            SetupInstallServicesFromInfSectionExW(
                 hInf,
                 SectionName,
                 0,
@@ -949,9 +960,6 @@ SetupDiInstallClassExW(
                 NULL,
                 NULL,
                 NULL);
-            if (!ret)
-                goto cleanup;
-
             ret = TRUE;
         }
 
@@ -1172,9 +1180,12 @@ SetupDiGetClassDevPropertySheetsA(
         PropertySheetHeader, PropertySheetHeaderPageListSize,
         RequiredSize, PropertySheetType);
 
-    psh.dwFlags = PropertySheetHeader->dwFlags;
-    psh.phpage = PropertySheetHeader->phpage;
-    psh.nPages = PropertySheetHeader->nPages;
+    if(PropertySheetHeader)
+    {
+        psh.dwFlags = PropertySheetHeader->dwFlags;
+        psh.phpage = PropertySheetHeader->phpage;
+        psh.nPages = PropertySheetHeader->nPages;
+    }
 
     ret = SetupDiGetClassDevPropertySheetsW(DeviceInfoSet, DeviceInfoData, PropertySheetHeader ? &psh : NULL,
                                             PropertySheetHeaderPageListSize, RequiredSize,
@@ -1217,6 +1228,42 @@ SETUP_GetClassDevPropertySheetsCallback(
     return PropPageData->DontCancel;
 }
 
+static DWORD
+SETUP_GetValueString(
+    IN HKEY hKey,
+    IN LPWSTR lpValueName,
+    OUT LPWSTR *lpString)
+{
+    LPWSTR lpBuffer;
+    DWORD dwLength = 0;
+    DWORD dwRegType;
+    DWORD rc;
+
+    *lpString = NULL;
+
+    RegQueryValueExW(hKey, lpValueName, NULL, &dwRegType, NULL, &dwLength);
+
+    if (dwLength == 0 || dwRegType != REG_SZ)
+        return ERROR_FILE_NOT_FOUND;
+
+    lpBuffer = HeapAlloc(GetProcessHeap(), 0, dwLength + sizeof(WCHAR));
+    if (lpBuffer == NULL)
+        return ERROR_NOT_ENOUGH_MEMORY;
+
+    rc = RegQueryValueExW(hKey, lpValueName, NULL, NULL, (LPBYTE)lpBuffer, &dwLength);
+    if (rc != ERROR_SUCCESS)
+    {
+        HeapFree(GetProcessHeap(), 0, lpBuffer);
+        return rc;
+    }
+
+    lpBuffer[dwLength / sizeof(WCHAR)] = UNICODE_NULL;
+
+    *lpString = lpBuffer;
+
+    return ERROR_SUCCESS;
+}
+
 /***********************************************************************
  *             SetupDiGetClassDevPropertySheetsW(SETUPAPI.@)
  */
@@ -1229,7 +1276,8 @@ SetupDiGetClassDevPropertySheetsW(
     OUT PDWORD RequiredSize OPTIONAL,
     IN DWORD PropertySheetType)
 {
-    struct DeviceInfoSet *list;
+    struct DeviceInfoSet *devInfoSet = NULL;
+    struct DeviceInfo *devInfo = NULL;
     BOOL ret = FALSE;
 
     TRACE("%p %p %p 0%lx %p 0x%lx\n", DeviceInfoSet, DeviceInfoData,
@@ -1240,7 +1288,7 @@ SetupDiGetClassDevPropertySheetsW(
         SetLastError(ERROR_INVALID_HANDLE);
     else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
         SetLastError(ERROR_INVALID_HANDLE);
-    else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
+    else if ((devInfoSet = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
         SetLastError(ERROR_INVALID_HANDLE);
     else if (!PropertySheetHeader)
         SetLastError(ERROR_INVALID_PARAMETER);
@@ -1248,7 +1296,7 @@ SetupDiGetClassDevPropertySheetsW(
         SetLastError(ERROR_INVALID_FLAGS);
     else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
         SetLastError(ERROR_INVALID_USER_BUFFER);
-    else if (!DeviceInfoData && IsEqualIID(&list->ClassGuid, &GUID_NULL))
+    else if (!DeviceInfoData && IsEqualIID(&devInfoSet->ClassGuid, &GUID_NULL))
         SetLastError(ERROR_INVALID_PARAMETER);
     else if (PropertySheetType != DIGCDP_FLAG_ADVANCED
           && PropertySheetType != DIGCDP_FLAG_BASIC
@@ -1263,74 +1311,66 @@ SetupDiGetClassDevPropertySheetsW(
         HMODULE hModule = NULL;
         PROPERTY_PAGE_PROVIDER pPropPageProvider = NULL;
         struct ClassDevPropertySheetsData PropPageData;
-        DWORD dwLength, dwRegType;
         DWORD InitialNumberOfPages;
         DWORD rc;
 
         if (DeviceInfoData)
-            hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_QUERY_VALUE);
-        else
-        {
-            hKey = SetupDiOpenClassRegKeyExW(&list->ClassGuid, KEY_QUERY_VALUE,
-                DIOCR_INSTALLER, list->MachineName + 2, NULL);
-        }
-        if (hKey == INVALID_HANDLE_VALUE)
-            goto cleanup;
-
-        rc = RegQueryValueExW(hKey, REGSTR_VAL_ENUMPROPPAGES_32, NULL, &dwRegType, NULL, &dwLength);
-        if (rc == ERROR_FILE_NOT_FOUND)
-        {
-            /* No registry key. As it is optional, don't say it's a bad error */
-            if (RequiredSize)
-                *RequiredSize = 0;
-            ret = TRUE;
-            goto cleanup;
-        }
-        else if (rc != ERROR_SUCCESS && dwRegType != REG_SZ)
-        {
-            SetLastError(rc);
-            goto cleanup;
-        }
+            devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
 
-        PropPageProvider = HeapAlloc(GetProcessHeap(), 0, dwLength + sizeof(WCHAR));
-        if (!PropPageProvider)
-        {
-            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-            goto cleanup;
-        }
-        rc = RegQueryValueExW(hKey, REGSTR_VAL_ENUMPROPPAGES_32, NULL, NULL, (LPBYTE)PropPageProvider, &dwLength);
-        if (rc != ERROR_SUCCESS)
+        /* Get the class property page provider */
+        if (devInfoSet->hmodClassPropPageProvider == NULL)
         {
-            SetLastError(rc);
-            goto cleanup;
-        }
-        PropPageProvider[dwLength / sizeof(WCHAR)] = 0;
+            hKey = SetupDiOpenClassRegKeyExW(devInfo ? &devInfo->ClassGuid : &devInfoSet->ClassGuid, KEY_QUERY_VALUE,
+                    DIOCR_INSTALLER, NULL/*devInfoSet->MachineName + 2*/, NULL);
+            if (hKey != INVALID_HANDLE_VALUE)
+            {
+                rc = SETUP_GetValueString(hKey, REGSTR_VAL_ENUMPROPPAGES_32, &PropPageProvider);
+                if (rc == ERROR_SUCCESS)
+                {
+                    rc = GetFunctionPointer(PropPageProvider, &hModule, (PVOID*)&pPropPageProvider);
+                    if (rc != ERROR_SUCCESS)
+                    {
+                        SetLastError(ERROR_INVALID_PROPPAGE_PROVIDER);
+                        goto cleanup;
+                    }
 
-        rc = GetFunctionPointer(PropPageProvider, &hModule, (PVOID*)&pPropPageProvider);
-        if (rc != ERROR_SUCCESS)
-        {
-            SetLastError(ERROR_INVALID_PROPPAGE_PROVIDER);
-            goto cleanup;
-        }
+                    devInfoSet->hmodClassPropPageProvider = hModule;
+                    devInfoSet->pClassPropPageProvider = pPropPageProvider;
 
-        if (DeviceInfoData)
-        {
-            struct DeviceInfo *devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
+                    HeapFree(GetProcessHeap(), 0, PropPageProvider);
+                    PropPageProvider = NULL;
+                }
 
-            if (devInfo->hmodDevicePropPageProvider == NULL)
-            {
-                devInfo->hmodDevicePropPageProvider = hModule;
-                devInfo->pDevicePropPageProvider = pPropPageProvider;
+                RegCloseKey(hKey);
+                hKey = INVALID_HANDLE_VALUE;
             }
         }
-        else
-        {
-            struct DeviceInfoSet *devInfoSet = (struct DeviceInfoSet *)DeviceInfoSet;
 
-            if (devInfoSet->hmodClassPropPageProvider == NULL)
+        /* Get the device property page provider */
+        if (devInfo != NULL && devInfo->hmodDevicePropPageProvider == NULL)
+        {
+            hKey = SETUPDI_OpenDrvKey(devInfoSet->HKLM, devInfo, KEY_QUERY_VALUE);
+            if (hKey != INVALID_HANDLE_VALUE)
             {
-                devInfoSet->hmodClassPropPageProvider = hModule;
-                devInfoSet->pClassPropPageProvider = pPropPageProvider;
+                rc = SETUP_GetValueString(hKey, REGSTR_VAL_ENUMPROPPAGES_32, &PropPageProvider);
+                if (rc == ERROR_SUCCESS)
+                {
+                    rc = GetFunctionPointer(PropPageProvider, &hModule, (PVOID*)&pPropPageProvider);
+                    if (rc != ERROR_SUCCESS)
+                    {
+                        SetLastError(ERROR_INVALID_PROPPAGE_PROVIDER);
+                        goto cleanup;
+                    }
+
+                    devInfo->hmodDevicePropPageProvider = hModule;
+                    devInfo->pDevicePropPageProvider = pPropPageProvider;
+
+                    HeapFree(GetProcessHeap(), 0, PropPageProvider);
+                    PropPageProvider = NULL;
+                }
+
+                RegCloseKey(hKey);
+                hKey = INVALID_HANDLE_VALUE;
             }
         }
 
@@ -1346,7 +1386,13 @@ SetupDiGetClassDevPropertySheetsW(
         PropPageData.NumberOfPages = 0;
         PropPageData.DontCancel = (RequiredSize != NULL) ? TRUE : FALSE;
 
-        pPropPageProvider(&Request, SETUP_GetClassDevPropertySheetsCallback, (LPARAM)&PropPageData);
+        /* Call the class property page provider */
+        if (devInfoSet->pClassPropPageProvider != NULL)
+            ((PROPERTY_PAGE_PROVIDER)devInfoSet->pClassPropPageProvider)(&Request, SETUP_GetClassDevPropertySheetsCallback, (LPARAM)&PropPageData);
+
+        /* Call the device property page provider */
+        if (devInfo != NULL && devInfo->pDevicePropPageProvider != NULL)
+            ((PROPERTY_PAGE_PROVIDER)devInfo->pDevicePropPageProvider)(&Request, SETUP_GetClassDevPropertySheetsCallback, (LPARAM)&PropPageData);
 
         if (RequiredSize)
             *RequiredSize = PropPageData.NumberOfPages;
@@ -1363,7 +1409,9 @@ SetupDiGetClassDevPropertySheetsW(
 cleanup:
         if (hKey != INVALID_HANDLE_VALUE)
             RegCloseKey(hKey);
-        HeapFree(GetProcessHeap(), 0, PropPageProvider);
+
+        if (PropPageProvider != NULL)
+            HeapFree(GetProcessHeap(), 0, PropPageProvider);
     }
 
     TRACE("Returning %d\n", ret);