massive refactor

This commit is contained in:
Akash Mozumdar 2018-08-21 22:43:30 -04:00
parent d03bd93bec
commit 2c37a50f7b
18 changed files with 169 additions and 253 deletions

View File

@ -7,7 +7,6 @@ set(RESOURCE_FILES NextHooker.rc NextHooker.ico)
set(gui_SRCS set(gui_SRCS
main.cpp main.cpp
mainwindow.cpp mainwindow.cpp
hostsignaller.cpp
misc.cpp misc.cpp
extensions.cpp extensions.cpp
${RESOURCE_FILES} ${RESOURCE_FILES}

View File

@ -1,7 +1,9 @@
#include "extensions.h" #include "extensions.h"
#include <shared_mutex>
#include <map> #include <map>
#include <QDir> #include <QDir>
std::shared_mutex extenMutex;
std::map<int, ExtensionFunction> extensions; std::map<int, ExtensionFunction> extensions;
int processing; int processing;
@ -21,50 +23,29 @@ std::map<int, QString> LoadExtensions()
file.remove(0, extensionNumber.length() + 1); file.remove(0, extensionNumber.length() + 1);
extensionNames[extensionNumber.toInt()] = file; extensionNames[extensionNumber.toInt()] = file;
} }
while (processing) Sleep(10); extenMutex.lock();
processing = -1;
extensions = newExtensions; extensions = newExtensions;
processing = 0; extenMutex.unlock();
return extensionNames; return extensionNames;
} }
std::wstring DispatchSentenceToExtensions(std::wstring sentence, std::unordered_map<std::string, int> miscInfo) std::wstring DispatchSentenceToExtensions(std::wstring sentence, std::unordered_map<std::string, int> miscInfo)
{ {
while (processing < 0) Sleep(10); wchar_t* sentenceBuffer = (wchar_t*)malloc((sentence.size() + 1) * sizeof(wchar_t));
processing++; wcscpy(sentenceBuffer, sentence.c_str());
wchar_t* sentenceOrigBuffer = (wchar_t*)malloc((sentence.size() + 1) * sizeof(wchar_t));
wcscpy(sentenceOrigBuffer, sentence.c_str());
const wchar_t* sentenceBuffer = sentenceOrigBuffer;
InfoForExtension* miscInfoLinkedList = new InfoForExtension; InfoForExtension* miscInfoLinkedList = new InfoForExtension;
InfoForExtension* miscInfoTraverser = miscInfoLinkedList; InfoForExtension* miscInfoTraverser = miscInfoLinkedList;
for (auto i : miscInfo) for (auto& i : miscInfo) miscInfoTraverser = miscInfoTraverser->nextProperty = new InfoForExtension{ i.first.c_str(), i.second, new InfoForExtension };
{ extenMutex.lock_shared();
miscInfoTraverser->propertyName = new char[i.first.size() + 1];
strcpy(miscInfoTraverser->propertyName, i.first.c_str());
miscInfoTraverser->propertyValue = i.second;
miscInfoTraverser->nextProperty = new InfoForExtension;
miscInfoTraverser = miscInfoTraverser->nextProperty;
}
miscInfoTraverser->propertyName = new char[sizeof("END")];
strcpy(miscInfoTraverser->propertyName, "END");
miscInfoTraverser->nextProperty = nullptr;
for (auto i : extensions) for (auto i : extensions)
{ {
const wchar_t* prev = sentenceBuffer; wchar_t* prev = sentenceBuffer;
sentenceBuffer = i.second(sentenceBuffer, miscInfoLinkedList); sentenceBuffer = i.second(sentenceBuffer, miscInfoLinkedList);
if (sentenceBuffer == nullptr) sentence = prev;
if (sentenceBuffer != prev) free((void*)prev); if (sentenceBuffer != prev) free((void*)prev);
} }
miscInfoTraverser = miscInfoLinkedList; extenMutex.unlock_shared();
while (miscInfoTraverser != nullptr) delete miscInfoLinkedList;
{
InfoForExtension* nextNode = miscInfoTraverser->nextProperty;
delete[] miscInfoTraverser->propertyName;
delete miscInfoTraverser;
miscInfoTraverser = nextNode;
}
std::wstring newSentence = std::wstring(sentenceBuffer); std::wstring newSentence = std::wstring(sentenceBuffer);
free((void*)sentenceBuffer); free((void*)sentenceBuffer);
processing--;
return newSentence; return newSentence;
} }

View File

@ -12,10 +12,11 @@ std::map<int, QString> LoadExtensions();
std::wstring DispatchSentenceToExtensions(std::wstring sentence, std::unordered_map<std::string, int> miscInfo); std::wstring DispatchSentenceToExtensions(std::wstring sentence, std::unordered_map<std::string, int> miscInfo);
struct InfoForExtension struct InfoForExtension
{ {
char* propertyName; ~InfoForExtension() { if (nextProperty) delete nextProperty; };
int propertyValue; const char* propertyName = "";
InfoForExtension* nextProperty; int propertyValue = 0;
InfoForExtension* nextProperty = nullptr;
}; };
typedef const wchar_t*(*ExtensionFunction)(const wchar_t*, const InfoForExtension*); typedef wchar_t*(*ExtensionFunction)(const wchar_t*, const InfoForExtension*);
#endif // EXTENSIONS_H #endif // EXTENSIONS_H

View File

@ -1,10 +0,0 @@
#include "hostsignaller.h"
#include "extensions.h"
void HostSignaller::Initialize()
{
Host::RegisterProcessAttachCallback([&](DWORD pid){ emit AddProcess(pid); });
Host::RegisterProcessDetachCallback([&](DWORD pid){ emit RemoveProcess(pid); });
Host::RegisterThreadCreateCallback([&](TextThread* thread) { emit AddThread(thread); });
Host::RegisterThreadRemoveCallback([&](TextThread* thread){ emit RemoveThread(thread); });
}

View File

@ -1,23 +0,0 @@
#ifndef HOSTSIGNALLER_H
#define HOSTSIGNALLER_H
#include <QObject>
#include <Windows.h>
#include "../host/host.h"
// Artikash 7/24/2018: This class is a workaround for the fact that Qt only lets me manipulate the GUI in the main thread.
class HostSignaller : public QObject
{
Q_OBJECT
public:
void Initialize();
signals:
void AddProcess(unsigned int processId);
void RemoveProcess(unsigned int processId);
void AddThread(TextThread* thread);
void RemoveThread(TextThread* thread);
};
#endif // HOSTSIGNALLER_H

