MFC TN010--Writing an OLE Server Application

Created: April 15, 1992

ABSTRACT

This technical note describes the classes and steps involved in creating an object linking and embedding (OLE) server application.

The Microsoft Foundation Class (MFC) library provides a full-featured set of C++ object classes for the MicrosoftÒ WindowsÔ graphical environment. It includes classes that directly support application development for Windows as well as general-purpose classes for collections, files, persistent storage, exceptions, diagnostics, memory management, strings, and time. Each MFC technical note describes a feature of MFC using code fragments and examples.

FEATURES OF AN OLE SERVER APPLICATION

User Interface

The following are some of the user interface features of a typical object linking and embedding (OLE) server application.

Editing embedded data

OLE servers support editing embedded data, that is, data stored in a client document and given to the server to edit or display. When the server is closed, the data is given back to the client document so it can be saved. When the user is editing an embedded document with a server, the Save menu item in the File menu should change to Update.

Editing linked data

A server may optionally support linking to server documents, in which case it allows users to open normal files and copy data to the Clipboard in addition to letting them edit embedded data. Data updated in the server can automatically be updated in the client. The client may turn on automatic updates if desired.

SDI vs. MDI user interface

Because multiple client applications can use embedded or linked data simultaneously, multiple server support is necessary. An application with a single document interface (SDI) must support multiple instances of the server (that is, a new instance of the server application is launched for each edited document). In server applications that support links or that have a multiple document interface (MDI), one instance of the application responds to all OLE client requests (that is, the server creates a new CMDIChildWnd for each document).

Additional verbs

All OLE client applications provide access to the primary verb for an embedded or a linked object. This primary verb is usually Edit. You may define additional verbs and present them in the OLE client’s Edit menu when the user selects the embedded (or linked) object. You can add these additional verbs by registering the server with the AfxOleRegisterServerName function or with a setup program.

Additional Features

You may implement many other advanced features of an OLE server on top of MFC OLE, for example:

You can add support for multiple data formats. MFC OLE supports Native format and metafile drawings by default.

OLE servers need not be visual nor have a complete user interface. For example, Note-It and sound players are simple servers that support embedding.

OLE servers can support multiple types. For example, MicrosoftÒ Excel supports charts and spreadsheets.

OLE servers can support generic dynamic data exchange (DDE) Execute commands. See the OnExecute member functions.

It is possible to support links but not embedding, although this is not typical.

MFC OLE does not support OLE handlers (these are dynamic link libraries that improve the efficiency of server operations). OLE handlers can be written using the OLE application programming interface (API) and can talk to an OLE server application written with OLE MFC.

TASKS FOR CREATING AN OLE SERVER

Steps for creating an OLE server application include creating the server, document, and item classes, checking errors and exceptions, handling asynchronous requests, and implementing the user interface.

The Classes

The MFC OLE classes require that you derive your own classes from the MFC OLE base classes. You must provide at least three derived classes, one for the server application, one for the server document, and one for the server items.

The server manages server documents and is notified when clients want to open or edit server documents. The server document class defines the structure of how items are managed. The server item class defines the structure of how linked and/or embedded OLE items fit into your application.

Typically, your application has only one server object. You need multiple server objects only if you want to support multiple OLE types. Each document has one server document object. An SDI multi-instance application has one document. An MDI single-instance application has one document for each MDI child window. Each document has one or more server items.

Creating the server class

The COleServer class provides a base class used for all global server management. You must derive your own document class from COleServer and override several member functions:

OnCreateDoc—Create a new server document.

OnEditDoc—Edit an existing server document.

For servers that support links, you must also implement:

OnOpenDoc—Open an existing document

In all cases, you should create a new object of your server document class (derived from COleServerDoc) and return it. Do not register this server document.

Creating the document class

The COleServerDoc class provides a base class to contain server items. You must derive your own document class from COleServerDoc and override several member functions:

OnGetDocument—Return a new item representing the entire document.

OnGetItem—Return a new item representing the named part of the document.

In both cases, you should create a new object of your server item class (derived from COleServerItem) and return it.

For applications that support links, you should create a server document for every named file. If the server document is not opened as a result of a COleServer request such as OnCreateDoc or OnOpenDoc, you must explicitly register the document (for example, when the user opens an existing file using File Open) with the Register member function. You can use Revoke to revoke the document.

When the server document changes, you must call specific notification routines:

NotifyRename—Call after user has renamed document.

NotifyRevert—Call after document has reverted to original (that is, after it is reopened ignoring recent changes).

NotifySaved—Call after document has been saved on disk.

Additional notifications include:

NotifyClosed—Closed notification for old OLE servers (NotifySaved and Revoke are usually enough).

NotifyChanged—Notification of global document changes.

Creating the item class

Your server item is the server-side view of the linked or embedded OLE object. The COleServerItem class provides a base class for all native data required to manage the server data and additional user interface data.

A COleServerItem must always be contained in a COleServerDoc. If the server item is created as a result of a COleServerDoc callback (OnGetDocument or OnGetItem), no extra work is needed. Do not create server items outside these callbacks.

You must override several member functions:

Call OnShow when the item is to be shown. It should scroll the specific item into view and set the focus to it, if appropriate.

Call OnDraw when the item is to be drawn. (An item is drawn into a metafile device context, not into a screen device context.)

Serialize is part of the normal CObject serialization.

Serialize is the means for getting the native data. You must implement Serialize in your item class to load and store all important native data for your server item. COleServerItem::Serialize is a pure virtual function, so do not call it as part of your serialize operation.

Flow of Control

The following scenario is used to create a new embedded object (from Insert New Object in the client application):

