diff --git a/GUI/extenwindow.cpp b/GUI/extenwindow.cpp index dfd343b..7d25cf1 100644 --- a/GUI/extenwindow.cpp +++ b/GUI/extenwindow.cpp @@ -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) diff --git a/GUI/extenwindow.h b/GUI/extenwindow.h index 3bd1c3c..4f54450 100644 --- a/GUI/extenwindow.h +++ b/GUI/extenwindow.h @@ -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 { diff --git a/GUI/mainwindow.cpp b/GUI/mainwindow.cpp index a63fdea..93904c0 100644 --- a/GUI/mainwindow.cpp +++ b/GUI/mainwindow.cpp @@ -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 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) {}; diff --git a/extensions/extrawindow.cpp b/extensions/extrawindow.cpp index 397fbd4..47a21b8 100644 --- a/extensions/extrawindow.cpp +++ b/extensions/extrawindow.cpp @@ -1,12 +1,10 @@ #include "extension.h" +#include "ui_extrawindow.h" #include "defs.h" -#include #include #include #include #include -#include -#include #include #include #include @@ -14,7 +12,6 @@ #include #include #include -#include 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()); + setTextColor(settings.value(TEXT_COLOR, ui.display->palette().windowText().color()).value()); + 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>{ + { 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()); - setTextColor(settings->value(TEXT_COLOR, display->palette().windowText().color()).value()); + 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)->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; } diff --git a/extensions/extrawindow.ui b/extensions/extrawindow.ui new file mode 100644 index 0000000..cc4181b --- /dev/null +++ b/extensions/extrawindow.ui @@ -0,0 +1,48 @@ + + + ExtraWindow + + + + 0 + 0 + 400 + 300 + + + + true + + + + + + + 0 + 0 + + + + + 16 + + + + Qt::CustomContextMenu + + + Qt::AlignTop + + + true + + + Qt::TextSelectableByMouse + + + + + + + + diff --git a/extensions/lua.cpp b/extensions/lua.cpp index 5c0eabc..4d1d4c7 100644 --- a/extensions/lua.cpp +++ b/extensions/lua.cpp @@ -5,7 +5,6 @@ #include #include #include -#include extern const char* LUA_INTRO; extern const char* LOAD_LUA_SCRIPT; @@ -45,61 +44,47 @@ bool logErrors = true; Synchronized script; std::atomic 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(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(¢ralWidget); setWindowTitle("Lua"); - show(); + QMetaObject::invokeMethod(this, &QWidget::show, Qt::QueuedConnection); } - std::function 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)->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{ ¢ralWidget }; + QPlainTextEdit scriptEditor{ std::string(std::istreambuf_iterator(std::ifstream(LUA_SAVE_FILE, std::ios::in)), {}).c_str(), ¢ralWidget }; + QPushButton loadButton{ LOAD_LUA_SCRIPT, ¢ralWidget }; +} window; bool ProcessSentence(std::wstring& sentence, SentenceInfo sentenceInfo) { diff --git a/extensions/regexfilter.cpp b/extensions/regexfilter.cpp index 4fb0825..a9a4f86 100644 --- a/extensions/regexfilter.cpp +++ b/extensions/regexfilter.cpp @@ -1,6 +1,5 @@ #include "extension.h" #include "ui_regexfilter.h" -#include 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)->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; } diff --git a/extensions/replacer.cpp b/extensions/replacer.cpp index 3c2308d..23dd93b 100644 --- a/extensions/replacer.cpp +++ b/extensions/replacer.cpp @@ -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 file(std::istreambuf_iterator(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; } diff --git a/extensions/threadlinker.cpp b/extensions/threadlinker.cpp index 68e0014..365bc36 100644 --- a/extensions/threadlinker.cpp +++ b/extensions/threadlinker.cpp @@ -5,7 +5,6 @@ #include #include #include -#include 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> 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(¢ralWidget); 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 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)->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{ ¢ralWidget }; + QListWidget linkList{ ¢ralWidget }; + QPushButton linkButton{ LINK, ¢ralWidget }; +} 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])