View File

@ -4,7 +4,6 @@
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
if (!Host::Start()) return 1;
QApplication a(argc, argv); QApplication a(argc, argv);
MainWindow w; MainWindow w;
w.show(); w.show();

View File

@ -21,12 +21,6 @@
#include "../vnrhook/include/const.h" #include "../vnrhook/include/const.h"
#include "misc.h" #include "misc.h"
QMainWindow* mainWindow;
QComboBox* processCombo;
QComboBox* ttCombo;
QComboBox* extenCombo;
QPlainTextEdit* textOutput;
QString ProcessString(DWORD processId) QString ProcessString(DWORD processId)
{ {
return QString("%1: %2").arg(QString::number(processId), GetModuleName(processId)); return QString("%1: %2").arg(QString::number(processId), GetModuleName(processId));
@ -35,26 +29,28 @@ QString ProcessString(DWORD processId)
QString TextThreadString(TextThread* thread) QString TextThreadString(TextThread* thread)
{ {
ThreadParameter tp = thread->GetThreadParameter(); ThreadParameter tp = thread->GetThreadParameter();
return QString("%1:%2:%3:%4:%5: ").arg( return QString("%1:0x%2:0x%3:0x%4: ").arg(
QString::number(thread->Number()), QString::number(tp.pid).toUpper(),
QString::number(tp.pid), QString::number(tp.hook, 16).toUpper(),
QString::number(tp.hook, 16), QString::number(tp.retn, 16).toUpper(),
QString::number(tp.retn, 16), QString::number(tp.spl, 16).toUpper()
QString::number(tp.spl, 16) );
).toUpper(); }
ThreadParameter ParseTextThreadString(QString textThreadString)
{
QStringList threadParam = textThreadString.split(":");
ThreadParameter tp = {};
tp.hook = threadParam[1].toULongLong();
return { threadParam[0].toUInt(), threadParam[1].toULongLong(nullptr, 0), threadParam[2].toULongLong(nullptr, 0), threadParam[3].toULongLong(nullptr, 0) };
} }
MainWindow::MainWindow(QWidget *parent) : MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent), QMainWindow(parent),
ui(new Ui::MainWindow), ui(new Ui::MainWindow)
hostSignaller(new HostSignaller)
{ {
ui->setupUi(this); ui->setupUi(this);
mainWindow = this;
processCombo = mainWindow->findChild<QComboBox*>("processCombo");
ttCombo = mainWindow->findChild<QComboBox*>("ttCombo");
extenCombo = mainWindow->findChild<QComboBox*>("extenCombo");
textOutput = mainWindow->findChild<QPlainTextEdit*>("textOutput");
QFile settings("NHWindow"); QFile settings("NHWindow");
settings.open(QIODevice::ReadOnly); settings.open(QIODevice::ReadOnly);
QDataStream reader(&settings); QDataStream reader(&settings);
@ -62,14 +58,24 @@ MainWindow::MainWindow(QWidget *parent) :
reader >> rect; reader >> rect;
if (rect.bottom()) this->setGeometry(rect); if (rect.bottom()) this->setGeometry(rect);
hostSignaller->Initialize(); processCombo = findChild<QComboBox*>("processCombo");
connect(hostSignaller, &HostSignaller::AddProcess, this, &MainWindow::AddProcess); ttCombo = findChild<QComboBox*>("ttCombo");
connect(hostSignaller, &HostSignaller::RemoveProcess, this, &MainWindow::RemoveProcess); extenCombo = findChild<QComboBox*>("extenCombo");
connect(hostSignaller, &HostSignaller::AddThread, this, &MainWindow::AddThread); textOutput = findChild<QPlainTextEdit*>("textOutput");
connect(hostSignaller, &HostSignaller::RemoveThread, this, &MainWindow::RemoveThread);
connect(this, &MainWindow::ThreadOutputReceived, this, &MainWindow::ThreadOutput); connect(this, &MainWindow::SigAddProcess, this, &MainWindow::AddProcess);
connect(this, &MainWindow::SigRemoveProcess, this, &MainWindow::RemoveProcess);
connect(this, &MainWindow::SigAddThread, this, &MainWindow::AddThread);
connect(this, &MainWindow::SigRemoveThread, this, &MainWindow::RemoveThread);
connect(this, &MainWindow::SigThreadOutput, this, &MainWindow::ThreadOutput);
Host::Start(
[&](DWORD processId) { emit SigAddProcess(processId); },
[&](DWORD processId) { emit SigRemoveProcess(processId); },
[&](TextThread* thread) { emit SigAddThread(thread); },
[&](TextThread* thread) { emit SigRemoveThread(thread); }
);
ReloadExtensions(); ReloadExtensions();
Host::Open();
Host::AddConsoleOutput(L"NextHooker beta v2.1.3 by Artikash\r\nSource code and more information available under GPLv3 at https://github.com/Artikash/NextHooker"); Host::AddConsoleOutput(L"NextHooker beta v2.1.3 by Artikash\r\nSource code and more information available under GPLv3 at https://github.com/Artikash/NextHooker");
} }
@ -93,13 +99,9 @@ void MainWindow::AddProcess(unsigned int processId)
for (int i = allProcesses.length() - 1; i >= 0; --i) for (int i = allProcesses.length() - 1; i >= 0; --i)
if (allProcesses.at(i).contains(processName)) if (allProcesses.at(i).contains(processName))
{ {
Sleep(50);
QStringList hooks = allProcesses.at(i).split(" , "); QStringList hooks = allProcesses.at(i).split(" , ");
for (int j = 1; j < hooks.length(); ++j) for (int j = 1; j < hooks.length(); ++j)
{
Sleep(10);
Host::InsertHook(processId, ParseCode(hooks.at(j))); Host::InsertHook(processId, ParseCode(hooks.at(j)));
}
return; return;
} }
} }
@ -115,27 +117,28 @@ void MainWindow::AddThread(TextThread* thread)
TextThreadString(thread) + TextThreadString(thread) +
QString::fromStdWString(Host::GetHookName(thread->GetThreadParameter().pid, thread->GetThreadParameter().hook)) + QString::fromStdWString(Host::GetHookName(thread->GetThreadParameter().pid, thread->GetThreadParameter().hook)) +
" (" + " (" +
GenerateCode(Host::GetHookParam(thread->GetThreadParameter().pid, thread->GetThreadParameter().hook), thread->GetThreadParameter().pid) + GenerateCode(Host::GetHookParam(thread->GetThreadParameter()), thread->GetThreadParameter().pid) +
")" ")"
); );
thread->RegisterOutputCallBack([&](TextThread* thread, std::wstring output) thread->RegisterOutputCallBack([&](TextThread* thread, std::wstring output)
{ {
output = DispatchSentenceToExtensions(output, GetInfoForExtensions(thread)); output = DispatchSentenceToExtensions(output, GetInfoForExtensions(thread));
output += L"\r\n"; output += L"\r\n";
emit ThreadOutputReceived(thread, QString::fromStdWString(output)); emit SigThreadOutput(thread, QString::fromStdWString(output));
return output; return output;
}); });
} }
void MainWindow::RemoveThread(TextThread* thread) void MainWindow::RemoveThread(TextThread* thread)
{ {
int threadIndex = ttCombo->findText(QString::number(thread->Number()) + ":", Qt::MatchStartsWith); int threadIndex = ttCombo->findText(TextThreadString(thread), Qt::MatchStartsWith);
if (threadIndex == ttCombo->currentIndex()) if (threadIndex == ttCombo->currentIndex())
{ {
ttCombo->setCurrentIndex(0); ttCombo->setCurrentIndex(0);
on_ttCombo_activated(0); on_ttCombo_activated(0);
} }
ttCombo->removeItem(threadIndex); ttCombo->removeItem(threadIndex);
delete thread;
} }
void MainWindow::ThreadOutput(TextThread* thread, QString output) void MainWindow::ThreadOutput(TextThread* thread, QString output)
@ -159,8 +162,8 @@ std::unordered_map<std::string, int> MainWindow::GetInfoForExtensions(TextThread
{ {
return return
{ {
{ "current select", ttCombo->currentText().split(":")[0].toInt() == thread->Number() ? 1 : 0 }, { "current select", (int)ttCombo->currentText().startsWith(TextThreadString(thread)) },
{ "text number", thread->Number() }, { "text number", 0 },
{ "process id", thread->GetThreadParameter().pid }, { "process id", thread->GetThreadParameter().pid },
{ "hook address", (int)thread->GetThreadParameter().hook }, { "hook address", (int)thread->GetThreadParameter().hook },
{ "hook address (upper 32 bits)", (int)(thread->GetThreadParameter().hook >> 32) } { "hook address (upper 32 bits)", (int)(thread->GetThreadParameter().hook >> 32) }
@ -172,15 +175,22 @@ QVector<HookParam> MainWindow::GetAllHooks(DWORD processId)
std::unordered_set<DWORD> addresses; std::unordered_set<DWORD> addresses;
QVector<HookParam> hooks; QVector<HookParam> hooks;
for (int i = 0; i < ttCombo->count(); ++i) for (int i = 0; i < ttCombo->count(); ++i)
if (ttCombo->itemText(i).split(":")[1].toInt() == processId &&
!addresses.count(ttCombo->itemText(i).split(":")[2].toInt(nullptr, 16)))
{ {
addresses.insert(ttCombo->itemText(i).split(":")[2].toInt(nullptr, 16)); ThreadParameter tp = ParseTextThreadString(ttCombo->itemText(i));
hooks.push_back(Host::GetHookParam(ttCombo->itemText(i).split(":")[1].toInt(), ttCombo->itemText(i).split(":")[2].toInt(nullptr, 16))); if (tp.pid == processId && !addresses.count(tp.hook))
{
addresses.insert(tp.hook);
hooks.push_back(Host::GetHookParam(tp));
}
} }
return hooks; return hooks;
} }
DWORD MainWindow::GetSelectedProcessId()
{
return processCombo->currentText().split(":")[0].toULong();
}
void MainWindow::on_attachButton_clicked() void MainWindow::on_attachButton_clicked()
{ {
std::unordered_map<std::wstring, DWORD> allProcesses = GetAllProcesses(); std::unordered_map<std::wstring, DWORD> allProcesses = GetAllProcesses();
@ -203,7 +213,7 @@ void MainWindow::on_attachButton_clicked()
void MainWindow::on_detachButton_clicked() void MainWindow::on_detachButton_clicked()
{ {
Host::DetachProcess(processCombo->currentText().split(":")[0].toInt()); Host::DetachProcess(GetSelectedProcessId());
} }
void MainWindow::on_hookButton_clicked() void MainWindow::on_hookButton_clicked()
@ -217,30 +227,30 @@ void MainWindow::on_hookButton_clicked()
Host::AddConsoleOutput(L"invalid code"); Host::AddConsoleOutput(L"invalid code");
return; return;
} }
Host::InsertHook(processCombo->currentText().split(":")[0].toInt(), ParseCode(hookCode)); Host::InsertHook(GetSelectedProcessId(), ParseCode(hookCode));
} }
void MainWindow::on_unhookButton_clicked() void MainWindow::on_unhookButton_clicked()
{ {
QVector<HookParam> hooks = GetAllHooks(processCombo->currentText().split(":")[0].toInt()); QVector<HookParam> hooks = GetAllHooks(GetSelectedProcessId());
QStringList hookList; QStringList hookList;
for (auto i : hooks) hookList.push_back( for (auto i : hooks) hookList.push_back(
QString::fromStdWString(Host::GetHookName(processCombo->currentText().split(":")[0].toInt(), i.address)) + QString::fromStdWString(Host::GetHookName(GetSelectedProcessId(), i.address)) +
": " + ": " +
GenerateCode(i, processCombo->currentText().split(":")[0].toInt()) GenerateCode(i, GetSelectedProcessId())
); );
bool ok; bool ok;
QString hook = QInputDialog::getItem(this, "Unhook", "Which hook to remove?", hookList, 0, false, &ok); QString hook = QInputDialog::getItem(this, "Unhook", "Which hook to remove?", hookList, 0, false, &ok);
if (ok) Host::RemoveHook(processCombo->currentText().split(":")[0].toInt(), hooks.at(hookList.indexOf(hook)).address); if (ok) Host::RemoveHook(GetSelectedProcessId(), hooks.at(hookList.indexOf(hook)).address);
} }
void MainWindow::on_saveButton_clicked() void MainWindow::on_saveButton_clicked()
{ {
QVector<HookParam> hooks = GetAllHooks(processCombo->currentText().split(":")[0].toInt()); QVector<HookParam> hooks = GetAllHooks(GetSelectedProcessId());
QString hookList = GetFullModuleName(processCombo->currentText().split(":")[0].toInt());; QString hookList = GetFullModuleName(GetSelectedProcessId());
for (auto i : hooks) for (auto i : hooks)
if (!(i.type & HOOK_ENGINE)) if (!(i.type & HOOK_ENGINE))
hookList += " , " + GenerateCode(i, processCombo->currentText().split(":")[0].toInt()); hookList += " , " + GenerateCode(i, GetSelectedProcessId());
QFile file("SavedHooks.txt"); QFile file("SavedHooks.txt");
if (!file.open(QIODevice::Append | QIODevice::Text)) return; if (!file.open(QIODevice::Append | QIODevice::Text)) return;
file.write((hookList + "\r\n").toUtf8()); file.write((hookList + "\r\n").toUtf8());
@ -248,7 +258,7 @@ void MainWindow::on_saveButton_clicked()
void MainWindow::on_ttCombo_activated(int index) void MainWindow::on_ttCombo_activated(int index)
{ {
textOutput->setPlainText(QString::fromStdWString(Host::GetThread(ttCombo->itemText(index).split(":")[0].toInt())->GetStore())); textOutput->setPlainText(QString::fromStdWString(Host::GetThread(ParseTextThreadString(ttCombo->itemText(index)))->GetStore()));
textOutput->moveCursor(QTextCursor::End); textOutput->moveCursor(QTextCursor::End);
} }

View File

@ -4,10 +4,11 @@
#include <QMainWindow> #include <QMainWindow>
#include <Windows.h> #include <Windows.h>
#include <QVector> #include <QVector>
#include <QPlainTextEdit>
#include <QComboBox>
#include <unordered_map> #include <unordered_map>
#include <string> #include <string>
#include "../host/host.h" #include "../host/host.h"
#include "hostsignaller.h"
namespace Ui namespace Ui
{ {
@ -23,7 +24,11 @@ public:
~MainWindow(); ~MainWindow();
signals: signals:
void ThreadOutputReceived(TextThread* thread, QString output); void SigAddProcess(unsigned int processId);
void SigRemoveProcess(unsigned int processId);
void SigAddThread(TextThread* thread);
void SigRemoveThread(TextThread* thread);
void SigThreadOutput(TextThread* thread, QString output);
private slots: private slots:
void AddProcess(unsigned int processId); void AddProcess(unsigned int processId);
@ -44,9 +49,13 @@ private:
void ReloadExtensions(); void ReloadExtensions();
std::unordered_map<std::string, int> GetInfoForExtensions(TextThread* thread); std::unordered_map<std::string, int> GetInfoForExtensions(TextThread* thread);
QVector<HookParam> GetAllHooks(DWORD processId); QVector<HookParam> GetAllHooks(DWORD processId);
DWORD GetSelectedProcessId();
Ui::MainWindow *ui; Ui::MainWindow *ui;
HostSignaller* hostSignaller; QComboBox* processCombo;
QComboBox* ttCombo;
QComboBox* extenCombo;
QPlainTextEdit* textOutput;
}; };
#endif // MAINWINDOW_H #endif // MAINWINDOW_H

View File

@ -210,11 +210,11 @@ QString GenerateHCode(HookParam hp, DWORD processId)
if (!(processHandle = OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, FALSE, processId))) return badCode; if (!(processHandle = OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, FALSE, processId))) return badCode;
MEMORY_BASIC_INFORMATION info; MEMORY_BASIC_INFORMATION info;
if (!VirtualQueryEx(processHandle, (LPCVOID)hp.address, &info, sizeof(info))) return badCode; if (!VirtualQueryEx(processHandle, (LPCVOID)hp.address, &info, sizeof(info))) return badCode;
wchar_t buffer[MAX_PATH]; QString moduleName = GetModuleName(processId, (HMODULE)info.AllocationBase);
if (!GetModuleFileNameExW(processHandle, (HMODULE)info.AllocationBase, buffer, MAX_PATH)) return badCode; if (moduleName.size() == 0) return badCode;
code += QString::number(hp.address - (DWORD)info.AllocationBase, 16) + ":"; code += QString::number(hp.address - (DWORD)info.AllocationBase, 16) + ":";
code = code.toUpper(); code = code.toUpper();
code += QString::fromWCharArray(wcsrchr(buffer, L'\\') + 1); code += moduleName;
return code; return code;
} }

View File

@ -13,7 +13,7 @@ extern "C"
*/ */
__declspec(dllexport) const wchar_t* OnNewSentence(const wchar_t* sentence, const InfoForExtension* miscInfo) __declspec(dllexport) const wchar_t* OnNewSentence(const wchar_t* sentence, const InfoForExtension* miscInfo)
{ {
if (GetProperty("current select", miscInfo) && GetProperty("text number", miscInfo) > 0) if (GetProperty("current select", miscInfo) && GetProperty("hook address", miscInfo) != -1)
{ {
HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, (wcslen(sentence) + 1) * sizeof(wchar_t)); HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, (wcslen(sentence) + 1) * sizeof(wchar_t));
memcpy(GlobalLock(hMem), sentence, (wcslen(sentence) + 1) * sizeof(wchar_t)); memcpy(GlobalLock(hMem), sentence, (wcslen(sentence) + 1) * sizeof(wchar_t));

View File

@ -13,7 +13,7 @@ extern "C"
*/ */
__declspec(dllexport) const wchar_t* OnNewSentence(const wchar_t* sentence, const InfoForExtension* miscInfo) __declspec(dllexport) const wchar_t* OnNewSentence(const wchar_t* sentence, const InfoForExtension* miscInfo)
{ {
if (GetProperty("text number", miscInfo) == 0) return sentence; if (GetProperty("hook address", miscInfo) == -1) return sentence;
wchar_t* newSentence = (wchar_t*)malloc((wcslen(sentence) + 6) * sizeof(wchar_t)); wchar_t* newSentence = (wchar_t*)malloc((wcslen(sentence) + 6) * sizeof(wchar_t));
swprintf(newSentence, wcslen(sentence) + 6, L"%s\r\n", sentence); swprintf(newSentence, wcslen(sentence) + 6, L"%s\r\n", sentence);
return newSentence; return newSentence;

View File

@ -49,7 +49,7 @@ extern "C"
wchar_t translation[10000] = {}; wchar_t translation[10000] = {};
wchar_t* message = error; wchar_t* message = error;
if (wcslen(sentence) > 2000 || GetProperty("text number", miscInfo) == 0) return sentence; if (wcslen(sentence) > 2000 || GetProperty("hook address", miscInfo) == -1) return sentence;
if (internet) if (internet)
{ {

View File

@ -5,51 +5,41 @@
#include "host.h" #include "host.h"
#include "pipe.h" #include "pipe.h"
#include "winmutex.h" #include "winmutex.h"
#include <mutex>
#include <thread>
#include <atlbase.h> #include <atlbase.h>
#include "../vnrhook/include/const.h" #include "../vnrhook/include/const.h"
#include "../vnrhook/include/defs.h" #include "../vnrhook/include/defs.h"
#include "../vnrhook/include/types.h" #include "../vnrhook/include/types.h"
#include <unordered_map> #include <unordered_map>
HANDLE preventDuplicationMutex; std::unordered_map<ThreadParameter, TextThread*, ThreadParameterHasher> textThreadsByParams;
std::unordered_map<DWORD, ProcessRecord> processRecordsByIds;
std::unordered_map<ThreadParameter, TextThread*, ThreadParameterHasher> textThreadsByParams(10); std::recursive_mutex hostMutex;
std::unordered_map<DWORD, ProcessRecord> processRecordsByIds(2);
CRITICAL_SECTION hostCs; ThreadEventCallback OnCreate, OnRemove;
ProcessEventCallback OnAttach, OnDetach;
ThreadEventCallback onCreate(nullptr), onRemove(nullptr); DWORD DUMMY[100];
ProcessEventCallback onAttach(nullptr), onDetach(nullptr);
WORD nextThreadNumber(0); #define HOST_LOCK std::lock_guard<std::recursive_mutex> hostLocker(hostMutex) // Synchronized scope for accessing private data
#define HOST_LOCK CriticalSectionLocker hostLocker(&hostCs) // Synchronized scope for accessing private data
namespace Host namespace Host
{ {
DLLEXPORT bool Start()
{
InitializeCriticalSection(&hostCs);
return true;
}
DLLEXPORT void Open() DLLEXPORT void Start(ProcessEventCallback onAttach, ProcessEventCallback onDetach, ThreadEventCallback onCreate, ThreadEventCallback onRemove)
{ {
TextThread* console = textThreadsByParams[{ 0, -1UL, -1UL, -1UL }] = new TextThread({ 0, -1UL, -1UL, -1UL }, nextThreadNumber++, USING_UNICODE); std::tie(OnAttach, OnDetach, OnCreate, OnRemove) = { onAttach, onDetach, onCreate, onRemove };
if (onCreate) onCreate(console); OnCreate(textThreadsByParams[{ 0, -1UL, -1UL, -1UL }] = new TextThread({ 0, -1UL, -1UL, -1UL }, USING_UNICODE));
CreateNewPipe(); CreateNewPipe();
} }
DLLEXPORT void Close() DLLEXPORT void Close()
{ {
// Artikash 7/25/2018: This is only called when NextHooker is closed, at which point Windows should free everything itself...right? // Artikash 7/25/2018: This is only called when NextHooker is closed, at which point Windows should free everything itself...right?
//EnterCriticalSection(&hostCs); HOST_LOCK;
//DestroyWindow(dummyWindow); for (auto i : processRecordsByIds) UnregisterProcess(i.first);
//RemoveThreads([](auto one, auto two) { return true; }, {});
////for (auto i : processRecordsByIds) UnregisterProcess(i.first); // Artikash 7/24/2018 FIXME: This segfaults since UnregisterProcess invalidates the iterator
//LeaveCriticalSection(&hostCs);
//DeleteCriticalSection(&hostCs);
//CloseHandle(preventDuplicationMutex);
} }
DLLEXPORT bool InjectProcess(DWORD processId, DWORD timeout) DLLEXPORT bool InjectProcess(DWORD processId, DWORD timeout)
@ -87,8 +77,7 @@ namespace Host
DLLEXPORT bool DetachProcess(DWORD processId) DLLEXPORT bool DetachProcess(DWORD processId)
{ {
DWORD command = HOST_COMMAND_DETACH; DWORD command = HOST_COMMAND_DETACH;
DWORD unused; return WriteFile(processRecordsByIds[processId].hostPipe, &command, sizeof(command), DUMMY, nullptr);
return WriteFile(processRecordsByIds[processId].hostPipe, &command, sizeof(command), &unused, nullptr);
} }
DLLEXPORT bool InsertHook(DWORD pid, HookParam hp, std::string name) DLLEXPORT bool InsertHook(DWORD pid, HookParam hp, std::string name)
@ -97,8 +86,7 @@ namespace Host
*(DWORD*)buffer = HOST_COMMAND_NEW_HOOK; *(DWORD*)buffer = HOST_COMMAND_NEW_HOOK;
*(HookParam*)(buffer + sizeof(DWORD)) = hp; *(HookParam*)(buffer + sizeof(DWORD)) = hp;
if (name.size()) strcpy((char*)buffer + sizeof(DWORD) + sizeof(HookParam), name.c_str()); if (name.size()) strcpy((char*)buffer + sizeof(DWORD) + sizeof(HookParam), name.c_str());
DWORD unused; return WriteFile(processRecordsByIds[pid].hostPipe, buffer, sizeof(DWORD) + sizeof(HookParam) + name.size(), DUMMY, nullptr);
return WriteFile(processRecordsByIds[pid].hostPipe, buffer, sizeof(DWORD) + sizeof(HookParam) + name.size(), &unused, nullptr);
} }
DLLEXPORT bool RemoveHook(DWORD pid, DWORD addr) DLLEXPORT bool RemoveHook(DWORD pid, DWORD addr)
@ -106,8 +94,7 @@ namespace Host
BYTE buffer[sizeof(DWORD) * 2] = {}; BYTE buffer[sizeof(DWORD) * 2] = {};
*(DWORD*)buffer = HOST_COMMAND_REMOVE_HOOK; *(DWORD*)buffer = HOST_COMMAND_REMOVE_HOOK;
*(DWORD*)(buffer + sizeof(DWORD)) = addr; *(DWORD*)(buffer + sizeof(DWORD)) = addr;
DWORD unused; return WriteFile(processRecordsByIds[pid].hostPipe, buffer, sizeof(DWORD) * 2, DUMMY, nullptr);
return WriteFile(processRecordsByIds[pid].hostPipe, buffer, sizeof(DWORD) * 2, &unused, nullptr);
} }
DLLEXPORT HookParam GetHookParam(DWORD pid, DWORD addr) DLLEXPORT HookParam GetHookParam(DWORD pid, DWORD addr)
@ -124,6 +111,8 @@ namespace Host
return ret; return ret;
} }
DLLEXPORT HookParam GetHookParam(ThreadParameter tp) { return GetHookParam(tp.pid, tp.hook); }
DLLEXPORT std::wstring GetHookName(DWORD pid, DWORD addr) DLLEXPORT std::wstring GetHookName(DWORD pid, DWORD addr)
{ {
if (pid == 0) return L"Console"; if (pid == 0) return L"Console";
@ -143,13 +132,10 @@ namespace Host
return std::wstring(A2W(buffer.c_str())); return std::wstring(A2W(buffer.c_str()));
} }
DLLEXPORT TextThread* GetThread(DWORD number) DLLEXPORT TextThread* GetThread(ThreadParameter tp)
{ {
HOST_LOCK; HOST_LOCK;
for (auto i : textThreadsByParams) return textThreadsByParams[tp];
if (i.second->Number() == number)
return i.second;
return nullptr;
} }
DLLEXPORT void AddConsoleOutput(std::wstring text) DLLEXPORT void AddConsoleOutput(std::wstring text)
@ -158,24 +144,20 @@ namespace Host
textThreadsByParams[{ 0, -1UL, -1UL, -1UL }]->AddSentence(std::wstring(text)); textThreadsByParams[{ 0, -1UL, -1UL, -1UL }]->AddSentence(std::wstring(text));
} }
DLLEXPORT void RegisterThreadCreateCallback(ThreadEventCallback cf) { onCreate = cf; } DLLEXPORT void RegisterThreadCreateCallback(ThreadEventCallback cf) { OnCreate = cf; }
DLLEXPORT void RegisterThreadRemoveCallback(ThreadEventCallback cf) { onRemove = cf; } DLLEXPORT void RegisterThreadRemoveCallback(ThreadEventCallback cf) { OnRemove = cf; }
DLLEXPORT void RegisterProcessAttachCallback(ProcessEventCallback cf) { onAttach = cf; } DLLEXPORT void RegisterProcessAttachCallback(ProcessEventCallback cf) { OnAttach = cf; }
DLLEXPORT void RegisterProcessDetachCallback(ProcessEventCallback cf) { onDetach = cf; } DLLEXPORT void RegisterProcessDetachCallback(ProcessEventCallback cf) { OnDetach = cf; }
} }
void DispatchText(DWORD pid, DWORD hook, DWORD retn, DWORD split, const BYTE * text, int len) void DispatchText(ThreadParameter tp, const BYTE* text, int len)
{ {
// jichi 2/27/2013: When PID is zero, the text comes from console, which I don't need // jichi 2/27/2013: When PID is zero, the text comes from console, which I don't need
if (!text || !pid || len <= 0) return; if (!text || len <= 0) return;
HOST_LOCK; HOST_LOCK;
ThreadParameter tp = { pid, hook, retn, split };
TextThread *it; TextThread *it;
if ((it = textThreadsByParams[tp]) == nullptr) if ((it = textThreadsByParams[tp]) == nullptr)
{ OnCreate(it = textThreadsByParams[tp] = new TextThread(tp, Host::GetHookParam(tp).type));
it = textThreadsByParams[tp] = new TextThread(tp, nextThreadNumber++, Host::GetHookParam(pid, hook).type);
if (onCreate) onCreate(it);
}
it->AddText(text, len); it->AddText(text, len);
} }
@ -186,9 +168,8 @@ void RemoveThreads(bool(*RemoveIf)(ThreadParameter, ThreadParameter), ThreadPara
for (auto i : textThreadsByParams) for (auto i : textThreadsByParams)
if (RemoveIf(i.first, cmp)) if (RemoveIf(i.first, cmp))
{ {
if (onRemove) onRemove(i.second); OnRemove(i.second);
//delete i.second; // Artikash 7/24/2018: FIXME: Qt GUI updates on another thread, so I can't delete this yet. //delete i.second; // Artikash 7/24/2018: FIXME: Qt GUI updates on another thread, so I can't delete this yet.
i.second->Clear(); // Temp workaround to free some memory.
removedThreads.push_back(i.first); removedThreads.push_back(i.first);
} }
for (auto i : removedThreads) textThreadsByParams.erase(i); for (auto i : removedThreads) textThreadsByParams.erase(i);
@ -204,7 +185,7 @@ void RegisterProcess(DWORD pid, HANDLE hostPipe)
record.process_handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); record.process_handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
record.hookman_mutex = OpenMutexW(MUTEX_ALL_ACCESS, FALSE, (ITH_HOOKMAN_MUTEX_ + std::to_wstring(pid)).c_str()); record.hookman_mutex = OpenMutexW(MUTEX_ALL_ACCESS, FALSE, (ITH_HOOKMAN_MUTEX_ + std::to_wstring(pid)).c_str());
processRecordsByIds[pid] = record; processRecordsByIds[pid] = record;
if (onAttach) onAttach(pid); OnAttach(pid);
} }
void UnregisterProcess(DWORD pid) void UnregisterProcess(DWORD pid)
@ -216,9 +197,9 @@ void UnregisterProcess(DWORD pid)
UnmapViewOfFile(pr.hookman_map); UnmapViewOfFile(pr.hookman_map);
CloseHandle(pr.process_handle); CloseHandle(pr.process_handle);
CloseHandle(pr.hookman_section); CloseHandle(pr.hookman_section);
processRecordsByIds.erase(pid); processRecordsByIds[pid] = {};
RemoveThreads([](auto one, auto two) { return one.pid == two.pid; }, { pid, 0, 0, 0 }); RemoveThreads([](auto one, auto two) { return one.pid == two.pid; }, { pid, 0, 0, 0 });
if (onDetach) onDetach(pid); OnDetach(pid);
} }
// EOF // EOF

View File

@ -34,8 +34,7 @@ struct ThreadParameterHasher
namespace Host namespace Host
{ {
DLLEXPORT void Open(); DLLEXPORT void Start(ProcessEventCallback onAttach, ProcessEventCallback onDetach, ThreadEventCallback onCreate, ThreadEventCallback onRemove);
DLLEXPORT bool Start();
DLLEXPORT void Close(); DLLEXPORT void Close();
DLLEXPORT bool InjectProcess(DWORD pid, DWORD timeout = 5000); DLLEXPORT bool InjectProcess(DWORD pid, DWORD timeout = 5000);
DLLEXPORT bool DetachProcess(DWORD pid); DLLEXPORT bool DetachProcess(DWORD pid);
@ -43,9 +42,10 @@ namespace Host
DLLEXPORT bool InsertHook(DWORD pid, HookParam hp, std::string name = ""); DLLEXPORT bool InsertHook(DWORD pid, HookParam hp, std::string name = "");
DLLEXPORT bool RemoveHook(DWORD pid, DWORD addr); DLLEXPORT bool RemoveHook(DWORD pid, DWORD addr);
DLLEXPORT HookParam GetHookParam(DWORD pid, DWORD addr); DLLEXPORT HookParam GetHookParam(DWORD pid, DWORD addr);
DLLEXPORT HookParam GetHookParam(ThreadParameter tp);
DLLEXPORT std::wstring GetHookName(DWORD pid, DWORD addr); DLLEXPORT std::wstring GetHookName(DWORD pid, DWORD addr);
DLLEXPORT TextThread* GetThread(DWORD number); DLLEXPORT TextThread* GetThread(ThreadParameter tp);
DLLEXPORT void AddConsoleOutput(std::wstring text); DLLEXPORT void AddConsoleOutput(std::wstring text);
DLLEXPORT void RegisterThreadCreateCallback(ThreadEventCallback cf); DLLEXPORT void RegisterThreadCreateCallback(ThreadEventCallback cf);
@ -54,7 +54,7 @@ namespace Host
DLLEXPORT void RegisterProcessDetachCallback(ProcessEventCallback cf); DLLEXPORT void RegisterProcessDetachCallback(ProcessEventCallback cf);
} }
void DispatchText(DWORD pid, DWORD hook, DWORD retn, DWORD split, const BYTE *text, int len); void DispatchText(ThreadParameter tp, const BYTE *text, int len);
void RemoveThreads(bool(*RemoveIf)(ThreadParameter, ThreadParameter), ThreadParameter cmp); void RemoveThreads(bool(*RemoveIf)(ThreadParameter, ThreadParameter), ThreadParameter cmp);
void RegisterProcess(DWORD pid, HANDLE hostPipe); void RegisterProcess(DWORD pid, HANDLE hostPipe);
void UnregisterProcess(DWORD pid); void UnregisterProcess(DWORD pid);

