
An Active Document server is an OLE local server, similar to an OLE in-place server, that provides all the functionality of the document application. The document is contained inside an Active Document container, but is allowed to merge its menus with the container's menus and has complete use of the container's view area. The server provides the majority of the user interface, including menus, toolbars, status bars, and scroll bars. This allows the server to be hosted by any number of different Active Document containers while still maintaining a user interface that is familiar to the user.
Registering an Active Document Server
The IOleDocumentView Interface
Palette Management for Active Document Servers
To create an Active Document server, you must create a file-based OLE local server that implements the following interfaces. Some of these interfaces are not required for a minimal implementation of a server. This table specifies which interfaces are required.
| Interface | Required | Description | |
| IOleDocument | Yes | The container uses this interface to cause an Active Document to create views of itself, enumerate the views the object supports, and provide miscellaneous information about the object's capabilities. | |
| IOleDocumentView | Yes | The container uses this interface to activate, deactivate, close, and communicate with a document view object. | |
| IPersistStorage | Yes | The container uses this interface to initialize the object and put it in the loaded or running state, and to instruct the object to perform various save operations or to release its storage. | |
| IOleObject | Yes | The container uses this interface to execute verbs, communicate site information, and close the view. | |
| IDataObject | Yes | The container uses this interface to get and set data in the object. | |
| IOleInPlaceObject | Yes | The container uses this interface to activate and deactivate the view object. | |
| IOleInPlaceActiveObject | Yes | The container uses this interface to control the view object while it is active. | |
| IEnumFORMATETC | No | The container uses this interface to determine what data formats the object supports. | |
| IEnumOleDocumentViews | No | The container uses this interface to enumerate the views that an Active Document supports. | |
| IOleCommandTarget | No | The container uses this interface to dispatch commands and obtain command status information from the Active Document. | |
| IPrint | No | The container uses this interface to print an Active Document. |
The following are the minimum registry entries necessary to register an Active Document server. Any information in "<>" brackets is implementation-specific.
HKEY_CLASSES_ROOT\<file extension> = <prog ID> HKEY_CLASSES_ROOT\<prog ID> = <document name> HKEY_CLASSES_ROOT\<prog ID>\CLSID = <clsid> HKEY_CLASSES_ROOT\CLSID\<clsid>\LocalServer32 = <server path and file> HKEY_CLASSES_ROOT\CLSID\<clsid>\InprocHandler32 = "ole32.dll" HKEY_CLASSES_ROOT\CLSID\<clsid>\Insertable = "" HKEY_CLASSES_ROOT\CLSID\<clsid>\DocObject = ""
The Insertable and DocObject registry keys noted in this example are not required if the CATID_Insertable and CATID_DocObject component categories are registered for the server. Registering the component categories causes these keys to be added automatically. For more information, see the ICatRegister::RegisterClassImplCategories method.
The following registry entry is optional and causes an icon to be displayed for the file in Windows® Explorer.
HKEY_CLASSES_ROOT\CLSID\<clsid>\DefaultIcon = <server path and file>,<icon index>
The IDataObject interface is not specific to Active Documents, but one point must be clarified. Some Active Document containers will store the document's information in a format specific to the container. Therefore, these containers will make a copy of the data before actually activating the document. This is done by requesting the data using the object's IDataObject::GetDataHere method for the "Embed Source" registered clipboard format, DVASPECT_CONTENT and TYMED_ISTORAGE. In response to this call, your server must store the document's current data in the IStorage interface provided in the STGMEDIUM structure. This can easily be accomplished by using the OleSave API.
The IOleDocument interface is the basis for your Active Document server. The container uses this interface to create views, obtain a view enumerator (IEnumOleDocumentViews), and obtain document status.
The container will request that your server create a document view to be displayed. It will do so in the following manner:
The following is a very simple example of an IOleObject::DoVerb implementation.
STDMETHODIMP COleObject::DoVerb( LONG iVerb,
LPMSG lpmsg,
LPOLECLIENTSITE pActiveSite,
LONG lindex,
HWND hwndParent,
LPCRECT lprcPosRect)
{
HRESULT hr = E_FAIL;
switch (iVerb)
{
case OLEIVERB_SHOW:
case OLEIVERB_PRIMARY:
case OLEIVERB_UIACTIVATE:
{
//try to get the IOleDocumentSite pointer
LPOLEDOCUMENTSITE pOleDocSite;
hr = pActiveSite->QueryInterface(IID_IOleDocumentSite, (LPVOID*)&pOleDocSite);
if(SUCCEEDED(hr))
{
//passing NULL to this will cause the site to call our CreateView method
hr = pOleDocSite->ActivateMe(NULL);
}
}
break;
default:
break;
}
return hr;
}
The following is a simple example of an IOleDocument::CreateView implementation.
STDMETHODIMP COleDocument::CreateView( IOleInPlaceSite *pInPlaceSite,
IStream *pStream,
DWORD dwReserved,
IOleDocumentView **ppOleDocumentView)
{
HRESULT hr = E_FAIL;
//NULL the view pointer
*ppOleDocumentView = NULL;
//this implementation only supports one view, so fail if the view already exists
if(!m_pOleDocView)
{
m_pOleDocView = new COleDocumentView();
if(m_pOleDocView)
{
//AddRef since the pointer is being given away
m_pOleDocView->AddRef();
//if a site has been given, set this as the site for the view just created
if(pInPlaceSite)
{
m_pOleDocView->SetInPlaceSite(pInPlaceSite);
}
//if given a stream to initialize from, initialize the view state
if(pStream)
{
m_pOleDocView->ApplyViewState(pStream);
}
*ppOleDocumentView = m_pOleDocView;
hr = S_OK;
}
}
return hr;
}
The IOleDocumentView interface is used by the container to manage the display of your Active Document. The container uses this interface to set the view's site and to activate and deactivate the view, among other things.
When your server's IOleDocumentView::SetInPlaceSite method is called, the server should release any saved IOleInPlaceSite pointer that it is maintaining, and then call AddRef and store the new IOleInPlaceSite pointer. This pointer will be used to inform the site of in-place activation and deactivation and to obtain the handle of the view's parent window. The parent window handle is obtained by calling this interface's IOleWindow::GetWindow. The following is a simple example of this method's implementation.
STDMETHODIMP COleDocumentView::SetInPlaceSite(IOleInPlaceSite *pNewSite)
{
//clean up previous site if it exists
if(m_pInPlaceSite)
{
if(m_fUIActive)
{
//call the view's private method that handles UI deactivation
DeactivateUI();
}
m_pInPlaceSite->Release();
m_pInPlaceSite = NULL;
}
m_pInPlaceSite = pNewSite;
if(m_pInPlaceSite)
{
m_pInPlaceSite->AddRef();
}
return S_OK;
}
The document view activation occurs in the following manner:
Some containers can contain more than one Active Document. These containers notify the object that the Active Document window is getting activated by calling the object's IOleInPlaceActiveObject::OnDocWindowActivate method with a nonzero argument. This does not normally occur until the object has already become UI-active. When this occurs, the object must display its UI objects, such as menus and toolbars. It is not necessary, however, to completely UI-deactivate the object.
The document view deactivation occurs in the following manner:
Some containers can contain more than one Active Document. These containers notify the object that the Active Document window is getting deactivated by calling the object's IOleInPlaceActiveObject::OnDocWindowActivate method with a zero argument. When this occurs, the object must hide its UI objects, such as toolbars. It is not necessary to remove the object's menus at this point because the container will do this on its own. It is also not necessary to completely UI-deactivate the object.
In general, the palette management scheme for Active Documents is the same as the scheme used for ActiveX Controls, except that Active Documents do not receive ambient properties from their client. The Active Document server has these responsibilities for managing palettes:
The only difference between the responsibilities of Active Documents and OLE controls is that Active Documents do not handle the DISPID_AMBIENT_PALETTE property.
© 1997 Microsoft Corporation. All rights reserved. Terms of Use.