Anyone know if its possible to gracefully test for and handle a missing .dll file in a Delphi application? For example, my code has this function declaration:
function KFUNC(Arg1, Arg2, Arg3, Arg4: DWord): longint stdcall; external 'KL2DLL32.DLL' name '_KFUNC@16';
...which of course requires the dll file KL2DLL32.DLL to be found on the system, otherwise my application wont start. Im wondering if theres some different way to code this, so my application could test for the dll file's existence, and then handle accordingly. Obviously, the goal would be have my application still start normally even if the dll file isn't there. Thanks.
Your import results in the function being linked using what is known as load-time or implicit linking. That is the executable contains meta data that tells the OS loader to load the DLL, and then bind to the functions that you named. If this load-time linking process fails, then the executable cannot be loaded.
You have a couple of options to avoid load-time linking, and thereby allow your program to be resilient to linking failures.
Delay-loading the DLL
Add the delayed
directive to your function import. The documentation says:
To postpone the loading of the library that contains the function to the moment the function is actually needed, append the delayed directive to the imported function:
function ExternalMethod(const SomeString: PChar): Integer; stdcall; external 'cstyle.dll' delayed;
delayed ensures that the library that contains the imported function is not loaded at application startup, but rather when the first call to the function is made.
The documentation contains other useful topics that go into more detail, and cover how to handle errors:
Explicit loading and binding to the DLL
The delayed
directive is merely a concise way to get the compiler to arrange explicit loading of your DLL. You can do the same yourself manually using LoadLibrary
and GetProcAddress
.
LoadLibrary
to load the DLL. Either supply a full path to the DLL, or just its name. In the latter case you rely on the DLL search order to locate the DLL. The call to LoadLibrary
yields a module handle.GetProcAddress
to obtain the address of a named function pointer. You must supply the module handle from step 1.FreeLibrary
to unload the DLL.At each step of the way you must check the function return values in case of error. How to handle errors is documented for each Win32 API function in the MSDN documentation (as linked to above). For example, if the DLL cannot be found, then LoadLibrary
returns 0
. You must detect that and deal with the consequences accordingly.
Discussion
Although the delayed
directive is very convenient, I personally have never used it. In my experience, whenever I have needed to link explicitly I've always found that I needed some extra flexibility that is not offered by delayed
. Perhaps my needs are special, but do not be surprised if you find yourself leaning towards explicit calls to LoadLibrary
and GetProcAddress
.
As an example, just today I found myself using LoadLibraryEx
because I wanted to pass the LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR
flag. That sort of fine grained control is not available when you use delayed
.
When the function is declared like that, there's nothing your program can do about a missing DLL. The OS attempts to resolve the imported DLL function before any bit of your program's code begins to execute, so there's no code you can write that would do anything about it.
As of Delphi 2010, though, you can change the function's declaration to use the new delayed loading feature. Add the delayed
directive to the end of the declaration:
function KFUNC(Arg1, Arg2, Arg3, Arg4: DWord): longint stdcall;
external 'KL2DLL32.DLL' name '_KFUNC@16' delayed;
If you're using an older Delphi version, then your only option is to load the DLL and the function at run time, and then handle the errors.
Another benefit of using delayed is that there are SetDliNotifyHook2
and SetDliFailureHook2
functions that allow you to assign hooks so you can handle run-time load notifications and failures, respectively.
So, if a given DLL, or even a given function, is not found at runtime, you can log an error, even substitute it with another DLL handle or function pointer to satisfy the load.
Both options are discussed in more detail in another question centering on using a DLL only when required.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With