File:  [WindowsNT SDKs] / mstools / ole20 / samples / outline / svrbase.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Thu Aug 9 18:24:38 2018 UTC (7 years, 9 months ago) by root
Branches: msft, MAIN
CVS tags: ntsdk-jul-1993, HEAD
Microsoft Windows NT Build 511 (SDK Final Release) 07-24-1993

/*************************************************************************
** 
**    OLE 2 Server Sample Code
**    
**    svrbase.c
**    
**    This file contains all interfaces, methods and related support
**    functions for the basic OLE Object (Server) application. The
**    basic OLE Object application supports embedding an object and
**    linking to a file-based or embedded object as a whole. The basic
**    Object application includes the following implementation objects:
**    
**    ClassFactory (aka. ClassObject) Object    (see file classfac.c)
**      exposed interfaces:
**          IClassFactory interface
**    
**    ServerDoc Object
**      exposed interfaces:
**          IUnknown
**          IOleObject interface
**          IPersistStorage interface
**          IDataObject interface
**    
**    ServerApp Object
**      exposed interfaces:
**          IUnknown
**    
**    (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved
**
*************************************************************************/


#include "outline.h"
#include <regdb.h>
#include <enumfetc.h>
#include <geticon.h>

OLEDBGDATA

extern LPOUTLINEAPP             g_lpApp;
extern IOleObjectVtbl           g_SvrDoc_OleObjectVtbl;
extern IPersistStorageVtbl      g_SvrDoc_PersistStorageVtbl;

#if defined( INPLACE_SVR )
extern IOleInPlaceObjectVtbl        g_SvrDoc_OleInPlaceObjectVtbl;
extern IOleInPlaceActiveObjectVtbl  g_SvrDoc_OleInPlaceActiveObjectVtbl;
#endif  // INPLACE_SVR

#if defined( SVR_TREATAS )
extern IStdMarshalInfoVtbl		g_SvrDoc_StdMarshalInfoVtbl;
#endif	// SVR_TREATAS


// REVIEW: should use string resource for messages
extern char ErrMsgSaving[];
extern char ErrMsgFormatNotSupported[];
static char ErrMsgPSSaveFail[] = "PSSave failed";
extern char g_szUpdateCntrDoc[] = "&Update %s";
extern char g_szExitNReturnToCntrDoc[] = "E&xit && Return to %s";


/*************************************************************************
** ServerDoc::IOleObject interface implementation
*************************************************************************/

// IOleObject::QueryInterface method

STDMETHODIMP SvrDoc_OleObj_QueryInterface(
        LPOLEOBJECT             lpThis,
        REFIID                  riid,
        LPVOID FAR*             lplpvObj
)
{
    LPSERVERDOC lpServerDoc =
            ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;

    return OleDoc_QueryInterface((LPOLEDOC)lpServerDoc, riid, lplpvObj);
}


// IOleObject::AddRef method

STDMETHODIMP_(ULONG) SvrDoc_OleObj_AddRef(LPOLEOBJECT lpThis)
{
    LPSERVERDOC lpServerDoc =
            ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;

    OleDbgAddRefMethod(lpThis, "IOleObject");

    return OleDoc_AddRef((LPOLEDOC)lpServerDoc);
}


// IOleObject::Release method

STDMETHODIMP_(ULONG) SvrDoc_OleObj_Release(LPOLEOBJECT lpThis)
{
    LPSERVERDOC lpServerDoc =
            ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;
    
    OleDbgReleaseMethod(lpThis, "IOleObject");

    return OleDoc_Release((LPOLEDOC)lpServerDoc);
}


// IOleObject::SetClientSite method

STDMETHODIMP SvrDoc_OleObj_SetClientSite(
        LPOLEOBJECT             lpThis,
        LPOLECLIENTSITE         lpclientSite
)
{
    LPSERVERDOC lpServerDoc =
            ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;
    LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;

    OLEDBG_BEGIN2("SvrDoc_OleObj_SetClientSite\r\n")

    // SetClientSite is only valid to call on an embedded object
    if (lpOutlineDoc->m_docInitType != DOCTYPE_EMBEDDED) {
        OleDbgAssert(lpOutlineDoc->m_docInitType == DOCTYPE_EMBEDDED);
        OLEDBG_END2
        return ResultFromScode(E_UNEXPECTED);
    }

    /* if we currently have a client site ptr, then release it. */
    if (lpServerDoc->m_lpOleClientSite) 
        OleStdRelease((LPUNKNOWN)lpServerDoc->m_lpOleClientSite);
    
    lpServerDoc->m_lpOleClientSite = (LPOLECLIENTSITE) lpclientSite;
    // OLE2NOTE: to be able to hold onto clientSite pointer, we must AddRef it
    if (lpclientSite)
        lpclientSite->lpVtbl->AddRef(lpclientSite); 
    
    OLEDBG_END2
    return NOERROR;
}


// IOleObject::GetClientSite method

STDMETHODIMP SvrDoc_OleObj_GetClientSite(
        LPOLEOBJECT             lpThis,
        LPOLECLIENTSITE FAR*    lplpClientSite
)
{
    LPSERVERDOC lpServerDoc =
            ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;

    OleDbgOut2("SvrDoc_OleObj_GetClientSite\r\n");

	/* OLE2NOTE: we MUST AddRef this interface pointer to give the
	**    caller a personal copy of the pointer
	*/
	lpServerDoc->m_lpOleClientSite->lpVtbl->AddRef(
			lpServerDoc->m_lpOleClientSite
	);
    *lplpClientSite = lpServerDoc->m_lpOleClientSite;
    
    return NOERROR;

}


// IOleObject::SetHostNames method

STDMETHODIMP SvrDoc_OleObj_SetHostNames(
        LPOLEOBJECT             lpThis,
        LPCSTR                  szContainerApp,
        LPCSTR                  szContainerObj
)
{
    LPSERVERDOC lpServerDoc =
            ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;
    LPOUTLINEDOC    lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;

    OleDbgOut2("SvrDoc_OleObj_SetHostNames\r\n");

    lstrcpy((LPSTR)lpServerDoc->m_szContainerApp, szContainerApp);
    lstrcpy((LPSTR)lpServerDoc->m_szContainerObj, szContainerObj);

    /* The Window title for an embedded object is constructed as
    **    follows: 
    **      <server app name> - <obj short type> in <cont. doc name>
    **    
    **    here we construct the current document title portion of the
    **    name which follows the '-'. OutlineDoc_SetTitle prepends the
    **    "<server app name> - " to the document title.
    */
    // REVIEW: this string should be loaded from string resource
    wsprintf(lpOutlineDoc->m_szFileName, "%s in %s", 
            (LPSTR)SHORTUSERTYPENAME, (LPSTR)lpServerDoc->m_szContainerObj);

    lpOutlineDoc->m_lpszDocTitle = lpOutlineDoc->m_szFileName;
    OutlineDoc_SetTitle(lpOutlineDoc);
    
    /* OLE2NOTE: update the application menus correctly for an embedded
    **    object. the changes include:
    **      1 Remove File/New and File/Open (SDI ONLY)
    **      2 Change File/Save As.. to File/Save Copy As.. 
    **      3 Change File menu so it contains "Update" instead of "Save" 
    **      4 Change File/Exit to File/Exit & Return to <client doc>" 
    */
    ServerDoc_UpdateMenu(lpServerDoc);

    return NOERROR;
}


// IOleObject::Close method

