mirror of
https://github.com/goatcorp/Dalamud.git
synced 2025-12-12 10:17:22 +01:00
Fix nullptr problems (#878)
This commit is contained in:
parent
74966fc4ef
commit
71f3680388
11 changed files with 161 additions and 84 deletions
|
|
@ -16,7 +16,7 @@ DllExport DWORD WINAPI Initialize(LPVOID lpParam, HANDLE hMainThreadContinue) {
|
|||
logging::print<logging::I>("No log file path given; not logging to file.");
|
||||
else {
|
||||
try {
|
||||
logging::start_file_logging(logFilePath);
|
||||
logging::start_file_logging(logFilePath, !bootconfig::is_show_console());
|
||||
logging::print<logging::I>(L"Logging to file: {}", logFilePath);
|
||||
} catch (const std::exception& e) {
|
||||
logging::print<logging::E>(L"Couldn't open log file: {}", logFilePath);
|
||||
|
|
@ -84,6 +84,13 @@ DllExport DWORD WINAPI Initialize(LPVOID lpParam, HANDLE hMainThreadContinue) {
|
|||
if (bootconfig::wait_messagebox() & bootconfig::WaitMessageboxFlags::BeforeDalamudEntrypoint)
|
||||
MessageBoxW(nullptr, L"Press OK to continue", L"Dalamud Boot", MB_OK);
|
||||
|
||||
if (hMainThreadContinue) {
|
||||
// Let the game initialize.
|
||||
SetEvent(hMainThreadContinue);
|
||||
}
|
||||
|
||||
utils::wait_for_game_window();
|
||||
|
||||
logging::print<logging::I>("Initializing Dalamud...");
|
||||
entrypoint_fn(lpParam, hMainThreadContinue);
|
||||
logging::print<logging::I>("Done!");
|
||||
|
|
|
|||
|
|
@ -37,14 +37,15 @@ static const auto LdrUnregisterDllNotification = utils::loaded_module(GetModuleH
|
|||
|
||||
hooks::getprocaddress_singleton_import_hook::getprocaddress_singleton_import_hook()
|
||||
: m_pfnGetProcAddress(GetProcAddress)
|
||||
, m_thunk([this](HMODULE hModule, LPCSTR lpProcName) { return get_proc_address_handler(hModule, lpProcName); }) {
|
||||
, m_thunk("kernel32!GetProcAddress(Singleton Import Hook)",
|
||||
[this](HMODULE hModule, LPCSTR lpProcName) { return get_proc_address_handler(hModule, lpProcName); }) {
|
||||
}
|
||||
|
||||
hooks::getprocaddress_singleton_import_hook::~getprocaddress_singleton_import_hook() {
|
||||
LdrUnregisterDllNotification(m_ldrDllNotificationCookie);
|
||||
}
|
||||
|
||||
std::shared_ptr<void> hooks::getprocaddress_singleton_import_hook::set_handler(std::wstring dllName, std::string functionName, void* pfnDetour) {
|
||||
std::shared_ptr<void> hooks::getprocaddress_singleton_import_hook::set_handler(std::wstring dllName, std::string functionName, void* pfnDetour, std::function<void(void*)> fnOnOriginalAddressAvailable) {
|
||||
const auto hModule = GetModuleHandleW(dllName.c_str());
|
||||
if (!hModule)
|
||||
throw std::out_of_range("Specified DLL is not found.");
|
||||
|
|
@ -53,6 +54,8 @@ std::shared_ptr<void> hooks::getprocaddress_singleton_import_hook::set_handler(s
|
|||
if (!pfn)
|
||||
throw std::out_of_range("Could not find the specified function.");
|
||||
|
||||
fnOnOriginalAddressAvailable(pfn);
|
||||
|
||||
auto& target = m_targetFns[hModule][functionName];
|
||||
if (target)
|
||||
throw std::runtime_error("Specified function has already been hooked.");
|
||||
|
|
@ -95,7 +98,7 @@ std::shared_ptr<hooks::getprocaddress_singleton_import_hook> hooks::getprocaddre
|
|||
}
|
||||
|
||||
void hooks::getprocaddress_singleton_import_hook::initialize() {
|
||||
m_getProcAddressHandler = set_handler(L"kernel32.dll", "GetProcAddress", m_thunk.get_thunk());
|
||||
m_getProcAddressHandler = set_handler(L"kernel32.dll", "GetProcAddress", m_thunk.get_thunk(), [this](void*) {});
|
||||
|
||||
LdrRegisterDllNotification(0, [](ULONG notiReason, const LDR_DLL_NOTIFICATION_DATA* pData, void* context) {
|
||||
if (notiReason == LDR_DLL_NOTIFICATION_REASON_LOADED) {
|
||||
|
|
@ -138,7 +141,7 @@ void hooks::getprocaddress_singleton_import_hook::hook_module(const utils::loade
|
|||
if (!hook) {
|
||||
logging::print<logging::I>("{} Hooking {}!{} imported by {}", LogTag, dllName, targetFn, unicode::convert<std::string>(mod.path().wstring()));
|
||||
|
||||
hook.emplace(static_cast<void**>(pGetProcAddressImport), pfnThunk);
|
||||
hook.emplace(std::format("getprocaddress_singleton_import_hook::hook_module({}!{})", dllName, targetFn), static_cast<void**>(pGetProcAddressImport), pfnThunk);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,8 +7,23 @@
|
|||
|
||||
namespace hooks {
|
||||
class base_untyped_hook {
|
||||
std::string m_name;
|
||||
|
||||
public:
|
||||
base_untyped_hook(std::string name) : m_name(name) {}
|
||||
|
||||
virtual ~base_untyped_hook() = default;
|
||||
|
||||
virtual bool check_consistencies() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void assert_dominance() const {
|
||||
}
|
||||
|
||||
const std::string& name() const {
|
||||
return m_name;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename>
|
||||
|
|
@ -23,9 +38,10 @@ namespace hooks {
|
|||
utils::thunk<TReturn(TArgs...)> m_thunk;
|
||||
|
||||
public:
|
||||
base_hook(TFn* pfnOriginal)
|
||||
: m_pfnOriginal(pfnOriginal)
|
||||
, m_thunk(m_pfnOriginal) {
|
||||
base_hook(std::string name, TFn* pfnOriginal)
|
||||
: base_untyped_hook(name)
|
||||
, m_pfnOriginal(pfnOriginal)
|
||||
, m_thunk(std::move(name), m_pfnOriginal) {
|
||||
}
|
||||
|
||||
virtual void set_detour(std::function<TFn> fn) {
|
||||
|
|
@ -56,23 +72,34 @@ namespace hooks {
|
|||
TFn** const m_ppfnImportTableItem;
|
||||
|
||||
public:
|
||||
import_hook(TFn** ppfnImportTableItem)
|
||||
: Base(*ppfnImportTableItem)
|
||||
import_hook(std::string name, TFn** ppfnImportTableItem)
|
||||
: Base(std::move(name), *ppfnImportTableItem)
|
||||
, m_ppfnImportTableItem(ppfnImportTableItem) {
|
||||
|
||||
const utils::memory_tenderizer tenderizer(ppfnImportTableItem, sizeof * ppfnImportTableItem, PAGE_READWRITE);
|
||||
*ppfnImportTableItem = Base::get_thunk();
|
||||
}
|
||||
|
||||
import_hook(const char* pcszDllName, const char* pcszFunctionName, int hintOrOrdinal)
|
||||
: import_hook(utils::loaded_module::current_process().get_imported_function_pointer<TFn>(pcszDllName, pcszFunctionName, hintOrOrdinal)) {
|
||||
import_hook(std::string name, const char* pcszDllName, const char* pcszFunctionName, int hintOrOrdinal)
|
||||
: import_hook(std::move(name), utils::loaded_module::current_process().get_imported_function_pointer<TFn>(pcszDllName, pcszFunctionName, hintOrOrdinal)) {
|
||||
}
|
||||
|
||||
~import_hook() override {
|
||||
const utils::memory_tenderizer tenderizer(m_ppfnImportTableItem, sizeof * m_ppfnImportTableItem, PAGE_READWRITE);
|
||||
|
||||
*m_ppfnImportTableItem = Base::get_original();
|
||||
}
|
||||
|
||||
bool check_consistencies() const override {
|
||||
return *m_ppfnImportTableItem == Base::get_thunk();
|
||||
}
|
||||
|
||||
void assert_dominance() const override {
|
||||
if (check_consistencies())
|
||||
return;
|
||||
|
||||
const utils::memory_tenderizer tenderizer(m_ppfnImportTableItem, sizeof * m_ppfnImportTableItem, PAGE_READWRITE);
|
||||
*m_ppfnImportTableItem = Base::get_thunk();
|
||||
}
|
||||
};
|
||||
|
||||
template<typename>
|
||||
|
|
@ -86,8 +113,8 @@ namespace hooks {
|
|||
TFn* m_pfnMinHookBridge;
|
||||
|
||||
public:
|
||||
direct_hook(TFn* pfnFunction)
|
||||
: Base(pfnFunction) {
|
||||
direct_hook(std::string name, TFn* pfnFunction)
|
||||
: Base(std::move(name), pfnFunction) {
|
||||
if (const auto mhStatus = MH_CreateHook(pfnFunction, Base::get_thunk(), reinterpret_cast<void**>(&m_pfnMinHookBridge)); mhStatus != MH_OK)
|
||||
throw std::runtime_error(std::format("MH_CreateHook(0x{:X}, ...) failure: {}", reinterpret_cast<size_t>(pfnFunction), static_cast<int>(mhStatus)));
|
||||
|
||||
|
|
@ -106,22 +133,33 @@ namespace hooks {
|
|||
class wndproc_hook : public base_hook<std::remove_pointer_t<WNDPROC>> {
|
||||
using Base = base_hook<std::remove_pointer_t<WNDPROC>>;
|
||||
|
||||
const HWND s_hwnd;
|
||||
const HWND m_hwnd;
|
||||
|
||||
public:
|
||||
wndproc_hook(HWND hwnd)
|
||||
: Base(reinterpret_cast<WNDPROC>(GetWindowLongPtrW(hwnd, GWLP_WNDPROC)))
|
||||
, s_hwnd(hwnd) {
|
||||
wndproc_hook(std::string name, HWND hwnd)
|
||||
: Base(std::move(name), reinterpret_cast<WNDPROC>(GetWindowLongPtrW(hwnd, GWLP_WNDPROC)))
|
||||
, m_hwnd(hwnd) {
|
||||
SetWindowLongPtrW(hwnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(Base::get_thunk()));
|
||||
}
|
||||
|
||||
~wndproc_hook() override {
|
||||
SetWindowLongPtrW(s_hwnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(Base::get_original()));
|
||||
SetWindowLongPtrW(m_hwnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(Base::get_original()));
|
||||
}
|
||||
|
||||
LRESULT call_original(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) override {
|
||||
return CallWindowProcW(Base::get_original(), hwnd, msg, wParam, lParam);
|
||||
}
|
||||
|
||||
bool check_consistencies() const override {
|
||||
return GetWindowLongPtrW(m_hwnd, GWLP_WNDPROC) == reinterpret_cast<LONG_PTR>(Base::get_thunk());
|
||||
}
|
||||
|
||||
void assert_dominance() const override {
|
||||
if (check_consistencies())
|
||||
return;
|
||||
|
||||
SetWindowLongPtrW(m_hwnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(Base::get_thunk()));
|
||||
}
|
||||
};
|
||||
|
||||
class untyped_import_hook : public base_untyped_hook {
|
||||
|
|
@ -129,8 +167,9 @@ namespace hooks {
|
|||
void* const m_pfnOriginalImport;
|
||||
|
||||
public:
|
||||
untyped_import_hook(void** ppfnImportTableItem, void* pThunk)
|
||||
: m_pfnOriginalImport(*ppfnImportTableItem)
|
||||
untyped_import_hook(std::string name, void** ppfnImportTableItem, void* pThunk)
|
||||
: base_untyped_hook(std::move(name))
|
||||
, m_pfnOriginalImport(*ppfnImportTableItem)
|
||||
, m_ppfnImportTableItem(ppfnImportTableItem) {
|
||||
|
||||
const utils::memory_tenderizer tenderizer(ppfnImportTableItem, sizeof * ppfnImportTableItem, PAGE_READWRITE);
|
||||
|
|
@ -165,7 +204,7 @@ namespace hooks {
|
|||
getprocaddress_singleton_import_hook();
|
||||
~getprocaddress_singleton_import_hook();
|
||||
|
||||
std::shared_ptr<void> set_handler(std::wstring dllName, std::string functionName, void* pfnDetour);
|
||||
std::shared_ptr<void> set_handler(std::wstring dllName, std::string functionName, void* pfnDetour, std::function<void(void*)> fnOnOriginalAddressAvailable);
|
||||
|
||||
static std::shared_ptr<getprocaddress_singleton_import_hook> get_instance();
|
||||
|
||||
|
|
@ -187,11 +226,16 @@ namespace hooks {
|
|||
std::shared_ptr<void> m_singleImportHook;
|
||||
|
||||
public:
|
||||
global_import_hook(std::wstring dllName, std::string functionName)
|
||||
: m_thunk(nullptr) {
|
||||
global_import_hook(std::string name, std::wstring dllName, std::string functionName)
|
||||
: base_untyped_hook(name)
|
||||
, m_thunk(std::move(name), nullptr) {
|
||||
|
||||
m_singleImportHook = getprocaddress_singleton_import_hook::get_instance()->set_handler(dllName, functionName, m_thunk.get_thunk());
|
||||
m_thunk.set_target(reinterpret_cast<TFn*>(m_singleImportHook.get()));
|
||||
m_singleImportHook = getprocaddress_singleton_import_hook::get_instance()->set_handler(
|
||||
dllName,
|
||||
functionName,
|
||||
m_thunk.get_thunk(),
|
||||
[this](void* p) { m_thunk.set_target(reinterpret_cast<TFn*>(p)); }
|
||||
);
|
||||
}
|
||||
|
||||
virtual void set_detour(std::function<TFn> fn) {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include "logging.h"
|
||||
|
||||
static bool s_bLoaded = false;
|
||||
static bool s_bSkipLogFileWrite = false;
|
||||
static std::shared_ptr<void> s_hLogFile;
|
||||
|
||||
void logging::print(Level level, const char* s) {
|
||||
|
|
@ -45,13 +46,13 @@ void logging::print(Level level, const char* s) {
|
|||
DWORD wr{};
|
||||
WriteFile(GetStdHandle(STD_ERROR_HANDLE), &estr[0], static_cast<DWORD>(estr.size()), &wr, nullptr);
|
||||
|
||||
if (s_hLogFile) {
|
||||
if (s_hLogFile && !s_bSkipLogFileWrite) {
|
||||
WriteFile(s_hLogFile.get(), &estr[0], static_cast<DWORD>(estr.size()), &wr, nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void logging::start_file_logging(const std::filesystem::path& path) {
|
||||
void logging::start_file_logging(const std::filesystem::path& path, bool redirect_stderrout) {
|
||||
if (s_hLogFile)
|
||||
return;
|
||||
|
||||
|
|
@ -76,6 +77,12 @@ void logging::start_file_logging(const std::filesystem::path& path) {
|
|||
|
||||
SetFilePointer(h, 0, 0, FILE_END);
|
||||
s_hLogFile = { h, &CloseHandle };
|
||||
|
||||
if (redirect_stderrout) {
|
||||
SetStdHandle(STD_ERROR_HANDLE, h);
|
||||
SetStdHandle(STD_OUTPUT_HANDLE, h);
|
||||
s_bSkipLogFileWrite = true;
|
||||
}
|
||||
}
|
||||
|
||||
void logging::update_dll_load_status(bool loaded) {
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ namespace logging {
|
|||
print(level, std::format(pcszFormat, std::forward<Arg>(arg1), std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
void start_file_logging(const std::filesystem::path& path);
|
||||
void start_file_logging(const std::filesystem::path& path, bool redirect_stderrout = false);
|
||||
|
||||
void update_dll_load_status(bool loaded);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <ranges>
|
||||
#include <set>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <mutex>
|
||||
|
|
|
|||
|
|
@ -241,20 +241,6 @@ void* get_mapped_image_base_address(HANDLE hProcess, const std::filesystem::path
|
|||
throw std::runtime_error("corresponding base address not found");
|
||||
}
|
||||
|
||||
/// @brief Find the game main window.
|
||||
/// @return Handle to the game main window, or nullptr if it doesn't exist (yet).
|
||||
HWND try_find_game_window() {
|
||||
HWND hwnd = nullptr;
|
||||
while ((hwnd = FindWindowExW(nullptr, hwnd, L"FFXIVGAME", nullptr))) {
|
||||
DWORD pid;
|
||||
GetWindowThreadProcessId(hwnd, &pid);
|
||||
|
||||
if (pid == GetCurrentProcessId() && IsWindowVisible(hwnd))
|
||||
break;
|
||||
}
|
||||
return hwnd;
|
||||
}
|
||||
|
||||
std::string from_utf16(const std::wstring& wstr, UINT codePage = CP_UTF8) {
|
||||
std::string str(WideCharToMultiByte(codePage, 0, &wstr[0], static_cast<int>(wstr.size()), nullptr, 0, nullptr, nullptr), 0);
|
||||
WideCharToMultiByte(codePage, 0, &wstr[0], static_cast<int>(wstr.size()), &str[0], static_cast<int>(str.size()), nullptr, nullptr);
|
||||
|
|
@ -360,15 +346,6 @@ DllExport DWORD WINAPI RewriteRemoteEntryPoint(HANDLE hProcess, const wchar_t* p
|
|||
return RewriteRemoteEntryPointW(hProcess, pcwzPath, to_utf16(pcszLoadInfo).c_str());
|
||||
}
|
||||
|
||||
void wait_for_game_window() {
|
||||
HWND game_window;
|
||||
while (!(game_window = try_find_game_window())) {
|
||||
WaitForInputIdle(GetCurrentProcess(), INFINITE);
|
||||
Sleep(100);
|
||||
};
|
||||
SendMessageW(game_window, WM_NULL, 0, 0);
|
||||
}
|
||||
|
||||
/// @brief Entry point function "called" instead of game's original main entry point.
|
||||
/// @param params Parameters set up from RewriteRemoteEntryPoint.
|
||||
DllExport void WINAPI RewrittenEntryPoint(RewrittenEntryPointParameters& params) {
|
||||
|
|
@ -383,21 +360,14 @@ DllExport void WINAPI RewrittenEntryPoint(RewrittenEntryPointParameters& params)
|
|||
std::string loadInfo;
|
||||
auto& params = *reinterpret_cast<RewrittenEntryPointParameters*>(p);
|
||||
{
|
||||
|
||||
|
||||
// Restore original entry point.
|
||||
// Use WriteProcessMemory instead of memcpy to avoid having to fiddle with VirtualProtect.
|
||||
write_process_memory_or_throw(GetCurrentProcess(), params.pEntrypoint, params.pEntrypointBytes, params.entrypointLength);
|
||||
|
||||
// Make a copy of load info, as the whole params will be freed after this code block.
|
||||
loadInfo = params.pLoadInfo;
|
||||
|
||||
// Let the game initialize.
|
||||
SetEvent(params.hMainThreadContinue);
|
||||
}
|
||||
|
||||
wait_for_game_window();
|
||||
|
||||
Initialize(&loadInfo[0], params.hMainThreadContinue);
|
||||
return 0;
|
||||
} catch (const std::exception& e) {
|
||||
|
|
|
|||
|
|
@ -488,3 +488,24 @@ std::filesystem::path utils::get_module_path(HMODULE hModule) {
|
|||
buf.resize(buf.size() * 2);
|
||||
}
|
||||
}
|
||||
|
||||
HWND utils::try_find_game_window() {
|
||||
HWND hwnd = nullptr;
|
||||
while ((hwnd = FindWindowExW(nullptr, hwnd, L"FFXIVGAME", nullptr))) {
|
||||
DWORD pid;
|
||||
GetWindowThreadProcessId(hwnd, &pid);
|
||||
|
||||
if (pid == GetCurrentProcessId() && IsWindowVisible(hwnd))
|
||||
break;
|
||||
}
|
||||
return hwnd;
|
||||
}
|
||||
|
||||
void utils::wait_for_game_window() {
|
||||
HWND game_window;
|
||||
while (!(game_window = try_find_game_window())) {
|
||||
WaitForInputIdle(GetCurrentProcess(), INFINITE);
|
||||
Sleep(100);
|
||||
};
|
||||
SendMessageW(game_window, WM_NULL, 0, 0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -137,12 +137,14 @@ namespace utils {
|
|||
static constexpr uint64_t Placeholder = 0xCC90CC90CC90CC90ULL;
|
||||
|
||||
const std::shared_ptr<void> m_pThunk;
|
||||
std::string m_name;
|
||||
std::function<TFn> m_fnTarget;
|
||||
|
||||
public:
|
||||
thunk(std::function<TFn> target)
|
||||
thunk(std::string name, std::function<TFn> target)
|
||||
: m_pThunk(utils::create_thunk(&detour_static, this, Placeholder))
|
||||
, m_fnTarget(std::move(target)) {
|
||||
, m_fnTarget(std::move(target))
|
||||
, m_name(name) {
|
||||
}
|
||||
|
||||
void set_target(std::function<TFn> detour) {
|
||||
|
|
@ -153,6 +155,10 @@ namespace utils {
|
|||
return reinterpret_cast<TFn*>(m_pThunk.get());
|
||||
}
|
||||
|
||||
const std::string& name() const {
|
||||
return m_name;
|
||||
}
|
||||
|
||||
private:
|
||||
// mark it as virtual to prevent compiler from inlining
|
||||
virtual TReturn detour(TArgs... args) {
|
||||
|
|
@ -249,4 +255,10 @@ namespace utils {
|
|||
bool is_running_on_linux();
|
||||
|
||||
std::filesystem::path get_module_path(HMODULE hModule);
|
||||
|
||||
/// @brief Find the game main window.
|
||||
/// @return Handle to the game main window, or nullptr if it doesn't exist (yet).
|
||||
HWND try_find_game_window();
|
||||
|
||||
void wait_for_game_window();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -184,7 +184,7 @@ void xivfixes::prevent_devicechange_crashes(bool bApply) {
|
|||
return;
|
||||
}
|
||||
|
||||
s_hookCreateWindowExA.emplace("user32.dll", "CreateWindowExA", 0);
|
||||
s_hookCreateWindowExA.emplace("user32.dll!CreateWindowExA (prevent_devicechange_crashes)", "user32.dll", "CreateWindowExA", 0);
|
||||
s_hookCreateWindowExA->set_detour([](DWORD dwExStyle, LPCSTR lpClassName, LPCSTR lpWindowName, DWORD dwStyle, int X, int Y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam)->HWND {
|
||||
const auto hWnd = s_hookCreateWindowExA->call_original(dwExStyle, lpClassName, lpWindowName, dwStyle, X, Y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam);
|
||||
|
||||
|
|
@ -198,7 +198,7 @@ void xivfixes::prevent_devicechange_crashes(bool bApply) {
|
|||
|
||||
s_hookCreateWindowExA.reset();
|
||||
|
||||
s_hookWndProc.emplace(hWnd);
|
||||
s_hookWndProc.emplace("FFXIVGAME:WndProc (prevent_devicechange_crashes)", hWnd);
|
||||
s_hookWndProc->set_detour([](HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -> LRESULT {
|
||||
if (uMsg == WM_DEVICECHANGE && wParam == DBT_DEVNODES_CHANGED) {
|
||||
if (!GetGetInputDeviceManager(hWnd)()) {
|
||||
|
|
@ -239,7 +239,7 @@ void xivfixes::disable_game_openprocess_access_check(bool bApply) {
|
|||
return;
|
||||
}
|
||||
|
||||
s_hook.emplace("kernel32.dll", "OpenProcess", 0);
|
||||
s_hook.emplace("kernel32.dll!OpenProcess (import, disable_game_openprocess_access_check)", "kernel32.dll", "OpenProcess", 0);
|
||||
s_hook->set_detour([](DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId)->HANDLE {
|
||||
logging::print<logging::I>("{} OpenProcess(0x{:08X}, {}, {}) was invoked by thread {}.", LogTag, dwDesiredAccess, bInheritHandle, dwProcessId, GetCurrentThreadId());
|
||||
|
||||
|
|
@ -267,6 +267,8 @@ void xivfixes::disable_game_openprocess_access_check(bool bApply) {
|
|||
void xivfixes::redirect_openprocess(bool bApply) {
|
||||
static const char* LogTag = "[xivfixes:redirect_openprocess]";
|
||||
static std::shared_ptr<hooks::base_untyped_hook> s_hook;
|
||||
static std::mutex s_silenceSetMtx;
|
||||
static std::set<DWORD> s_silenceSet;
|
||||
|
||||
if (bApply) {
|
||||
if (!bootconfig::gamefix_is_enabled(L"redirect_openprocess")) {
|
||||
|
|
@ -275,9 +277,10 @@ void xivfixes::redirect_openprocess(bool bApply) {
|
|||
}
|
||||
|
||||
if (bootconfig::dotnet_openprocess_hook_mode() == bootconfig::ImportHooks) {
|
||||
auto hook = std::make_shared<hooks::global_import_hook<decltype(OpenProcess)>>(L"kernel32.dll", "OpenProcess");
|
||||
auto hook = std::make_shared<hooks::global_import_hook<decltype(OpenProcess)>>("kernel32.dll!OpenProcess (global import, redirect_openprocess)", L"kernel32.dll", "OpenProcess");
|
||||
hook->set_detour([hook = hook.get()](DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId)->HANDLE {
|
||||
if (dwProcessId == GetCurrentProcessId()) {
|
||||
if (s_silenceSet.emplace(GetCurrentThreadId()).second)
|
||||
logging::print<logging::I>("{} OpenProcess(0x{:08X}, {}, {}) was invoked by thread {}. Redirecting to DuplicateHandle.", LogTag, dwDesiredAccess, bInheritHandle, dwProcessId, GetCurrentThreadId());
|
||||
|
||||
if (HANDLE res; DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(), GetCurrentProcess(), &res, dwDesiredAccess, bInheritHandle, 0))
|
||||
|
|
@ -292,9 +295,10 @@ void xivfixes::redirect_openprocess(bool bApply) {
|
|||
logging::print<logging::I>("{} Enable via import_hook", LogTag);
|
||||
|
||||
} else {
|
||||
auto hook = std::make_shared<hooks::direct_hook<decltype(OpenProcess)>>(OpenProcess);
|
||||
auto hook = std::make_shared<hooks::direct_hook<decltype(OpenProcess)>>("kernel32.dll!OpenProcess (direct, redirect_openprocess)", OpenProcess);
|
||||
hook->set_detour([hook = hook.get()](DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId)->HANDLE {
|
||||
if (dwProcessId == GetCurrentProcessId()) {
|
||||
if (s_silenceSet.emplace(GetCurrentThreadId()).second)
|
||||
logging::print<logging::I>("{} OpenProcess(0x{:08X}, {}, {}) was invoked by thread {}. Redirecting to DuplicateHandle.", LogTag, dwDesiredAccess, bInheritHandle, dwProcessId, GetCurrentThreadId());
|
||||
|
||||
if (HANDLE res; DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(), GetCurrentProcess(), &res, dwDesiredAccess, bInheritHandle, 0))
|
||||
|
|
@ -309,6 +313,12 @@ void xivfixes::redirect_openprocess(bool bApply) {
|
|||
logging::print<logging::I>("{} Enable via direct_hook", LogTag);
|
||||
}
|
||||
|
||||
//std::thread([]() {
|
||||
// SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_IDLE);
|
||||
// for (const auto to = GetTickCount64() + 3000; GetTickCount64() < to;)
|
||||
// s_hook->assert_dominance();
|
||||
//}).detach();
|
||||
|
||||
} else {
|
||||
if (s_hook) {
|
||||
logging::print<logging::I>("{} Disable OpenProcess", LogTag);
|
||||
|
|
|
|||
|
|
@ -9,29 +9,31 @@ namespace Dalamud.Interface.GameFonts
|
|||
/// </summary>
|
||||
public class FdtReader
|
||||
{
|
||||
private static unsafe T StructureFromByteArray<T> (byte[] data, int offset)
|
||||
{
|
||||
var len = Marshal.SizeOf<T>();
|
||||
if (offset + len > data.Length)
|
||||
throw new Exception("Data too short");
|
||||
|
||||
fixed (byte* ptr = data)
|
||||
return Marshal.PtrToStructure<T>(new(ptr + offset));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FdtReader"/> class.
|
||||
/// </summary>
|
||||
/// <param name="data">Content of a FDT file.</param>
|
||||
public FdtReader(byte[] data)
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
fixed (byte* ptr = data)
|
||||
{
|
||||
this.FileHeader = *(FdtHeader*)ptr;
|
||||
this.FontHeader = *(FontTableHeader*)(ptr + this.FileHeader.FontTableHeaderOffset);
|
||||
this.KerningHeader = *(KerningTableHeader*)(ptr + this.FileHeader.KerningTableHeaderOffset);
|
||||
this.FileHeader = StructureFromByteArray<FdtHeader>(data, 0);
|
||||
this.FontHeader = StructureFromByteArray<FontTableHeader>(data, this.FileHeader.FontTableHeaderOffset);
|
||||
this.KerningHeader = StructureFromByteArray<KerningTableHeader>(data, this.FileHeader.KerningTableHeaderOffset);
|
||||
|
||||
var glyphs = (FontTableEntry*)(ptr + this.FileHeader.FontTableHeaderOffset + Marshal.SizeOf(this.FontHeader));
|
||||
for (var i = 0; i < this.FontHeader.FontTableEntryCount; i++)
|
||||
this.Glyphs.Add(glyphs[i]);
|
||||
this.Glyphs.Add(StructureFromByteArray<FontTableEntry>(data, this.FileHeader.FontTableHeaderOffset + Marshal.SizeOf<FontTableHeader>() + (Marshal.SizeOf<FontTableEntry>() * i)));
|
||||
|
||||
var kerns = (KerningTableEntry*)(ptr + this.FileHeader.KerningTableHeaderOffset + Marshal.SizeOf(this.KerningHeader));
|
||||
for (var i = 0; i < this.FontHeader.KerningTableEntryCount; i++)
|
||||
this.Distances.Add(kerns[i]);
|
||||
}
|
||||
}
|
||||
for (int i = 0, i_ = Math.Min(this.FontHeader.KerningTableEntryCount, this.KerningHeader.Count); i < i_; i++)
|
||||
this.Distances.Add(StructureFromByteArray<KerningTableEntry>(data, this.FileHeader.KerningTableHeaderOffset+ Marshal.SizeOf<KerningTableHeader>() + (Marshal.SizeOf<KerningTableEntry>() * i)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue