Безопасное место для установки небезопасного кода очистки DLL в Windows?
Мы столкнулись с ситуацией, когда для нас было бы лучшим решением FreeLibrary
позвонить в DllMain
/ DLL_PROCESS_DETACH
,
Конечно, вы не должны делать это:
Вызывать FreeLibrary из DllMain небезопасно.
Случай использования заключается в том, что у нас есть такая ситуация:
(unknown client dll or exe) links dynamically or statically to ->
-> DLL_1, loads dynamically -> DLL_x
DLL_1 должна загружать DLL_x прозрачно по сравнению с к его клиентскому коду, и он должен динамически загружать DLL_x. Теперь загрузка может быть выполнена лениво, так что LoadLibrary
вызов не должен находиться в DLL_PROCESS_ATTACH
часть DLL_1.
Но как только клиент завершит работу с DLL_1, когда / до того, как DLL_1 будет выгружен из процесса, он также должен выгрузить (== FreeLibrary) DLL_x.
Есть ли способ сделать это без явного DLL_1/Uninitialize
функция, которая должна быть вызвана клиентом?
Я отмечу:
DllMain
и, следовательно, также нельзя использовать любой глобальный статический деструктор C++.- Есть ли какой-либо другой механизм обратного вызова в kernel32/ntdll или, возможно, в общем CRT MS, чтобы это произошло?
- Существуют ли другие шаблоны, чтобы этот вариант использования работал?
1 ответ
Правильный подход - явная функция Uninitialize в DLL_1.
Однако, если вы не можете этого сделать, вы можете обойти эту проблему, запустив вспомогательный поток, выполняющий разгрузку за вас. Если вы хотите, чтобы это было безопасно, запустите поток одновременно с загрузкой DLL_x и дождитесь, пока он обработает объект события. (Для записи, однако, обычно считается безопасным запускать поток из DllMain
до тех пор, пока вы уважаете тот факт, что он не запустится до DllMain
вышел.)
Очевидно, что код вспомогательного потока не может быть в DLL_1. Если вы можете изменить DLL_x, вы можете поместить его туда. Если нет, вам понадобится вспомогательная DLL. В любом случае библиотека DLL, содержащая код вспомогательного потока, может безопасно выгружаться самостоятельно с помощью функции FreeLibraryAndExitThread.