implemented SetupDiSetSelectedDriverA
[reactos.git] / reactos / lib / setupapi / devinst.c
index 9f0c4f8..880a5ad 100644 (file)
@@ -121,7 +121,7 @@ struct DeviceInterface /* Element of DeviceInfoElement.InterfaceListHead */
 struct InfFileDetails
 {
     HINF hInf;
-    ULONG References;
+    LONG References;
 };
 
 struct DriverInfoElement /* Element of DeviceInfoSet.DriverListHead and DeviceInfoElement.DriverListHead */
@@ -2383,7 +2383,10 @@ BOOL WINAPI SetupDiGetDeviceRegistryPropertyW(
                     *RequiredSize = BufferSize;
                 switch(rc) {
                     case ERROR_SUCCESS:
-                        ret = TRUE;
+                        if (PropertyBuffer != NULL || BufferSize == 0)
+                            ret = TRUE;
+                        else
+                            SetLastError(ERROR_INSUFFICIENT_BUFFER);
                         break;
                     case ERROR_MORE_DATA:
                         SetLastError(ERROR_INSUFFICIENT_BUFFER);
@@ -2997,14 +3000,6 @@ GetFunctionPointer(
         goto cleanup;
     }
 
-    /* W->A conversion for function name */
-    FunctionNameA = UnicodeToMultiByte(Comma + 1, CP_ACP);
-    if (!FunctionNameA)
-    {
-        rc = GetLastError();
-        goto cleanup;
-    }
-
     /* Load library */
     *Comma = '\0';
     hModule = LoadLibraryW(InstallerName);
@@ -3015,6 +3010,18 @@ GetFunctionPointer(
         goto cleanup;
     }
 
+    /* Skip comma spaces */
+    while (*Comma == ',' || isspaceW(*Comma))
+        Comma++;
+
+    /* W->A conversion for function name */
+    FunctionNameA = UnicodeToMultiByte(Comma, CP_ACP);
+    if (!FunctionNameA)
+    {
+        rc = GetLastError();
+        goto cleanup;
+    }
+
     /* Search function */
     *FunctionPointer = GetProcAddress(hModule, FunctionNameA);
     if (!*FunctionPointer)
@@ -3141,7 +3148,39 @@ BOOL WINAPI SetupDiCallClassInstaller(
 
             if (CanHandle & DEVICE_COINSTALLER)
             {
-                FIXME("Doesn't use Device co-installers at the moment\n");
+                hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_QUERY_VALUE);
+                if (hKey != INVALID_HANDLE_VALUE)
+                {
+                    rc = RegQueryValueExW(hKey, L"CoInstallers32", NULL, &dwRegType, NULL, &dwLength);
+                    if (rc == ERROR_SUCCESS && dwRegType == REG_MULTI_SZ)
+                    {
+                        LPWSTR KeyBuffer = HeapAlloc(GetProcessHeap(), 0, dwLength);
+                        if (KeyBuffer != NULL)
+                        {
+                            rc = RegQueryValueExW(hKey, L"CoInstallers32", NULL, NULL, (LPBYTE)KeyBuffer, &dwLength);
+                            if (rc == ERROR_SUCCESS)
+                            {
+                                LPWSTR ptr;
+                                for (ptr = KeyBuffer; *ptr; ptr += strlenW(ptr) + 1)
+                                {
+                                    /* Add coinstaller to DeviceCoInstallersListHead list */
+                                    struct CoInstallerElement *coinstaller;
+                                    TRACE("Got device coinstaller '%s'\n", debugstr_w(ptr));
+                                    coinstaller = HeapAlloc(GetProcessHeap(), 0, sizeof(struct CoInstallerElement));
+                                    if (!coinstaller)
+                                        continue;
+                                    memset(coinstaller, 0, sizeof(struct CoInstallerElement));
+                                    if (GetFunctionPointer(ptr, &coinstaller->Module, (PVOID*)&coinstaller->Function) == ERROR_SUCCESS)
+                                        InsertTailList(&DeviceCoInstallersListHead, &coinstaller->ListEntry);
+                                    else
+                                        HeapFree(GetProcessHeap(), 0, coinstaller);
+                                }
+                            }
+                            HeapFree(GetProcessHeap(), 0, KeyBuffer);
+                        }
+                    }
+                    RegCloseKey(hKey);
+                }
             }
             if (CanHandle & CLASS_COINSTALLER)
             {
@@ -3157,7 +3196,7 @@ BOOL WINAPI SetupDiCallClassInstaller(
                     if (UuidToStringW((UUID*)&DeviceInfoData->ClassGuid, &lpGuidString) == RPC_S_OK)
                     {
                         rc = RegQueryValueExW(hKey, lpGuidString, NULL, &dwRegType, NULL, &dwLength);
-                        if (rc == ERROR_SUCCESS && dwRegType == REG_SZ)
+                        if (rc == ERROR_SUCCESS && dwRegType == REG_MULTI_SZ)
                         {
                             LPWSTR KeyBuffer = HeapAlloc(GetProcessHeap(), 0, dwLength);
                             if (KeyBuffer != NULL)
@@ -3165,11 +3204,20 @@ BOOL WINAPI SetupDiCallClassInstaller(
                                 rc = RegQueryValueExW(hKey, lpGuidString, NULL, NULL, (LPBYTE)KeyBuffer, &dwLength);
                                 if (rc == ERROR_SUCCESS)
                                 {
-                                    LPCWSTR ptr;
+                                    LPWSTR ptr;
                                     for (ptr = KeyBuffer; *ptr; ptr += strlenW(ptr) + 1)
                                     {
                                         /* Add coinstaller to ClassCoInstallersListHead list */
-                                        FIXME("Class coinstaller is '%S'. UNIMPLEMENTED!\n", ptr);
+                                        struct CoInstallerElement *coinstaller;
+                                        TRACE("Got class coinstaller '%s'\n", debugstr_w(ptr));
+                                        coinstaller = HeapAlloc(GetProcessHeap(), 0, sizeof(struct CoInstallerElement));
+                                        if (!coinstaller)
+                                            continue;
+                                        memset(coinstaller, 0, sizeof(struct CoInstallerElement));
+                                        if (GetFunctionPointer(ptr, &coinstaller->Module, (PVOID*)&coinstaller->Function) == ERROR_SUCCESS)
+                                            InsertTailList(&ClassCoInstallersListHead, &coinstaller->ListEntry);
+                                        else
+                                            HeapFree(GetProcessHeap(), 0, coinstaller);
                                     }
                                 }
                                 HeapFree(GetProcessHeap(), 0, KeyBuffer);
@@ -3195,6 +3243,7 @@ BOOL WINAPI SetupDiCallClassInstaller(
                             if (rc == ERROR_SUCCESS)
                             {
                                 /* Get ClassInstaller function pointer */
+                                TRACE("Got class installer '%s'\n", debugstr_w(KeyBuffer));
                                 if (GetFunctionPointer(KeyBuffer, &ClassInstallerLibrary, (PVOID*)&ClassInstaller) != ERROR_SUCCESS)
                                 {
                                     InstallParams.FlagsEx |= DI_FLAGSEX_CI_FAILED;
@@ -4265,6 +4314,14 @@ SetupDiBuildDriverInfoList(
                 Buffer, RequiredSize,
                 &RequiredSize);
         }
+        if (!Result && GetLastError() == ERROR_FILE_NOT_FOUND)
+        {
+            /* No .inf file in specified directory. So, we should
+             * success as we created an empty driver info list.
+             */
+            ret = TRUE;
+            goto done;
+        }
         if (Result)
         {
             LPCWSTR filename;
@@ -4555,18 +4612,6 @@ SetupDiDestroyDriverInfoList(
         if (!DeviceInfoData)
             /* Fall back to destroying class driver list */
             DriverType = SPDIT_CLASSDRIVER;
-        if (DriverType == SPDIT_CLASSDRIVER)
-        {
-            if (!(InstallParams.Flags & DI_DIDCLASS))
-                /* The list was not created */
-                goto done;
-        }
-        else if (DriverType == SPDIT_COMPATDRIVER)
-        {
-            if (!(InstallParams.Flags & DI_DIDCOMPAT))
-                /* The list was not created */
-                goto done;
-        }
 
         if (DriverType == SPDIT_CLASSDRIVER)
         {
@@ -4929,6 +4974,70 @@ SetupDiGetSelectedDriverW(
     return ret;
 }
 
+
+/***********************************************************************
+ *             SetupDiSetSelectedDriverA (SETUPAPI.@)
+ */
+BOOL WINAPI
+SetupDiSetSelectedDriverA(
+    IN HDEVINFO DeviceInfoSet,
+    IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
+    IN OUT PSP_DRVINFO_DATA_A DriverInfoData OPTIONAL)
+{
+    SP_DRVINFO_DATA_V1_W DriverInfoDataW;
+    PSP_DRVINFO_DATA_W pDriverInfoDataW = NULL;
+    BOOL ret = FALSE;
+
+    if (DriverInfoData != NULL)
+    {
+        if (DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V2_A) &&
+            DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V1_A));
+        {
+            SetLastError(ERROR_INVALID_PARAMETER);
+            return FALSE;
+        }
+
+        DriverInfoDataW.cbSize = sizeof(SP_DRVINFO_DATA_V1_W);
+        DriverInfoDataW.Reserved = DriverInfoData->Reserved;
+
+        if (DriverInfoDataW.Reserved == 0)
+        {
+            DriverInfoDataW.DriverType = DriverInfoData->DriverType;
+
+            /* convert the strings to unicode */
+            if (!MultiByteToWideChar(CP_ACP,
+                                     0,
+                                     DriverInfoData->Description,
+                                     LINE_LEN,
+                                     DriverInfoDataW.Description,
+                                     LINE_LEN) ||
+                !MultiByteToWideChar(CP_ACP,
+                                     0,
+                                     DriverInfoData->ProviderName,
+                                     LINE_LEN,
+                                     DriverInfoDataW.ProviderName,
+                                     LINE_LEN))
+            {
+                return FALSE;
+            }
+        }
+
+        pDriverInfoDataW = (PSP_DRVINFO_DATA_W)&DriverInfoDataW;
+    }
+
+    ret = SetupDiSetSelectedDriverW(DeviceInfoSet,
+                                    DeviceInfoData,
+                                    pDriverInfoDataW);
+
+    if (ret && pDriverInfoDataW != NULL)
+    {
+        DriverInfoData->Reserved = DriverInfoDataW.Reserved;
+    }
+
+    return ret;
+}
+
+
 /***********************************************************************
  *             SetupDiSetSelectedDriverW (SETUPAPI.@)
  */
@@ -5337,13 +5446,13 @@ SetupDiInstallDriverFiles(
         InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
         ret = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
         if (!ret)
-            goto cleanup;
+            goto done;
 
         SelectedDriver = (struct DriverInfoElement *)InstallParams.Reserved;
         if (!SelectedDriver)
         {
             SetLastError(ERROR_NO_DRIVER_SELECTED);
-            goto cleanup;
+            goto done;
         }
 
         ret = SetupDiGetActualSectionToInstallW(
@@ -5351,34 +5460,22 @@ SetupDiInstallDriverFiles(
             SelectedDriver->Details.SectionName,
             SectionName, MAX_PATH, &SectionNameLength, NULL);
         if (!ret)
-            goto cleanup;
+            goto done;
 
-        if (InstallParams.InstallMsgHandler)
-        {
-            ret = SetupInstallFromInfSectionW(InstallParams.hwndParent,
-                SelectedDriver->InfFileDetails->hInf, SectionName,
-                SPINST_FILES, NULL, NULL, SP_COPY_NEWER,
-                InstallParams.InstallMsgHandler, InstallParams.InstallMsgHandlerContext,
-                DeviceInfoSet, DeviceInfoData);
-        }
-        else
-        {
-            PVOID callback_context = SetupInitDefaultQueueCallback(InstallParams.hwndParent);
-            ret = SetupInstallFromInfSectionW(InstallParams.hwndParent,
-                SelectedDriver->InfFileDetails->hInf, SectionName,
-                SPINST_FILES, NULL, NULL, SP_COPY_NEWER,
-                SetupDefaultQueueCallbackW, callback_context,
-                DeviceInfoSet, DeviceInfoData);
-                SetupTermDefaultQueueCallback(callback_context);
-        }
-cleanup:
-        if (ret)
+        if (!InstallParams.InstallMsgHandler)
         {
-            InstallParams.Flags |= DI_NOFILECOPY;
-            ret = SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
+            InstallParams.InstallMsgHandler = SetupDefaultQueueCallbackW;
+            InstallParams.InstallMsgHandlerContext = SetupInitDefaultQueueCallback(InstallParams.hwndParent);
+            SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
         }
+        ret = SetupInstallFromInfSectionW(InstallParams.hwndParent,
+            SelectedDriver->InfFileDetails->hInf, SectionName,
+            SPINST_FILES, NULL, NULL, SP_COPY_NEWER,
+            InstallParams.InstallMsgHandler, InstallParams.InstallMsgHandlerContext,
+            DeviceInfoSet, DeviceInfoData);
     }
 
+done:
     TRACE("Returning %d\n", ret);
     return ret;
 }
@@ -5391,12 +5488,91 @@ SetupDiRegisterCoDeviceInstallers(
     IN HDEVINFO DeviceInfoSet,
     IN PSP_DEVINFO_DATA DeviceInfoData)
 {
+    BOOL ret = FALSE; /* Return value */
+
     TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
 
-    FIXME("SetupDiRegisterCoDeviceInstallers not implemented. Doing nothing\n");
-    //SetLastError(ERROR_GEN_FAILURE);
-    //return FALSE;
-    return TRUE;
+    if (!DeviceInfoSet)
+        SetLastError(ERROR_INVALID_PARAMETER);
+    else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
+        SetLastError(ERROR_INVALID_HANDLE);
+    else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
+        SetLastError(ERROR_INVALID_HANDLE);
+    else if (!DeviceInfoData)
+        SetLastError(ERROR_INVALID_PARAMETER);
+    else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
+        SetLastError(ERROR_INVALID_USER_BUFFER);
+    else
+    {
+        SP_DEVINSTALL_PARAMS_W InstallParams;
+        struct DriverInfoElement *SelectedDriver;
+        BOOL Result;
+        DWORD DoAction;
+        WCHAR SectionName[MAX_PATH];
+        DWORD SectionNameLength = 0;
+        HKEY hKey = INVALID_HANDLE_VALUE;;
+
+        InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
+        Result = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
+        if (!Result)
+            goto cleanup;
+
+        SelectedDriver = (struct DriverInfoElement *)InstallParams.Reserved;
+        if (SelectedDriver == NULL)
+        {
+            SetLastError(ERROR_NO_DRIVER_SELECTED);
+            goto cleanup;
+        }
+
+        /* Get .CoInstallers section name */
+        Result = SetupDiGetActualSectionToInstallW(
+            SelectedDriver->InfFileDetails->hInf,
+            SelectedDriver->Details.SectionName,
+            SectionName, MAX_PATH, &SectionNameLength, NULL);
+        if (!Result || SectionNameLength > MAX_PATH - wcslen(L".CoInstallers") - 1)
+            goto cleanup;
+        wcscat(SectionName, L".CoInstallers");
+
+        /* Open/Create driver key information */
+#if _WIN32_WINNT >= 0x502
+        hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_READ | KEY_WRITE);
+#else
+        hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_ALL_ACCESS);
+#endif
+        if (hKey == INVALID_HANDLE_VALUE && GetLastError() == ERROR_FILE_NOT_FOUND)
+            hKey = SetupDiCreateDevRegKeyW(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, NULL, NULL);
+        if (hKey == INVALID_HANDLE_VALUE)
+            goto cleanup;
+
+        /* Install .CoInstallers section */
+        DoAction = SPINST_REGISTRY;
+        if (!(InstallParams.Flags & DI_NOFILECOPY))
+        {
+            DoAction |= SPINST_FILES;
+            if (!InstallParams.InstallMsgHandler)
+            {
+                InstallParams.InstallMsgHandler = SetupDefaultQueueCallbackW;
+                InstallParams.InstallMsgHandlerContext = SetupInitDefaultQueueCallback(InstallParams.hwndParent);
+                SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
+            }
+        }
+        Result = SetupInstallFromInfSectionW(InstallParams.hwndParent,
+            SelectedDriver->InfFileDetails->hInf, SectionName,
+            DoAction, hKey, NULL, SP_COPY_NEWER,
+            InstallParams.InstallMsgHandler, InstallParams.InstallMsgHandlerContext,
+            DeviceInfoSet, DeviceInfoData);
+        if (!Result)
+            goto cleanup;
+
+        ret = TRUE;
+
+cleanup:
+        if (hKey != INVALID_HANDLE_VALUE)
+            RegCloseKey(hKey);
+    }
+
+    TRACE("Returning %d\n", ret);
+    return ret;
 }
 
 /***********************************************************************
@@ -5525,9 +5701,15 @@ SetupDiInstallDevice(
     /* Install main section */
     DoAction = SPINST_REGISTRY;
     if (!(InstallParams.Flags & DI_NOFILECOPY))
+    {
         DoAction |= SPINST_FILES;
-    /* Files have already been copied in SetupDiInstallDriverFiles.
-     * Process only registry entries. */
+        if (!InstallParams.InstallMsgHandler)
+        {
+            InstallParams.InstallMsgHandler = SetupDefaultQueueCallbackW;
+            InstallParams.InstallMsgHandlerContext = SetupInitDefaultQueueCallback(InstallParams.hwndParent);
+            SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
+        }
+    }
     *pSectionName = '\0';
     Result = SetupInstallFromInfSectionW(InstallParams.hwndParent,
         SelectedDriver->InfFileDetails->hInf, SectionName,
@@ -5538,10 +5720,11 @@ SetupDiInstallDevice(
         goto cleanup;
     if (!(InstallParams.Flags & DI_NOFILECOPY) && !(InstallParams.Flags & DI_NOVCP))
     {
-        Result = SetupCommitFileQueueW(InstallParams.hwndParent,
-            InstallParams.FileQueue,
-            InstallParams.InstallMsgHandler,
-            InstallParams.InstallMsgHandlerContext);
+        if (Result && InstallParams.InstallMsgHandler == SetupDefaultQueueCallbackW)
+        {
+            /* Delete resources allocated by SetupInitDefaultQueueCallback */
+            SetupTermDefaultQueueCallback(InstallParams.InstallMsgHandlerContext);
+        }
     }
     InstallParams.Flags |= DI_NOFILECOPY;
     SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);