The server is asked to create a new document (OnCreateDoc).

The server document is asked to get an item representing the entire document (OnGetDocument).

The server item is shown, but the client still has a “blank” item.

When the user saves the server document (for example, with File Update), the client is updated.

The following scenario is used to edit an existing embedded object:

The server is asked to create a new document (OnCreateDoc).

The server document is asked to get an item representing the entire document (OnGetDocument).

The server item is deserialized from the data provided by the client from a previous serialization.

The server item is shown.

When the user saves the server document (for example, with File Update), the client is updated.

The following scenario is used to edit a linked object:

The server is asked to create a new document (OnCreateDoc).

The server document is asked to get an item representing the entire document (OnGetDocument) or a part of the document (OnGetItem), depending on how the link was stored.

The server item is shown.

Checking Errors and Catching Exceptions

Some callbacks from the server, from the server document, or from server items return OLESTATUS codes. These should follow the conventions of the OLE API (that is, they should return OLE_OK if OK or another OLESTATUS code such as OLE_ERROR_GENERIC if there is an error). Other callbacks that return more useful information may throw exceptions in the server or, if possible, simply return a NULL value (for example, for OnCreateDoc in the COleServer).

Handling Asynchronous Requests

When inside a callback from a server, a server document, or a server item, you should not perform a modal operation or anything that causes your application to call GetMessage or PeekMessage. The debugging version of the MFC CWinApp class has special ASSERT statements that catch scenarios in which server code calls the main message pump when it shouldn’t.

IMPLEMENTING THE USER INTERFACE

The following is a brief overview of how to implement the major user interface features of OLE for your server application. The four major user interface features were discussed earlier. See the OSERVER and TESTSERV sample programs. OSERVER supports embedding; TESTSERV supports linking and embedding.

Editing Embedded Data

When your program executes, examine the command-line argument in InitInstance. Check for the special –Embedding or /Embedding flag, which determines whether this application was launched for embedding.

When constructing a server object (that is, an object of your class derived from COleServer), pass TRUE to the constructor if the application was launched for embedding. If so, the server application automatically shuts down when client applications are no longer connected to it.

The basic structure of the server/server document/server item provides most of what is needed for editing embedded data. If your application also links to files, be sure to change the File Save menu item to File Update.

Editing Linked Data

There are additional ways to access linked data. Server applications that support links should look for a file name after the embedding flag on the command line. If found, this file should be opened first.

For a client to paste a link to your server application, you must copy a link to the Clipboard. See the TESTSERV program for an example of this.

Because clients may want immediate updates, the NotifyChanged operation in COleServerItem can be used to notify the client of a specific change. In general, the client is notified of changes to all server items (embedded and linked) when the server document is saved (that is, when NotifySaved is called).

SDI vs. MDI User Interface

Building an SDI or MDI application is exactly like building an MFC WindowsÔ application. Additionally, you must register your server. Call the Register function with the OLE class name (nonlocalized) and a BOOL indicating whether your application allows multiple instances.

SDI <==> multiple instance (one CFrameWnd per document)

MDI <==> single instance (usually one CMDIChildWnd per document)

Additional Verbs

Additional verbs must be defined in the registration database. (Steps for creating a REG file are explained in the next section.) To handle additional verbs, override COleServerItem::OnExtraVerb and do a switch on the passed verb number. You should return OLE_ERROR_DOVERB for verbs you don’t understand. The primary verb 0 is handled automatically by the default OnShow member function.

CREATING A REG FILE

To provide the OLE system with information about your OLE server, you must add this information to the system registration database. The sample OSERVER.REG file provides a basic structure. Follow the additional steps below.

You can use the AfxOleRegisterServerName function to place the information in the registration database. This function automatically registers the server when you run the server from the Program Manager, from the File Manager, or by clicking an icon and keeps up with any changes in the server location. To use AfxOleRegisterServerName, simply call it within your application’s InitInstance function. The function takes a class name and a human-readable name as parameters (see the second and third steps below).

Steps for Writing and Customizing a REG File

1.Start from an existing REG file from the source directory of an OLE sample program.

2.Pick an OLE class name for each OLE object type. Use your company’s name or your initials at the beginning of the name to avoid collisions. Do not use spaces in the name. Sample class names are “MSGraph” and “JOE_CHART”.

3.Provide a human-readable form of the OLE class name. This is what users will see in the Insert New Object dialog box and other user interfaces. This name may contain spaces, for example, “Microsoft Graph” or “Joe’s Cool Chart Thing”.

4.Provide the path indicating where your server application will be installed. Place each server in a subdirectory of the Windows system directory (usually C:\WINDOWS\OLEAPPS\MYSERVER). If the server is going to be on the search path when Windows is running, you need not specify an absolute path.

5.If you have a standard suffix for all your data files, add that to the registration file.

6.If you have additional verbs for your server data, add them starting with index 0. (Use index 0 as the standard Edit verb.)

7.Save the registration file, using the same name as your server (for example, if you are building MYSERVER.EXE, name the file MYSERVER.REG).

OTHER ISSUES

Building

If you are already building a normal MFC Windows-based application, you must take the following additional steps:

1.Include AFXOLE.H in those source files that use MFC OLE (this includes AFXWIN.H if not included already).

2.Link with the appropriate MFC library as usual.

3.Link with two additional libraries:

OLESVR.LIB interfaces to the server-side OLE APIs.

SHELL.LIB interfaces to the system registration database.

TESTING AND DEBUGGING

See “Windows Debugging and Trace Options” (TN007) and “Writing an OLE Client Application” (TN009) for tips on debugging OLE applications.