View File

@ -10,14 +10,14 @@
void CreateNewPipe() void CreateNewPipe()
{ {
CloseHandle(CreateThread(nullptr, 0, [](auto) std::thread([]()
{ {
HANDLE hookPipe = CreateNamedPipeW(ITH_TEXT_PIPE, PIPE_ACCESS_INBOUND, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, PIPE_UNLIMITED_INSTANCES, PIPE_BUFFER_SIZE, PIPE_BUFFER_SIZE, MAXDWORD, NULL); HANDLE hookPipe = CreateNamedPipeW(ITH_TEXT_PIPE, PIPE_ACCESS_INBOUND, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, PIPE_UNLIMITED_INSTANCES, PIPE_BUFFER_SIZE, PIPE_BUFFER_SIZE, MAXDWORD, NULL);
HANDLE hostPipe = CreateNamedPipeW(ITH_COMMAND_PIPE, PIPE_ACCESS_OUTBOUND, 0, PIPE_UNLIMITED_INSTANCES, PIPE_BUFFER_SIZE, PIPE_BUFFER_SIZE, MAXDWORD, NULL); HANDLE hostPipe = CreateNamedPipeW(ITH_COMMAND_PIPE, PIPE_ACCESS_OUTBOUND, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, PIPE_UNLIMITED_INSTANCES, PIPE_BUFFER_SIZE, PIPE_BUFFER_SIZE, MAXDWORD, NULL);
ConnectNamedPipe(hookPipe, nullptr); ConnectNamedPipe(hookPipe, nullptr);
// jichi 9/27/2013: why recursion? // jichi 9/27/2013: why recursion?
// Artikash 5/20/2018: To create a new pipe for another process // Artikash 5/20/2018: Easy way to create a new pipe for another process
CreateNewPipe(); CreateNewPipe();
BYTE buffer[PIPE_BUFFER_SIZE + 1] = {}; BYTE buffer[PIPE_BUFFER_SIZE + 1] = {};
@ -44,10 +44,13 @@ void CreateNewPipe()
Host::AddConsoleOutput(A2W((LPCSTR)(buffer + sizeof(DWORD) * 2))); // Text Host::AddConsoleOutput(A2W((LPCSTR)(buffer + sizeof(DWORD) * 2))); // Text
break; break;
} }
else DispatchText(processId, else DispatchText(
{
processId,
*(DWORD*)buffer, // Hook address *(DWORD*)buffer, // Hook address
*(DWORD*)(buffer + sizeof(DWORD)), // Return address *(DWORD*)(buffer + sizeof(DWORD)), // Return address
*(DWORD*)(buffer + sizeof(DWORD) * 2), // Split *(DWORD*)(buffer + sizeof(DWORD) * 2) // Split
},
buffer + HEADER_SIZE, // Data buffer + HEADER_SIZE, // Data
bytesRead - HEADER_SIZE // Data size bytesRead - HEADER_SIZE // Data size
); );
@ -58,9 +61,7 @@ void CreateNewPipe()
UnregisterProcess(processId); UnregisterProcess(processId);
CloseHandle(hookPipe); CloseHandle(hookPipe);
CloseHandle(hostPipe); CloseHandle(hostPipe);
return (DWORD)0; }).detach();
},
nullptr, 0, nullptr));
} }
// EOF // EOF

