From bd616d538238626c1c9a62a8207cd4c74c881a6b Mon Sep 17 00:00:00 2001 From: lx-s Date: Tue, 18 Aug 2026 08:06:53 +0200 Subject: [PATCH] Retry WTSRegisterSessionNotification for about half a minute.. Disable lock-on-mute if it fails completely. --- Translations/lang-de.json | 2 + Translations/lang-en.json | 2 + WinMute/WinMute.cpp | 95 ++++++++++++++++++++++++++++++++++++--- WinMute/WinMute.h | 7 +++ 4 files changed, 100 insertions(+), 6 deletions(-) diff --git a/Translations/lang-de.json b/Translations/lang-de.json index b6bbc6a..b57257d 100644 --- a/Translations/lang-de.json +++ b/Translations/lang-de.json @@ -16,6 +16,8 @@ "general.error.audio-service-shutdown.text": "WinMute kann diese Situation nicht Beheben. Bitte starten Sie das Programm neu.", "popup.remote-session-detected.title": "Remote Session festgestellt", "popup.remote-session-detected.text": "Alle Audiogeräte wurden stumm geschaltet", + "popup.session-notification-failed.title": "Stummschalten bei Arbeitsplatz-Sperre deaktiviert", + "popup.session-notification-failed.text": "WinMute konnte sich nicht für Sperr-Benachrichtigungen registrieren.\nBitte prüfen Sie das Protokoll für weitere Details.", "popup.bluetooth-muting-disabled.title": "Bluetooth-Stummschalten deaktiviert", "popup.bluetooth-muting-disabled.text": "Bluetooth ist nicht verfügbar oder deaktiviert.\nDas Bluetooth-abhängige Stummschalten wurde deaktiviert.", "popup.wlan-muting-disabled.title": "WLAN-Stummschalten deaktiviert", diff --git a/Translations/lang-en.json b/Translations/lang-en.json index 1883aba..4299fc0 100644 --- a/Translations/lang-en.json +++ b/Translations/lang-en.json @@ -22,6 +22,8 @@ "pupup.error.update-check-failed.text": "Unable to check for a new version.\nPlease check/enable logging for further details.", "popup.remote-session-detected.title": "Remote Session detected", "popup.remote-session-detected.text": "All audio devices have been muted", + "popup.session-notification-failed.title": "Muting on workstation lock disabled", + "popup.session-notification-failed.text": "WinMute could not register for session notifications.\nPlease check the log for further details.", "popup.bluetooth-muting-disabled.title": "Bluetooth muting disabled", "popup.bluetooth-muting-disabled.text": "Bluetooth is not available or disabled.\nBluetooth muting will be disabled on this computer.", "popup.wlan-muting-disabled.title": "WLAN muting disabled", diff --git a/WinMute/WinMute.cpp b/WinMute/WinMute.cpp index 494f10a..b2b190e 100644 --- a/WinMute/WinMute.cpp +++ b/WinMute/WinMute.cpp @@ -46,6 +46,14 @@ static const wchar_t* TERMINAL_SERVER_KEY = L"SYSTEM\\CurrentControlSet\\Control\\Terminal Server\\"; static const wchar_t* GLASS_SESSION_ID = L"GlassSessionId"; +static constexpr UINT_PTR WTS_RETRY_TIMER_ID = 190503; +// When WinMute is started from autostart, the services Remote Desktop +// Services depends on can still be coming up, which makes +// WTSRegisterSessionNotification fail with RPC_S_INVALID_BINDING. Retry for +// roughly half a minute before giving up. +static constexpr UINT WTS_RETRY_INTERVAL_MS = 1000; +static constexpr int WTS_RETRY_MAX_ATTEMPTS = 30; + static LRESULT CALLBACK WinMuteWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { @@ -64,6 +72,15 @@ static LRESULT CALLBACK WinMuteWndProc(HWND hWnd, UINT msg, WPARAM wParam, : DefWindowProcW(hWnd, msg, wParam, lParam); } +static void CALLBACK WtsRetryTimerProc(HWND hWnd, UINT, UINT_PTR, DWORD) +{ + auto wm = + reinterpret_cast(GetWindowLongPtrW(hWnd, GWLP_USERDATA)); + if (wm != nullptr) { + wm->RetrySessionNotification(); + } +} + static bool IsCurrentSessionRemoteable() noexcept { bool isRemoteable = false; @@ -202,6 +219,72 @@ bool WinMute::InitTrayMenu() } #undef CHECK_MENU_ITEM +bool WinMute::TryRegisterSessionNotification() +{ + if (wtsSessionNotificationRegistered_) { + return true; + } + if (!WTSRegisterSessionNotification(hWnd_, NOTIFY_FOR_THIS_SESSION)) { + WMLog::GetInstance().LogWinError(L"WTSRegisterSessionNotification", + GetLastError()); + return false; + } + wtsSessionNotificationRegistered_ = true; + return true; +} + +void WinMute::StartSessionNotificationRetry() +{ + WMLog& log = WMLog::GetInstance(); + + if (wtsRetryTimerId_ != 0) { + return; + } + if (SetTimer(hWnd_, WTS_RETRY_TIMER_ID, WTS_RETRY_INTERVAL_MS, + WtsRetryTimerProc) == 0) + { + log.LogWinError(L"SetTimer (session notification retry)", + GetLastError()); + log.LogError(L"Muting on workstation lock is not available"); + return; + } + wtsRetryTimerId_ = WTS_RETRY_TIMER_ID; + wtsRetryAttempts_ = 0; + log.LogInfo(L"Retrying to register for session notifications every {} ms", + WTS_RETRY_INTERVAL_MS); +} + +void WinMute::StopSessionNotificationRetry() noexcept +{ + if (wtsRetryTimerId_ != 0) { + KillTimer(hWnd_, wtsRetryTimerId_); + wtsRetryTimerId_ = 0; + } +} + +void WinMute::RetrySessionNotification() +{ + WMLog& log = WMLog::GetInstance(); + + ++wtsRetryAttempts_; + if (TryRegisterSessionNotification()) { + StopSessionNotificationRetry(); + log.LogInfo(L"Registered for session notifications after {} attempts", + wtsRetryAttempts_); + return; + } + if (wtsRetryAttempts_ >= WTS_RETRY_MAX_ATTEMPTS) { + StopSessionNotificationRetry(); + log.LogError( + L"Giving up on registering for session notifications after {} " + L"attempts. Muting on workstation lock is not available", + wtsRetryAttempts_); + wmTray_.ShowPopup( + i18n_.GetTranslationW("popup.session-notification-failed.title"), + i18n_.GetTranslationW("popup.session-notification-failed.text")); + } +} + bool WinMute::Init() { WMLog& log = WMLog::GetInstance(); @@ -232,13 +315,12 @@ bool WinMute::Init() return false; } - if (!WTSRegisterSessionNotification(hWnd_, NOTIFY_FOR_THIS_SESSION)) { - const DWORD lastError = GetLastError(); - ShowWindowsError(L"WTSRegisterSessionNotification"); - log.LogWinError(L"WTSRegisterSessionNotification", lastError); - return false; + // Try to register session notification. This is needed for mute-on-lock + // to work. If it fails, try again for a few times in the background, + // but don't block startup on it. + if (!TryRegisterSessionNotification()) { + StartSessionNotificationRetry(); } - wtsSessionNotificationRegistered_ = true; hPowerNotify_ = RegisterPowerSettingNotification( hWnd_, &GUID_CONSOLE_DISPLAY_STATE, DEVICE_NOTIFY_WINDOW_HANDLE); @@ -878,6 +960,7 @@ void WinMute::Unload() noexcept UnregisterPowerSettingNotification(hLidCloseNotify_); hLidCloseNotify_ = nullptr; } + StopSessionNotificationRetry(); if (wtsSessionNotificationRegistered_) { WTSUnRegisterSessionNotification(hWnd_); wtsSessionNotificationRegistered_ = false; diff --git a/WinMute/WinMute.h b/WinMute/WinMute.h index 4d78612..f993ef6 100644 --- a/WinMute/WinMute.h +++ b/WinMute/WinMute.h @@ -51,6 +51,7 @@ public: // for internal use LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); + void RetrySessionNotification(); private: HWND hWnd_; HMENU hTrayMenu_; @@ -66,6 +67,8 @@ private: } muteConfig_; bool wtsSessionNotificationRegistered_ = false; + UINT_PTR wtsRetryTimerId_ = 0; + int wtsRetryAttempts_ = 0; HPOWERNOTIFY hPowerNotify_ = nullptr; HPOWERNOTIFY hLidCloseNotify_ = nullptr; @@ -86,6 +89,10 @@ private: bool InitTrayMenu(); bool LoadSettings(); + bool TryRegisterSessionNotification(); + void StartSessionNotificationRetry(); + void StopSessionNotificationRetry() noexcept; + void Unload() noexcept; void ToggleMenuCheck(UINT item, bool* setting) noexcept; -- 2.43.0