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