DLL Development (FireDAC)

From RAD Studio
Jump to: navigation, search

Go Up to Working with Connections (FireDAC)


This topic describes how to use FireDAC in the dynamic-link libraries.

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 it had before the DLL call. It is indicated not to handle transactions in a DLL, change the transaction isolation level and other settings in a DLL.

Also, setting SharedCliHandle does not transfer any of the option values from an application to a DLL connection object. The DLL connection options can be set similar 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;

Note: This code does not:

  • 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