Reputation: 1542
We've had this error being reported on and off for a few years, and now I've got to spend some time on it to sort it out for good.
There's been a few mentions of it from other sources:
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
I had opened a ticket with DevArt, giving them a copy of my test program and dll, but they quite rightly replied that the problem occurs even without DevArt drivers, which I have confirmed using the standard MSSQL driver supplied with 10.2 Tokyo Enterprise and no DevArt drivers being installed, at all.
The DLL has a single function:
exports
CheckConnection;
And here's the unit code in the 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.
This implementation line enables the DLL function to be used from the main program:
function CheckConnection(const Server, Database, User, Password: PAnsiChar): Boolean; stdCall; external 'Project3.dll';
And here's the code for the button click event for calling the 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;
The problem stems from the loop within TDBXDriverRegistry.CloseAllDrivers, where it is calling TDBXDriverRegistry.DBXDriverRegistry.FreeDriver for each dbExpress driver installed/used.
When FreeDriver is called, the execution thread goes to this method:
destructor TDBXDynalinkDriver.Destroy;
begin
if FMethodTable <> nil then
FMethodTable.FDBXBase_Close(FDriverHandle);
FDriverHandle := nil;
FreeAndNil(FMethodTable);
inherited Destroy;
end;
It is the FMethodTable.FDBXBase_Close(FDriverHandle); line that is throwing the Access Violation, and since it is untrapped, it causes the 216 error to occur in the calling program.
This call only fails on the last driver being freed, and only if we actually Open the TSQLConnection.
Given my experience with using DevExpress VCL components in DLL's, where you need to call the dxInitialize and dxFinalize in order to work with GDIPlus properly, I can only think that something needs to be done either in the DLL, or from the calling program, in order to resolve this error, but I just cannot figure out what that may be, hence this question.
Upvotes: 2
Views: 758
Reputation: 1542
I received a response from Embarcadero that says we should add AutoUnloadDriver=True to the parameters to
"avoid finalization order issues."
The only place we can add this and make any difference (in that it resolved the 216 error) is in the [MSSQL]
block of the dbxdrivers.ini file.
http://edn.embarcadero.com/article/39392/
I've been informed by DevArt that they have now added support for the AutoUnloadDriver parameter to their dbExpress driver for SQL Server. They sent me a nightly build that included this fix, since it is not yet in their public release version.
With a dbxdrivers.ini file in the application installation folder, and with the AutoUnloadDriver=True parameter added to the [MSSQL]
and [DevArtSQLServer]
sections, we no longer get any 216 errors when closing applications where a DLL was used to make a connection to SQL Server.
Upvotes: 1