jbaseico.jpg (1294 bytes) Interfacing jBASE OBjEX with Delphi

Back to Knowledge Base Back to Knowledge Base Articles

Introduction

This document outlines the steps necessary to interface jBASE OBjEX with Delphi versions 3, 4 and 5. This discussion requires a prerequisite knowledge of Delphi language syntax, Object Pascal and a familiarity with the syntax of OBjEX. A knowledge of how Delphi records are manipulated is helpful but not necessary.

Sample units which illustrate all of the principles described in this document are included.

So that we won't have to reiterate too much we will discuss Delphi 4 and point out differences in Delphi 5. We will treat Delphi 3 as a separate topic at the end of this document.

 

Early vs. Late Binding

Delphi 4 and 5 supports a Dual Interface meaning that it supports both early binding and late binding. Delphi 3 only supports late binding. Early binding allows you to resolve the elements of a COM server at compile time whereas late binding can only determine the elements at run time. Early binding has several advantages over late binding the most significant of which are performance and the availability of Delphi's Code Insights.

Early binding allows you to specify the interface of an object like IjBase to access the properties, methods, events and constants of a COM server like OBjEX. Once the interface is declared the object is then instantiated from its parent CoClass. From there you are able to access any element in the object through its interface. Now it is really only necessary to understand the preceding explanation to the point that interfacing Delphi and OBjEX is a 2-step process to create the jBase object. The Delphi 4 Programmer's Guide goes into considerably more detail if you desire a deeper understanding of what is happening at each stage of the coding process.

Delphi 4 & 5

Prerequisite to using OBjEX (or any COM server for that matter) in Delphi you must import the type library. This need only be done once for the life of that version of OBjEX. To import the OBjEX type library, open a new or existing project then click Project > Import Type Library, select the OBjEX Type Library and click OK (Delphi 4) or Install (Delphi 5). By default, the type library is stored in the C:\Program Files\Borland\Delphi4\Imports sub-directory (if you installed Delphi in the default location of course) or, for Delphi 5, C:\Program Files\Borland\Delphi5\Imports.

To link the OBjEX type library to a project, add OBjEX_TLB to the Uses clause in the interface (Public) or implementation (Private) section of the unit. 

    uses
       Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, OBjEX_TLB, StdCtrls;

At this point you can now declare variables by specifying their type as an "interface" to the OBjEX type library. Once this has been added I recommend that you compile the project which will permit the use of the object Browser.

 

Instantiating the jBase Object

The OBjEX jBase object represents the jBase engine. It is the top-level object which contains and controls all other objects in the hierarchy of objects.  

First declare the variable jB by creating a reference to the IjBase interface. This is typically done in the interface section of the main unit:

    var
   
     jB: IjBase;

Now that the interface has been defined you can instantiate the jB object from it's CoClass This is typically done in the FormCreate event:

    begin
        jB := CojBase.Create;
        {...the rest of the code for the FormCreate event...}
    end;

You are now free to use the properties, methods and constants of the jB object anywhere in the unit or any unit which refers to this unit. For example:

    MyDate := jB.Oconv('11689', 'D');

Note that all Code Insights are available to you since you declared the object's interface as IjBase and not as the generic OleObject, in which case you would have to instantiate the object via the CreateOleObject function. In fact, there is no reason really to use the CreateOleObject function in Delphi 4 and above. The use of CreateOleObject will be described in more detail when we discuss Delphi 3. The jBase object, as are all types in the OBjEX type library, is also available to you in the object Browser by selecting the unit OBJEX_TBL.OBJEX_TBL. Note that the project must be compiled in order to use the Browser.

Handling Optional Parameters

A major difference between Delphi and VB is that in Delphi you can not leave off optional parameters. In many cases this is not a problem as it is only necessary to specify the default value in its place.

There are two types of optional parameters, optional input and optional output. Optional input parameters are distinguished from optional output parameters in that they do not return a value.

The methods which have optional output parameters are:

Find
FindStr
Field
ReadNext
ReadNextBool
ReadPrev

For example, suppose we have a string, MyString := '123.456.789', and we need to use the Field method to extract the 2nd dot delimited field (i.e. '456'). The Field method contains 4 optional parameters: Occurrence and Count are optional input parameters, BeforeCol and AfterCol are optional output parameters. The full syntax for the Field method is:

    jB.Field(Source, Delimiter, [Occurrence], [Count], [BeforeCol], [AfterCol])

