Chapter 20 Creating ActiveX Clients


Develop and test the ActiveX client

To write and test code for your ActiveX client, you must be connected to a Jaguar server (or have the Jaguar server running on your machine) and have the ActiveX runtime files installed on your machine. To install the ActiveX runtime files, see "Deploy the ActiveX client"; if you install the Jaguar server on your machine, you have the option to install the ActiveX runtime files as well. For more information, see the Enterprise Application Server Installation Guide for Windows or the Enterprise Application Studio Installation Guide for Windows.

Before invoking methods on component instances, the client must connect to a Jaguar server and instantiate the components. There are two techniques for proxy instantiation:

If you currently have ActiveX proxy automation server clients, Sybase recommends that you migrate you current ActiveX clients to use the CORBA-style so that you can take advantage of the new benefits. The following features are available to CORBA style clients and not to Jaguar 1.1 style clients:

The ORB, SessionManager, and other CORBA-style interfaces are documented in Chapter 4, "ActiveX Client Interfaces" in the Jaguar CTS API Reference.

Instantiating proxies using CORBA-style interfaces

Proxies are local objects that allow you to call Jaguar component methods as if the component were a local object in your program. Instantiate proxies using the Jaguar ORB and SessionManager::Manager interfaces, as follows:

Step

What it does

Detailed explanation

1

Initialize the CORBA ORB and create an ORB reference.

"Initializing the ORB"

2

Use the ORB reference to create a Manager instance for the Jaguar server.

"Creating a Manager instance"

3

Use the Manager instance to create a Session.

"Creating sessions"

4

Use the Session instance to create stub component instances.

"Creating stub instances"

5

Call the stub methods to remotely invoke component methods.

"Invoke component methods"

Note   If you are using Visual Basic, before using the ORB, Session, Factory, and Manager objects in your client, create references to JaguarORB.tlb, SessionManager.tlb and CtsSecurity.tlb in your Visual Basic project using the standard Visual Basic mechanism.

Initializing the ORB

Before any ORB classes can be used, you must call the init method, which:

Initialization parameters

The ORB.init() method acceps a formatted string that can contain settings for multiple initialization parameters. Pass initialization parameters as shown in this example, which configures the -ORBlogFile property and the -ORBpin property, to specify a file name for logging errors and the Sybase SSL-certificate-database password, respectively:

orb.init("-ORBlogFile=d:\jagorb.log,-ORBpin=sybase")
As shown in the example, parameter names and values must be separated by an equals sign, '=', and each name/value pair must be separated from the next with a comma and no white space.

For each initialization parameter, there is an equivalent environment variable. If the environment variable and initialization parameter are set, the value of the initialization parameter is used. Parameter and environment variable names are the same as for the C++ client ORB (see Chapter 17, "Creating CORBA C++ Clients").

You can set any initialization parameter to a value of none, which overrides the value of the environment variable and sets the value to the default, if any.

You can pass the following initialization parameters to the driver class:

Example: ORB initialization

ORB initialization is demonstrated in the following example.

Dim orb As ORB
Dim Manager As Manager
Dim Session As Session
Dim Factory As Factory

' Create a new ORB object
Set orb = New ORB

' Initialize the ORB instance
orb.init ("")

init returns an object reference to the Jaguar ORB. When orb is deallocated or assigned a new object reference, it will be automatically released.

Creating a Manager instance

The SessionManager::Manager interface is used for interacting with a Jaguar server. To create a Manager instance, you must identify a server listener using a URL of the format:

protocol://host:port

where:

Pass the URL to the string_to_object method to convert the URL string into a Manager instance, as shown in the following example. The object returned by string_to_object must be narrowed to the SessionManager/Manager interface.

Dim orb As ORB
Dim Manager As Manager
Dim obj as Object
... deleted orb initialization ...
Set obj = orb.string_to_object(
"iiop://puddle:9000")
Set Manager = obj.Narrow_("SessionManager/Manager")
...

Creating sessions

The SessionManager::Session interface represents an authenticated session between the client application and a Jaguar server. The createSession method accepts a user name and password and returns a session object, as shown in the example below:

Dim orb As ORB
Dim Manager As Manager
Dim Session as Session
Dim obj as Object
...deleted manager initialization
Set obj = Manager.createSession("jagadmin","")
Set Session = obj.Narrow_("SessionManager/Session")
...

