fix: Guard MSVC runtime version depending on compiler version
This commit is contained in:
parent
a7ce936d68
commit
495331108b
6 changed files with 79 additions and 2 deletions
|
|
@ -11,7 +11,7 @@ macro(configure_libs)
|
||||||
find_package(Python REQUIRED QUIET)
|
find_package(Python REQUIRED QUIET)
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP /D _BIND_TO_CURRENT_VCLIBS_VERSION=1")
|
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")
|
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(
|
add_definitions(
|
||||||
/DWIN32
|
/DWIN32
|
||||||
/D_WINDOWS
|
/D_WINDOWS
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,8 @@
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
#if SYSAPI_WIN32
|
#if SYSAPI_WIN32
|
||||||
|
ArchMiscWindows::guardRuntimeVersion();
|
||||||
|
|
||||||
// record window instance for tray icon, etc
|
// record window instance for tray icon, etc
|
||||||
ArchMiscWindows::setInstanceWin32(GetModuleHandle(NULL));
|
ArchMiscWindows::setInstanceWin32(GetModuleHandle(NULL));
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,8 @@ void handleError(const char *message);
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
#if SYSAPI_WIN32
|
#if SYSAPI_WIN32
|
||||||
|
ArchMiscWindows::guardRuntimeVersion();
|
||||||
|
|
||||||
// Save window instance for later use, e.g. `GetModuleFileName` which is used when installing the daemon.
|
// Save window instance for later use, e.g. `GetModuleFileName` which is used when installing the daemon.
|
||||||
ArchMiscWindows::setInstanceWin32(GetModuleHandle(nullptr));
|
ArchMiscWindows::setInstanceWin32(GetModuleHandle(nullptr));
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,8 @@
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
#if SYSAPI_WIN32
|
#if SYSAPI_WIN32
|
||||||
|
ArchMiscWindows::guardRuntimeVersion();
|
||||||
|
|
||||||
// record window instance for tray icon, etc
|
// record window instance for tray icon, etc
|
||||||
ArchMiscWindows::setInstanceWin32(GetModuleHandle(NULL));
|
ArchMiscWindows::setInstanceWin32(GetModuleHandle(NULL));
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -6,16 +6,28 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "arch/win32/ArchMiscWindows.h"
|
#include "arch/win32/ArchMiscWindows.h"
|
||||||
|
|
||||||
#include "arch/win32/ArchDaemonWindows.h"
|
#include "arch/win32/ArchDaemonWindows.h"
|
||||||
#include "arch/win32/XArchWindows.h"
|
#include "arch/win32/XArchWindows.h"
|
||||||
#include "base/Log.h"
|
#include "base/Log.h"
|
||||||
#include "common/constants.h"
|
#include "base/String.h"
|
||||||
|
|
||||||
#include <Wtsapi32.h>
|
#include <Wtsapi32.h>
|
||||||
#pragma warning(disable : 4099)
|
#pragma warning(disable : 4099)
|
||||||
#include <Userenv.h>
|
#include <Userenv.h>
|
||||||
#pragma warning(default : 4099)
|
#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
|
// parent process name for services in Vista
|
||||||
#define SERVICE_LAUNCHER "services.exe"
|
#define SERVICE_LAUNCHER "services.exe"
|
||||||
|
|
||||||
|
|
@ -30,6 +42,11 @@
|
||||||
#endif
|
#endif
|
||||||
using EXECUTION_STATE = DWORD;
|
using EXECUTION_STATE = DWORD;
|
||||||
|
|
||||||
|
void errorMessageBox(const char *message, const char *title = "Fatal Error")
|
||||||
|
{
|
||||||
|
MessageBoxA(nullptr, message, title, MB_ICONERROR | MB_OK);
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// ArchMiscWindows
|
// ArchMiscWindows
|
||||||
//
|
//
|
||||||
|
|
@ -483,3 +500,54 @@ std::string ArchMiscWindows::getActiveDesktopName()
|
||||||
CloseDesktop(desk);
|
CloseDesktop(desk);
|
||||||
return name;
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -157,6 +157,9 @@ public:
|
||||||
//! Returns true if we got the parent process name.
|
//! Returns true if we got the parent process name.
|
||||||
static bool getParentProcessName(std::string &name);
|
static bool getParentProcessName(std::string &name);
|
||||||
|
|
||||||
|
//! Prevent hard to troubleshoot errors, e.g. access violations.
|
||||||
|
static void guardRuntimeVersion();
|
||||||
|
|
||||||
static HINSTANCE instanceWin32();
|
static HINSTANCE instanceWin32();
|
||||||
static void setInstanceWin32(HINSTANCE instance);
|
static void setInstanceWin32(HINSTANCE instance);
|
||||||
static BOOL WINAPI getProcessEntry(PROCESSENTRY32 &entry, DWORD processID);
|
static BOOL WINAPI getProcessEntry(PROCESSENTRY32 &entry, DWORD processID);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue