MFC TN009--Writing an OLE Client Application

Created: April 15, 1992

ABSTRACT

This technical note describes the classes and steps involved in creating an object linking and embedding (OLE) client 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 CLIENT APPLICATION

User Interface

The following list briefly describes some user interface features of a typical object linking and embedding (OLE) client application.

Insert New Object dialog

The Insert New Object menu item usually resides on the Insert or Edit menu. Selecting this menu item brings up a dialog box that shows all the available class names (from the registered OLE servers in the system). The selected class name is used to create a new object of that type and insert it into the client document. The new object starts out in a blank state. You must add data to it (by editing it in the server application) before it can be available to the user.

Paste, Paste Link menu items

The standard Edit menu usually contains Paste and Paste Link. If the client application supports only embedding, Paste Link does not appear. These menu items are enabled or disabled depending on the current contents of the Clipboard.

Object menu item

The bottom of the Edit menu usually contains an Object menu item. This is a dynamic menu item that changes when the current selection changes. If more than one verb is possible, the Edit menu becomes a pop-up menu that lists all the verbs.

Links dialog box

This is the standard dialog box used to view, fix, and otherwise manipulate all links in the current document.

In situ features

The client document is responsible for drawing the embedded/linked object data in the appropriate location. The client document is also responsible for supporting selection of items and/or ranges of items as well as non-embedded document components. Double-clicking on an embedded/linked object should activate that object.

OLE items as part of a document

The embedded/linked items are maintained as part of the document. When the document is saved, so are the embedded items and the links to the linked items. When the client document is loaded from disk, the reverse happens, and the embedded/linked items are loaded as part of the document. If your current client application (or the one you are planning) does not have documents or “load” and “save” functionality, you may want to implement an OLE server instead.

Additional Features

You can implement many other advanced features of an OLE client on top of MFC OLE. These features are minimally supported in the MFC OLE classes and are not well documented or illustrated in the sample programs. These will be added into future versions of MFC OLE. The MicrosoftÒ WindowsÔ version 3.1 OLE documentation contains additional information on these features.

Features Not Supported

Paste Special dialog box (all interfaces exist, but there is no canned dialog box to make this easy).

Full support for Undo (COleClientItem::CreateCloneFrom is provided, but a client application must still do a lot of extra work).

Full range of object creation options (for example, creating from template or creating from file). If necessary, you can easily add this functionality to your class derived from COleClientItem, but it is usually done with the MFC CFile and CArchive classes.

Clients using the server data for more than pictures. In general, a client creates an embedded/linked object with the standard draw option (olerender_draw). The client simply draws the embedded/linked object in a rectangle on the screen. Other render options are available.

After loading a document that has manual links, the client application should prompt the user to see if she or he wants to update links now.

TASKS FOR CREATING AN OLE CLIENT

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

The Classes

The MFC OLE classes require that you derive your own document and item classes from the MFC OLE base classes.

The document class defines the structure of how items are managed. The item class defines the structure of how linked and/or embedded OLE items fit into your application.

Creating the document class

Your client document typically contains both OLE and non-OLE data. Presumably you already have a class or two to manage non-OLE data in your application (for example, to store, to display, to detect mouse actions in a window’s client area).

You must decide how OLE data will mix with non-OLE data. If your non-OLE data is stored as a CObject* collection, no extra work is needed (because an OLE item is a CObject as well). If your non-OLE data is not stored as a CObject*, you must extend your data structures so that they can contain a client item wherever you want to mix OLE and non-OLE data.

The COleClientDoc class provides a base class to contain embedded items. You must derive your own document class from COleClientDoc. Be sure to override the GetNextItem member function to iterate over all the OLE items in the document (the interface is similar to MFC lists).

You must register your client document when it is created (using Register), and 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.

The OCLIENT sample program covers all these steps. The CMainDocument class is attached to CMainWnd, and together they serve as the main client document.

Creating the item class

Your client item is the client-side view of the linked or embedded OLE object. The COleClientItem class provides a base class for extra application-specific information about each linked/embedded item. The position of the item in the client document is an example of extra member data you can add to your class derived from COleClientItem.

Because a COleClientItem must always be in a COleClientDoc, the containing document must be passed as a parameter to the constructor.

Your client item objects (derived from COleClientItem) can be created with the Insert New Object dialog box, when pasted from the Clipboard (paste or paste-link), or when loaded from an existing file.

You must override the OnChange member function, which is a callback that notifies the client that the server has changed. The client item can change if a linked item is changed and automatic notification is turned on, if the document edited on the server is saved, or if the document edited on the server is closed.

In general, do not redraw the client item when you get the OnChange callback, but post an update message (or use InvalidateRect for the window).

The OCLIENT sample program covers all these steps.

The CEmbeddedItem class is attached to CItemWnd, and together they provide both the data and user interface to the client item.

