On Linux, we can specify shared library search paths for our executable/libraries using RPATH. On Windows, however, there is no such easy way to do that. A possible solution is to use /DELAYLOAD and SetDllDirectory.
Ways to Load a DLL
Basically speaking, there are three ways to load a DLL on windows.
- Implicitly loading. In this way, we link our application against the .lib file of the DLL. The DLL will be loaded once the application was invoked.
- Explicitly loading. That is the way we call LoadLibrary
Win32 API to load a DLL. The search path can be changed by calling SetDllDirectory
function.
- Delayed loading. Similar to Implicit loading, but the DLL won’t be loaded until once of functions in it got called.
Delay loading
/DELAYLOAD
is a linker option of MSVC compiler (version 6 or later) that can tell the linker which DLL we want to delay load. So, to simulate the functionality of RPATH, we can specify the DLL should be delay loaded via /DELAYLOAD
at link time, and call SetDllDirectory
function to set the search path. After that, there are three ways to force load the library.
- We can simply call a function that is exported in that library to force loading the library.
- Call
LoadLibrary
to explicitly load the library. - Call
__HrLoadAllImportsForDll
to force load the library.
Listed below is an example to use the above method to delay load a DLL. Please note that to make the code work, delayimp.lib
should be linked against.
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <delayimp.h>
#include <string>
bool loadTheLibraryNow(const char* dir) {
const char* baseDllName = "library-to-delay-load.dll";
if (!dir)
return false;
// backup current dll directory
char previousDllDirectory[MAX_PATH] = { '\0' };
if (!::GetDllDirectoryA(MAX_PATH, previousDllDirectory)) {
previousDllDirectory[0] = '\0';
}
// set new current dll directory to
if (!::SetDllDirectoryA(dir))
return false;
// force load the dll
bool result = SUCCEEDED(__HrLoadAllImportsForDll(baseDllName));
// restore the dll directory to old value
::SetDllDirectoryA(previousDllDirectory);
return result;
}
Please See here for more details.
No comments:
Post a Comment