DLL Development (FireDAC)
Go Up to Working with Connections (FireDAC)
This topic describes how to use FireDAC in the dynamic-link libraries.
Contents
General
FireDAC may be used in a DLL as in a normal application. However, developers must be aware of two techniques, specific to DLL development.
Connection Sharing Between an Application and a DLL
When a connection must be transferred from an application to the DLL, the application should not transfer the TFDCustomConnection object because this may lead to AV errors and other issues. This is not an issue of FireDAC. It is due to the Delphi RTL / RTTI limitations. Note that a connection cannot be shared with another process because the sharing works only inside the same address space.
To transfer a connection between an application and a DLL, the application should transfer the TFDCustomConnection.CliHandle property value to the DLL. Here the handle must be assigned to the TFDCustomConnection.SharedCliHandle property.
After the TFDCustomConnection.SharedCliHandle is assigned, the DLL connection can be activated by setting Connected to True. Note that there is no need to set up a connection definition, including DriverID. Then, the connection can be used as a normal database connection. Finally, it can be closed by setting Connected to False. That does not close the physical connection, therefore the application connection remains active.
The application connection does not track state changes performed by the DLL. Therefore, the DLL should preserve the same transaction state as before the DLL call. The application is indicated not to handle transactions in a DLL or change the transaction isolation level and other settings in a DLL. Note that DLL does not track changes performed by the application either.
Also, setting SharedCliHandle does not transfer option values from an application to a DLL connection object. The DLL connection options can be set similarly to the application connection options.
For example, the DLL code:
procedure SomeTask(ACliHandle: Pointer); stdcall;
var
oConn: TFDConnection;
oQuery: TFDQuery;
begin
oConn := TFDConnection.Create(nil);
oQuery := TFDQuery.Create(nil);
try
oConn.SharedCliHandle := ACliHandle;
oConn.Connected := True;
oQuery.Connection := oConn;
oQuery.ExecSQL('delete from aaa');
finally
oQuery.Free;
oConn.Free;
end;
end;
exports
SomeTask;
And the application code:
procedure TForm1.Button1Click(Sender: TObject);
type
TSomeTaskProc = procedure (ACliHandle: Pointer); stdcall;
var
hDll: THandle;
pSomeTask: TSomeTaskProc;
begin
hDll := LoadLibrary(PChar('Project2.dll'));
try
@pSomeTask := GetProcAddress(hDll, PChar('SomeTask'));
FDConnection1.StartTransaction;
try
pSomeTask(FDConnection1.CliHandle);
FDConnection1.Commit;
except
FDConnection1.Rollback;
raise;
end;
finally
FreeLibrary(hDll);
end;
end;
- Handle DLL loading errors.
- Care about FireDAC DLL unloading - see next chapter.
- Keep DLL loaded for a long time and keep DLL objects for a long time.
FireDAC DLL Unloading
An application can hang up at unloading of a DLL containing FireDAC. The standard symptom for this is the application hanging up on the FreeLibrary call. This is a limitation of FireDAC, which has two workarounds:
- Enable the FireDAC silent mode in the DLL so that no wait cursors, no dialogs, and so on are shown by FireDAC. For this, put in your DLL DPR file:
uses
FireDAC.UI.Intf;
begin
FFDGUIxSilentMode := True;
end.
- Terminate FireDAC manager before the unloading of a DLL. For this, the DLL should export a procedure, which calls the ADTerminate procedure. For this, put in your DLL DPR file:
uses
FireDAC.Stan.Factory;
procedure Shutdown;
begin
FDTerminate;
end;
exports
Shutdown;
Then, import and call the Shutdown procedure from the application before the FreeLibrary call:
var
Shutdown: procedure;
....
Shutdown := GetProcAddress(hLib, 'Shutdown');
if Assigned(Shutdown) then
Shutdown();
FreeLibrary(hLib);
Note: The above technique must be used for the ActiveX servers with FireDAC inside.
See Also
Samples
- FireDAC DLL Sharing sample