View File

@ -6,44 +6,24 @@
#endif // _MSC_VER #endif // _MSC_VER
#include "textthread.h" #include "textthread.h"
#include <mutex>
#include "../vnrhook/include/const.h" #include "../vnrhook/include/const.h"
#include "winmutex.h" #include "winmutex.h"
#define TT_LOCK CriticalSectionLocker ttLocker(&ttCs) // Synchronized scope for accessing private data #define TT_LOCK std::lock_guard<std::recursive_mutex> ttLocker(ttMutex) // Synchronized scope for accessing private data
TextThread::TextThread(ThreadParameter tp, unsigned int threadNumber, DWORD status) : TextThread::TextThread(ThreadParameter tp, DWORD status) :
storage(),
sentenceBuffer(),
status(status), status(status),
timestamp(GetTickCount()), timestamp(GetTickCount()),
threadNumber(threadNumber), Output(nullptr),
output(nullptr), tp(tp),
tp(tp) flushThread([&]() { while (Sleep(25), FlushSentenceBuffer()); })
{ {}
InitializeCriticalSection(&ttCs);
flushThread = CreateThread(nullptr, 0, [](void* textThread)
{
while (true)
{
Sleep(100);
((TextThread*)textThread)->FlushSentenceBuffer();
}
return (DWORD)0;
}, this, 0, nullptr);
}
TextThread::~TextThread() TextThread::~TextThread()
{ {
EnterCriticalSection(&ttCs); status = -1UL;
LeaveCriticalSection(&ttCs); flushThread.join();
DeleteCriticalSection(&ttCs);
}
void TextThread::Clear()
{
TT_LOCK;
storage.clear();
storage.shrink_to_fit();
} }
std::wstring TextThread::GetStore() std::wstring TextThread::GetStore()
@ -52,10 +32,11 @@ std::wstring TextThread::GetStore()
return storage; return storage;
} }
void TextThread::FlushSentenceBuffer() bool TextThread::FlushSentenceBuffer()
{ {
TT_LOCK; TT_LOCK;
if (timestamp - GetTickCount() < 250 || sentenceBuffer.size() == 0) return; // TODO: let user change delay before sentence is flushed if (status == -1UL) return false;
if (timestamp - GetTickCount() < 250 || sentenceBuffer.size() == 0) return true; // TODO: let user change delay before sentence is flushed
std::wstring sentence; std::wstring sentence;
if (status & USING_UNICODE) if (status & USING_UNICODE)
{ {
@ -75,12 +56,13 @@ void TextThread::FlushSentenceBuffer()
} }
AddSentence(sentence); AddSentence(sentence);
sentenceBuffer.clear(); sentenceBuffer.clear();
return true;
} }
void TextThread::AddSentence(std::wstring sentence) void TextThread::AddSentence(std::wstring sentence)
{ {
TT_LOCK; TT_LOCK;
if (output) sentence = output(this, sentence); if (Output) sentence = Output(this, sentence);
storage.append(sentence); storage.append(sentence);
} }

