diff --git a/GUI/GUI.pro b/GUI/GUI.pro index 83dd4d2..fac6fea 100644 --- a/GUI/GUI.pro +++ b/GUI/GUI.pro @@ -24,10 +24,12 @@ CONFIG += c++11 SOURCES += \ main.cpp \ - mainwindow.cpp + mainwindow.cpp \ + hostsignaller.cpp HEADERS += \ - mainwindow.h + mainwindow.h \ + hostsignaller.h FORMS += \ mainwindow.ui diff --git a/GUI/hostsignaller.cpp b/GUI/hostsignaller.cpp new file mode 100644 index 0000000..fb5a9a2 --- /dev/null +++ b/GUI/hostsignaller.cpp @@ -0,0 +1,19 @@ +#include "hostsignaller.h" +#include "../texthook/host.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); + thread->RegisterOutputCallBack([&](TextThread* thread, std::wstring output) + { + //output = DispatchToExtensions(output); + emit ThreadOutput(thread, QString::fromWCharArray(output.c_str())); + return output; + }); + }); + Host::RegisterThreadRemoveCallback([&](TextThread* thread){ emit RemoveThread(thread); }); +} diff --git a/GUI/hostsignaller.h b/GUI/hostsignaller.h new file mode 100644 index 0000000..537d3a5 --- /dev/null +++ b/GUI/hostsignaller.h @@ -0,0 +1,24 @@ +#ifndef HOSTSIGNALLER_H +#define HOSTSIGNALLER_H + +#include +#include +#include "../texthook/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); + void ThreadOutput(TextThread* thread, QString output); +}; + +#endif // HOSTSIGNALLER_H diff --git a/GUI/mainwindow.cpp b/GUI/mainwindow.cpp index 09369d7..306e6f7 100644 --- a/GUI/mainwindow.cpp +++ b/GUI/mainwindow.cpp @@ -1,11 +1,13 @@ #include "mainwindow.h" #include "ui_mainwindow.h" +#include "QCoreApplication" #include "QTextBrowser" #include "QMessageBox" #include "QComboBox" #include "QLineEdit" -#include "QTableWidget" #include "QInputDialog" +#include +#include #include #include #include @@ -33,63 +35,82 @@ QString ProcessString(DWORD processId) QString TextThreadString(TextThread* thread) { ThreadParameter tp = thread->GetThreadParameter(); - return QString("%1:%2:%3:%4:%5:%6").arg( + return QString("%1:%2:%3:%4:%5: ").arg( QString::number(thread->Number()), QString::number(tp.pid), QString::number(tp.hook, 16), QString::number(tp.retn, 16), - QString::number(tp.spl, 16), - QString::fromWCharArray(Host::GetHookName(tp.pid, tp.hook).c_str()) - ); + QString::number(tp.spl, 16) + ).toUpper() + QString::fromWCharArray(Host::GetHookName(tp.pid, tp.hook).c_str()); } MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), - ui(new Ui::MainWindow) + ui(new Ui::MainWindow), + hostSignaller(new HostSignaller) { ui->setupUi(this); mainWindow = this; processCombo = mainWindow->findChild("processCombo"); ttCombo = mainWindow->findChild("ttCombo"); - textOutput = this->findChild("textOutput"); + textOutput = mainWindow->findChild("textOutput"); Host::Start(); - Host::RegisterProcessAttachCallback(AddProcess); - Host::RegisterProcessDetachCallback(RemoveProcess); - Host::RegisterThreadCreateCallback(AddThread); - Host::RegisterThreadRemoveCallback(RemoveThread); + hostSignaller->Initialize(); + connect(hostSignaller, &HostSignaller::AddProcess, this, &MainWindow::AddProcess); + connect(hostSignaller, &HostSignaller::RemoveProcess, this, &MainWindow::RemoveProcess); + connect(hostSignaller, &HostSignaller::AddThread, this, &MainWindow::AddThread); + connect(hostSignaller, &HostSignaller::RemoveThread, this, &MainWindow::RemoveThread); + connect(hostSignaller, &HostSignaller::ThreadOutput, this, &MainWindow::ThreadOutput); Host::Open(); } MainWindow::~MainWindow() { Host::Close(); + delete hostSignaller; delete ui; } -void AddProcess(DWORD processId) +void MainWindow::AddProcess(unsigned int processId) { - processCombo->addItem(ProcessString(processId)); + processCombo->addItem(ProcessString(processId), Qt::AlignHCenter); } -void RemoveProcess(DWORD processId) +void MainWindow::RemoveProcess(unsigned int processId) { - processCombo->removeItem(processCombo->findText(ProcessString(processId))); + for (int i = 0; i < processCombo->count(); ++i) + if (processCombo->itemText(i).split(":")[0] == QString::number(processId)) + processCombo->removeItem(i); } -void AddThread(TextThread* thread) +void MainWindow::AddThread(TextThread* thread) { ttCombo->addItem(TextThreadString(thread)); - thread->RegisterOutputCallBack([](auto thread, auto data) - { - if (ttCombo->currentText() == TextThreadString(thread)) textOutput->append(QString::fromWCharArray(data.c_str())); - return data + L"\r\n"; - }); } -void RemoveThread(TextThread* thread) +void MainWindow::RemoveThread(TextThread* thread) { - ttCombo->removeItem(ttCombo->findText(TextThreadString(thread))); + for (int i = 0; i < ttCombo->count(); ++i) + if (ttCombo->itemText(i).split(":")[0] == QString::number(thread->Number())) + { + ttCombo->removeItem(i); + if (i == ttCombo->currentIndex()) + { + ttCombo->setCurrentIndex(0); + on_ttCombo_activated(0); + } + } +} + +void MainWindow::ThreadOutput(TextThread* thread, QString output) +{ + if (TextThreadString(thread) == ttCombo->currentText()) + { + textOutput->moveCursor(QTextCursor::End); + textOutput->insertPlainText(output); + textOutput->moveCursor(QTextCursor::End); + } } void MainWindow::on_attachButton_clicked() @@ -104,5 +125,5 @@ void MainWindow::on_detachButton_clicked() void MainWindow::on_ttCombo_activated(int index) { - textOutput->setText(QString::fromWCharArray(Host::GetThread(index)->GetStore().c_str())); + textOutput->setText(QString::fromWCharArray(Host::GetThread(ttCombo->itemText(index).split(":")[0].toInt())->GetStore().c_str())); } diff --git a/GUI/mainwindow.h b/GUI/mainwindow.h index 2d4781c..6169cbd 100644 --- a/GUI/mainwindow.h +++ b/GUI/mainwindow.h @@ -4,6 +4,7 @@ #include #include #include "../texthook/textthread.h" +#include "hostsignaller.h" namespace Ui { @@ -18,18 +19,20 @@ public: explicit MainWindow(QWidget *parent = nullptr); ~MainWindow(); + QString ProcessOutput(TextThread *thread, QString output); private slots: void on_attachButton_clicked(); void on_detachButton_clicked(); void on_ttCombo_activated(int index); + void AddProcess(unsigned int processId); + void RemoveProcess(unsigned int processId); + void AddThread(TextThread* thread); + void RemoveThread(TextThread* thread); + void ThreadOutput(TextThread* thread, QString output); private: Ui::MainWindow *ui; + HostSignaller* hostSignaller; }; -void AddProcess(DWORD processId); -void RemoveProcess(DWORD processId); -void AddThread(TextThread* thread); -void RemoveThread(TextThread* thread); - #endif // MAINWINDOW_H diff --git a/GUI/mainwindow.ui b/GUI/mainwindow.ui index b8e4cad..d9b5878 100644 --- a/GUI/mainwindow.ui +++ b/GUI/mainwindow.ui @@ -10,6 +10,11 @@ 600 + + + 10 + + NextHooker @@ -33,6 +38,13 @@ + + + + QComboBox::InsertAtBottom + + + @@ -40,9 +52,6 @@ - - - @@ -79,6 +88,11 @@ 0 + + + 12 + + @@ -92,7 +106,7 @@ 0 0 800 - 21 + 23 diff --git a/texthook/host.cc b/texthook/host.cc index 78c4fb9..668aee8 100644 --- a/texthook/host.cc +++ b/texthook/host.cc @@ -45,10 +45,6 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID unused) // jichi 8/24/2013: Create hidden window so that ITH can access timer and events dummyWindow = CreateWindowW(L"Button", L"InternalWindow", 0, 0, 0, 0, 0, 0, 0, hinstDLL, 0); break; - case DLL_PROCESS_DETACH: - Host::Close(); - DestroyWindow(dummyWindow); - break; default: break; } @@ -73,7 +69,6 @@ namespace Host onAttach = onDetach = nullptr; onCreate = onRemove = nullptr; nextThreadNumber = 0; - // Console text thread return true; } } @@ -92,8 +87,9 @@ namespace Host { EnterCriticalSection(&hostCs); running = false; + DestroyWindow(dummyWindow); RemoveThreads([](auto one, auto two) { return true; }, {}); - for (auto i : processRecordsByIds) UnregisterProcess(i.first); + //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); @@ -243,7 +239,8 @@ void RemoveThreads(bool(*RemoveIf)(ThreadParameter, ThreadParameter), ThreadPara if (RemoveIf(i.first, cmp)) { if (onRemove) onRemove(i.second); - delete i.second; + //delete i.second; // Artikash 7/24/2018: FIXME: Qt GUI updates on another thread, so I can't delete this yet. + i.second->Reset(); // Temp workaround to free some memory. removedThreads.push_back(i.first); } for (auto i : removedThreads) textThreadsByParams.erase(i); @@ -276,4 +273,4 @@ void UnregisterProcess(DWORD pid) if (onDetach) onDetach(pid); } -// EOF \ No newline at end of file +// EOF diff --git a/texthook/host.h b/texthook/host.h index 9154786..48b8667 100644 --- a/texthook/host.h +++ b/texthook/host.h @@ -9,6 +9,7 @@ #include #include "textthread.h" #include +#include #include "../vnrhook/include/types.h" struct ProcessRecord @@ -20,8 +21,8 @@ struct ProcessRecord HANDLE hostPipe; }; -typedef void(*ProcessEventCallback)(DWORD pid); -typedef void(*ThreadEventCallback)(TextThread*); +typedef std::function ProcessEventCallback; +typedef std::function ThreadEventCallback; struct ThreadParameterHasher { diff --git a/texthook/textthread.h b/texthook/textthread.h index b67d016..219e1b7 100644 --- a/texthook/textthread.h +++ b/texthook/textthread.h @@ -7,6 +7,7 @@ #include #include #include +#include struct ThreadParameter { @@ -23,7 +24,7 @@ struct ThreadParameter }; class TextThread; -typedef std::wstring(*ThreadOutputCallback)(TextThread*, std::wstring data); +typedef std::function ThreadOutputCallback; //extern DWORD split_time,repeat_count,global_filter,cyclic_remove;