Using Other Object Domains | OLE Data Types |
Object Linking and Embedding (OLE) is a feature of Microsoft Windows which enables an application to expose functionality that can be utilized by other applications. You can use parts of off-the-shelf packages in conjunction with custom software to create new applications. All of the applications in the Microsoft Office suite and much of the Microsoft BackOffice suite expose their functionality through OLE automation, enabling you to reuse parts of them to perform common functions. For example, if you want your application to generate an attractive looking report and print it, you can use the functionality of Microsoft Word to create and print the report.
Micro Focus OLE automation support enables you to send messages to ActiveX objects from Object COBOL programs and classes (Object COBOL as an ActiveX client). You can also create ActiveX objects, enabling you to manipulate an Object COBOL class through OLE automation.
There are two main differences between the Component Object Model (COM) on which OLE automation is built, and that for an OO language like Object COBOL:
OLE support is documented in three main sections:
A client is an application that controls ActiveX objects by accessing the functionality exposed by those objects.
An ActiveX object is an application that exposes its functionality so that it can be controlled by other applications. Examples of such objects include Microsoft Word. Micro Focus ActiveX servers support dual interfaces, and the NetExpress Class and Method Wizards can automatically create and update the type libraries needed to support this.
Object COBOL ActiveX clients and objects automatically use DCOM when necessary. You only need to change the registry entries. This is covered later in this chapter, in the section Using DCOM..
Note: ActiveX clients and objects were formerly known as OLE automation clients and servers.
OLE and DCOM technology is evolving very quickly, and it is possible that not all the third-party software you plan to use for a project supports the functionality you want to use. Before beginning a project, make sure you have up-to-date releases for all third-party software, and that it supports all the functionality you need.
In particular, check the following:
For example, OLE automation for local communication between processes is available on all releases of Windows 95 and Windows NT. But DCOM (using OLE automation across different machine) for in-process servers is only supported on Windows NT if you have Windows NT 4.0 and Service pack 2 or later. To use DCOM on Windows 95 you need to add DCOM support.
This information is available from the Microsoft Web site (see For More Information).
For example, DCOM is only supported by Visual Basic 5.0 or later.
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 ActiveX objects like this is known as an ActiveX client.
COM enables the ActiveX object 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 objects. Any data sent to OLE objects from Object COBOL programs is type-coerced according to the rules outlined in the chapter OLE Data Types.
Object COBOL OLE automation support represents ActiveX objects as Object COBOL objects, by providing a proxy for each ActiveX object a client is using. The client sends messages to the proxy, and these are forwarded on to the ActiveX object by the Object COBOL run-time system.
Fig 5-1: An Object COBOL client sending messages to an ActiveX proxy
The following sections cover the process of writing an ActiveX client:
Any Object COBOL program can be made into an ActiveX client; you don't need to write an Object COBOL class. All you need to do is:
$set ooctrl(+p)
Note: This limits the number of parameters in any method invoked or declared to 31, plus an optional RETURNING parameter.
class-control. class-name IS CLASS "$OLE$windows-registry-name"
where windows-registry-name is the server name under which the ActiveX object is entered in the Windows system registry. You can use either the ProgID, which is a human-readable name, or the CLSID, which is a 16-byte number guaranteed to be unique for each ActiveX object in the world. You would normally use the ProgID, as the CLSID is likely to change for each new version of the ActiveX object released.
For example:
class-control Word is class "$OLE$word.basic" HTMLHelp is class "$OLE${adb880a6-d8ff-11cf-9377-00aa003b7a11}" .
For example:
$set ooctrl(+P) class-control. *> comploan is the name (ProgID) of the ActiveX object comploan is class "$OLE$comploan" ... . working-storage section. 01 theCompLoanServer object reference.
You need to create a proxy object for each ActiveX object you want to use. When you create the proxy, two things happen:
To create a proxy:
You can now start sending messages to the ActiveX object through the proxy.
Example:
working-storage section. 01 theCompLoanServer object reference. ... procedure division. ... invoke comploan "new" returning theCompLoanServer ...
You can also specify the location of the server when you create it. To specify the server location:
Example:
working-storage section. 01 theCompLoanServer object reference. ... procedure division. ... invoke comploan "newWithServer" using z"machine1" returning theCompLoanServer ...
Once you have an ActiveX object, you can send it messages and set or get its properties. Both message sends and property get/set operations are handled by using the INVOKE verb to send messages to the proxy object. Whenever you send a message to the proxy object, where the name begins with "get" or "set", the Object COBOL run-time system automatically converts that to a property get or set on the ActiveX object, as shown in the diagram below.
Fig 5-2: Sending messages and setting properties
To send a message:
invoke proxyObject "messagename" [using param-1 [param-2..]] [returning result]
proxyObject | The proxy for the ActiveX object. Creating a proxy and starting the ActiveX object is explained in the section Creating an ActiveX proxy object |
messagename | The message you want to send. |
param-1 | Any parameters needed for the message. COBOL data types are converted to OLE data types as explained in the chapter OLE Data Types. Pass all parameters by reference (COBOL default). |
result | The result if this method returns one. COBOL data types are converted to OLE data types as explained in the chapter OLE Data Types. |
To set a property:
invoke proxyObject "setPropertyName" using value
proxyObject | The proxy for the ActiveX object. Creating a proxy and starting the ActiveX object is explained in the section Creating an ActiveX proxy object |
PropertyName | The name of the property you want to set. |
value | The new value for the property. COBOL data types are converted to OLE data types as explained in the chapter OLE Data Types. Pass the value by reference (COBOL default). |
To get a property:
invoke proxyObject "getPropertyName" returning value
proxyObject | The proxy for the ActiveX object. Creating a proxy and starting the ActiveX object is explained in the section Creating an ActiveX proxy object |
PropertyName | The name of the property you want to set. |
value | The value of the property. OLE data types are converted to COBOL data types as explained in the chapter OLE Data Types. The value is returned to you in an area of memory which can be overwritten by OLE, so take a copy of the value if you need to keep it. |
The following example sets a property, sends a message, and then gets a property.
working-storage section. 01 theCompLoanServer object reference. 01 AnAmount pic 9(7).99. 01 ARate pic 99.99. 01 Amount20 pic $9(7).99. ... procedure division. ... invoke theCompLoanServer "SetLoanTermYears" using "20" invoke theCompLoanServer "calculate" invoke theCompLoanServer "GetYearPayment" returning Amount20 ...
You can override the run-time system default of assuming that all OLE messages sent from Object COBOL beginning "set" or "get" are property set or get operations. You can also force a message which is not prefixed "set" or "get" to be a property set or get. To force the message type, send the message "setDispatchType" to class olesup (filename olesup):
invoke olesup "setDispatchType" using by value lsType
where:
lsType | PIC X(4) COMP-5
value 0 = next message forced to invoke a method |
The message type is only forced for the next OLE message send, after which it reverts to the default behavior until you "setDispatchType" again. Class olesup encapsulates several useful functions for OLE automation programming, and is fully documented in the OLE Automation Class Library Reference. Click Help Topics on the NetExpress Help menu, and then click Reference, OO Class Library, Class Library Reference, and click the shortcut to start the Class Library Reference.
The type library for an ActiveX object defines information that can be useful when you are writing a client. You can generate a COBOL copyfile for any type library by using the Type Library Assistant. Click Type Library Assistant on the NetExpress Tools menu.
Depending on the information in the type library, the COBOL copyfile includes the following:
The proxy objects created to represent ActiveX objects are not automatically garbage collected by the Object COBOL run-time system. When you have finished with an ActiveX object, you should send the "finalize" message to its proxy. When an ActiveX object has no connections remaining, it will usually shut itself down unless it is visible or requires an explicit method call (for example "quit" shuts down Word 97). .
For example:
invoke theCompLoanServer "finalize" returning theCompLoanServer
ActiveX clients get notified of OLE errors through Object COBOL exceptions. Any OLE errors raised by an ActiveX object (for instance, when you send a message that the object doesn't recognize), are returned to those ActiveX clients written in Object COBOL, as exceptions. The default exception behavior is for the client to display a message warning of the exception, and then terminate. You can trap the exception yourself though, and handle it with your own error processing code.
The instructions below assume you have first read the information on exception handling in the on-line help. Click Help Topics on the NetExpress Help menu, then select Programming, Object-oriented Programming, Class Library Frameworks, Exception Handling.
To trap OLE exceptions:
class-control. ... OLEExceptionManager is class "oleexpt" ExceptionManager is class "exptnmgr" olesup is class "olesup" Callback is class "callback" EntryCallback is class "entrycll" ...
invoke Callback "new" using anObject z"methodName" returning aHandler
An EntryCallback looks like this:
invoke EntryCallback "new" using z"entryPointname" returning aHandler
invoke ExceptionManager "register" using OLEExceptionManager aHandler
Now all OLE exceptions sent through to the client get sent to your exception handler.
Your exception handler receives two parameters; the first is the object handle to the OLEExeptionManager, and the second is an exception ID. To get the OLE error code, you need to subtract the base OLE Exception error number from the exception ID. You can get the value of the base OLE Exception error number by sending the "getBaseOleException" message to class olesup. 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 |
9 | OLE server unavailable |
10 | The OLE server threw an exception |
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.
The first piece of example code below is a short COBOL subroutine for handling OLE exceptions, called ole-err1.cbl. The second piece wraps the subroutine in an EntryCallback, and registers it as an OLE exception handler.
The exception handler:
class-control. olesup is class "olesup" . working-storage section. 01 wsOffset pic x(4) comp-5. 01 wsOLEException pic x(4) comp-5. linkage section. 01 lnkExceptionObject object reference. 01 lnkExceptionNumber pic x(4) comp-5. procedure division using lnkExceptionObject lnkExceptionNumber. ... invoke olesup "getBaseOleException" returning wsOffset subtract wsOffset from lnkExceptionNumber giving wsOLEException *> OLE exception ... exit program.
Registering the exception handler:
class-control. ... EntryCallback is class "entrycll" oleexpt is class "oleexpt" ExceptionManager is class "exptnmgr" . working-storage section. ... 01 exceptionHandler object reference. ... procedure division. ... *> Set up exception OLE exception handler invoke EntryCallBack "new" using z"exception-section" returning exceptionHandler invoke ExceptionManager "register" using oleexpt exceptionHandler ...
The Microsoft OLE Programmer's Reference defines an ActiveX object as: "an instance of a class that exposes properties, methods, and events to ActiveX clients". You can create ActiveX objects from an Object COBOL class that meets the following criteria:
These classes provide the code needed to enable a class to work through OLE automation. The Component Object Model (COM) which underlies OLE automation does not support inheritance. OLEBase-s specifies a single use server; that is a new server is created for each client that tries to connect to it. OLEBase is used for multiple use servers - most servers are multiple use. Single and multiple use are not applicable to in-process servers.
Your class must inherit from class olebase. OLE does not support inheritance, so you can't create subclasses from your OLE classes.
OOCTRL(+P) forces the compiler to provide some extra type-checking information required for programs to work with OLE automation.
Note: This limits the number of parameters in any method invoked or declared to 31, plus an optional RETURNING parameter.
Clients locate your class through the Windows Registry. The format of the registration depends on how the ActiveX object is run (see below).
Use the NetExpress Class Wizard to generate the class skeleton for you, a registry entry, type library, hand a trigger program (if required). To run the Class Wizard, click New on the File menu and select Class from the New dialog box.
An ActiveX program can be run in one of three ways:
The object runs in a separate process space to the client using it. Out-of-process objects are built as stand-alone .exe programs. If an out-of-process object crashes, the client can recover from the error.
The object is loaded into the same process space as the client. In-process objects are built as .dll programs. Access to in-process ActiveX objects is faster. If the object crashes (for example, if it causes a protection violation) the client is likely to crash as well.
The client and object run on different machines. Messages are passed across the network. A remote ActiveX object can be built as either an in-process or out-of-process server. You can develop an ActiveX object that runs locally, and convert it to a remote object when you are ready to deploy it, by following the instructions in the section Using DCOM.
If built as an in-process server, it does not run in the process space of the client, but is loaded on the remote machine by a proxy client. This improves performance as the in-process server stays loaded, and doesn't have to be reloaded for subsequent clients.
Remote ActiveX objects are supported by an extension to COM, Distributed Component Object Model (DCOM). Not all versions of Windows support DCOM - see Checklist - Before You Start for details.
The source code for all three types is the same, but the way you build and register them is different. The next two diagrams contrast in-process, out-of-process and remote objects.
Fig 5-3: Out-of-process and in-process ActiveX objects
The following sections tell you how you can write, register and debug your own OLE Automation Servers using Object COBOL.
How to create the class and add methods and properties.
Gives you a choice of techniques for registering your server.
Determine under what conditions OLE can terminate your server.
How to debug your server code.
Keeping the type library for an ActiveX Object in step with changes you make to the server class.
How to override COM threading defaults for running multi-threaded ActiveX objects. You only need to read this section if you intend to write multi-threaded server classes.
Object COBOL OLE automation servers are Object COBOL classes. An instance of this class is an ActiveX object. We have split writing a class into three stages:
The NetExpress Class Wizard can generate an outline of your OLE automation class, trigger program and registry entry for you. Before you run the wizard, you need to decide the following:
If you prefer, you can create the server as a local server, and change it to a remote server when you have finished developing it. The only difference between local and remote servers is in how they are registered with Windows.
A type library provides useful information for clients of your class.
If you create the library to support dual interfaces (the default), a clients can early bind to the type library, providing a significant increase in performance. You must keep the type library up-to-date with the class - see Updating Type Libraries. And because dual interface clients are early bound to the class through the type library, you must relink them if you change the type library. If you fail to keep type libraries and clients up-to-date with changes, programs can crash at run-time due to parameter mismatches.
Then, to run the wizard:
This starts the Class Wizard. Follow the prompts.
When you click the Finish button on the last wizard dialog box, the Class Wizard generates or updates the following files and adds them to the project:
If you asked for a type library, it also generates these files:
The Class Wizard also ensures that your class is built as a .dll or .exe depending on whether you elected to build it as an in-process or out-of-process server.
Note: When you create an in-process server, the Class Wizard also adds to your NetExpress project directives which link in dllserver.obj to the .dll file. Dllserver.obj is supplied in the NetExpress link libraries (these are installed in \netexpress\base\lib by default).
To convert an out-of-process server to an in-process server: rebuild the class as a .dll file, omitting the trigger program, and add dllserver.obj to the Additional CBLLINK Directives Field, on the Link tab of the Build Settings dialog box for the .dll.
dllserver.obj
Click the Close button.
All the instance methods you add to your OLE automation server class are exposed as methods of the ActiveX object, unless the method name starts with "set" or "get" (see the section Adding Properties to the ActiveX Object). Declare any parameters you want passed to or from the method in the Linkage Section of the method. The Object COBOL run-time system converts between COBOL and OLE automation data types as explained in the chapter OLE Data Types.
To add a new method:
When you add or remove methods you must update any type libraries for the object. This happens automatically when you use the Method Wizard. For more information, see Working with Type Libraries.
Note:
COM does not support class objects and class methods. Any class methods you write for an OLE automation server are ignored. However, if your class object needs notification of new instances being created, write a class method named "new". Put the notification code in this method. You do not need to put any code in this "new" method to actually create the "new" instance as you would with a non-OLE Object COBOL class.
Define OLE automation properties for your ActiveX object by writing "set" and "get" methods. Any OLE property get or set operation from a client is mapped onto the "set" and get" methods. To enable setting a property, name the method "setpropertyname", where propertyname is the name of the property. To enable getting a property, name the method "getpropertyname", where propertyname is the name of the property.
Set methods have one USING parameter, from which the property is set, and Get methods have a RETURNING parameter, used to send back the value of the property. The Object COBOL run-time system converts between COBOL and OLE automation data types as explained in the chapter OLE Data Types.
To add a new method:
When you add or remove methods you must update any type libraries for the object. This happens automatically when you use the Method Wizard. For more information, see Working with Type Libraries.
The following example shows a method which enables an OLE automation client to set a property called LoanTermYears, and another which enables the client to get a property called YearPayment.
method-id. "SetLoanTermYears". linkage section. 01 NewLoanTermYears pic 99. procedure division using NewLoanTermYears. move NewLoanTermYears to LoanTermYears exit method. end method "SetLoanTermYears". method-id. "GetYearPayment". linkage section. 01 CurrentYearPayment pic $9(7).99. procedure division returning CurrentYearPayment. move YearPayment to CurrentYearPayment exit method. end method "GetYearPayment".
An OLE automation server must be registered with the Windows system before a client can send it messages, and use it to create an ActiveX object. There are four ways of registering Object COBOL automation servers:
All Object COBOL automation servers register themselves automatically when run. This only works for out-of-process servers which can be run standalone. The information entered into the registry is minimal when you use this method.
Windows NT:
The registration lasts until the operating system is rebooted.
Windows 95 :
The registration is permanent.
This registers the server permanently. This requires some extra code in the server .dll which is created automatically by the Class Wizard. See the section Enabling Self Registration for more information.
This registers the server permanently on the system.
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 ActiveX 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 NetExpress Class Wizard generates a .reg file with all the information you need to register an object, whenever you use it to create an OLE 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 Object 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 OLE automation server.
There are two ways of entering the information in the .reg file into the Windows registry:
or
regedit filename.reg
You can build your OLE automation servers to contain all the information needed for successful registration. The information is stored inside two methods in each OLE automation class:
Returns information about the class.
Returns information about the class type library.
These methods are generated for you by the Class Wizard when you create an OLE 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. procedure division using by reference theProgId by reference theClassId by reference theInterfceId by reference theVersion. move z"{clsid}" to theClassId move z"{clsid}" to theInterfceId 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 has been 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 below:
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. For example, to register myserver.exe, the end-user enters the following command:
myserver /Register
To unregister the server, the end-user enters:
myserver /Unregister
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. |
The Microsoft regsvr32 utility enables you to register or unregister an in-process server (built as a .dll file) from the command line. To register a server:
regsvr32 server.dll
To unregister a server:
regsvr32 -u server.dll
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:
*> OLE 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 |
By default, out-of-process servers terminate automatically when the last client logs out. This is not always desirable behavior - if for example, if 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
where option is one of the following:
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 Object 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). |
You debug ActiveX objects using NetExpress. The procedure is slightly different for in-process and out-of-process ActiveX objects.
When the OLE clients and server are running as separate processes, you need to start a copy of NetExpress to debug the server. There are two different ways of doing this:
To debug by starting the trigger:
invoke olesup "becomeServer"
or
invoke anEventManager "run"
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, the NetExpress animator 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 NetExpress Animator is suspended again until the server receives another message.
To debug by adding a call:
CALL "CBL_DEBUGBREAK"
When execution in the server reaches the call to "CBL_DEBUGBREAK", a message box appears asking you whether you want to start animating.
You can either run your client normally, in which case you will only debug the server, or you can start the client inside a debugger as well, in which case control switches between the two debuggers as you step into message sends from the client to the server. If the client is written in Object COBOL, you need to start a second instance of NetExpress to debug the client. If the client is written in another language, debug it using the tools provided by the language vendor.
In-process servers are loaded inside the same address space as the client. If the client is written in Object COBOL, simply debug it using NetExpress, and as you step through statements that send messages to the server, the server code appears inside the NetExpress Animator.
If the client is written in a different language, add a class method "new" to your Object COBOL OLE automation server. Put the following statement inside the "new" method:
call "CBL_DEBUGBREAK"
When the client starts the server, it automatically starts up NetExpress, enabling you to debug server code.
The type libraries generated by the NetExpress Class Wizard contain the following information:
You can also generate a type library at any time for an existing OLE automation class using the NetExpress Ocreg utility. Click Help Topics on the NetExpress Help menu and look up Type Library on the Index tab for more information.
You should use the Method Wizard to add all properties and methods. The Method Wizard automatically updates the type library with the new interface information each time you start it.
To delete a method or property from a type library:
//OCXWIZARD - start methods
...
//OCXWIZARD - end methods
A method looks like this:
[id(DISPID_CLASSNAME_METHODNAME)] HRESULT MethodName ( parameter_descriptions);
and a property looks like this:
[id(DISPID_CLASSNAME_SETPROPERTYNAME), propput] HRESULT PropertyName ( parameter_descriptions); [id(DISPID_CLASSNAME_GETPROPERTYNAME), propget] HRESULT PropertyName (parameter_descriptions);
where:
CLASSNAME | Name of the class |
METHODNAME | Name of the method |
property_name | Name of the property |
parameter_descriptions | One or more lines describing the parameters used by the method |
To change the datatypes of parameters in a method or property set or get:
1) Change them in the source 2) Locate the method in the filename_if.idl file and change the IDL types to match the new COBOL types. (A good way to do this is to create a test class & add a method to it to see what the wizard gives) 3) Recompile the .TLB and server 4) Relink/rereference any clients that use the type library
If you are changing a property datatype, the datatype must match for the get and set methods.
If you are not sure how to match
IDL and COBOL datatypes, use the Class Wizard to create a dummy OLE automation server, and then use the Method Wizard to add methods with the datatypes you want. You can then copy the parameter information from the type library for your dummy class to the one you are working on.You only need to read this section if you intend to build and run your servers multi-threaded. By default, Object 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 NetExpress, click Help Topics on the NetExpress Help menu, then select Programming, Multi-threaded Programming on the Contents tab.
COM has the following different threading options for servers:
Objects can be called in any method from any thread, so you they cannot have any thread-local data.
COM manages threading differently for out-of-process servers and in-process servers.
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.
By default COM always runs in-process servers as single-threaded, regardless of build options. You can only change the threading options for a in-process server by editing its registry entry:
The full registry path to this key is: [HKEY_CLASSES_ROOT\{clsid}\InProcServer32] where clsid is the CLSID for the server.
Note:
The registry files generated by the NetExpress 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 NetExpress, 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.
DCOM (Distributed Common Object Model) enables you to distribute ActiveX clients and objects across different machines on a network. You can run any Object COBOL ActiveX object across a network by providing the right registry information on the client and server machines. The registry entry for the client machine enables it to find the remote machine where the server exists.
Figure 4-1: Locating a remote ActiveX object
You need to generate two .reg files for your ActiveX object; one to register it on client machines, and one to register it on the remote server machine. The NetExpress Class Wizard does this for you if you specify that an OLE Automation server class is remote when you create it, but quite often you develop an ActiveX object as a local server, and then redeploy it as a remote server when you have finished.
To generate the registry files:
Unless you are going to install the server in the \windows\system directory on the remote machine, also include a full path when you enter its filename.
Use the client registry file to register the server on all the client machines you want to have access to it. Use the server registry file to register the server on the server machine. You also need to install either NetExpress or Application Server on your server machine.
Windows NT security can occasionally cause some problems in starting, running and accessing distributed servers. This section lists the main points you should check when using DCOM and Windows NT:
DCOM enforces these rules. You can set up the values for each server using the Microsoft DCOMCNFG utility. To test that everything is working, use custom launch and access permissions, add "Everyone" to each list, and use a client within the same domain as the server. Then refine your security.
You can choose one of the following:
The interactive user | The server is launched under the account of the user currently logged in to the server. For multiple use servers, only one server need be launched. The server has automatic access to the screen. |
The launching user | The server is launched under the machine account that the client application is running under. For multiple use servers, a server is launched under each new client login. |
A specified user | The server is launched under a particular user account. For multiple use servers, only one server need be launched. |
See Microsoft documentation for more information about security issues.
NetExpress generates .reg files for you to make it easy to register your ActiveX 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 the parameters are:
The UUIDGEN tool is part of the Microsoft Win32 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 Win 32 SDK documentation.
OLE is a large subject, and is not covered in depth by a short chapter like this. You might find it helpful to familiarize yourself further with OLE. Use the information sources listed below to do this:
This includes a part on OLE automation. The Win32 SDK and documentation are included on the NetExpress CD-ROM.
The following locations on the Microsoft Web Site are also worth exploring:
Up-to-date news and technical articles for OLE, COM and DCOM developers
Useful information for any one building a distributed system using OLE automation.
Using Other Object Domains | OLE Data Types |