Avoid stop service race window during uninstall (#40625)

Disable service before stopping service during uninstall.

Feng Wang committed Jun 1, 2026 at 10:14 UTC c28bd152e9be65003bf602db2756c168add7114b
3 files changed +57 -1
msipackage/package.wix.in
+10
@@ -620,6 +620,11 @@
620 <CustomAction Id="InstallMsix.SetProperty" Return="check" Property="InstallMsix" Value='[DATABASE]' Execute='immediate' />
621 <CustomAction Id="CalculateWslSettingsProtocolIds" Impersonate="no" BinaryRef="wslinstall.dll" DllEntry="CalculateWslSettingsProtocolIds" Return="check" Execute='immediate' />
622
623 + <!-- Disable WSLService before StopServices so SCM rejects activation attempts
624 + from COM clients while it is being stopped on uninstall. -->
625 + <CustomAction Id="DisableWslService" Impersonate="no" BinaryRef="wslinstall.dll" DllEntry="DisableWslService" Return="ignore" Execute="deferred" />
626 + <CustomAction Id="EnableWslService" Impersonate="no" BinaryRef="wslinstall.dll" DllEntry="EnableWslService" Return="ignore" Execute="rollback" />
627 +
628 <!-- See https://learn.microsoft.com/en-us/windows/win32/msi/examples-of-conditional-statement-syntax -->
629 <InstallExecuteSequence>
630 <Custom Action="ValidateInstall" After="InstallInitialize" Condition="(not INSTALLED) and (not SKIPVALIDATION = 1)" />
@@ -675,6 +680,11 @@
680
681 <Custom Action="FinalizeInstall" After="PublishFeatures"/>
682
683 + <!-- Rollback CA must be sequenced before the forward action so it is registered
684 + in the rollback script first. -->
685 + <Custom Action="EnableWslService" Before="DisableWslService" Condition='REMOVE~="ALL"' />
686 + <Custom Action="DisableWslService" Before="StopServices" Condition='REMOVE~="ALL"' />
687 +
688 </InstallExecuteSequence>
689
690 <!-- Don't show a 'Modify' button in settings since there is nothing to modify -->
src/windows/wslinstall/DllMain.cpp
+44
@@ -940,6 +940,50 @@ extern "C" UINT __stdcall CalculateWslSettingsProtocolIds(MSIHANDLE install)
940 return NOERROR;
941 }
942
943 +static void SetWslServiceStartType(DWORD StartType)
944 +{
945 + const wil::unique_schandle manager{OpenSCManagerW(nullptr, nullptr, SC_MANAGER_CONNECT)};
946 + THROW_LAST_ERROR_IF(!manager);
947 +
948 + const wil::unique_schandle service{OpenServiceW(manager.get(), L"WSLService", SERVICE_CHANGE_CONFIG)};
949 + if (!service)
950 + {
951 + const auto error = GetLastError();
952 + if (error == ERROR_SERVICE_DOES_NOT_EXIST)
953 + {
954 + return;
955 + }
956 + THROW_WIN32(error);
957 + }
958 +
959 + THROW_IF_WIN32_BOOL_FALSE(ChangeServiceConfigW(
960 + service.get(), SERVICE_NO_CHANGE, StartType, SERVICE_NO_CHANGE, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr));
961 +}
962 +
963 +extern "C" UINT __stdcall DisableWslService(MSIHANDLE install)
964 +{
965 + try
966 + {
967 + WSL_INSTALL_LOG("DisableWslService");
968 + SetWslServiceStartType(SERVICE_DISABLED);
969 + }
970 + CATCH_LOG();
971 +
972 + return NOERROR;
973 +}
974 +
975 +extern "C" UINT __stdcall EnableWslService(MSIHANDLE install)
976 +{
977 + try
978 + {
979 + WSL_INSTALL_LOG("EnableWslService");
980 + SetWslServiceStartType(SERVICE_AUTO_START);
981 + }
982 + CATCH_LOG();
983 +
984 + return NOERROR;
985 +}
986 +
987 EXTERN_C BOOL STDAPICALLTYPE DllMain(_In_ HINSTANCE Instance, _In_ DWORD Reason, _In_opt_ LPVOID Reserved)
988 {
989 wil::DLLMain(Instance, Reason, Reserved);
src/windows/wslinstall/wslinstall.def
+3 -1
@@ -13,4 +13,6 @@ EXPORTS
13 RemoveMsixAsUser
14 RemoveRegistryKeyProtections
15 UnregisterLspCategories
16 - CalculateWslSettingsProtocolIds
\ No newline at end of file
16 + CalculateWslSettingsProtocolIds
17 + DisableWslService
18 + EnableWslService
\ No newline at end of file