Building a COM or COM+ Client

About this chapter

This chapter explains how to build a PowerBuilder client that accesses a COM or COM+ server component.

About building a COM or COM+ client

A PowerBuilder application can act as a client to a COM server. The server can be built using any COM-compliant application development tool and it can run locally, on a remote computer as an in-process server, or in COM+.

Configuring a client computer to access a remote component

When a COM component is running on a remote computer, the client computer needs to be able to access its methods transparently. To do this, the client needs a local proxy DLL for the server and it needs registry entries that identify the remote server.

If the component is installed in COM+, the COM+ Component Services tool can create a Microsoft Windows Installer (MSI) file that installs an application proxy on the client computer.

If the server is not installed in COM+, the client and proxy files must be copied to the client and the server must be configured to run in a surrogate process.

Remote server name written to registry

If the COM server is moved to a different computer, the registry entries on the client must be updated.

Connecting to a COM server

To access a method associated with a component in the COM server, the PowerBuilder client connects to the component using its programmatic identifier (ProgID) or its class identifier (CLSID).

You can use a tool such as OLEVIEW or the OLE tab in the PowerBuilder Browser to view the Program ID or CLSID and methods of registered COM objects.

To establish a connection to the COM server, you need to execute the PowerScript statements required to perform these operations:

  1. Declare a variable of type OLEObject and use the Create statement to instantiate it.

  2. Connect to the object using its Program ID or CLSID.

  3. Check that the connection was established.

Example

The following script instantiates the EmpObj OLEObject object, connects to the COM object PBcom.Employee, and checks for errors:

OLEObject EmpObj
Integer li_rc
EmpObj = CREATE OLEObject
li_rc = EmpObj.ConnectToNewObject("PBcom.employee")
IF li_rc < 0 THEN
    DESTROY EmpObj
MessageBox("Connecting to COM Object Failed",  &
   "Error: " + String(li_rc))
Return
END IF

Interacting with the COM component

Invoking component methods

Once a connection to a COM component has been established, the client application can begin using the component methods.

Use the REF keyword for output parameters

You must use the REF keyword when you call a method on a COM object that has an output parameter. For example: of_add( arg1, arg2, REF sum )

Example

Using the EmpObj object created in the previous example, this example calls two methods on the component, then disconnects and destroys the instance:

Long units, time
Double  avg, ld_retn
String  ls_retn

ld_retn = EmpObj.f_calcdayavg(units, time, REF avg) 
ls_retn = EmpObj.f_teststring()

EmpObj.DisconnectObject()
DESTROY EmpObj

Passing result sets

PowerBuilder provides three system objects to handle getting result sets from components running in transaction server environments and returning result sets from PowerBuilder user objects running as transaction server components. These system objects (ResultSet, ResultSets, and ADOResultSet) are designed to simplify the conversion of transaction server result sets to and from DataStore objects and do not contain any state information.

Handling runtime errors

Runtime error information from custom class user objects executing as OLE automation objects, COM objects, or COM+ components is reported to the container holding the object as exceptions (or, for automation objects, as exceptions or facility errors). Calls to the PowerBuilder SignalError function are also reported to the container. To handle runtime errors generated by PowerBuilder objects, code the ExternalException event of the OLE client.

For more information about handling runtime errors in OLE or COM objects, see Handling errors.

Controlling transactions from a client

PowerBuilder clients can exercise explicit control of a transaction on a COM+ server by using a variable of type OleTxnObject instead of OLEObject to connect to the COM object.

Requires COM+ installation

The ConnectToNewObject call on an OleTxnObject fails if COM+ is not installed on the client computer.

The OleTxnObject object, derived from the OLEObject object, provides two additional functions (SetComplete and SetAbort) that enable the client to participate in transaction control. When the client calls SetComplete, the transaction is committed if no other participant in the transaction has called SetAbort or otherwise failed. If the client calls SetAbort, the transaction is always aborted.

Example

In this example, the clicked event on a button creates a variable of type OleTxnObject, connects to a COM object on a server, and calls some methods on the object. When all the methods have returned, the client calls SetComplete and disconnects from the object.

integer li_rc
OleTxnObject lotxn_obj

lotxn_obj = CREATE OleTxnObject
li_rc = lotxn_obj.ConnectToNewObject("pbcom.n_test")
IF li_rc <> 0 THEN
    Messagebox( "Connect Error", string(li_rc) )
    HALT
END IF

lotxn_obj.f_dowork()
lotxn_obj.f_domorework()

lotxn_obj.SetComplete()
lotxn_obj.DisconnectObject()

This f_dowork function on the COM object on the server creates an instance of the transaction context service and calls its DisableCommit method to prevent the transaction from committing prematurely between method calls. After completing some work, the function calls SetAbort if the work was not successfully completed and SetComplete if it was.

TransactionServer txninfo_one
integer li_rc

li_rc = GetContextService( "TransactionServer",  &
    txninfo_one )
txninfo_one.DisableCommit()

// do some work and return a return code
IF li_rc <> 0 THEN
    txninfo_one.SetAbort()
    return -1
ELSE
    txninfo_one.SetComplete()
    return 1
END IF

The SetComplete call on the client commits the transaction if all of the methods in the transaction called SetComplete or EnableCommit.