Итак, я пытаюсь создать dll на С ++, который будет открывать форму при ее внедрении в процесс.
Это код, который у меня есть (отдельный файл из файлов, созданных для формы):
#include "Main.h"
#include <Windows.h>
using namespace::System;
using namespace::System::Windows::Forms;
auto FormRender(void) -> void {
Hyperscanner::Main lpMain;
lpMain.ShowDialog();
return;
}
HANDLE g_Thread = nullptr;
auto __stdcall DllMain(HMODULE hMod, DWORD dwReason, void* lpReserved) -> int {
if (dwReason) {
g_Thread = CreateThread(nullptr, 0, reinterpret_cast<LPTHREAD_START_ROUTINE>
(FormRender), nullptr, 0, nullptr);
}
if (!dwReason) {
TerminateThread(g_Thread, 0);
CloseHandle(g_Thread);
FreeLibraryAndExitThread(hMod, 0);
}
return true;
}
Проблема в том, что по какой-то причине он продолжает создавать формы, когда я вставляю их в процесс, как будто в потоке был цикл, но, как вы можете видеть, его нет. И когда я пытаюсь вызвать его как обычно, без потока, он вообще не отображается, что не имеет смысла, потому что технически это то же самое, что и внутри потока.
Мне интересно, что я сделал не так, и мне нужна помощь. Спасибо!
РЕШЕНИЕ (от @hacksalot):
Проблема заключалась в том, что было много запускаемых потоков, которые проходили через мой обратный вызов DllMain, поэтому он запускал кучу потоков (по какой-то причине не думал о проверке, сколько потоков было создано).
Чтобы исправить это, я добавил глобальную переменную, чтобы убедиться, что она выполняется только один раз.
#include "Main.h"
#include <Windows.h>
using namespace::System;
using namespace::System::Windows::Forms;
volatile int g_StartOnce = 0;
auto FormRender(void) -> void {
Hyperscanner::Main lpMain;
lpMain.ShowDialog();
return;
}
auto StartRenderThread(HANDLE& ThreadHandle) -> bool {
ThreadHandle = CreateThread(nullptr, 0, reinterpret_cast<LPTHREAD_START_ROUTINE>
(FormRender), nullptr, 0, nullptr);
if (ThreadHandle)
{
return true;
}
return false;
}
auto StopRenderThread(HANDLE& ThreadHandle) -> bool {
if (ThreadHandle) {
if (TerminateThread(ThreadHandle, 0)) {
CloseHandle(ThreadHandle);
return true;
}
}
return false;
}
HANDLE g_Thread = nullptr;
auto __stdcall DllMain(HMODULE hMod, DWORD dwReason, void* lpReserved) -> int {
if (dwReason && !g_StartOnce) {
StartRenderThread(g_Thread);
++g_StartOnce;
}
if (!dwReason) {
StopRenderThread(g_Thread);
FreeLibraryAndExitThread(hMod, 0);
}
return true;
}





От документация:
You should never perform the following tasks from within
DllMain:~ Call
CreateThread.
Также FormRender не соответствует сигнатуре обратного вызова ThreadProc, и его вызов вызывает повреждение стека. Я даже не буду упоминать про CLR ...
Вы можете рекурсивно создавать потоки там, поскольку DllMain вызывается для всех загруженных DLL для каждого созданного потока, если память обслуживает, с DLL_THREAD_ATTACH для dwReason.
@hacksalot помог мне решить мою проблему, но я не могу принять его ответ, так как он только оставил комментарий, обновит OP с разрешением
Ничего страшного, все получается в стирке, и я давно не смотрел на это, поэтому не решался дать полный ответ. Рад, что ты решил эту проблему!
Все, что сказал @VTT (есть много вещей, которые вы не должны делать из DllMain), плюс имейте в виду, что
if (dwReason)будет проверять истину каждый раз, когда создается поток, а не только когда DLL впервые присоединяется к процессу. Возможно, поэтому вы видите "зацикливание". Обычно мы видим более явный переключатель if /, чтобы различать присоединение процесса и потока.