where the optional parameters are enclosed in square brackets []. The optional parameters Occurrence and Count default to the integer value "1" so this value (or a variable of the expected type, an integer in this case) can be used in its place. Alternatively, you can substitute optional input parameters with a special kind of variable.

To specify optional input parameters as optional parameters we must declare an OleVariant of type varError  (VT_ERROR = $000A) with a VError value of DISP_E_PARAMNOTFOUND ($80020004). We will call the variable OptionalParam. 

In the interface section of the unit, declare:

    var
        OptionalParam: OleVariant;

Then place the following code in the initialization section of the unit:

    TVarData(OptionalParam).VType := varError;
    TVarData(OptionalParam).VError := $80020004; {DISP_E_PARAMNOTFOUND}

The parameters (BeforeCol and AfterCol) are optional output parameters and must be declared according to their expected types, OleVariant in this case.

We can now construct the complete statement as the following code snippet illustrates::

    var
        SecondPart: WideString;
        Col1: OleVariant;
        Col2: OleVariant;
    begin
        SecondPart := jB.Field(MyString, '.', 2, OptionalParam, Col1, Col2);
    end;

In still other situations you can 'fill in' the optional parameters with a placeholder. For instance, to extract the 3rd attribute from a jDynArray object called MyRec, you could fill in the ValueNo and SubValueNo with zeros:

    FieldThree := MyRec.Extract(3, 0, 0);

The preceding example could also be specified as:

    FieldThree := MyRec.Extract(3, OptionalParam, OptionalParam);

In all cases, Code Insights will let you know for each parameter what is expected so that you can declare it in advance.

If you are using Delphi 5, one advantage is that the System unit already comes packaged with the predefined value, EmptyParam, which can be used in place of the OptionalParam code. If you locate its declaration in the System unit you will see that it is identical to that which we used to declare the OptionalParam variable. Therefore it is not necessary to declare OptionalParam, simply use the value EmpyParam for all optional input parameters. For example,

    LocalDB := jB.Connect(EmptyParam, EmptyParam);

 

Local and Remote Connections

One task which will invariably be in most every Delphi/OBjEX project is connecting to at least one database on a server. Connecting to a local database (i.e. a database which resides on the same server where the Delphi process is running) is relatively straightforward. We will assume that the code for the jB object already exists as well as the code for OptionalParam (or EmptyParam) as discussed above:

First declare a jConnection variable in the interface section of the unit:

    var
        LocalDB: IjConnection;

Then instantiate the jConnection object. This is typically done in the FormCreate event as illustrated in the sample unit below:

    LocalDB := jB.Connect(OptionalParam, OptionalParam); {Delphi 4 or 5}

    LocalDB := jB.Connect(EmptyParam, EmptyParam); {Delphi 5 only}

Connecting to a remote database is somewhat more complex in that you must define the name of the remote server as an Ole String. VB hides much of this COMplexity behind the scenes whereas in Delphi you must handle this explicitly in the code:

First declare a jConnection variable in the interface section of the unit:

    var
        RemoteDB: IjConnection;

Since the first parameter of the Connect method is required to be an Ole String, you must define the UNC name of the remote server as an Ole Variant String. This is typically done in the FormCreate event:

procedure TForm1.FormCreate(Sender: TObject);
var
    RemoteName: OleVariant;
begin
    TVarData(RemoteName).VType := varOleStr;
    TVarData(RemoteName).VOleStr := StringToOleStr('RemoteServerName');
    {...the rest of the code for the FormCreate event...}    
end;

It is worth mentioning at this point that you should not be opening remote files by connecting to a remote database. Instead, remote files should be opened from the local database either through jRFS, F-pointers, mapped network drives or UNC paths. You would connect to a remote database only if you really need to have a subroutine or Execute statement actually run on the remote system.

 

Putting it all together - A Sample Unit

The following unit serves to illustrates all of the heretofore mentioned principles. The purpose of this unit is to show in context all of the principles which have been discussed. The unit illustrates how to instantiate the jBase object, connect to both local and remote databases, declare and define the OptionalParam variable (although this is not needed with Delphi 5) and a simple procedure which reads a record from the local database and populates a textbox with data from the record:

