Код (C): HANDLE hShutdownEvent = nullptr; DWORD CALLBACK MainThread(LPVOID lpParameter) { while (WaitForSingleObject(hShutdownEvent, 0) != WAIT_OBJECT_0) { Sleep(10); } return ERROR_SUCCESS; } BOOL APIENTRY DllMain(HINSTANCE hInstance, DWORD reason, LPVOID lpReserved) { switch (reason) { case DLL_PROCESS_ATTACH: { hShutdownEvent = CreateEventW(nullptr, TRUE, FALSE, nullptr); const HANDLE hMainThread = CreateThread(nullptr, 0, &MainThread, nullptr, 0, nullptr); if (!hMainThread) return FALSE; } break; case DLL_PROCESS_DETACH: SetEvent(hShutdownEvent); } return TRUE; } При получении библиотекой события DLL_PROCESS_ATTACH вызывается SetEvent который переводит событие hShutdownEvent в сигнальное состояние, однако поток НЕ завершается и процесс падает. В чём дело? Как тогда вообще корректно завершить потоки?
Старая песня о главном. У DllMain куча ограничений, в ее обработчиках лучше вообще ничего кроме внутренней утилитарщины не делать. https://learn.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-best-practices
Я думал ограничения распространяются на ожидание, но никак не на SetEvent. Как тогда можно дать понять потоку что ему необходимо завершиться? Использовать bool переменную не хочется, так как будет сильная нагрузка на процессор. WaitForSingleObject внутри потока был идеальным вариантом. Даже если вызывать в DLL_PROCESS_DETACH Код (C): PostThreadMessageW(GetThreadId(hMainThread), WM_QUIT, 0, 0); И иметь два потока, один главный (с циклом сообщений) а другой с циклом WaitForSingleObject, то все равно происходит краш. Что за бред? Прикол в том что когда у меня один поток с циклом сообщений и я вызываю из DLL_PROCESS_DETACH Код (C): PostThreadMessageW(GetThreadId(hMainThread), WM_QUIT, 0, 0); То он нормально завершается. Но дело в том что мне нужно ДВА потока.
Общая идея в том, что если тебе надо создавать поток в обработчике события загрузки длл, то ты что-то делаешь неправильно. При обработке импортов например управление туда передается задолго до его передачи в entry point и видимо не всё для этого готово. Законные-легитимные приложения так не строят вобщем. ЗЫ: че-то навеяло. TerminateThread попробуй потоком на себя кастовать, мне в похожем случае когда-то помогало.
Я пишу библиотеку-кликер, которая должна иметь возможность быть выгруженной из процесса в любой момент, без завершения целевого процесса. Никаких меню в ней нет, при выгрузке должны завершиться два потока. Дожидаться их завершения не нужно, я лишь хочу чтобы они в итоге просто завершились. TerminateThread работает корректно, но очень мозолит глаза предупреждение о том что очистка потоков не выполнится корректно. Хотелось бы сделать как можно корректно, чтобы на код можно было смотреть без отврата.
Создавай потоки удаленно. И вообще длл для инжекта в чужой процесс не особо нужна, их используют ради удобства.
У меня вроде-бы не с созданием потоков проблема, а с их завершением) Задумка такая, что библиотека это единое целое, нет какого-то приложения которое её внедряет, человек сам должен ее заинжектить чем-то. --- Сообщение объединено, 20 авг 2023 --- Проблема была в главном потоке библиотеки. Он делал вызов SetEvent и сразу же выгружался, а в моем потоке задержка 10 мс. В итоге получалось в итоге что функция WaitForSingleObject обращалась к недоступной памяти и это приводило к крашу. Решение нашел не сам, спасибо @DymOk