I am not a C++ developer and nor do I have access to mIRC's code base, but here is my analysis of possible causes.

FreeLibrary unloads the library if and only if the reference count becomes zero. At this stage I am assuming that there is not a bug in Windows whereby the DLL is not unloaded despite the reference count being zero, so we have to assume that the reason that it is not unloaded is because the reference count is NON-ZERO. So the question then becomes why it is non-zero? Possible causes:

1. Internal mIRC code is loading the DLL more than once. I consider this to be very unlikely as if so it would be likely to cause all DLLs to remain locked.

2. It is an issue of unmanaged code dynamically loading managed code. I suspect that mIRC's code predates the concept of managed code by at least a decade, but it is possible that managed code automatically creates a reference to itself. Further research might come up with examples and fixes in other projects.

3. It could be an issue of the Hello World code - for example, FreeLibrary makes a call to the DLL to allow it to clean up - I don't see any code to handle this call (though it might be done under the covers by .NET) but perhaps this is the cause. Or perhaps something else in the code.

4. Dlls are loaded by mIRC scripts. You have not posted the script you are using to load the Hello World dll nor the output it produces. It could be something in your script which is causing the reference count to be > 0.

I am not sure whether this will help at all, but it is all I can add.