forked from crosire/reshade
-
Notifications
You must be signed in to change notification settings - Fork 2
/
hook.cpp
82 lines (65 loc) · 2.32 KB
/
hook.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
/*
* Copyright (C) 2014 Patrick Mours
* SPDX-License-Identifier: BSD-3-Clause OR MIT
*/
#include "hook.hpp"
#include <cassert>
#include <MinHook.h>
// Verify status codes match the ones from MinHook
static_assert(static_cast<int>(reshade::hook::status::unknown) == MH_UNKNOWN);
static_assert(static_cast<int>(reshade::hook::status::success) == MH_OK);
static_assert(static_cast<int>(reshade::hook::status::not_executable) == MH_ERROR_NOT_EXECUTABLE);
static_assert(static_cast<int>(reshade::hook::status::unsupported_function) == MH_ERROR_UNSUPPORTED_FUNCTION);
static_assert(static_cast<int>(reshade::hook::status::allocation_failure) == MH_ERROR_MEMORY_ALLOC);
static_assert(static_cast<int>(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<hook::status>(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<hook::status>(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;
}