diff --git a/GUI/CMakeLists.txt b/GUI/CMakeLists.txt index 95d0397..476f311 100644 --- a/GUI/CMakeLists.txt +++ b/GUI/CMakeLists.txt @@ -9,7 +9,7 @@ set(gui_SRCS main.cpp mainwindow.cpp misc.cpp - extensions.cpp + extendialog.cpp tests.cpp host/host.cc host/textthread.cc diff --git a/GUI/extendialog.cpp b/GUI/extendialog.cpp new file mode 100644 index 0000000..fe28cd6 --- /dev/null +++ b/GUI/extendialog.cpp @@ -0,0 +1,117 @@ +#include "extendialog.h" +#include "ui_extendialog.h" +#include "types.h" +#include + +ListRearrangeFilter::ListRearrangeFilter(QWidget* parent) : QObject(parent) {} + +bool ListRearrangeFilter::eventFilter(QObject*, QEvent* event) +{ + if (event->type() == QEvent::ChildRemoved) emit SigRearranged(); + return false; +} + +ExtenDialog::ExtenDialog(QWidget* parent) : + QDialog(parent), + ui(new Ui::ExtenDialog), + filter(new ListRearrangeFilter(this)) +{ + ui->setupUi(this); + + extenList = findChild("extenList"); + extenList->installEventFilter(filter); + connect(filter, &ListRearrangeFilter::SigRearranged, this, &ExtenDialog::Rearrange); + + if (extensions.empty()) + { + extenSaveFile.open(QIODevice::ReadOnly); + for (auto extenName : QString(extenSaveFile.readAll()).split(">")) Load(extenName); + extenSaveFile.close(); + } + + for (auto extension : extensions) + extenList->addItem(extension.name); +} + +ExtenDialog::~ExtenDialog() +{ + delete ui; +} + +bool ExtenDialog::DispatchSentenceToExtensions(std::wstring& sentence, std::unordered_map miscInfo) +{ + bool success = true; + wchar_t* sentenceBuffer = (wchar_t*)HeapAlloc(GetProcessHeap(), 0, (sentence.size() + 1) * sizeof(wchar_t)); + wcscpy_s(sentenceBuffer, sentence.size() + 1, sentence.c_str()); + + InfoForExtension miscInfoLinkedList{ "", 0, nullptr }; + InfoForExtension* miscInfoTraverser = &miscInfoLinkedList; + for (auto& i : miscInfo) miscInfoTraverser = miscInfoTraverser->next = new InfoForExtension{ i.first.c_str(), i.second, nullptr }; + + std::shared_lock sharedLock(extenMutex); + for (auto extension : extensions) + { + wchar_t* nextBuffer = extension.callback(sentenceBuffer, &miscInfoLinkedList); + if (nextBuffer == nullptr) { success = false; break; } + if (nextBuffer != sentenceBuffer) HeapFree(GetProcessHeap(), 0, sentenceBuffer); + sentenceBuffer = nextBuffer; + } + sentence = std::wstring(sentenceBuffer); + + HeapFree(GetProcessHeap(), 0, sentenceBuffer); + return success; +} + +void ExtenDialog::Load(QString extenName) +{ + // Extension is dll and exports "OnNewSentence" + HMODULE module = GetModuleHandleW(extenName.toStdWString().c_str()); + if (!module) module = LoadLibraryW(extenName.toStdWString().c_str()); + if (!module) return; + FARPROC callback = GetProcAddress(module, "OnNewSentence"); + if (!callback) return; + extensions.push_back({ extenName, (wchar_t*(*)(const wchar_t*, const InfoForExtension*))callback }); +} + +void ExtenDialog::Unload(QString extenName) +{ + extensions.erase(std::remove_if(extensions.begin(), extensions.end(), [&](Extension extension) { return extension.name == extenName; }), extensions.end()); + FreeLibrary(GetModuleHandleW(extenName.toStdWString().c_str())); +} + +void ExtenDialog::on_addButton_clicked() +{ + QString extenFileName = QFileDialog::getOpenFileName(this, "Select Extension", "C:\\", "Extensions (*.dll)"); + if (!extenFileName.size()) return; + QString extenName = extenFileName.mid(extenFileName.lastIndexOf("/") + 1); + QFile::copy(extenFileName, extenName); + Load(extenName.left(extenName.lastIndexOf(".dll"))); + Sync(); +} + +void ExtenDialog::on_rmvButton_clicked() +{ + for (auto extenName : extenList->selectedItems()) Unload(extenName->text()); + Sync(); +} + +void ExtenDialog::Rearrange() +{ + QVector newExtensions; + for (int i = 0; i < extenList->count(); ++i) + newExtensions.push_back(*std::find_if(extensions.begin(), extensions.end(), [=](Extension extension) { return extension.name == extenList->item(i)->text(); })); + extensions = newExtensions; + Sync(); +} + +void ExtenDialog::Sync() +{ + extenList->clear(); + extenSaveFile.open(QIODevice::WriteOnly | QIODevice::Truncate); + for (auto extension : extensions) + { + extenList->addItem(extension.name); + extenSaveFile.write((extension.name + ">").toUtf8()); + } + extenSaveFile.close(); +} diff --git a/GUI/extendialog.h b/GUI/extendialog.h new file mode 100644 index 0000000..2ad0c0e --- /dev/null +++ b/GUI/extendialog.h @@ -0,0 +1,70 @@ +#ifndef EXTENSIONS_H +#define EXTENSIONS_H + +#include "qtcommon.h" +#include +#include +#include +#include + +namespace Ui +{ + class ExtenDialog; +} + +class ListRearrangeFilter : public QObject +{ + Q_OBJECT + +public: + explicit ListRearrangeFilter(QWidget* parent = nullptr); + +protected: + bool eventFilter(QObject*, QEvent* event); + +signals: + void SigRearranged(); +}; + +class ExtenDialog : public QDialog +{ + Q_OBJECT + +public: + explicit ExtenDialog(QWidget* parent = nullptr); + ~ExtenDialog(); + static bool DispatchSentenceToExtensions(std::wstring& sentence, std::unordered_map miscInfo); + +private slots: + void on_addButton_clicked(); + void on_rmvButton_clicked(); + void Rearrange(); + +private: + struct InfoForExtension + { + const char* name; + int64_t value; + InfoForExtension* next; + ~InfoForExtension() { if (next) delete next; }; + }; + struct Extension + { + QString name; + wchar_t*(*callback)(const wchar_t*, const InfoForExtension*); + }; + inline static std::shared_mutex extenMutex; + inline static QVector extensions; + + static void Load(QString extenName); + static void Unload(QString extenName); + + void Sync(); + + Ui::ExtenDialog* ui; + QFile extenSaveFile = QFile("Extensions.txt"); + QListWidget* extenList; + ListRearrangeFilter* filter; +}; + +#endif // EXTENSIONS_H diff --git a/GUI/extendialog.ui b/GUI/extendialog.ui new file mode 100644 index 0000000..31d3257 --- /dev/null +++ b/GUI/extendialog.ui @@ -0,0 +1,78 @@ + + + ExtenDialog + + + + 0 + 0 + 400 + 300 + + + + Extensions + + + + + + QAbstractItemView::InternalMove + + + Qt::MoveAction + + + QAbstractItemView::MultiSelection + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Add + + + + + + + Remove + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + diff --git a/GUI/extensions.cpp b/GUI/extensions.cpp deleted file mode 100644 index 082f3d0..0000000 --- a/GUI/extensions.cpp +++ /dev/null @@ -1,67 +0,0 @@ -#include "extensions.h" -#include "types.h" - -static std::optional LoadExtension(QString extenName) -{ - // Extension is dll and exports "OnNewSentence" - HMODULE module = GetModuleHandleW(extenName.toStdWString().c_str()); - if (!module) module = LoadLibraryW(extenName.toStdWString().c_str()); - if (!module) return {}; - FARPROC callback = GetProcAddress(module, "OnNewSentence"); - if (!callback) return {}; - return Extension{ extenName, (wchar_t*(*)(const wchar_t*, const InfoForExtension*))callback }; -} - -void Extension::Load(QString extenName) -{ - LOCK(extenMutex); - if (auto extension = LoadExtension(extenName)) extensions.push_back(extension.value()); -} - -void Extension::SendToBack(QString extenName) -{ - LOCK(extenMutex); - Extension* extenIter = std::find_if(extensions.begin(), extensions.end(), [&](Extension extension) { return extension.name == extenName; }); - Extension extension = *extenIter; - extensions.erase(extenIter); - extensions.push_back(extension); -} - -void Extension::Unload(QString extenName) -{ - LOCK(extenMutex); - extensions.erase(std::find_if(extensions.begin(), extensions.end(), [&](Extension extension) { return extension.name == extenName; })); - FreeLibrary(GetModuleHandleW(extenName.toStdWString().c_str())); -} - -QVector Extension::GetNames() -{ - std::shared_lock sharedLock(extenMutex); - QVector ret; - for (auto extension : extensions) ret.push_back(extension.name); - return ret; -} - -bool Extension::DispatchSentence(std::wstring& sentence, std::unordered_map miscInfo) -{ - bool success = true; - wchar_t* sentenceBuffer = (wchar_t*)HeapAlloc(GetProcessHeap(), 0, (sentence.size() + 1) * sizeof(wchar_t)); - wcscpy_s(sentenceBuffer, sentence.size() + 1, sentence.c_str()); - - InfoForExtension miscInfoLinkedList{ "", 0, nullptr }; - InfoForExtension* miscInfoTraverser = &miscInfoLinkedList; - for (auto& i : miscInfo) miscInfoTraverser = miscInfoTraverser->next = new InfoForExtension{ i.first.c_str(), i.second, nullptr }; - - std::shared_lock sharedLock(extenMutex); - for (auto extension : extensions) - { - wchar_t* nextBuffer = extension.callback(sentenceBuffer, &miscInfoLinkedList); - if (nextBuffer == nullptr) { success = false; break; } - if (nextBuffer != sentenceBuffer) HeapFree(GetProcessHeap(), 0, sentenceBuffer); - sentenceBuffer = nextBuffer; - } - sentence = std::wstring(sentenceBuffer); - - HeapFree(GetProcessHeap(), 0, sentenceBuffer); - return success; -} diff --git a/GUI/extensions.h b/GUI/extensions.h deleted file mode 100644 index fd414f9..0000000 --- a/GUI/extensions.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef EXTENSIONS_H -#define EXTENSIONS_H - -#include "qtcommon.h" -#include - -struct InfoForExtension -{ - const char* name; - int64_t value; - InfoForExtension* next; - ~InfoForExtension() { if (next) delete next; }; -}; - -class Extension -{ -public: - static bool DispatchSentence(std::wstring& sentence, std::unordered_map miscInfo); - static void Load(QString extenName); - static void SendToBack(QString extenName); - static void Unload(QString extenName); - static QVector GetNames(); - - QString name; - wchar_t* (*callback)(const wchar_t*, const InfoForExtension*); - -private: - inline static std::shared_mutex extenMutex; - inline static QVector extensions; -}; - -#endif // EXTENSIONS_H diff --git a/GUI/mainwindow.cpp b/GUI/mainwindow.cpp index e094c76..15912f6 100644 --- a/GUI/mainwindow.cpp +++ b/GUI/mainwindow.cpp @@ -1,7 +1,7 @@ #include "mainwindow.h" #include "ui_mainwindow.h" #include "defs.h" -#include "extensions.h" +#include "extendialog.h" #include "misc.h" #include #include @@ -9,7 +9,8 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), - ui(new Ui::MainWindow) + ui(new Ui::MainWindow), + extenDialog(new ExtenDialog(this)) { ui->setupUi(this); @@ -18,19 +19,6 @@ MainWindow::MainWindow(QWidget *parent) : extenCombo = findChild("extenCombo"); textOutput = findChild("textOutput"); - QFile extenSaveFile("Extensions.txt"); - if (extenSaveFile.exists()) - { - extenSaveFile.open(QIODevice::ReadOnly); - for (auto extenName : QString(extenSaveFile.readAll()).split(">")) Extension::Load(extenName); - } - else - { - for (auto file : QDir().entryList()) - if (file.endsWith(".dll") && file != ITH_DLL) Extension::Load(file.left(file.lastIndexOf(".dll"))); - } - ReloadExtensions(); - if (settings.contains("Window")) this->setGeometry(settings.value("Window").toRect()); // TODO: add GUI for changing these if (settings.contains("Flush_Delay")) TextThread::flushDelay = settings.value("Flush_Delay").toInt(); @@ -120,7 +108,7 @@ void MainWindow::ThreadOutput(QString threadString, QString output) bool MainWindow::ProcessThreadOutput(TextThread* thread, std::wstring& output) { - if (Extension::DispatchSentence(output, GetInfoForExtensions(thread))) + if (ExtenDialog::DispatchSentenceToExtensions(output, GetInfoForExtensions(thread))) { output += L"\r\n"; emit SigThreadOutput(TextThreadString(thread), QString::fromStdWString(output)); @@ -152,18 +140,6 @@ DWORD MainWindow::GetSelectedProcessId() return processCombo->currentText().split(":")[0].toULong(nullptr, 16); } -void MainWindow::ReloadExtensions() -{ - extenCombo->clear(); - QFile extenSaveFile("Extensions.txt"); - extenSaveFile.open(QIODevice::WriteOnly | QIODevice::Truncate); - for (auto extenName : Extension::GetNames()) - { - extenSaveFile.write((extenName + ">").toUtf8()); - extenCombo->addItem(extenName); - } -} - std::unordered_map MainWindow::GetInfoForExtensions(TextThread* thread) { return @@ -259,25 +235,5 @@ void MainWindow::on_ttCombo_activated(int index) void MainWindow::on_addExtenButton_clicked() { - QString extenFileName = QFileDialog::getOpenFileName(this, "Select Extension", "C:\\", "Extensions (*.dll)"); - if (!extenFileName.size()) return; - QString extenName = extenFileName.mid(extenFileName.lastIndexOf("/") + 1); - QFile::copy(extenFileName, extenName); - Extension::Load(extenName.left(extenName.lastIndexOf(".dll"))); - ReloadExtensions(); -} - -void MainWindow::on_moveExtenButton_clicked() -{ - if (extenCombo->currentText() == "") return; - Extension::SendToBack(extenCombo->currentText()); - ReloadExtensions(); - Host::AddConsoleOutput(L"extension sent to back"); -} - -void MainWindow::on_rmvExtenButton_clicked() -{ - if (extenCombo->currentText() == "") return; - Extension::Unload(extenCombo->currentText()); - ReloadExtensions(); + extenDialog->show(); } diff --git a/GUI/mainwindow.h b/GUI/mainwindow.h index 91a3840..c312a38 100644 --- a/GUI/mainwindow.h +++ b/GUI/mainwindow.h @@ -43,15 +43,12 @@ private slots: void on_hookButton_clicked(); void on_saveButton_clicked(); void on_addExtenButton_clicked(); - void on_moveExtenButton_clicked(); - void on_rmvExtenButton_clicked(); private: bool ProcessThreadOutput(TextThread* thread, std::wstring& output); QString TextThreadString(TextThread* thread); ThreadParam ParseTextThreadString(QString textThreadString); DWORD GetSelectedProcessId(); - void ReloadExtensions(); std::unordered_map GetInfoForExtensions(TextThread* thread); QVector GetAllHooks(DWORD processId); @@ -61,6 +58,7 @@ private: QComboBox* ttCombo; QComboBox* extenCombo; QPlainTextEdit* textOutput; + QWidget* extenDialog; }; #endif // MAINWINDOW_H diff --git a/GUI/tests.cpp b/GUI/tests.cpp index a831b8a..35ae875 100644 --- a/GUI/tests.cpp +++ b/GUI/tests.cpp @@ -1,4 +1,4 @@ -#include "extensions.h" +#include "extendialog.h" #include "misc.h" static int TESTS = []