]> repos.lx-s.de Git - winmute.git/commitdiff
Added update check
authorlx-s <lx-s@users.noreply.github.com>
Tue, 19 Dec 2023 09:07:24 +0000 (10:07 +0100)
committerlx-s <lx-s@users.noreply.github.com>
Tue, 19 Dec 2023 09:07:24 +0000 (10:07 +0100)
Translations/lang-en.json
WinMute/TrayIcon.cpp
WinMute/TrayIcon.h
WinMute/UpdateChecker.cpp
WinMute/UpdateChecker.h
WinMute/WinMain.cpp
WinMute/WinMute.cpp
WinMute/WinMute.h
WinMute/common.h

index e24a92e00a8cfb7b79927e3c655fa62d351dabec..1f7638b813a279ce8e316e67e1f9e00adead5223 100644 (file)
   "general.error.winapi.text": "{} failed with error {}: {}",
   "general.error.audio-service-shutdown.title": "The audio service has been shut down.",
   "general.error.audio-service-shutdown.text": "WinMute is not able to recover from that condition.\nPlease try to restart the program.",
+  "popup.update-available.title": "WinMute {} is available!",
+  "popup.update-available.text": "Your current version is {}.\nClick on this message to open the download page.",
+  "popup.error.update-check-failed.title": "Update check failed.",
+  "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 endpoints have been muted",
   "popup.bluetooth-muting-disabled.title": "Bluetooth muting disabled",
index e1c44dcd7da885a5380199c5996e1ca184550f4a..516c314bc037b796dee5de36c7eaa544b03035d5 100644 (file)
@@ -132,7 +132,10 @@ void TrayIcon::ChangeText(const std::wstring& tooltip)
       ChangeText();
 }
 
