Мы сообщали об этой ошибке в течение нескольких лет, и теперь мне нужно потратить некоторое время на ее исправление.
Несколько упоминанийэто из других источников:
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, что я подтвердил, используя стандартный драйвер MSSQL, поставляемый с 10.2 Tokyo Enterprise, и вообще без драйверов 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 , гдеэто звонит TDBXDriverRegistry.DBXDriverRegistry.FreeDriver для каждого установленного / используемого драйвера dbExpress.
Когда вызывается 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 .
Учитывая мой опыт использования компонентов DevExpress VCL в DLL, где вам нужноЧтобы вызвать dxInitialize и dxFinalize для правильной работы с GDIPlus, я могу только думать, что нужно что-то делать либо в DLL, либо из вызывающей программы, чтобыустранить эту ошибку, но я просто не могу понять, что это может быть, поэтому этот вопрос.