PreviousUsing Other Object Domains (32-bit) SOM (OS/2)Next"

Chapter 35: OLE Automation (Windows 95 & Windows NT)

Object Linking and Embedding (OLE) is a feature of Microsoft Windows which enables one application to load and send messages to any application registered with the operating system as an OLE class or server.

35.1 Overview

Micro Focus OLE automation support enables you to send messages to OLE objects from Object COBOL programs and classes (Object COBOL as an OLE client). You can also create Object COBOL classes which you can enter into the Windows registry. Instances of these classes are OLE servers, which can receive messages from other OLE objects.

There are two main differences between the OLE object model and that for an OO language like Object COBOL:

OLE support is documented in three main sections:

35.2 Writing OLE Automation Clients

From an Object COBOL progam you can:

This enables you to control any windows application which has an OLE automation interface, directly from Object COBOL. A program which uses OLE objects like this is known as an OLE client. The objects it uses are OLE servers.

OLE enables the server to be written in a different language to the client, and defines the type and format of data which can be sent between clients and servers. Any data sent to OLE objects from Object COBOL programs is type-coerced according to the rules outlined in the section OLE Type Coercion Rules.

When you have finished with an OLE object, send it the "finalize" message. This closes the client's connection to it.

>>To write an OLE automation client

  1. Set Checker directives MFOO and OOCTRL(+P) in your program:
    $set mfoo ooctrl(+p)

  2. Map each OLE class to an Object COBOL proxy class in the CLASS-CONTROL paragraph. Give the OLE class an Object COBOL class-name, and specify that it is in the OLE domain, using a statement of the form:

    class-name IS CLASS "$OLE$windows-registry-name"

    where windows-registry-name is the server name under which the OLE class is entered in the Windows system registry.

  3. Create an instance of the Object COBOL OLE class.

    Send the message "new" to the Object COBOL proxy class. This starts the OLE server if it is not already running. You are returned an Object COBOL handle which you can use to send messages to the OLE server.

  4. Send messages to the OLE server.

  5. To access properties, prefix the property name with "Set" to set a property or "Get" to retrieve a property. You can override this behavior - see the section Forcing the OLE Message Type.

    When setting a property, pass a single parameter, when getting a property the value is returned as the RETURNING parameter.

  6. All parameters returned from OLE methods are passed by reference. The value pointed to by the reference will get overwritten by OLE, so copy the value of any parameter you want to keep, before sending any more messages through OLE.

The following example starts Word for Windows as an OLE automation server, and requests it to open a file.

$set ooctrl(+P) mfoo

 class-control.
 ...
* Register Word for Windows as an OLE automation server for
* this program. When Word for Windows is installed it enters 
* itself in the Windows registry under the name word.basic 
    word is class "$OLE$word.basic"
    ...
    . 
 working-storage section.
* Data item to hold a reference to the server
 01 wordServer        object reference. 
 ...

 procedure division. 
 ...
* Start Word for Windows and get a handle
 invoke Word "new" returning wordServer

...
* Send a message to the OLE server.
 invoke wordServer "fileOpen" using aFilename

35.2.1 Forcing the OLE Message Type

The run-time system defaults to assuming that all OLE messages sent from Object COBOL are messages to invoke a method, unless they begin "set" or "get". Messages in the fom "setPropertyName" are assumed to be OLE property set messages, and messages in the form "getPropertyName" are assumed to be OLE property get messages.

You can force the message type by sending the message "setDispatchType" to class olesup (filename olesup):

invoke olesup "setDispatchType" using lsType

where:

lsType PIC X(4) COMP-5

value 0 = next message forced to go to method
value 1 = next message forced as property set
value 2 = next message forced as property get

The message type is only forced for the next OLE message send, after which it reverts to the default behavior until you "setDispatchType" again.

35.2.2 OLE Automation Exceptions

