Sample Application
To illustrate explicitly loading a DLL, we'll use a sample DLL with a modal form. Listing 1 shows the code for the main form of the application that demonstrates explicitly loading this DLL.
Listing 1Main Form for Calendar DLL Demo Application
unit MainFfm; interface uses SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type { First, define a procedural data type; this should reflect the procedure that is exported from the DLL. } TShowCalendar = function (AHandle: THandle; ACaption: String): TDateTime; StdCall; { Create a new exception class to reflect a failed DLL load } EDLLLoadError = class(Exception); TMainForm = class(TForm) lblDate: TLabel; btnGetCalendar: TButton; procedure btnGetCalendarClick(Sender: TObject); end; var MainForm: TMainForm; implementation {$R *.DFM} procedure TMainForm.btnGetCalendarClick(Sender: TObject); var LibHandle : THandle; ShowCalendar: TShowCalendar; begin { Attempt to load the DLL } LibHandle := LoadLibrary('CALENDARLIB.DLL'); try { If the load failed, LibHandle will be zero. If this occurs, raise an exception. } if LibHandle = 0 then raise EDLLLoadError.Create('Unable to Load DLL'); { If the code makes it here, the DLL loaded successfully; now obtain the link to the DLL's exported function so that it can be called. } @ShowCalendar := GetProcAddress(LibHandle, 'ShowCalendar'); { If the function is imported successfully, then set lblDate.Caption to reflect the returned date from the function. Otherwise, show the return raise an exception. } if not (@ShowCalendar = nil) then lblDate.Caption := DateToStr(ShowCalendar(Application.Handle, Caption)) else RaiseLastWin32Error; finally FreeLibrary(LibHandle); // Unload the DLL. end; end; end.
This unit first defines a procedural datatype, TShowCalendar, that reflects the definition of the function it will be using from CalendarLib.dll. It then defines a special exception, which is raised when there's a problem loading the DLL. In the btnGetCalendarClick() event handler, you'll notice the use of three Win32 API functions: LoadLibrary(), FreeLibrary(), and GetProcAddress().
LoadLibrary()
LoadLibrary() is defined this way:
function LoadLibrary(lpLibFileName: PChar): HMODULE; stdcall;
This function loads the DLL module specified by lpLibFileName and maps it into the address space of the calling process. If this function succeeds, it returns a handle to the module. If it fails, it returns the value 0, and an exception is raised. You can look up LoadLibrary() in the online help for detailed information on its functionality and possible return error values.
FreeLibrary()
FreeLibrary() is defined like this:
function FreeLibrary(hLibModule: HMODULE): BOOL; stdcall;
FreeLibrary() decrements the instance count of the library specified by LibModule. It removes the library from memory when the library's instance count is zero. The instance count keeps track of the number of tasks using the DLL.
GetProcAddress()
Here's how GetProcAddress() is defined:
function GetProcAddress(hModule: HMODULE; lpProcName: LPCSTR): FARPROC; stdcall
GetProcAddress() returns the address of a function within the module specified in its first parameter, hModule. hModule is the THandle returned from a call to LoadLibrary(). If GetProcAddress() fails, it returns nil. You must call GetLastError() for extended error information.