-void TrayIcon::ShowPopup(const std::wstring& title, const std::wstring& text) const
+void TrayIcon::ShowPopup(
+   const std::wstring& title,
+   const std::wstring& text,
+   int callbackID) const
 {
    if (!initialized_) {
       TrayIconPopup popup;
@@ -141,13 +144,17 @@ void TrayIcon::ShowPopup(const std::wstring& title, const std::wstring& text) co
       popupQueue_.push_back(popup);
       return;
    } 
-   NOTIFYICONDATA tnid{0};
-   tnid.cbSize = sizeof(NOTIFYICONDATA);
+   NOTIFYICONDATAW tnid{0};
+   tnid.cbSize = sizeof(tnid);
    tnid.uVersion = NOTIFYICON_VERSION_4;
    tnid.hWnd = hWnd_;
    tnid.uID = trayID_;
-   tnid.uFlags = NIF_INFO;
+   tnid.uFlags = NIF_INFO | NIF_SHOWTIP;
    tnid.dwInfoFlags = NIIF_INFO | NIIF_NOSOUND | NIIF_LARGE_ICON | NIIF_RESPECT_QUIET_TIME;
+   if (callbackID != 0) {
+      tnid.uCallbackMessage = callbackID;
+      tnid.uFlags |= NIF_MESSAGE;
+   }
    tnid.uTimeout = 10 * 1000;
    StringCchCopy(tnid.szInfoTitle, ARRAY_SIZE(tnid.szInfoTitle), title.c_str());
    StringCchCopy(tnid.szInfo, ARRAY_SIZE(tnid.szInfo), text.c_str());
@@ -165,12 +172,12 @@ void TrayIcon::DestroyTrayIcon()
 
 bool TrayIcon::AddNotifyIcon()
 {
-   NOTIFYICONDATA tnid{ 0 };
-   tnid.cbSize = sizeof(NOTIFYICONDATA);
+   NOTIFYICONDATAW tnid{ 0 };
+   tnid.cbSize = sizeof(tnid);
    tnid.uVersion = NOTIFYICON_VERSION_4;
    tnid.hWnd = hWnd_;
    tnid.uID = trayID_;
-   tnid.uFlags = NIF_ICON | NIF_TIP | NIF_MESSAGE;
+   tnid.uFlags = NIF_ICON | NIF_TIP | NIF_MESSAGE | NIF_SHOWTIP;
    tnid.hIcon = hIcon_;
    tnid.uCallbackMessage = WM_TRAYICON;
 
@@ -182,8 +189,8 @@ bool TrayIcon::AddNotifyIcon()
 
 bool TrayIcon::RemoveNotifyIcon()
 {
-   NOTIFYICONDATA tnid{0};
-   tnid.cbSize = sizeof(NOTIFYICONDATA);
+   NOTIFYICONDATAW tnid{0};
+   tnid.cbSize = sizeof(tnid);
    tnid.uVersion = NOTIFYICON_VERSION_4;
    tnid.hWnd = hWnd_;
    tnid.uID = trayID_;
@@ -193,8 +200,8 @@ bool TrayIcon::RemoveNotifyIcon()
 
 bool TrayIcon::ChangeText()
 {
-   NOTIFYICONDATA tnid{0};
-   tnid.cbSize = sizeof(NOTIFYICONDATA);
+   NOTIFYICONDATAW tnid{0};
+   tnid.cbSize = sizeof(tnid);
    tnid.uVersion = NOTIFYICON_VERSION_4;
    tnid.hWnd = hWnd_;
    tnid.uID = trayID_;
index 6d7cc10feab84dffb3bc35105bed148ba114e9d2..f5d3d126f97225c24310dfca151682ba7236266a 100644 (file)
@@ -35,7 +35,7 @@ POSSIBILITY OF SUCH DAMAGE.
 
 #include "common.h"
 
-#define WM_TRAYICON (WM_APP + 700)
+constexpr int WM_TRAYICON = WM_APP + 700;
 
 struct TrayIconPopup {
    std::wstring title;
@@ -55,7 +55,10 @@ public:
    bool IsShown() const noexcept { return iconVisible_; }
    void ChangeIcon(HICON hNewIcon);
    void ChangeText(const std::wstring& tooltip);
-   void ShowPopup(const std::wstring& title, const std::wstring& text) const;
+   void ShowPopup(
+      const std::wstring& title,
+      const std::wstring& text,
+      int callbackID = 0) const;
 
 private:
    void DestroyTrayIcon();
index 429797e57ad36c457ce52ac71e34fcf7e11b14cc..9cc6eef60b4e6d6bbccd480d0cf8ba399d72fd2b 100644 (file)
@@ -91,7 +91,7 @@ bool UpdateChecker::ParseVersionFile(
    return true;
 }
 
-bool UpdateChecker::ParseVersion(const std::wstring &vers, std::vector<int> parsedVers) const
+bool UpdateChecker::ParseVersion(const std::wstring &vers, std::vector<int>& parsedVers) const
 {
    size_t lastVersionPos = 0;
    size_t curPos = 0;
@@ -106,10 +106,6 @@ bool UpdateChecker::ParseVersion(const std::wstring &vers, std::vector<int> pars
          lastVersionPos = curPos + 1;
       }
    }
-   auto pos = vers.find('.');
-   if (pos != std::wstring::npos) {
-      parsedVers.push_back(std::stoi(vers));
-   }
    return true;
 }
 
@@ -164,10 +160,12 @@ bool UpdateChecker::GetVersionFile(std::string &fileContents) const
 {
    WMLog &log = WMLog::GetInstance();
 
-
-   URL_COMPONENTS updateUrl;
+   URL_COMPONENTS updateUrl{0};
    updateUrl.dwStructSize = sizeof(updateUrl);
-   if (!WinHttpCrackUrl(UPDATE_FILE_URL, 0, ICU_ESCAPE, &updateUrl)) {
+   updateUrl.dwSchemeLength = (DWORD)-1;
+   updateUrl.dwHostNameLength = (DWORD)-1;
+   updateUrl.dwUrlPathLength = (DWORD)-1;
+   if (!WinHttpCrackUrl(UPDATE_FILE_URL, 0, 0, &updateUrl)) {
       log.WriteWindowsError(L"WinHttpCrackUrl", GetLastError());
       return false;
    }
@@ -189,7 +187,7 @@ bool UpdateChecker::GetVersionFile(std::string &fileContents) const
    HInternetHolder hConnect = WinHttpConnect(
       hSession,
       updateHost.c_str(),
-      INTERNET_DEFAULT_HTTPS_PORT,
+      (updateUrl.nScheme == INTERNET_SCHEME_HTTPS) ? INTERNET_DEFAULT_HTTPS_PORT : INTERNET_DEFAULT_HTTP_PORT,
       0);
    if (hConnect == nullptr) {
       log.WriteWindowsError(L"WinHttpConnect", GetLastError());
index 9731fe27a7e4fcc252fb236fe5ab7d97ad8f6d7f..bbfb93facf2f12c2d92db2a8e22b8b2d5279e9e7 100644 (file)
@@ -63,5 +63,5 @@ private:
    bool GetVersionFile(std::string &fileContents) const;
    bool ParseVersionFile(const std::string &fileContents, UpdateInfo& updateInfo) const;
    std::optional<bool> IsVersionGreater(const std::wstring &newVers, const std::wstring &curVers) const;
-   bool ParseVersion(const std::wstring &vers, std::vector<int> parsedVers) const;
+   bool ParseVersion(const std::wstring &vers, std::vector<int>& parsedVers) const;
 };
index ad21bc7d710ec6ecef3a07ad89779f9649d7bf4c..e5f9a9f0b7899c9c7a1cb0aefb5aa85b16030842 100644 (file)
@@ -72,44 +72,6 @@ static bool InitWindowsComponents()
    return TRUE;
 }
 
-static DWORD CheckForUpdates_Thread(LPVOID param)
-{
-   auto updateChecker = reinterpret_cast<UpdateChecker *>(param);
-   if (updateChecker == nullptr) {
-      return 1;
-   }
-   UpdateInfo updateInfo;
-   if (!updateChecker->GetUpdateInfo(updateInfo)) {
-      // Print Error
-   } else {
-      // Print Update Message
-   }
-
-   delete updateChecker;
-   return 0;
-}
-
-static void CheckForUpdates(const WMSettings& settings)
-{
-   UpdateChecker *updateChecker = new UpdateChecker();
-   if (updateChecker == nullptr) {
-      return;
-   }
-   if (!updateChecker->IsUpdateCheckEnabled(settings)) {
-      delete updateChecker;
-      return;
-   }
-   auto updateThread = CreateThread(
-      nullptr, 0, CheckForUpdates_Thread,
-      reinterpret_cast<LPVOID>(updateChecker),
-      0, nullptr);
-   if (updateThread == nullptr) {
-      delete updateChecker;
-      return;
-   }
-
-}
-
 int WINAPI wWinMain(
    _In_ HINSTANCE hInstance,
    _In_opt_ HINSTANCE,
@@ -172,8 +134,6 @@ int WINAPI wWinMain(
       return FALSE;
    }
 
-   CheckForUpdates(settings);
-
    MSG msg = { nullptr };
    WinMute program(settings);
    if (program.Init()) {
index 30dbac6bbf00b4516876f12c9f9f15b26583b737..9c352aeeaebf26a662f9f43a00be329296e25387 100644 (file)
@@ -101,6 +101,7 @@ static bool IsCurrentSessionRemoteable() noexcept
    return isRemoteable;
 }
 
+
 WinMute::MuteConfig::MuteConfig()
    : muteOnWlan(false), muteOnBluetooth(false), showNotifications(false)
 {
@@ -112,7 +113,7 @@ WinMute::WinMute(WMSettings& settings) :
    hAppIcon_(nullptr),
    hTrayIcon_(nullptr),
    settings_(settings),
-   i18n(WMi18n::GetInstance())
+   i18n_(WMi18n::GetInstance())
 {
 }
 
@@ -157,8 +158,8 @@ bool WinMute::InitAudio()
       TaskDialog(
          nullptr, nullptr,
          PROGRAM_NAME,
-         i18n.GetTranslationW("init.error.winmute.platform-support.title").c_str(),
-         i18n.GetTranslationW("init.error.winmute.platform-support.text").c_str(),
+         i18n_.GetTranslationW("init.error.winmute.platform-support.title").c_str(),
+         i18n_.GetTranslationW("init.error.winmute.platform-support.text").c_str(),
          TDCBF_OK_BUTTON, TD_ERROR_ICON, nullptr);
       return false;
    }
@@ -249,11 +250,13 @@ bool WinMute::Init()
    if (settings_.QueryValue(SettingsKey::MUTE_ON_RDP)
        && IsCurrentSessionRemoteable()) {
       trayIcon_.ShowPopup(
-         i18n.GetTranslationW("popup.remote-session-detected.title"),
-         i18n.GetTranslationW("popup.remote-session-detected.text"));
+         i18n_.GetTranslationW("popup.remote-session-detected.title"),
+         i18n_.GetTranslationW("popup.remote-session-detected.text"));
       muteCtrl_.SetMute(true);
    }
 
+   CheckForUpdates();
+
    return true;
 }
 
@@ -307,8 +310,8 @@ bool WinMute::LoadSettings()
    } else {
       if (!btDetector_.Init(hWnd_)) {
          trayIcon_.ShowPopup(
-            i18n.GetTranslationW("popup.bluetooth-muting-disabled.title"),
-            i18n.GetTranslationW("popup.bluetooth-muting-disabled.text"));
+            i18n_.GetTranslationW("popup.bluetooth-muting-disabled.title"),
+            i18n_.GetTranslationW("popup.bluetooth-muting-disabled.text"));
          settings_.SetValue(SettingsKey::MUTE_ON_BLUETOOTH, FALSE);
       } else {
          muteCtrl_.SetMuteOnBluetoothDisconnect(true);
@@ -323,8 +326,8 @@ bool WinMute::LoadSettings()
    } else {
       if (!wifiDetector_.Init(hWnd_)) {
          trayIcon_.ShowPopup(
-            i18n.GetTranslationW("popup.wlan-muting-disabled.title"),
-            i18n.GetTranslationW("popup.wlan-muting-disabled.text"));
+            i18n_.GetTranslationW("popup.wlan-muting-disabled.title"),
+            i18n_.GetTranslationW("popup.wlan-muting-disabled.text"));
          settings_.SetValue(SettingsKey::MUTE_ON_WLAN, FALSE);
       } else {
          const bool isMuteList = !settings_.QueryValue(SettingsKey::MUTE_ON_WLAN_ALLOWLIST);
@@ -351,18 +354,18 @@ void WinMute::ToggleMenuCheck(UINT item, bool* setting) noexcept
 void WinMute::LoadMainMenuText()
 {
    std::map<UINT, std::wstring> menuText;
-   menuText[ID_TRAYMENU_INFO] = i18n.GetTranslationW("traymenu.info");
-   menuText[ID_TRAYMENU_LABEL_MUTEWHEN] = i18n.GetTranslationW("traymenu.mute-when");
-   menuText[ID_TRAYMENU_MUTEONLOCK] = i18n.GetTranslationW("traymenu.mute-on-lock");
-   menuText[ID_TRAYMENU_MUTEONSCREENSUSPEND] = i18n.GetTranslationW("traymenu.mute-on-screen-suspend");
-   menuText[ID_TRAYMENU_RESTOREAUDIO] = i18n.GetTranslationW("traymenu.restore-volume");
-   menuText[ID_TRAYMENU_LABEL_MUTEON_NO_RESTORE] = i18n.GetTranslationW("traymenu.mute-no-restore");
-   menuText[ID_TRAYMENU_MUTEONSHUTDOWN] = i18n.GetTranslationW("traymenu.mute-on-shutdown");
-   menuText[ID_TRAYMENU_MUTEONSUSPEND] = i18n.GetTranslationW("traymenu.mute-on-sleep");
-   menuText[ID_TRAYMENU_MUTEONLOGOUT] = i18n.GetTranslationW("traymenu.mute-on-logout");
-   menuText[ID_TRAYMENU_MUTE] = i18n.GetTranslationW("traymenu.mute-all-devices");
-   menuText[ID_TRAYMENU_SETTINGS] = i18n.GetTranslationW("traymenu.settings");
-   menuText[ID_TRAYMENU_EXIT] = i18n.GetTranslationW("traymenu.exit");
+   menuText[ID_TRAYMENU_INFO] = i18n_.GetTranslationW("traymenu.info");
+   menuText[ID_TRAYMENU_LABEL_MUTEWHEN] = i18n_.GetTranslationW("traymenu.mute-when");
+   menuText[ID_TRAYMENU_MUTEONLOCK] = i18n_.GetTranslationW("traymenu.mute-on-lock");
+   menuText[ID_TRAYMENU_MUTEONSCREENSUSPEND] = i18n_.GetTranslationW("traymenu.mute-on-screen-suspend");
+   menuText[ID_TRAYMENU_RESTOREAUDIO] = i18n_.GetTranslationW("traymenu.restore-volume");
+   menuText[ID_TRAYMENU_LABEL_MUTEON_NO_RESTORE] = i18n_.GetTranslationW("traymenu.mute-no-restore");
+   menuText[ID_TRAYMENU_MUTEONSHUTDOWN] = i18n_.GetTranslationW("traymenu.mute-on-shutdown");
+   menuText[ID_TRAYMENU_MUTEONSUSPEND] = i18n_.GetTranslationW("traymenu.mute-on-sleep");
+   menuText[ID_TRAYMENU_MUTEONLOGOUT] = i18n_.GetTranslationW("traymenu.mute-on-logout");
+   menuText[ID_TRAYMENU_MUTE] = i18n_.GetTranslationW("traymenu.mute-all-devices");
+   menuText[ID_TRAYMENU_SETTINGS] = i18n_.GetTranslationW("traymenu.settings");
+   menuText[ID_TRAYMENU_EXIT] = i18n_.GetTranslationW("traymenu.exit");
 
    for (const auto& mt : menuText) {
       MENUITEMINFO mii{ sizeof(MENUITEMINFO) };
@@ -379,6 +382,37 @@ void WinMute::LoadMainMenuText()
    }
 }
 
+void WinMute::CheckForUpdates()
+{
+   auto updateChecker = std::make_unique<UpdateChecker>();
+   if (!updateChecker ||
+       !updateChecker->IsUpdateCheckEnabled(settings_)) {
+      return;
+   }
+   std::thread updateThread(&WinMute::CheckForUpdatesAsync, this, std::move(updateChecker));
+   updateThread.detach();
+}
+
+void WinMute::CheckForUpdatesAsync(std::unique_ptr<UpdateChecker> updateChecker)
+{
+   if (!updateChecker) {
+      return;
+   }
+   if (!updateChecker->GetUpdateInfo(updateInfo_)) {
+      trayIcon_.ShowPopup(
+         i18n_.GetTranslationW("popup.error.update-check-failed.title"),
+         i18n_.GetTranslationW("popup.error.update-check-failed.text"));
+   } else if (updateInfo_.shouldUpdate) {
+      const std::wstring popupTitle = std::vformat(
+         i18n_.GetTranslationW("popup.update-available.title"),
+         std::make_wformat_args(updateInfo_.newVersion));
+      const std::wstring popupText = std::vformat(
+         i18n_.GetTranslationW("popup.update-available.text"),
+         std::make_wformat_args(updateInfo_.currentVersion));
+      trayIcon_.ShowPopup(popupTitle, popupText, WM_WINMUTE_UPDATE_POPUP);
+   }
+}
+
 LRESULT WinMute::OnCommand(HWND hWnd, WPARAM wParam, LPARAM)
 {
    switch (LOWORD(wParam)) {
@@ -523,8 +557,8 @@ LRESULT WinMute::OnQuietHours(HWND, UINT msg, WPARAM, LPARAM)
       muteCtrl_.NotifyQuietHours(true);
       if (settings_.QueryValue(SettingsKey::QUIETHOURS_NOTIFICATIONS)) {
          trayIcon_.ShowPopup(
-            i18n.GetTranslationW("popup.quiet-hours-started.title"),
-            i18n.GetTranslationW("popup.quiet-hours-started.text"));
+            i18n_.GetTranslationW("popup.quiet-hours-started.title"),
+            i18n_.GetTranslationW("popup.quiet-hours-started.text"));
       }
       quietHours_.SetEnd();
       return 0;
@@ -532,8 +566,8 @@ LRESULT WinMute::OnQuietHours(HWND, UINT msg, WPARAM, LPARAM)
       muteCtrl_.NotifyQuietHours(false);
       if (settings_.QueryValue(SettingsKey::QUIETHOURS_NOTIFICATIONS)) {
          trayIcon_.ShowPopup(
-            i18n.GetTranslationW("popup.quiet-hours-ended.title"),
-            i18n.GetTranslationW("popup.quiet-hours-ended.text"));
+            i18n_.GetTranslationW("popup.quiet-hours-ended.title"),
+            i18n_.GetTranslationW("popup.quiet-hours-ended.text"));
       }
       if (settings_.QueryValue(SettingsKey::QUIETHOURS_FORCEUNMUTE)) {
          muteCtrl_.SetMute(false);
@@ -570,15 +604,15 @@ LRESULT WinMute::OnWifiStatusChange(HWND, WPARAM wParam, LPARAM lParam)
       wchar_t *wifiName = reinterpret_cast<wchar_t *>(lParam);
       if (settings_.QueryValue(SettingsKey::MUTE_ON_WLAN_ALLOWLIST)) {
          popupMsg = std::vformat(
-            i18n.GetTranslationW("popup.wlan-not-on-mute-list.text"),
+            i18n_.GetTranslationW("popup.wlan-not-on-mute-list.text"),
             std::make_wformat_args(wifiName));
       } else {
          popupMsg = std::vformat(
-            i18n.GetTranslationW("popup.wlan-is-on-mute-list.text"),
+            i18n_.GetTranslationW("popup.wlan-is-on-mute-list.text"),
             std::make_wformat_args(wifiName));
       }
       trayIcon_.ShowPopup(
-         i18n.GetTranslationW("popup.workstation-muted.title"),
+         i18n_.GetTranslationW("popup.workstation-muted.title"),
          popupMsg);
       delete[] wifiName;
    }
@@ -587,6 +621,16 @@ LRESULT WinMute::OnWifiStatusChange(HWND, WPARAM wParam, LPARAM lParam)
    return 0;
 }
 
+LRESULT WinMute::OnUpdatePopup(HWND hWnd, WPARAM, LPARAM lParam)
+{
+   if (lParam == NIN_BALLOONUSERCLICK) {
+      ShellExecuteW(
+         hWnd, L"open", updateInfo_.versionPageUrl.c_str(),
+         nullptr, nullptr, SW_SHOW);
+   }
+   return 0;
+}
+
 LRESULT CALLBACK WinMute::WindowProc(
    HWND hWnd,
    UINT msg,
@@ -600,6 +644,8 @@ LRESULT CALLBACK WinMute::WindowProc(
       return TRUE;
    case WM_COMMAND:
       return OnCommand(hWnd, wParam, lParam);
+   case WM_WINMUTE_UPDATE_POPUP:
+      return OnUpdatePopup(hWnd, wParam, lParam);
    case WM_TRAYICON:
       return OnTrayIcon(hWnd, wParam, lParam);
    case WM_CLOSE:
index e346b98a606937203cb685c7eb33376c2b3023cc..25481c05fa600ca51da1ca9fd27a21b58d328d41 100644 (file)
@@ -51,6 +51,7 @@ public:
 
    // for internal use
    LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
+   void CheckForUpdatesAsync(std::unique_ptr<UpdateChecker> updateChecker);
 private:
    HWND hWnd_;
    HMENU hTrayMenu_;
@@ -67,11 +68,13 @@ private:
    TrayIcon trayIcon_;
    WifiDetector wifiDetector_;
    WMSettings& settings_;
-   WMi18n &i18n;
+   WMi18n &i18n_;
    MuteControl muteCtrl_;
    QuietHoursTimer quietHours_;
    BluetoothDetector btDetector_;
+   UpdateInfo updateInfo_;
 
+   void CheckForUpdates();
    bool RegisterWindowClass();
    bool InitWindow();
    bool InitAudio();
@@ -90,6 +93,7 @@ private:
    LRESULT OnSettingChange(HWND hWnd, WPARAM wParam, LPARAM lParam);
    LRESULT OnPowerBroadcast(HWND hWnd, WPARAM wParam, LPARAM lParam);
    LRESULT OnWifiStatusChange(HWND hWnd, WPARAM wParam, LPARAM lParam);
+   LRESULT OnUpdatePopup(HWND hWnd, WPARAM wParam, LPARAM lParam);
    
    LRESULT OnDeviceChange(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
    LRESULT OnQuietHours(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
index c87d21e730b1a1d144cb5485c47c4435b17eeebe..0f1b4fc50e411bea47c1610567ada67378c756d3 100644 (file)
@@ -129,6 +129,7 @@ static const wchar_t *PROGRAM_NAME = L"WinMute";
 static const wchar_t *LOG_FILE_NAME = L"WinMute.log";
 
 constexpr int WM_SAVESETTINGS = WM_USER + 300;
+constexpr int WM_WINMUTE_UPDATE_POPUP = WM_USER + 301;
 
 // =============================================================================
 // Utility