Delphi & DLLs I
What
is a Dynamic Linked Library file (DLL)?
- DLL files are special files that contain subroutines which applications
can call and usually have the file extension of dll but may also be given
the extension drv (eg. driver files) and usually reside in the
\Windows\System folder so all applications can access them.
- variables within a DLL are always private to the DLL so that the
only way for other programs to access them is if there are exported
functions for doing so such as GetVariableXValue & SetVariableXValue,
BUT remember that DLLs are shared resources so that changing a variable
in a DLL will change it for any other program accessing it!!!!!
- DLL's, unlike exe files:
- cannot be ran alone but require an application to load them & then
call a routine within them.
- do not have their own message queues, but rely on the flow of messages
& events in the application which called it
- Window's operating system has 3 main dll files which contain the
code and data for the Window's Application Programming Interface (API):
- some of the advantages of DLL files are:
- that many applications can be ran simultaneously, each calling a
routine from the same DLL file, but only one instance of the DLL file
need be loaded into memory thus conserving resources
- the code for the routines do not need to be embedded in the
application's exe file, but only referenced from there, thus saving
storage space (nb. embedding routines within an exe is called statically
linked as opposed to dynamically linked as with DLL)
- if a change needs to be made to a routine, then just the one DLL file
need be upgraded rather than every executable application file that
requires it
- provide a unified interface to a variety of hardware items such as
different brand printers
- it is more easy to customise an application by having different DLLs
(eg. according to language spoken by user)
- they facilitate the development of large, complex applications by
allowing a more strict separation of subsystems
- they enable one to streamline access to data & data-like resources
(such as business model infrastructures) & to hardware devices
- most programming languages used in Windows can access DLL routines
- these Window's DLL files are written in C++ and thus can be difficult to
program with unless one is proficient at C++
- DLLs can be created by C++ or Delphi but not by Visual Basic or Java or
scripting languages
- Delphi hides much of this complexity by creating similar routines in
Object Pascal which call the Window's DLL routines and in the process
converting many of the more complex C++ data structures including pointers
into easier Object Pascal structures.
How
can you call a DLL routine from within Delphi?
- there are several ways of achieving this:
- using implicit binding:
- this is the easiest way as Delphi automatically loads &
unloads the library for you
- the manual way if you know the
DLL export routines:
- in the interface section of your Delphi unit, add the
following line:
- function DLLFunctionName(parameter types if any):ReturnDataType;
- example:
- procedure LoadForm1;
- function StripString(const s: String) : String;
- in the implementation section of your Delphi unit, add the
following line:
- function DLLFunctionName; external 'DLLName' (optionally:
index indexNo);
- a DLL export may be called by its ordinal index number
which is quicker than calling by name
- the DLLName is a string constant, so one could
actually declare a const of type string and assign it a
DLL name then use the constant in place of the DLL name
- when giving a DLLName, the extension "DLL"
is assumed & Window's will search & load a DLL
by that name
- examples:
- procedure LoadForm1; external 'MyForm';
- procedure LoadForm1; external 'MyForm' index
23;
- function StripString; external 'StringLib';
- const DLLa = 'StringLib'; function StripString;
external DLLa;
- then in your routine where you wish to call it, just call the
function as you would another function within Delphi.
- NB. your program will terminate with an error message if it
cannot find the DLL file!
- via importing the type library
of the DLL:
- from the Delphi menu, select Project:Import Type Library then
select the DLL you wish to import
- NB. the DLL must be registered in Window's to import it
- Delphi will create a Unit file with the exported DLL routines
formatted as above, this file is usually saved in the folder
\Imports
- to call a routine, just include the name of the Unit in your
Unit's uses clause.
- the advantage of this method is that once the import unit is
created, it can be re-used by other projects you create.
- this is how one uses COM interfaces
to other programs, although these require a little more
complexity
- NB. you could create such a unit yourself if you know all the
exported routines and their parameters
- using explicit loading &
releasing of the DLL:
- this uses Windows API calls to load & release a DLL when
needed, but requires you to create a handle for the DLL, the API
calls are:
- LoadLibrary(LibFilename:PChar):THandle;
- FreeLibrary(LibModule:THandle);
- NB. if the DLL is already loaded by another program, loadLibrary
just increments the "usage counter" of the DLL that is
maintained by Windows and thus it is important to decrement this
counter using FreeLibrary otherwise the DLL will never be unloaded
from Windows as it will think that your program is still accessing
it even after your program shuts down!
- thus, the following is needed to achieve this:
- uses: WinProcs, WinTypes, SysUtils;
- var
- ALibrary : THandle; //Windows uses handles for lots
of things such as an open window or DLL
- AFilename: string; ABuffer: array[0..255] of Char; //this
is to convert Pascal string to PChar
- aDLLFunctionName: function(parameter types):ReturnDataType;
//this is a procedural-type variable!
- //initialise variables:
- AFilename := 'mylibrary.dll';
StrPCopy(ABuffer,AFilename);
- @aDLLFunctionName := nil;
- try
- ALibrary := LoadLibrary(ABuffer);
- if ALibrary > HINSTANCE_ERROR then
- begin {its safe to use library}
- //retrieve subroutine addresses:
- @aDLLFunctionName := GetProcAddress(ALibrary, 'DLLFunctionName');
- //use function:
- if assigned(aDLLFunctionName) then
- x := aDLLFunctionName(parameter values);
- end
- else {there was a problem}
- finally FreeLibrary(ALibrary); end;
-