View File

@ -8,13 +8,15 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include <functional> #include <functional>
#include <mutex>
#include <thread>
struct ThreadParameter struct ThreadParameter
{ {
DWORD pid; // jichi: 5/11/2014: The process ID DWORD pid; // jichi: 5/11/2014: The process ID
unsigned __int64 hook; // Artikash 6/6/2018: The start address of the hook unsigned __int64 hook; // Artikash 6/6/2018: The insertion address of the hook
unsigned __int64 retn; // jichi 5/11/2014: The return address of the hook unsigned __int64 retn; // jichi 5/11/2014: The return address of the hook
__int64 spl; // jichi 5/11/2014: the processed split value of the hook paramete unsigned __int64 spl; // jichi 5/11/2014: the processed split value of the hook paramete
// Artikash 5/31/2018: required for unordered_map to work with struct key // Artikash 5/31/2018: required for unordered_map to work with struct key
friend bool operator==(const ThreadParameter& one, const ThreadParameter& two) friend bool operator==(const ThreadParameter& one, const ThreadParameter& two)
@ -31,29 +33,27 @@ typedef std::function<std::wstring(TextThread*, std::wstring)> ThreadOutputCallb
class TextThread class TextThread
{ {
public: public:
TextThread(ThreadParameter tp, unsigned int threadNumber, DWORD status); TextThread(ThreadParameter tp, DWORD status);
~TextThread(); virtual ~TextThread();
virtual std::wstring GetStore(); virtual std::wstring GetStore();
WORD Number() const { return threadNumber; }
ThreadParameter GetThreadParameter() { return tp; } ThreadParameter GetThreadParameter() { return tp; }
void RegisterOutputCallBack(ThreadOutputCallback cb) { output = cb; } void RegisterOutputCallBack(ThreadOutputCallback cb) { Output = cb; }
void Clear();
void AddText(const BYTE *con, int len); void AddText(const BYTE *con, int len);
void FlushSentenceBuffer();
void AddSentence(std::wstring sentence); void AddSentence(std::wstring sentence);
private: private:
CRITICAL_SECTION ttCs; bool FlushSentenceBuffer();
ThreadOutputCallback output;
ThreadOutputCallback Output;
std::vector<char> sentenceBuffer; std::vector<char> sentenceBuffer;
std::wstring storage; std::wstring storage;
ThreadParameter tp; ThreadParameter tp;
HANDLE flushThread; std::recursive_mutex ttMutex;
unsigned int threadNumber; std::thread flushThread;
DWORD timestamp; DWORD timestamp;
DWORD status; DWORD status;
}; };

View File

@ -8,28 +8,14 @@
# pragma warning(disable:4800) // C4800: forcing value to bool # pragma warning(disable:4800) // C4800: forcing value to bool
#endif // _MSC_VER #endif // _MSC_VER
// Artikash 7/20/2018: these are similar to std::lock guard but use Winapi objects // Artikash 7/20/2018: similar to std::lock guard but use Winapi objects for cross process comms
class MutexLocker class MutexLocker
{ {
HANDLE mutex; HANDLE mutex;
public: public:
explicit MutexLocker(HANDLE mutex) : mutex(mutex) explicit MutexLocker(HANDLE mutex) : mutex(mutex) { WaitForSingleObject(mutex, 0); }
{
WaitForSingleObject(mutex, 0);
}
~MutexLocker() { if (mutex != INVALID_HANDLE_VALUE && mutex != nullptr) ReleaseMutex(mutex); } ~MutexLocker() { if (mutex != INVALID_HANDLE_VALUE && mutex != nullptr) ReleaseMutex(mutex); }
}; };
class CriticalSectionLocker
{
CRITICAL_SECTION* cs;
public:
explicit CriticalSectionLocker(CRITICAL_SECTION* cs) : cs(cs)
{
EnterCriticalSection(cs);
}
~CriticalSectionLocker() { LeaveCriticalSection(cs); }
};
// EOF // EOF