refactor and perf improvements

This commit is contained in:
Akash Mozumdar 2019-06-21 01:29:48 -04:00
parent 6bac544c89
commit f1d46e9f73
9 changed files with 254 additions and 298 deletions

View File

@ -70,6 +70,14 @@ bool DispatchSentenceToExtensions(std::wstring& sentence, const InfoForExtension
return !sentence.empty();
}
void CleanupExtensions()
{
std::scoped_lock writeLock(extenMutex);
for (auto extension : extensions)
FreeLibrary(GetModuleHandleW(extension.name.c_str()));
extensions.clear();
}
ExtenWindow::ExtenWindow(QWidget* parent) :
QMainWindow(parent, Qt::WindowCloseButtonHint),
ui(new Ui::ExtenWindow)

View File

@ -14,6 +14,7 @@ struct InfoForExtension
};
bool DispatchSentenceToExtensions(std::wstring& sentence, const InfoForExtension* miscInfo);
void CleanupExtensions(); // must call this before exiting the program, only way to uphold guarantee that DllMain and OnNewSentence won't be called concurrently
class ExtenWindow : public QMainWindow
{

View File

@ -134,6 +134,7 @@ MainWindow::MainWindow(QWidget *parent) :
MainWindow::~MainWindow()
{
QSettings(CONFIG_FILE, QSettings::IniFormat).setValue(WINDOW, geometry());
CleanupExtensions();
SetErrorMode(SEM_NOGPFAULTERRORBOX);
ExitProcess(0);
}
@ -177,7 +178,7 @@ void MainWindow::ThreadAdded(TextThread& thread)
{
std::wstring threadCode = Util::GenerateCode(thread.hp, thread.tp.processId);
QString ttString = TextThreadString(thread) + S(thread.name) + " (" + S(threadCode) + ")";
bool savedMatch = savedThreadCtx.first == thread.tp.ctx && savedThreadCtx.second == thread.tp.ctx2 && savedThreadCode == threadCode;
bool savedMatch = savedThreadCtx == std::pair(thread.tp.ctx, thread.tp.ctx2) && savedThreadCode == threadCode;
if (savedMatch) savedThreadCtx.first = savedThreadCtx.second = savedThreadCode[0] = 0;
QMetaObject::invokeMethod(this, [this, ttString, savedMatch]
{
@ -236,9 +237,9 @@ std::array<InfoForExtension, 10> MainWindow::GetMiscInfo(TextThread& thread)
{
void(*AddSentence)(MainWindow*, int64_t, const wchar_t*) = [](MainWindow* This, int64_t number, const wchar_t* sentence)
{
std::wstring sentenceStr = sentence;
std::wstring copy = sentence;
// pointer from Host::GetThread may not stay valid unless on main thread
QMetaObject::invokeMethod(This, [=]() mutable { if (TextThread* thread = Host::GetThread(number)) thread->AddSentence(std::move(sentenceStr)); });
QMetaObject::invokeMethod(This, [=]() mutable { if (TextThread* thread = Host::GetThread(number)) thread->AddSentence(std::move(copy)); });
};
return
@ -394,7 +395,7 @@ void MainWindow::FindHooks()
connect(&confirm, &QDialogButtonBox::accepted, &dialog, &QDialog::accept);
connect(&confirm, &QDialogButtonBox::helpRequested, &dialog, &QDialog::accept);
dialog.setWindowTitle(SEARCH_FOR_HOOKS);
if (dialog.exec() == QDialog::Rejected) return;
if (!dialog.exec()) return;
if (customSettings)
{
@ -432,7 +433,7 @@ void MainWindow::FindHooks()
QPushButton startButton(START_HOOK_SEARCH, &dialog);
layout.addWidget(&startButton);
connect(&startButton, &QPushButton::clicked, &dialog, &QDialog::accept);
if (dialog.exec() == QDialog::Rejected) return;
if (!dialog.exec()) return;
QByteArray pattern = QByteArray::fromHex(patternInput.text().replace("??", QString::number(XX, 16)).toUtf8());
memcpy(sp.pattern, pattern.data(), sp.length = min(pattern.size(), 25));
try { filter = std::wregex(S(filterInput.text())); } catch (std::regex_error) {};

View File

@ -1,12 +1,10 @@
#include "extension.h"
#include "ui_extrawindow.h"
#include "defs.h"
#include <QDialog>
#include <QInputDialog>
#include <QColorDialog>
#include <QMessageBox>
#include <QMenu>
#include <QLayout>
#include <QLabel>
#include <QFormLayout>
#include <QLineEdit>
#include <QSpinBox>
@ -14,7 +12,6 @@
#include <QPainter>
#include <QMouseEvent>
#include <QSettings>
#include <QTimer>
extern const char* EXTRA_WINDOW_INFO;
extern const char* TOPMOST;
@ -29,117 +26,117 @@ extern const char* FONT_FAMILY;
extern const char* FONT_WEIGHT;
extern const char* SAVE_SETTINGS;
std::mutex m;
struct : QDialog
struct Window : QDialog
{
public:
void launch()
Window()
{
settings->beginGroup("Extra Window");
(new QHBoxLayout(this))->addWidget(display = new QLabel(EXTRA_WINDOW_INFO, this));
display->setTextFormat(Qt::PlainText);
display->setTextInteractionFlags(Qt::TextSelectableByMouse);
display->setAlignment(Qt::AlignTop);
display->setWordWrap(true);
display->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
ui.setupUi(this);
settings.beginGroup("Extra Window");
setWindowFlags(Qt::FramelessWindowHint);
setAttribute(Qt::WA_TranslucentBackground);
setSizeGripEnabled(true);
resize(400, 300);
show();
QMetaObject::invokeMethod(this, [this]
{
show();
auto setBackgroundColor = [=](QColor color)
{
if (!color.isValid()) return;
if (color.alpha() == 0) color.setAlpha(1);
bgColor = color;
repaint();
settings->setValue(BG_COLOR, color);
};
auto setTextColor = [=](QColor color)
{
if (!color.isValid()) return;
auto newPalette = display->palette();
newPalette.setColor(QPalette::WindowText, color);
display->setPalette(newPalette);
settings->setValue(TEXT_COLOR, color);
};
auto requestFont = [=]
{
QFont font = display->font();
auto fontDialog = new QDialog(this, Qt::WindowCloseButtonHint);
fontDialog->setAttribute(Qt::WA_DeleteOnClose);
fontDialog->setWindowTitle(FONT);
auto layout = new QFormLayout(fontDialog);
fontDialog->setLayout(layout);
auto fontFamily = new QLineEdit(font.family(), fontDialog);
layout->addRow(FONT_FAMILY, fontFamily);
auto fontSize = new QSpinBox(fontDialog);
fontSize->setValue(font.pointSize());
layout->addRow(FONT_SIZE, fontSize);
auto fontWeight = new QSpinBox(fontDialog);
fontWeight->setValue(font.weight());
layout->addRow(FONT_WEIGHT, fontWeight);
auto save = new QPushButton(SAVE_SETTINGS, fontDialog);
layout->addWidget(save);
connect(save, &QPushButton::clicked, fontDialog, &QDialog::accept);
fontDialog->open();
connect(fontDialog, &QDialog::accepted, [=]
QFont font = ui.display->font();
if (font.fromString(settings.value(FONT, font.toString()).toString())) ui.display->setFont(font);
setBackgroundColor(settings.value(BG_COLOR, palette().window().color()).value<QColor>());
setTextColor(settings.value(TEXT_COLOR, ui.display->palette().windowText().color()).value<QColor>());
setLock(settings.value(SIZE_LOCK, false).toBool());
setTopmost(settings.value(TOPMOST, false).toBool());
setGeometry(settings.value(WINDOW, geometry()).toRect());
menu.addAction(FONT, this, &Window::RequestFont);
menu.addAction(BG_COLOR, [this] { setBackgroundColor(QColorDialog::getColor(bgColor, this, BG_COLOR, QColorDialog::ShowAlphaChannel)); });
menu.addAction(TEXT_COLOR, [this] { setTextColor(QColorDialog::getColor(ui.display->palette().windowText().color(), this, TEXT_COLOR, QColorDialog::ShowAlphaChannel)); });
for (auto [name, default, slot] : Array<std::tuple<const char*, bool, void(Window::*)(bool)>>{
{ TOPMOST, false, &Window::setTopmost },
{ SIZE_LOCK, false, &Window::setLock },
{ SHOW_ORIGINAL, true, &Window::setShowOriginal }
})
{
QFont font(fontFamily->text(), fontSize->value(), fontWeight->value());
settings->setValue(FONT, font.toString());
display->setFont(font);
});
};
auto setTopmost = [=](bool topmost)
{
SetWindowPos((HWND)winId(), topmost ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
settings->setValue(TOPMOST, topmost);
};
auto setLock = [=](bool lock)
{
locked = lock;
setSizeGripEnabled(!lock);
settings->setValue(SIZE_LOCK, lock);
};
auto setShowOriginal = [=](bool showOriginal)
{
if (!showOriginal) QMessageBox::information(this, SHOW_ORIGINAL, SHOW_ORIGINAL_INFO);
settings->setValue(SHOW_ORIGINAL, showOriginal);
};
setGeometry(settings->value(WINDOW, geometry()).toRect());
setLock(settings->value(SIZE_LOCK, false).toBool());
setTopmost(settings->value(TOPMOST, false).toBool());
QFont font = display->font();
font.setPointSize(16);
font.fromString(settings->value(FONT, font.toString()).toString());
display->setFont(font);
setBackgroundColor(settings->value(BG_COLOR, palette().window().color()).value<QColor>());
setTextColor(settings->value(TEXT_COLOR, display->palette().windowText().color()).value<QColor>());
auto action = menu.addAction(name, this, slot);
action->setCheckable(true);
action->setChecked(settings.value(name, default).toBool());
}
connect(ui.display, &QLabel::customContextMenuRequested, [this](QPoint point) { menu.exec(mapToGlobal(point)); });
auto menu = new QMenu(display);
auto topmost = menu->addAction(TOPMOST, setTopmost);
topmost->setCheckable(true);
topmost->setChecked(settings->value(TOPMOST, false).toBool());
auto lock = menu->addAction(SIZE_LOCK, setLock);
lock->setCheckable(true);
lock->setChecked(settings->value(SIZE_LOCK, false).toBool());
auto showOriginal = menu->addAction(SHOW_ORIGINAL, setShowOriginal);
showOriginal->setCheckable(true);
showOriginal->setChecked(settings->value(SHOW_ORIGINAL, true).toBool());
menu->addAction(BG_COLOR, [=] { setBackgroundColor(QColorDialog::getColor(bgColor, this, BG_COLOR, QColorDialog::ShowAlphaChannel)); });
menu->addAction(TEXT_COLOR, [=] { setTextColor(QColorDialog::getColor(display->palette().windowText().color(), this, TEXT_COLOR, QColorDialog::ShowAlphaChannel)); });
menu->addAction(FONT, requestFont);
display->setContextMenuPolicy(Qt::CustomContextMenu);
connect(display, &QLabel::customContextMenuRequested, [=](QPoint point) { menu->exec(mapToGlobal(point)); });
connect(this, &QDialog::destroyed, [=] { settings->setValue(WINDOW, geometry()); });
QMetaObject::invokeMethod(this, [this] { ui.display->setText(EXTRA_WINDOW_INFO); }, Qt::QueuedConnection);
}, Qt::QueuedConnection);
}
QSettings* settings = new QSettings(CONFIG_FILE, QSettings::IniFormat, this);
QLabel* display;
~Window()
{
settings.setValue(WINDOW, geometry());
settings.sync();
}
Ui::ExtraWindow ui;
QSettings settings{ CONFIG_FILE, QSettings::IniFormat, this };
private:
void RequestFont()
{
QFont font = ui.display->font();
QDialog fontDialog(this, Qt::WindowCloseButtonHint);
fontDialog.setWindowTitle(FONT);
QFormLayout layout(&fontDialog);
QLineEdit fontFamily(font.family(), &fontDialog);
layout.addRow(FONT_FAMILY, &fontFamily);
QSpinBox fontSize(&fontDialog);
fontSize.setValue(font.pointSize());
layout.addRow(FONT_SIZE, &fontSize);
QSpinBox fontWeight(&fontDialog);
fontWeight.setValue(font.weight());
layout.addRow(FONT_WEIGHT, &fontWeight);
QPushButton save(SAVE_SETTINGS, &fontDialog);
layout.addWidget(&save);
connect(&save, &QPushButton::clicked, &fontDialog, &QDialog::accept);
if (!fontDialog.exec()) return;
font = QFont(fontFamily.text(), fontSize.value(), fontWeight.value());
settings.setValue(FONT, font.toString());
ui.display->setFont(font);
};
void setBackgroundColor(QColor color)
{
if (!color.isValid()) return;
if (color.alpha() == 0) color.setAlpha(1);
bgColor = color;
repaint();
settings.setValue(BG_COLOR, color);
};
void setTextColor(QColor color)
{
if (!color.isValid()) return;
auto newPalette = ui.display->palette();
newPalette.setColor(QPalette::WindowText, color);
ui.display->setPalette(newPalette);
settings.setValue(TEXT_COLOR, color);
};
void setTopmost(bool topmost)
{
SetWindowPos((HWND)winId(), topmost ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
settings.setValue(TOPMOST, topmost);
};
void setLock(bool lock)
{
locked = lock;
setSizeGripEnabled(!lock);
settings.setValue(SIZE_LOCK, lock);
};
void setShowOriginal(bool showOriginal)
{
if (!showOriginal) QMessageBox::information(this, SHOW_ORIGINAL, SHOW_ORIGINAL_INFO);
settings.setValue(SHOW_ORIGINAL, showOriginal);
};
void paintEvent(QPaintEvent*) override
{
QPainter(this).fillRect(rect(), bgColor);
@ -157,51 +154,19 @@ private:
oldPos = event->globalPos();
}
bool locked;
QMenu menu{ ui.display };
bool locked = true;
QColor bgColor;
QPoint oldPos;
}*window = nullptr;
BOOL WINAPI DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
{
QTimer::singleShot(0, []
{
std::lock_guard l(m);
(window = new std::remove_pointer_t<decltype(window)>)->launch();
});
}
break;
case DLL_PROCESS_DETACH:
{
std::lock_guard l(m);
if (window)
{
window->settings->setValue(WINDOW, window->geometry());
window->settings->sync();
}
if (lpReserved == NULL) // https://blogs.msdn.microsoft.com/oldnewthing/20120105-00/?p=8683
{
delete window;
window = nullptr;
}
}
break;
}
return TRUE;
}
} window;
bool ProcessSentence(std::wstring& sentence, SentenceInfo sentenceInfo)
{
std::lock_guard l(m);
if (window == nullptr || !sentenceInfo["current select"]) return false;
if (!sentenceInfo["current select"]) return false;
QString qSentence = QString::fromStdWString(sentence);
if (!window->settings->value(SHOW_ORIGINAL).toBool()) qSentence = qSentence.section('\n', qSentence.count('\n') / 2 + 1);
if (!window.settings.value(SHOW_ORIGINAL).toBool()) qSentence = qSentence.section('\n', qSentence.count('\n') / 2 + 1);
QMetaObject::invokeMethod(window, [=] { window->display->setText(qSentence); });
QMetaObject::invokeMethod(&window, [=] { window.ui.display->setText(qSentence); });
return false;
}

48
extensions/extrawindow.ui Normal file
View File

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ExtraWindow</class>
<widget class="QDialog" name="ExtraWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="sizeGripEnabled">
<bool>true</bool>
</property>
<layout class="QHBoxLayout">
<item>
<widget class="QLabel" name="display">
<property name="sizePolicy">
<sizepolicy hsizetype="Ignored" vsizetype="Ignored">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>16</pointsize>
</font>
</property>
<property name="contextMenuPolicy">
<enum>Qt::CustomContextMenu</enum>
</property>
<property name="alignment">
<set>Qt::AlignTop</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -5,7 +5,6 @@
#include <QLayout>
#include <QPlainTextEdit>
#include <QPushButton>
#include <QTimer>
extern const char* LUA_INTRO;
extern const char* LOAD_LUA_SCRIPT;
@ -45,61 +44,47 @@ bool logErrors = true;
Synchronized<std::string> script;
std::atomic<int> revCount = 0;
struct : QMainWindow
class Window : public QMainWindow
{
void launch()
public:
Window()
{
auto centralWidget = new QWidget(this);
auto layout = new QHBoxLayout(centralWidget);
auto scriptEditor = new QPlainTextEdit(std::string(std::istreambuf_iterator<char>(std::ifstream(LUA_SAVE_FILE, std::ios::in)), {}).c_str(), centralWidget);
auto loadButton = new QPushButton(LOAD_LUA_SCRIPT, centralWidget);
if (scriptEditor->toPlainText().isEmpty()) scriptEditor->setPlainText(LUA_INTRO);
layout->addWidget(scriptEditor);
layout->addWidget(loadButton);
save = [=]
{
auto script = scriptEditor->toPlainText().toUtf8();
std::ofstream(LUA_SAVE_FILE, std::ios::out | std::ios::trunc).write(script, strlen(script));
};
connect(loadButton, &QPushButton::clicked, [=](bool)
{
revCount += 1;
script->assign(scriptEditor->toPlainText().toUtf8());
save();
});
connect(&loadButton, &QPushButton::clicked, this, &Window::LoadScript);
if (scriptEditor.toPlainText().isEmpty()) scriptEditor.setPlainText(LUA_INTRO);
layout.addWidget(&scriptEditor);
layout.addWidget(&loadButton);
resize(800, 600);
setCentralWidget(centralWidget);
setCentralWidget(&centralWidget);
setWindowTitle("Lua");
show();
QMetaObject::invokeMethod(this, &QWidget::show, Qt::QueuedConnection);
}
std::function<void()> save;
}*window = nullptr;
~Window()
{
Save();
}
BOOL WINAPI DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
private:
void LoadScript()
{
case DLL_PROCESS_ATTACH:
revCount += 1;
script->assign(scriptEditor.toPlainText().toUtf8());
Save();
}
void Save()
{
QTimer::singleShot(0, []
{
(window = new std::remove_pointer_t<decltype(window)>)->launch();
});
auto script = scriptEditor.toPlainText().toUtf8();
std::ofstream(LUA_SAVE_FILE, std::ios::out | std::ios::trunc).write(script, script.size());
}
break;
case DLL_PROCESS_DETACH:
{
if (window) window->save();
if (lpReserved == NULL) // https://blogs.msdn.microsoft.com/oldnewthing/20120105-00/?p=8683
{
delete window;
}
}
break;
}
return TRUE;
}
QWidget centralWidget{ this };
QHBoxLayout layout{ &centralWidget };
QPlainTextEdit scriptEditor{ std::string(std::istreambuf_iterator<char>(std::ifstream(LUA_SAVE_FILE, std::ios::in)), {}).c_str(), &centralWidget };
QPushButton loadButton{ LOAD_LUA_SCRIPT, &centralWidget };
} window;
bool ProcessSentence(std::wstring& sentence, SentenceInfo sentenceInfo)
{

View File

@ -1,6 +1,5 @@
#include "extension.h"
#include "ui_regexfilter.h"
#include <QTimer>
extern const char* REGEX_FILTER;
extern const char* INVALID_REGEX;
@ -9,56 +8,35 @@ extern const char* CURRENT_FILTER;
std::wregex regex;
std::shared_mutex m;
struct : QMainWindow
class Window : public QMainWindow
{
void launch()
public:
Window()
{
ui.setupUi(this);
connect(ui.input, &QLineEdit::textEdited, [=](QString newRegex)
{
std::lock_guard l(m);
try { regex = newRegex.toStdWString(); }
catch (std::regex_error) { return ui.output->setText(INVALID_REGEX); }
ui.output->setText(QString(CURRENT_FILTER).arg(newRegex));
});
connect(ui.input, &QLineEdit::textEdited, this, &Window::setRegex);
setWindowTitle(REGEX_FILTER);
show();
QMetaObject::invokeMethod(this, &QWidget::show, Qt::QueuedConnection);
}
private:
void setRegex(QString newRegex)
{
std::lock_guard l(m);
try { regex = newRegex.toStdWString(); }
catch (std::regex_error) { return ui.output->setText(INVALID_REGEX); }
ui.output->setText(QString(CURRENT_FILTER).arg(newRegex));
}
Ui::FilterWindow ui;
}*window = nullptr;
BOOL WINAPI DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
{
QTimer::singleShot(0, []
{
std::lock_guard l(m);
(window = new std::remove_pointer_t<decltype(window)>)->launch();
});
}
break;
case DLL_PROCESS_DETACH:
{
if (lpReserved == NULL) // https://blogs.msdn.microsoft.com/oldnewthing/20120105-00/?p=8683
{
std::lock_guard l(m);
delete window;
window = nullptr;
}
}
break;
}
return TRUE;
}
} window;
bool ProcessSentence(std::wstring& sentence, SentenceInfo sentenceInfo)
{
std::shared_lock l(m);
if (sentenceInfo["text number"] == 0) return false;
std::shared_lock l(m);
sentence = std::regex_replace(sentence, regex, L"");
return true;
}

