Microsoft Foundation Classes                           Microsoft Corporation
Technical Notes

#9 : Writing an OLE Client Application

This note describes the classes and steps involved in creating
an OLE client application.

Please be sure to read the general MFC OLE overview first (TN008.TXT).

=============================================================================
Features of an OLE Client Application
=====================================

User Interface Features
-----------------------
The following list briefly describes some of the end-user features of a
typical OLE Client application. How the MFC OLE classes are used to provide
this support is described later.

1) Insert New Object dialog
    The menu item "Insert &New Object" usually resides on the "Insert"
    or "Edit" menu.  This menu item will bring up a dialog showing 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 will start out in a blank state - which means
    you must add data to it (by editing it in the server application)
    before it becomes useable by the end user.

2) Paste, Paste Link menu items
    The standard "Edit" menu will usually contain "Paste" and "Paste Link".
    If the client app only supports embedding, there will be no "Paste Link".
    These menu items will be enabled or disabled depending on the current
    contents of the clipboard.

3) Object menu item
    The bottom of the "Edit" menu will usually contain an "Object" menu item.
    This is a dynamic menu item that changes depending on the current
    selection.  If more than one verb is possible it will change into
    a popup menu listing all the verbs.

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

5) Insitu features
    The client document is reponsible for drawing the embedded/linked object
    data in the appropriate location.  Also supporting selection of items
    and/or ranges of items as well as non-embedded document components.
    Lastly double-clicking on an embedded/linked object should activate
    that object.

6) 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 as well as 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
-------------------
There are many other advanced features of an OLE Client than you can
implement on top of MFC OLE. These features are minimally supported in
the MFC OLE classes and are not well documented or illustrated in the
existing sample programs.  These will be added into future versions of
MFC OLE.

Additional information on these features can be found in the Windows 3.1
OLE documentation.

Features not supported:
    * Paste Special dialog (all the interfaces are there, but no canned
        dialog to make this easy).
    * Full support for UNDO (COleClientItem::CreateCloneFrom is provided,
        but a client app must still do a lot of extra work).
    * Full range of object creation options (for example creating from
        template, or creating from file).  Easy to add in your class derived
        from COleClientItem if needed, but this functionality is
        usually done with the MFC CFile and CArchive classes.
    * Clients using the server data for more than pictures.  In general
        a client will create an embedded/linked object with the
        standard draw option (olerender_draw).  This means the 
        client will just draw the embedded/linked object in a
        rectangle on the screen.  Other render options are available.
    * After loading a document which has manual links, the client app
        should prompt the user to see if they want to update links now.

=============================================================================
Tasks of an OLE Client Developer
================================

The Classes
------------
As mentioned in the overview, 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 will typically contain both OLE and non-OLE data.
Presumably you already have a class or two to manage non-OLE data in
your application (i.e. to store, display, hit detect the contents
of a Window's client area).
You must decide how OLE data will mix with the non-OLE data.
If your non-OLE data is stored as a CObject* collection, then there is
no extra work needed (since an OLE item is a CObject as well).
If not, you will have to extend your data structures so that they can
contain a client item wherever you want to mix OLE and non-OLE data.

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

You must register your client document when it is created (using 'Register').
Also there are specific notification routines that must be called:
    NotifyRename        - call after document has been renamed by user
    NotifyRevert        - call after document has been reverted to original
                        (i.e. re-opened ignoring recent changes)
    NotifySaved            - call after document has been saved to disk

All of these steps are covered in the OCLIENT sample program.
The class CMainDocument 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.  Class 'COleClientItem' provides a base class that is used
to keep 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.

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

Your client item objects (derived from COleClientItem) will be created
in several end-user scenarios: (see below for how to implement these)
    * with the InsertNewObject dialog
    * when pasted from the clipboard (paste or paste-link)
    * when loaded from an existing file

You must override the member function 'OnChange' which is a callback
that notifies the client that the server has changed.  There are three
reasons the client item may change: a linked item is changed (with
automatic notification turned on), the document edited on the server
is saved or the document edited on the server is closed.

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

All of these steps are covered in the OCLIENT sample program.
The class CEmbeddedItem 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, like out of memory, or can't launch server will
result in a COleException being thrown.  A COleException object
can be examined to see what OLESTATUS error code caused the problem.
If a set of conditions are expected, the MFC OLE member function will
return 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 API function call.

Asynchronous Requests
---------------------
The member function COleClientItem::WaitForServer is used
to synchronize the client with the server.  If a server request can't
be finished immediately, the client application will wait inside of
'WaitForServer' until the operation is complete (successful or not).
The client code calling this just sees a simple synchronous call.

While the client app is waiting it will continue to dispatch windows
messages.  The static member function 'COleClientItem::InWaitForServer'
can be used to see if the client application is already nested in
a server request.  See the OCLIENT sample app for an example of the
use of 'InWaitForServer'.

Advanced users may wish to override 'WaitForServer' and customize
it's behavior as appropriate.  See the OCLIENT sample app for an
example of how to turn on the hourglass when a client operation
is going to take too long as the result of a server not being ready.

Implementing the UI features
----------------------------
The following gives a brief overview of what you must do to implement
the major User Interface features of OLE for your client application.
See above for the list of 6 major UI features.  See the OCLIENT sample
program for a working example of how to implement these features.

1) Insert New Object dialog
    (a) call 'AfxOleInsertDialog' to prompt the user for class name
    (b) create an object of your COleClientItem derived class using
            'COleClientItem::CreateNewObject'.
    (c) insert it at the current document (eg: at the insertion point
            if applicable to your application).

