The code snippet shown in this article is used to delay load a DLL, i.e., DLL is implicitly linked but not actually loaded until your code attempts to reference a symbol contained within the DLL. If your application uses several DLLs, its initialization time might be slow because the loader maps all of the required DLLs into the process' address space and there is every possibility that even a single function from one of these DLLs is not called, so a better way for a loading a DLL which is rarely used is to delay load, it i.e., load it when required instead of loading initially. This improves the start up time. Sounds great. Now, we will actually try to delay load a DLL, and analyze its advantages and disadvantages, so all set...
Using the code
First, you create a DLL just as you normally would. You also create an executable as you normally would but you do have to change a couple of linker switches and re-link the executable. Here are the two linker switches you need to add:
#pragma comment(lib, "DelayImp.lib")
pragma comment(linker, "/DelayLoad:Dll.Dll")
#pragma comment(linker, "/Delay:unload")
So simple, isn't it? Just add the above three lines in your EXE's code and your DLL is delay-loaded. Now, let's have a look at how it is achieved.
The Lib, "DelayImp.lib" switch tells the linker to embed a special function,
__delayLoadHelper, into your executable.
The second switch tells the linker the following things:
Remove Dll.dll from the executable module's import section so that the operating system loader does not implicitly load the DLL when the process initializes. You can watch it from the dependency walker utility that ships with VC 6.0. Below is the image of the dependency walker with and without delay loading. As seen, in the case of delay loading, it has no entry in the EXE's dependencies.
As seen in the first case without delay-loading, Dll.Dll is shown in the EXE's dependencies but not in the second image of the EXE which is using delay loaded DLL.
Continuing abt the linker switch
... It embeds a new Delay Import section (called .didata) in the executable indicating which functions are being imported from Dll.dll.
Resolve calls to the delay-loaded functions by having calls jump to the
When the application runs, a call to a delay-loaded function actually calls the
__delayLoadHelper function instead. This function references the special Delay Import section and knows to call
LoadLibrary followed by
GetProcAddress. Once the address of the delay-loaded function is obtained,
__delayLoadHelper fixes up calls to that function so future calls go directly to the delay-loaded function. Note that other functions in the same DLL still have to be fixed up the first time you call them. Also note that you can specify the /DelayLoad linker switch multiple times—once for every DLL that you want to delay-load.
When the operating system loader loads your executable, it tries to load all the required DLLs. If a DLL can't be loaded, the loader displays an error message. But for delay-loaded DLLs, the existence of the DLL is not checked at initialization time. If the DLL can't be found when a delay-loaded function is called, the
__delayLoadHelper function raises a software exception. You can trap this exception using structured exception handling (SEH) and keep your application running. If you don't trap the exception, your process is terminated.
Another problem can occur when
_delayLoadHelper does find your DLL but the function you're trying to call isn't in the DLL. This can happen if the loader finds an old version of the DLL, for example. In this case,
_delayLoadHelper also raises a software exception and the same rules apply.
If both the DLL and the function are found, the loader will try to load the DLL when a function or a symbol from that DLL is referenced. Since it is loaded now and not at application start up, it will take some time, but things get even worse if while building your DLL you haven't rebased its address to an appropriate one so at the time of function call, the loader will first try to load the DLL and it has to rebase the DLL which has a lot of overhead (for rebasing details, please go through the article Need for Rebasing a DLL). So also, if possible, rebase it properly to load the DLL quickly.
Acknowledgement and References
I would like to acknowledge author Mr Jeffery Richter and his book on Windows OS, which is one of the best books to know about the Windows operating system internals. Parts of this article is taken from the book and examples were added to simplify things.