Creating stub instances

You call the Session.lookup method to return an object reference factory. You then use the factory to create one or more proxies for the component.

lookup takes a string that specifies the Jaguar component name. By default, the name is package/component, where package is the Jaguar Manager package name and component is the component name. Package and component names are not case sensitive. Component developers can override the default name by setting the Bean Name property for EJB components, or the com.sybase.jaguar.component.bind.naming property for other types of components.

lookup returns a CORBA::Object reference. You use Narrow_ to convert the object reference into an instance of the factory for the component.

After instantiating the factory, the factory Create method returns an instance of the component proxy.

The code to instantiate a proxy for a component named Foo/Bar looks like this:

Dim Session as Session
Dim fact as Factory
Dim barComp as Bar // Component proxy
Dim obj as Object
...deleted session initialization ...
Set obj = Session.lookup("Foo/Bar")
Set fact = obj.Narrow_("SessionManager/Factory")
Set barComp = fact.Create()

Instantiating stub instances using the Jaguar 1.1 interface

Sybase recommends that you use the CORBA style interfaces for new development. The Jaguar 1.1 interface is provided for backward compatibility with existing applications.

To invoke Jaguar components, your ActiveX client should:

  1. Declare proxy objects - The application creates an ActiveX interface pointer for the proxy object.
  2. Set connection properties - The application sets connection properties for the component instance. These properties describe the Jaguar server that contains the component and the user name to be used for a connection.
  3. Instantiate server components - The application calls the proxy object's Initialize method. Initialize connects to the server and creates an instance of the server component. After Initialize succeeds, the server component methods can be called through the proxy object.
  4. Invoke component methods - The application invokes methods on the Jaguar server, passing the appropriate ActiveX datatype for each parameter.

Declare proxy objects

Proxy objects are instantiated and invoked via ActiveX dispatch interfaces. Jaguar proxy objects can be identified by their program identifier (PROGID). See "Check the PROGID for each interface" for more information.

Different ActiveX-enabled IDEs have different mechanisms for declaring an ActiveX object. In Visual Basic, you can simply declare the proxy object and instantiate it. For example, you can write either one of the following to instantiate a proxy object:

Dim bar as Bar
Set bar = New Bar
or
Dim bar as Object
Set bar = CreateObject("Foo.Bar")

Although the ActiveX proxy object exists once you have declared it, you cannot invoke methods until after you have set connection properties and called the Initialize method.

Set connection properties

Before calling the Initialize method, set the connection properties, such as UserName , Password , Host , and Name . The ActiveX client uses connection properties to connect to the Jaguar server. This example sets the connection information for the employeeproxy object.

employeeproxy.UserName = "Guest"
employeeproxy.Password = "Guest"
employeeproxy.Host = "Jaguar"
employeeproxy.Name = "Company/Employee"

The user name and password, which must be specified, are required for login authentication and access control. The defaults for user name and password are empty strings. If the Jaguar server administrator has enabled authentication, you must use a valid user name and password. If user access to the package or component is limited, the user name must be in a group that has access to the component. For more information on security, see "Security Configuration" in Jaguar CTS Administration Guide.

The Host property, which is optional, is the machine name and IIOP port number or the environment variable that specifies the machine name and IIOP port number. If the machine name and IIOP port number are specified for the Host property, the environment variable is ignored. See "Deploy the ActiveX client" for more information about defining the environment variable.

The syntax for specifying the machine name and IIOP port number is:

"machine:port"

where:

machine is the machine name.

port is the IIOP port number.

Note   If the Host property or environment variable is not specified, or defined incorrectly, the default, which is "localhost:9000", is used.

The Name property, which is optional, specifies the package and component names. By default, the package name is the same as the module name, and the component name is the same as the interface name. Specify the Name property when a component's package or component name is different from its module or interface name. The package and component are automatically located relative to the Jaguar server's Initial Context property. The syntax for the Name property is:

"package/component"

where:

Instantiate server components

To instantiate the components on the Jaguar server, use the Initialize() method. Initialize() establishes a connection to the Jaguar server, using the connection properties you set in the previous step. If the Jaguar server host name is not valid, or if another error occurs, the APAS displays an error message. This example executes the Initialize() method on the employeeproxy object, and instantiates on the Jaguar server an instance of the Employee component belonging to the Company package.

