Programming Guide: Run-Time Environment

# Programming Guide

## Run-Time Environment

The run-time model for the execution of part editors in the OpenDoc environment is different from that of conventional applications. This section discusses those differences in terms of the run-time process model, System Object Model run-time issues, and the part wrapper object. It also discusses name spaces, a run-time service provided by OpenDoc.

### OpenDoc Run-Time Process

The OpenDoc document-centered approach requires a run-time process model significantly different from the classic application-centered process model. On personal-computer platforms, each process is usually owned by an application. This process provides the address space in which the application code executes, as well as the memory for every document opened by that application. The operating system assigns a document to a process based on the document's type, an indication of which application created it.

In OpenDoc, a document no longer has a single type, but is instead composed of many parts that may be of different types. Thus the document, not any application, is the owner of the process. The document manages standard tasks such as handling the event loop, managing files, printing, and interacting with system menus, dialog boxes, and so on. In OpenDoc, some of this behavior is provided by an executable called the document shell. The fact that individual parts in a document share this code is one reason why part editors can be significantly smaller than conventional applications.

The document shell has the following basic responsibilities:

- It creates and initializes the session object, which in turn creates and initializes the other session-wide OpenDoc objects, as shown in Figure 71.

- It opens the document chosen by the user.

- It accepts events and passes them to the OpenDoc dispatcher.

- It handles certain document-wide menu commands.

The executable code of part editors is stored and accessed as DLLs independent of any process. (Part-editor code must be reentrant because several instances of a part in a single document may use the same editor). What the process provides is an address space for the contents of a particular document, along with any additional memory needed by the individual part editors. All state information used by any part editor is, with some minor exceptions, maintained in the processes of those documents that contain parts manipulated by the editor.

### Dynamic Linking and System Object Model

Two cornerstones of the OpenDoc run-time environment are dynamic linking, which allows compound documents to be assembled at run-time, and a language-neutral object model, which facilitates run-time compatibility of parts and minimizes the recompilation required by changes to OpenDoc or to part editors.

Dynamic linking is provided by the base operating system. The object model used by OpenDoc is the System Object Model (SOM). This section introduces some run-time aspects of dynamic linking and SOM that are of interest to part-editor developers. (The particulars of writing SOM-based code are discussed in "Developing with SOM and IDL").

#### Dynamic Linking

OpenDoc depends on dynamic linking to allow the appropriate executable code to be added to the run-time environment of a document. Before a document is opened, there is no way of knowing what part editors may be needed to manipulate its contents. Dynamic linking has the following capabilities:

- It allows an executable module to be loaded into memory once and then shared by multiple processes.

- It allows dynamically linked code to call code contained in another dynamically linked library.

- It gives dynamically linked code access to global variables.

#### SOM and Distributed Dispatching

System Object Model (SOM) objects are CORBA-compliant, meaning that they follow the language-neutral distributed standards of the Common Object Request Broker Architecture (CORBA), established by the Object Management Group (OMG), an industry consortium. This compliance means that objects compiled in different languages or with different compilers can communicate with each other.

SOM objects running on different machines can communicate with each other. This distributed dispatching may be a future capability of OpenDoc and is therefore supported in these basic architectural features:

- Almost all objects are instantiated by factory objects, rather than by constructors called by your part. See Table 12 for a list of the factory objects.

#### SOM Exception Handling

OpenDoc objects are SOM objects, and as such they follow the CORBA rules for handling exceptions. Every method call made to an OpenDoc object (including your part, as a subclass of ODPart) must therefore include an environment parameter (ev), a pointer to a value that can describe an error. For example, the CreateLinkSource method of ODDraft has the following prototype (in IDL):

    ODLinkSource CreateLinkSource(in ODPart part);

The method takes a single parameter, of type ODPart. To use this method, however, a caller in C++ must supply two parameters:

    MyLinkSource = MyDraft->CreateLinkSource(ev, somSelf);

If execution of the method results in an error condition, the receiver of the call (the draft object in this case) must place an exception code in the value pointed to by ev and return. The caller must examine the ev parameter after every call to a SOM object, to see if an exception has been raised.