unit Unit1;

interface

uses
  {Note the inclusion of OBjEX_TLB}
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, OBjEX_TLB, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    TextBox: TEdit;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  {Declare the interfaces of the various objects we will be using}
  jB: IjBase;
  LocalDB: IjConnection;
  RemoteDB: IjConnection;
  LocalFileVar: IjEDI;
  RemoteFileVar: IjEDI;
  MyArray: IjDynArray;
  {Declare the optional parameter variable. This is not needed with Delphi 5}
  OptionalParam: OleVariant;

implementation

{$R *.DFM}

procedure TForm1.FormCreate(Sender: TObject);

var
  RemoteName: OleVariant;

begin
  {Define the name of the remote server to be used when connecting to the remote database}
  TVarData(RemoteName).VType := varOleStr;
  TVarData(RemoteName).VOleStr := StringToOleStr('vroomfondel');
  {Instantiate the jB object}
  jB := CojBase.Create;
  {Connect to the local and remote databases}
  LocalDB := jB.Connect(OptionalParam, OptionalParam);
  RemoteDB := jB.Connect(RemoteName, OptionalParam);
  {Open one file on the local database and one file on the remote database}
  LocalFileVar := LocalDB.Open('C:\Home\LocalFile');
  RemoteFileVar := RemoteDB.Open('D:\RemotePath\RemoteFile');
  RemoteName := Unassigned; {We don't need this anymore}
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  {Read a record from the local database and populate a textbox with value 4 of attribute 2}
  MyArray      := LocalFileVar.Read('123');
  TextBox.Text := MyArray.Extract(2, 4, 0);
end;

initialization
  {Define a variable to be used as an optional parameter. This is not needed with Delphi 5}
  TVarData(OptionalParam).VType := varError; {VT_ERROR}
  TVarData(OptionalParam).VError := $80020004; {DISP_E_PARAMNOTFOUND}

end.

Delphi 3

This version of Delphi is by far the most limiting in terms of the way the jBase object must be instantiated and the lack of Code Insight help you receive from the IDE. This is due to the fact that Delphi 3 only supports the COM IDispatch interface and not the dual interface that versions 4 and 5 support. There was no way in Delphi 3 to import a type library such as that supplied by OBjEX. The only way to instantiate the jBase object is to use the CreateOleObject function which resides in the ComObj unit. This is called 'late binding'.

The steps needed to interface OBjEX with Delphi 3 are:

1) Add the ComObj unit to the Uses clause in the interface section of the unit.
2) Set up OptionalParam as outlined in above.
3) Declare an OleVariant for each OBjEX object that you wish to instantiate.
4) Use the CreateOleObject method to instantiate the jBase object.
5) Connect to the local and/or remote database. This technique is the same as oulined for Delphi 4/5 above.

 

A Sample Delphi 3 Unit

The following unit illustrate this technique. Note the mandatory use of OptionalParam when using Delphi 3:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, ComObj, StdCtrls;

type
  TForm1 = class(TForm)
  Edit1: TEdit;
  Button1: TButton;
  procedure FormCreate(Sender: TObject);
  procedure Button1Click(Sender: TObject);
private
  { Private declarations }
public
  { Public declarations }
end;

var
  Form1: TForm1;
  jB: OleVariant;
  LocalDB: OleVariant;
  LocalFileVar: OleVariant;
  MyArray: OleVariant;
  OptionalParam: OleVariant;

implementation

{$R *.DFM}

procedure TForm1.FormCreate(Sender: TObject);
begin
  jB := CreateOleObject('OBjEX.jBaseObject');
  LocalDB := jB.Connect(OptionalParam, OptionalParam);
  LocalFileVar := LocalDB.Open('D:\temp');
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  MyArray := LocalFileVar.Read('123');
  Edit1.Text := MyArray.Extract(2, 4, 0);
end;

initialization
  {Define a variable to be used as an optional parameter}
  TVarData(OptionalParam).VType := varError; {VT_ERROR}
  TVarData(OptionalParam).VError := $80020004; {DISP_E_PARAMNOTFOUND}

end.


http://807199.827977/r5/knowledgebase/howto/general/windows/DelphiAndOBjEX.htm last modified on 06/19/09 05:29 AM