Microsoft KB Archive/104139

From BetaArchive Wiki
Knowledge Base


Object Creation Overview

Article ID: 104139

Article Last Modified on 12/3/2003



APPLIES TO

  • Microsoft OLE 2.0
  • Microsoft OLE 4.0, when used with:
    • Microsoft Windows NT 4.0
    • Microsoft Windows NT 3.51 Service Pack 5
    • Microsoft Windows NT 4.0
    • Microsoft Windows 95



This article was previously published under Q104139

SUMMARY

The actual process of creating an OLE object can seem confusing when first learning OLE. To elucidate the object creation process, this article describes the steps taken by the OLE 2.0 libraries in response to a call to OleCreate(), with the OLERENDER_DRAW format passed as the renderopt parameter. This article gives a basic overview of the object creation process; it does not describe specific application programming interfaces (APIs) in detail.

MORE INFORMATION

Typically, the container application presents the user with a dialog box containing the various types of objects that can be created on a particular system. These object types are enumerated from the Registration Database--each entry in the database has a name that the user can understand, as well as a unique identifier for the object type called a CLSID.

The container tells OLE that it wants to create an object. At this point, the container gives OLE the CLSID of the desired object, a pointer to a child storage within the container's compound file, and a pointer variable for OLE to return a pointer to a requested interface (typically IOleObject):

    Container         OLE
   -----------    -----------
   |OleCreate|--->|         |
   |         |    |         |
   |         |    |         |
   |         |    |         |
   |         |    |         |
   |         |    |         |
   -----------    -----------
                

The OLE libraries then consult the registration database to find the name of the executable file associated with the CLSID:

    Container         OLE
   -----------    -----------
   |OleCreate|--->|         |
   |         |    |         |
   |         |    |         |
   |         |    |         |
   |         |    |         |
   |         |    |         |
   -----------    -----------
                    |
                    V
                 Reg DB
                

The server is then started with the -Embedding flag. When the server parses the command line and sees the -Embedding flag, it knows that it is being started on behalf of OLE and should remain hidden until it is explicitly told to become visible. At this point, the server registers a pointer to its IClassFactory interface with OLE:

    Container         OLE           Server
   -----------    -----------    -----------------
   |OleCreate|--->|         |--->|               |
   |         |    |         |<---| IClassFactory |
   |         |    |         |    |               |
   |         |    |         |    |               |
   |         |    |         |    |               |
   |         |    |         |    |               |
   -----------    -----------    -----------------
                    |
                    V
                 Reg DB
                

OLE calls the server through the IClassFactory interface and asks to instantiate an object, returning the pointer to the interface requested by the container in the creation routine:

    Container         OLE           Server
   -----------    -----------    ------------------
   |OleCreate|--->|         |--->|                |
   |         |    |         |<---| IClassFactory  |
   |         |    |         |--->| -------------  |
   |         |    |         |<---|-|IOleObject |  |
   |         |    |         |    | |IDataObject|  |
   |         |    |         |    | |    etc    |  |
   |         |    |         |    | -------------  |
   -----------    -----------    ------------------
                    |
                    V
                 Reg DB
                

OLE queries the object for the IDataObject interface, and then calls GetData method to fill the presentation cache with a metafile, device-independent bitmap (DIB), or a bitmap. Later, when the container asks the object to draw itself, OLE will intercept the call and use one of the entries in the presentation cache:

    Container         OLE           Server
   -----------    -----------    ------------------
   |OleCreate|--->|         |--->|                |
   |         |    |         |<---| IClassFactory  |
   |         |    |         |--->| -------------  |
   |         |    |         |<---|-|IOleObject |  |
   |         |    |         |    | |IDataObject|  |
   |         |    |         |    | |    etc    |  |
   |         |    |         |    | -------------  |
   -----------    -----------    ------------------
                    |      |
                    V      v
                Reg DB  Cache
                

At this point, the creation routine returns to the container. Now, the container will generally query the interface pointer returned for the IViewObject interface. The container uses the IViewObject interface to ask the object to notify the container (through the container's IAdviseSink interface) every time the object's view changes, so that the container can update its display. At this point, the server creates an advise holder to notify the object of its changes:

    Container             OLE              Server
   --------------    -------------    ------------------
   |            |    |           |    |                |
   |            |    |           |    | IClassFactory  |
   |            |    |           |    | -------------  |
   |            |--->|IOleObject |----->|IOleObject |  |
   |            |    |           |    | |IDataObject|  |
   |            |    |           |    | |    etc    |  |
   |            |    |           |    | -------------  |
   |IAdviseSink |<---|           |<---|IOleAdviseHolder|
   --------------    -------------    ------------------
                        |      |
                        V      v
                     Reg DB  Cache
                

NOTE: The object still is not visible at this point. Now an explicit call to IOleObject::DoVerb() must be made with the verb OLEIVERB_SHOW. This tells the server to make the object visible for editing.

Every time the user makes a change to the object, the object calls OLE through the advise holder to notify the libraries that the view has been changed. The libraries then query the object for the new presentation(s) to fill the presentation cache. Then the advise sink of the container application is called to notify the container that its view is no longer up to date, and should be repainted.

The container then in turn tells OLE to draw the object, at which point the libraries render the information from the cache.

At some point, the user tells the server that he or she is finished editing the object. The server tells the container that it is now going away, and that the object needs to be saved into the container's persistent storage. The container responds by telling the object to save itself into a substorage of the container's compound file. The OLE libraries "intercept" this call and save internal state information, as well as the presentation cache, into streams of this substorage. Then, the libraries tell the object to save itself into the container provided substorage.

After saving the object, the container's compound file resembles the following:

   ----------------
   | Root Storage |
   ----------------
           |   ---------------                   * = Stream
           |---|   object    |                   - = Storage
           |   | sub-storage |
           |   ---------------
           |          |   ****************
           |          |---*  OLE State   *
           |          |   ****************
           |          |   ****************
           |          |---* Presentation *
           |          |   ****************
           |          |   ****************
           |          |---* Native Data  *
           |              ****************
           |    ***************
           |    *  Container  *
           |--- *    State    *
                * Information *
                ***************
                

The container can continue to redraw the object even though the server application is no longer around because the object's presentation is stored in OLE's internal cache:

    Container             OLE
   --------------    -------------
   |            |    |           |
   |            |    |           |
   |            |    |           |
   |            |--->|IOleObject |
   |            |    |           |
   |            |    |           |
   |            |    |           |
   |IAdviseSink |<---|           |
   --------------    -------------
                        |      |
                        V      v
                     Reg DB  Cache
                

Now the user can save the document in the container application and exit. Upon exiting, the container queries the object for the IViewObject interface so the container can tell OLE to stop sending updates. Then the container asks the object to close.

If the user now reloads the document, or moves the document to another machine, the OLE libraries can still render the object because the presentation is actually stored within the container's compound file. When the object is reloaded, the libraries can refill the presentation cache from the information stored within the compound file.


Additional query words: 2.00 3.50 4.00

Keywords: kbprogramming KB104139