home *** CD-ROM | disk | FTP | other *** search
- unit Dllunit1;
-
- interface
-
- uses
- SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
- Forms, Dialogs, StdCtrls, Buttons, Grids, DBGrids, DB, DBTables;
-
- {
- Note that the TDllForm1 form is always used modally. Borland does not
- recommend using a modeless form from a DLL because the OnActivate and
- OnDeactivate mechanisms do not work when control is transferred between
- a DLL owned form and another DLL or EXE owned form.
- }
-
- type
- TDllForm1 = class(TForm)
- Table1: TTable;
- DataSource1: TDataSource;
- DBGrid1: TDBGrid;
- OKBtn1: TBitBtn;
- procedure FormClose(Sender: TObject; var Action: TCloseAction);
- private
- { Private declarations }
- public
- { Public declarations }
- end;
-
- const
- DllErrorUnload = 'The DLL must first be unloaded before re-use';
- DllErrorInUse = 'The DLL is already in use by another application';
- DllErrorViewingTable = 'The table could not be viewed: %s';
-
- var
- DllForm1: TDllForm1;
-
- {
- UseDLL should be called to verify that the DLL may be used by the
- current application.
-
- ExitDLL should be called before the DLL client exits. It CANNOT be
- called from a DLL WEP.
- }
-
- function UseDLL: string; export;
- procedure ExitDLL; export;
- function ViewTable (const TableName: string): string; export;
-
- implementation
-
- var
- Task: THandle;
- Unloaded: Boolean;
-
- {$R *.DFM}
-
- {
- Exceptions that are raised across a DLL call boundary cause an application
- termination. Therefore they are caught here and converted to an error
- return. The caller may convert back to an exception (if written in Delphi
- or C++) or pass the result back through some other error handling mechanism.
-
- Note that if ViewTable may be called by a C client, the TableName parameter
- should be a PChar rather than a string, and all error returns should be PChar,
- integer, or some common inter-language type. Here the types are string to
- make the code just a little more straightforward.
- }
-
- function ViewTable (const TableName: string): string;
- begin
- try
- if not Assigned (DllForm1) then
- DllForm1 := TDllForm1.Create (nil);
-
- with DllForm1 do
- begin
- Table1.TableName := TableName;
- Table1.Active := True;
- ShowModal;
- Result := ''
- end
- except
- on EResult: Exception do
- Result := Format (DllErrorViewingTable, [EResult.Message]);
- else
- Result := Format (DllErrorViewingTable, ['Unknown error']);
- end
- end;
-
- { Deactivate the table before the form is closed }
-
- procedure TDllForm1.FormClose(Sender: TObject; var Action: TCloseAction);
- begin
- Table1.Active := False;
- end;
-
- {
- Some services need to be de-initialized before the DLL WEP is called during
- DLL unload. BDE is an example of a service that cannot be de-initialized
- from within the WEP. The following routine must be called by the user of
- this DLL to de-initialize this DLL and its services. Once the
- deinitialization occurs, the DLL cannot be used again until it is unloaded.
- }
-
- procedure ExitDLL;
- begin
- CallExitProcs;
- Unloaded := True;
- end;
-
- {
- Many services require per-task initialization. BDE is an example of such
- a service. If a service DLL uses other such services, it too may require
- per-task initialization. Since the VCL BDE Session variable is allocated
- and initialized per-module rather than per-task, multiple applications
- cannot simultaneously use a DLL that itself uses BDE.
-
- In this demo service, multiple access is protected against via
- initialization and use validation routines. Another application
- (.EXE or .DLL in another task) cannot use this DLL until the first
- application unloads the DLL. For statically linked DLLs, the unload
- occurs automatically during application termination.
- }
-
- function UseDLL: string;
- begin
- if Task <> GetCurrentTask then Result := DllErrorInUse else
- if Unloaded then Result := DllErrorUnload
- else Result := ''
- end;
-
- { Initialize the task as soon as this service is loaded }
-
- begin
- Task := GetCurrentTask
- end.
-