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;