--- /dev/null
+/*
+ WinMute
+ Copyright (c) 2023, Alexander Steinhoefer
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of the author nor the names of its contributors may
+ be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+#include "common.h"
+
+class HInternetHolder {
+public:
+ HInternetHolder(HINTERNET hInternet)
+ : hInternet_(hInternet)
+ {}
+ ~HInternetHolder()
+ {
+ if (hInternet_ != nullptr) {
+ WinHttpCloseHandle(hInternet_);
+ }
+ }
+ operator HINTERNET()
+ {
+ return hInternet_;
+ }
+private:
+ HINTERNET hInternet_;
+};
+
+
+UpdateChecker::UpdateChecker(const WMSettings &settings):
+ settings_(settings)
+{
+
+}
+
+UpdateChecker::~UpdateChecker()
+{
+
+}
+
+bool UpdateChecker::ShouldUpdate(std::wstring& , std::wstring& ) const
+{
+ //if (!IsUpdateCheckEnabled()) {
+ // return false;
+ //}
+
+ WMLog &log = WMLog::GetInstance();
+ HInternetHolder hSession = WinHttpOpen(
+ L"WinMute",
+ WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY,
+ WINHTTP_NO_PROXY_NAME,
+ WINHTTP_NO_PROXY_BYPASS,
+ WINHTTP_FLAG_SECURE_DEFAULTS);
+ if (hSession == nullptr) {
+ log.WriteWindowsError(L"WinHttpOpen", GetLastError());
+ return false;
+ }
+
+ HInternetHolder hConnect = WinHttpConnect(
+ hSession,
+ L"raw.githubusercontent.com",
+ INTERNET_DEFAULT_HTTPS_PORT,
+ 0);
+ if (hConnect == nullptr) {
+ log.WriteWindowsError(L"WinHttpConnect", GetLastError());
+ return false;
+ }
+
+#ifdef _DEBUG
+ const wchar_t *updateFileUrl = L"/lx-s/WinMute/dev/CURRENT_VERSION";
+#else
+ const wchar_t *updateFileUrl = L"/lx-s/WinMute/main/CURRENT_VERSION";
+#endif
+ HInternetHolder hRequest = WinHttpOpenRequest(
+ hConnect,
+ L"GET",
+ updateFileUrl,
+ nullptr,
+ WINHTTP_NO_REFERER,
+ WINHTTP_DEFAULT_ACCEPT_TYPES,
+ WINHTTP_FLAG_REFRESH | WINHTTP_FLAG_SECURE);
+
+ if (hRequest == nullptr) {
+ log.WriteWindowsError(L"WinHttpConnect", GetLastError());
+ return false;
+ }
+
+ bool result = WinHttpSendRequest(
+ hRequest,
+ WINHTTP_NO_ADDITIONAL_HEADERS,
+ 0,
+ WINHTTP_NO_REQUEST_DATA,
+ 0,
+ 0,
+ 0);
+
+ if (!result) {
+ log.WriteWindowsError(L"WinHttpSendRequest", GetLastError());
+ return false;
+ }
+
+ result = WinHttpReceiveResponse(hRequest, nullptr);
+ if (!result) {
+ log.WriteWindowsError(L"WinHttpReceiveResponse", GetLastError());
+ return false;
+ }
+
+ DWORD statusCode = 0;
+ DWORD statusCodeSize = static_cast<DWORD>(sizeof(statusCode));
+ result = WinHttpQueryHeaders(
+ hRequest,
+ WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER,
+ WINHTTP_HEADER_NAME_BY_INDEX,
+ reinterpret_cast<LPVOID>(&statusCode),
+ &statusCodeSize,
+ WINHTTP_NO_HEADER_INDEX);
+ if (!result) {
+ log.WriteWindowsError(L"WinHttpQueryHeaders(WINHTTP_QUERY_STATUS_CODE)", GetLastError());
+ return false;
+ } else if (statusCode != HTTP_STATUS_OK) {
+ log.Write(L"Update-Server returned HTTP %d", HTTP_STATUS_OK);
+ return false;
+ }
+
+ std::string versionFileContents;
+ for (;;) {
+ DWORD availBytes = 0;
+ if (!WinHttpQueryDataAvailable(hRequest, &availBytes)) {
+ log.WriteWindowsError(L"WinHttpQueryDataAvailable", GetLastError());
+ return false;
+ }
+ if (availBytes == 0) {
+ break;
+ }
+ std::string chunk(availBytes, ' ');
+ DWORD byRead = 0;
+ if (!WinHttpReadData(hRequest, reinterpret_cast<LPVOID>(&chunk[0]), availBytes, &byRead)) {
+ log.WriteWindowsError(L"WinHttpReadData", GetLastError());
+ return false;
+ }
+ versionFileContents.append(chunk.begin(), chunk.begin() + byRead);
+ }
+
+ // Check contents of version file
+ return true;
+}
+
+bool UpdateChecker::IsUpdateCheckEnabled() const
+{
+ const auto updateCheckSetting = settings_.QueryValue(SettingsKey::CHECK_FOR_UPDATE);
+ if (updateCheckSetting == static_cast<int>(UpdateCheckInterval::DISABLED)) {
+ return false;
+ }
+
+ wchar_t thisExePath[MAX_PATH * 2];
+ const DWORD thisExePathSize = ARRAY_SIZE(thisExePath);
+ const DWORD thisPathLen = GetModuleFileNameW(nullptr, thisExePath, thisExePathSize);
+ if (thisPathLen == 0 || (thisPathLen == thisExePathSize && GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
+ WMLog::GetInstance().WriteWindowsError(L"GetModuleFileNameW", ERROR_INSUFFICIENT_BUFFER);
+ return false;
+ }
+ fs::path updateDisableFile{ thisExePath };
+ updateDisableFile.replace_filename(L"update-check-disabled");
+ if (fs::exists(updateDisableFile)) {
+ return false;
+ }
+
+ return true;
+}
--- /dev/null
+/*
+ WinMute
+ Copyright (c) 2023, Alexander Steinhoefer
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of the author nor the names of its contributors may
+ be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+#pragma once
+
+#include "WMSettings.h"
+
+enum class UpdateCheckInterval : int {
+ DISABLED = 0,
+ ON_STARTUP = 1,
+};
+
+class UpdateChecker {
+public:
+ explicit UpdateChecker(const WMSettings& settings);
+ ~UpdateChecker();
+
+ bool ShouldUpdate(std::wstring& curVersion, std::wstring& newVersion) const;
+ std::wstring GetUpdateURL() const;
+private:
+ UpdateChecker(const UpdateChecker &) = delete;
+ UpdateChecker &operator=(const UpdateChecker &) = delete;
+ UpdateChecker(const UpdateChecker &&) = delete;
+ UpdateChecker &operator=(const UpdateChecker &&) = delete;
+
+ bool IsUpdateCheckEnabled() const;
+
+ bool ExtractVersion(HINTERNET hRequest) const;
+
+ const WMSettings &settings_;
+};
case SettingsKey::APP_LANGUAGE:
keyStr = L"AppLanguage";
break;
+ case SettingsKey::CHECK_FOR_UPDATE:
+ keyStr = L"CheckForUpdate";
+ break;
}
return keyStr;
}
return 0;
case SettingsKey::APP_LANGUAGE:
return 0;
+ case SettingsKey::CHECK_FOR_UPDATE:
+ return 0;
}
return 0;
}
, NOTIFICATIONS_ENABLED
, LOGGING_ENABLED
, APP_LANGUAGE
+ , CHECK_FOR_UPDATE
};
class WMSettings {
return FALSE;
}
+ UpdateChecker updateChecker(settings);
+ std::wstring w1, w2;
+ updateChecker.ShouldUpdate(w1, w2);
+
LoadLanguage(settings, i18n);
HANDLE hMutex = CreateMutexW(nullptr, TRUE, L"LxSystemsWinMuteRunOnce");
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
- <AdditionalDependencies>strsafe.lib;comctl32.lib;WtsApi32.lib;Winmm.lib;UxTheme.lib;comsuppwd.lib;Wlanapi.lib;Version.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <AdditionalDependencies>Advapi32.lib;Winhttp.lib;Bthprops.lib;comsuppwd.lib;comctl32.lib;strsafe.lib;UxTheme.lib;Winmm.lib;Wlanapi.lib;WtsApi32.lib;Shell32.lib;Version.lib;Gdi32.lib</AdditionalDependencies>
</Link>
<Manifest>
<EnableDpiAwareness>PerMonitorHighDPIAware</EnableDpiAwareness>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
- <AdditionalDependencies>strsafe.lib;comctl32.lib;WtsApi32.lib;Winmm.lib;UxTheme.lib;comsuppwd.lib;Wlanapi.lib;Version.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <AdditionalDependencies>Advapi32.lib;Winhttp.lib;Bthprops.lib;comsuppwd.lib;comctl32.lib;strsafe.lib;UxTheme.lib;Winmm.lib;Wlanapi.lib;WtsApi32.lib;Shell32.lib;Version.lib;Gdi32.lib</AdditionalDependencies>
</Link>
<Manifest>
<EnableDpiAwareness>PerMonitorHighDPIAware</EnableDpiAwareness>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
- <AdditionalDependencies>Bthprops.lib;comsuppwd.lib;comctl32.lib;strsafe.lib;UxTheme.lib;Winmm.lib;Wlanapi.lib;WtsApi32.lib;Version.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <AdditionalDependencies>Advapi32.lib;Winhttp.lib;Bthprops.lib;comsuppwd.lib;comctl32.lib;strsafe.lib;UxTheme.lib;Winmm.lib;Wlanapi.lib;WtsApi32.lib;Shell32.lib;Version.lib;Gdi32.lib</AdditionalDependencies>
</Link>
<Manifest>
<EnableDpiAwareness>PerMonitorHighDPIAware</EnableDpiAwareness>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
- <AdditionalDependencies>Bthprops.lib;comsuppwd.lib;comctl32.lib;strsafe.lib;UxTheme.lib;Winmm.lib;Wlanapi.lib;WtsApi32.lib;Version.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <AdditionalDependencies>Advapi32.lib;Winhttp.lib;Bthprops.lib;comsuppwd.lib;comctl32.lib;strsafe.lib;UxTheme.lib;Winmm.lib;Wlanapi.lib;WtsApi32.lib;Shell32.lib;Version.lib;Gdi32.lib</AdditionalDependencies>
</Link>
<Manifest>
<EnableDpiAwareness>PerMonitorHighDPIAware</EnableDpiAwareness>
<ClInclude Include="common.h" />
<ClInclude Include="libs\json.hpp" />
<ClInclude Include="resource.h" />
+ <ClInclude Include="UpdateChecker.h" />
<ClInclude Include="WiFiDetector.h" />
<ClInclude Include="WMi18n.h" />
<ClInclude Include="WMLog.h" />
<ClCompile Include="Settings_ManageEndpointsDlg.cpp" />
<ClCompile Include="Settings_MuteDlg.cpp" />
<ClCompile Include="Settings_WifiDlg.cpp" />
+ <ClCompile Include="UpdateChecker.cpp" />
<ClCompile Include="WifiDetector.cpp" />
<ClCompile Include="WMi18n.cpp" />
<ClCompile Include="WMLog.cpp" />
<ClInclude Include="libs\json.hpp">
<Filter>Source Files\_External</Filter>
</ClInclude>
+ <ClInclude Include="UpdateChecker.h">
+ <Filter>Source Files\Base\Settings</Filter>
+ </ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="WinMute.rc">
<ClCompile Include="Settings_GeneralDlg.cpp">
<Filter>Source Files\UI\Dialogs\Settings</Filter>
</ClCompile>
- <ClCompile Include="AboutDlg.cpp">
- <Filter>Source Files\UI\Dialogs</Filter>
- </ClCompile>
<ClCompile Include="Settings_MuteDlg.cpp">
<Filter>Source Files\UI\Dialogs\Settings</Filter>
</ClCompile>
<ClCompile Include="WMi18n.cpp">
<Filter>Source Files\Base\Settings</Filter>
</ClCompile>
+ <ClCompile Include="UpdateChecker.cpp">
+ <Filter>Source Files\Base\Settings</Filter>
+ </ClCompile>
+ <ClCompile Include="AboutDlg.cpp">
+ <Filter>Source Files\UI\Dialogs\Settings</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<CustomBuild Include="..\Translations\lang-de.json">
#include <algorithm>
#include <array>
#include <cassert>
-#include <span>
#include <chrono>
#include <cstdarg>
#include <filesystem>
-#include <optional>
#include <fstream>
#include <iterator>
#include <locale>
+#include <map>
#include <memory>
-#include <string_view>
+#include <optional>
+#include <span>
#include <string>
+#include <string_view>
+#include <type_traits>
#include <unordered_map>
-#include <map>
#include <vector>
namespace fs = std::filesystem;
#include <windowsx.h>
#include <commctrl.h>
#include <WtsApi32.h>
+#include <winhttp.h>
#include <dbt.h>
#include <Bthdef.h>
#include <Bthsdpdef.h>
#include "WMi18n.h"
#include "WMSettings.h"
#include "WMLog.h"
+#include "UpdateChecker.h"
#include "TrayIcon.h"
#include "WinAudio.h"
#include "MuteControl.h"
#include "WinMute.h"
#include "VersionHelper.h"
-
// Utility
void PrintWindowsError(const wchar_t *functionName, DWORD lastError = -1);
bool GetWinMuteVersion(std::wstring &versNumber);