Check if CRT version is at least 14.40.33816.0 (#2361)

* Check if CRT version is at least 14.40.33816.0

* Fix ULD path

* Remove debugging code
This commit is contained in:
srkizer 2025-08-10 23:56:22 +09:00 committed by GitHub
parent 4413634508
commit 8fcf633f02
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 91 additions and 11 deletions

View file

@ -13,9 +13,86 @@
HMODULE g_hModule;
HINSTANCE g_hGameInstance = GetModuleHandleW(nullptr);
void CheckMsvcrtVersion() {
constexpr WORD RequiredMsvcrtVersionComponents[] = {14, 40, 33816, 0};
constexpr auto RequiredMsvcrtVersion = 0ULL
| (static_cast<uint64_t>(RequiredMsvcrtVersionComponents[0]) << 48)
| (static_cast<uint64_t>(RequiredMsvcrtVersionComponents[1]) << 32)
| (static_cast<uint64_t>(RequiredMsvcrtVersionComponents[2]) << 16)
| (static_cast<uint64_t>(RequiredMsvcrtVersionComponents[3]) << 0);
#ifdef _DEBUG
constexpr const wchar_t* RuntimeDllNames[] = {
L"msvcp140d.dll",
L"vcruntime140d.dll",
L"vcruntime140_1d.dll",
};
#else
constexpr const wchar_t* RuntimeDllNames[] = {
L"msvcp140.dll",
L"vcruntime140.dll",
L"vcruntime140_1.dll",
};
#endif
uint64_t lowestVersion = 0;
for (const auto& runtimeDllName : RuntimeDllNames) {
const utils::loaded_module mod(GetModuleHandleW(runtimeDllName));
if (!mod) {
logging::E("Runtime DLL not found: {}", runtimeDllName);
continue;
}
const auto& versionFull = mod.get_file_version();
logging::I("Runtime DLL {} has version {}.", runtimeDllName, utils::format_file_version(versionFull));
const auto version = (static_cast<uint64_t>(versionFull.dwFileVersionMS) << 32) |
static_cast<uint64_t>(versionFull.dwFileVersionLS);
// Commit introducing inline mutex ctor: tagged vs-2022-17.14 (2024-06-18)
// - https://github.com/microsoft/STL/commit/22a88260db4d754bbc067e2002430144d6ec5391
// MSVC Redist versions:
// - https://github.com/abbodi1406/vcredist/blob/master/source_links/README.md
// - 14.40.33810.0 dsig 2024-04-28
// - 14.40.33816.0 dsig 2024-09-11
if (version < RequiredMsvcrtVersion && (lowestVersion == 0 || lowestVersion > version))
lowestVersion = version;
}
if (lowestVersion) {
switch (MessageBoxW(
nullptr,
L"Microsoft Visual C++ Redistributable should be updated, or Dalamud may not work as expected."
L" Do you want to download and install the latest version from Microsoft?"
L"\n"
L"\n* Clicking \"Yes\" will exit the game and open the download page from Microsoft."
L"\n* Clicking \"No\" will continue loading the game with Dalamud. This may fail."
L"\n"
L"\nClick \"X64\" from the table in the download page, regardless of what CPU you have.",
L"Dalamud",
MB_YESNO | MB_ICONWARNING)) {
case IDYES:
ShellExecuteW(
nullptr,
L"open",
L"https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist?view=msvc-170#latest-microsoft-visual-c-redistributable-version",
nullptr,
nullptr,
SW_SHOW);
ExitProcess(0);
break;
case IDNO:
break;
}
}
}
HRESULT WINAPI InitializeImpl(LPVOID lpParam, HANDLE hMainThreadContinue) {
g_startInfo.from_envvars();
CheckMsvcrtVersion();
std::string jsonParseError;
try {
from_json(nlohmann::json::parse(std::string_view(static_cast<char*>(lpParam))), g_startInfo);

View file

@ -11,6 +11,9 @@
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
// https://developercommunity.visualstudio.com/t/Access-violation-with-std::mutex::lock-a/10664660
#define _DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR
// Windows Header Files (1)
#include <Windows.h>
@ -21,6 +24,7 @@
#include <iphlpapi.h>
#include <PathCch.h>
#include <Psapi.h>
#include <shellapi.h>
#include <ShlObj.h>
#include <Shlwapi.h>
#include <SubAuth.h>

View file

@ -148,7 +148,7 @@ std::unique_ptr<std::remove_pointer_t<HGLOBAL>, decltype(&FreeResource)> utils::
const auto hres = FindResourceW(m_hModule, lpName, lpType);
if (!hres)
throw std::runtime_error("No such resource");
const auto hRes = LoadResource(m_hModule, hres);
if (!hRes)
throw std::runtime_error("LoadResource failure");
@ -159,7 +159,7 @@ std::unique_ptr<std::remove_pointer_t<HGLOBAL>, decltype(&FreeResource)> utils::
std::wstring utils::loaded_module::get_description() const {
const auto rsrc = get_resource(MAKEINTRESOURCE(VS_VERSION_INFO), RT_VERSION);
const auto pBlock = LockResource(rsrc.get());
struct LANGANDCODEPAGE {
WORD wLanguage;
WORD wCodePage;
@ -190,11 +190,11 @@ std::wstring utils::loaded_module::get_description() const {
continue;
return std::wstring(currName);
}
throw std::runtime_error("Invalid version information (2)");
}
VS_FIXEDFILEINFO utils::loaded_module::get_file_version() const {
const VS_FIXEDFILEINFO& utils::loaded_module::get_file_version() const {
const auto rsrc = get_resource(MAKEINTRESOURCE(VS_VERSION_INFO), RT_VERSION);
const auto pBlock = LockResource(rsrc.get());
UINT size = 0;
@ -353,7 +353,7 @@ const char* utils::signature_finder::result::resolve_jump_target(size_t instruct
nmd_x86_instruction instruction{};
if (!nmd_x86_decode(&Match[instructionOffset], NMD_X86_MAXIMUM_INSTRUCTION_LENGTH, &instruction, NMD_X86_MODE_64, NMD_X86_DECODER_FLAGS_ALL))
throw std::runtime_error("Matched address does not have a valid assembly instruction");
size_t numExplicitOperands = 0;
for (size_t i = 0; i < instruction.num_operands; i++)
numExplicitOperands += instruction.operands[i].is_implicit ? 0 : 1;
@ -625,7 +625,7 @@ void utils::wait_for_game_window() {
std::wstring utils::escape_shell_arg(const std::wstring& arg) {
// https://docs.microsoft.com/en-us/archive/blogs/twistylittlepassagesallalike/everyone-quotes-command-line-arguments-the-wrong-way
std::wstring res;
if (!arg.empty() && arg.find_first_of(L" \t\n\v\"") == std::wstring::npos) {
res.append(arg);

View file

@ -23,9 +23,8 @@ namespace utils {
bool is_current_process() const { return m_hModule == GetModuleHandleW(nullptr); }
bool owns_address(const void* pAddress) const;
operator HMODULE() const {
return m_hModule;
}
operator HMODULE() const { return m_hModule; }
operator bool() const { return m_hModule; }
size_t address_int() const { return reinterpret_cast<size_t>(m_hModule); }
size_t image_size() const { return is_pe64() ? nt_header64().OptionalHeader.SizeOfImage : nt_header32().OptionalHeader.SizeOfImage; }
@ -60,7 +59,7 @@ namespace utils {
[[nodiscard]] std::unique_ptr<std::remove_pointer_t<HGLOBAL>, decltype(&FreeResource)> get_resource(LPCWSTR lpName, LPCWSTR lpType) const;
[[nodiscard]] std::wstring get_description() const;
[[nodiscard]] VS_FIXEDFILEINFO get_file_version() const;
[[nodiscard]] const VS_FIXEDFILEINFO& get_file_version() const;
static loaded_module current_process();
static std::vector<loaded_module> all_modules();