== Creating and Using a Library DLL ==
== Creating a Library DLL ==
Create library project:
**MyLib.dpr**
library MyLib;
{ Important note about DLL memory management: ShareMem must be the
first unit in your library's USES clause AND your project's (select
Project-View Source) USES clause if your DLL exports any procedures or
functions that pass strings as parameters or function results. This
applies to all strings passed to and from your DLL--even those that
are nested in records and classes. ShareMem is the interface unit to
the BORLNDMM.DLL shared memory manager, which must be deployed along
with your DLL. To avoid using BORLNDMM.DLL, pass string information
using PChar or ShortString parameters. }
uses
MyUtils in 'MyUtils.pas';
{$R *.res}
//------------------------------------------------------------------------------
// exports
//------------------------------------------------------------------------------
exports
myHelloWorld, MySecondHello, DisplayLastGreeting;
begin
end.
Create routines in unit file:
**MyUtils.pas**
unit MyUtils;
interface
uses
SysUtils,
Classes,
Dialogs;
const
Left = 0;
Right = 1;
//------------------------------------------------------------------------------
// Global Variables
//------------------------------------------------------------------------------
var
FAppHandle: integer;
LastGreeting: Widestring;
//------------------------------------------------------------------------------
// Function Prototypes
//------------------------------------------------------------------------------
function TestUnit(AppHandle: integer): Boolean; stdcall;
procedure MyHelloWorld(InitialGreeting: Widestring=''); stdcall;
procedure MySecondHello(greeting: Widestring); stdcall;
//------------------------------------------------------------------------------
// Function Implementations
//------------------------------------------------------------------------------
implementation
//------------------------------------------------------------------------------
{*
// @section TestUnit Procedure: TestUnit
// @brief Unit test routine, for easy testing of different function in library.
// @param[in] AppHandle: integer; Application Handle, in case we need to use it.
// @retval Boolean
// @remarks Rev.History:
// - smayr 19-Sep-2006, Routine creation.
}
//------------------------------------------------------------------------------
function TestUnit(AppHandle: integer): Boolean; stdcall;
begin
//-------------------------------
// perform unit testing
//-------------------------------
MyHelloWorld('Hello World');
MySecondHello('Greetings from Planet Earth');
DisplayLastGreeting();
//-------------------------------
// Unit Test Results
//-------------------------------
result := True; // Unit Test Passed
end;
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
procedure MyHelloWorld(InitialGreeting: Widestring=''); stdcall;
begin
LastGreeting := InitialGreeting;
ShowMessage(InitialGreeting);
end;
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
procedure MySecondHello(Greeting: Widestring); stdcall;
begin
LastGreeting := InitialGreeting;
ShowMessage(Greeting);
end;
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
procedure DisplayLastGreeting(); stdcall;
begin
ShowMessage(LastGreeting);
end;
end.
== Using a Library DLL ==
=== Loading Library Permanently (Implicit Binding) ===
Create an application, and include a declaration of the routines found in the library DLL. For example, the main form (frmMain) would look like this:
unit TstMain;
interface
uses
Windows, Messages, SysUtils, Variants, Classes,
Graphics, Controls, Forms, Dialogs, StdCtrls;
type
TfrmMain = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject) ;
private
{ Private declarations }
public
{ Public declarations }
end;
var
frmMain: TfrmMain;
//-----------------------------------------------------------
// function prototypes
//-----------------------------------------------------------
function TestUnit(AppHandle: THandle): Boolean; stdcall;
procedure MyHelloWorld(InitialGreeting: Widestring=''); stdcall;
procedure MySecondHello(Greeting: Widestring=''); stdcall;
procedure DisplayLastGreeting(); stdcall;
implementation
{$R *.dfm}
//-----------------------------------------------------------
// function implementations. Here, externally implemented
//-----------------------------------------------------------
function TestUnit; external 'MyLib.dll'
procedure MyHelloWorld; external 'MyLib.dll'
procedure MySecondHello; external 'MyLib.dll'
procedure DisplayLastGreeting; external 'MyLib.dll'
//-----------------------------------------------------------
// other function implementations
//-----------------------------------------------------------
procedure TForm1.Button1Click(Sender: TObject) ;
begin
TestUnit();
end;
end.
=== Loading Library Randomly (Explicit Loading and Releasing) ===
Create an application, and include a routine to dynamically load the library DLL. For example, the main form (frmMain) would look like this:
**main.pas**
unit TstMain;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls, ComCtrls, ActnList, Grids, ValEdit, ActnMan, ActnColorMaps, Buttons;
type
TfrmMain = class(TForm)
procedure actTestUnitExecute(Sender: TObject);
. . . code removed . . .
private
{ Private declarations }
function LoadDLL(DLLName: string): Boolean;
procedure UnloadDLL();
public
{ Public declarations }
end;
//----------------------------------------------------------------------------
// function/procedure pointers types
//----------------------------------------------------------------------------
TEzTestUnit = function (AppHandle: integer): Boolean; stdcall;
TMyHelloWorld = function (InitialGreeting: Widestring): stdcall;
TMySecondHello = procedure (Greeting: Widestring); stdcall;
TDisplayLastGreeting = function (): WideString; stdcall;
function GetProc(HandleInst: THandle; ProcName: string): TFarProc;
var
frmMain: TfrmMain;
TestUnit: TTestUnit;
MyHelloWorld: TMyHelloWorld;
MySecondHello: TMySecondHello;
DisplayLastGreeting: TDisplayLastGreeting;
HInst: THandle;
ProcPtr: TFarProc;
DllLoaded: boolean=False;
implementation
//----------------------------------------------------------------------------
// function to load the specified Library DLL
//----------------------------------------------------------------------------
function TfrmMain.LoadDLL(DLLName: string): boolean;
var
ProcLoaded: boolean;
begin
if DllLoaded then begin
result := True; // loaded
Exit;
end;
// initialize function pointers
ProcLoaded := False;
// load library
HInst := SafeLoadLibrary(DLLName);
if HInst > 0 then begin
try
DllLoaded := True;
// initialize procedures/functions
ProcPtr := GetProc(HInst, 'TestUnit');
ProcLoaded := ProcPtr <> nil;
if ProcLoaded then begin
TestUnit := TTestUnit(ProcPtr);
end;
ProcPtr := GetProc(HInst, 'MyHelloWorld');
ProcLoaded := ProcPtr <> nil;
if ProcLoaded then begin
MyHelloWorld:= TMyHelloWorld(ProcPtr);
end;
ProcPtr := GetProc(HInst, 'MySecondHello');
ProcLoaded := ProcPtr <> nil;
if ProcLoaded then begin
MySecondHello:= TMySecondHello(ProcPtr);
end;
ProcPtr := GetProc(HInst, 'DisplayLastGreeting');
ProcLoaded := ProcPtr <> nil;
if ProcLoaded then begin
DisplayLastGreeting:= TDisplayLastGreeting(ProcPtr);
end;
finally
if ProcLoaded then begin
result := True; // we loaded the DLL
end else begin
FreeLibrary(HInst); // unload DLL
DllLoaded := False;
ShowMessage('A function/procedure in ' + DLLName + ' library was not loaded.');
result := False;
end;
end;
end else begin
DllLoaded := False;
ShowMessage(DLLName + ' library not found');
result := False;
end;
end;
//----------------------------------------------------------------------------
// function to get the procedure name from the specified Library DLL
//----------------------------------------------------------------------------
function GetProc(HandleInst: THandle; ProcName: string): TFarProc;
var
ProcPtr: TFarProc;
begin
ProcPtr := nil;
// get procedure/function entry point
if HandleInst > 0 then begin
ProcPtr := GetProcAddress(HandleInst, PAnsiChar(ProcName));
if ProcPtr = nil then begin
ShowMessage(ProcName + '() DLL function/procedure not found');
end;
end else begin
ShowMessage('Library not loaded');
end;
result := ProcPtr;
end;
//----------------------------------------------------------------------------
// Routine to unload the library at will or when destroying the form or application:
//----------------------------------------------------------------------------
procedure TfrmMain.UnloadDLL();
begin
FreeLibrary(HInst); // unload DLL
DllLoaded := False;
end;
//----------------------------------------------------------------------------
// OnDestroy event for the main form, making sure the library resources are freed.
//----------------------------------------------------------------------------
procedure TfrmMain.FormDestroy(Sender: TObject);
begin
UnloadDLL();
FreeLibrary(HInst); // unload DLL
end;
//----------------------------------------------------------------------------
// Load a Library DLL and execute a function
//----------------------------------------------------------------------------
procedure TfrmMain.actTestUnitExecute(Sender: TObject);
begin
if LoadDLL('MyLib.DLL') then begin
if TestUnit() then begin
MessageDlg('Test Unit was performed successfully!', mtInformation, [mbOK], 0);
end else begin
MessageDlg('Test Unit failed to run correctly', mtError, [mbOK], 0);
end;
end;
end;