diff --git a/GUI/CMakeLists.txt b/GUI/CMakeLists.txt index 0b07df8..c8e17de 100644 --- a/GUI/CMakeLists.txt +++ b/GUI/CMakeLists.txt @@ -10,6 +10,7 @@ add_executable(Textractor WIN32 main.cpp mainwindow.cpp extenwindow.cpp + attachtoprocessdialog.cpp host/exception.cpp host/host.cpp host/textthread.cpp diff --git a/GUI/attachtoprocessdialog.cpp b/GUI/attachtoprocessdialog.cpp new file mode 100644 index 0000000..c85b9d4 --- /dev/null +++ b/GUI/attachtoprocessdialog.cpp @@ -0,0 +1,92 @@ +#include "attachtoprocessdialog.h" +#include "ui_attachtoprocessdialog.h" +#include "utils/windowshelpers.h" + +#include +#include +#include + +namespace +{ + QString GetNameProcessFromIndex(const QModelIndex &index, const QVector>& data) + { + const int row = index.row(); + return data[row].first; + } +} + +AttachToProcessDialog::AttachToProcessDialog(QWidget *parent) : + QDialog(parent, Qt::WindowCloseButtonHint), + ui(new Ui::AttachToProcessDialog), + model(new QStandardItemModel(this)) +{ + ui->setupUi(this); + + const QIntValidator* validator = new QIntValidator(0, INT_MAX, this); + ui->lineEdit->setValidator(validator); +} + +AttachToProcessDialog::~AttachToProcessDialog() +{ + delete ui; +} + +void AttachToProcessDialog::setLabelText(const QString& text) +{ + ui->label->setText(text); +} + +void AttachToProcessDialog::setData(QVector>&& newData) +{ + data = std::move(newData); + selectedProcess.clear(); + std::sort(data.begin(), data.end(), [](const auto& left, const auto& right) { + return left.first < right.first; + }); + model->clear(); + for (const auto& [process, hIcon] : data) + { + QIcon icon = WindowsHepers::CreateQIconFromHIcon(hIcon); + auto* item = new QStandardItem(icon, process); + item->setEditable(false); + model->appendRow(item); + } + ui->listView->setModel(model); +} + +QString AttachToProcessDialog::getSelectedData() +{ + return selectedProcess.isEmpty() ? ui->lineEdit->text() : selectedProcess; +} + +void AttachToProcessDialog::on_buttonBox_accepted() +{ + accept(); +} + +void AttachToProcessDialog::on_buttonBox_rejected() +{ + reject(); +} + +void AttachToProcessDialog::on_listView_doubleClicked(const QModelIndex& index) +{ + selectedProcess = GetNameProcessFromIndex(index, data); + accept(); +} + +void AttachToProcessDialog::on_lineEdit_returnPressed() +{ + selectedProcess = ui->lineEdit->text(); + accept(); +} + +void AttachToProcessDialog::on_listView_clicked(const QModelIndex &index) +{ + selectedProcess = GetNameProcessFromIndex(index, data); +} + +void AttachToProcessDialog::on_lineEdit_editingFinished() +{ + selectedProcess = ui->lineEdit->text(); +} diff --git a/GUI/attachtoprocessdialog.h b/GUI/attachtoprocessdialog.h new file mode 100644 index 0000000..3dde6e5 --- /dev/null +++ b/GUI/attachtoprocessdialog.h @@ -0,0 +1,51 @@ +#ifndef ATTACHTOPROCESSDIALOG_H +#define ATTACHTOPROCESSDIALOG_H + +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE +namespace Ui { +class AttachToProcessDialog; +} +QT_END_NAMESPACE + +class QStandardItemModel; +class QModelIndex; + +class AttachToProcessDialog : public QDialog +{ + Q_OBJECT + +public: + explicit AttachToProcessDialog(QWidget *parent = nullptr); + void setData(QVector>&& newData); + void setLabelText(const QString& text); + QString getSelectedData(); + ~AttachToProcessDialog(); + +private slots: + void on_buttonBox_accepted(); + + void on_buttonBox_rejected(); + + void on_listView_doubleClicked(const QModelIndex &index); + + void on_lineEdit_returnPressed(); + + void on_listView_clicked(const QModelIndex &index); + + void on_lineEdit_editingFinished(); + +private: + Ui::AttachToProcessDialog* ui; + QStandardItemModel* model; + QString selectedProcess; + QVector> data; +}; + +#endif // ATTACHTOPROCESSDIALOG_H \ No newline at end of file diff --git a/GUI/attachtoprocessdialog.ui b/GUI/attachtoprocessdialog.ui new file mode 100644 index 0000000..9f3c231 --- /dev/null +++ b/GUI/attachtoprocessdialog.ui @@ -0,0 +1,52 @@ + + + AttachToProcessDialog + + + Qt::WindowModal + + + + 0 + 0 + 813 + 426 + + + + Form + + + + + + + + TextLabel + + + + + + + PID + + + + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + + diff --git a/GUI/mainwindow.cpp b/GUI/mainwindow.cpp index e848db8..9880919 100644 --- a/GUI/mainwindow.cpp +++ b/GUI/mainwindow.cpp @@ -5,6 +5,9 @@ #include "extenwindow.h" #include "host/host.h" #include "host/hookcode.h" +#include "attachtoprocessdialog.h" +#include "utils/windowshelpers.h" + #include #include #include @@ -14,6 +17,7 @@ #include #include #include +#include extern const char* ATTACH; extern const char* LAUNCH; @@ -79,6 +83,7 @@ namespace Ui::MainWindow ui; std::atomic selectedProcessId = 0; ExtenWindow* extenWindow = nullptr; + AttachToProcessDialog* attachDialog = nullptr; std::unordered_set alreadyAttached; bool autoAttach = false, autoAttachSavedOnly = true; bool showSystemProcesses = false; @@ -152,17 +157,51 @@ namespace } void AttachProcess() - { - QMultiHash allProcesses; - for (auto [processId, processName] : GetAllProcesses()) + { + auto processes = GetAllProcesses(); + QMultiHash processesMap; + QVector> dialogData; + dialogData.reserve(processes.size()); + for (auto [processId, processName] : processes) + { if (processName && (showSystemProcesses || processName->find(L":\\Windows\\") == std::string::npos)) - allProcesses.insert(QFileInfo(S(processName.value())).fileName(), processId); + { + const auto& value = processName.value(); + const QFileInfo& fileInfo = QFileInfo(S(value)); + const QString& fileName = fileInfo.fileName(); + if (!processesMap.contains(fileName)) + { + const auto icon = WindowsHepers::GetIconHandlerFromExe(value.c_str()); + dialogData.push_back({fileName, icon}); + } + processesMap.insert(fileName, processId); + } + } + dialogData.shrink_to_fit(); + processes.clear(); - QStringList processList(allProcesses.uniqueKeys()); - processList.sort(Qt::CaseInsensitive); - if (QString process = QInputDialog::getItem(This, SELECT_PROCESS, ATTACH_INFO, processList, 0, true, &ok, Qt::WindowCloseButtonHint); ok) - if (process.toInt(nullptr, 0)) Host::InjectProcess(process.toInt(nullptr, 0)); - else for (auto processId : allProcesses.values(process)) Host::InjectProcess(processId); + attachDialog->setWindowTitle(SELECT_PROCESS); + attachDialog->setLabelText(ATTACH_INFO); + + attachDialog->setData(std::move(dialogData)); + const bool hasChosenData = attachDialog->exec() != 0; + + if (hasChosenData) + { + const QString& process = attachDialog->getSelectedData(); + const int pid = process.toInt(nullptr, 0); + if (pid) + { + Host::InjectProcess(pid); + } + else + { + for (const auto& processId : processesMap.values(process)) + { + Host::InjectProcess(processId); + } + } + } } void LaunchProcess() @@ -597,6 +636,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) This = this; ui.setupUi(this); extenWindow = new ExtenWindow(this); + attachDialog = new AttachToProcessDialog(this); for (auto [text, slot] : Array{ { ATTACH, AttachProcess }, { LAUNCH, LaunchProcess },