STDMETHODIMP SvrDoc_OleObj_Close(
        LPOLEOBJECT             lpThis,
        DWORD                   dwSaveOption
)
{
    LPSERVERDOC lpServerDoc =
            ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;
    BOOL fStatus;

    OLEDBG_BEGIN2("SvrDoc_OleObj_Close\r\n")

    // REVIEW: dwSaveOption not yet supported

    /* OLE2NOTE: the OLE 2.0 user model is that embedded objects should
    **    always be saved when closed WITHOUT any prompting to the
    **    user. this is the recommendation irregardless of whether the
    **    object is activated in-place or open in its own window.
    **    this is a CHANGE from the OLE 1.0 user model where it
    **    was the guideline that servers always prompt to save changes.
    **    thus OLE 2.0 compound document oriented container's should
    **    always pass dwSaveOption==OLECLOSE_SAVEIFDIRTY. it is
    **    possible that for programmatic uses a container may want to
    **    specify a different dwSaveOption. the implementation of
    **    various save options can be tricky, particularly considering
    **    cases involving in-place activation. the following would be
    **    reasonable behavior:
    **
    **      (1) OLECLOSE_SAVEIFDIRTY: if dirty, save. close.
    **      (2) OLECLOSE_NOSAVE: close.
    **      (3) OLECLOSE_PROMPTSAVE:
    **        (a) object visible, but not in-place:
    **               if not dirty, close.
    **               switch(prompt)
    **                  case IDYES: save. close.
    **                  case IDNO: close.
    **                  case IDCANCEL: return OLE_E_PROMPTSAVECANCELLED
    **        (b) object invisible (includes UIDeactivated object)
    **               if dirty, save. close.
    **               NOTE: NO PROMPT. it is not appropriate to prompt
    **                     if the object is not visible.
    **        (c) object is in-place active:
    **               if dirty, save. close.
    **               NOTE: NO PROMPT. it is not appropriate to prompt
    **                     if the object is active in-place.
    */

    fStatus = OutlineDoc_Close((LPOUTLINEDOC)lpServerDoc, dwSaveOption);
    OleDbgAssertSz(fStatus == TRUE, "SvrDoc_OleObj_Close failed\r\n");

    OLEDBG_END2
    return (fStatus ? NOERROR : ResultFromScode(E_FAIL));
}


// IOleObject::SetMoniker method

STDMETHODIMP SvrDoc_OleObj_SetMoniker(
        LPOLEOBJECT             lpThis, 
        DWORD                   dwWhichMoniker, 
        LPMONIKER               lpmk
)
{
    LPSERVERDOC lpServerDoc =
            ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;
    LPOLEDOC lpOleDoc = (LPOLEDOC)lpServerDoc;
    LPMONIKER lpmkFull;
    HRESULT hrErr;
    SCODE sc;

    OLEDBG_BEGIN2("SvrDoc_OleObj_SetMoniker\r\n")

    /* only our container should call IOleObject::SetMoniker. if we
    **    don't have a ClientSite assigned then ignore this attempt to
    **    set our moniker.
    */
    if (lpServerDoc->m_lpOleClientSite == NULL) {
        sc = E_FAIL;
        goto error;
    }

    /* retrieve our full, absolute moniker from our container. the
    **    moniker passed to the current method is either the relative
    **    moniker of the object or the moniker of our container. we
    **    require the full moniker in order to register as running.
    */
    hrErr = lpServerDoc->m_lpOleClientSite->lpVtbl->GetMoniker(
            lpServerDoc->m_lpOleClientSite,
            OLEGETMONIKER_ONLYIFTHERE, 
            OLEWHICHMK_OBJFULL,
            &lpmkFull
    );
    if (hrErr != NOERROR) {
        sc = GetScode(hrErr);
        goto error;
    }

    /* Register the document as running with the new moniker and
    **      notify any clients that our moniker has changed. 
    */
    OleDoc_DocRenamedUpdate(lpOleDoc, lpmkFull);

    if (lpmkFull) 
        OleStdRelease((LPUNKNOWN)lpmkFull);
                
    OLEDBG_END2
    return NOERROR;

error:
    OLEDBG_END2
    return ResultFromScode(sc);
}


// IOleObject::GetMoniker method

STDMETHODIMP SvrDoc_OleObj_GetMoniker(
        LPOLEOBJECT             lpThis, 
        DWORD                   dwAssign,
        DWORD                   dwWhichMoniker, 
        LPMONIKER FAR*          lplpmk
)
{
    LPSERVERDOC lpServerDoc =
            ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;
    HRESULT hrErr;
    SCODE sc;

    OLEDBG_BEGIN2("SvrDoc_OleObj_GetMoniker\r\n")

    /* OLE2NOTE: we must make sure to set all out parameters to NULL. */
    *lplpmk = NULL;
    
    if (lpServerDoc->m_lpOleClientSite != NULL) {
        OleDbgAssert(((LPOUTLINEDOC)lpServerDoc)->m_docInitType==DOCTYPE_EMBEDDED);

        /* document is an embedded object. retrieve our moniker from
        **    our container.
        */
        OLEDBG_BEGIN2("IOleClientSite::GetMoniker called\r\n")
        hrErr = lpServerDoc->m_lpOleClientSite->lpVtbl->GetMoniker(
                lpServerDoc->m_lpOleClientSite,
                dwAssign, 
                dwWhichMoniker,
                lplpmk
        );
        OLEDBG_END2

    } else if (((LPOUTLINEDOC)lpServerDoc)->m_docInitType == DOCTYPE_FROMFILE) {

        // document is a file-based document => return a FileMoniker
        hrErr = CreateFileMoniker(
                ((LPOUTLINEDOC)lpServerDoc)->m_szFileName, 
                lplpmk
        );

    } else {
        // document is either New or not yet fully initialized => no moniker
        sc = E_FAIL;
        goto error;
    }

    OLEDBG_END2
    return hrErr;

error:
    OLEDBG_END2
    return ResultFromScode(sc);
}


// IOleObject::InitFromData method

STDMETHODIMP SvrDoc_OleObj_InitFromData(
        LPOLEOBJECT             lpThis,
        LPDATAOBJECT            lpDataObject,
        BOOL                    fCreation,
        DWORD                   reserved
)
{
    LPSERVERDOC lpServerDoc =
            ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;

    OLEDBG_BEGIN2("SvrDoc_OleObj_InitFromData\r\n")

    // REVIEW: NOT YET IMPLEMENTED

    OLEDBG_END2
    return ResultFromScode(E_NOTIMPL);
}


// IOleObject::GetClipboardData method

STDMETHODIMP SvrDoc_OleObj_GetClipboardData(
        LPOLEOBJECT             lpThis,
        DWORD                   reserved,
        LPDATAOBJECT FAR*       lplpDataObject
)
{
    LPSERVERDOC lpServerDoc =
            ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;

    OLEDBG_BEGIN2("SvrDoc_OleObj_GetClipboardData\r\n")

    // REVIEW: NOT YET IMPLEMENTED

    OLEDBG_END2
    return ResultFromScode(E_NOTIMPL);
}


// IOleObject::DoVerb method

