mwasoftware.co.uk

The Delphi IBX library still works very well with Firebird. However, there is one annoying problem: it expects the Firebird Client library DLL to be called "gds32.dll". In Delphi 7, IBX is even more restrictive in that it checks the library version number and expects it to have a major version of 6.

If you want to use Firebird with IBX then you either have to rename the Firebird client library to gds32.dll and patch it so that it has a version number of 6.3, or - if you have access to the IBX source code - hack the source of ibintf.pas so that it loads fbclient.dll instead. Both approaches have their downsides. Renaming fbclient.dll to gds32.dll is probably the easiest strategy - but can result in other problems. Hacking the library also works. But then you can't use the ibexpress package in your application or any standard package that uses it. You also have to be careful to ensure that your application is always linked with the hacked version.

The good news is that with Delphi 2005, the IBX library introduced a new way of referencing the GDS client library. A Delphi "interface" was defined for all functions exported by the library and a new class (TDynamicLibrary) was also declared that provided this interface. TDynamicLibrary is declared in the implementation section of ibintf.pas. At runtime, an instance of the class is created and all accesses to the library go through this instance.

A "hook" function is also provided that allows the application to replace TDynamicLibrary with its own class. As long as that class also provides the GDS interface then all should be well. If the replacement TDynamicLibrary loads fbclient.dll instead then IBX will use the standard Firebird client library. Ideally, the replacement TDynamicLibrary would be a simple subclass of TDynamicLibrary. However, for reasons unknown, IBX does not make life so easy. TDynamicLibrary is hidden in ibintf.pas and has no virtual function to load the library. Our only choice is to copy the source code of ibintf.pas and use this to create a TFBDynamicLibrary to load the Firebird client.

The following code snippet is a skeleton of a suggested fbintf.pas. All that you need to do is to include this Pascal unit in the "uses" clause of your application and it will force IBX to load the Firebird Client library instead of the InterBase one. In fact, it does more than that. It first looks for the embedded server fbembed.dll in the application's installation folder, and loads that if it finds it. If not, it looks for fbclient.dll in the application's installation folder and loads that if it finds it - but first setting the FIREBIRD environment variable to the application's installation folder. This is so that the Firebird Client library will look in the same folder for firebird.msg and firebird.conf.

Finally, if it finds neither library, it tries to load fbclient.dll using the Windows default search algorithm for it and, if that fails then it similarly tries to load gds32.dll. Note that the FIREBIRD environment variable is not set in this case and any Firebird client library loaded will use its default search algorithm for firebird.msg and firebird.conf.

Unfortunately, it is not possible to publish a complete fbintf.pas. The ibintf.pas code is Borland/Codegear copyright and not freely distributable. You need a Professional or higher version of Delphi to have access to it and to complete the Unit. The instructions for copying code from ibint.pas are given as comments to this unit.

If you do use this unit in your applications then the suggested deployment strategy is to include fbembed.dll or fbclient.dll in your application's installation folder, along with the support files. For a development system, you will probably find it more useful to copy fbclient.dll to the Windows System32 folder, or at  least locate it somewhere on the Environment PATH.

(*
* PROGRAM: Firebird Library Loader for IBX
* MODULE: fbintf.pas
* DESCRIPTION: This unit clones the TDynamicLibrary class from
ibintf and modifies it to load the Firebird embedded
server (if available) or the Firebird Client library
from the application installation directory.
Otherwise, gds32.dll is loaded as the default.
*
* The contents of this file are subject to the Initial Developer's
* Public License Version 1.0 (the "License"); you may not use this
* file except in compliance with the License. You may obtain a copy
* of the License here:
*
* http://www.ibphoenix.com?a=ibphoenix&page=ibp_idpl.
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing rights
* and limitations under the License.
*
* The Initial Developer of the Original Code is Tony Whyman.
*
* The Original Code is (C) 2007 Tony Whyman.
*
* All Rights Reserved.
*
* Contributor(s): ______________________________________.
*
*)

unit fbintf;

{$D-,L-,Y-,M-,O+,Q-,R-}

interface

uses Windows, IB, IBXConst, IBExternals, IBHeader, IBIntf;

type

TFBDynamicLibrary = class(TInterfacedObject, IGDSLibrary)
private
{.. copy from TDynamicLibrary ..}
protected
function LoadFirebirdLibrary: THandle; virtual;
public
{.. copy from TDynamicLibrary ..}
end;

implementation

uses SysUtils, Forms, IBInstallHeader, IBXMLHeader;

{copy TDynamicLibrary's methods, stub functions and variables from ibintf}

function TFBDynamicLibrary.LoadFirebirdLibrary: THandle;
var InstallDir: string;
dllPathName: string;
begin
InstallDir := ExtractFilePath(Application.ExeName);
if FileExists(InstallDir + 'fbembed.dll') then
begin
dllPathName := InstallDir +'fbembed.dll';
Result := LoadLibrary(PChar(dllPathName))
end
else
if FileExists(InstallDir + 'fbclient.dll') then
begin
SetEnvironmentVariable('FIREBIRD',PChar(InstallDir));
dllPathName := InstallDir +'fbclient.dll';
Result := LoadLibrary(PChar(dllPathName))
end
else
begin
Result := LoadLibrary('fbclient.dll');
if Result <= HINSTANCE_ERROR then
Result := LoadLibrary(PChar(IBASE_DLL));
end
end;

{Modify LoadIBLibrary method.

Replace line :"IBLibrary := LoadLibrary(PChar(IBASE_DLL));"

with: "IBLibrary := LoadFirebirdLibrary;"

}

function GetMyGDSLibary: IGDSLibrary;
begin
Result := TFBDynamicLibrary.Create
end;

initialization

RegisterGDSLibraryFactory(GetMyGDSLibary)

end.