/* * Copyright (C) 2014 Patrick Mours * SPDX-License-Identifier: BSD-3-Clause OR MIT */ #include "hook.hpp" #include #include // Verify status codes match the ones from MinHook static_assert(static_cast(reshade::hook::status::unknown) == MH_UNKNOWN); static_assert(static_cast(reshade::hook::status::success) == MH_OK); static_assert(static_cast(reshade::hook::status::not_executable) == MH_ERROR_NOT_EXECUTABLE); static_assert(static_cast(reshade::hook::status::unsupported_function) == MH_ERROR_UNSUPPORTED_FUNCTION); static_assert(static_cast(reshade::hook::status::allocation_failure) == MH_ERROR_MEMORY_ALLOC); static_assert(static_cast(reshade::hook::status::memory_protection_failure) == MH_ERROR_MEMORY_PROTECT); static unsigned long s_reference_count = 0; void reshade::hook::enable() const { MH_QueueEnableHook(target); } void reshade::hook::disable() const { MH_QueueDisableHook(target); } reshade::hook::status reshade::hook::install() { if (!valid()) return hook::status::unsupported_function; // Only leave MinHook active as long as any hooks exist if (InterlockedIncrement(&s_reference_count) == 1) MH_Initialize(); const MH_STATUS status_code = MH_CreateHook(target, replacement, &trampoline); if (status_code == MH_OK || status_code == MH_ERROR_ALREADY_CREATED) { // Installation was successful, so enable the hook and return enable(); return hook::status::success; } if (InterlockedDecrement(&s_reference_count) == 0) MH_Uninitialize(); return static_cast(status_code); } reshade::hook::status reshade::hook::uninstall() { if (!valid()) return hook::status::unsupported_function; const MH_STATUS status_code = MH_RemoveHook(target); if (status_code == MH_ERROR_NOT_CREATED) return hook::status::success; // If the hook was never created, then uninstallation is implicitly successful else if (status_code != MH_OK) return static_cast(status_code); trampoline = nullptr; // MinHook can be uninitialized after all hooks were uninstalled if (InterlockedDecrement(&s_reference_count) == 0) MH_Uninitialize(); return hook::status::success; } reshade::hook::address reshade::hook::call() const { assert(installed()); return trampoline; } bool reshade::hook::apply_queued_actions() { return MH_ApplyQueued() == MH_OK; }