【发布时间】:2019-04-01 04:53:04
【问题描述】:
几年来我们一直在不断报告这个错误,现在我必须花一些时间来解决它。
其他来源也提到过几次:
https://forums.embarcadero.com/thread.jspa?threadID=112713
https://forums.devart.com/viewtopic.php?t=37398
https://forums.devart.com/viewtopic.php?f=10&t=16520
我已经向 DevArt 开了一张票,给了他们我的测试程序和 dll 的副本,但他们非常正确地回答说即使没有 DevArt 驱动程序也会出现问题,我已经使用 10.2 Tokyo Enterprise 提供的标准 MSSQL 驱动程序确认了这一点并且根本没有安装 DevArt 驱动程序。
DLL 有一个功能:
exports
CheckConnection;
这是 DLL 中的单元代码:
unit Unit7;
interface
uses
System.SysUtils, Data.SqlExpr, Data.DBXMSSQL;
function CheckConnection(const ServerName, DatabaseName, UserName, Password: PAnsiChar): Boolean; stdCall export;
implementation
function CheckConnection(const ServerName, DatabaseName, UserName, Password: PAnsiChar): Boolean; stdCall export;
var
SQLConnection: TSQLConnection;
begin
SQLConnection := TSQLConnection.Create(nil);
try
SQLConnection.DriverName := 'MSSQL';
SQLConnection.LibraryName := 'dbxmss.dll';
SQLConnection.VendorLib := 'sqlncli10.dll';
SQLConnection.GetDriverFunc := 'getSQLDriverMSSQL';
SQLConnection.Params.Values['HostName'] := ServerName;
SQLConnection.Params.Values['Database'] := DatabaseName;
SQLConnection.Params.Values['User_Name'] := UserName;
SQLConnection.Params.Values['Password'] := Password;
SQLConnection.LoginPrompt := False;
SQLConnection.Open;
Result := SQLConnection.Connected;
finally
SQLConnection.Close;
FreeAndNil(SQLConnection);
end;
end;
end.
此实现行允许从主程序中使用 DLL 函数:
function CheckConnection(const Server, Database, User, Password: PAnsiChar): Boolean; stdCall; external 'Project3.dll';
这是调用 DLL 的按钮单击事件的代码:
procedure TForm8.Button1Click(Sender: TObject);
var
Server, Database, User, Password: AnsiString;
begin
Server := Edit1.Text;
Database := Edit2.Text;
User := Edit3.Text;
Password := Edit4.Text;
if CheckConnection(@Server[1], @Database[1], @User[1], @Password[1]) then
Label1.Caption := 'DLL connected OK'
else
Label1.Caption := 'DLL did not connect';
end;
问题源于 TDBXDriverRegistry.CloseAllDrivers 内的循环,它为每个安装/使用的 dbExpress 驱动程序调用 TDBXDriverRegistry.DBXDriverRegistry.FreeDriver。
当FreeDriver被调用时,执行线程转到这个方法:
destructor TDBXDynalinkDriver.Destroy;
begin
if FMethodTable <> nil then
FMethodTable.FDBXBase_Close(FDriverHandle);
FDriverHandle := nil;
FreeAndNil(FMethodTable);
inherited Destroy;
end;
是FMethodTable.FDBXBase_Close(FDriverHandle);这行抛出了Access Violation,由于它没有被捕获,导致调用程序出现216错误。
此调用仅在最后一个驱动程序被释放时失败,并且仅当我们真正打开 TSQLConnection。
鉴于我在 DLL 中使用 DevExpress VCL 组件的经验,您需要调用 dxInitialize 和 dxFinalize 才能正确使用 GDIPlus,我只能认为为了解决这个错误,需要在 DLL 中或从调用程序中做一些事情,但我就是不知道那可能是什么,因此这个问题。
【问题讨论】:
-
无用评论:我在使用 MSSQL 的应用程序中使用 dbgo (ADO)。
标签: sql-server delphi vcl delphi-10.2-tokyo dbexpress