DllMain DLL_PROCESS_DETACH и вход функции GetMessage

Я написал глобальный хук, который перехватывает с помощью SetWindowsHookEx WH_GETMESSAGE, WH_CALLWNDPROC и WH_CALLWNDPROCRET.
Хук dll создает новый поток в перехваченном процессе, который, среди прочего, проверяет состояние звука процесса и вызывает IAudioSessionManager2:: GetSessionEnumerator().

Теперь интересная часть: я вызывал UnhookWindowsHookEx() с хоста перехвата и в то время, когда рабочий поток моей библиотеки DLL выполнял вызов IAudioSessionManager2:: GetSessionEnumerator(). Этот вызов был в стеке вызовов того же потока, где был вызван DllMain с DLL_PROCESS_DETACH. Я предполагаю, что причина была в том, что GetSessionEnumerator() вызывает функцию GetMessage() где-то, и последняя является реентерабельной. К сожалению, я точно не помню, но думаю, что видел это в стеке вызовов.

Но есть несколько важных вещей, которые меня интересуют, и вещи, которые остаются неясными. Итак, вот мои связанные вопросы:

  1. Может ли DllMain с DLL_PROCESS_DETACH вызываться в любое время, даже в потоке, который выполняет функции из той dll, которая в данный момент выгружается?
  2. Что происходит с функциями в стеке при выходе из DllMain DLL_PROCESS_DETACH? Будет ли в конечном итоге выполняться код в функциях стека вызовов?
  3. Что делать, если эти функции не выходят? Когда DLL будет выгружен?
  4. Может ли DllMain DLL_PROCESS_DETACH аналогичным образом вызываться во время обратных вызовов для хуков WH_GETMESSAGE, WH_CALLWNDPROC и WH_CALLWNDPROCRET? Я знаю и экспериментально подтвердил, что иногда, хотя и не слишком часто, эти функции являются реентерабельными, поэтому вызовы этих функций могут быть введены в то время, когда предыдущий вызов все еще выполняется в том же стеке, но я не знаю, также являются ли вызовы DllMain можно вводить аналогичным образом.
  5. Когда именно DllMain может быть вызван в потоке - существуют ли какие-то определенные функции Windows API, которые необходимо вызвать и которые, в свою очередь, могут привести к вызову DllMain DLL_PROCESS_DETACH, или это может произойти при любой инструкции?
  6. Если вызов DllMain DLL_PROCESS_DETACH может быть "внедрен" в любое время и функции из стека вызовов больше не выполняются, то как узнать, где именно была прервана функция вверх по стеку вызовов? Так что я мог бы внутри DllMain выпустить некоторые дескрипторы или ресурсы, выделенные функцией вверх по стеку.
  7. Есть ли способ временно предотвратить / отложить вызовы DllMain DLL_PROCESS_DETACH? Блокировки, очевидно, не помогают, если вызов / прерывание происходит в том же стеке.

К сожалению, я, вероятно, не могу экспериментально решить эти вопросы, так как мой код перехвата (и отсоединения) выполнялся на нескольких компьютерах в течение нескольких месяцев, прежде чем такая ситуация с DllMain возникла во время отсоединения. Хотя почему-то это произошло сразу с четырьмя разными программами...


Также, пожалуйста, кто-нибудь с достаточно хорошей репутацией хотел бы объединить теги "reentrant" и "reentrancy"?

1 ответ

Решение

Так что благодаря Гансу я теперь знаю относительно пункта (4), что DllMain DLL_PROCESS_DETACH не будет повторно использоваться с подключаемыми процедурами.

Что касается потока, созданного ловушкой, мои файлы журналов в настоящее время указывают, что если DllMain DLL_PROCESS_DETACH вставляется в стек этого потока, то этот поток действительно будет прерван после выхода из DllMain и НЕ будет работать до завершения. Это должно отвечать пунктам (2) и (3). Сам вопрос неявно отвечает на пункт (1).

Но для решения проблемы для этого потока, созданного хуком, я предполагаю, что DllMain DLL_PROCESS_DETACH можно предотвратить, вызвав

GetModuleHandleEx
(
    GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
    (LPCTSTR)DllMain,
    &hModule_thread
)

и до вызова завершения потока

FreeLibraryAndExitThread(hModule_thread, 0)

Поэтому использование GetModuleHandleEx должно отвечать точке (7), что, в свою очередь, делает все остальные точки неактуальными. Конечно, я должен использовать какой-то IPC для запуска завершения потока в подключенных процессах.

Оставшийся интересный вопрос - это пункт (5), но он просто из любопытства:
"Когда именно DllMain DLL_PROCESS_DETACH может быть вызван в потоке - существуют ли какие-то определенные функции Windows API, которые необходимо вызвать и которые, в свою очередь, могут привести к вызову DllMain DLL_PROCESS_DETACH, или это может произойти при любой инструкции?"

Другие вопросы по тегам