I have a DLL I inject into other processes using SetWindowsHookEx
. Inside the DLL I increment the module\'s reference counter by calling GetModuleHandleEx
I found the cause of the problem and the solution. I honestly feel quite stupid for missing it and struggling with it for so long.
As I mentioned in the original problem, the processes that are problematic do not have a UI. Turns out they do have a message pump running. The problem is nothing is sending messages to these processes without a UI after we call UnhookWindowsHookEx
that would trigger the unloading. (In fact, I believe MSDN does state that window messages are not sent to processes when calling UnhookWindowsHookEx
.)
By broadcasting WM_NULL to all processes after the injecting process calls UnhookWindowsHookEx
the message pump wakes up in the injected processes and the DLL reference count is decremented. The DLL is unloaded immediately when the injected DLL finally calls FreeLibraryAndExitThread
.
This is only part of the solution. If the injecting process is killed or crashes, no message is broadcasted so the DLL does not get unloaded from processes that do not have a UI. As I mention before I have a thread running in the DLL that waits on the injecting process handle. When the injecting process ends the DLL is signaled and then calls PostThreadMessage
to send WM_NULL to each thread in the process. Then it waits until the DLL reference count is decremented before continuing and cleaning up before calling FreeLibraryAndExitThread
. As a result, the DLL is unloaded almost immediately from all processes, UI or no UI.