Checking Errors and Catching Exceptions

Abnormal conditions, such as out of memory or the inability to launch a server, result in a COleException being thrown. You can examine the COleException object to see which OLESTATUS error code caused the problem. If a set of conditions are expected, the MFC OLE member function returns a BOOL. If the BOOL returns FALSE, a more detailed error report can be determined by COleClientItem::GetLastStatus, which returns the OLESTATUS of the last OLE function call.

Handling Asynchronous Requests

The COleClientItem::WaitForServer member function synchronizes the client with the server. If a server request cannot be finished immediately, the client application waits inside WaitForServer until the operation is complete (successful or not). The client code calling this member function sees only a simple synchronous call.

While the client application waits, it continues to dispatch Windows messages. You can use the COleClientItem::InWaitForServer static member function to determine whether the client application is already nested in a server request. See the OCLIENT sample program for how to use InWaitForServer.

Advanced users may want to override WaitForServer and customize its behavior as appropriate. See the OCLIENT sample program for how to turn on the hourglass when a client operation is expected to take too long because the server is not ready.

IMPLEMENTING THE USER INTERFACE

The following is a brief overview of how to implement the major user interface features of OLE for your client application. See the OCLIENT sample program for information on implementing these features.

Insert New Object Dialog Box

1.Call AfxOleInsertDialog to prompt the user for class name.

2.Create an object of your COleClientItem derived class using COleClientItem::CreateNewObject.

3.Insert the object in the current document (for example, at the insertion point if applicable to your application).

Paste, Paste Link Menu Items

1.Create menu items for Paste and, optionally, Paste Link.

2.Override OnInitMenu or OnInitMenuPopup in your main frame window.

Call COleClientItem::CanPaste to determine whether you can paste and then enable the menu item accordingly.

Call COleClientItem::CanPasteLink to determine whether you can paste link and then enable the menu item accordingly.

3.When either is selected, use CreateFromClipboard or CreateLinkFromClipboard to create the new object from the Clipboard.

Object Menu Item

This user interface is complicated and is in the standard MFC OLE library.

1.Create menu items for Object with special ID values.

2.Override OnInitMenu or OnInitMenuPopup in your main frame window.

3.Call AfxOleSetEditMenu with the item, menu, and the position at which to store the Object menu in the specific pop-up.

Links Dialog Box

1.Add a Links menu item to the Edit menu pop-up.

2.When the user selects the Links menu item, call AfxOleLinksDialog.

3.You can disable the menu item (by overriding OnInitMenu or OnInitMenuPopup in your main frame window) if no linked items are selected or if the document contains no linked items.

In Situ Features

1.When your window receives an OnPaint request, it must draw the COleClientItem by calling Draw. This routine is passed a device context (DC) and a bounds rectangle.

2.You may want to support selection of linked/embedded items, depending on your model of selection.

3.To support resizing of embedded items, call SetBounds to change the size.

4.When the user double-clicks a client item, call Activate to activate the item that is implemented by overriding OnLButtonDblClk in the appropriate window class.

Object as Part of a Document

1.Provide an implementation of save/load that uses the CArchive serialization mechanism.

2.Implement Serialize for your derived COleClientItem class, and be sure to call the COleClientItem::Serialize base class. Doing so saves the embedded/linked object information.

OTHER ISSUES

Building

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

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

Link with the appropriate MFC library as usual.

Link with three additional libraries:

OLECLI.LIB interfaces to the client-side OLE APIs.

SHELL.LIB interfaces to the registration API.

COMMDLG.LIB interfaces to the common dialog API.

Include the standard client resources by including AFXOLEUI.H and AFXOLEUI.RC in your client application’s RC file. This includes the dialog templates and standard strings for the user interface parts of the OLE support.

Warning:

The OLE Links dialog box may call COMMDLG to prompt the user for a new file name. This requires 8K or more stack space.

Testing

Two test programs are provided in source form in the MFC SAMPLE directory:

TESTCLNT: A test client (used to test servers)

TESTSERV: A test server (used to test clients)

You will probably want to use TESTSERV or some other OLE server to test your application. See the contents of the sample source directories for details on these test programs.

Debugging

See “Windows Debugging and Trace Options” (TN007) for a description of the afxTraceFlags options for advanced debugging:

The multi-application debugging option (option 0x01) is extremely useful, especially if you are debugging a client and a server at the same time.

The main message pump reporting (option 0x02) is useful when you are trying to figure out which messages are being dispatched.

Option 0x10 is provided specifically for OLE debugging and turns on some rather verbose reporting messages informing you what is going on in the MFC OLE classes.

SAMPLE CODE

In addition to the test programs, the OCLIENT sample provides a simple example of an OLE client application. This sample exploits all of the user interfaces provided by MFC OLE.