Is there no way for your DLL to safely remove the WNDPROC when mIRC calls the UnloadDLL routine?
No, because UnloadDll will be called from the WM_CLOSE message handler function that is in turn called from the WNDPROC; therefore a subclass-wndproc from a DLL will still be on the call stack after the DLL is unloaded.
DLLs cannot take proper countermeasures against this (such as the LoadLibrary-on-itself trick or VirtualAlloc'ing a special zone to put the subclass-wndproc on) because there's no way of telling whether the UnloadDll function was called in response to mIRC exiting or the user doing /dll -u. In the latter case, the DLL would not want to leave anything behind.
To me, it seems like the easiest solution is for mIRC to not actually
FreeLibrary() the DLLs from WM_CLOSE, but instead either wait with this until after the main message loop is exited, or even just let Windows do it automatically when mIRC itself actually terminates. Thoughts?