diff --git a/OptiScaler/State.h b/OptiScaler/State.h index a0c253fe..0b53716c 100644 --- a/OptiScaler/State.h +++ b/OptiScaler/State.h @@ -41,7 +41,9 @@ public: return instance; } - // Init flags + std::string GameName; + std::string GameExe; + // Used per feature // Reseting on creation of new feature std::optional AutoExposure; @@ -116,8 +118,8 @@ public: bool skipDxgiLoadChecks = false; // FSR3.x - std::vector fsr3xVersionNames; - std::vector fsr3xVersionIds; + std::vector fsr3xVersionNames{}; + std::vector fsr3xVersionIds{}; // Linux check bool isRunningOnLinux = false; diff --git a/OptiScaler/Util.cpp b/OptiScaler/Util.cpp index dedcf869..cdd2edbc 100644 --- a/OptiScaler/Util.cpp +++ b/OptiScaler/Util.cpp @@ -1,4 +1,5 @@ #include "pch.h" + #include "Util.h" #include "Config.h" @@ -7,6 +8,29 @@ extern HMODULE dllModule; typedef LONG(WINAPI* RtlGetVersionPtr)(PRTL_OSVERSIONINFOW); +typedef DWORD(*PFN_GetFileVersionInfoSizeW)(LPCWSTR lptstrFilename, LPDWORD lpdwHandle); +typedef BOOL(*PFN_GetFileVersionInfoW)(LPCWSTR lptstrFilename, DWORD dwHandle, DWORD dwLen, LPVOID lpData); +typedef BOOL(*PFN_VerQueryValueW)(LPCVOID pBlock, LPCWSTR lpSubBlock, LPVOID* lplpBuffer, PUINT puLen); + +std::wstring Util::GetWindowTitle(HWND hwnd) +{ + const int maxLength = 512; + wchar_t buffer[maxLength] = { 0 }; + + // First, check if the window is valid and visible + if (!IsWindow(hwnd) || !IsWindowVisible(hwnd)) + return L""; + + // Try to get the text using SendMessageTimeout to avoid hanging + LRESULT result = 0; + if (SendMessageTimeoutW(hwnd, WM_GETTEXT, (WPARAM)maxLength, (LPARAM)buffer, + SMTO_ABORTIFHUNG | SMTO_BLOCK, 2, (PDWORD_PTR)&result) != 0) + { + return std::wstring(buffer); + } + + return L""; +} bool Util::GetRealWindowsVersion(OSVERSIONINFOW& osInfo) { @@ -50,6 +74,55 @@ std::string Util::GetWindowsName(const OSVERSIONINFOW& os) return "Unknown Windows Version"; } +std::wstring Util::GetExeProductName() +{ + // In case of working ag version.dll + // Loading original dll from system + + wchar_t sysFolder[MAX_PATH]; + GetSystemDirectory(sysFolder, MAX_PATH); + std::filesystem::path sysPath(sysFolder); + + auto dll = LoadLibraryExW((sysPath / L"version.dll").c_str(), NULL, 0); + + if (dll == nullptr) + return L""; + + auto o_GetFileVersionInfoSizeW = (PFN_GetFileVersionInfoSizeW)GetProcAddress(dll, "GetFileVersionInfoSizeW"); + auto o_GetFileVersionInfoW = (PFN_GetFileVersionInfoW)GetProcAddress(dll, "GetFileVersionInfoW"); + auto o_VerQueryValueW = (PFN_VerQueryValueW)GetProcAddress(dll, "VerQueryValueW"); + + if (o_GetFileVersionInfoSizeW == nullptr || o_GetFileVersionInfoW == nullptr || o_VerQueryValueW == nullptr) + return L""; + + DWORD handle = 0; + DWORD versionSize = o_GetFileVersionInfoSizeW(Util::ExePath().c_str(), &handle); + if (versionSize == 0) + return L""; + + std::vector versionData(versionSize); + if (!o_GetFileVersionInfoW(Util::ExePath().c_str(), handle, versionSize, versionData.data())) + return L""; + + struct LANGANDCODEPAGE + { + WORD wLanguage; + WORD wCodePage; + } *lpTranslate; + + UINT cbTranslate = 0; + if (!o_VerQueryValueW(versionData.data(), L"\\VarFileInfo\\Translation", (LPVOID*)&lpTranslate, &cbTranslate)) + return L""; + + std::wstring query = L"\\StringFileInfo\\" + std::format(L"{:04x}{:04x}", lpTranslate[0].wLanguage, lpTranslate[0].wCodePage) + L"\\ProductName"; + LPWSTR productName = nullptr; + UINT size = 0; + if (o_VerQueryValueW(versionData.data(), query.c_str(), (LPVOID*)&productName, &size) && productName) + return productName; + + return L""; +} + std::filesystem::path Util::DllPath() { static std::filesystem::path dll; @@ -161,12 +234,12 @@ HWND Util::GetProcessWindow() { return hwnd; } -inline std::string LogLastError() +inline std::string LogLastError() { DWORD errorCode = GetLastError(); LPWSTR errorBuffer = nullptr; FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, errorCode, 0, (LPWSTR)&errorBuffer, 0, NULL); + NULL, errorCode, 0, (LPWSTR)&errorBuffer, 0, NULL); std::string result; @@ -185,56 +258,56 @@ inline std::string LogLastError() } bool Util::GetDLLVersion(std::wstring dllPath, version_t* versionOut) { - // Step 1: Get the size of the version information - DWORD handle = 0; - DWORD versionSize = GetFileVersionInfoSizeW(dllPath.c_str(), &handle); + // Step 1: Get the size of the version information + DWORD handle = 0; + DWORD versionSize = GetFileVersionInfoSizeW(dllPath.c_str(), &handle); - if (versionSize == 0) - { - //LOG_ERROR("Failed to get version info size: {0:X}", LogLastError()); - return false; - } - - // Step 2: Allocate buffer and get the version information - std::vector versionInfo(versionSize); - if (!GetFileVersionInfoW(dllPath.c_str(), handle, versionSize, versionInfo.data())) - { - //LOG_ERROR("Failed to get version info: {0:X}", LogLastError()); - return false; - } - - // Step 3: Extract the version information - VS_FIXEDFILEINFO* fileInfo = nullptr; - UINT size = 0; - if (!VerQueryValueW(versionInfo.data(), L"\\", reinterpret_cast(&fileInfo), &size)) { - //LOG_ERROR("Failed to query version value: {0:X}", LogLastError()); - return false; - } - - if (fileInfo != nullptr && versionOut != nullptr) { - // Extract major, minor, build, and revision numbers from version information - DWORD fileVersionMS = fileInfo->dwFileVersionMS; - DWORD fileVersionLS = fileInfo->dwFileVersionLS; - - versionOut->major = (fileVersionMS >> 16) & 0xffff; - versionOut->minor = (fileVersionMS >> 0) & 0xffff; - versionOut->patch = (fileVersionLS >> 16) & 0xffff; - versionOut->reserved = (fileVersionLS >> 0) & 0xffff; - } - else - { - LOG_ERROR("No version information found!"); + if (versionSize == 0) + { + //LOG_ERROR("Failed to get version info size: {0:X}", LogLastError()); return false; - } + } + + // Step 2: Allocate buffer and get the version information + std::vector versionInfo(versionSize); + if (!GetFileVersionInfoW(dllPath.c_str(), handle, versionSize, versionInfo.data())) + { + //LOG_ERROR("Failed to get version info: {0:X}", LogLastError()); + return false; + } + + // Step 3: Extract the version information + VS_FIXEDFILEINFO* fileInfo = nullptr; + UINT size = 0; + if (!VerQueryValueW(versionInfo.data(), L"\\", reinterpret_cast(&fileInfo), &size)) { + //LOG_ERROR("Failed to query version value: {0:X}", LogLastError()); + return false; + } + + if (fileInfo != nullptr && versionOut != nullptr) { + // Extract major, minor, build, and revision numbers from version information + DWORD fileVersionMS = fileInfo->dwFileVersionMS; + DWORD fileVersionLS = fileInfo->dwFileVersionLS; + + versionOut->major = (fileVersionMS >> 16) & 0xffff; + versionOut->minor = (fileVersionMS >> 0) & 0xffff; + versionOut->patch = (fileVersionLS >> 16) & 0xffff; + versionOut->reserved = (fileVersionLS >> 0) & 0xffff; + } + else + { + LOG_ERROR("No version information found!"); + return false; + } return true; } bool Util::GetDLLVersion(std::wstring dllPath, xess_version_t* xessVersionOut) { - version_t tempVersion; - auto result = Util::GetDLLVersion(dllPath, &tempVersion); + version_t tempVersion; + auto result = Util::GetDLLVersion(dllPath, &tempVersion); - // Don't assume that the structs are identical + // Don't assume that the structs are identical if (result) { xessVersionOut->major = tempVersion.major; xessVersionOut->minor = tempVersion.minor; diff --git a/OptiScaler/Util.h b/OptiScaler/Util.h index 2f616c59..42cb95a8 100644 --- a/OptiScaler/Util.h +++ b/OptiScaler/Util.h @@ -26,6 +26,8 @@ namespace Util bool GetDLLVersion(std::wstring dllPath, xess_version_t* versionOut); bool GetRealWindowsVersion(OSVERSIONINFOW& osInfo); std::string GetWindowsName(const OSVERSIONINFOW& os); + std::wstring GetExeProductName(); + std::wstring GetWindowTitle(HWND hwnd); }; inline void ThrowIfFailed(HRESULT hr) diff --git a/OptiScaler/dllmain.cpp b/OptiScaler/dllmain.cpp index 817af45b..66ea831d 100644 --- a/OptiScaler/dllmain.cpp +++ b/OptiScaler/dllmain.cpp @@ -674,10 +674,14 @@ static void CheckQuirks() { auto exePathFilename = Util::ExePath().filename().string(); + State::Instance().GameExe = exePathFilename; + State::Instance().GameName = wstring_to_string(Util::GetExeProductName()); + for (size_t i = 0; i < exePathFilename.size(); i++) exePathFilename[i] = std::tolower(exePathFilename[i]); LOG_INFO("Game's Exe: {0}", exePathFilename); + LOG_INFO("Game Name: {0}", State::Instance().GameName); if (exePathFilename == "cyberpunk2077.exe") { State::Instance().gameQuirk = Cyberpunk; @@ -851,6 +855,7 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserv spdlog::info("Windows version: {} ({}.{}.{})", Util::GetWindowsName(winVer), winVer.dwMajorVersion, winVer.dwMinorVersion, winVer.dwBuildNumber, winVer.dwPlatformId); else spdlog::warn("Can't read windows version"); + spdlog::info(""); CheckQuirks(); diff --git a/OptiScaler/menu/menu_common.cpp b/OptiScaler/menu/menu_common.cpp index de30a264..196cfbe9 100644 --- a/OptiScaler/menu/menu_common.cpp +++ b/OptiScaler/menu/menu_common.cpp @@ -23,6 +23,7 @@ static bool inputFps = false; static bool inputFpsCycle = false; static bool hasGamepad = false; static bool fsr31InitTried = false; +static std::string windowTitle; void MenuCommon::ShowTooltip(const char* tip) { if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) @@ -1123,7 +1124,7 @@ bool MenuCommon::RenderMenu() else { if (currentFeature != nullptr) - ImGui::Text("%s | FPS: %5.1f, Avg: %5.1f | %s -> %s %d.%d.%d", api.c_str(), frameRate, 1000.0f / averageFrameTime, State::Instance().currentInputApiName.c_str(), + ImGui::Text("%s | FPS: %5.1f, Avg: %5.1f | %s -> %s %d.%d.%d", api.c_str(), frameRate, 1000.0f / averageFrameTime, State::Instance().currentInputApiName.c_str(), currentFeature->Name(), State::Instance().currentFeature->Version().major, State::Instance().currentFeature->Version().minor, State::Instance().currentFeature->Version().patch); else ImGui::Text("%s | FPS: %5.1f, Avg: %5.1f", api.c_str(), frameRate, 1000.0f / averageFrameTime); @@ -1284,7 +1285,10 @@ bool MenuCommon::RenderMenu() ImGui::SetNextWindowSize(size); // Main menu window - if (ImGui::Begin(VER_PRODUCT_NAME, NULL, flags)) + if (windowTitle.empty()) + windowTitle = std::format("{} - {} {}", VER_PRODUCT_NAME, State::Instance().GameExe, State::Instance().GameName.empty() ? "" : std::format("- {}", State::Instance().GameName)); + + if (ImGui::Begin(windowTitle.c_str(), NULL, flags)) { bool rcasEnabled = false;