OLE automation clients get notified of OLE errors through Object COBOL exceptions. Any OLE errors raised by an OLE server (for instance, sending a message that the server doesn't respond to), are raised as Object COBOL exceptions by the Object COBOL run-time.

To trap these exceptions in your OLE automation client, write an exception handler, and register it against the the OLEExceptionManager class (filename olexpt). See the chapter Exception Handling Frameworks for more information about exception handling.

The number returned by the ExceptionManager is the sum of the exception number, and a base number (this is part of the ExceptionManager mechanisms - see the chapter Exception Handling Frameworks for more information.

To get the base number:

invoke OleSup "getBaseOleException" returning lsBase

where:

lsBase PIC X(4) COMP-5

The table below gives brief descriptions of the exception numbers returned through the ExceptionManager by the Object COBOL run-time system.

Value
Description
1 Server defined OLE exception
2 Parameter count mismatch.
3 OLE type mismatch error
4 OLE name not found
5 Out of memory for OLE operation.
6 Name is a method
7 Name is a property
8 OLE automation error

The exception method can get more information about the OLE error which occurred by sending the message "getLastSCode" to OleSup:

invoke olesup "getLastSCode" returning lsErrorCode

where:

lsErrorCode PIC X(4) COMP-5

For information about OLE error codes, consult the Win 32 SDK documentation.

35.3 Creating OLE Automation Servers

This section tells you how you can create your own OLE automation servers using Object COBOL. Follow the steps below to create a server and make it available to other processes.

  1. Write an Object COBOL class as your OLE automation server.

  2. Write a trigger program to start the OLE automation server when it is called.

  3. Register the server with Windows.

  4. Debug the server.

Each of these steps is covered in more detail in the following sections.

35.3.1 Writing a Class for OLE Automation

Object COBOL OLE automation servers are Object COBOL classes. Each instance method in the class is available as part of the OLE interface for the server. When you write an OLE automation server, you must follow the rules below:

The following example shows a methods which enable an OLE automation client to get and set a property called osData.

 method-id. GetOsData.

 linkage section.
 01 osDataValue pic x(4) comp-5.

 * A property get method always has a returning value.
 procedure division returning osDataValue.
     move osData to osDataValue
     exit method.
 end method GetOsData.

 method-id. SetOsData.
 linkage section.
 01 newOsData pic x(4) comp-5.

 * A property set method always has a using value.
 procedure division using newOsData.
     move newOsData to osData
     exit method.
 end method SetOsData.

When you compile your OLE automation server, you can compile it as an .int file, .gnt file, link it into a .dll, or link it into an .exe with the trigger program. When you want to ship an OLE automation server, .dll or .exe files are the best formats, but while you are developing it, .int and .gnt files are easier to work with.

35.3.2 Writing the Trigger Program

In addition to the OLE server class, you must write a trigger program which makes a COBOL CALL to your OLE class to load it. Once it has loaded the class, the trigger must start an event loop to process OLE events. You can do this in one of two ways. For an OLE server which does not use Object COBOL GUI classes, add the olesup class to the Class-Control paragraph:

class-control. 
...
olesup is class "olesup"

Then use the statement:

invoke olesup "becomeServer"

For an OLE server which is a GUI application (it uses the GUI classes), create and start an EventManager (see the chapter GUI Frameworks for more information about the EventManager. In effect, you simply need to include a CALL to your OLE automation server as part of the startup code for the GUI application. As soon as the application sends the message "run" to the EventManager, the OLE automation server becomes available.

35.3.3 Registering an OLE Automation Server

OLE automation servers must be registered with the Windows system before clients can send messages to them. There are two ways of registering Object COBOL automation servers:

The first of these methods can be very useful when you are developing and debugging a server. The second method is preferable when you don't know when clients are likely to request the server to start. Once the server is entered into the Registry, Windows will start the server automatically when a client requests a new instance of the server.

The easiest way to enter information into the Windows System Registry is to create an ASCII text file containing the entries you want inserted into the registry. All entries in the registry are key/data pairs. You have to provide entries which enable the operating system to look a server class up by either its name or by its Clsid (a unique numeric key).

This is the format of a registry entry file:

REGEDIT
HKEY_CLASSES_ROOT\classname = description HKEY_CLASSES_ROOT\classname\Clsid = uuid HKEY_CLASSES_ROOT\CLSID\uuid = description HKEY_CLASSES_ROOT\CLSID\uuid\ProgID = classname HKEY_CLASSES_ROOT\CLSID\uuid\LocalServer32 = startup

where the parameters are:

classname The name by which your OLE automation server is known to clients.
description A brief text comment describing the server.
uuid A unique numeric identifier created by the UUIDGEN tool (this is explained below).
startup The trigger to run your server. If your trigger is compiled as a .exe file, you just need the trigger name. If you have compiled it as a .int or .gnt file, you need to use the COBOL run command.

This could be the name of a .exe file, or it could be a batch file, or a COBOL run command. For example:

            run mytrigger

The UUIDGEN tool is part of the Microsoft Win32 SDK. Each time UUIDGEN runs, it generates a unique hexadecimal number. To run UUIDGEN, enter the following at a command prompt:

UUIDGEN

The number generated is very long, so use the Windows DOS prompt mark and copy facility to paste it into your registry file.

Once you have created your registry file, enter the information into the Windows registry. At a command prompt, enter:

regedit registryfile 

where registryfile is the name of the file with your registry entry.

You need to register the automation server each time you install it into a different Windows system - use the same registry file each time.

35.3.4 Debugging OLE Automation Servers

You debug OLE Automation servers using Animator V2. OLE clients and servers run as separate processes, so if the OLE client is also an Object COBOL program, you need to start one copy of the Animator V2 to debug the client and a second one to debug the server. If the client is written in a different language, debug it using the tools supplied by the compiler vendor.

Start animating the trigger program for the server application. Step through the trigger program until you get to the one of the following statements:

invoke olesup "becomeServer"

or

invoke anEventManager "run" 

When you step this statement, Animator V2 stops responding. The server is now waiting in an event loop to receive a message from an OLE client. You can now run or debug the client application. When the client sends a message to the server, Animator V2 wakes up with the execution point positioned on the first statement of the OLE server method invoked.

You can now debug the server method. When you step the exit method statement, execution returns to the event loop and Animator V2 is suspended again until the server receives another message.

35.4 OLE Datatype Coercion Rules

When you send COBOL data to OLE objects, it is coerced into appropriate OLE data types. Similarly, when a COBOL program receives data from an OLE object, it is coerced to a COBOL type.

Coercion when sending data from Object COBOL through OLE:

COBOL data type
OLE data type
PIC X(2) COMP-5 INT2 (2 byte integer)
PIC X(4) COMP-5 INT4 (4 byte integer)
OBJECT REFERENCE IDispatch (OLE object handle type)
all other data types BSTRING (length prefixed string)

Coercion when Object COBOL receives data from OLE:

OLE data type
COBOL data type
INT2 (2 byte integer) PIC X(2) COMP-5
INT4 (4 byte integer) PIC X(4) COMP-5
IDispatch (OLE object handle type) OBJECT REFERENCE
BSTRING (length prefixed string) PIC X(n)

35.5 Miscellaneous OLE Support - Class olesup

This section documents the methods in class olesup. This class provides extra functions for using OLE automation from Object COBOL. The olesup class exists in the native Object COBOL domain (it is not an OLE class itself), and to use it in your programs or classes, include the following entry in the Class-Control paragraph:

olesup is class "olesup"

All olesup methods are class methods, which are detailed below.


setDispatchType

Force the type of the next message sent through OLE automation. The Object COBOL run-time system defaults to treating messages in the form "setattribute" or "getattribute" as property sets and gets.

Syntax:
invoke olesup "setDispatchType" using by value lsType
Parameters:

lsType PIC X(4) COMP-5

On Entry:

lsType value 0 - next message forced to go to method
value 1 = next message forced to be a property set
value 2 = next message forced to be a property get


becomeServer

Begin waiting for OLE messages.

Syntax:
invoke olesup "becomeServer" 
Remarks:

Used in the trigger program for an Object COBOL server


getLastScode

Return the last OLE automation error code.

invoke olesup "getLastSCode" returning lsErrorCode
Parameters:

lsErrorCode PIC X(4) COMP-5

On Exit:

lsErrorCode OLE automation error code. Consult the Win 32 SDK documentation for information.


getBaseOleException

Return the exception offset for exceptions raised by the Object COBOL OLE automation support.

Syntax:
invoke olesup "getBaseOleException" returning lsNumber
Parameters:

lsNumber PIC X(4) COMP-5

On Exit:

lsNumber Value of the offset. Subtract this number from an exception id raised by the Object COBOL run-time system to get the exception number.


Copyright © 1999 MERANT International Limited. All rights reserved.
This document and the proprietary marks and names used herein are protected by international law.

PreviousUsing Other Object Domains (32-bit) SOM (OS/2)Next"