View File

@ -93,12 +93,12 @@ bool Replace(std::wstring& sentence)
BOOL WINAPI DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
static HANDLE replacementFile; // not actually used to read/write, just to ensure it exists
// not actually used to read/write, just to ensure it exists
static AutoHandle<> replacementFile = CreateFileA(REPLACE_SAVE_FILE, FILE_GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
{
replacementFile = CreateFileA(REPLACE_SAVE_FILE, FILE_GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
std::vector<BYTE> file(std::istreambuf_iterator<char>(std::ifstream(REPLACE_SAVE_FILE, std::ios::in | std::ios::binary)), {});
if (Parse(std::wstring((wchar_t*)file.data(), file.size() / sizeof(wchar_t))) == 0)
{
@ -110,7 +110,6 @@ BOOL WINAPI DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved
break;
case DLL_PROCESS_DETACH:
{
CloseHandle(replacementFile);
}
break;
}

View File

@ -5,7 +5,6 @@
#include <QListWidget>
#include <QInputDialog>
#include <QKeyEvent>
#include <QTimer>
extern const char* THREAD_LINKER;
extern const char* LINK;
@ -13,86 +12,58 @@ extern const char* THREAD_LINK_FROM;
extern const char* THREAD_LINK_TO;
extern const char* HEXADECIMAL;
std::mutex m;
std::unordered_map<int64_t, std::unordered_multiset<int64_t>> linkedTextHandles;
std::shared_mutex m;
struct : QMainWindow
class Window : public QMainWindow
{
void launch()
public:
Window()
{
auto centralWidget = new QWidget(this);
auto layout = new QHBoxLayout(centralWidget);
auto linkList = new QListWidget(centralWidget);
auto addLink = new QPushButton(LINK, centralWidget);
layout->addWidget(linkList);
layout->addWidget(addLink);
connect(&linkButton, &QPushButton::clicked, this, &Window::Link);
connect(addLink, &QPushButton::clicked, [=]
{
bool ok1, ok2, ok3, ok4;
int from = QInputDialog::getText(this, THREAD_LINK_FROM, HEXADECIMAL, QLineEdit::Normal, "", &ok1, Qt::WindowCloseButtonHint).toInt(&ok2, 16);
int to = QInputDialog::getText(this, THREAD_LINK_TO, HEXADECIMAL, QLineEdit::Normal, "", &ok3, Qt::WindowCloseButtonHint).toInt(&ok4, 16);
if (ok1 && ok2 && ok3 && ok4)
{
std::lock_guard l(m);
linkedTextHandles[from].insert(to);
linkList->addItem(QString::number(from, 16) + "->" + QString::number(to, 16));
}
});
Unlink = [=]
{
if (linkList->currentItem())
{
QStringList link = linkList->currentItem()->text().split("->");
linkList->takeItem(linkList->currentRow());
std::lock_guard l(m);
linkedTextHandles[link[0].toInt(nullptr, 16)].erase(link[1].toInt(nullptr, 16));
}
};
layout.addWidget(&linkList);
layout.addWidget(&linkButton);
setCentralWidget(centralWidget);
setCentralWidget(&centralWidget);
setWindowTitle(THREAD_LINKER);
show();
QMetaObject::invokeMethod(this, &QWidget::show, Qt::QueuedConnection);
}
private:
void Link()
{
bool ok1, ok2, ok3, ok4;
int from = QInputDialog::getText(this, THREAD_LINK_FROM, HEXADECIMAL, QLineEdit::Normal, "", &ok1, Qt::WindowCloseButtonHint).toInt(&ok2, 16);
int to = QInputDialog::getText(this, THREAD_LINK_TO, HEXADECIMAL, QLineEdit::Normal, "", &ok3, Qt::WindowCloseButtonHint).toInt(&ok4, 16);
if (ok1 && ok2 && ok3 && ok4)
{
std::lock_guard l(m);
linkedTextHandles[from].insert(to);
linkList.addItem(QString::number(from, 16) + "->" + QString::number(to, 16));
}
}
void keyPressEvent(QKeyEvent* event) override
{
if (event->key() == Qt::Key_Delete) Unlink();
}
std::function<void()> Unlink;
}*window = nullptr;
BOOL WINAPI DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
{
QTimer::singleShot(0, []
if (event->key() == Qt::Key_Delete && linkList.currentItem())
{
QStringList link = linkList.currentItem()->text().split("->");
linkList.takeItem(linkList.currentRow());
std::lock_guard l(m);
(window = new std::remove_pointer_t<decltype(window)>)->launch();
});
}
break;
case DLL_PROCESS_DETACH:
{
if (lpReserved == NULL) // https://blogs.msdn.microsoft.com/oldnewthing/20120105-00/?p=8683
{
std::lock_guard l(m);
delete window;
window = nullptr;
linkedTextHandles[link[0].toInt(nullptr, 16)].erase(link[1].toInt(nullptr, 16));
}
}
break;
}
return TRUE;
}
QWidget centralWidget{ this };
QHBoxLayout layout{ &centralWidget };
QListWidget linkList{ &centralWidget };
QPushButton linkButton{ LINK, &centralWidget };
} window;
bool ProcessSentence(std::wstring& sentence, SentenceInfo sentenceInfo)
{
std::lock_guard l(m);
std::shared_lock l(m);
int64_t textHandle = sentenceInfo["text number"];
for (auto linkedHandle : linkedTextHandles[textHandle])