STDMETHODIMP SvrDoc_OleObj_DoVerb(
        LPOLEOBJECT             lpThis,
        LONG                    lVerb,
        LPMSG                   lpmsg,
        LPOLECLIENTSITE         lpActiveSite,
		LONG					lindex,
		HWND					hwndParent,
		LPCRECT					lprcPosRect
)
{
    LPSERVERDOC lpServerDoc =
            ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;
    LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;
	SCODE sc = S_OK;

    OLEDBG_BEGIN2("SvrDoc_OleObj_DoVerb\r\n")
    
    switch (lVerb) {

		default:
			/* OLE2NOTE: when an unknown verb number is given, the
            **    server must take careful action:
            **    1. if it is one of the specially defined OLEIVERB
            **    (negative numbered) verbs, the app should return an
            **    error (E_NOTIMPL) and perform no action.
            **    
            **    2. if the verb is a application specific verb
            **    (positive numbered verb), then the app should
			**    return the special scode (OLEOBJ_S_INVALIDVERB). BUT,
			**    we should still perform our normal primary verb action.
			*/
			if (lVerb < 0) {
                OLEDBG_END2
				return ResultFromScode(E_NOTIMPL);
            } else {
                sc = OLEOBJ_S_INVALIDVERB;
            }
			
			// deliberatly fall through to Primary Verb

        case 0:
        case OLEIVERB_SHOW:

#if defined( INPLACE_SVR )                        
            /* OLE2NOTE: if our window is already open (visible) then
            **    we should simply surface the open window. if not,
            **    then we can do our primary action of in-place 
            **    activation.
            */
            if ( lpServerDoc->m_lpOleClientSite 
                    && ! (IsWindowVisible(lpOutlineDoc->m_hWndDoc) &&
                            ! lpServerDoc->m_fInPlaceActive) ) {
                ServerDoc_DoInPlaceActivate(
                        lpServerDoc, lVerb, lpmsg, lpActiveSite);
            }
#endif // INPLACE_SVR         

            OutlineDoc_ShowWindow(lpOutlineDoc);
            break;

        case 1:
        case OLEIVERB_OPEN:
#if defined( INPLACE_SVR )
			ServerDoc_DoInPlaceDeactivate(lpServerDoc);
#endif // INPLACE_SVR
            OutlineDoc_ShowWindow(lpOutlineDoc);
            break;


        case OLEIVERB_HIDE:
#if defined( INPLACE_SVR )
			if (lpServerDoc->m_fInPlaceActive) {

                SvrDoc_IPObj_UIDeactivate(
                        (LPOLEINPLACEOBJECT)&lpServerDoc->m_OleInPlaceObject);

#if defined( SVR_INSIDEOUT )
                /* OLE2NOTE: an inside-out style in-place server will
                **    NOT hide its window in UIDeactive (an outside-in
                **    style object will hide its window in
                **    UIDeactivate). thus we need to explicitly hide
                **    our window now.
                */
				ServerDoc_DoInPlaceHide(lpServerDoc);
#endif // INSIEDOUT

            } else {
				OleDoc_HideWindow((LPOLEDOC)lpServerDoc, FALSE /*fShutdown*/);
            }
#endif // INPLACE_SVR
            break;

#if defined( INPLACE_SVR )			
		case OLEIVERB_UIACTIVATE:

#if defined( SVR_INSIDEOUT )
        /* OLE2NOTE: only an inside-out style object supports
        **    INPLACEACTIVATE verb 
        */
		case OLEIVERB_INPLACEACTIVATE:
#endif // INSIEDOUT
            /* OLE2NOTE: if our window is already open (visible) then
            **    we can NOT activate in-place.
            */
            if (IsWindowVisible(lpOutlineDoc->m_hWndDoc) &&
                        ! lpServerDoc->m_fInPlaceActive ) {
                sc = OLE_E_NOT_INPLACEACTIVE;
            } else {
                sc = GetScode( ServerDoc_DoInPlaceActivate(
                        lpServerDoc, lVerb, lpmsg, lpActiveSite) );
                if (SUCCEEDED(sc)) 
                    OutlineDoc_ShowWindow(lpOutlineDoc);
            }
            break;
#endif  // INPLACE_SVR
    }
    
    OLEDBG_END2
	return ResultFromScode(sc);
}


// IOleObject::EnumVerbs method

STDMETHODIMP SvrDoc_OleObj_EnumVerbs(
        LPOLEOBJECT             lpThis,
        LPENUMOLEVERB FAR*      lplpenumOleVerb 
)
{
    OleDbgOut2("SvrDoc_OleObj_EnumVerbs\r\n");

    /* OLE2NOTE: we must make sure to set all out parameters to NULL. */
    *lplpenumOleVerb = NULL;

    // Tell OLE to enumerate our verbs using the REGDB
    return ResultFromScode(OLE_S_USEREG);
}


// IOleObject::Update method

STDMETHODIMP SvrDoc_OleObj_Update(LPOLEOBJECT lpThis)
{
    OleDbgOut2("SvrDoc_OleObj_Update\r\n");

    /* OLE2NOTE: a server-only app is always "up-to-date". 
    **    a container-app which contains links where the link source
    **    has changed since the last update of the link would be
    **    considered "out-of-date". the "Update" method instructs the
    **    object to get an update from any out-of-date links.
    */

    return NOERROR;
}


// IOleObject::IsUpToDate method

STDMETHODIMP SvrDoc_OleObj_IsUpToDate(LPOLEOBJECT lpThis)
{
    OleDbgOut2("SvrDoc_OleObj_IsUpToDate\r\n");

    /* OLE2NOTE: a server-only app is always "up-to-date". 
    **    a container-app which contains links where the link source
    **    has changed since the last update of the link would be
    **    considered "out-of-date".
    */
    return NOERROR;
}


// IOleObject::GetUserClassID method

STDMETHODIMP SvrDoc_OleObj_GetUserClassID(
        LPOLEOBJECT             lpThis, 
        LPCLSID                 lpClassID
)
{
    LPSERVERDOC lpServerDoc =
            ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;

    OleDbgOut2("SvrDoc_OleObj_GetClassID\r\n");

	/* OLE2NOTE: we must be carefull to return the correct CLSID here.
	**    if we are currently preforming a "TreatAs (aka. ActivateAs)"
	**    operation then we need to return the class of the object
	**    written in the storage of the object. otherwise we would
	**    return our own class id. 
	*/
	return ServerDoc_GetClassID(lpServerDoc, lpClassID);
}


// IOleObject::GetUserType method

STDMETHODIMP SvrDoc_OleObj_GetUserType(
        LPOLEOBJECT             lpThis,
        DWORD                   dwFormOfType, 
        LPSTR FAR*              lpszUserType
)
{
    OleDbgOut2("SvrDoc_OleObj_GetUserType\r\n");

    /* OLE2NOTE: we must make sure to set all out parameters to NULL. */
    *lpszUserType = NULL;

    // Tell OLE to enumerate our verbs using the REGDB
    return ResultFromScode(OLE_S_USEREG);

#if defined( LATER )
    LPSERVERDOC lpServerDoc =
            ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;

	/* OLE2NOTE: we must be carefull to return the correct UserType here.
	**    if we are currently preforming a "TreatAs (aka. ActivateAs)"
	**    operation then we need to return the UserType of the object
	**    written in the storage of the object. otherwise we would
	**    return our own UserType.
	*/
	return ServerDoc_GetUserType(lpServerDoc, dwFormOfType, lpszUserType);
#endif
}


// IOleObject::SetExtent method

STDMETHODIMP SvrDoc_OleObj_SetExtent(
        LPOLEOBJECT             lpThis,
        DWORD                   dwDrawAspect,
        LPSIZEL                 lplgrc
)
{
    OleDbgOut2("SvrDoc_OleObj_SetExtent\r\n");

    /* SVROUTL does NOT allow the object's size to be set by its
    **    container. the size of the ServerDoc object is determined by
    **    the data contained within the document.
    */
    return ResultFromScode(S_FALSE);
}


// IOleObject::GetExtent method

