There's another option: set the DLL to be delay-loaded, and use the delay load DLL import hook to load explicitly the DLL you want.
When it comes to resolving a delay-loaded DLL, usually the system (though I'm not sure which part - presumably the CRT?) will spot that there's a plugin.dll
already loaded and hand out another handle to it. But with the delay load DLL hook you can get it to load another DLL with LoadLibrary
- in this case the plugin specific copy of the shared DLL. Supply the full path, so there's no chance LoadLibrary
will return a handle to the existing DLL.
To do this, store the DLL's HINSTANCE in DllMain
.
static HINSTANCE g_hinstDLL;
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
if (fdwReason == DLL_PROCESS_ATTACH)
g_hinstDLL = hinstDLL;
return TRUE;
}
And have a suitable delay load hook that watches for dliNotePreLoadLibrary
.
static FARPROC WINAPI DliHook(unsigned dliNotify, PDelayLoadInfo pdli) {
if (dliNotify == dliNotePreLoadLibrary) {
if (strcmp(pdli->szDll, "plugin.dll") == 0) {
char path[MAX_PATH];
GetModuleFileNameA(g_hinstDLL, path, sizeof path);
PathRemoveFileSpecA(path);
PathAppendA(path, "plugin.dll");
HMODULE hModule = LoadLibraryA(path);
return (FARPROC)hModule;
}
}
return 0;
}
const PfnDliHook __pfnDliNotifyHook2 = &DliHook;
(In the end I had to give up on this whole approach - lib.dll
seemed to assume it would only ever be loaded once per process, not unreasonably, and conflicted with itself in various ways when loaded multiple times. Probably solvable in principle, but I expect I'd only then have to do the same again for Linux and OS X...)