延迟的 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
我在 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