== 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;