我编写了一个全局挂钩,它使用SetWindowsHookEx挂钩WH_GETMESSAGE、WH_CALLWNDPROC 和 WH_CALLWNDPROCRET。
钩子 dll 在钩子进程中创建一个新线程,除其他外,该线程检查进程的音频状态并调用IAudioSessionManager2::GetSessionEnumerator()。
现在有趣的部分是,我从钩子主机调用了UnhookWindowsHookEx()并且在我的 dll 的工作线程运行对IAudioSessionManager2::GetSessionEnumerator()的调用期间。该调用位于同一个线程的调用堆栈中,其中调用了带有 DLL_PROCESS_DETACH 的 DllMain。我认为原因是GetSessionEnumerator()在某处调用GetMessage()函数,而后者是可重入的。不幸的是,我记不清了,但我想我在调用堆栈中看到了。
但是有很多重要的事情我想知道并且仍然不清楚。所以这里有我的相关问题:
- 是否可以随时调用带有 DLL_PROCESS_DETACH 的 DllMain,即使是在运行当前正在卸载的 dll 中的函数的线程中?
- 当 DllMain DLL_PROCESS_DETACH 退出时,堆栈上的函数会发生什么?调用堆栈上的函数中的代码最终会执行吗?
- 如果这些功能不退出怎么办?dll什么时候卸载?
- DllMain DLL_PROCESS_DETACH 是否可以在 WH_GETMESSAGE、WH_CALLWNDPROC 和 WH_CALLWNDPROCRET 挂钩的回调期间被类似地调用?我知道并且已经通过实验证实,有时,虽然不是太频繁,但这些函数是可重入的,所以对这些函数的调用可以在上一次调用仍在同一个堆栈中运行的时间内注入,但我不知道是否也调用DllMain 可以以类似的方式注入。
- 何时可以在线程中准确调用 DllMain - 是否有一些特定的 Windows API 函数需要调用,而这又可能导致 DllMain DLL_PROCESS_DETACH 调用,或者它可能发生在任何指令中?
- 如果 DllMain DLL_PROCESS_DETACH 调用可以随时“注入”并且调用堆栈上的函数不再执行,那么我如何知道调用堆栈上的函数在哪里被中断?所以我可以在 DllMain 内部释放一些由函数在堆栈上分配的句柄或资源。
- 有什么方法可以暂时阻止/推迟对 DllMain DLL_PROCESS_DETACH 的调用?如果调用/中断发生在同一个堆栈中,锁显然没有帮助。
不幸的是,我可能无法通过实验解决这些问题,因为我已经在多台计算机上运行了几个月的挂钩(以及取消挂钩)代码,然后在取消挂钩期间发生 DllMain 的这种情况。尽管由于某种原因,它同时出现了四个不同的程序......
另外请有足够声誉的人喜欢合并标签“reentrant”和“reentrancy”吗?