通过Delphi DLL连接到SQL时,Delphi 10.2 Tokyo程序引发216错误

时间:2019-04-01 04:53:05

标签: sql-server delphi vcl delphi-10.2-tokyo dbexpress

几年来我们一直在报告此错误,现在,我不得不花一些时间对此问题进行彻底解决。

还有其他来源提到过它:

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.

此实现行允许从主程序使用DL​​L函数:

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); 行,由于未捕获该行,因此在调用程序中导致216错误。

仅当我们实际上打开 TSQLConnection 时,此调用才在释放最后一个驱动程序时失败。

基于我在DLL中使用DevExpress VCL组件的经验,您需要调用 dxInitialize dxFinalize 才能正确使用GDIPlus,我只能认为为了解决此错误,需要在DLL中或从调用程序中进行某些操作,但我只是无法弄清楚可能是什么,因此出现了这个问题。

编辑9/4/2019

我收到了Embarcadero的回复,说我们应该将 AutoUnloadDriver = True 添加到

的参数中
  

“避免敲定订单问题。”

我们唯一可以添加此文件并有所作为(因为它解决了216错误)的位置是dbxdrivers.ini文件的[MSSQL]块中。如果通过以下两种方法之一将其添加到 TSQLConnection Params 属性中,则无效:

SQLConnection.Params.Values['AutoUnloadDriver'] := 'True';

SQLConnection.Params.AddPair('AutoUnloadDriver', 'True');

这可能是一厢情愿的,但是在DLL中使用该驱动程序时,将该参数添加到dbxdrivers.ini文件的[DevArtSQLServer]块中也没有任何影响。

我现在再次联系DevArt,看看他们是否还有其他内容要添加,同时还尝试让Embarcadero向我们提供有关在部署情况下使用此 AutoUnloadDriver = True 的更多信息,因为最终用户安装没有dbxdrivers.ini文件。

编辑2 9/4/2019

本文介绍了对此参数所做的修复,

http://edn.embarcadero.com/article/39392/

您应该可以将其添加到 TSQLConnection 对象的 Params 集合中。

进入Embarcadero代码后,事实证明,如果dbxdrivers.ini中存在驱动程序名称(在此示例中为MSSQL),则在那里定义的参数将覆盖运行时设置的参数,但某些参数除外主机名,数据库,用户名和密码。这意味着

SQLConnection.Params.AddPair('AutoUnloadDriver', 'True');

正在努力将其添加到集合中,但是当它从ini文件中定义的驱动程序默认值重新加载集合时被删除了。

这确实意味着,如果在运行时进行设置,则它应该可以在完全没有dbxdrivers.ini文件的系统上运行。

1 个答案:

答案 0 :(得分:1)

我收到了Embarcadero的回复,说我们应该将 AutoUnloadDriver = True 添加到

的参数中
  

“避免敲定订单问题。”

我们唯一可以添加此文件并有所作为(因为它解决了216错误)的位置是dbxdrivers.ini文件的<form onsubmit="return check_form()"> ... </form> <script> function check_form() { return document.getElementById('g-recaptcha-response').value != ''; } </script> 块中。

http://edn.embarcadero.com/article/39392/

DevArt通知我,他们现在已在其用于SQL Server的dbExpress驱动程序中添加了对 AutoUnloadDriver 参数的支持。他们向我发送了包含此修复程序的每晚版本,因为该版本尚未发布。

在应用程序安装文件夹中包含一个 dbxdrivers.ini 文件,并将 AutoUnloadDriver = True 参数添加到check_form()[MSSQL]部分,关闭使用DLL来建立与SQL Server的连接的应用程序时,再也不会出现216错误。