Create a new attach dialog window

New dialog window that shows processes with icons in QListView instead of ComboBox.
This commit is contained in:
tera8m4 2021-05-02 07:14:18 -07:00 committed by Akash Mozumdar
parent dd4b8cfbb5
commit a1d3abb080
5 changed files with 245 additions and 9 deletions

View File

@ -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

View File

@ -0,0 +1,92 @@
#include "attachtoprocessdialog.h"
#include "ui_attachtoprocessdialog.h"
#include "utils/windowshelpers.h"
#include <QStandardItemModel>
#include <algorithm>
#include <limits>
namespace
{
QString GetNameProcessFromIndex(const QModelIndex &index, const QVector<QPair<QString, HICON>>& 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<QPair<QString, HICON>>&& 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();
}

View File

@ -0,0 +1,51 @@
#ifndef ATTACHTOPROCESSDIALOG_H
#define ATTACHTOPROCESSDIALOG_H
#include <QDialog>
#include <QString>
#include <QPair>
#include <QStyledItemDelegate>
#include <QVector>
#include <QtWinExtras/QtWin>
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<QPair<QString, HICON>>&& 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<QPair<QString, HICON>> data;
};
#endif // ATTACHTOPROCESSDIALOG_H

View File

@ -0,0 +1,52 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AttachToProcessDialog</class>
<widget class="QWidget" name="AttachToProcessDialog">
<property name="windowModality">
<enum>Qt::WindowModal</enum>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>813</width>
<height>426</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>TextLabel</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEdit">
<property name="placeholderText">
<string>PID</string>
</property>
</widget>
</item>
<item>
<widget class="QListView" name="listView"/>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -5,6 +5,9 @@
#include "extenwindow.h"
#include "host/host.h"
#include "host/hookcode.h"
#include "attachtoprocessdialog.h"
#include "utils/windowshelpers.h"
#include <shellapi.h>
#include <process.h>
#include <QRegularExpression>
@ -14,6 +17,7 @@
#include <QDialogButtonBox>
#include <QFileDialog>
#include <QFontDialog>
#include <QHash>
extern const char* ATTACH;
extern const char* LAUNCH;
@ -79,6 +83,7 @@ namespace
Ui::MainWindow ui;
std::atomic<DWORD> selectedProcessId = 0;
ExtenWindow* extenWindow = nullptr;
AttachToProcessDialog* attachDialog = nullptr;
std::unordered_set<DWORD> alreadyAttached;
bool autoAttach = false, autoAttachSavedOnly = true;
bool showSystemProcesses = false;
@ -152,17 +157,51 @@ namespace
}
void AttachProcess()
{
QMultiHash<QString, DWORD> allProcesses;
for (auto [processId, processName] : GetAllProcesses())
{
auto processes = GetAllProcesses();
QMultiHash<QString, DWORD> processesMap;
QVector<QPair<QString, HICON>> 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<const char*, void(&)()>{
{ ATTACH, AttachProcess },
{ LAUNCH, LaunchProcess },