Poll for the result of operations during MSI installation (#41415)

* Poll for the result of operations during MSI installation * Cleanup

Blue committed Aug 21, 2026 at 23:47 UTC 780845097a33b8937d7f831870e8fc228b1feb19
1 file changed +33 -8
src/windows/wslinstall/DllMain.cpp
+33 -8
@@ -75,18 +75,42 @@ void TrustPackageCertificate(LPCWSTR Path)
75 }
76 #endif
77
78 -void ThrowIfOperationError(
79 - const winrt::Windows::Foundation::IAsyncOperationWithProgress<winrt::Windows::Management::Deployment::DeploymentResult, winrt::Windows::Management::Deployment::DeploymentProgress>& result,
78 +winrt::Windows::Management::Deployment::DeploymentResult WaitForDeploymentOperation(
79 + const winrt::Windows::Foundation::IAsyncOperationWithProgress<winrt::Windows::Management::Deployment::DeploymentResult, winrt::Windows::Management::Deployment::DeploymentProgress>& operation,
80 const std::source_location& source = std::source_location::current())
81 {
82 - const auto status = result.get();
82 + // IAsyncOperation::get() installs a completion delegate whose implementation resides in this DLL. The operation can retain
83 + // that delegate after get() returns, allowing its final Release() to call into the DLL after MSI unloads it.
84 + // To avoid this, poll until the operation is completed.
85 + auto cleanup = wil::scope_exit_log(WI_DIAGNOSTICS_INFO, [&]() { operation.Close(); });
86 +
87 + auto status = operation.Status();
88 + while (status == winrt::Windows::Foundation::AsyncStatus::Started)
89 + {
90 + Sleep(10);
91 + status = operation.Status();
92 + }
93 +
94 + if (status == winrt::Windows::Foundation::AsyncStatus::Error)
95 + {
96 + const auto error = operation.ErrorCode();
97 + THROW_HR_MSG(error, "Source: %hs() - %hs:%lu", source.function_name(), source.file_name(), source.line());
98 + }
99
84 - if (result.Status() == winrt::Windows::Foundation::AsyncStatus::Error)
100 + if (status == winrt::Windows::Foundation::AsyncStatus::Canceled)
101 {
86 - THROW_HR_MSG(result.ErrorCode(), "Source: %hs() - %hs:%lu", source.function_name(), source.file_name(), source.line());
102 + throw winrt::hresult_canceled();
103 }
104
89 - THROW_IF_FAILED_MSG(status.ExtendedErrorCode(), "%ls", status.ErrorText().c_str());
105 + return operation.GetResults();
106 +}
107 +
108 +void ThrowIfOperationError(
109 + const winrt::Windows::Foundation::IAsyncOperationWithProgress<winrt::Windows::Management::Deployment::DeploymentResult, winrt::Windows::Management::Deployment::DeploymentProgress>& operation,
110 + const std::source_location& source = std::source_location::current())
111 +{
112 + const auto result = WaitForDeploymentOperation(operation, source);
113 + THROW_IF_FAILED_MSG(result.ExtendedErrorCode(), "%ls", result.ErrorText().c_str());
114 }
115
116 std::wstring GetMsiProperty(MSIHANDLE install, LPCWSTR name)
@@ -530,7 +554,8 @@ try
554 WSL_INSTALL_LOG("DeprovisionMsix");
555
556 const winrt::Windows::Management::Deployment::PackageManager packageManager;
533 - const auto result = packageManager.DeprovisionPackageForAllUsersAsync(wsl::windows::common::wslutil::c_msixPackageFamilyName).get();
557 + const auto result = WaitForDeploymentOperation(
558 + packageManager.DeprovisionPackageForAllUsersAsync(wsl::windows::common::wslutil::c_msixPackageFamilyName));
559 LOG_IF_FAILED_MSG(result.ExtendedErrorCode(), "%ls", result.ErrorText().c_str());
560
561 return NOERROR;
@@ -1013,4 +1038,4 @@ EXTERN_C BOOL STDAPICALLTYPE DllMain(_In_ HINSTANCE Instance, _In_ DWORD Reason,
1038 }
1039
1040 return TRUE;
1016 -}
\ No newline at end of file
1041 +}