A Dynamic Link Library (DLL) is an executable file that cannot run on its own. It is a library of code and data that can be loaded and executed by other applications (either written in Delphi or other languages like C++ or C#).
1. Why Use DLLs?
- Modularity: Breaking a large application into smaller, manageable, and isolated components.
- Code Sharing: Allowing multiple client applications to use the same functionality without duplicating the code.
- Updatability: You can update or replace a specific feature (the DLL) without recompiling or redeploying the entire main application (the EXE).
- Language Interoperability: DLLs are the primary way Delphi applications interface with functions exported from other languages (and vice versa).
2. Creating a Delphi DLL
The process of creating a DLL is similar to creating an executable, but the project file is marked as a library.
A. The Library Project File (.dpr)
The DLL entry point uses the library keyword instead of program. The key step is using the exports clause to list the functions and procedures that the DLL will make available to external applications.
library MathFunctions; // Use 'library' instead of 'program'
uses
SysUtils,
MathUnit in 'MathUnit.pas'; // The unit containing the functions
exports
// List the functions/procedures available to external callers
// Syntax: FunctionName name 'ExternalName'
AddIntegers,
SubtractIntegers name 'Subtract'; // Can specify an external name
begin
// Initialization code runs when the DLL is loaded by the application
end.
B. The Unit File (.pas)
The functions or procedures you want to export must be defined in the DLL’s units. They should use the standard Pascal calling convention, or if specifically targeting Windows APIs or C code, use the stdcall directive.
unit MathUnit;
interface
// Standard Pascal functions to be exported
function AddIntegers(A, B: Integer): Integer;
function SubtractIntegers(A, B: Integer): Integer;
implementation
function AddIntegers(A, B: Integer): Integer;
begin
Result := A + B;
end;
function SubtractIntegers(A, B: Integer): Integer;
begin
Result := A - B;
end;
end.
3. Consuming a DLL from a Delphi Application
There are two primary ways a client application (the EXE) can use the functions exported by the DLL: Static Loading or Dynamic Loading.
A. Static Loading (Load-time Linking)
This is the easiest method. The functions are declared in the client application’s unit, and the linker ensures the DLL is loaded when the program starts.
- Requirement: The DLL file must be in the same folder as the EXE, or in the Windows search path.
- Failure: If the DLL is not found, the EXE will fail to start.
// In the client application's unit (interface section)
// Declare the external functions. The 'external' clause points to the DLL file.
// The 'name' clause matches the exported name from the DLL's exports section.
function AddIntegers(A, B: Integer): Integer; external 'MathFunctions.dll';
function SubtractIntegers(A, B: Integer): Integer; external 'MathFunctions.dll' name 'Subtract';
// Usage:
procedure TForm1.btnCalculateClick(Sender: TObject);
var
Sum: Integer;
begin
// Call the function as if it were a local procedure
Sum := AddIntegers(10, 5);
ShowMessage('Sum: ' + IntToStr(Sum));
end;
B. Dynamic Loading (Run-time Linking)
This method loads the DLL explicitly at run time using Windows API functions. It is more complex but allows the application to handle missing DLLs gracefully and only loads the library when needed.
- API Functions:
LoadLibrary(FileName): Loads the DLL into memory, returning a handle (THandle).GetProcAddress(Handle, FunctionName): Retrieves a pointer to the exported function.FreeLibrary(Handle): Unloads the DLL and frees its memory.
// Requires System.SysUtils and Winapi.Windows in uses clause
// 1. Define the function signature (matching the DLL export) as a Pointer Type
type
TAddFunction = function(A, B: Integer): Integer; stdcall;
procedure TForm1.btnDynamicCalculateClick(Sender: TObject);
var
DLLHandle: THandle;
AddFuncPtr: TAddFunction; // Pointer to the function
Sum: Integer;
begin
// 1. Load the DLL
DLLHandle := LoadLibrary('MathFunctions.dll');
if DLLHandle <> 0 then
try
// 2. Get the address of the exported function
AddFuncPtr := GetProcAddress(DLLHandle, 'AddIntegers');
if Assigned(AddFuncPtr) then
begin
// 3. Call the function via the pointer
Sum := AddFuncPtr(20, 10);
ShowMessage('Dynamic Sum: ' + IntToStr(Sum));
end;
finally
// 4. Always free the library
FreeLibrary(DLLHandle);
end
else
ShowMessage('Error: Could not load MathFunctions.dll');
end;
