延迟的 DLL 指令导致 FireDAC 查询上的应用程序死锁

Delayed DLL directive causing application deadlock on FireDAC query

我在 Delphi XE5 中按以下方式设置了一个应用程序:

main.exe: 使用导出延迟指令

调用 sub.dll 中的函数
function MyFunction: boolean; external 'sub.dll' delayed;

sub.dll:包含一个运行简单 SELECT 查询的 FireDAC 查询对象。

打开查询后,使用延迟指令,应用程序不会在主窗体关闭时终止(进程 main.exe 保留在任务管理器中)。 Process Explorer 显示线程剩余 sub.dll。当我没有指定延迟指令时,main.exe 进程正确终止。我错过了什么?我觉得我没有释放一个对象,但我不知道它是什么。

简化代码:

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.

VCL 可靠地 在 Dll 中工作 只有 如果你的主 Exe 和 Dll 在相同版本的 Delphi 中编译为它们启用了运行时包。

这是 FireDAC 的限制。参见 http://docwiki.embarcadero.com/RADStudio/XE8/en/DLL_Development_(FireDAC)#FireDAC_DLL_Unloading