fix: Guard MSVC runtime version depending on compiler version

This commit is contained in:
Nick Bolton
2025-03-06 12:36:14 +00:00
committed by Chris Rizzitello
parent a7ce936d68
commit 495331108b
6 changed files with 79 additions and 2 deletions

View File

@ -11,7 +11,7 @@ macro(configure_libs)
find_package(Python REQUIRED QUIET)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP /D _BIND_TO_CURRENT_VCLIBS_VERSION=1")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MD /O2 /Ob2")
list(APPEND libs Wtsapi32 Userenv Wininet comsuppw Shlwapi)
list(APPEND libs Wtsapi32 Userenv Wininet comsuppw Shlwapi version)
add_definitions(
/DWIN32
/D_WINDOWS

View File

@ -18,6 +18,8 @@
int main(int argc, char **argv)
{
#if SYSAPI_WIN32
ArchMiscWindows::guardRuntimeVersion();
// record window instance for tray icon, etc
ArchMiscWindows::setInstanceWin32(GetModuleHandle(NULL));
#endif

View File

@ -32,6 +32,8 @@ void handleError(const char *message);
int main(int argc, char **argv)
{
#if SYSAPI_WIN32
ArchMiscWindows::guardRuntimeVersion();
// Save window instance for later use, e.g. `GetModuleFileName` which is used when installing the daemon.
ArchMiscWindows::setInstanceWin32(GetModuleHandle(nullptr));
#endif

View File

@ -18,6 +18,8 @@
int main(int argc, char **argv)
{
#if SYSAPI_WIN32
ArchMiscWindows::guardRuntimeVersion();
// record window instance for tray icon, etc
ArchMiscWindows::setInstanceWin32(GetModuleHandle(NULL));
#endif

View File

@ -6,16 +6,28 @@
*/
#include "arch/win32/ArchMiscWindows.h"
#include "arch/win32/ArchDaemonWindows.h"
#include "arch/win32/XArchWindows.h"
#include "base/Log.h"
#include "common/constants.h"
#include "base/String.h"
#include <Wtsapi32.h>
#pragma warning(disable : 4099)
#include <Userenv.h>
#pragma warning(default : 4099)
#include <array>
#if _MSC_VER >= 1942 // Visual Studio 2022 Update 12
const auto kRequiredMajor = 14;
const auto kRequiredMinor = 42;
const auto kRuntimeDll = "vcruntime140.dll";
#else
#pragma message("MSC version: " STRINGIFY(_MSC_VER))
#error "Unsupported MSC version"
#endif
// parent process name for services in Vista
#define SERVICE_LAUNCHER "services.exe"
@ -30,6 +42,11 @@
#endif
using EXECUTION_STATE = DWORD;
void errorMessageBox(const char *message, const char *title = "Fatal Error")
{
MessageBoxA(nullptr, message, title, MB_ICONERROR | MB_OK);
}
//
// ArchMiscWindows
//
@ -483,3 +500,54 @@ std::string ArchMiscWindows::getActiveDesktopName()
CloseDesktop(desk);
return name;
}
void ArchMiscWindows::guardRuntimeVersion() // NOSONAR - `noreturn` is not available
{
HMODULE hModule = nullptr;
if (!GetModuleHandleEx(0, kRuntimeDll, &hModule) && hModule) {
errorMessageBox("Microsoft Visual C++ Runtime is not installed.");
abort();
}
std::array<char, MAX_PATH> pathBuffer;
const auto path = pathBuffer.data();
if (!GetModuleFileNameA(hModule, path, MAX_PATH)) {
errorMessageBox("Failed to get the path of Microsoft Visual C++ Runtime.");
abort();
}
DWORD handle;
DWORD size = GetFileVersionInfoSizeA(path, &handle);
if (size <= 0) {
errorMessageBox("Failed to get the version info size for Microsoft Visual C++ Runtime.");
abort();
}
std::vector<BYTE> versionInfo(size);
if (!GetFileVersionInfoA(path, handle, size, versionInfo.data())) {
errorMessageBox("Failed to get the file version info for Microsoft Visual C++ Runtime.");
abort();
}
VS_FIXEDFILEINFO *fileInfo = nullptr;
const auto lplpFileInfo = reinterpret_cast<void **>(&fileInfo); // NOSONAR - Idiomatic Win32
if (UINT len = 0; !VerQueryValueA(versionInfo.data(), "\\", lplpFileInfo, &len)) {
errorMessageBox("Failed to get the version information for Microsoft Visual C++ Runtime.");
abort();
}
const auto currentMajor = HIWORD(fileInfo->dwFileVersionMS);
const auto currentMinor = LOWORD(fileInfo->dwFileVersionMS);
const auto currentBuild = HIWORD(fileInfo->dwFileVersionLS);
if (currentMajor < kRequiredMajor || currentMinor < kRequiredMinor) {
const auto message = deskflow::string::sprintf(
"Installed Microsoft Visual C++ Runtime v%d.%d.%d is outdated.\n\n"
"Minimum required version: v%d.%d\n\n"
"Please update to the latest Microsoft Visual C++ Redistributable.",
currentMajor, currentMinor, currentBuild, kRequiredMajor, kRequiredMinor
);
MessageBoxA(nullptr, message.c_str(), "Dependency Error", MB_ICONERROR | MB_OK);
exit(1);
}
}

View File

@ -157,6 +157,9 @@ public:
//! Returns true if we got the parent process name.
static bool getParentProcessName(std::string &name);
//! Prevent hard to troubleshoot errors, e.g. access violations.
static void guardRuntimeVersion();
static HINSTANCE instanceWin32();
static void setInstanceWin32(HINSTANCE instance);
static BOOL WINAPI getProcessEntry(PROCESSENTRY32 &entry, DWORD processID);