Search code examples
delphidlldeadlockdelphi-xe5firedac

Delayed DLL directive causing application deadlock on FireDAC query


I have an application set up in the following manner in Delphi XE5:

main.exe: calls a function in sub.dll using the export delayed directive

function MyFunction: boolean; external 'sub.dll' delayed;

sub.dll: contains a FireDAC query object which runs a simple SELECT query.

Upon opening the query, with the delayed directive the application does not terminate when the main form is closed (process main.exe remains in task manager). Process explorer shows a thread remaining for sub.dll. The main.exe process terminates correctly when I do not specify the delayed directive. What am I missing? I feel like I'm not freeing an object but I can't figure out what it is.

Simplified code:

Main.exe:

program Main;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils;

  function MyFunction: boolean; external 'Sub.dll' delayed;

begin
  try
    MyFunction;
  except
    on E: Exception do begin
      Writeln(E.ClassName, ': ', E.Message);
      readln;
    end;
  end;
end.

Sub.dll

library Sub;

uses
  System.SysUtils,
  System.Classes,
  DBConn in 'DBConn.pas';

{$R *.res}

function MyFunction: boolean; export;
var Conn: TConn;
begin
  Conn := TConn.Create;
  Conn.Destroy;
  Result := True;
end;

exports
  MyFunction;

begin
end.

DBConn.pas

unit DBConn;

interface

uses
  FireDAC.Stan.Intf, FireDAC.Stan.Option,
  FireDAC.Stan.Error, FireDAC.UI.Intf, FireDAC.Phys.Intf, FireDAC.Stan.Def,
  FireDAC.Phys, FireDAC.Stan.Pool, FireDAC.Stan.Async, FireDAC.Stan.Param,
  FireDAC.DatS, FireDAC.DApt.Intf, FireDAC.DApt, FireDAC.VCLUI.Wait,
  FireDAC.Comp.UI, FireDAC.Phys.ODBCBase, FireDAC.Phys.ASA, Data.DB,
  FireDAC.Comp.DataSet, FireDAC.Comp.Client;

type
  TConn = class
    FDConnection: TFDConnection;
    FDQuery: TFDQuery;

    constructor Create;
    destructor Destroy; override;
  end;

var
  Conn: TConn;

{ TConn }

implementation

constructor TConn.Create;
begin
  FDConnection := TFDConnection.Create(nil);
  //Set database connection parameters
  with FDConnection do begin
    close; Params.Clear;
    Params.Add('DriverID=ASA');
    Params.Add('Database=');
    Params.Add('Server=');
    Params.Add('USER_NAME=');
    Params.Add('PASSWORD=');
    open;
  end;
  FDQuery := TFDQuery.Create(nil);
  with FDQuery do begin
    Connection := FDConnection;
    close; unprepare; SQL.Clear;
    SQL.Add('Select first LAST_NAME');
    SQL.Add('From USERS');
    SQL.Add('Order By LAST_NAME');
    prepare; open; //this causes the deadlock
    writeln(Output, FieldByName('LAST_NAME').AsString);
  end;
end;

destructor TConn.Destroy;
begin
  FDConnection.Close;
  FDConnection.Free;
  inherited;
end;

end.

Solution

  • This is a FireDAC limitation. See http://docwiki.embarcadero.com/RADStudio/XE8/en/DLL_Development_(FireDAC)#FireDAC_DLL_Unloading