diff --git a/CMakeLists.txt b/CMakeLists.txt index d68844c0b..fb2be894d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -94,6 +94,8 @@ set(REQUIRED_OPENSSL_VERSION 3.0) set(REQUIRED_LIBEI_VERSION 1.3) set(REQUIRED_LIBPORTAL_VERSION 0.8) set(REQUIRED_QT_VERSION 6.7.0) +set(REQUIRED_MSVC_RUNTIME_MAJOR 14) +set(REQUIRED_MSVC_RUNTIME_MINOR 42) # Control debug item visibility # When not set logging is forced to DEBUG and show code locations diff --git a/cspell.json b/cspell.json index 3d876976f..905ad93f5 100644 --- a/cspell.json +++ b/cspell.json @@ -26,6 +26,7 @@ "Hadzhylov", "Hetu", "HINSTANCE", + "HKLM", "hotspots", "Hutterer", "ifdef", @@ -65,6 +66,7 @@ "qobject", "qputenv", "readf", + "Redist", "Regen", "Repology", "Rizzitello", diff --git a/deploy/windows/deploy.cmake b/deploy/windows/deploy.cmake index fe71d90cb..1b539dcb2 100644 --- a/deploy/windows/deploy.cmake +++ b/deploy/windows/deploy.cmake @@ -53,3 +53,18 @@ configure_file( # This patch set ups filewall rules, the service and msm module set(CPACK_WIX_PATCH_FILE "${CMAKE_CURRENT_BINARY_DIR}/wix-patch.xml") + +# Creates a DLL that can be used by our MSI for custom actions. +configure_file( + ${MY_DIR}/wix-custom.h.in + ${CMAKE_CURRENT_BINARY_DIR}/wix-custom.h @ONLY +) +add_library( + wix-custom SHARED + ${MY_DIR}/wix-custom.cpp +) +target_include_directories(wix-custom PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) +set_target_properties(wix-custom PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" +) +target_link_libraries(wix-custom PRIVATE Msi) diff --git a/deploy/windows/wix-custom.cpp b/deploy/windows/wix-custom.cpp new file mode 100644 index 000000000..09a690f34 --- /dev/null +++ b/deploy/windows/wix-custom.cpp @@ -0,0 +1,72 @@ +/* + * Deskflow -- mouse and keyboard sharing utility + * SPDX-FileCopyrightText: (C) 2025 Symless Ltd. + * SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception + */ + +#include "wix-custom.h" + +#define WIN32_LEAN_AND_MEAN +#include + +// Include after Windows.h +#include + +#include +#include + +namespace { +// Warning: DLL will crash with error code 1603 if we exceed this. +const auto kLogLineMax = 1024; + +// Prefixes log messages with the app name so they're easier to find/filter. +const std::string kLogPrefix = std::string(kAppId) + " installer: "; + +// Note: Resized to log line max when used. +static std::string s_logMessageBuffer; // NOSONAR - Must be mutable. +} // namespace + +// This log output can be viewed by using the DebugView program. +#define MS_LOG_DEBUG(message, ...) \ + s_logMessageBuffer.resize(kLogLineMax); \ + sprintf(s_logMessageBuffer.data(), message, __VA_ARGS__); \ + OutputDebugStringA((kLogPrefix + s_logMessageBuffer + "\n").c_str()) + +extern "C" __declspec(dllexport) UINT __stdcall CheckVCRedist(MSIHANDLE hInstall) +{ + const auto kKeyName = TEXT("SOFTWARE\\Microsoft\\VisualStudio\\14.0\\VC\\Runtimes\\x64"); + const auto kValueName = TEXT("Minor"); + const auto kProperty = "VC_REDIST_VERSION_OK"; + + MS_LOG_DEBUG("checking for msvc redist v%d.%d", kWindowsRuntimeMajor, kWindowsRuntimeMinor); + + HKEY hKey; + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, kKeyName, 0, KEY_READ, &hKey) != ERROR_SUCCESS) { + MS_LOG_DEBUG("msvc redist registry key not found"); + return ERROR_FUNCTION_FAILED; + } + + MS_LOG_DEBUG("msvc redist registry key found, querying minor version"); + + DWORD minorVersion = 0; + DWORD size = sizeof(DWORD); + RegQueryValueEx(hKey, kValueName, nullptr, nullptr, (LPBYTE)&minorVersion, &size); + RegCloseKey(hKey); + + MS_LOG_DEBUG("msvc redist minor version: %lu", minorVersion); + + if (minorVersion < kWindowsRuntimeMinor) { + MS_LOG_DEBUG("msvc redist minor version %lu too low, expected >= %d", minorVersion, kWindowsRuntimeMinor); + // Returning success allows the installer will show a friendly error message. + return ERROR_SUCCESS; + } + + MS_LOG_DEBUG("msvc redist version ok, setting: %s", kProperty); + if (MsiSetProperty(hInstall, kProperty, "ok") != ERROR_SUCCESS) { + MS_LOG_DEBUG("failed to set property: %s", kProperty); + return ERROR_FUNCTION_FAILED; + } + + MS_LOG_DEBUG("msvc redist version check successful"); + return ERROR_SUCCESS; +} diff --git a/deploy/windows/wix-custom.h.in b/deploy/windows/wix-custom.h.in new file mode 100644 index 000000000..23e159d4e --- /dev/null +++ b/deploy/windows/wix-custom.h.in @@ -0,0 +1,14 @@ +/* + * Deskflow -- mouse and keyboard sharing utility + * SPDX-FileCopyrightText: (C) 2025 Symless Ltd. + * SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception + */ + +#pragma once + +const auto kAppId = "@CMAKE_PROJECT_NAME@"; + +// clang-format off +const auto kWindowsRuntimeMajor = @REQUIRED_MSVC_RUNTIME_MAJOR@; +const auto kWindowsRuntimeMinor = @REQUIRED_MSVC_RUNTIME_MINOR@; +// clang-format on diff --git a/deploy/windows/wix-patch.xml.in b/deploy/windows/wix-patch.xml.in index 55fd1e9b6..b8f53cd94 100644 --- a/deploy/windows/wix-patch.xml.in +++ b/deploy/windows/wix-patch.xml.in @@ -32,20 +32,42 @@ - - + + + + + Error="Microsoft Visual C++ Redistributable v@REQUIRED_MSVC_RUNTIME_MAJOR@.@REQUIRED_MSVC_RUNTIME_MINOR@ or later is required. Please download and install the latest version and then restart the installation. See our documentation for instructions." /> + + - - + + + diff --git a/src/lib/arch/win32/ArchMiscWindows.cpp b/src/lib/arch/win32/ArchMiscWindows.cpp index 9bfabde40..33fd3ff77 100644 --- a/src/lib/arch/win32/ArchMiscWindows.cpp +++ b/src/lib/arch/win32/ArchMiscWindows.cpp @@ -20,8 +20,8 @@ // See table of the compiler versions and the matching runtime DLL versions: // https://dev.to/yumetodo/list-of-mscver-and-mscfullver-8nd #if _MSC_VER >= 1942 // Visual Studio 2022 Update 12 (v17.12.4) -const auto kRequiredMajor = 14; -const auto kRequiredMinor = 42; +const auto kRequiredMajor = kWindowsRuntimeMajor; +const auto kRequiredMinor = kWindowsRuntimeMinor; #elif _MSC_VER >= 1920 // Visual Studio 2019 Update 7 (v16.7) const auto kRequiredMajor = 14; const auto kRequiredMinor = 27; diff --git a/src/lib/common/constants.h.in b/src/lib/common/constants.h.in index b45543dc0..cf1f30176 100644 --- a/src/lib/common/constants.h.in +++ b/src/lib/common/constants.h.in @@ -39,3 +39,12 @@ const auto kTlsCertificateFilename = "@CMAKE_PROJECT_NAME@.pem"; const auto kTlsFingerprintLocalFilename = "local-fingerprint"; const auto kTlsFingerprintTrustedServersFilename = "trusted-servers"; const auto kTlsFingerprintTrustedClientsFilename = "trusted-clients"; + +#ifdef _WIN32 + +// clang-format off +const auto kWindowsRuntimeMajor = @REQUIRED_MSVC_RUNTIME_MAJOR@; +const auto kWindowsRuntimeMinor = @REQUIRED_MSVC_RUNTIME_MINOR@; +// clang-format on + +#endif