You will have a handle leak in the case:
Program -Load> Dll A
-Load> Dll B
-Unload> Dll A
No code is implicitly executed by a module being unloaded to unload the modules that it loaded.
Since no code is executed to decrease the reference count, the module B will never be unloaded.
Here are the rules for loading / unloading dlls:
- Each call to LoadLibrary and LoadLibraryEx will increment the reference count for that module. This is in the context of the calling process only, not across process boundaries.
- Each call to FreeLibrary or FreeLibraryAndExitThread will decrement the reference count.
- When the reference count reaches 0, it will be unloaded.
- When Windows sees that your program is closed, any leaked unloaded modules will then be unloaded.
- Depending on what you are doing, DllCanUnloadNow might be useful to you.
Still in memory vs still loaded:
There is no guarantee that your module will be released from memory at a certain time when the reference reaches 0. But you should consider the module as if it is unloaded when the reference count reaches 0.
Stopping the DLL from being unloaded:
To force the DLL from being unloaded you could try
- The system calls DllMain with the DLL_PROCESS_DETACH flag. You could try to not return from this via some kind of blocking operation.
- You could try to call LoadLibrary from within the DLL that you want to not be able to unload. (Self load)
Edit:
You mentioned your goal is to injet code into the running program and that you wanted to leak the handle on purpose.
That is fine, but if you run this operation a lot it can lead to a crash in your source Program because too many handles will be used, or eventually too much memory will be used.
You can return FALSE from your DllMain to stop it from being loaded so that you don't waste memory. You do this when fdwReason is DLL_PROCESS_ATTACH. You can read more about it here.
If you are trying to emulate a DLL and add in your own extra functionality, you will need to implement all of the functions that the source DLL implements and delegate each call back to the source DLL.