【问题标题】:216 error thrown by Delphi 10.2 Tokyo program when connecting to SQL through a Delphi DLL通过 Delphi DLL 连接到 SQL 时 Delphi 10.2 Tokyo 程序抛出 216 错误
【发布时间】: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 组件的经验,您需要调用 dxInitializedxFinalize 才能正确使用 GDIPlus,我只能认为为了解决这个错误,需要在 DLL 中或从调用程序中做一些事情,但我就是不知道那可能是什么,因此这个问题。

【问题讨论】:

  • 无用评论:我在使用 MSSQL 的应用程序中使用 dbgo (ADO)。

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


【解决方案1】:

我收到了 Embarcadero 的回复,说我们应该在参数中添加 AutoUnloadDriver=True

“避免最终定单问题。”

我们可以添加它并做出任何改变的唯一地方(因为它解决了 216 错误)是在 dbxdrivers.ini 文件的 [MSSQL] 块中。

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

DevArt 通知我,他们现在已将 AutoUnloadDriver 参数支持添加到他们的 dbExpress 驱动程序用于 SQL Server。他们给我发了一个包含此修复程序的夜间版本,因为它还没有在他们的公开发布版本中。

使用应用程序安装文件夹中的 dbxdrivers.ini 文件,并将 AutoUnloadDriver=True 参数添加到 [MSSQL][DevArtSQLServer] 部分,我们不会在关闭使用 DLL 与 SQL Server 建立连接的应用程序时,不再出现任何 216 错误。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多