2) Paste, Paste Link menu items
    (a) create menu items for "Paste" and, optionally, "Paste Link"
    (b) override OnInitMenu or OnInitMenuPopup in your main frame window
        (i) call 'COleClientItem::CanPaste' to determine if you
            can paste or not and enable menu item accordinglly
        (ii) call 'COleClientItem::CanPasteLink' to determine if you
            can paste link or not and enable menu item accordinglly

    (c) when either is selected, use CreateFromClipboard or
        CreateLinkFromClipboard to create the new object from clipboard.

3) Object menu item
    This is a complicated UI which is provided for you in the standard
    MFC OLE library.
    (a) create menu items for "Object" with special ID value
    (b) as with Paste, override OnInitMenu or OnInitMenuPopup in
            your main frame window
    (c) call 'AfxOleSetEditMenu' with the item, menu, and the position where
            to store the 'Object' menu in the specific popup.

4) Links dialog
    (a) add a "Links" menu item to the "Edit" menu popup
    (b) when the user selects the "Links" menu item, call 'AfxOleLinksDialog'
    (c) you can disable the menu item either if no linked items are
        selected, or if the document does not contain linked items.
        (by overriding OnInitMenu or OnInitMenuPopup in
        your main frame window).

5) Insitu features
    This is the most work.
    (a) when your window gets an OnPaint request, it must draw the
    COleClientItem by calling 'Draw'.  This draw routine is passed
    a DC and a bounds rectangle.
    (b) depending on your model of selection - you probably want to support
    selection of linked/embedded items
    (c) perhaps support resizing of embedded items - call SetBounds to
    change the size.
    (d) lastly, when the user double-clicks on a client item, it should
    be activated by calling 'Activate'.  Overriding OnLButtonDblClk
    in the appropriate window class.

6) Object as part of a document
    (a) provide an implementation of Save/load that uses the CArchive
        serialization mechanism.
    (b) implement Serialize for your derived COleClientItem class, and
        be sure to call the base class COleClientItem::Serialize, since
        this will save the embedded/linked object information.

=============================================================================
Other Issues:
=============

Building
--------
Assuming you are already building a normal MFC windows application,
you must do the following additional steps:

    * include 'afxole.h' in those source files using MFC OLE (this will
        include 'afxwin.h' if not included already).
    * Link with the appropriate MFC library as usual.
    * You will also need to link with two 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
    * you must 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 UI parts of the OLE support.

    * Warning: the OLE Links dialog may call COMMDLG to prompt
        the user for a new filename.  This requires a reasonable
        amount of stack space (8K or more).

Testing
-------
There are two test programs provided in source form in the MFC SAMPLE
directory.

        TESTCLNT    - a test client (i.e. used to test servers)
        TESTSERV    - a test server (i.e. 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 more details on these test programs.

Debugging
---------
See TN007.TXT for a description of the 'afxTraceFlags' options for
doing advanced debugging.  The multi-application debugging option
(option 1) is extremely useful, especially if you are debugging a
client and a server at the same time.

The main message pump reporting (option 2) is very 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
sample of a OLE Client application.  It exploits all of the user interfaces
provided by MFC OLE.
It is a good example since it is relatively simple.
It is a poor example since each embedded/linked items is stored in a
CWnd (a CItemWnd).  In general embedded/linked items are normally
drawn as part of your client area.

=============================================================================
