ComBridge allows UNIX and Linux clients to access
COM, DCOM and COM+ Automation objects residing on Windows (WIN32) systems.
Support is included for retrieving and using ADO Recordsets. ComBridge
can be embedded in CORBA wrappers facilitating CORBA/COM communication
and UNIX/Windows connectivity. The system is implmeneted as a Client-Side
library and a Server-Side WIN32 Service (or server program for WIN32 systems
that don't support services.
Contents
Keywords: COM, DCOM, COM+, Active/X,
Active/X Automation, OLE, OLE Automation, IDispatch, CORBA, UNIX, LINUX,
Connectivity, Inter Operability.
Summary: ComBridge enables
you to connect to WIN32 COM objects from UNIX or Linux systems via a simple
client library and a WIN32 service.
Server Side Components
-
ComBridge Server (ComBridgeSrv.exe
and ComBridgeService.exe)
In the full version, this is an NT service, but in the demo version
it is a standalone EXE
-
Test Com Object (ComBdgTestObj.exe)
This object is used by the client-side test
-
The ADORSproxy object (ComBdgAdoPxy.dll)
This object provides ADO recordset functionality for ComBridge Clients
-
Interactive management and test utility (UseComBridgeSrvr.exe)
This program allows the server to be tested from other WIN32 systems,
and provides some management functions and
-
This document in HTML format
No System DLLs are installed or changed on your
system.
One directory will be added to your system, C:\Program
Files\Octatec\ComBridge (by default), and all executables and documentation
will be placed in there. Further information can be found in the Server
Side Installation Guide
System Requirements
There are no special system requirements, you just need a WIN32 system
with the TCP/IP protocol stack activated. ComBridge uses the standard sockets
API for network access.
Registry Entries
The server uses several registry entries, more is
said about these in the Server Configuration section
The Server Program
There are 2 versions of the server programs supplied with the system. One
version has a User Interface (ComBridgeSrv.exe) that can be used
on WIN32 systems that don't support services, i.e. Windows95; and one version
that runs as an NT or Windows2000 service (ComBridgeService.exe).
Note: the demo download contains only ComBridgeSrv.exe. NOTE: you
do not need to run both versions of the server program.
The ComBridge service will be added to the system by the installation
program. It will not, however, be started, and it will be configured
for manual activation. To start it and/or to arrange to have the it started
automatically at system boot, you should use the services icon from
the control panel.
The Interactive version of the ComBridge server program must be started
manually, it is not added to any program group. You must find it in the
file system, using Windows Explorer, and double click it. The program
is placed in C:\Program Files\Octatec\ComBridge
by the installation procedure, however, you will have the opportunity to
chose an alternative directory. ComBridgeSrv.exe has a minimal user
interface - in order to receive incoming calls, you must take the
Start
option from the File menu, when the server is started, the
client window will turn green. If the ComBridge Service is running, you
should not try to start the ComBridge Server Program, and vice versa -
only one ComBridge server can run on a system.
The ADORSproxy Object
This is a very simple automation object. It has just one method, GetRecordset()
which allows a client to run a query on a database and obtain an IDispatch
pointer to a recordset. This pointer can easily be used by attaching it
to a RecordsetBridge object. See bellow
for the IDL definition of the object.
In order to use this object, you must already know an Ado Connection
String and a Query String. If you don't know these, the owner
of the database you wish to access will provide you with them. The Programing
Guide below shows you how to use the ADORSproxy object. This
object is just a convenience object, you could equally well create an ADO
recordset object directly, but using this object makes it simpler.
The Test Object
The ComBridge system comes with a test COM object, ComBdgTestObj.exe.
This will be automatically registered and placed in either C:\Program
Files\Octatec\ComBridge or a directory of your choosing
during installation. This object is used by the cbtest
client test program, and the
UseComBridgeSrvr
test program.
The Interactive Test Utility
The ComBridge system comes with an interactive test utility,
UseComBridgeSrvr.exe.
Again,
this is placed in either C:\Program Files\Octatec\ComBridge
or a directory of your choosing during installation. It is not added to
a menu or the desktop, so you will have to use Windows Explorer
to
locate it in the file system and double click it to start it. The menu
options are self explanatory; the mostt interesting one is the Server
Tests menu, which runs a series of tests against the localy installed
server.
Server Side Installation Guide
To install the demo server, simply download the self installing EXE and
double-click it. If you order
the full version, you will be provided with a similar self installing
EXE. The process is extremely fast and simple - it does not require a reboot,
and it does not add, or modify any system/shared DLLs
Server Side Configuration Guide
There are a few registry entries that you can modify to configure the ComBridge
Server.
Server Registry Entries
These parameters are located under the following registry key
HKEY_LOCAL_MACHINE\SOFTWARE\Octatec\ComBridge\1.00
AllowClients
This is a single string of space separated ip-addresses that are allowed
to use the server, E.G. "129.32.10.1 132.76.12.5" Note: it must
be the actual ip-address and not the hostname that appears in the string.
If you have the hostname but don't know the ip-address, use the ping command
to determine it. If you want to allow all ip-addresses to access your system,
set the string-value to a single asterisk (*). If you want
to prevent any ip-addresses from connecting, set the string-value to a
singe hash (#).
ExcludeClients
This is a single string of space separated ip-addresses that are not
allowed to use the server. If an ip-address appears in both the AllowClients
and ExcludeClients parameters, the ip-address will be excluded. If
AllowClients is set to *, clients
in the Exclude list will still be excluded.
Port
This is a string parameter that contains the port used by the ComBridge
server. By default, this is 1082. If you get "Can't Bind"
errors, it probably means the port is used by another program, so in such
cases, you should change the value of this parameter. NB, if you change
this parameter, you must remember to inform all your clients.
Logging
You can switch logging On or Off using this string-value. A value or
1
indicates ON, and 0 indicates off. The log file is written to %TEMP%\ComBridgeSrv.log.
You
should normally have logging switched off - if errors occur they will still
be recorded in the log file even with logging off. (NB this parameter is
ignored by the EXE-based server - logging is controlled from the user interface).
Client Side Components
-
ComBridge Library (libComBdg.a)
This library allows your application to use any COM or DCOM Automation
object on any WIN32 system running the ComBridge server
-
ComBridge Library C++ headers (./lib/*.h)
-
Test program (cbtest)
This test program calls methods on the test object on the server. It
is supplied in source code form.
Two directories will be added to your system ./lib and ./cbtest.
Further information can be found in the Client
Side Installation Guide. The library can be configured using
some environment variables, these are covered in the Client
Configuration section
System Requirements
There are no special system requirements, you just need a UNIX system.
ComBridge
uses the standard sockets API for network access
The Client Library And Headers
The client library is a C++ class library named libComBdg.a. It
contains the following classes.( These classes are covered in more detail
in the section dealing with the ComBridge API.)
-
ComBridge "ComBridge.h"
this class implements the actual communications link to the server
- it is the first class you will create.
-
IDispatchBridge "IDispatchBridge.h"
this class implements access to the COM/DCOM IDispatch object
-
RecordsetBridge "RecordsetBridge.h"
this class simplifies the use of ADO recordsets, and implements Bulk
Transfer of records to improve performance
-
_Variant "Sarray.h"
this class acts as a holder for the various types that can be accepted
by ActiveX Automation objects
-
Sarray "Sarray.h"
this class implements an array which can be sent to or received from
IDispatch objects
-
_DateTime "DateTime.h"
this class encapsulates the DATE type used by ActiveX Automation, it
provides a great deal of functionality, and is a useful class in its own
right
-
_Currency "Currency.h"
this class holds a CURRENCY ActiveX Automation, type, it provides
no other functionality other than the data it contains.
The make_app shell script utility that builds the cbtest
program shows how to link in libComBdg.a for your version of UNIX.
The cbtest Test Program
Usage: cbtest hostname
[port]
This program creates a ComBridge to the named host and calls some internal
data transfer test functions. It then creates the Test
Object and calls methods on it.
The source code is supplied with the installation and provides a detailed
example of how all data types can be passed and received. Included in the
tests are calls to object methods that return ADO recordsets. To build
cbtest,
cd
to the cbtest sub directory which will be created after you have
installed the ComBridge client package, and type
make_app.
Inside cbtest
Main.C processes the command line and calls the TestDataTypes()
function
that calls functions that test ComBridge's low level data transfer methods,
and then tests ComBridge's higher level methods by using the test
object. The test methods are all contained in DataTests.C. The functions
that will be of most interest to the programer, and demonstrate the API
are...
-
OnCallObject1();
-
OnBigStringTest();
-
OnTestArrayString();
-
OnTestObjSimpleVar();
-
OnTestObjectMDimArray();
-
OnTestObject3dArray();
-
OnTestObject4dArray();
-
OnDateTest();
-
OnDateArrayTest();
-
OnCyTest();
-
OnCyArrayTest();
-
OnTestDblArray();
-
OnTestReturnIdispatch();
-
OnAdoRecordSetTest();
-
OnAdoBulkTest();
The functions are named so as to describe the tests they perform, the OnCallObject1()
function performs general tests and is a good place to start.
Client Side Installation Guide
The client side installation is downloaded as a Compressed tar file,
ComBdg.tar.Z..
You simply uncompress it and extract the files. You can do this in any
directory. Then you just build the test program,
cbtest, and run
it. The following commands are all you need...
$ uncompress ComBdg.tar.Z
NB the name
of your tar file will be different, depending on the Unix/Linux version
you have downloaded
$ tar xvf ComBdg.tar
$ cd cbtest
$ ./make_app
NB: you may find the name
of the Compiler in this script is not the same as the one on your system,
this is quite likely on Linux systems, the compiler in the script is CC,
whereas you may find it is g++ on your system.
$ ./cbtest $WIN32_SERVER
You must have already setup the ComBridge server on a WIN32 system
in order to run cbtest successfully. In the above example $WIN32_SERVER
is
the hostname or IP-Address of the system where the ComBridge server
is loacated..
Client Side Configuration Guide
There are a few environment variables that you can set to configure the
behaviour of the ComBridge Client Library.
$COM_BRIDGE_PORT
The default port used to connect to the server is 1082. This can be
changed by setting this environment variable. The programmer can override
this functionality by explicitly setting a port in the code.
$COM_BRIDGE_LOGGING
If this environment variable is set to "1", the ComBridge Client
Library will write logging information to /tmp/ComBridgeClient.log.
Even if this is set to "0", errors are still recorder in the log file.
$COM_BRIDGE_LOG_FILE
The log file can be changed from the default by setting this environment
variable. The length of the log file name must be less than 64 characters.
The programmer can override this functionality by explicitly setting a
log file name in the code
Client-Side Programing
Guide
Introduction to ActiveX Automation
ActiveX Automation Objects are objects that implement
the IDispatch interface. Basically an Automation object has a
list of methods, each identified by a unique number. To call a method you
pass the object the methods number and a list of arguments, you then get
back a return value and any return arguments provided by the method. Automation
objects are usually described by an ODL (object definition language) or
IDL (interface definition language) file, which is very similar to a C++
header.
A word about CORBA...
ComBridge is not a CORBA implementation but it could be used to allow
CORBA objects to call ActiveX Automation objects, i.e. it could be used
to implement CORBA wrappers for ActiveX Automation objects - simply write
a CORBA object with the desired methods, and embed calls to ComBridge within
the body of the CORBA methods.
ComBridge API
The ComBridge API has been designed to be very easy
to use. In order to connect to a remote COM object, you simply create a
ComBridge
to
the server system as follows
char *hostname = "some-win32-host";
ComBridge comBridge;
if( !comBridge.Connect(hostname) )
// ...report error...
Then to access a COM Automation object on the server,
you create an IDispatchBridge to the object, using the ComBridge
object already created.
IDispatchBridge object(&comBridge);
char *objectName = "ComBridgeTest";
object.Create(objectName);
Then you 'prepare' the method you are going to use.
In order to do this, and latter steps, you will need the ODL (or IDL) of
the object you are going to use. The following is an extract for the ComBridgeTest's
ODL.
[id(2)] BSTR ToUpper(BSTR str)
Using the method id (2) we can 'prepare' the method
(the ToUpper method takes an input string and converts
it to upper case and returns it)
Then we 'push' all the arguments. (NB: BSTR
is
equivalent to char*, see the section about Automation
Types for more information). NOTE: it is your responsibility to ensure
that the parameters you push are the correct type and are in the correct
order. If they are not you will get and error return from the Invoke()
method. [NOTE: Arguments can be input/output, in which case the address
of the variable is passed in, or input only in which case the variable
itself is passed in. input/output variables will change value after Invoke()
has been called and all pointers to non-simple types (e.g. pointer to strings,
i.e. char**) must be deleted after use - if you just pass in a char* you
don't need to deleted it (at least, not as a result of passing it to an
IDispatchBridge
method ) unless, that is, you passed it to the Invoke method
which takes a reference as an argument. (you will, of course, need to delete
any object you previously new'd). The important point is: complex output
parameters and return parameters are allocated by ComBridge and must be
deleted by you if your program isn't to leak memory,
char *input = "to-upper";
object.PushArg(input);
Once all the arguments have been pushed, the method
can be invoked
char *returnValue = NULL;
object.Invoke(returnValue);
//... use returnValue ...
delete [] returnValue;
NB: it is the callers responsibility to delete strings
that have been returned by IDispatchBridge methods.
A more complex example is the TestByRef method.
This method takes 3 input/output parameters. (NOTE: IDL files will usually
contain the 'direction' of the parameter in square brackets, whereas ODL
files do not). The method appends the string "+StringByRef" to the input
string, it adds 9999.99 to the input double parameter and 1000 to the input
long parameter. The ODL description of the method is...
[id(5)] long TestByRef(BSTR* pBstr, double*
pDBl, long* pLong);
The method is called as follows
object.PrepareMethod(5);
char *s = "String";
object.PushArg(&s); // note it is
&s that is passed because the ODL uses BSTR*
double d = 0.0;
object.PushArg(&d);
object.PushArg(&l);
long returnValue;
object.Invoke(returnValue);
// ... the addresses passed into the PushArg
method will now contain the new values
// ... NB: if the input char pointer had
been new'd, you would have to take care since
// ... the output pointer s will point
to a different location and you run the danger of
// ... leaking memory
delete [] s; // you must delete
pointers returned by IDispatchBridge methods
There is a fair degree of scope for errors in passing
the wrong type, and to reduce this, a code generator that reads IDL and
ODL files and produce IDispatchBridge wrapper classes is planed
for the near future.
Now we will look at methods that actually return
objects from the Server. The following method in the test object returns
an IDispatch pointer in an output parameter...
[id(22)] long GetDispTestAsParam(IDispatch**
lpDisp);
Whenever you see a method that returns an IDispatch pointer as
either a parameter or a return value, you should pass in a NULL initialized
pointer to an IDispatchBridge object, E.G.
object.PrepareMethod(22);
IDispatchBridge *pdisp = NULL;
object.PushArg(&pdisp);
long result;
object.Invoke(result);
// pdisp will now point to an IDispatchBridge object that you can
use, and then must delete
delete pdisp;
Another example receives an object pointer as a return value...
[id(20)] IDispatch* GetDispTestAsReturn(long* result);
object.PrepareMethod(22);
long result;
object.PushArg(&result);
IDispatchBridge *pdisp = NULL;
object.Invole(pdisp);
// ... call methods on pdisp...
delete pdisp;
The final example presented here receives an ADO recordset pointer. An
ADO recordset is just an IDispatch object with a set of well known
methods.
[id(21)] long GetAdoRecordset(BSTR database, BSTR query,
IDispatch** lpRecordset);
object.PrepareMethod(21);
char *database = "unused-paramter";
object.PushArg(database);
char *query = "unused-parameter";
object.PushArg(query);
IDispatchBridge *pRecordset=NULL;
object.PushArg(&pResordset);
long result;
object.Invoke(result);
//...use the recordset...
(You are probably wondering about the unused parameters. In a previous
version of the test object, a database and a sql-query-string were required.
However, there was a problem with this - You might not know the name of
a database (or even have access to one) when you run the test. Now, the
test object 'manufactures' a standard ADO recordset and returns it, ignoring
the database and query parameters. Of course, this
behaviour is specific to the test object, and if you want to use ADO recordsets
for real, you will have to know a database name and a sql-query-string.)
You may call all the methods on the ADO recordset by using PushArg and
Invoke, however, there is a wrapper class (RecordsetBridge) which
makes the use of ADO recordsets easier and faster.
RecordsetBridge adoRS(pResordset);
adoRS.InitializeBulkFetch(); // improve speed of data access
long n = adoRS.GetCount();
for(int i=0; i<n; i++)
{
adoRS.GetNextRow();
long columnOne;
adoRS.GetColum("NameOfFirstColumn", columnOne);
// read the columns
by name into variables - you
// must know the correct
column type - if you do not
// you can pass in a
variant...
_Variant v;
adoRS.GetColumn("NameOfSecondColumn", v);
// if you don't know
the name of the column you
// can pass in a position
adoRS.GetColumn(3, v);
}
// because we passed the pResordset pointer to a RecordsetBridge
// we do NOT have to delete it, the RecordsetBridge will delete
// it in its destructor
The source code of cbtest
is included as a programing example. The above extracts are taken from
cbtest.
Note: in the above examples the return values are not tested; in practice
they should be tested, a value of 0 indicates success.
The ADORSproxy Object
This object is an In-Processes Automation Object that exists on the server.
It is used to obtain ADO Recordsets from the Server. The ODL for the ADORSproxy
looks like...
[id(1)] IDispatch* OpenRecordset(BSTR query, BSTR connectionString,
long openFlag, long lockFlag, long optionFlag, boolean disconnectedMode);
[id(2)] long GetLastError();
It is used as follows...
char *hostname = "some-win32-host";
ComBridge comBridge(hostname);
comBridge.Connect(hostname);
IDispatchBridge ado_rs_proxy(&comBridge);
if( ado_rs_proxy.Create("ADORSproxy") !=
0 )
// report error
ado_rs_proxy.PrepareMethod(1);
char *query = "some_sql_query";
char *connection = "DSN=???;UID=???;PWD=???";
long openFlag = -1;
long lockFlag = -1;
long optionFlag = -1;
long disconnected = 1; // TRUE
ado_rs_proxy.PushArg(query);
ado_rs_proxy.PushArg(connection);
ado_rs_proxy.PushArg(openFlag);
ado_rs_proxy.PushArg(lockFlag);
ado_rs_proxy.PushArg(optionFlag);
ado_rs_proxy.PushArg(disconnected);
IDispatchBridge *prs = NULL;
if( ado_rs_proxy.Invoke(prs) != 0 )
// report error
RecordsetBridge adoRS(prs);
adoRS.InitializeBulkFetch(); // improve speed of data access
long n = adoRS.GetCount();
for(int i=0; i<n; i++)
{
adoRS.GetNextRow();
...
}
Automation Data Types
Only a limited number of data types can be passed to an Automation Object's
methods, however this limitation is rarely a problem. The following data
types are supported
Simple Types
long |
short |
double |
long* |
short* |
double * |
Complex Types
ComBridge API Classes
Link to: libComBdg.a
#include <ComBridge.h>
This class is used to set up the connection to the remote WIN32 system.
ComBridge()
Default constructor
bool Connect(char *host=NULL, int port=0)
Connect to the named host using the specified port. If the port is
0, the default ComBridge port (1082) is used, however if $COM_BRIDGE_PORT
is set, and the input port is 0, the value of $COM_BRIDGE_PORT
will be used. The method returns true if successful.
void Disconnect()
Disconnect the current connection
int GetErrno()
If an error has occurred, this method returns the error number
bool IsConnected()
Return true if the object is connected
static void SetLogfileName(const char *name)
You can use this to specify the log file written to by the library.
If you use this method, the environment variable $COM_BRIDGE_LOG_FILE
will
be ignored.
static void SetLoggingOn(bool mode)
You can use this to programmatically set logging on (mode=true) or
off (mode=false). This will override the shell variable that normally controls
logging, $COM_BRIDGE_LOGGING
will be ignored.
~ComBridge()
The destructor will close any open connection
#include <IDispatchBridge.h>
This is the most important class. It allows you to create an ActiveX
Automation Object on a WIN32 system. pass it parameters and call methods
on it. All methods that return int, will return 0 on success, and a COM
error code on failure. A NULL-initialized IDispatchBridge pointer can be
passed to methods that are defined as taking an LPDISPATCH* (or IDispatch**)
in the ODL/IDL - if this is done you must delete the returned IDispatchBridge
pointer yourself.
IDispatchBridge(ComBridge *pServer)
Constructor - IDispatchBridge objects are created by passing them a
pointer to an already connected ComBridge object. At this point no Automation
object is created, you must use the Create() method to do that.
int Create(char *clsID)
Create the object on the remote system. You need to know it's class-id
or class name to do this. In the case of the ComBridge test object, it's
name is ComBridgeTest. The method returns 0 on success, otherwise
a COM error code is returned.
int PrepareMethod(long dispID)
Once you have created an object, you are ready to call methods on it.
To do this you must 'prepare' a method - call PrepareMethod() with the
methods DISPID. You will get the DISPID from the ODL or IDL file that describes
the object. In order to successfully call an Automation Object you will
need to see its IDL or ODL file.
int PushArg(TYPE value)
Once a method has been prepared, you can pass it arguments. You do
this by calling PushArg repeatedly with all the arguments that the method
requires. It is the programers responsibility to pass the correct arguments
in the correct order. The TYPE in the methods argument list represents
one of the valid Automation types, these are: long,
short, double, string(char*), _LPDISPATCH*, DATE, Variant, _Currency
int PushArg(TYPE *value)
Instead of passing the argument by value, you can pass it by reference.
You should do this if the ODL/IDL specifies the argument is a pointer.
This is usually done if the method is expected to change the value of the
parameter, i.e. it is an output parameter. The TYPE in the methods
argument list represents the the same Automation Types listed above, with
the addition of IDispatchBridge - you may receive objects in output parameters
but you cannot pass an object to an Automation Method. Note: if the
TYPE is a string(char **), or an IDispatchBridge** the pointer MUST be
initialized, and in the case of IDispatchBridge** it must be initialized
to NULL. The returned object must be deleted after use if your program
isn't to leak memory.
int Invoke(TYPE &returnValue)
Once You have pushed all the arguments you can invoke the method. To
do that call Invoke. You must know the correct return type of the method,
and pass a suitable variable to receive the value. If the method has no
return type, don't pass anything. The type of the returnValue is specified
if the IDL or ODL. It is slightly different in ODL files to IDL files.
In ODL files it will specified just as in a standard C++ method definition
However in an IDL file, all methods will be defined as returning an HRESULT
(Error Code), the actual return value is specified as an output parameter
with a description of [retval,out] immediately preceding
it - such return values in IDL files will always be specified as pointers,
but when you call Invoke, you don't pass a pointer, unless the IDL files
specifies a pointer-to-a-pointer. Note: once Invoke has returned any arguments
'passed-by-value' will automatically have been updated with their new values.
If you pass in references to char* or IDispatchBridge* the returned pointer
must be deleted after use.
int GetProperty(TYPE &returnValue)
In some circumstances, you will not call Invoke, but rather GetProperty().
This is the case when you want the value of a property. You will know to
call GetProperty because the method will be prefixed with [propget] in
the IDL or ODL file.
int PutProperty()
In other cases, i.e. when you are setting a property of an object,
you will cal PutProperty instead of Invoke. You will know that you must
cal this method if the OLD or IDL file prefixes the method name with [propput].
If you call Invoke() for a method that you know exists, and you
get an error return (i.e. something other than 0) and you are sure the
DISPID and parameters are correct, it may be that the method is implementing
a property, in which case you will need to call PropertyGet() or PropertyPut()
- normally PropertyPut() methods will only require one input argument and
have no return value, while PropertyGet() methods will not have any input
arguments and have a return value.
int Release()
Release (i.e. destroy) the remote object - you don't need to call this
method, it is automatically called in the destructor.
~IDispatchBridge()
The automation object on the remote system is automatically released
when the IDispatchBridge is destroyed.
#include <RecordsetBridge.h>
This class wraps up the ADO recordset class, making it easier to use.
ADO recordset are the 'modern' way of receiving data from databases. They
are returned in the form of IDispatchBridge objects from WIN32 COM Automation
Objects. As such, you can call all the methods on the object directly using
IDispatchBridge methods, and do not need to use a RecordsetBridge at all.
However, using a recordset bridge makes things much easier, and also improves
performance with a ''bulk fetch'' option.
RecordsetBridge()
The default constructor - after construction an object it this way,
you must call the Attach() method
RecordsetBridge(IDispatchBridge *pADOdisp, bool takeOwnership=true)
This is an alternative way to construct a RecordSet bridge object.
The pADOdisp parameter is an IDispatchBridge object returned
by an Automation Object. If the takeOwnership parameter
is true, the pADOdisp pointer is deleted in the RecordsetBridge destructor.
void Attach(IDispatchBridge *pADOdisp, bool takeOwnership=true)
If the default constructor is used, you must call this method to attach
an ADOrecordset object to the RecordsetBridge.
bool GetNextRow()
Once the RecordsetBridge object has been attached to an ADOrecordset,
you can begin iterating the records in the recordset. To do this, you repeatedly
call this method until it returns false. Note: you should
call this method before you try to access the first record.
bool GetColumn(const char *name, TYPE &value)
To access column-values in the record, call this method. TYPE
can be one of long, double, char*, _DateTime
or _Variant.
If you don't know the type of the
data or if it is not one of long,
double, char*
or
_DateTime, use the _Variant type. If the type
is wrong or if the value is database-NULL, the method will return false
- to test for database NULL, call ColumnIsNull() after GetColumn()
returns false.
bool GetColumnAt(long pos, TYPE &value)
This method provides a way to access columns by position rather than
by name, apart from that it is the same as the GetColumn() method.
bool ColumnIsNull()
This method returns true is the last column whose value you tried to
retrieve was database-NULL.
long GetLastError()
If any method fails, this will return the last COM error code.
bool InitializeBulkFetch(long rowsPerBlock = -1)
You can call this method immediately after attaching a recordset to
the bridge in order to improve performance. As its name suggests, the method
will arrange for records to be fetched in bulk from the server, thus
reducing network calls. The GetNextRow(), GetColumnm() and
GetColumnAt()
methods work in just the same way whether or not bulk fetch has been initialized.
If rowsPerBlock is -1, the whole recordset will be fetched
in one network request. You can set rowsPerBlock to any
value.
long GetRecordCount()
This method will return the number of records in the recordset. However,
it is not guaranteed to work, it may return -1 depending on the type of
recordset you actually have. There are many types of ADOrecordset; if the
type is 'disconnected' the GetRecordCount() method will work, otherwise
it will return -1. NOT: if the record count is not available, InitializeBulkFetch()
will set the rowsPerBlock to 100 if it is called with rowsPerBlock
set
to -1.
~RecordsetBridge()
The destructor will delete the IDispatchBridge to which it was attached
if the takeOwnership parameter in the Constructor
or in the Attach() method was true.
#include <Sarray.h>
The Sarray class is used to transfer arrays of data to Automation Objects.
In practice it is never used on its own, it is always contained within
a _Variant. The ComBridge's implementation of the Sarray limits
it to 4 dimensions. The Sarray is limited to the following automation data
types: long, short,double,_Variant,_Date, _Currency.
The type is indicated by the _VariantType Enumeration found in Sarray.h.
Use
Sarray whenever a VARIANT containing a SAFEARRAY is specified
Sarray()
The default constructor. If you construct an Sarray in this way, you
will have to use the Init() method to set its size and type.
Sarray(unsigned char type, unsigned char numberOfDimensions,
SarrayBound *pbounds)
This method creates an array of the given type, with the specified
number of dimensions. The upper and lower bound of each dimension is specified
by the array of SarrayBounds structures, these structures have the members
unsigned
long m_lowerBound and unsigned long m_size;
usually m_lowerBound will be 0, but it need not be. As
in all methods that take a type parameter, it must be one
of _VT_LONG, _VT_SHORT, _VT_CY, _VT_DOUBLE, _VT_DATE, _VT_STRING,
_VT_VARIANT.
Sarray(unsigned char type, unsigned char numberOfDimensions,
int *sizes)
This version of the constructor provides a slightly simpler way of
creating an Sarray object, in that it assumes all lower bounds are 0, and
then just needs an array of integer sizes for each dimension.
Sarray(const Sarray &rhs)
The copy constructor
Sarray &operator = (const Sarray &rhs)
The assignment operator
bool Init(unsigned char type, unsigned char numberOfDimensions,
SarrayBound *pbounds)
This method provides a way to create an Sarray after it has been constructed.
bool Init(unsigned char type, unsigned char numberOfDimensions,
int *sizes)
This method provides a simpler way to create an Sarray after it has
been constructed, assuming all dimensions lower bounds are 0.
void *GetAt(int *pIndices)
This method provides a way to access elements of an array. You should
cast the returned pointer the desired type. The pIndices parameter
points to an integer array specifying the indices of the element to set.
bool SetAt(int *pIndices, void *pdata);
This method provides a way to set elements of an array. You should
cast the input pdata address to void*. The pIndices
parameter points to an integer array specifying the indices of the element
to set.
const SarrayBound *GetDimensions() const
This method returns the SarrayBounds structure that defines the bounds
of each dimension.
unsigned char GetNumberOfDimensions() const
Get the number of dimensions
unsigned char GetType() const
Get the type of the array, the return value is one of the _VariantType
enumeration values .
unsigned long GetSize() const
Get the total number of elements in the array.
Empty()
Free any memory, and set the type of the array to _VT_EMPTY.
There are many examples of using the Sarray and _Variant classes in
the cbtest source code, included in the client distribution.
#include <Sarray.h>
This type is used to pass data and a description of the data, i.e. its
type. To use a _Variant you must assign the
m_type member to one of the _VariantType enumeration
values. You then assign one of the following members, depending on the
type. USe this type whenever you see VARIANT specified in the ODL/IDL file.
long
m_l
long
*m_pl
short
m_i
short
*m_pi
double
m_d /* also DATE */
double
*m_pd /* also DATE * */
char
*m_s
char
**m_ps
_Currency
m_cy
_Currency *m_pcy
Sarray
m_a
Sarray
*m_pa
IDispatchBridge *m_pdisp
_Variant& operator = (const _Variant &rhs)
The assignment operator
~_Variant
The destructor, it will automatically free any memory allocated.
#include <Sarray.h>
This is simply a char* (or char** for a pointer to a string). Use _Bstr
whenever the ODL/IDL specifies BSTR and user _Bstr* whenever the
OLD/IDL specifies BSTR*. It is important to understand that if you pass
a pointer to a char* to a method to receive an output value or receive
a char* as a return value (i.e. a char* parameter to the Invoke method),
the char * pointer will have been newly allocated when the method returns
and must be deleted by you when you no longer need it. It follows from
this that if you allocate a char* on the heap, and then pass its address
to an IDispatchBridge method, the pointer will come back pointing at a
different location, and you will leak the memory that the pointer originally
pointed to unless you make another copy of the pointer before you pass
its address to IDispatchBridge.
#include <DateTime.h>
The _DateTime class is used transfer DATE information between
Automation objects. It has many members that facility its use. The public
member m_date is the only state information held by a _DateTime
object, this is a double precision value, and it is that value that is
actually passed to the Automation object. The header defines DATE
to be a double. The _DateTime type is basically
a wrapper for an OLE DATE which is a double precision floating point number,
the fractional part represents the time of day, and the whole part represents
the number of days. Dates start from 1/1/100 AD, and the value of
this date is -657434. Jan 1st 1900 is 2.0, Dec 30 1899
is 0, Dec 31st 1899 is 1.0. Use this type whenever the ODL/IDL specifies
the DATE type. The _DateTime class wraps up the double precision date and
provides a variety of useful access/assignment/arithmetic methods, making
it a useful class in its own right.
_DateTime();
_DateTime(const DATE dDate);
_DateTime(const _DateTime &rhs);
_DateTime(const struct tm *tmIn, const short nMs=0);
_DateTime(const time_t tTime);
_DateTime(const char* szDate, const bool fUsMode=false);
Constructors. Note the string szDate is interpreted
as "MM/DD/YYYY HH:MM:SS" or "DD/MM/YYYY HH:MM:SS" is
fUsMode=true.
operator==(const _DateTime &rhs) const
operator> (const _DateTime &rhs) const
operator< (const _DateTime &rhs) const
operator>=(const _DateTime &rhs) const
operator<=(const _DateTime &rhs) const
Logical operators.
short GetHour()const
void SetHour(short nHour) void
SetMonth(const char* szMonth);
short GetMinute()const
void SetMinute(short nMin)
short GetSecond()const
void SetSecond(short nSec)
short GetDay()conts
void SetDay(short nDay)
short GetMonth()const
void SetMonth(short nMon)
short GetYear()const
void SetYear(short nYear)
short GetMilliSecond()const
void SetMilliSecond(short nMs)
short GetJulian() const
void SetJulian(short nDays, short nYear=0)
Accsessor methods. NB: the SetJulian() method assumes the current
year unless the nYear parameters is specified.
_DateTime& AddDay(long nDay=1);
_DateTime& AddHour(double nHour=1.0);
_DateTime& AddMinute(double nMinute=1.0);
_DateTime& AddSecond(double nSec=1.0);
_DateTime& AddMilliSecond(double nMili=1.0);
_DateTime& AddYear(short nYears=1);
_DateTime& AddMonth(short nMonths=1);
Arithmetic methods
bool IsLeapYear(long year=0)
If year is unspecified, the year in the current object is used, otherwise
the specified year is used.
const char* Format(char *usrBuff, char cFmt=0) const
Formatting method, the cFmt can be one of
FMT_UK_MS : |
MM/DD/YYYY HH:MM:SS.mmm |
FMT_US_MS : |
DD/HH/YYYY HH:MM:SS.mmm |
FMT_UK : |
MM/DD/YYYY HH:MM:SS |
FMT_US : |
DD/HH/YYYY HH:MM:SS.mmm |
FMT_US_DATE : |
MM/DD/YYYY |
FMT_UK_DATE : |
DD/MM/YYYY |
FMT_STRING : |
DD MMM YYYY HH:MM:SS |
FMT_TIME : |
HH:MM:SS |
FMT_STRING_MS : |
DD MMM YYYY HH:MM:SS:mmm |
FMT_TIME_MS : |
HH:MM:SS:mmm |
FMT_STRING_DATE : |
DD MMM YYYY |
FMT_ODBC : |
YYYYMMDD |
The user must ensure the buffer is large enough to take the formatted
string.
struct tm GetAsTmStruct()
Get a tm stuct from a _DateTime object.
#include <Currency.h>
Use this type whenever the ODL/IDL specifies the CURRENCY or CY type.
This is a structure containing 2 longs. This type can be passed and received,
but there is no additional support for it, and if you use it you will have
to program such things as formatting and arithmetic yourself. This will
be considerably easier if your compiler supports 64 bit integers. |