- - * - WhiteUnicorn - * - -




* #WhiteUnicorn/ StartPage/ Documentation/DelphiFAQ >


TI3318 - Importing or "Wrapping" DLL Function Calls


Importing or "wrapping" dll function calls

Two methods exist for importing or loading functions 
from a Dynamic Link Library(DLL). The first method 
(which is discussed extensively in this document) is 
called "implicit" loading. Implicit loading involves 
loading the DLL statically at startup and accessing 
the functions through an Object PASCAL interface.  
This method should be used when an application is totally 
dependent upon the loading of a DLL for proper functioning. 
The other method available is referred to as "explicit" 
loading because the DLL is loaded dynamically on demand.  
This method requires a little more coding and should be 
used if the application needs to run even if the DLL fails
to load properly.

What is a "wrapped" function call?

A wrapped function or set of functions consists
of an entry into the interface section and an 
entry into the implementation section (along
with associated constants or types) which corresponds
to a function or set of functions to be imported from
a DLL.  A wrapper is simply a declaration in a PASCAL 
unit that provides an entry Point into a DLL. With Delphi, 
this wrapper is represented by a unit file containing 
object pascal code. The Delphi development team has 
already conveniently wrapped many standard Windows 
controls and functions for you. On occasion it may become
necessary to create wrappers for dll function calls
that are not already wrapped in Delphi.  

The first and often the most difficult step in this 
process is locating information about the function(s). 
One of the best sources for locating documentation of 
the function(s) in question is the World Wide Web.
An extensive search beginning with the MSDN and 
extending to the numerous available search engines will 
often reveal some pertinent information.Search C++ header
files in a product like Borland C++ or MS Visual C++ to
get the structure of the function calls. Type conversion
and calling conventions are generally able to be resolved
when converting between C++ and PASCAL. A good resource
for compatibility between Delphi and C++ can be found
on the Borland web site at: 
"http://www.borland.com/delphi/papers/brick.html".

After locating an example or documentation of the DLL in 
question the next step is to create a new unit file. The 
interface of the unit will contain the types and constants 
that are specific to the function calls of the DLL along 
with the function headers. These function headers are the 
Object PASCAL interface that is being provided for other 
Delphi applications to call the DLL function. Once 
the interface section of the unit is complete the next 
section is the implementation. The implementation section
of the unit contains declarations of the imported external
functions. These headers are not identical to those found in 
the interface section of the unit (these contain the actual 
function identifiers plus other important implementation 
information).  For a more thorough treatment of this subject 
see the help topic "DLLs:accessing procedures and functions" 
in the Delphi 3 help file.

For example, say there exists a function called BOB in a DLL 
called 'BLODGE.DLL'.  (detailed below are the steps required to
implicitly load the DLL)

1) WWW Research on the function BOB reveals that it returns a 
boolean and takes a word and a boolean as it's arguments.  

2) Create a new unit file named 'UseBob.pas' via Delphi 
(File|New and choose unit)

3) The following line of code would go in the interface section 
of the new unit:

function BOB(Fire: Word; Dances: Boolean): Boolean; stdcall;

4) The following line of code would go in the implementation 
section of the new unit:

function BOB; external 'BLODGE';

5) Save the unit, name it 'UseBob.pas'.

6) It is also necessary to make sure that UseBob.pas 
is in the same directory of the current project or that it 
resides in a directory that is in the Delphi search path.

7) Add the 'UseBob' unit to a new project's uses clause. The 
function BOB can be called from this new project just like any 
other standard function.

8)  At runtime  BLODGE.DLL must be in the path of the current
process's environment.

The steps required to explicitly load the 'BLODGE.DLL' are 
slightly different and involve a bit of coding.  As before a 
knowledge of the function/procedure arguments is necessary 
(and a result type if it's a function).

What follows is a unit that implements the BOB function call 
on a button click event:

unit UDLLTest;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, 
  Forms, Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

{ Here's a type which points to our bob function }
  TBOB = function(Fire: Word; Dances: Boolean): Boolean; stdcall;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject);
var
  BOB: TBOB;
  hDLLInst: THandle;
  IsAlive,IsDancing: Boolean;
  Years: Word;

begin
  { Load a handle to our BLODGE.DLL }
  hDLLInst:= LoadLibrary('BLODGE.DLL');
  { If the load was unsuccessful raise a custom exception } 
  if (hDLLInst <= 0) then
    raise exception.create('[LoadLibrary Fail]');
  { Try to load the address of the BOB function }
  try
    @BOB:= GetProcAddress(hDLLInst,'BOB');
    if not assigned(BOB) then
      raise exception.Create('[GetProcAddress Fail]');
    Years:= 25;
    IsDancing:= True;
  { Now we can execute the BOB function }
    IsAlive:= BOB(Years,IsDancing);
  finally
  { Free the handle to the DLL }
    FreeLibrary(hDLLInst);
  end;
end;
end.
 
JG



* #WhiteUnicorn/ StartPage/ Documentation/DelphiFAQ >



- - * - Anastasija aka WhiteUnicorn - * - - LJLiveJournal
PFPhotoFile