refactor. less global variables

This commit is contained in:
Akash Mozumdar 2018-11-10 23:29:12 -05:00
parent f351148b3d
commit d0f48a67a4
9 changed files with 159 additions and 197 deletions

View File

@ -5,7 +5,7 @@
#include "host.h"
#include "const.h"
#include "defs.h"
#include "../vnrhook/hijack/texthook.h"
#include "../vnrhook/texthook.h"
namespace
{
@ -51,7 +51,7 @@ namespace
std::recursive_mutex hostMutex;
DWORD DUMMY[1];
DWORD DUMMY;
ThreadParam CONSOLE{ 0, -1ULL, -1ULL, -1ULL }, CLIPBOARD{ 0, 0, -1ULL, -1ULL };
void DispatchText(ThreadParam tp, const BYTE* text, int len)
@ -111,7 +111,7 @@ namespace
CreatePipe();
while (ReadFile(hookPipe, buffer, PIPE_BUFFER_SIZE, &bytesRead, nullptr))
switch (*(int*)buffer)
switch (*(HostNotificationType*)buffer)
{
case HOST_NOTIFICATION_RMVHOOK:
{
@ -242,22 +242,22 @@ namespace Host
void DetachProcess(DWORD processId)
{
LOCK(hostMutex);
auto command = HOST_COMMAND_DETACH;
WriteFile(processRecordsByIds.at(processId)->hostPipe, &command, sizeof(command), DUMMY, nullptr);
HostCommandType buffer(HOST_COMMAND_DETACH);
WriteFile(processRecordsByIds.at(processId)->hostPipe, &buffer, sizeof(buffer), &DUMMY, nullptr);
}
void InsertHook(DWORD processId, HookParam hp, std::string name)
{
LOCK(hostMutex);
auto command = InsertHookCmd(hp, name);
WriteFile(processRecordsByIds.at(processId)->hostPipe, &command, sizeof(command), DUMMY, nullptr);
InsertHookCmd buffer(hp, name);
WriteFile(processRecordsByIds.at(processId)->hostPipe, &buffer, sizeof(buffer), &DUMMY, nullptr);
}
void RemoveHook(DWORD processId, uint64_t addr)
{
LOCK(hostMutex);
auto command = RemoveHookCmd(addr);
WriteFile(processRecordsByIds.at(processId)->hostPipe, &command, sizeof(command), DUMMY, nullptr);
RemoveHookCmd buffer(addr);
WriteFile(processRecordsByIds.at(processId)->hostPipe, &buffer, sizeof(buffer), &DUMMY, nullptr);
}
HookParam GetHookParam(DWORD processId, uint64_t addr)

View File

@ -3,18 +3,16 @@ include_directories(. util)
if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8")
set(vnrhook_src
main.cc
pipe.cc
texthook.cc
util/ithsys/ithsys.cc
hijack/texthook.cc
)
else()
set(vnrhook_src
main.cc
pipe.cc
texthook.cc
engine/engine.cc
engine/match.cc
engine/native/pchooks.cc
hijack/texthook.cc
util/util.cc
util/ithsys/ithsys.cc
util/disasm/disasm.cc

View File

@ -11,6 +11,7 @@
#include "engine/match.h"
#include "util/util.h"
#include "main.h"
#include "texthook.h"
#include "engine/mono/funcinfo.h"
#include "engine/ppsspp/funcinfo.h"
#include "ithsys/ithsys.h"
@ -2232,7 +2233,7 @@ void InsertRealliveHook()
//ConsoleOutput("Probably Reallive. Wait for text.");
ConsoleOutput("vnreng: TRIGGER Reallive");
trigger_fun_ = InsertRealliveDynamicHook;
SwitchTrigger(true);
SetTrigger();
}
namespace { // unnamed
@ -5766,7 +5767,8 @@ int GetShinaRioVersion()
//char *buffer,*version;//,*ptr;
enum { BufferSize = 0x40 };
char buffer[BufferSize];
ReadFile(hFile, buffer, BufferSize, (DWORD*)buffer, nullptr);
DWORD DUMMY;
ReadFile(hFile, buffer, BufferSize, &DUMMY, nullptr);
CloseHandle(hFile);
if (buffer[0] == '[') {
buffer[0x3f] = 0; // jichi 8/24/2013: prevent strstr from overflow
@ -5785,7 +5787,7 @@ bool InsertShinaHook()
{
int ver = GetShinaRioVersion();
if (ver >= 50) {
SwitchTrigger(true);
SetTrigger();
trigger_fun_ = StackSearchingTrigger<GetGlyphOutlineA, NULL>;
ConsoleOutput("Textractor: ShinaRio 2.50+: adding trigger");
return true;
@ -5960,7 +5962,7 @@ void InsertWaffleHook()
}
//ConsoleOutput("Probably Waffle. Wait for text.");
trigger_fun_ = InsertWaffleDynamicHook;
SwitchTrigger(true);
SetTrigger();
//ConsoleOutput("vnreng:WAFFLE: failed");
}
@ -8503,7 +8505,7 @@ bool InsertSystemAoiDynamic()
ConsoleOutput("vnreng: DYNAMIC SystemAoi");
//ConsoleOutput("Probably SoftHouseChara. Wait for text.");
trigger_fun_ = InsertSystemAoiDynamicHook;
SwitchTrigger(true);
SetTrigger();
return true;
}
@ -8818,7 +8820,7 @@ void InsertIronGameSystemHook()
{
//ConsoleOutput("Probably IronGameSystem. Wait for text.");
trigger_fun_ = InsertIGSDynamicHook;
SwitchTrigger(true);
SetTrigger();
ConsoleOutput("vnreng: TRIGGER IronGameSystem");
}
@ -9454,7 +9456,7 @@ void InsertRyokuchaHook()
{
//ConsoleOutput("Probably Ryokucha. Wait for text.");
trigger_fun_ = InsertRyokuchaDynamicHook;
SwitchTrigger(true);
SetTrigger();
ConsoleOutput("vnreng: TRIGGER Ryokucha");
}

View File

@ -11,18 +11,107 @@
#include "main.h"
#include "defs.h"
#include "MinHook.h"
#include "pipe.h"
#include "engine/engine.h"
#include "engine/match.h"
#include "hijack/texthook.h"
#include "texthook.h"
#include "util/growl.h"
HANDLE hSection;
HANDLE hSection, hookPipe;
TextHook* hooks;
bool running;
int currentHook = 0, userhookCount = 0;
DWORD trigger = 0;
DWORD DUMMY;
std::unique_ptr<WinMutex> sectionMutex;
DWORD WINAPI Pipe(LPVOID)
{
while (running)
{
DWORD count = 0;
BYTE buffer[PIPE_BUFFER_SIZE] = {};
HANDLE hostPipe = hookPipe = INVALID_HANDLE_VALUE;
while (hookPipe == INVALID_HANDLE_VALUE || hostPipe == INVALID_HANDLE_VALUE)
{
if (hookPipe == INVALID_HANDLE_VALUE)
{
hookPipe = CreateFileW(HOOK_PIPE, GENERIC_WRITE, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
}
if (hookPipe != INVALID_HANDLE_VALUE && hostPipe == INVALID_HANDLE_VALUE)
{
hostPipe = CreateFileW(HOST_PIPE, GENERIC_READ | FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
DWORD mode = PIPE_READMODE_MESSAGE;
SetNamedPipeHandleState(hostPipe, &mode, NULL, NULL);
continue;
}
Sleep(50);
}
*(DWORD*)buffer = GetCurrentProcessId();
WriteFile(hookPipe, buffer, sizeof(DWORD), &count, nullptr);
ConsoleOutput("Textractor: pipe connected");
#ifdef _WIN64
ConsoleOutput("Hooks don't work on x64, only read codes work. Engine disabled.");
#else
Engine::Hijack();
#endif
while (running && ReadFile(hostPipe, buffer, PIPE_BUFFER_SIZE, &count, nullptr))
switch (*(HostCommandType*)buffer)
{
case HOST_COMMAND_NEW_HOOK:
{
auto info = *(InsertHookCmd*)buffer;
NewHook(info.hp, info.name, 0);
}
break;
case HOST_COMMAND_REMOVE_HOOK:
{
auto info = *(RemoveHookCmd*)buffer;
RemoveHook(info.address);
}
break;
case HOST_COMMAND_DETACH:
{
running = false;
}
break;
}
CloseHandle(hostPipe);
CloseHandle(hookPipe);
}
FreeLibraryAndExitThread(GetModuleHandleW(ITH_DLL), 0);
return 0;
}
void TextOutput(ThreadParam tp, BYTE* text, int len)
{
if (len < 0) return;
BYTE buffer[PIPE_BUFFER_SIZE] = {};
*(ThreadParam*)buffer = tp;
memcpy_s(buffer + sizeof(ThreadParam), sizeof(buffer) - sizeof(ThreadParam), text, len);
WriteFile(hookPipe, buffer, sizeof(ThreadParam) + len, &DUMMY, nullptr);
}
void ConsoleOutput(LPCSTR text)
{
ConsoleOutputNotif buffer(text);
WriteFile(hookPipe, &buffer, sizeof(buffer), &DUMMY, nullptr);
}
void ConsoleOutput(std::string text)
{
ConsoleOutput(text.c_str());
}
void NotifyHookRemove(uint64_t addr)
{
HookRemovedNotif buffer(addr);
WriteFile(hookPipe, &buffer, sizeof(buffer), &DUMMY, nullptr);
}
BOOL WINAPI DllMain(HINSTANCE hModule, DWORD fdwReason, LPVOID)
{
switch (fdwReason)
@ -35,23 +124,22 @@ BOOL WINAPI DllMain(HINSTANCE hModule, DWORD fdwReason, LPVOID)
// jichi 9/25/2013: Interprocedural communication with vnrsrv.
hSection = CreateFileMappingW(INVALID_HANDLE_VALUE, nullptr, PAGE_EXECUTE_READWRITE, 0, HOOK_SECTION_SIZE, (ITH_SECTION_ + std::to_wstring(GetCurrentProcessId())).c_str());
::hookman = (TextHook*)MapViewOfFile(hSection, FILE_MAP_ALL_ACCESS | FILE_MAP_EXECUTE, 0, 0, HOOK_BUFFER_SIZE);
memset(::hookman, 0, HOOK_BUFFER_SIZE);
hooks = (TextHook*)MapViewOfFile(hSection, FILE_MAP_ALL_ACCESS | FILE_MAP_EXECUTE, 0, 0, HOOK_BUFFER_SIZE);
memset(hooks, 0, HOOK_BUFFER_SIZE);
MH_Initialize();
running = true;
::running = true;
CreatePipe();
CreateThread(nullptr, 0, Pipe, nullptr, 0, nullptr);
}
break;
case DLL_PROCESS_DETACH:
{
::running = false;
running = false;
MH_Uninitialize();
for (TextHook *man = ::hookman; man < ::hookman + MAX_HOOK; man++) if (man->hp.insertion_address) man->ClearHook();
for (int i = 0; i < MAX_HOOK; ++i) if (hooks[i].hp.insertion_address) hooks[i].ClearHook();
//if (ith_has_section)
UnmapViewOfFile(::hookman);
UnmapViewOfFile(hooks);
CloseHandle(hSection);
//} ITH_EXCEPT {}
}
@ -61,17 +149,17 @@ BOOL WINAPI DllMain(HINSTANCE hModule, DWORD fdwReason, LPVOID)
}
//extern "C" {
void NewHook(const HookParam &hp, LPCSTR lpname, DWORD flag)
void NewHook(HookParam hp, LPCSTR lpname, DWORD flag)
{
std::string name = lpname;
if (++currentHook < MAX_HOOK)
{
if (name[0] == '\0') name = "UserHook" + std::to_string(userhookCount++);
ConsoleOutput(("Textractor: try inserting hook: " + name).c_str());
if (name.empty()) name = "UserHook" + std::to_string(userhookCount++);
ConsoleOutput("Textractor: try inserting hook: " + name);
// jichi 7/13/2014: This function would raise when too many hooks added
::hookman[currentHook].InitHook(hp, name.c_str(), flag);
if (::hookman[currentHook].InsertHook()) ConsoleOutput(("Textractor: inserted hook: " + name).c_str());
hooks[currentHook].InitHook(hp, name.c_str(), flag);
if (hooks[currentHook].InsertHook()) ConsoleOutput("Textractor: inserted hook: " + name);
else ConsoleOutput("Textractor:WARNING: failed to insert hook");
}
else ConsoleOutput("Textractor: too many hooks: can't insert");
@ -80,16 +168,7 @@ void NewHook(const HookParam &hp, LPCSTR lpname, DWORD flag)
void RemoveHook(uint64_t addr)
{
for (int i = 0; i < MAX_HOOK; i++)
if (abs((long long)(::hookman[i].hp.insertion_address - addr)) < 9)
{
::hookman[i].ClearHook();
return;
}
}
void SwitchTrigger(DWORD t)
{
trigger = t;
if (abs((long long)(hooks[i].hp.insertion_address - addr)) < 9) return hooks[i].ClearHook();
}
// EOF

View File

@ -6,11 +6,12 @@
#include "common.h"
#include "types.h"
#include "pipe.h"
void NewHook(const HookParam &hp, LPCSTR name, DWORD flag = HOOK_ENGINE);
void TextOutput(ThreadParam tp, BYTE* text, int len);
void ConsoleOutput(LPCSTR text);
void NotifyHookRemove(uint64_t addr);
void NewHook(HookParam hp, LPCSTR name, DWORD flag = HOOK_ENGINE);
void RemoveHook(uint64_t addr);
void SwitchTrigger(DWORD on);
#define ITH_RAISE (*(int*)0 = 0) // raise C000005, for debugging only
#define ITH_TRY __try

View File

@ -1,100 +0,0 @@
// pipe.cc
// 8/24/2013 jichi
// Branch: ITH_DLL/pipe.cpp, rev 66
// 8/24/2013 TODO: Clean up this file
#ifdef _MSC_VER
# pragma warning (disable:4100) // C4100: unreference formal parameter
#endif // _MSC_VER
#include "pipe.h"
#include "main.h"
#include "hijack/texthook.h"
#include "engine/match.h"
#include "defs.h"
#include "const.h"
#include "growl.h"
HANDLE hookPipe;
DWORD DUMMY[100];
void CreatePipe()
{
CreateThread(nullptr, 0, [](LPVOID)
{
while (::running)
{
DWORD count = 0;
BYTE buffer[PIPE_BUFFER_SIZE] = {};
HANDLE hostPipe = ::hookPipe = INVALID_HANDLE_VALUE;
while (::hookPipe == INVALID_HANDLE_VALUE || hostPipe == INVALID_HANDLE_VALUE)
{
if (::hookPipe == INVALID_HANDLE_VALUE)
{
::hookPipe = CreateFileW(HOOK_PIPE, GENERIC_WRITE, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
}
if (::hookPipe != INVALID_HANDLE_VALUE && hostPipe == INVALID_HANDLE_VALUE)
{
hostPipe = CreateFileW(HOST_PIPE, GENERIC_READ | FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
DWORD mode = PIPE_READMODE_MESSAGE;
SetNamedPipeHandleState(hostPipe, &mode, NULL, NULL);
continue;
}
Sleep(50);
}
*(DWORD*)buffer = GetCurrentProcessId();
WriteFile(::hookPipe, buffer, sizeof(DWORD), &count, nullptr);
ConsoleOutput("Textractor: pipe connected");
#ifdef _WIN64
ConsoleOutput("Hooks don't work on x64, only read codes work. Engine disabled.");
#else
Engine::Hijack();
#endif
while (::running && ReadFile(hostPipe, buffer, PIPE_BUFFER_SIZE, &count, nullptr))
switch (*(int*)buffer)
{
case HOST_COMMAND_NEW_HOOK:
{
auto info = *(InsertHookCmd*)buffer;
NewHook(info.hp, info.name, 0);
}
break;
case HOST_COMMAND_REMOVE_HOOK:
{
auto info = *(RemoveHookCmd*)buffer;
RemoveHook(info.address);
}
break;
case HOST_COMMAND_DETACH:
{
::running = false;
}
break;
}
CloseHandle(hostPipe);
CloseHandle(::hookPipe);
}
FreeLibraryAndExitThread(GetModuleHandleW(ITH_DLL), 0);
return (DWORD)0;
}, nullptr, 0, nullptr);
}
void ConsoleOutput(LPCSTR text)
{
auto info = ConsoleOutputNotif(text);
WriteFile(::hookPipe, &info, strlen(text) + sizeof(info), DUMMY, nullptr);
}
void NotifyHookRemove(uint64_t addr)
{
auto info = HookRemovedNotif(addr);
WriteFile(::hookPipe, &info, sizeof(info), DUMMY, nullptr);
}
// EOF

View File

@ -1,8 +0,0 @@
#pragma once
#include "common.h"
#include "types.h"
void CreatePipe();
void NotifyHookRemove(uint64_t addr);
void ConsoleOutput(LPCSTR text); // jichi 12/25/2013: Used to return length of sent text

View File

@ -9,17 +9,22 @@
//# pragma warning (disable:4733) // C4733: Inline asm assigning to 'FS:0' : handler not registered as safe handler
#endif // _MSC_VER
#include "hijack/texthook.h"
#include "texthook.h"
#include "MinHook.h"
#include "engine/match.h"
#include "main.h"
#include "pipe.h"
#include "const.h"
#include "ithsys/ithsys.h"
#include "growl.h"
#include <Psapi.h>
TextHook *hookman;
extern std::unique_ptr<WinMutex> sectionMutex;
bool trigger = 0;
void SetTrigger()
{
trigger = true;
}
// - Unnamed helpers -
@ -125,8 +130,8 @@ void TextHook::Send(DWORD dwDataBase)
* @param stack address of current stack - 4
* @return If success, which is reverted
*/
if (::trigger)
::trigger = Engine::InsertDynamicHook((LPVOID)dwAddr, *(DWORD *)(dwDataBase - 0x1c), *(DWORD *)(dwDataBase - 0x18));
if (trigger)
trigger = Engine::InsertDynamicHook((LPVOID)dwAddr, *(DWORD *)(dwDataBase - 0x1c), *(DWORD *)(dwDataBase - 0x18));
// jichi 10/24/2014: generic hook function
if (hp.hook_fun && !hp.hook_fun(dwDataBase, &hp))
@ -168,25 +173,18 @@ void TextHook::Send(DWORD dwDataBase)
dwDataIn = _byteswap_ushort(dwDataIn & 0xffff);
if (dwCount == 1)
dwDataIn &= 0xff;
*(WORD *)(pbData + sizeof(ThreadParam)) = dwDataIn & 0xffff;
*(WORD*)pbData = dwDataIn & 0xffff;
}
else
::memcpy(pbData + sizeof(ThreadParam), (void *)dwDataIn, dwCount);
::memcpy(pbData, (void*)dwDataIn, dwCount);
// jichi 10/14/2014: Add filter function
if (hp.filter_fun && !hp.filter_fun(pbData + sizeof(ThreadParam), &dwCount, &hp, 0) || dwCount <= 0) return;
if (hp.filter_fun && !hp.filter_fun(pbData, &dwCount, &hp, 0) || dwCount <= 0) return;
if (dwType & (NO_CONTEXT | FIXING_SPLIT))
dwRetn = 0;
*(ThreadParam*)pbData = { GetCurrentProcessId(), dwAddr, dwRetn, dwSplit };
if (dwCount) {
DWORD unused;
//CliLockPipe();
WriteFile(::hookPipe, pbData, dwCount + sizeof(ThreadParam), &unused, nullptr);
//CliUnlockPipe();
}
TextOutput({ GetCurrentProcessId(), dwAddr, dwRetn, dwSplit }, pbData, dwCount);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
@ -205,9 +203,9 @@ bool TextHook::InsertHookCode()
else if (HMODULE moduleBase = GetModuleHandleW(hp.module)) hp.insertion_address += (uint64_t)moduleBase;
else return ConsoleOutput("Textractor: InsertHookCode FAILED: module not present"), false;
BYTE* original;
void* original;
insert:
if (MH_STATUS err = MH_CreateHook((void*)hp.insertion_address, (void*)trampoline, (void**)&original))
if (MH_STATUS err = MH_CreateHook((void*)hp.insertion_address, (void*)trampoline, &original))
if (err == MH_ERROR_ALREADY_CREATED)
{
RemoveHook(hp.insertion_address);
@ -222,7 +220,7 @@ insert:
*(TextHook**)(common_hook + 9) = this;
*(void(TextHook::**)(DWORD))(common_hook + 14) = &TextHook::Send;
*(BYTE**)(common_hook + 24) = original;
*(void**)(common_hook + 24) = original;
memcpy(trampoline, common_hook, sizeof(common_hook));
//BYTE* original;
@ -240,7 +238,7 @@ insert:
}
#endif // _WIN32
DWORD WINAPI ReaderThread(LPVOID hookPtr)
DWORD WINAPI Reader(LPVOID hookPtr)
{
TextHook* hook = (TextHook*)hookPtr;
BYTE buffer[PIPE_BUFFER_SIZE] = {};
@ -253,7 +251,7 @@ DWORD WINAPI ReaderThread(LPVOID hookPtr)
{
if (hook->hp.type & DATA_INDIRECT) currentAddress = *((char**)hook->hp.insertion_address + hook->hp.index);
Sleep(500);
if (memcmp(buffer + sizeof(ThreadParam), currentAddress, dataLen + 1) == 0)
if (memcmp(buffer, currentAddress, dataLen + 1) == 0)
{
changeCount = 0;
continue;
@ -269,15 +267,13 @@ DWORD WINAPI ReaderThread(LPVOID hookPtr)
else
dataLen = strlen((const char*)currentAddress);
*(ThreadParam*)buffer = { GetCurrentProcessId(), hook->hp.insertion_address, 0, 0 };
memcpy(buffer + sizeof(ThreadParam), currentAddress, dataLen + 1);
DWORD unused;
WriteFile(::hookPipe, buffer, dataLen + sizeof(ThreadParam), &unused, nullptr);
memcpy(buffer, currentAddress, dataLen + 1);
TextOutput({ GetCurrentProcessId(), hook->hp.insertion_address, 0, 0 }, buffer, dataLen);
}
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
ConsoleOutput("Textractor: ReaderThread ERROR (likely an incorrect R-code)");
ConsoleOutput("Textractor: Reader ERROR (likely an incorrect R-code)");
}
ConsoleOutput("Textractor: remove read code");
hook->ClearHook();
@ -287,14 +283,14 @@ DWORD WINAPI ReaderThread(LPVOID hookPtr)
bool TextHook::InsertReadCode()
{
//RemoveHook(hp.address); // Artikash 8/25/2018: clear existing
readerHandle = CreateThread(nullptr, 0, ReaderThread, this, 0, nullptr);
readerHandle = CreateThread(nullptr, 0, Reader, this, 0, nullptr);
return true;
}
void TextHook::InitHook(const HookParam &h, LPCSTR name, DWORD set_flag)
void TextHook::InitHook(HookParam h, LPCSTR name, DWORD set_flag)
{
LOCK(*sectionMutex);
hp = h;
this->hp = h;
hp.insertion_address = hp.address;
hp.type |= set_flag;
strcpy_s<HOOK_NAME_SIZE>(hookName, name);

View File

@ -10,8 +10,7 @@
#include "common.h"
#include "types.h"
extern int currentHook;
extern DWORD trigger;
void SetTrigger();
// jichi 9/25/2013: This class will be used by NtMapViewOfSectionfor
// interprocedure communication, where constructor/destructor will NOT work.
@ -23,6 +22,7 @@ class TextHook
int GetLength(DWORD base, DWORD in); // jichi 12/25/2013: Return 0 if failed
void RemoveHookCode();
void RemoveReadCode();
public:
HookParam hp;
char hookName[HOOK_NAME_SIZE];
@ -30,17 +30,11 @@ public:
HANDLE readerHandle;
bool InsertHook();
void InitHook(const HookParam &hp, LPCSTR name, DWORD set_flag);
void InitHook(HookParam hp, LPCSTR name, DWORD set_flag);
void Send(DWORD dwDataBase);
void ClearHook();
};
enum { MAX_HOOK = 300 };
enum { HOOK_SECTION_SIZE = MAX_HOOK * sizeof(TextHook) * 2, HOOK_BUFFER_SIZE = MAX_HOOK * sizeof(TextHook) };
extern TextHook *hookman;
extern bool running;
extern HANDLE hookPipe;
extern std::unique_ptr<WinMutex> sectionMutex;
enum { MAX_HOOK = 300, HOOK_BUFFER_SIZE = MAX_HOOK * sizeof(TextHook), HOOK_SECTION_SIZE = HOOK_BUFFER_SIZE * 2 };
// EOF