Chapter 3: Running COM Automation Servers

This chapter explains the registration of COM objects so that they can function as COM Automation servers.

Registering a COM Object

A COM Object must be registered with the Windows system before it can function as a COM Automation server and receive messages from a client. There are four ways of registering OO COBOL Automation servers:

The first of these methods can be very useful when you are developing and debugging a server. The other methods are 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 starts the server automatically when a client requests a new instance of the server.

Some development environments (for example Visual Basic) automatically register any new COM object you create on the development machine - although you don't see the registration being carried out, it still happens behind the scenes. You need to register the object on each machine where you want to deploy it.

The Net Express Class Wizard generates a .reg file with all the information you need to register an object, whenever you use it to create a COM Automation server. This is an ASCII text file containing the entries to be inserted into the Windows registry. The format of this file is documented in the section Editing Registry Entries.

The information enables a client to obtain a unique ID for the object (its Clsid) from the object's ProgID. The ProgID for OO COBOL classes is by default the filename of the class, although you can change this by editing method "queryClassInfo" (see the next section). The Clsid enables the client to find another entry in the registry which provides the information needed to start the COM Automation server.

There are two ways of entering the information in the .reg file into the Windows registry. Do one of the following:

Enabling Self-registration

You can build your COM Automation servers to contain all the information needed for successful registration. The information is stored inside two methods in each COM Automation class:

These methods are generated for you by the Class Wizard when you create a COM Automation class ("queryLibraryInfo" is only included if you generate a type library at the same time). You can change some of the information returned by these methods to alter self-registration details for your class.

The "queryClassInfo" method looks like this:

 method-id. queryClassInfo.
 linkage section.
 01 theProgId             pic x(256).
 01 theClassId            pic x(39).
 01 theInterfceId         pic x(39).
 01 theVersion            pic x(4) comp-5.
 01 theDescription        pic x(256). 
 01 theThreadingModel     pic x(20).  
 procedure division using by reference theProgId
                          by reference theClassId
                          by reference theInterfceId
                          by reference theVersion
                          by reference theDescription
                          by reference theThreadModel.
     move z"{clsid}" to theClassId
     move z"{clsid}" to theInterfceId
     move z"A description of your class" to theDescription
*> For automatic registration of the DLL, you can specify the
*> the ThreadingModel registry entry
     move z"Apartment" to theThreadModel
     exit method.
 end method queryClassInfo.

where {clsid} is a string representing a 128-bit clsid. For example: {F08FCA68-286C-11D2-831F-B01A09C10000}. Do not alter the clsid value; it is generated by a Windows API call that guarantees every class a unique clsid. The clsid is used in a number of different places as part of registering a class and its interfaces and the values must match or the results are unpredictable. You can change the ProgID of the class by moving a null-terminated string with the new ProgID into data item theProgId. The version number is currently ignored by the COBOL run-time system.

The "queryLibraryInfo" method looks like this:

 method-id. queryLibraryInfo.
 linkage section.
 01 theLibraryName        pic x(512).
 01 theMajorVersion       pic x(4) comp-5.
 01 theMinorVersion       pic x(4) comp-5.
 01 theLibraryId          pic x(39).
 01 theLocale             pic x(4) comp-5.
 procedure division using by reference theLibraryName
                          by reference theMajorVersion
                          by reference theMinorVersion
                          by reference theLibraryId
                          by reference theLocale. 
                                        *> currently ignored
     move 1 to theMajorVersion
     move 0 to theMinorVersion
     move z"{clsid}" to theLibraryId
     exit method.
 end method queryLibraryInfo.

As for "queryClassInfo", you should not change the value of the library id. However, you can specify the location of the type library for a class by setting theTypeLibrary to one of the following:

no string Indicates that the type library is embedded as a resource in the .dll or .exe file for the class. This is the default location for classes created with the Class Wizard.
n A numeric value indicates that the type library is a resource in the .dll or .exe file for the class.
path A full path and filename to the type library.

You can also optionally set major and minor version numbers for your type library by setting the values of theMajorVersion and theMinorVersion.

Registration procedures for in-process and out-of-process servers are described in the following two sections.

Out-of-process Servers

It is good practice to enable your out-of-process servers to register and unregister themselves. Self-registration is usually controlled by a command-line switch. See the Help topic To register an out-of-process COM object using the executable file for more information.

The olesup class has two methods, "registerServer" and "unRegisterServer" to enable you to do this easily. You need to add code to the trigger program for the server which detects switches on the command-line for registration and unregistration.

When the trigger program detects the registration switch, execute the following code:

invoke olesup "registerServer" using theClass commandline
                           returning error-code

The "registerServer" method in olesup interrogates theClass for class and type library information using the "queryClassInfo" and "queryLibraryInfo" methods.

When the trigger program detects the unregistration switch, execute the following code:

invoke olesup "unregisterServer" using theClass 
                             returning error-code

where:

