Static vs. Dynamic Dynamic Link Library Loading - A Comparison

When to Use Static, When to Use Dynamic DLL Loading in Delphi

Static vs. Dynamic DLL Loading
Static vs. Dynamic DLL Loading.

A DLL or a dynamic link library acts as a shared library of function, that can be called by applications and by other DLLs.

Using Delphi, you can create and use our own DLLs, you can call functions in DLLs developed with other programming languages / by other developers.

If you are new to working with DLLs, make sure you read Introduction to DLLs.

Static or Dynamic Loading?

When you want to call a function exported by a DLL, one question comes up: should you use static or dynamic DLL loading?.

Before you can call routines defined in DLL, you must import them.

Functions exported from a DLL can be imported in two ways: by declaring an external procedure or function (static), or by direct calls to DLL specific API functions (dynamic).

Let's create a simple DLL. Here's the code to the "circle.dll" exporting one function "CircleArea" which calculates the area of a circle using the given radius:

 library circle;
   SysUtils, Classes, Math;
 {$R *.res}
 function CircleArea(const radius : double) : double; stdcall;
   result := radius * radius * PI;
 exports CircleArea;
Note: if you need help with creating a DLL using Delphi, read the How to create (and use) a DLL in Delphi. Once you have the circle.dll you can use the exported "CircleArea" function from your application.

Static Loading

The simplest way to import a procedure or function is to declare it using the external directive:
 function CircleArea(const radius : double) : double; external 'circle.dll';
If you include this declaration in the interface part of a unit, circle.dll is loaded once, when the program starts. Throughout execution of the program, the function CircleArea is available to all units that use the unit where the above declaration is.

Dynamic Loading

You can access routines in a library through direct calls to Win32 APIs, including LoadLibrary, FreeLibrary, and GetProcAddress.
These functions are declared in Windows.pas.

Here's how to call the CircleArea function using dynamic loading:

   TCircleAreaFunc = function (const radius: double) : double; stdcall;
   dllHandle : cardinal;
   circleAreaFunc : TCircleAreaFunc;
   dllHandle := LoadLibrary('circle.dll') ;
   if dllHandle <> 0 then
     @circleAreaFunc := GetProcAddress(dllHandle, 'CircleArea') ;
     if Assigned (circleAreaFunc) then
       circleAreaFunc(15) ; //call the function
       ShowMessage('"CircleArea" function not found') ;
     FreeLibrary(dllHandle) ;
     ShowMessage('circle.dll not found / not loaded') ;

When you import using dynamic loading, the DLL is not loaded until the call to LoadLibrary. The library is unloaded by the call to FreeLibrary.

With static loading the DLL will be loaded and its initialization sections will execute before the calling application's initialization sections are executed. With dynamic loading, this is reversed.

Static or Dynamic

Let's now compare static and dynamic DLL loading to see what are advantages and disadvantages of both.

Static loading PROS:

  • More easy for a beginner developer, no "ugly" API calls.
  • DLLs loaded once, when the program starts.

Static loading CONS:

  • The application will NOT start if any DLLs are missing (cannot be found). When you run the program you will see an ugly message: "This application has failed to start because 'missing.dll' was not found. Re-installingn the application may fix this problem".
    By design the DLL search order with static linking includes: the directory from which the application loaded, the system directory, the Windows directory, directories listed in the PATH environment variable.
    Note also that the search order might be different for various Windows versions.
    The safest is to always expect to have all the DLLs in the directory where the calling application is.
  • More memory used, as all DLLs are loaded even if you will not use some of the functions.

Dynamic loading PROS:

  • You can run your program even when some of the libraries it uses are not present.
  • Smaller memory consumption - DLLs used when needed.
  • You can specify the full path to the DLL.
  • Use for functionality that is rarely needed by the application.
  • Could be used for modular applications. The application only exposes (loads) modules (dlls) "approved" for the user.
  • The ability to load and unload library dynamically, is the foundation of a plug-in system that allow a developer to add extra functionality to programs.
  • Backwards compatibility with older Windows versions, in which system dlls may not support the same functions or in the same way. Detecting the Windows version first, then dynamic linking based on what your app is running on, allows you to support more versions of Windows and provide work arounds for older OSs, or at the very least gracefully disabling features you can't support.

Dynamic loading CONS:

  • Requires more code, not trivial for a beginner developer.

I hope differences are clear and that you will know what type of DLL loading to use for your next project ;)

If you think some PROS or CONS are missing, feel free to let me know - I'll add it to the list.