All OpenDoc methods that you call, as well as all public methods of your part editor that you write, must return errors this way. These are the implications for your exception handling:

- You must supply an environment variable with all method calls to OpenDoc objects.

- You must check the environment variable after the call returns.

- You must set an environment variable, if appropriate, in ODPart methods that you override.

The environment variable is passed along through a sequence of calls and can be used in calls to both SOM and C++ objects. Here is how you can use it correctly:

- If your SOM method calls another SOM method, it can simply pass on the environment parameter it has received. This is the usual case, since your part editor executes only in response to calls to its SOM interface, and thus should always have received a value for the environment variable.

- If your SOM method calls a C++ method that may in turn call a SOM method, your SOM method can pass the environment parameter on to the C++ method (if the C++ method was designed to accept it; see next bullet)

- If your C++ method is called by a SOM method and in turn makes calls to SOM methods, it is best to design it to accept an environment parameter that it can then pass on.

- If your C++ method (that does not itself receive an environment parameter) calls a SOM method, it can use a function provided by SOM (somGetGlobalEnvironment) to obtain a value for the environment variable.

For more information on the environment parameter and exceptions, see SOMObjects Developer Toolkit Users Guide and SOMObjects Developer Toolkit Programmers Reference

Any exception-handling scheme that you use must support this method of passing exceptions. See "Exception Handling".

### Part-Wrapper Object

Your part first initializes itself when OpenDoc calls its InitPart or InitPartFromStorage methods, as described in "Initializing and Reading a Part from Storage". At that time, OpenDoc passes your part an object reference in the partWrapper parameter of InitPart or InitPartFromStorage. That reference is to a part-wrapper object, a private object that OpenDoc instantiates and uses to represent your part.

The part wrapper keeps other parts of OpenDoc from having direct pointers to your part object; its only function is to delegate methods of ODPart to your part. Using a part wrapper gives OpenDoc more flexibility in manipulating parts. For example, use of a part wrapper allows OpenDoc to switch editors for a part without having to close and reopen the part's document.

You must use that part-wrapper reference in all calls to the OpenDoc interface that require you to pass a reference to yourself. (Typically, if your part object keeps a field such as fSelf to hold a reference to itself, that field should contain the part-wrapper reference.) Specifically, you should never pass somSelf as a parameter to any OpenDoc method, except when accessing objects such as extensions and embedded-frame iterators for which your part itself is the factory.

Part-wrapper methods

The interface to ODPart includes three part-wrapper methods: IsRealPart, GetRealPart, and ReleaseRealPart. OpenDoc provides these methods for the exclusive use of the part-wrapper object, and calls the methods when associating your part with or disassociating it from its part wrapper. When you subclass ODPart to create your part editor, do not override these methods.

### Name Spaces

Each OpenDoc session provides a run-time service allowing you to define name spaces. A name space is an object that maps data types to values. It consists of a set of string-value pairs, whose purpose is to associate the string (an ISO string) with the value (a four-byte unsigned value, which could be a pointer to code).

For example, OpenDoc uses name spaces to represent the preferences of the user for binding parts (whose part kinds are represented by ISO strings) to part editors (represented by pointers to editor IDs).

Name spaces are a general-purpose run-time registry mechanism. You can use them to define global spaces in which to share information with other parts. You can define as many name spaces as you wish; the OpenDoc Name Space Manager keeps a list (which is itself a name space) of all currently defined name spaces.

For example, you can use a name space to create palettes or other controls to be shared among several parts. Use an ISO string to identify the name space itself and ISO strings to identify each of the controls it encompasses. You then can get pointers to the controls (if the name space has already been instantiated) or instantiate the name space and provide pointers to the controls (if your part is the first in the session to use the name space).

If you publish the ISO strings that define your name space and its contents, the name space can be used publicly. If you do not publish the names, you can still use the name space for your own private globals.

[ Top | Previous | Next | Contents | Index | Documentation Homepage ]