employeeproxy.Initialize()

Invoke component methods

"ActiveX datatype support" lists the ActiveX types supported by Jaguar, as well as the equivalent Jaguar Manager and CORBA IDL types.

Jaguar components appear as automation objects in the ActiveX-enabled IDE. If your IDE supports it, you can simply drag and drop the component method into your ActiveX client code and use the IDE's object browser to see the component's method syntax. You must call the proxy methods using the syntax required by your development tool.

To execute a component method, execute the method on the proxy object. In this example, the GetEmployeeInfo() and the SetEmployeeInfo() methods are executed on employeeproxy . The parameters in the SetEmployeeInfo() method are in parameters. The parameters in the GetEmployeeInfo() method are inout parameters.

String name
Long age
String sex

name = "John"
age = 32
sex = "male"

// Example for parameters using the in argument mode
employeeproxy.SetEmployeeInfo (name, age, sex)

// Example for parameters using the inout argument mode
employeeproxy.GetEmployeeInfo (REF name, REF age, REF sex)

Methods may return result sets. After a method invocation, you can retrieve result sets as described in "Result set support".

Note   If a component that the ActiveX client accesses is an ActiveX component and a C++ IDE such as Visual C++ was used to develop it, string parameter types are always passed by reference (as BSTR *). Make sure that you defined these parameters as inout in Jaguar Manager.

When you invoke component methods, these restrictions apply:

Code exception handling

Always make sure that your application handles exceptions gracefully. At minimum, you should display the exception text, which will aid debugging.

Errors in ActiveX proxy execution can be handled as ActiveX exceptions, or inline using a try/catch model similar to the structured exception handling model in the C++ and Java languages.

Using an ActiveX error handler

By default, the ActiveX proxy raises an ActiveX exception when a Jaguar component method raises an exception or an internal error occurs. Visual Basic and most other ActiveX scripting tools do not allow you to handle these errors inline. Instead, control transfers to an error handler (specified by on error goto in Visual Basic) or to a system-wide error dialog box. To handle proxy errors inline, you must enable inline exception handling as described in "Handling exceptions inline".

Structure of an ActiveX exception

In C++, the OLE EXCEPINFO structure describes an ActiveX exception. Different ActiveX-enabled IDEs provide different mechanisms for applications to obtain the EXCEPINFO structure contents.

In Visual Basic, exceptions are mapped to the built-in Err object. The exception number maps to Err.Number and the description is available as Err.Description. You can handle exceptions by activating error handling code with On Error Goto statement or by checking whether Err.Number is > 0.

The proxy type library defines error numbers for client-side errors in the JagORBClientErrNum enumeration and server-side error numbers in the JagORBServerErrNum enumeration.

Note   IDL user-defined exceptions are not supported and are mapped to error number 9000.

Client error numbers

The following table lists the codes for client-side error numbers defined in the JagORBClientErrNum enumeration:

Table 20-1: JagORBClientErrNum error codes

Symbolic error code

Number

Description

jagClNonByteArrayErr

8000

Method arguments of type array can only have a base element type of byte.

jagClMultiDimArrayErr

8001

Multi-dimensional arrays not supported as an argument to a method.

jagClArrayRedimErr

8002

A Fatal Internal Error was encountered while attempting to resize a method argument of type array.

jagClArrayProcErr

8003

A Fatal Internal Error was encountered while processing a method argument of type array.

jagClArrayEmptyErr

8004

An array of size 0 was passed as parameter to a method.

jagClArrayBoundsErr

8005

A Fatal Internal Error was encounterd while attempting to determine the upper bound on a method argument of type array.

jagClNotJagComponentErr

8006

The component being instantiated is not a valid Jaguar component or was not registered in the Windows Registry.

jagClOutOfMem

8007

The Application failed to acquire memory from the Operating System.

jagClCreateFactErr

8008

The Jaguar Proxy Server could not instantiate a Factory Object. Please contact Sybase Technical Support.

jagClTypeLibErr

8009

The type library for the Component could not read from the NT Registry. Please check if a valid directory location was specified for the Type Library while registering the component.

jagClTypeInfoErr

8010

The type information for the Component could not read from the Type Library. Please regenerate TLB and REG files for the component using Jaguar Manager.

jagClMethInfoErr

