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.
This is a FireDAC limitation. See http://docwiki.embarcadero.com/RADStudio/XE8/en/DLL_Development_(FireDAC)#FireDAC_DLL_Unloading