STDMETHODIMP SvrDoc_OleObj_GetExtent(
        LPOLEOBJECT             lpThis,
        DWORD                   dwDrawAspect,
        LPSIZEL                 lpsizel
)
{
    LPOLEDOC lpOleDoc =
            (LPOLEDOC)((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;

    OleDbgOut2("SvrDoc_OleObj_GetExtent\r\n");

	if (dwDrawAspect == DVASPECT_CONTENT
			|| dwDrawAspect == DVASPECT_THUMBNAIL
			|| dwDrawAspect == DVASPECT_DOCPRINT) 
    {
		OleDoc_GetExtent(lpOleDoc, lpsizel);
		return NOERROR;
    }

#if defined( LATER )

    else if (dwDrawAspect == DVASPECT_THUMBNAIL) 
    {
        /* as our thumbnail we will render only the first page of the 
        **    document. calculate extents of our thumbnail rendering.
        **    
        ** OLE2NOTE: thumbnails are most often used by applications in
        **    FindFile or FileOpen type dialogs to give the user a
        **    quick view of the contents of the file or object.
        */
		OleDoc_GetThumbnailExtent(lpOleDoc, lpsizel);
		return NOERROR;
    }
#endif

	else 
    {
		return ResultFromScode(E_INVALIDARG);
	}
}


// IOleObject::Advise method

STDMETHODIMP SvrDoc_OleObj_Advise(
        LPOLEOBJECT             lpThis, 
        LPADVISESINK            lpAdvSink, 
        LPDWORD                 lpdwConnection
)
{
    LPSERVERDOC lpServerDoc =
            ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;
    HRESULT hrErr;
    SCODE   sc;

    OLEDBG_BEGIN2("SvrDoc_OleObj_Advise\r\n");

    if (lpServerDoc->m_lpOleAdviseHldr == NULL && 
        CreateOleAdviseHolder(&lpServerDoc->m_lpOleAdviseHldr) != NOERROR) {
        sc = E_OUTOFMEMORY;
        goto error;
    }

    OLEDBG_BEGIN2("IOleAdviseHolder::Advise called\r\n")
    hrErr = lpServerDoc->m_lpOleAdviseHldr->lpVtbl->Advise(
            lpServerDoc->m_lpOleAdviseHldr, 
            lpAdvSink, 
            lpdwConnection
    );
    OLEDBG_END2

    OLEDBG_END2
    return hrErr;

error:
    OLEDBG_END2
    return ResultFromScode(sc);
}


// IOleObject::Unadvise method

STDMETHODIMP SvrDoc_OleObj_Unadvise(LPOLEOBJECT lpThis, DWORD dwConnection)
{
    LPSERVERDOC lpServerDoc =
            ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;
    HRESULT hrErr;
    SCODE   sc;

    OLEDBG_BEGIN2("SvrDoc_OleObj_Unadvise\r\n");

    if (lpServerDoc->m_lpOleAdviseHldr == NULL) {
        sc = E_FAIL;
        goto error;
    }

    OLEDBG_BEGIN2("IOleAdviseHolder::Unadvise called\r\n")
    hrErr = lpServerDoc->m_lpOleAdviseHldr->lpVtbl->Unadvise(
            lpServerDoc->m_lpOleAdviseHldr, 
            dwConnection
    );
    OLEDBG_END2

    OLEDBG_END2
    return hrErr;

error:
    OLEDBG_END2
    return ResultFromScode(sc);
}


// IOleObject::EnumAdvise method

STDMETHODIMP SvrDoc_OleObj_EnumAdvise(
        LPOLEOBJECT             lpThis, 
        LPENUMSTATDATA FAR*     lplpenumAdvise
)
{
    LPSERVERDOC lpServerDoc =
            ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;
    HRESULT hrErr;
    SCODE   sc;

    OLEDBG_BEGIN2("SvrDoc_OleObj_EnumAdvise\r\n");

    /* OLE2NOTE: we must make sure to set all out parameters to NULL. */
    *lplpenumAdvise = NULL;

    if (lpServerDoc->m_lpOleAdviseHldr == NULL) {
        sc = E_FAIL;
        goto error;
    }

    OLEDBG_BEGIN2("IOleAdviseHolder::EnumAdvise called\r\n")
    hrErr = lpServerDoc->m_lpOleAdviseHldr->lpVtbl->EnumAdvise(
            lpServerDoc->m_lpOleAdviseHldr, 
            lplpenumAdvise
    );
    OLEDBG_END2

    OLEDBG_END2
    return hrErr;

error:
    OLEDBG_END2
    return ResultFromScode(sc);
}


// IOleObject::GetMiscStatus method

STDMETHODIMP SvrDoc_OleObj_GetMiscStatus(
        LPOLEOBJECT             lpThis,
        DWORD                   dwAspect,
        DWORD FAR*              lpdwStatus
)
{
	LPSERVERDOC lpServerDoc =
            ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;
	LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;

    OleDbgOut2("SvrDoc_OleObj_GetMiscStatus\r\n");

	*lpdwStatus = 0;

    /* OLE2NOTE: check if the data copied is compatible to be
    **    linked by an OLE 1.0 container. it is compatible if
    **    either the data is an untitled document, a file, or a
    **    selection of data within a file. if the data is part of
    **    an embedded object, then it is NOT compatible to be
    **    linked by an OLE 1.0 container. if it is compatible then
    **    we must include OLEMISC_CANLINKBYOLE1 as part of the
    **    dwStatus flags transfered via CF_OBJECTDESCRIPTOR or
    **    CF_LINKSRCDESCRIPTOR.
    */
	if (lpOutlineDoc->m_docInitType == DOCTYPE_NEW || 
		lpOutlineDoc->m_docInitType == DOCTYPE_FROMFILE) 
		*lpdwStatus |= OLEMISC_CANLINKBYOLE1;

#if defined( INPLACE_SVR )	
	if (dwAspect == DVASPECT_CONTENT)
		*lpdwStatus |= (OLEMISC_INSIDEOUT | OLEMISC_ACTIVATEWHENVISIBLE);
#endif  // INPLACE_SVR

	return NOERROR;
}


// IOleObject::SetColorScheme method

STDMETHODIMP SvrDoc_OleObj_SetColorScheme(
        LPOLEOBJECT             lpThis,
        LPLOGPALETTE            lpLogpal
)
{
    OleDbgOut2("SvrDoc_OleObj_SetColorScheme\r\n");

    // REVIEW: NOT YET IMPLEMENTED

    return ResultFromScode(E_NOTIMPL);
}


/*************************************************************************
** ServerDoc::IPersistStorage interface implementation
*************************************************************************/

// IPersistStorage::QueryInterface method

STDMETHODIMP SvrDoc_PStg_QueryInterface(
        LPPERSISTSTORAGE        lpThis,
        REFIID                  riid,
        LPVOID FAR*             lplpvObj
)
{
    LPSERVERDOC lpServerDoc =
            ((struct CDocPersistStorageImpl FAR*)lpThis)->lpServerDoc;

    return OleDoc_QueryInterface((LPOLEDOC)lpServerDoc, riid, lplpvObj);
}


// IPersistStorage::AddRef method

STDMETHODIMP_(ULONG) SvrDoc_PStg_AddRef(LPPERSISTSTORAGE lpThis)
{
    LPSERVERDOC lpServerDoc = 
            ((struct CDocPersistStorageImpl FAR*)lpThis)->lpServerDoc;
    
    OleDbgAddRefMethod(lpThis, "IPersistStorage");

    return OleDoc_AddRef((LPOLEDOC)lpServerDoc);
}


// IPersistStorage::Release method

STDMETHODIMP_(ULONG) SvrDoc_PStg_Release(LPPERSISTSTORAGE lpThis)
{
    LPSERVERDOC lpServerDoc = 
            ((struct CDocPersistStorageImpl FAR*)lpThis)->lpServerDoc;
    
    OleDbgReleaseMethod(lpThis, "IPersistStorage");

    return OleDoc_Release((LPOLEDOC)lpServerDoc);
}


// IPersistStorage::GetClassID method

STDMETHODIMP SvrDoc_PStg_GetClassID(
        LPPERSISTSTORAGE        lpThis, 
        LPCLSID                 lpClassID
)
{
    LPSERVERDOC lpServerDoc = 
            ((struct CDocPersistStorageImpl FAR*)lpThis)->lpServerDoc;

    OleDbgOut2("SvrDoc_PStg_GetClassID\r\n");

	/* OLE2NOTE: we must be carefull to return the correct CLSID here.
	**    if we are currently preforming a "TreatAs (aka. ActivateAs)"
	**    operation then we need to return the class of the object
	**    written in the storage of the object. otherwise we would
	**    return our own class id. 
	*/
	return ServerDoc_GetClassID(lpServerDoc, lpClassID);
}


// IPersistStorage::IsDirty method

STDMETHODIMP  SvrDoc_PStg_IsDirty(LPPERSISTSTORAGE  lpThis)
{
    LPSERVERDOC lpServerDoc = 
            ((struct CDocPersistStorageImpl FAR*)lpThis)->lpServerDoc;

    OleDbgOut2("SvrDoc_PStg_IsDirty\r\n");

    if (OutlineDoc_IsModified((LPOUTLINEDOC)lpServerDoc))
        return NOERROR;
    else 
        return ResultFromScode(S_FALSE);
}



// IPersistStorage::InitNew method

STDMETHODIMP SvrDoc_PStg_InitNew(
        LPPERSISTSTORAGE        lpThis, 
        LPSTORAGE               lpStg
)
{
    LPSERVERDOC lpServerDoc = 
            ((struct CDocPersistStorageImpl FAR*)lpThis)->lpServerDoc;
    SCODE sc;

    OLEDBG_BEGIN2("SvrDoc_PStg_InitNew\r\n")

#if defined( SVR_TREATAS )
	{
		LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;
		CLSID		clsid;
		CLIPFORMAT	cfFmt;
		LPSTR		lpszType;

		/* OLE2NOTE: if the Server is capable of supporting "TreatAs"
		**    (aka. ActivateAs), it must read the class that is written
		**    into the storage. if this class is NOT the app's own
		**    class ID, then this is a TreatAs operation. the server
		**    then must faithfully pretend to be the class that is
		**    written into the storage. it must also faithfully write
		**    the data back to the storage in the SAME format as is
		**    written in the storage.
		**    
		**    SVROUTL and ISVROTL can emulate each other. they have the
		**    simplification that they both read/write the identical
		**    format. thus for these apps no actual conversion of the
		**    native bits is actually required.
		*/
		lpServerDoc->m_clsidTreatAs = CLSID_NULL;
		if (OleStdGetTreatAsFmtUserType(&CLSID_APP, lpStg, &clsid,
							(CLIPFORMAT FAR*)&cfFmt, (LPSTR FAR*)&lpszType)) {
							
			if (cfFmt == lpOutlineApp->m_cfOutline) {
				// We should perform TreatAs operation
				if (lpServerDoc->m_lpszTreatAsType) 
					OleStdFreeString(lpServerDoc->m_lpszTreatAsType, NULL);

				lpServerDoc->m_clsidTreatAs = clsid;
				((LPOUTLINEDOC)lpServerDoc)->m_cfSaveFormat = cfFmt; 
				lpServerDoc->m_lpszTreatAsType = lpszType;

				OleDbgOut3("SvrDoc_PStg_InitNew: TreateAs ==> '");
				OleDbgOutNoPrefix3(lpServerDoc->m_lpszTreatAsType);
				OleDbgOutNoPrefix3("'\r\n");
			} else {
				// ERROR: we ONLY support TreatAs for CF_OUTLINE format
				OleDbgOut("SvrDoc_PStg_InitNew: INVALID TreatAs Format\r\n");
				OleStdFreeString(lpszType, NULL);
			}
		}
	}
#endif	// SVR_TREATAS

    // set the doc to a new embedded object.
    if (! ServerDoc_InitNewEmbed(lpServerDoc)) {
        sc = E_FAIL;
        goto error;
    }

	lpServerDoc->m_dwStorageMode = STGMODE_NORMAL;

    OLEDBG_END2
    return NOERROR;

error:
    OLEDBG_END2
    return ResultFromScode(sc);
}


// IPersistStorage::Load method

STDMETHODIMP SvrDoc_PStg_Load(
        LPPERSISTSTORAGE        lpThis, 
        LPSTORAGE               lpStg
)
{
    LPSERVERDOC lpServerDoc = 
            ((struct CDocPersistStorageImpl FAR*)lpThis)->lpServerDoc;
	LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;
    SCODE sc;

    OLEDBG_BEGIN2("SvrDoc_PStg_Load\r\n")

    if (OutlineDoc_LoadFromStg((LPOUTLINEDOC)lpServerDoc, lpStg)) {

        ((LPOUTLINEDOC)lpServerDoc)->m_docInitType = DOCTYPE_EMBEDDED;

		lpServerDoc->m_dwStorageMode = STGMODE_NORMAL;

		/* OLE2NOTE: we need to check if the ConvertStg bit is on. if
		**    so, we need to clear the ConvertStg bit and mark the
        **    document as dirty so as to force a save when the document
        **    is closed. the actual conversion of the bits should be
        **    performed when the data is loaded from the IStorage*. in
        **    our case any conversion of data formats would be done in
        **    OutlineDoc_LoadFromStg function. in reality both SVROUTL
        **    and ISVROTL read and write the same format so no actual
        **    conversion of data bits is necessary.
		*/
		if (GetConvertStg(lpStg) == NOERROR) {
            SetConvertStg(lpStg, FALSE);

			OleDbgOut3("SvrDoc_PStg_Load: ConvertStg==TRUE\r\n");
			OutlineDoc_SetModified(lpOutlineDoc, TRUE, FALSE, FALSE);
		}

    } else {
        sc = E_FAIL;
        goto error;
    }

    OLEDBG_END2
    return NOERROR;

error:
    OLEDBG_END2
    return ResultFromScode(sc);
}


// IPersistStorage::Save method

STDMETHODIMP SvrDoc_PStg_Save(
        LPPERSISTSTORAGE        lpThis,
        LPSTORAGE               lpStg,
        BOOL                    fSameAsLoad
)
{
    LPSERVERDOC lpServerDoc = 
            ((struct CDocPersistStorageImpl FAR*)lpThis)->lpServerDoc;
    LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;
    BOOL fStatus;
    SCODE sc;

    OLEDBG_BEGIN2("SvrDoc_PStg_Save\r\n")

    fStatus = OutlineDoc_SaveSelToStg(
            (LPOUTLINEDOC)lpServerDoc, 
            NULL, 
            lpOutlineDoc->m_cfSaveFormat,
            lpStg, 
            FALSE
    );

    lpServerDoc->m_fSaveWithSameAsLoad = fSameAsLoad;

    if (! fStatus) {
        OutlineApp_ErrorMessage(g_lpApp, ErrMsgPSSaveFail);
        sc = E_FAIL;
        goto error;
    }

	lpServerDoc->m_dwStorageMode = STGMODE_NOSCRIBBLE;
    OLEDBG_END2
    return NOERROR;

error:
    OLEDBG_END2
    return ResultFromScode(sc);
}



// IPersistStorage::SaveCompleted method

STDMETHODIMP SvrDoc_PStg_SaveCompleted(
        LPPERSISTSTORAGE        lpThis, 
        LPSTORAGE               lpStgNew
)
{
    LPSERVERDOC lpServerDoc = 
            ((struct CDocPersistStorageImpl FAR*)lpThis)->lpServerDoc;
    LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;

    OLEDBG_BEGIN2("SvrDoc_PStg_SaveCompleted\r\n")

	/* OLE2NOTE: because we are a pure server that loads all data into
	**    memory, we do not hold on to our storage. thus we do not have
	**    to remember the storage passed into SaveCompleted.
	**    a container/server application must hold on to its storage
	**    however. any application that holds onto its storage must now
	**    remember the storage if one is passed in. in addition a
	**    container/server application would have to call SaveCompleted
	**    for each of its contained compound document objects. if a new
	**    storage was given, then the container/server would have to
	**    open the corresponding new sub-storage for each compound
	**    document object and pass as an argument in the SaveCompleted
	**    call. 
	*/

	lpServerDoc->m_dwStorageMode = STGMODE_NORMAL;

    /* OLE2NOTE: it is only legal to perform a Save or SaveAs operation 
    **    on an embedded object. if the document is a file-based document
    **    then we can not be changed to a IStorage-base object.
    **    
    **      fSameAsLoad   lpStgNew     Type of Save     Send OnSave
    **    ---------------------------------------------------------
    **         TRUE        NULL        SAVE             YES
    **         TRUE        ! NULL      SAVE *           YES
    **         FALSE       ! NULL      SAVE AS          YES
    **         FALSE       NULL        SAVE COPY AS     NO
    **    
    **    * this is a strange case that is possible. it is inefficient
    **    for the caller; it would be better to pass lpStgNew==NULL for
    **    the Save operation.
    */
    if ( ((lpServerDoc->m_fSaveWithSameAsLoad && lpStgNew==NULL) || lpStgNew)
            && (lpOutlineDoc->m_docInitType != DOCTYPE_EMBEDDED) ) {
        OLEDBG_END2
        return ResultFromScode(E_INVALIDARG);
    }

    /* OLE2NOTE: inform any linking clients that the document has been
    **    saved. in addition, any currently active pseudo objects
    **    should also inform their clients. we should only broadcast an
    **    OnSave notification if a Save or SaveAs operation was
    **    performed. we do NOT want to send the notification if a
    **    SaveCopyAs operation was performed.
    */
    if ((lpServerDoc->m_fSaveWithSameAsLoad && lpStgNew==NULL) || lpStgNew) {

        // Clear dirty flag upon save or saveAs
        OutlineDoc_SetModified(lpOutlineDoc, FALSE, FALSE, FALSE);

        ServerDoc_SendAdvise (
                lpServerDoc, 
                OLE_ONSAVE, 
                NULL,	/* lpmkDoc -- not relevant here */
                0   	/* advf -- not relevant here */
        );
    }
    OLEDBG_END2
    return NOERROR;
}


// IPersistStorage::HandsOffStorage method

STDMETHODIMP SvrDoc_PStg_HandsOffStorage(LPPERSISTSTORAGE lpThis)
{
    LPSERVERDOC lpServerDoc = 
            ((struct CDocPersistStorageImpl FAR*)lpThis)->lpServerDoc;

    OLEDBG_BEGIN2("SvrDoc_PStg_HandsOffStorage\r\n")

	/* OLE2NOTE: because we are a pure server that loads all data into
	**    memory, we do not hold on to our storage. thus we do not have
	**    a storage to release (ie. to enter HandsOff Mode). 
	**    a container/server application must hold on to its storage
	**    however. any application that holds onto its storage must now
	**    release its storage. when SaveCompleted is called, then a new
	**    storage will be given.
	*/

	lpServerDoc->m_dwStorageMode = STGMODE_HANDSOFF;
    
    OLEDBG_END2
    return NOERROR;
}



#if defined( SVR_TREATAS )

/*************************************************************************
** ServerDoc::IStdMarshalInfo interface implementation
*************************************************************************/

// IStdMarshalInfo::QueryInterface method

STDMETHODIMP SvrDoc_StdMshl_QueryInterface(
        LPSTDMARSHALINFO        lpThis,
        REFIID                  riid,
        LPVOID FAR*             lplpvObj
)
{
    LPSERVERDOC lpServerDoc =
            ((struct CDocStdMarshalInfoImpl FAR*)lpThis)->lpServerDoc;

    return OleDoc_QueryInterface((LPOLEDOC)lpServerDoc, riid, lplpvObj);
}


// IStdMarshalInfo::AddRef method

STDMETHODIMP_(ULONG) SvrDoc_StdMshl_AddRef(LPSTDMARSHALINFO lpThis)
{
    LPSERVERDOC lpServerDoc = 
            ((struct CDocStdMarshalInfoImpl FAR*)lpThis)->lpServerDoc;
    
    OleDbgAddRefMethod(lpThis, "IStdMarshalInfo");

    return OleDoc_AddRef((LPOLEDOC)lpServerDoc);
}


// IStdMarshalInfo::Release method

STDMETHODIMP_(ULONG) SvrDoc_StdMshl_Release(LPSTDMARSHALINFO lpThis)
{
    LPSERVERDOC lpServerDoc = 
            ((struct CDocStdMarshalInfoImpl FAR*)lpThis)->lpServerDoc;
    
    OleDbgReleaseMethod(lpThis, "IStdMarshalInfo");

    return OleDoc_Release((LPOLEDOC)lpServerDoc);
}


// IStdMarshalInfo::GetClassForHandler

STDMETHODIMP SvrDoc_StdMshl_GetClassForHandler(
        LPSTDMARSHALINFO        lpThis, 
		DWORD					dwDestContext, 
		LPVOID					pvDestContext, 
        LPCLSID                 lpClassID
)
{
    LPSERVERDOC lpServerDoc = 
            ((struct CDocStdMarshalInfoImpl FAR*)lpThis)->lpServerDoc;

    OleDbgOut2("SvrDoc_StdMshl_GetClassForHandler\r\n");

	// OLE2NOTE: we only handle LOCAL marshal context.
	if (dwDestContext != MSHCTX_LOCAL || pvDestContext != NULL) 
		return ResultFromScode(E_INVALIDARG);

	/* OLE2NOTE: we must return our REAL clsid, NOT the clsid that we
	**    are pretending to be if a "TreatAs" is in effect.
	*/
    *lpClassID = CLSID_APP; 
    return NOERROR;
}
#endif	// SVR_TREATAS



/*************************************************************************
** ServerDoc Support Functions
*************************************************************************/


/* ServerDoc_Init
 * --------------
 *
 *  Initialize the fields of a new ServerDoc object. The object is initially
 *  not associated with a file or an (Untitled) document. This function sets
 *  the docInitType to DOCTYPE_UNKNOWN. After calling this function the 
 *  caller should call:
 *      1.) OutlineDoc_InitNewFile to set the ServerDoc to (Untitled)
 *      2.) OutlineDoc_LoadFromFile to associate the ServerDoc with a file.
 *  This function creates a new window for the document.
 *  
 *  NOTE: the window is initially created with a NIL size. it must be
 *        sized and positioned by the caller. also the document is initially
 *        created invisible. the caller must call OutlineDoc_ShowWindow 
 *        after sizing it to make the document window visible.
 */
BOOL ServerDoc_Init(LPSERVERDOC lpServerDoc, BOOL fDataTransferDoc)
{
    lpServerDoc->m_cPseudoObj                   = 0;
    lpServerDoc->m_lpOleClientSite              = NULL;
    lpServerDoc->m_lpOleAdviseHldr              = NULL;
    lpServerDoc->m_lpDataAdviseHldr             = NULL;
	
	// initialy doc does not have any storage
	lpServerDoc->m_dwStorageMode				= STGMODE_HANDSOFF;
    lpServerDoc->m_fSaveWithSameAsLoad          = FALSE;
    lpServerDoc->m_szContainerApp[0]            = '\0';
    lpServerDoc->m_szContainerObj[0]            = '\0';
    lpServerDoc->m_nNextRangeNo                 = 0L;
    lpServerDoc->m_lrSrcSelOfCopy.m_nStartLine  = -1;
    lpServerDoc->m_lrSrcSelOfCopy.m_nEndLine    = -1;
    lpServerDoc->m_fDataChanged                 = FALSE;
    lpServerDoc->m_fSizeChanged                 = FALSE;
    lpServerDoc->m_fSendDataOnStop              = FALSE;

#if defined( SVR_TREATAS )
	lpServerDoc->m_clsidTreatAs					= CLSID_NULL;		
	lpServerDoc->m_lpszTreatAsType				= NULL;
#endif	// SVR_TREATAS

#if defined( INPLACE_SVR )
	lpServerDoc->m_hWndHatch					= 
			CreateHatchWindow(
					OutlineApp_GetWindow(g_lpApp),
					OutlineApp_GetInstance(g_lpApp)
			);
	if (!lpServerDoc->m_hWndHatch)
		return FALSE;

    lpServerDoc->m_fInPlaceActive               = FALSE;
    lpServerDoc->m_fInPlaceVisible				= FALSE;	
    lpServerDoc->m_fUIActive                    = FALSE;
    lpServerDoc->m_lpIPData                     = NULL; 

    INIT_INTERFACEIMPL(
            &lpServerDoc->m_OleInPlaceObject,
            &g_SvrDoc_OleInPlaceObjectVtbl,
            lpServerDoc
    );
    INIT_INTERFACEIMPL(
            &lpServerDoc->m_OleInPlaceActiveObject,
            &g_SvrDoc_OleInPlaceActiveObjectVtbl,
            lpServerDoc
    );
#endif // INPLACE_SVR

    INIT_INTERFACEIMPL(
            &lpServerDoc->m_OleObject,
            &g_SvrDoc_OleObjectVtbl,
            lpServerDoc
	);

    INIT_INTERFACEIMPL(
            &lpServerDoc->m_PersistStorage,
            &g_SvrDoc_PersistStorageVtbl,
            lpServerDoc
    );

#if defined( SVR_TREATAS )

    INIT_INTERFACEIMPL(
            &lpServerDoc->m_StdMarshalInfo,
            &g_SvrDoc_StdMarshalInfoVtbl,
            lpServerDoc
    );
#endif	// SVR_TREATAS
    return TRUE;
}


/* ServerDoc_InitNewEmbed
 * ----------------------
 *
 *  Initialize the ServerDoc object to be a new embedded object document.
 *  This function sets the docInitType to DOCTYPE_EMBED.
 */
BOOL ServerDoc_InitNewEmbed(LPSERVERDOC lpServerDoc)
{
    LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;
    
    OleDbgAssert(lpOutlineDoc->m_docInitType == DOCTYPE_UNKNOWN);

    lpOutlineDoc->m_docInitType = DOCTYPE_EMBEDDED;

    /* The Window title for an embedded object is constructed as
    **    follows: 
    **      <server app name> - <obj short type> in <cont. doc name>
    **    
    **    here we construct the current document title portion of the
    **    name which follows the '-'. OutlineDoc_SetTitle prepends the
    **    "<server app name> - " to the document title.
    */
    // REVIEW: this string should be loaded from string resource
    wsprintf(lpOutlineDoc->m_szFileName, "%s in %s", 
        (LPSTR)SHORTUSERTYPENAME, 
        (LPSTR)DEFCONTAINERNAME);
    lpOutlineDoc->m_lpszDocTitle = lpOutlineDoc->m_szFileName;

    
    /* OLE2NOTE: an embedding should be marked as initially dirty so
    **    that on close we always call IOleClientSite::SaveObject.
    */
    OutlineDoc_SetModified(lpOutlineDoc, TRUE, FALSE, FALSE);

    OutlineDoc_SetTitle(lpOutlineDoc);

    return TRUE;
}


/* ServerDoc_SendAdvise
 * --------------------
 *
 * This function sends an advise notification on behalf of a specific 
 *  doc object to all its clients.
 */
void ServerDoc_SendAdvise(
        LPSERVERDOC     lpServerDoc, 
        WORD            wAdvise, 
        LPMONIKER       lpmkDoc,
		DWORD			dwAdvf
)
{
    LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;
    LPOLEDOC lpOleDoc = (LPOLEDOC)lpServerDoc;

    switch (wAdvise) {

        case OLE_ONDATACHANGE:

            // inform clients that the data of the object has changed

            if (lpOutlineDoc->m_nDisableDraw == 0) {
                /* drawing is currently enabled. inform clients that
                **    the data of the object has changed 
                */

                lpServerDoc->m_fDataChanged = FALSE;

                if (lpServerDoc->m_lpDataAdviseHldr) {
                    OLEDBG_BEGIN2(
                        "IDataAdviseHolder::SendOnDataChange called\r\n"
                    );
                    lpServerDoc->m_lpDataAdviseHldr->lpVtbl->SendOnDataChange(
                            lpServerDoc->m_lpDataAdviseHldr, 
                            (LPDATAOBJECT)&lpOleDoc->m_DataObject, 
                            0, 
                            dwAdvf
                    );
                    OLEDBG_END2
                        
                    /* OLE2NOTE: we must note the time of last change
                    **    for our object in the RunningObjectTable.
                    **    this is used as the basis to answer
                    **    IOleObject::IsUpToDate.
                    */
                    OleStdNoteObjectChangeTime(lpOleDoc->m_dwRegROT);
                }

#if defined( INPLACE_SVR )
				/* OLE2NOTE: if the ServerDoc is currently in-place UI active,
				**    then is it important to renegotiate the size for the
				**    in-place document window BEFORE sending OnDataChange
				**    (which will cause the window to repaint).
				*/
				if (lpServerDoc->m_fSizeChanged) {
					lpServerDoc->m_fSizeChanged = FALSE;
					if (lpServerDoc->m_fInPlaceActive) 
						ServerDoc_UpdateInPlaceWindowOnExtentChange(lpServerDoc);
				}
#endif              
                
                /* OLE2NOTE: we do NOT need to tell our pseudo objects to
                **    broadcast OnDataChange notification because
                **    they will do it automatically when an editing
                **    change in the document affects a PseudoObj.
                **    (see OutlineNameTable_AddLineUpdate,
                **         OutlineNameTable_DeleteLineUpdate,
                **    and  ServerNameTable_EditLineUpdate)
                */

            } else {
                /* drawing is currently disabled. do not send
                **    notifications or call 
				**    IOleInPlaceObject::OnPosRectChange until drawing
				**    is re-enabled.  
                */
            }
            break;

        case OLE_ONCLOSE:

            // inform clients that the document is shutting down

            if (lpServerDoc->m_lpOleAdviseHldr) {
                OLEDBG_BEGIN2("IOleAdviseHolder::SendOnClose called\r\n");
                lpServerDoc->m_lpOleAdviseHldr->lpVtbl->SendOnClose(
                        lpServerDoc->m_lpOleAdviseHldr
                );
                OLEDBG_END2
            }

            /* OLE2NOTE: we do NOT need to tell our pseudo objects to
            **    broadcast OnClose notification because they will do
            **    it automatically when the pseudo object is closed.
            **    (see PseudoObj_Close)
            */

            break;

        case OLE_ONSAVE:

            // inform clients that the object has been saved

            OLEDBG_BEGIN3("ServerDoc_SendAdvise ONSAVE\r\n");

            if (lpServerDoc->m_lpOleAdviseHldr) {
                OLEDBG_BEGIN2("IOleAdviseHolder::SendOnSave called\r\n");
                lpServerDoc->m_lpOleAdviseHldr->lpVtbl->SendOnSave(
                        lpServerDoc->m_lpOleAdviseHldr
                );
                OLEDBG_END2
            }

            /* OLE2NOTE: inform any clients of pseudo objects
            **    within our document, that our document has been
            **    saved.  
            */
            ServerNameTable_InformAllPseudoObjectsDocSaved(
                    (LPSERVERNAMETABLE)lpOutlineDoc->m_lpNameTable,
                    lpmkDoc
            );


            if (lpOutlineDoc->m_docInitType == DOCTYPE_FROMFILE) {
                /* OLE2NOTE: we must note the time this File-Based
                **    object has been saved in the RunningObjectTable.
                **    These change times are used as the basis for
                **    IOleObject::IsUpToDate.  It is important to set
                **    the time of the file-based object following a
                **    save operation to exactly the time of the saved
                **    file. this helps IOleObject::IsUpToDate to give
                **    the correct answer after a file has been saved.
                */
                OleStdNoteFileChangeTime(
                        lpOutlineDoc->m_szFileName, lpOleDoc->m_dwRegROT);
            }
            OLEDBG_END3
            break;

        case OLE_ONRENAME:

            // inform clients that the object's name has changed

            OLEDBG_BEGIN3("ServerDoc_SendAdvise ONRENAME\r\n");

            if (lpmkDoc && lpServerDoc->m_lpOleAdviseHldr) {
                OLEDBG_BEGIN2("IOleAdviseHolder::SendOnRename called\r\n");
                lpServerDoc->m_lpOleAdviseHldr->lpVtbl->SendOnRename(
                        lpServerDoc->m_lpOleAdviseHldr,
                        lpmkDoc
                );
                OLEDBG_END2
            }

            /* OLE2NOTE: inform any clients of pseudo objects
            **    within our document, that our document's
            **    Moniker has changed.  
            */
            ServerNameTable_InformAllPseudoObjectsDocRenamed(
                    (LPSERVERNAMETABLE)lpOutlineDoc->m_lpNameTable, lpmkDoc);

            OLEDBG_END3
            break;
    }
}


/* ServerDoc_GetClassID
** --------------------
**    Return the class ID corresponding to the bits in the storage.
**    normally this will be our application's given CLSID. but if a
**    "TreateAs (aka. ActivateAs)" operation is taking place, then our
**    application needs to pretend to be the class of the object that
**    we are emulating. this is also the class that will be written
**    into the storage.
*/
HRESULT ServerDoc_GetClassID(LPSERVERDOC lpServerDoc, LPCLSID lpclsid)
{
#if defined( SVR_TREATAS )
	if (! IsEqualCLSID(&lpServerDoc->m_clsidTreatAs, &CLSID_NULL))
		*lpclsid = lpServerDoc->m_clsidTreatAs;
	else 
#endif	// SVR_TREATAS
		*lpclsid = CLSID_APP;
	
	return NOERROR;
}


#if defined( LATER )

/* ServerDoc_GetUserType
** ---------------------
**    Return the UserType corresponding to the bits in the storage.
**    normally this will be our application's given UserType. but if a
**    "TreateAs (aka. ActivateAs)" operation is taking place, then our
**    application needs to pretend to be the UserType of the object that
**    we are emulating. this is also the class that will be written
**    into the storage.
*/
HRESULT ServerDoc_GetUserType(LPSERVERDOC lpServerDoc, LPCLSID lpclsid)
{
    /* OLE2NOTE: we must make sure to set all out parameters to NULL. */
    *lpszUserType = NULL;

#if defined( SVR_TREATAS )
	if (lpServerDoc->m_clsidTreatAs != CLSID_NULL) 
		return OleStdGetUserType(&lpServerDoc->m_clsidTreatAs);
	else 
#endif	// SVR_TREATAS
		return OleStdGetUserType(&CLSID_APP);
}

#endif	// LATER


/* ServerDoc_UpdateMenu
 * --------------------
 *
 *  Update menu for embedding mode. the changes include:
 *      1 Remove File/New and File/Open (SDI ONLY)
 *      2 Change File/Save As.. to File/Save Copy As.. 
 *      3 Change File menu so it contains "Update" instead of "Save" 
 *      4 Change File/Exit to File/Exit & Return to <client doc>" 
 */
void ServerDoc_UpdateMenu(LPSERVERDOC lpServerDoc)
{
    char    str[256];
    HWND    hWndMain;
    HMENU   hMenu;
    
    OleDbgOut2("ServerDoc_UpdateMenu\r\n");

    hWndMain=g_lpApp->m_hWndApp;
    hMenu=GetMenu(hWndMain);

#if defined( SDI_VERSION )
    /* SDI ONLY: Remove File/New and File/Open */
    DeleteMenu(hMenu, IDM_F_NEW, MF_BYCOMMAND);
    DeleteMenu(hMenu, IDM_F_OPEN, MF_BYCOMMAND);
#endif
    
    // Change File.Save As.. to File.Save Copy As.. */
    ModifyMenu(hMenu,IDM_F_SAVEAS, MF_STRING, IDM_F_SAVEAS, "Save Copy As..");

    // Change File.Save to "&Update <container doc>"
    wsprintf(str, g_szUpdateCntrDoc, lpServerDoc->m_szContainerObj);
    ModifyMenu(hMenu, IDM_F_SAVE, MF_STRING, IDM_F_SAVE, str);
    
    // Change File/Exit to File/Exit & Return to <container doc>" */
    wsprintf(str, g_szExitNReturnToCntrDoc, lpServerDoc->m_szContainerObj);
    ModifyMenu(hMenu, IDM_F_EXIT, MF_STRING, IDM_F_EXIT, str);
    
    DrawMenuBar(hWndMain);
}

#if defined( MDI_VERSION )

// NOTE: ServerDoc_RestoreMenu is actually redundant because the 
//          app is dying when the function is called.  (In SDI, the 
//          app will terminate when the ref counter of the server doc 
//          is zero). However, it is important for MDI.

/* ServerDoc_RestoreMenu
 * ---------------------
 *
 *      Reset the menu to non-embedding mode
 */
void ServerDoc_RestoreMenu(LPSERVERDOC lpServerDoc)
{
    LPOUTLINEAPP	lpOutlineApp = (LPOUTLINEAPP)g_lpApp;
    HWND			hWndMain;
    HMENU			hMenu;
    
    OleDbgOut2("ServerDoc_RestoreMenu\r\n");

    hWndMain = lpOutlineApp->m_hWndApp;
    hMenu = GetMenu(hWndMain);

    /* Add back File/New, File/Open.. and File/Save */
    InsertMenu(hMenu, IDM_F_SAVEAS, MF_BYCOMMAND | MF_ENABLED | MF_STRING, 
        IDM_F_NEW, "&New");
    InsertMenu(hMenu, IDM_F_SAVEAS, MF_BYCOMMAND | MF_ENABLED | MF_STRING, 
        IDM_F_OPEN, "&Open...");

    /* Change File menu so it contains "Save As..." instead of */
    /* "Save Copy As..." */
    ModifyMenu(hMenu, IDM_F_SAVEAS, MF_STRING, IDM_F_SAVEAS, "Save &As..");

    /* Change File menu so it contains "Save" instead of "Update" */
    ModifyMenu(hMenu, IDM_F_SAVE, MF_STRING, IDM_F_SAVE, "&Save");
        
    /* Change File menu so it contains "Exit" */
    /* instead of just "Exit & Return to <client doc>" */
    ModifyMenu(hMenu, IDM_F_EXIT, MF_STRING, IDM_F_EXIT, "E&xit");
    
    DrawMenuBar (hWndMain);
}

#endif  // MDI_VERSION

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.