C3POs in GroupWise 5: Extensibility at Its Best
Articles and Tips: article
01 Sep 1996
Shows how a Custom 3rd-Party Object (C3PO) can extend the GroupWise 5 environment. Discusses interface, registration and inheritance of C3POs.
A Custom 3rd Party Object(C3PO) is an OLE COM server object that is used to extend the GroupWise5 environment. The extensions take various forms, ranging from implementing custom record types (objects) in the GroupWise data store to modifying the GroupWise browser or toolbar functionality. A C3PO can be developed by using C++, Delphi, or Visual Basic.
C3POs combine and replace the older and less functional notion of custom messages and custom commands. The 16 bit custom message and custom command drivers of GroupWise 4.x do not run under the 32 bit C3PO implementation. However, a 32 bit C3PO can be written to support 16 bit custom messages and custom commands.
C3POs may make the following modifications to the user interface:
Add new commands to the menus and new buttonsto the toolbar.
Place user defined bitmaps on the toolbar.
Add separator lines to enhance the appearanceof menu items.
Provide a Help file with customized information about the C3PO.
The ability to modify the user interface allows a C3PO to appear as an integrated feature of GroupWise.
One way to run a C3PO is to select the menu item or toolbar button that was added by the C3PO. However, C3POs may be registered to run when an existing menu item or toolbar button is selected. This allows a C3PO to enhance or replace the normal functionality. C3POs can also be triggered to run when GroupWise starts, when GroupWise ends, and when a new item arrives in the mailbox.
All objects in the GroupWise data store (mail messages, appointments, tasks, and so forth) are theoretically C3POs. By installing a C3PO against the default message class names, customized C3PO behavior can be invoked. For example, arrival of all items in the GroupWise 5 data store can be monitored by installing a C3PO under the root item message class. Multiple handlers for a given message class are allowed; however, the order of execution depends on the order of handler installation in the Windows registry.
C3POs and the Object API
C3POs access and manipulate the GroupWise data store through the GroupWise 5 Object API. The combination of C3POs and Object API provides a powerful framework to open the GroupWise system to third-party development.
C3PO classes are expressed in the GroupWise Object API as the MessageClass property on the message object and its derivatives. Every object in the GroupWise data store has a message class field, which is a string. The object class ties an instance of a C3PO back to the associated object handler hierarchy.
Some C3POs never generate any data records in the GroupWise 5 data store. This allows the C3PO to fully participate in menu modifications, toolbar negotiations, chaining of command extensions, and so forth, without requiring the overhead of managing instance data. Hence, a single set of extensions (the C3PO specification) can be used for client extensions. Although it is legal to register C3PO implementations that do not generate instance records under other headings, they are typically registered under GW.APPLICATION.
C3POs are COM servers that implement the appropriate interfaces to achieve a desired purpose. The C3PO specification defines the prototypes of functions and methods. The C3PO writer must write the code to implement these methods. This is distinct from other APIs, which supply a library of functions that may be called by the user. A list of the C3PO interfaces appears in the C3PO documentation in the GroupWise SDK.
The C3PO specification defines the interfaces that a C3PO can choose to support. A C3PO is required to support only those interfaces that are necessary to implement the desired behavior. The GroupWise 5 client determines which interfaces a C3PO supports by calling the Query interface. Minimizing the set of supported interfaces can improve performance. Because excessive processing while adding items to the GroupWise menus can hinder the perceived performance, the C3PO writer should take care not to disturb system processing beyond reasonable limits.
The C3PO interfaces are applicable to remote applications. However, the menu and toolbar modifications cannot be made from a remote application unless the C3PO writer performs custom marshaling using the raw menu and toolbar handles which will be exposed.
Each C3PO must appear in the Windows 95 system registry under a series of names that identify the C3PO to the GroupWise environment. Information stored in the registry includes ProgID identifications for C3PO servers, hints about how the C3PO is to be used, and identification information. This information registers the C3PO with the GroupWise environment.
The registration naming system identifies a type relationship to GroupWise and is used to support inheritance of behavior. Names in the system are of the form GW.Classtype.Subtype. Classtype identifies the category of C3PO being registered (see GW.MESSAGEand GW.APPLICATION below). Subtype is used to relate one C3PO to another for purposes of supporting inheritance of behavioral semantics.
As each C3PO is registered with GroupWise, an association between the C3PO server and a particular type name is made. It is possible to register more than one C3PO at a specific naming point, but be careful when doing so because many operations have meaning only when bound to a single C3PO instance. To guarantee correct behavior, GroupWise will bind to the first registered C3PO in those instances. It is generally preferable to use subtypes or COM TreatAs mechanisms rather than registering more than one C3PO at a specific naming point.
The C3PO naming system has some restrictions. Naming is accomplished by appending a period (.) to an existing type and including an extension, which indicates a subtype. There are fixed root names under which names can be registered. Only one of these root names can be extended by subtyping. The root names available for registration are GW.MESSAGE and GW.APPLICATION.
C3POs registered under this root name are intended to implement behavior of specific record types. That is, the C3PO intends to create, display, send, or manipulate individual records.
Each item must be a subtype of one of the following:
GW.MESSAGE.MAIL GW.MESSAGE.APPOINTMENT GW.MESSAGE.TASK GW.MESSAGE.NOTE GW.MESSAGE.PHONE GW.MESSAGE.DOCREF
This root name indicates that the C3PO wants to implement some type of global behavior. Typically this is global menu modification, startup processing, or processing of delivery for all object types. The following subtypes are allowed:
Implementsbehavior local to the attachment viewer.
Implementsbehavior local to the browser window.
Implementsbehavior local to calendar windows.
Implementsbehavior local to the attachment viewer.
Implementsbehavior local to a document version list window.
Implementsbehavior local to the information window.
Implementsbehavior local to a query results window.
Record Type Taxonomy
The GroupWise 5 environment (both client and data access components) bind to the registered C3PO providers as the support mechanism for custom data types. The data types are implemented via the data store in GroupWise 5.
Figure 1: Relationship of C3PO data types and object classes.
As illustrated, each C3PO data type is associated with a specific object class designation. These object classes are hierarchical in nature, representing a subtyping relation. All behavior of an object, whether predefined, subclassed, or a newly instantiated type, is fully inheritable. For example, new methods introduced for new objects in the data store are fully inherited by any subtyped object.
Aggregations, delegation, and use of ancestor methods for implementation are fully supported. This is achieved by each C3PO writer having access to the instances of the C3PO servers for supertypes. The C3PO writer is thereby free to invoke ancestor methods for any reason, such as delegation, aggregation, and behavior modification.
C3POs support the notion of inheritance. That is, if class Msg.Foobar exists (along with the requisite object handler), the message class Msg.Foobar.Bif represents specialized behavior of Msg.Foobar. For example, when an action is attempted against a database record of type Msg.Foobar.Bif, the associated handler is passed contextual information (COM interfaces) that allow it to delegate behavior to ancestor classes. Individual C3PO servers are responsible for delegation semantics. The C3PO Manager code (C3POManager) allows the C3PO server to build various enumerators for proper aggregation and delegation semantics.
The inheritance scheme is substantially (though not fully) realized in the first GroupWise 5 release. Each C3PO component can navigate the tree of data types and use the facilities of other C3POs. This is achieved through use of the C3PO manager interfaces coupled with appropriate aggregation and delegation.
C3PO Classes and the Object API
C3PO classes are expressed in the GroupWise Object API as the MessageClass property on the message object and its derivatives. In terms of the GroupWise 5 engine-level API, this maps to the NGW_HWZ_ITEM_SUBTYPE field. This field represents, in the low-level GroupWise implementation, the subtype of the record in which it is found. For example, for a mail message with no further subtyping, the field is empty. For a message of type GW.MESSAGE.MAIL.XYZ, the subtype field contains XYZ.
GroupWise refers to these registry entries to invoke the C3PO handlers. All Registry entries appear as subkeys of the following entry:
Beneath this key appear entries for supported C3PO contexts. For example:
...\GW.MESSAGE.MAIL ...\GW.MESSAGE.MAIL.X ...\GW.CLIENT.WINDOW
Each registry section for a specific context contains subkeys used for naming the object server. The subkeys at this level are the PROGIDs of the COM servers for the C3PO. The value of each subkey is a description of the C3PO server. For example:
...\GW.MESSAGE.MAIL.X\Vendor.ObjName.Version = "My Description" ... \GW.MESSAGE.MAIL.X\Vendor2.ObjName2.Version = "Your Description"
These examples indicate that "Vendor.ObjName.Version" is the PROGID of the COM server supporting the C3PO. Beneath each PROGID key are further subkeys that clarify the use of the C3PO server. The subkeys are Objects and Events:
This key is required. It identifies the objects that are supported by the C3PO. This is an optimization to allow loading of the C3PO to be deferred. This is also a multi valued key. Each value names a particular object that is supported by the C3PO server. For example:
\ProgID\Objects = "CommandFactory" = "IconFactory"
Identifies the events for which the C3PO is interested in receiving notification messages. This is a multi valued key. Each value names a particular event. For example:
\ProgID\Events = "OnDelivery"" = OnReady = OnShutdown = Persistent Command ID
This optional key represents a series of language designations. The languages are precisely those supported by the component, which implies that multilingual support is accomplished by mapping from a single originating component into multiple languages. Presence of this section implies that the component can only operate in the target languages. Because LCID of 0' means any language, the restriction can be released by adding this key. Each language is specified by a subkey which is the LCID.
Some C3POs never generate any data records in the GroupWise 5 data store. These empty objects allow the C3POs to fully participate in menu modifications, toolbar negotiations, chaining of command extensions, and such without requiring the overhead of managing instance data. This allows a single set of extensions (the C3PO specification), rather than two or three, to be used for client extensions.
Typically, C3PO implementations that do not generate instance records should be registered under GW.APPLICATION. However, it is legal to register such C3PO implementations under other headings.
C3PO Instance Management
Each object in the GroupWise 5 data store has a message class field, which is a string. The Object Class ties a C3PO instance to the associated object handler hierarchy. The C3PO system supports the multiserver concept which allows multiple C3PO servers to register under a single C3PO name. However, certain C3PO operations can only operate on a single server, in which case the first server registered under the C3PO name is invoked.
* Originally published in Novell AppNotes
The origin of this information may be internal or external to Novell. While Novell makes all reasonable efforts to verify this information, Novell does not make explicit or implied claims to its validity.