Data Item Datatype Description
theClass OBJECT REFERENCE The class for registration.
commandline PIC X(256) The command-line to start the server. You should include the path to the server.
error-code PIC X(4) COMP-5 Returns 0 for a successful registration. If unsuccessful returns an OLE error code.

In-process Servers

The Microsoft regsvr32 utility enables you to register or unregister an in-process server (built as a .dll file) from the command line. See the Help topic To register an in-process COM object for more information.

In addition to the "queryClassInfo" and "queryLibraryInfo" methods generated automatically by the Class Library Wizard, the .dll file must include an entry-point named DllOleLoadClasses for regsvr32 registration to work. The Class Library Wizard also creates this automatically if you select the option to generate a trigger program for the class.

The code below shows an example of DllOleLoadClasses:

*> COM server trigger (for in-process servers only)
*> WARNING: Do not add further entry points to this file
$set case
 linkage section.
 01 loadReason    pic x(4) comp-5.
 procedure division.
 entry "DllOleLoadClasses" using by value loadReason.
*> OCWIZARD - start classes
*> Calling the class registers it as available to OLE clients
     call "myserver"
*> OCWIZARD - end classes
      exit program.
       .

The example above registers a single class called with the filename myserver.

You can add your own code to the DllOleLoadClasses - the parameter loadReason tells you why the COBOL run-time system has called this entry-point:

1 Server is being loaded
2 Class is being registered
3 Server is being unregistered

Editing Registry Entries

Net Express generates .reg files for you to make it easy to register your COM objects. This section provides some information on the format of these files, in case you need to change the path to a server. A .reg file is an ASCII file in the following format:

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\servertype] 

@ = startup

where:

classname The ProgID, which is the name by which your COM Automation server is known to clients. The ProgID is usually the base filename.
description A brief text comment describing the server.
uuid A unique numeric identifier created by the CreateGUID() function in the Windows API. You can also create these by running the UUIDGEN tool (this is explained below).
startup The trigger to run your server. If your trigger is compiled as an .exe file, you just need the trigger name. If you have compiled it as an .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 .exe or batch file must be on the system path (set by the PATH environment variable) or have an explicit path set as part of the startup parameter.

servertype The type of COM server. Common types are LocalServer32 and InProcServer32.

The UUIDGEN tool is part of the Microsoft Platform SDK. Each time UUIDGEN runs, it generates a unique hexadecimal number.

To enter the information into the Windows registry, enter the following at a command prompt:

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. You can use the same registry file each time - although if the registry file contains any machine-specific paths you must edit them.

Note: Registry files can vary in format and structure. For full details, see your Microsoft Platform SDK documentation.

Setting Threading Options

You only need to read this section if you intend to build and run your servers multi-threaded. By default, OO COBOL servers are built single-threaded. Single-threaded COBOL programs cannot be run with any COM threading option other than single-threaded.

For more information about building multi-threaded programs with Net Express, from the Net Express toolbar, click Help > Help Topics. Then, on the Contents tab, click Programming > Multi-threaded Programming.

COM has the following different threading options for servers:

COM manages threading differently for out-of-process servers and in-process servers.

Thread Management for Out-of-process Servers

Out-of-process servers run as single-threaded when built for single-threading (the default for COBOL programs), and free-threaded when built for multi-threading.

To set a multi-threaded out-of-process server to run as apartment threaded, include the following statement in the trigger code for the server, before the class is executed:

invoke olesup "singleThread" returning aBoolean 

where aBoolean is a PIC X(4) COMP-5, set to 1 for success.

Thread Management for In-process Servers

The Net Express Class Wizard and Interface Mapper generate in-process servers using the multi-threaded "apartment" model by default. You can only change the threading options for in-process servers generated by the Class Wizard by editing its registry entry:

  1. Locate the InProcServer32 key in the server's registry entry.

    The full registry path to this key is: [HKEY_CLASSES_ROOT\{clsid}\InProcServer32] where clsid is the CLSID for the server.

  2. Change the ThreadingModel named value under this key to one of the following:

Note: The registry files generated by Net Express do not include the named value ThreadingModel. It is not included in registry entries generated by running regsvr32 either.

You can either add this key to a registry file generated by Net Express, manually edit the registry file, or write code to use the Windows API to edit the registry when the server is registered. You can add this code to the entry-point DllLoadClasses in the in-process trigger program generated by the Class Wizard - see the section In-process Servers for more information.

Setting Termination Options

By default, out-of-process servers terminate automatically when the last client logs out. This is not always desirable behavior if, for example, the server is displaying a window on the desktop. You can change this by using the "setOLETerminateOption" method in class OLESup:

invoke olesup "setOLETerminateOption" using by value option
0 Only allow the server to terminate if no windows are visible.
1 Only allow the server to terminate if no windows are visible, apart from a console window. (An OO COBOL GUI application opens a console window if your application uses DISPLAY statements.)
2 Allow the server to terminate regardless of any windows open (this is the default behavior).

Copyright © 2006 Micro Focus (IP) Ltd. All rights reserved.