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

@ -194,7 +194,7 @@ std::wstring utils::loaded_module::get_description() const {
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;

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();

View file

@ -27,7 +27,7 @@ internal class UldWidget : IDataWindowWidget
{
// ULD styles can be hardcoded for now as they don't add new ones regularly. Can later try and find where to load these from in the game EXE.
private static readonly string[] ThemeDisplayNames = ["Dark", "Light", "Classic FF", "Clear Blue"];
private static readonly string[] ThemeBasePaths = ["ui/uld/", "ui/uld/light/", "ui/uld/third/", "ui/uld/fourth/"];
private static readonly string[] ThemeBasePaths = ["ui/uld/", "ui/uld/img01/", "ui/uld/img02/", "ui/uld/img03/"];
// 48 8D 15 ?? ?? ?? ?? is the part of the signatures that contain the string location offset
// 48 = 64 bit register prefix