8011

The metadata for the method or component could not be read from the NT Registry or the method is using parameter types that are not presently supported in the Jaguar ActiveX Proxy.

jagClMethNameErr

8012

The metadata for the method invoked on component could not be read from the NT Registry. Please regenerate TLB and REG files for the component using Jaguar Manager.

jagClCompNameErr

8013

The component name for the component being instantiated could not read from the NT Registry.

jagClPkgNameErr

8014

The package name for the Component being instantiated could not read from the NT Registry.

jagClPxyCreateErr

8015

Component creation failed.

jagClPxyDestroyErr

8016

Component deletion failed.

jagClPxyFuncDescErr

8017

The metadata information for the method could not read from the type library.

jagClArgCountErr

8018

There was a mismatch between the number of parameters passed to method and the number of parameters as described by the information in the type library.

jagClInternalErr

8019

An error was encountered while invoking a Jaguar method.

jagClParamInfoErr

8020

The type information for a method parameter could not be read from the Type Library.

jagClTypeMismatchErr

8021

There is a mismatch between type of the value passed as an argument with its specified type in the Type Library.

jagClConversionErr

8022

The data conversion attempted is presently not supported.

jagClArgUpdateErr

8023

An error was encountered while updating an input-output or output parameter for a method.

jagClRetValSetErr

8024

An error was encountered while updating the return value for a method.

jagClRecsetArgErr

8025

The ResultSet type cannot be passed as a parameter in either the input or input-output modes by a Jaguar ActiveX application.

jagClUnsuppTypeErr

8026

An unsupported OLE Automation type was used as a parameter in a method.

jagClAxConvertErr

8027

An error was encountered while converting a input-output method parameter received from the Jaguar server.

jagClJagConvertErr

8028

An error was encountered while converting a input parameter prior to method invocation.

jagClNoInitErr

8029

A Jaguar component instance must be created prior to invoking a method.

jagClRecordsetCreateErr

8030

An internal error was encountered while creating the Recordset object.

jagClRecordsetMoveErr

8031

Attempt to call MoveNext on a RecordSet which has its EOF property as TRUE.

jagClIteratorPosErr

8032

An invalid position was specified while attempting to retrieve an element from a collection.

jagClInvalidMethodErr

8033

The only method supported on the generic Jaguar Object type is Narrow_.

jagClNarrowFailErr

8034

The object reference cannot be narrowed to the interface name specified.

jagClInvalidIntfErr

8035

The fully scoped interface name passed as an argument to the Narrow_ method is invalid.

jagClOrbInitErr

8036

An internal error was encountered while initializing client-side ORB.

jagClOrbStrToObjErr

8037

An internal error was encountered while invoking the ORB.string_to_object method.

Server error numbers

The following table lists the codes for server-side error numbers defined in the JagORBServerErrNum enumeration:

Table 20-2: JagORBServerErrNum error codes

Symbolic error code

Number

Description

jagSrvMethExcepErr

9000

The method implementation threw an user-defined exception while executing on the Jaguar Server.

jagSrvMethInvalidErr

9001

The method name is either invalid or is presently not defined in the component's interface.

jagSrvMethInvalidArgErr

9002

The invocation of the method on the Jaguar Server failed because an invalid number of parameters was passed or a parameter type mismatch occurred.

jagSrvMethNotImplErr

9003

The invocation of the method on the Jaguar Server failed because the component does not implement the method.

jagSrvCompPermErr

9004

The invocation of the method on the Jaguar Server failed because user does not have the permissions to instantiate the component.

jagSrvCompDeployErr

9005

The invocation of the method on the Jaguar Server failed because component implementation was not deployed on the Jaguar Server.

jagSrvInternalErr

9006

The invocation of the method on the Jaguar Server failed due a fatal internal error.

jagSrvArgCountErr

9007

The invocation of the method on the Jaguar Server failed because an invalid parameter type was used by the method.

jagSrvSrvConnectErr

9008

The requested operation failed since the client could not to acquire connection to the Jaguar Server.

jagSrvConversionErr

9009

The invocation of the method on the Jaguar Server failed due to a data conversion error.

jagSrvFreeMemErr

9010

The invocation of the method on the Jaguar Server failed while releasing memory resources.

jagSrvIntfReposErr

9011

The invocation of the method on the Jaguar Server failed while trying to access the interface repository.

jagSrvOutOfMemErr

9012

The invocation of the method on the Jaguar Server failed while trying to acquire memory from the Operating System.

jagSrvOutOfResErr

9013

The invocation of the method on the Jaguar Server failed since it could not acquire the necessary resources.

jagSrvSrvRespErr

9014

The invocation of the method on the Jaguar Server failed because there was no valid response from the server.

jagSrvInvObjrefErr

9015

The invocation of the method on the Jaguar Server failed because the object reference is invalid.

Handling exceptions inline

By default, the ActiveX proxy raises an ActiveX exception when a Jaguar component method raises an exception or an internal error occurs. Visual Basic and most other ActiveX scripting tools do not allow you to handle these errors inline. Instead, control transfers to an error handler (specified by on error goto in Visual Basic) or to a system-wide error dialog box.

Inline exception handling can simplify the code that handles recoverable errors. For example, you can keep program logic that allows a user to retry a failed login in one place, rather than split into mainline code and the separate error handling code. Inline exception handling also allows you to handle errors explicitly in scripting tools that do not allow you to install user-coded error handlers.

The ActiveX proxy supports inline exception handling with Try, Catch, and End methods and an internal exception store. When an exception occurs with inline handling active, the proxy stores the error information rather than raising an ActiveX exception. Each component proxy object supports these methods and contains an exception store that is specific to that object. To handle exceptions inline, call the Try_, Catch_, and End_ methods as follows:

Special considerations

The Try_ and Catch_ methods do not have the same semantics of structured exception handling in Java or C++. In particular:

Example: using "catch all" exception handling

When you call the Catch_ method, you can check for exceptions of a specific type, or for exceptions of any type. To check for any exception, pass "..." as the exception type parameter.

The following example illustrates this style of exception handling:

barcomp.Try_
barcomp.methodThatRaisesException(1007)
Dim anyExcep As Object
If (barcomp.Catch_("...", anyExcep) = True) Then
Dim excepType as String
excepType = anyExcep.GetExceptionType
if (StrComp(excepType, "Foo/NotValidIdException") == 0) then
Dim invalidIdExcep as NotValidIdException
set invalidIdExcep = anyExcep
Dim id as integer
Dim msg as String
id = invalidIdExcep.id
msg = invalidIdExcep.message
Else if (StrComp(excepType, "Foo/NoAuthorizationException") == 0) then
Dim noAuthorizationExcep as NoAuthorizationException
set noAuthorizationExcep = anyExcep
Dim user as String
Dim cert as String
user = noAuthorizationExcep.username
cert = noAuthorizationExcep.certificate
Else if (StrComp(excepType, "Jaguar/ClientException") == 0) then
Dim systemExcep as SystemException
set systemExcep = excep
Dim code as integer
Dim msg as String
code = systemExcep.code
msg = systemExcep.message
End if
Else
' No Exception has occurred. Proceed
End If

Exception datatypes

Exception datatypes are used with the Try_ method when handling exceptions inline. The ActiveX proxy includes predefined system exceptions that correspond to the standard CORBA system exceptions. User-defined exceptions that are declared in an IDL module are also mapped to ActiveX types.

System exceptions In IDL, system exceptions extend the CORBA SystemException IDL type:

interface SystemException
{
long code; // numeric error code
string message; // text error message
};

Unlike user-defined exceptions, a component method can throw system exceptions that are not listed in the raises clause of the IDL method signature. The C++ and ActiveX client runtime engines may also raise system exceptions when errors occur in the processing of a method invocation.

In the ActiveX proxy, system exceptions are mapped to the interface SystemException with the following properties and methods:

The ActiveX proxy uses SystemException to represent the standard CORBA system exception types that can be returned by components, as well as errors that occur in the ActiveX proxy. "Exception identifiers" lists the system exception types.

User-defined exceptions In IDL, user-defined exceptions are defined using syntax similar to an IDL structure. For example:

exception InvalidValueException
{
string message;
string value;
};

User-defined exceptions can be defined within an IDL module or interface. The IDL method signature for a component method must list user-defined exceptions thrown by the method in the raises clause. A method cannot throw user-defined exceptions that are not listed in the raises clause.

In ActiveX, the IDL exception maps to an interface with the following properties and methods:

Exception identifiers Both system and user-defined exceptions support a GetExceptionType method that returns a string identifier for the exception. The exception identifier for a user-defined exception defined in a module is:

module/exception 

Where module is the IDL module name and exception is the IDL exception type. For example, "CtsSecurity/No Certificate Exception". The exception identifier for an exception defined in an interface is:

module/interface/exception 

Where interface is the IDL interface name.

Exception identifiers for system exceptions are predefined and listed in the following table:

Table 20-3: System exception identifiers

Identifier

Notes

Jaguar/ClientException

An error occurred internally to the ActiveX proxy. For example, you may have called a method that uses an unsupported parameter type.

CORBA/BAD_CONTEXT

CORBA/BAD_INV_ORDER

CORBA/BAD_PARAM

CORBA/BAD_OPERATION

CORBA/BAD_TYPECODE

CORBA/COMM_FAILURE

A network error occurred. When creating a connection, this usually indicates that the server is down or you have specified the wrong listener address. When calling a method, the error may indicate a transient network fault; you can retry the method.

CORBA/DATA_CONVERSION

CORBA/FREE_MEM

CORBA/IMP_LIMIT

CORBA/INTERNAL

CORBA/INTF_REPOS

CORBA/INV_FLAG

CORBA/INV_IDENT

CORBA/INV_OBJREF

CORBA/INVALID_TRANSACTION

CORBA/INITIALIZE

CORBA/MARSHAL

CORBA/NO_IMPLEMENT

The component does not implement the method that you called.

CORBA/NO_MEMORY

CORBA/NO_RESOURCES

CORBA/NO_RESPONSE

CORBA/NO_PERMISSION

The user cannot access the server or a specified component.

CORBA/OBJ_ADAPTER

CORBA/OBJECT_NOT_EXIST

The object does not exist. This can happen if:

  • The component is not installed correctly on the server. For example, the component class or skeleton class cannot be loaded.
  • The object represents a stateful component and your reference to it has expired. Check the value of the component's Instance Timeout property, and, if needed, code your client to create another instance in response to this error.

CORBA/PERSIST_STORE

CORBA/TRANSACTION_REQUIRED

The method you attempted to call must be called in the context of an open transaction.

CORBA/TRANSACTION_ROLLEDBACK

The method you called rolled back its transaction, or if you have started a client-managed transaction, the transaction timed out.

CORBA/TRANSIENT

CORBA/UNKNOWN

Example

This example calls a method CtsSecurity.SSLServiceProvider.setGlobalProperty. This method can be called to specify SSL settings for a connection to a Jaguar server (see Chapter 21, "Using SSL in ActiveX Clients" for more information).

The method signature and the exceptions raised are detailed in the following IDL:

module CtsSecurity
{
interface SSLServiceProvider
{
string setGlobalProperty
(
in string property,
in string value
)
raises (CtsSecurity::InvalidPropertyException,
CtsSecurity::InvalidValueException);
};

exception InvalidPropertyException
{
string message;
string property;
};

exception InvalidValueException
{
string message;
string value;
};
};

setGlobalProperty raises InvalidValueException if you attempt to set a property to an invalid value, and raises InvalidPropertyException if you specify a property that does not exist.

The following Visual Basic code calls setGlobalProperty and calls the Catch method to handle InvalidValueException inline. Since there is no Catch_ call for InvalidPropertyException, if this exception is thrown, it will be thrown as an ActiveX exception when End_ is called:

Dim ssp as CtsSecurity.SSLServiceProvider

// Assume ssp has been properly initialized

Dim ivException as CtsSecurity.InvalidValueException
// Activate inline exception handling
call ssp.Try
ssp.setGlobalProperty("qop", "An invalid value")
if (ssp.Catch_("CtsSecurity/InvalidValueException", ivException) then
call MessageBox ("Invalid value: " & ivException.value & ". " & _
ivException.message, , "Error");
endif
call ssp.End_

Using Try_ and Catch_ in multithreaded programs

If your program uses a proxy object in multiple threads and handles exceptions inline, you must call the Duplicate_ method to obtain a copy of the proxy object for use in each thread. Duplicate_ has the following syntax:

Object Duplicate_

Duplicate_ returns a proxy instance of the same type as the original.

 


Copyright © 2000 Sybase, Inc. All rights reserved.