SVRBASE.C
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:65k
源码类别:

Windows编程

开发平台:

Visual C++

  1. /*************************************************************************
  2. **
  3. **    OLE 2 Server Sample Code
  4. **
  5. **    svrbase.c
  6. **
  7. **    This file contains all interfaces, methods and related support
  8. **    functions for the basic OLE Object (Server) application. The
  9. **    basic OLE Object application supports embedding an object and
  10. **    linking to a file-based or embedded object as a whole. The basic
  11. **    Object application includes the following implementation objects:
  12. **
  13. **    ClassFactory (aka. ClassObject) Object    (see file classfac.c)
  14. **      exposed interfaces:
  15. **          IClassFactory interface
  16. **
  17. **    ServerDoc Object
  18. **      exposed interfaces:
  19. **          IUnknown
  20. **          IOleObject interface
  21. **          IPersistStorage interface
  22. **          IDataObject interface
  23. **
  24. **    ServerApp Object
  25. **      exposed interfaces:
  26. **          IUnknown
  27. **
  28. **    (c) Copyright Microsoft Corp. 1992 - 1997 All Rights Reserved
  29. **
  30. *************************************************************************/
  31. #include "outline.h"
  32. OLEDBGDATA
  33. extern LPOUTLINEAPP             g_lpApp;
  34. extern IOleObjectVtbl           g_SvrDoc_OleObjectVtbl;
  35. extern IPersistStorageVtbl      g_SvrDoc_PersistStorageVtbl;
  36. #if defined( INPLACE_SVR )
  37. extern IOleInPlaceObjectVtbl        g_SvrDoc_OleInPlaceObjectVtbl;
  38. extern IOleInPlaceActiveObjectVtbl  g_SvrDoc_OleInPlaceActiveObjectVtbl;
  39. #endif  // INPLACE_SVR
  40. #if defined( SVR_TREATAS )
  41. extern IStdMarshalInfoVtbl      g_SvrDoc_StdMarshalInfoVtbl;
  42. #endif  // SVR_TREATAS
  43. // REVIEW: should use string resource for messages
  44. extern OLECHAR ErrMsgSaving[];
  45. extern OLECHAR ErrMsgFormatNotSupported[];
  46. static OLECHAR ErrMsgPSSaveFail[] = OLESTR("PSSave failed");
  47. static OLECHAR ErrMsgLowMemNClose[] = OLESTR("Warning OUT OF MEMORY! We must close down");
  48. extern char g_szUpdateCntrDoc[] = "&Update %s";
  49. extern char g_szExitNReturnToCntrDoc[] = "E&xit && Return to %s";
  50. /*************************************************************************
  51. ** ServerDoc::IOleObject interface implementation
  52. *************************************************************************/
  53. // IOleObject::QueryInterface method
  54. STDMETHODIMP SvrDoc_OleObj_QueryInterface(
  55.       LPOLEOBJECT             lpThis,
  56.       REFIID                  riid,
  57.       LPVOID FAR*             lplpvObj
  58. )
  59. {
  60.    LPSERVERDOC lpServerDoc =
  61.          ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;
  62.    return OleDoc_QueryInterface((LPOLEDOC)lpServerDoc, riid, lplpvObj);
  63. }
  64. // IOleObject::AddRef method
  65. STDMETHODIMP_(ULONG) SvrDoc_OleObj_AddRef(LPOLEOBJECT lpThis)
  66. {
  67.    LPSERVERDOC lpServerDoc =
  68.          ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;
  69.    OleDbgAddRefMethod(lpThis, "IOleObject");
  70.    return OleDoc_AddRef((LPOLEDOC)lpServerDoc);
  71. }
  72. // IOleObject::Release method
  73. STDMETHODIMP_(ULONG) SvrDoc_OleObj_Release(LPOLEOBJECT lpThis)
  74. {
  75.    LPSERVERDOC lpServerDoc =
  76.          ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;
  77.    OleDbgReleaseMethod(lpThis, "IOleObject");
  78.    return OleDoc_Release((LPOLEDOC)lpServerDoc);
  79. }
  80. // IOleObject::SetClientSite method
  81. STDMETHODIMP SvrDoc_OleObj_SetClientSite(
  82.       LPOLEOBJECT             lpThis,
  83.       LPOLECLIENTSITE         lpclientSite
  84. )
  85. {
  86.       LPSERVERDOC lpServerDoc =
  87.          ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;
  88.    LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;
  89.    // artificial AddRef in case object is destroyed during call
  90.    SvrDoc_OleObj_AddRef(lpThis);
  91.    OLEDBG_BEGIN2("SvrDoc_OleObj_SetClientSitern")
  92.    // SetClientSite is only valid to call on an embedded object
  93.    if (lpOutlineDoc->m_docInitType != DOCTYPE_EMBEDDED) {
  94.       OleDbgAssert(lpOutlineDoc->m_docInitType == DOCTYPE_EMBEDDED);
  95.       OLEDBG_END2
  96.       // release artificial AddRef
  97.       SvrDoc_OleObj_Release(lpThis);
  98.       return E_UNEXPECTED;
  99.    }
  100.    /* if we currently have a client site ptr, then release it. */
  101.    if (lpServerDoc->m_lpOleClientSite)
  102.       OleStdRelease((LPUNKNOWN)lpServerDoc->m_lpOleClientSite);
  103.    lpServerDoc->m_lpOleClientSite = (LPOLECLIENTSITE) lpclientSite;
  104.    // NOTE: to be able to hold onto clientSite pointer, we must AddRef it
  105.    if (lpclientSite)
  106.       lpclientSite->lpVtbl->AddRef(lpclientSite);
  107.    OLEDBG_END2
  108.    // release artificial AddRef
  109.    SvrDoc_OleObj_Release(lpThis);
  110.    return NOERROR;
  111. }
  112. // IOleObject::GetClientSite method
  113. STDMETHODIMP SvrDoc_OleObj_GetClientSite(
  114.       LPOLEOBJECT             lpThis,
  115.       LPOLECLIENTSITE FAR*    lplpClientSite
  116. )
  117. {
  118.    LPSERVERDOC lpServerDoc =
  119.          ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;
  120.    // artificial AddRef in case object is destroyed during call
  121.    SvrDoc_OleObj_AddRef(lpThis);
  122.    OleDbgOut2("SvrDoc_OleObj_GetClientSitern");
  123.    /* NOTE: we MUST AddRef this interface pointer to give the
  124.    **    caller a personal copy of the pointer
  125.    */
  126.    lpServerDoc->m_lpOleClientSite->lpVtbl->AddRef(
  127.          lpServerDoc->m_lpOleClientSite
  128.    );
  129.    *lplpClientSite = lpServerDoc->m_lpOleClientSite;
  130.    // release artificial AddRef
  131.    SvrDoc_OleObj_Release(lpThis);
  132.    return NOERROR;
  133. }
  134. // IOleObject::SetHostNames method
  135. STDMETHODIMP SvrDoc_OleObj_SetHostNames(
  136.       LPOLEOBJECT             lpThis,
  137.       LPCOLESTR               szContainerApp,
  138.       LPCOLESTR               szContainerObj
  139. )
  140. {
  141.    LPSERVERDOC lpServerDoc =
  142.          ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;
  143.    LPOUTLINEDOC    lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;
  144.    char szAnsiStr1[256], szAnsiStr2[256], szAnsiStr3[256];
  145.    // artificial AddRef in case object is destroyed during call
  146.    SvrDoc_OleObj_AddRef(lpThis);
  147.    OleDbgOut2("SvrDoc_OleObj_SetHostNamesrn");
  148.    OLESTRCPY(/*(LPOLESTR)*/lpServerDoc->m_szContainerApp, szContainerApp);
  149.    OLESTRCPY(/*(LPOLESTR)*/lpServerDoc->m_szContainerObj, szContainerObj);
  150.    /* The Window title for an embedded object is constructed as
  151.    **    follows:
  152.    **      <server app name> - <obj short type> in <cont. doc name>
  153.    **
  154.    **    here we construct the current document title portion of the
  155.    **    name which follows the '-'. OutlineDoc_SetTitle prepends the
  156.    **    "<server app name> - " to the document title.
  157.    */
  158.    // REVIEW: this string should be loaded from string resource
  159.    W2A (lpServerDoc->m_szContainerObj, szAnsiStr1, 256);
  160.    W2A (SHORTUSERTYPENAME, szAnsiStr3, 256);
  161.    wsprintf(szAnsiStr2, "%s in %s",
  162.          szAnsiStr3, (LPSTR)szAnsiStr1);
  163.    A2W (szAnsiStr2, lpOutlineDoc->m_szFileName, OLEUI_CCHPATHMAX);
  164.    lpOutlineDoc->m_lpszDocTitle = lpOutlineDoc->m_szFileName;
  165.    OutlineDoc_SetTitle(lpOutlineDoc, FALSE /*fMakeUpperCase*/);
  166.    /* NOTE: update the application menus correctly for an embedded
  167.    **    object. the changes include:
  168.    **      1 Remove File/New and File/Open (SDI ONLY)
  169.    **      2 Change File/Save As.. to File/Save Copy As..
  170.    **      3 Change File menu so it contains "Update" instead of "Save"
  171.    **      4 Change File/Exit to File/Exit & Return to <client doc>"
  172.    */
  173.    ServerDoc_UpdateMenu(lpServerDoc);
  174.    // release artificial AddRef
  175.    SvrDoc_OleObj_Release(lpThis);
  176.    return NOERROR;
  177. }
  178. // IOleObject::Close method
  179. STDMETHODIMP SvrDoc_OleObj_Close(
  180.       LPOLEOBJECT             lpThis,
  181.       DWORD                   dwSaveOption
  182. )
  183. {
  184.    LPSERVERDOC lpServerDoc =
  185.          ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;
  186.    BOOL fStatus;
  187.    OLEDBG_BEGIN2("SvrDoc_OleObj_Closern")
  188.    /* NOTE: the OLE 2.0 user model is that embedded objects should
  189.    **    always be saved when closed WITHOUT any prompting to the
  190.    **    user. this is the recommendation irregardless of whether the
  191.    **    object is activated in-place or open in its own window.
  192.    **    this is a CHANGE from the OLE 1.0 user model where it
  193.    **    was the guideline that servers always prompt to save changes.
  194.    **    thus OLE 2.0 compound document oriented container's should
  195.    **    always pass dwSaveOption==OLECLOSE_SAVEIFDIRTY. it is
  196.    **    possible that for programmatic uses a container may want to
  197.    **    specify a different dwSaveOption. the implementation of
  198.    **    various save options can be tricky, particularly considering
  199.    **    cases involving in-place activation. the following would be
  200.    **    reasonable behavior:
  201.    **
  202.    **      (1) OLECLOSE_SAVEIFDIRTY: if dirty, save. close.
  203.    **      (2) OLECLOSE_NOSAVE: close.
  204.    **      (3) OLECLOSE_PROMPTSAVE:
  205.    **        (a) object visible, but not in-place:
  206.    **               if not dirty, close.
  207.    **               switch(prompt)
  208.    **                  case IDYES: save. close.
  209.    **                  case IDNO: close.
  210.    **                  case IDCANCEL: return OLE_E_PROMPTSAVECANCELLED
  211.    **        (b) object invisible (includes UIDeactivated object)
  212.    **               if dirty, save. close.
  213.    **               NOTE: NO PROMPT. it is not appropriate to prompt
  214.    **                     if the object is not visible.
  215.    **        (c) object is in-place active:
  216.    **               if dirty, save. close.
  217.    **               NOTE: NO PROMPT. it is not appropriate to prompt
  218.    **                     if the object is active in-place.
  219.    */
  220.    fStatus = OutlineDoc_Close((LPOUTLINEDOC)lpServerDoc, dwSaveOption);
  221.    OleDbgAssertSz(fStatus == TRUE, "SvrDoc_OleObj_Close failedrn");
  222.    OLEDBG_END2
  223.    return (fStatus ? NOERROR : E_FAIL);
  224. }
  225. // IOleObject::SetMoniker method
  226. STDMETHODIMP SvrDoc_OleObj_SetMoniker(
  227.       LPOLEOBJECT             lpThis,
  228.       DWORD                   dwWhichMoniker,
  229.       LPMONIKER               lpmk
  230. )
  231. {
  232.    LPSERVERDOC lpServerDoc =
  233.          ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;
  234.    LPOLEDOC lpOleDoc = (LPOLEDOC)lpServerDoc;
  235.    LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;
  236.    LPMONIKER lpmkFull = NULL;
  237.    HRESULT hrErr;
  238.    HRESULT sc;
  239.    // artificial AddRef in case object is destroyed during call
  240.    SvrDoc_OleObj_AddRef(lpThis);
  241.    OLEDBG_BEGIN2("SvrDoc_OleObj_SetMonikerrn")
  242.    /* NOTE: if our full moniker is passed then we can use it,
  243.    **    otherwise we must call back to our ClientSite to get our full
  244.    **    moniker.
  245.    */
  246.    if (dwWhichMoniker == OLEWHICHMK_OBJFULL) {
  247.       /* Register the document as running with the new moniker and
  248.       **      notify any clients that our moniker has changed.
  249.       */
  250.       OleDoc_DocRenamedUpdate(lpOleDoc, lpmk);
  251.       if (lpOutlineDoc->m_docInitType != DOCTYPE_EMBEDDED) {
  252.          IBindCtx  FAR  *pbc = NULL;
  253.          LPOLESTR lpszName = NULL;
  254.          /* NOTE: if this is a FILE-based or untitled document
  255.          **    then we should accept this new moniker as our document's
  256.          **    moniker. we will remember this moniker instead of the
  257.          **    FileMoniker that we have by default. this allows
  258.          **    systems that use special monikers to track the
  259.          **    location of documents to inform a document that is a
  260.          **    link source of its special moniker. this enables the
  261.          **    document to use this special moniker when building
  262.          **    composite monikers to identify contained objects and
  263.          **    pseudo objects (ranges).
  264.          **
  265.          **    we should also use the DisplayName form of this
  266.          **    moniker as our document name in our window title.
  267.          */
  268.          if (lpOleDoc->m_lpFileMoniker) {
  269.             lpOleDoc->m_lpFileMoniker->lpVtbl->Release(
  270.                   lpOleDoc->m_lpFileMoniker);
  271.          }
  272.          lpOleDoc->m_lpFileMoniker = lpmk;
  273.          // we must AddRef the moniker to hold on to it
  274.          lpmk->lpVtbl->AddRef(lpmk);
  275.          /* we should also use the DisplayName form of this
  276.          **    moniker as our document name in our window title.
  277.          */
  278.          CreateBindCtx(0, (LPBC FAR*)&pbc);
  279.          lpmk->lpVtbl->GetDisplayName(lpmk,pbc,NULL,&lpszName);
  280.          pbc->lpVtbl->Release(pbc);
  281.          if (lpszName) {
  282.             OLESTRCPY(lpOutlineDoc->m_szFileName, lpszName);
  283.             lpOutlineDoc->m_lpszDocTitle = lpOutlineDoc->m_szFileName;
  284.             OutlineDoc_SetTitle(lpOutlineDoc, FALSE /*fMakeUpperCase*/);
  285.             OleStdFreeString(lpszName, NULL);
  286.          }
  287.       }
  288.       OLEDBG_END2
  289.       // release artificial AddRef
  290.       SvrDoc_OleObj_Release(lpThis);
  291.       return NOERROR;
  292.    }
  293.    /* if the passed moniker was NOT a full moniker then we must call
  294.    **    back to our ClientSite to get our full moniker. this is
  295.    **    needed in order to register in the RunningObjectTable. if we
  296.    **    don't have a ClientSite then this is an error.
  297.    */
  298.    if (lpServerDoc->m_lpOleClientSite == NULL) {
  299.       sc = E_FAIL;
  300.       goto error;
  301.    }
  302.    hrErr = lpServerDoc->m_lpOleClientSite->lpVtbl->GetMoniker(
  303.          lpServerDoc->m_lpOleClientSite,
  304.          OLEGETMONIKER_ONLYIFTHERE,
  305.          OLEWHICHMK_OBJFULL,
  306.          &lpmkFull
  307.    );
  308.    if (hrErr != NOERROR) {
  309.       sc = hrErr;
  310.       goto error;
  311.    }
  312.    /* Register the document as running with the new moniker and
  313.    **      notify any clients that our moniker has changed.
  314.    */
  315.    OleDoc_DocRenamedUpdate(lpOleDoc, lpmkFull);
  316.    if (lpmkFull)
  317.       OleStdRelease((LPUNKNOWN)lpmkFull);
  318.    OLEDBG_END2
  319.    // release artificial AddRef
  320.    SvrDoc_OleObj_Release(lpThis);
  321.    return NOERROR;
  322. error:
  323.    OLEDBG_END2
  324.    // release artificial AddRef
  325.    SvrDoc_OleObj_Release(lpThis);
  326.    return sc;
  327. }
  328. // IOleObject::GetMoniker method
  329. STDMETHODIMP SvrDoc_OleObj_GetMoniker(
  330.       LPOLEOBJECT             lpThis,
  331.       DWORD                   dwAssign,
  332.       DWORD                   dwWhichMoniker,
  333.       LPMONIKER FAR*          lplpmk
  334. )
  335. {
  336.    LPSERVERDOC lpServerDoc =
  337.          ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;
  338.    LPOLEDOC lpOleDoc = (LPOLEDOC)lpServerDoc;
  339.    HRESULT sc;
  340.    // artificial AddRef in case object is destroyed during call
  341.    SvrDoc_OleObj_AddRef(lpThis);
  342.    OLEDBG_BEGIN2("SvrDoc_OleObj_GetMonikerrn")
  343.    /* NOTE: we must make sure to set all out parameters to NULL. */
  344.    *lplpmk = NULL;
  345.    if (lpServerDoc->m_lpOleClientSite) {
  346.       /* document is an embedded object. retrieve our moniker from
  347.       **    our container.
  348.       */
  349.       OLEDBG_BEGIN2("IOleClientSite::GetMoniker calledrn")
  350.       sc =  lpServerDoc->m_lpOleClientSite->lpVtbl->GetMoniker(
  351.             lpServerDoc->m_lpOleClientSite,
  352.             dwAssign,
  353.             dwWhichMoniker,
  354.             lplpmk
  355.       ) ;
  356.       OLEDBG_END2
  357.    } else if (lpOleDoc->m_lpFileMoniker) {
  358.       /* document is a top-level user document (either
  359.       **    file-based or untitled). return the FileMoniker stored
  360.       **    with the document; it uniquely identifies the document.
  361.       */
  362.       if (dwWhichMoniker == OLEWHICHMK_CONTAINER)
  363.          sc = E_INVALIDARG;  // file-based object has no CONTAINER moniker
  364.       else {
  365.          *lplpmk = lpOleDoc->m_lpFileMoniker;
  366.          (*lplpmk)->lpVtbl->AddRef(*lplpmk); // must AddRef to pass out ptr
  367.          sc = S_OK;
  368.       }
  369.    } else {
  370.       // document is not yet fully initialized => no moniker
  371.       sc = E_FAIL;
  372.    }
  373.    OLEDBG_END2
  374.    // release artificial AddRef
  375.    SvrDoc_OleObj_Release(lpThis);
  376.    return sc;
  377. }
  378. // IOleObject::InitFromData method
  379. STDMETHODIMP SvrDoc_OleObj_InitFromData(
  380.       LPOLEOBJECT             lpThis,
  381.       LPDATAOBJECT            lpDataObject,
  382.       BOOL                    fCreation,
  383.       DWORD                   reserved
  384. )
  385. {
  386.    LPSERVERDOC lpServerDoc =
  387.          ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;
  388.    OLEDBG_BEGIN2("SvrDoc_OleObj_InitFromDatarn")
  389.    // REVIEW: NOT YET IMPLEMENTED
  390.    OLEDBG_END2
  391.    return E_NOTIMPL;
  392. }
  393. // IOleObject::GetClipboardData method
  394. STDMETHODIMP SvrDoc_OleObj_GetClipboardData(
  395.       LPOLEOBJECT             lpThis,
  396.       DWORD                   reserved,
  397.       LPDATAOBJECT FAR*       lplpDataObject
  398. )
  399. {
  400.    LPSERVERDOC lpServerDoc =
  401.          ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;
  402.    OLEDBG_BEGIN2("SvrDoc_OleObj_GetClipboardDatarn")
  403.    // REVIEW: NOT YET IMPLEMENTED
  404.    OLEDBG_END2
  405.    return E_NOTIMPL;
  406. }
  407. // IOleObject::DoVerb method
  408. STDMETHODIMP SvrDoc_OleObj_DoVerb(
  409.       LPOLEOBJECT             lpThis,
  410.       LONG                    lVerb,
  411.       LPMSG                   lpmsg,
  412.       LPOLECLIENTSITE         lpActiveSite,
  413.       LONG                    lindex,
  414.       HWND                    hwndParent,
  415.       LPCRECT                 lprcPosRect
  416. )
  417. {
  418.    LPSERVERDOC lpServerDoc =
  419.          ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;
  420.    LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;
  421.    HRESULT sc = S_OK;
  422.    // artificial AddRef in case object is destroyed during call
  423.    SvrDoc_OleObj_AddRef(lpThis);
  424.    OLEDBG_BEGIN2("SvrDoc_OleObj_DoVerbrn")
  425.    switch (lVerb) {
  426.       default:
  427.          /* NOTE: when an unknown verb number is given, the
  428.          **    server must take careful action:
  429.          **    1. if it is one of the specially defined OLEIVERB
  430.          **    (negative numbered) verbs, the app should return an
  431.          **    error (E_NOTIMPL) and perform no action.
  432.          **
  433.          **    2. if the verb is a application specific verb
  434.          **    (positive numbered verb), then the app should
  435.          **    return the special HRESULT (OLEOBJ_S_INVALIDVERB). BUT,
  436.          **    we should still perform our normal primary verb action.
  437.          */
  438.          if (lVerb < 0) {
  439.             OLEDBG_END2
  440.             return E_NOTIMPL;
  441.          } else {
  442.             sc = OLEOBJ_S_INVALIDVERB;
  443.          }
  444.          // deliberatly fall through to Primary Verb
  445. #if !defined( INPLACE_SVR )
  446.       case 0:
  447.       case OLEIVERB_SHOW:
  448.       case OLEIVERB_OPEN:
  449.          OutlineDoc_ShowWindow(lpOutlineDoc);
  450.          break;
  451.       case OLEIVERB_HIDE:
  452.          OleDoc_HideWindow((LPOLEDOC)lpServerDoc, FALSE /*fShutdown*/);
  453.          break;
  454. #endif  // ! INPLACE_SVR
  455. #if defined( INPLACE_SVR )
  456.       case 0:
  457.       case OLEIVERB_SHOW:
  458.          /* NOTE: if our window is already open (visible) then
  459.          **    we should simply surface the open window. if not,
  460.          **    then we can do our primary action of in-place
  461.          **    activation.
  462.          */
  463.          if ( lpServerDoc->m_lpOleClientSite
  464.                && ! (IsWindowVisible(lpOutlineDoc->m_hWndDoc) &&
  465.                      ! lpServerDoc->m_fInPlaceActive) ) {
  466.             ServerDoc_DoInPlaceActivate(
  467.                   lpServerDoc, lVerb, lpmsg, lpActiveSite);
  468.          }
  469.          OutlineDoc_ShowWindow(lpOutlineDoc);
  470.          break;
  471.       case 1:
  472.       case OLEIVERB_OPEN:
  473.          ServerDoc_DoInPlaceDeactivate(lpServerDoc);
  474.          OutlineDoc_ShowWindow(lpOutlineDoc);
  475.          break;
  476.       case OLEIVERB_HIDE:
  477.          if (lpServerDoc->m_fInPlaceActive) {
  478.             SvrDoc_IPObj_UIDeactivate(
  479.                   (LPOLEINPLACEOBJECT)&lpServerDoc->m_OleInPlaceObject);
  480. #if defined( SVR_INSIDEOUT )
  481.             /* NOTE: an inside-out style in-place server will
  482.             **    NOT hide its window in UIDeactive (an outside-in
  483.             **    style object will hide its window in
  484.             **    UIDeactivate). thus we need to explicitly hide
  485.             **    our window now.
  486.             */
  487.             ServerDoc_DoInPlaceHide(lpServerDoc);
  488. #endif // INSIEDOUT
  489.          } else {
  490.             OleDoc_HideWindow((LPOLEDOC)lpServerDoc, FALSE /*fShutdown*/);
  491.          }
  492.          break;
  493.       case OLEIVERB_UIACTIVATE:
  494. #if defined( SVR_INSIDEOUT )
  495.       /* NOTE: only an inside-out style object supports
  496.       **    INPLACEACTIVATE verb
  497.       */
  498.       case OLEIVERB_INPLACEACTIVATE:
  499. #endif // SVR_INSIDEOUT
  500.          /* NOTE: if our window is already open (visible) then
  501.          **    we can NOT activate in-place.
  502.          */
  503.          if (IsWindowVisible(lpOutlineDoc->m_hWndDoc) &&
  504.                   ! lpServerDoc->m_fInPlaceActive ) {
  505.             sc = OLE_E_NOT_INPLACEACTIVE;
  506.          } else {
  507.             sc =  ServerDoc_DoInPlaceActivate(
  508.                   lpServerDoc, lVerb, lpmsg, lpActiveSite) ;
  509.             if (SUCCEEDED(sc))
  510.                OutlineDoc_ShowWindow(lpOutlineDoc);
  511.          }
  512.          break;
  513. #endif  // INPLACE_SVR
  514.    }
  515.    OLEDBG_END2
  516.    // release artificial AddRef
  517.    SvrDoc_OleObj_Release(lpThis);
  518.    return sc;
  519. }
  520. // IOleObject::EnumVerbs method
  521. STDMETHODIMP SvrDoc_OleObj_EnumVerbs(
  522.       LPOLEOBJECT             lpThis,
  523.       LPENUMOLEVERB FAR*      lplpenumOleVerb
  524. )
  525. {
  526.    OleDbgOut2("SvrDoc_OleObj_EnumVerbsrn");
  527.    /* NOTE: we must make sure to set all out parameters to NULL. */
  528.    *lplpenumOleVerb = NULL;
  529.    /* An object implemented as a server EXE (as this sample
  530.    **    is) may simply return OLE_S_USEREG to instruct the OLE
  531.    **    DefHandler to call the OleReg* helper API which uses info in
  532.    **    the registration database. Alternatively, the OleRegEnumVerbs
  533.    **    API may be called directly. Objects implemented as a server
  534.    **    DLL may NOT return OLE_S_USEREG; they must call the OleReg*
  535.    **    API or provide their own implementation. For EXE based
  536.    **    objects it is more efficient to return OLE_S_USEREG, because
  537.    **    in then the verb enumerator is instantiated in the callers
  538.    **    process space and no LRPC remoting is required.
  539.    */
  540.    return OLE_S_USEREG;
  541. }
  542. // IOleObject::Update method
  543. STDMETHODIMP SvrDoc_OleObj_Update(LPOLEOBJECT lpThis)
  544. {
  545.    OleDbgOut2("SvrDoc_OleObj_Updatern");
  546.    /* NOTE: a server-only app is always "up-to-date".
  547.    **    a container-app which contains links where the link source
  548.    **    has changed since the last update of the link would be
  549.    **    considered "out-of-date". the "Update" method instructs the
  550.    **    object to get an update from any out-of-date links.
  551.    */
  552.    return NOERROR;
  553. }
  554. // IOleObject::IsUpToDate method
  555. STDMETHODIMP SvrDoc_OleObj_IsUpToDate(LPOLEOBJECT lpThis)
  556. {
  557.    OleDbgOut2("SvrDoc_OleObj_IsUpToDatern");
  558.    /* NOTE: a server-only app is always "up-to-date".
  559.    **    a container-app which contains links where the link source
  560.    **    has changed since the last update of the link would be
  561.    **    considered "out-of-date".
  562.    */
  563.    return NOERROR;
  564. }
  565. // IOleObject::GetUserClassID method
  566. STDMETHODIMP SvrDoc_OleObj_GetUserClassID(
  567.       LPOLEOBJECT             lpThis,
  568.       LPCLSID                 lpClassID
  569. )
  570. {
  571.    LPSERVERDOC lpServerDoc =
  572.          ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;
  573.    OleDbgOut2("SvrDoc_OleObj_GetClassIDrn");
  574.    /* NOTE: we must be carefull to return the correct CLSID here.
  575.    **    if we are currently preforming a "TreatAs (aka. ActivateAs)"
  576.    **    operation then we need to return the class of the object
  577.    **    written in the storage of the object. otherwise we would
  578.    **    return our own class id.
  579.    */
  580.    return ServerDoc_GetClassID(lpServerDoc, lpClassID);
  581. }
  582. // IOleObject::GetUserType method
  583. STDMETHODIMP SvrDoc_OleObj_GetUserType(
  584.       LPOLEOBJECT             lpThis,
  585.       DWORD                   dwFormOfType,
  586.       LPOLESTR FAR*           lpszUserType
  587. )
  588. {
  589.    LPSERVERDOC lpServerDoc =
  590.          ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;
  591.    OleDbgOut2("SvrDoc_OleObj_GetUserTypern");
  592.    /* NOTE: we must make sure to set all out parameters to NULL. */
  593.    *lpszUserType = NULL;
  594.    /* NOTE: we must be carefull to return the correct user type here.
  595.    **    if we are currently preforming a "TreatAs (aka. ActivateAs)"
  596.    **    operation then we need to return the user type name that
  597.    **    corresponds to the class of the object we are currently
  598.    **    emmulating. otherwise we should return our normal user type
  599.    **    name corresponding to our own class. This routine determines
  600.    **    the current clsid in effect.
  601.    **
  602.    **    An object implemented as a server EXE (as this sample
  603.    **    is) may simply return OLE_S_USEREG to instruct the OLE
  604.    **    DefHandler to call the OleReg* helper API which uses info in
  605.    **    the registration database. Alternatively, the OleRegGetUserType
  606.    **    API may be called directly. Objects implemented as a server
  607.    **    DLL may NOT return OLE_S_USEREG; they must call the OleReg*
  608.    **    API or provide their own implementation. For EXE based
  609.    **    objects it is more efficient to return OLE_S_USEREG, because
  610.    **    in then the return string is instantiated in the callers
  611.    **    process space and no LRPC remoting is required.
  612.    */
  613. #if defined( SVR_TREATAS )
  614.    if (! IsEqualCLSID(&lpServerDoc->m_clsidTreatAs, &CLSID_NULL) )
  615.       return OleRegGetUserType(
  616.          (REFCLSID)&lpServerDoc->m_clsidTreatAs,dwFormOfType,lpszUserType);
  617.    else
  618. #endif  // SVR_TREATAS
  619.    return OLE_S_USEREG;
  620. }
  621. // IOleObject::SetExtent method
  622. STDMETHODIMP SvrDoc_OleObj_SetExtent(
  623.       LPOLEOBJECT             lpThis,
  624.       DWORD                   dwDrawAspect,
  625.       LPSIZEL                 lplgrc
  626. )
  627. {
  628.    OleDbgOut2("SvrDoc_OleObj_SetExtentrn");
  629.    /* SVROUTL does NOT allow the object's size to be set by its
  630.    **    container. the size of the ServerDoc object is determined by
  631.    **    the data contained within the document.
  632.    */
  633.    return E_FAIL;
  634. }
  635. // IOleObject::GetExtent method
  636. STDMETHODIMP SvrDoc_OleObj_GetExtent(
  637.       LPOLEOBJECT             lpThis,
  638.       DWORD                   dwDrawAspect,
  639.       LPSIZEL                 lpsizel
  640. )
  641. {
  642.    LPOLEDOC lpOleDoc =
  643.          (LPOLEDOC)((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;
  644.    // artificial AddRef in case object is destroyed during call
  645.    SvrDoc_OleObj_AddRef(lpThis);
  646.    OleDbgOut2("SvrDoc_OleObj_GetExtentrn");
  647.    /* NOTE: it is VERY important to check which aspect the caller
  648.    **    is asking about. an object implemented by a server EXE MAY
  649.    **    fail to return extents when asked for DVASPECT_ICON.
  650.    */
  651.    if (dwDrawAspect == DVASPECT_CONTENT) {
  652.       OleDoc_GetExtent(lpOleDoc, lpsizel);
  653.       // release artificial AddRef
  654.       SvrDoc_OleObj_Release(lpThis);
  655.       return NOERROR;
  656.    }
  657. #if defined( LATER )
  658.    else if (dwDrawAspect == DVASPECT_THUMBNAIL)
  659.    {
  660.       /* as our thumbnail we will render only the first page of the
  661.       **    document. calculate extents of our thumbnail rendering.
  662.       **
  663.       ** NOTE: thumbnails are most often used by applications in
  664.       **    FindFile or FileOpen type dialogs to give the user a
  665.       **    quick view of the contents of the file or object.
  666.       */
  667.       OleDoc_GetThumbnailExtent(lpOleDoc, lpsizel);
  668.       // release artificial AddRef
  669.       SvrDoc_OleObj_Release(lpThis);
  670.       return NOERROR;
  671.    }
  672. #endif
  673.    else
  674.    {
  675.       // release artificial AddRef
  676.       SvrDoc_OleObj_Release(lpThis);
  677.       return E_FAIL;
  678.    }
  679. }
  680. // IOleObject::Advise method
  681. STDMETHODIMP SvrDoc_OleObj_Advise(
  682.       LPOLEOBJECT             lpThis,
  683.       LPADVISESINK            lpAdvSink,
  684.       LPDWORD                 lpdwConnection
  685. )
  686. {
  687.    LPSERVERDOC lpServerDoc =
  688.          ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;
  689.    HRESULT hrErr;
  690.    HRESULT   sc;
  691.    // artificial AddRef in case object is destroyed during call
  692.    SvrDoc_OleObj_AddRef(lpThis);
  693.    OLEDBG_BEGIN2("SvrDoc_OleObj_Advisern");
  694.    if (lpServerDoc->m_OleDoc.m_fObjIsClosing)
  695.    {
  696.        //  We don't accept any more Advise's once we're closing
  697.        sc = OLE_E_ADVISENOTSUPPORTED;
  698.        goto error;
  699.    }
  700.    if (lpServerDoc->m_lpOleAdviseHldr == NULL &&
  701.       CreateOleAdviseHolder(&lpServerDoc->m_lpOleAdviseHldr) != NOERROR) {
  702.       sc = E_OUTOFMEMORY;
  703.       goto error;
  704.    }
  705.    OLEDBG_BEGIN2("IOleAdviseHolder::Advise calledrn")
  706.    hrErr = lpServerDoc->m_lpOleAdviseHldr->lpVtbl->Advise(
  707.          lpServerDoc->m_lpOleAdviseHldr,
  708.          lpAdvSink,
  709.          lpdwConnection
  710.    );
  711.    OLEDBG_END2
  712.    OLEDBG_END2
  713.    // release artificial AddRef
  714.    SvrDoc_OleObj_Release(lpThis);
  715.    return hrErr;
  716. error:
  717.    OLEDBG_END2
  718.    *lpdwConnection = 0;
  719.    // release artificial AddRef
  720.    SvrDoc_OleObj_Release(lpThis);
  721.    return sc;
  722. }
  723. // IOleObject::Unadvise method
  724. STDMETHODIMP SvrDoc_OleObj_Unadvise(LPOLEOBJECT lpThis, DWORD dwConnection)
  725. {
  726.    LPSERVERDOC lpServerDoc =
  727.          ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;
  728.    HRESULT hrErr;
  729.    HRESULT   sc;
  730.    // artificial AddRef in case object is destroyed during call
  731.    SvrDoc_OleObj_AddRef(lpThis);
  732.    OLEDBG_BEGIN2("SvrDoc_OleObj_Unadvisern");
  733.    if (lpServerDoc->m_lpOleAdviseHldr == NULL) {
  734.       sc = E_FAIL;
  735.       goto error;
  736.    }
  737.    OLEDBG_BEGIN2("IOleAdviseHolder::Unadvise calledrn")
  738.    hrErr = lpServerDoc->m_lpOleAdviseHldr->lpVtbl->Unadvise(
  739.          lpServerDoc->m_lpOleAdviseHldr,
  740.          dwConnection
  741.    );
  742.    OLEDBG_END2
  743.    OLEDBG_END2
  744.    // release artificial AddRef
  745.    SvrDoc_OleObj_Release(lpThis);
  746.    return hrErr;
  747. error:
  748.    OLEDBG_END2
  749.    // release artificial AddRef
  750.    SvrDoc_OleObj_Release(lpThis);
  751.    return sc;
  752. }
  753. // IOleObject::EnumAdvise method
  754. STDMETHODIMP SvrDoc_OleObj_EnumAdvise(
  755.       LPOLEOBJECT             lpThis,
  756.       LPENUMSTATDATA FAR*     lplpenumAdvise
  757. )
  758. {
  759.    LPSERVERDOC lpServerDoc =
  760.          ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;
  761.    HRESULT hrErr;
  762.    HRESULT   sc;
  763.    // artificial AddRef in case object is destroyed during call
  764.    SvrDoc_OleObj_AddRef(lpThis);
  765.    OLEDBG_BEGIN2("SvrDoc_OleObj_EnumAdvisern");
  766.    /* NOTE: we must make sure to set all out parameters to NULL. */
  767.    *lplpenumAdvise = NULL;
  768.    if (lpServerDoc->m_lpOleAdviseHldr == NULL) {
  769.       sc = E_FAIL;
  770.       goto error;
  771.    }
  772.    OLEDBG_BEGIN2("IOleAdviseHolder::EnumAdvise calledrn")
  773.    hrErr = lpServerDoc->m_lpOleAdviseHldr->lpVtbl->EnumAdvise(
  774.          lpServerDoc->m_lpOleAdviseHldr,
  775.          lplpenumAdvise
  776.    );
  777.    OLEDBG_END2
  778.    OLEDBG_END2
  779.    // release artificial AddRef
  780.    SvrDoc_OleObj_Release(lpThis);
  781.    return hrErr;
  782. error:
  783.    OLEDBG_END2
  784.    // release artificial AddRef
  785.    SvrDoc_OleObj_Release(lpThis);
  786.    return sc;
  787. }
  788. // IOleObject::GetMiscStatus method
  789. STDMETHODIMP SvrDoc_OleObj_GetMiscStatus(
  790.       LPOLEOBJECT             lpThis,
  791.       DWORD                   dwAspect,
  792.       DWORD FAR*              lpdwStatus
  793. )
  794. {
  795.    LPSERVERDOC lpServerDoc =
  796.          ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;
  797.    LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;
  798.    // artificial AddRef in case object is destroyed during call
  799.    SvrDoc_OleObj_AddRef(lpThis);
  800.    OleDbgOut2("SvrDoc_OleObj_GetMiscStatusrn");
  801.    /* Get our default MiscStatus for the given Aspect. this
  802.    **    information is registered in the RegDB. We query the RegDB
  803.    **    here to guarantee that the value returned from this method
  804.    **    agrees with the values in RegDB. in this way we only have to
  805.    **    maintain the info in one place (in the RegDB). Alternatively
  806.    **    we could have the values hard coded here.
  807.    */
  808.    OleRegGetMiscStatus((REFCLSID)&CLSID_APP, dwAspect, lpdwStatus);
  809.    /* NOTE: check if the data copied is compatible to be
  810.    **    linked by an OLE 1.0 container. it is compatible if
  811.    **    either the data is an untitled document, a file, or a
  812.    **    selection of data within a file. if the data is part of
  813.    **    an embedded object, then it is NOT compatible to be
  814.    **    linked by an OLE 1.0 container. if it is compatible then
  815.    **    we must include OLEMISC_CANLINKBYOLE1 as part of the
  816.    **    dwStatus flags transfered via CF_OBJECTDESCRIPTOR or
  817.    **    CF_LINKSRCDESCRIPTOR.
  818.    */
  819.    if (lpOutlineDoc->m_docInitType == DOCTYPE_NEW ||
  820.       lpOutlineDoc->m_docInitType == DOCTYPE_FROMFILE)
  821.       *lpdwStatus |= OLEMISC_CANLINKBYOLE1;
  822. #if defined( INPLACE_SVR )
  823.    if (dwAspect == DVASPECT_CONTENT)
  824.       *lpdwStatus |= (OLEMISC_INSIDEOUT | OLEMISC_ACTIVATEWHENVISIBLE);
  825. #endif  // INPLACE_SVR
  826.    // release artificial AddRef
  827.    SvrDoc_OleObj_Release(lpThis);
  828.    return NOERROR;
  829. }
  830. // IOleObject::SetColorScheme method
  831. STDMETHODIMP SvrDoc_OleObj_SetColorScheme(
  832.       LPOLEOBJECT             lpThis,
  833.       LPLOGPALETTE            lpLogpal
  834. )
  835. {
  836.    OleDbgOut2("SvrDoc_OleObj_SetColorSchemern");
  837.    // REVIEW: NOT YET IMPLEMENTED
  838.    return E_NOTIMPL;
  839. }
  840. /*************************************************************************
  841. ** ServerDoc::IPersistStorage interface implementation
  842. *************************************************************************/
  843. // IPersistStorage::QueryInterface method
  844. STDMETHODIMP SvrDoc_PStg_QueryInterface(
  845.       LPPERSISTSTORAGE        lpThis,
  846.       REFIID                  riid,
  847.       LPVOID FAR*             lplpvObj
  848. )
  849. {
  850.    LPSERVERDOC lpServerDoc =
  851.          ((struct CDocPersistStorageImpl FAR*)lpThis)->lpServerDoc;
  852.    return OleDoc_QueryInterface((LPOLEDOC)lpServerDoc, riid, lplpvObj);
  853. }
  854. // IPersistStorage::AddRef method
  855. STDMETHODIMP_(ULONG) SvrDoc_PStg_AddRef(LPPERSISTSTORAGE lpThis)
  856. {
  857.    LPSERVERDOC lpServerDoc =
  858.          ((struct CDocPersistStorageImpl FAR*)lpThis)->lpServerDoc;
  859.    OleDbgAddRefMethod(lpThis, "IPersistStorage");
  860.    return OleDoc_AddRef((LPOLEDOC)lpServerDoc);
  861. }
  862. // IPersistStorage::Release method
  863. STDMETHODIMP_(ULONG) SvrDoc_PStg_Release(LPPERSISTSTORAGE lpThis)
  864. {
  865.    LPSERVERDOC lpServerDoc =
  866.          ((struct CDocPersistStorageImpl FAR*)lpThis)->lpServerDoc;
  867.    OleDbgReleaseMethod(lpThis, "IPersistStorage");
  868.    return OleDoc_Release((LPOLEDOC)lpServerDoc);
  869. }
  870. // IPersistStorage::GetClassID method
  871. STDMETHODIMP SvrDoc_PStg_GetClassID(
  872.       LPPERSISTSTORAGE        lpThis,
  873.       LPCLSID                 lpClassID
  874. )
  875. {
  876.    LPSERVERDOC lpServerDoc =
  877.          ((struct CDocPersistStorageImpl FAR*)lpThis)->lpServerDoc;
  878.    OleDbgOut2("SvrDoc_PStg_GetClassIDrn");
  879.    /* NOTE: we must be carefull to return the correct CLSID here.
  880.    **    if we are currently preforming a "TreatAs (aka. ActivateAs)"
  881.    **    operation then we need to return the class of the object
  882.    **    written in the storage of the object. otherwise we would
  883.    **    return our own class id.
  884.    */
  885.    return ServerDoc_GetClassID(lpServerDoc, lpClassID);
  886. }
  887. // IPersistStorage::IsDirty method
  888. STDMETHODIMP  SvrDoc_PStg_IsDirty(LPPERSISTSTORAGE  lpThis)
  889. {
  890.    LPSERVERDOC lpServerDoc =
  891.          ((struct CDocPersistStorageImpl FAR*)lpThis)->lpServerDoc;
  892.    OleDbgOut2("SvrDoc_PStg_IsDirtyrn");
  893.    if (OutlineDoc_IsModified((LPOUTLINEDOC)lpServerDoc))
  894.       return NOERROR;
  895.    else
  896.       return S_FALSE;
  897. }
  898. // IPersistStorage::InitNew method
  899. STDMETHODIMP SvrDoc_PStg_InitNew(
  900.       LPPERSISTSTORAGE        lpThis,
  901.       LPSTORAGE               lpStg
  902. )
  903. {
  904.    LPSERVERDOC lpServerDoc =
  905.          ((struct CDocPersistStorageImpl FAR*)lpThis)->lpServerDoc;
  906.    LPOLEDOC lpOleDoc = (LPOLEDOC)lpServerDoc;
  907.    LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;
  908.    LPOLESTR    lpszUserType = /*(LPOLESTR)*/FULLUSERTYPENAME;
  909.    HRESULT hrErr;
  910.    HRESULT sc;
  911.    OLEDBG_BEGIN2("SvrDoc_PStg_InitNewrn")
  912. #if defined( SVR_TREATAS )
  913.    {
  914.       LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;
  915.       CLSID       clsid;
  916.       CLIPFORMAT  cfFmt;
  917.       LPOLESTR       lpszType;
  918.       /* NOTE: if the Server is capable of supporting "TreatAs"
  919.       **    (aka. ActivateAs), it must read the class that is written
  920.       **    into the storage. if this class is NOT the app's own
  921.       **    class ID, then this is a TreatAs operation. the server
  922.       **    then must faithfully pretend to be the class that is
  923.       **    written into the storage. it must also faithfully write
  924.       **    the data back to the storage in the SAME format as is
  925.       **    written in the storage.
  926.       **
  927.       **    SVROUTL and ISVROTL can emulate each other. they have the
  928.       **    simplification that they both read/write the identical
  929.       **    format. thus for these apps no actual conversion of the
  930.       **    native bits is actually required.
  931.       */
  932.       lpServerDoc->m_clsidTreatAs = CLSID_NULL;
  933.       if (OleStdGetTreatAsFmtUserType(&CLSID_APP, lpStg, &clsid,
  934.                      (CLIPFORMAT FAR*)&cfFmt, /*(LPOLESTR FAR*)*/&lpszType)) {
  935.          if (cfFmt == lpOutlineApp->m_cfOutline) {
  936.             // We should perform TreatAs operation
  937.             if (lpServerDoc->m_lpszTreatAsType)
  938.                OleStdFreeString(lpServerDoc->m_lpszTreatAsType, NULL);
  939.             lpServerDoc->m_clsidTreatAs = clsid;
  940.             ((LPOUTLINEDOC)lpServerDoc)->m_cfSaveFormat = cfFmt;
  941.             lpServerDoc->m_lpszTreatAsType = lpszType;
  942.             lpszUserType = lpServerDoc->m_lpszTreatAsType;
  943.             OleDbgOut3("SvrDoc_PStg_InitNew: TreateAs ==> '");
  944. //            OleDbgOutNoPrefix3(lpServerDoc->m_lpszTreatAsType);
  945.             OleDbgOutNoPrefix3("'rn");
  946.          } else {
  947.             // ERROR: we ONLY support TreatAs for CF_OUTLINE format
  948.             OleDbgOut("SvrDoc_PStg_InitNew: INVALID TreatAs Formatrn");
  949.             OleStdFreeString(lpszType, NULL);
  950.          }
  951.       }
  952.    }
  953. #endif  // SVR_TREATAS
  954.    /* NOTE: a server EXE object should write its format tag to its
  955.    **    storage in InitNew so that the DefHandler can know the format
  956.    **    of the object. this is particularly important if the objects
  957.    **    uses CF_METATFILE or CF_DIB as its format. the DefHandler
  958.    **    automatically avoids separately storing presentation cache
  959.    **    data when the object's native data is a standard presentation
  960.    **    format.
  961.    */
  962.    WriteFmtUserTypeStg(lpStg,(CLIPFORMAT)lpOutlineApp->m_cfOutline,lpszUserType);
  963.    // set the doc to a new embedded object.
  964.    if (! ServerDoc_InitNewEmbed(lpServerDoc)) {
  965.       sc = E_FAIL;
  966.       goto error;
  967.    }
  968.    /* NOTE: An embedded object must guarantee that it can save
  969.    **    even in low memory situations. it must be able to
  970.    **    successfully save itself without consuming any additional
  971.    **    memory. this means that a server is NOT supposed to open or
  972.    **    create any streams or storages when
  973.    **    IPersistStorage::Save(fSameAsLoad==TRUE) is called. thus an
  974.    **    embedded object should hold onto its storage and pre-open and
  975.    **    hold open any streams that it will need later when it is time
  976.    **    to save.
  977.    */
  978.    hrErr = lpStg->lpVtbl->CreateStream(
  979.          lpStg,
  980.          OLESTR("LineList"),
  981.          STGM_WRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE,
  982.          0,
  983.          0,
  984.          &lpOleDoc->m_lpLLStm
  985.    );
  986.    if (hrErr != NOERROR) {
  987.       OleDbgAssertSz(hrErr==NOERROR,"Could not create LineList stream");
  988.       OleDbgOutHResult("LineList CreateStream returned", hrErr);
  989.       sc = hrErr;
  990.       goto error;
  991.    }
  992.    hrErr = lpStg->lpVtbl->CreateStream(
  993.          lpStg,
  994.          OLESTR("NameTable"),
  995.          STGM_WRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE,
  996.          0,
  997.          0,
  998.          &lpOleDoc->m_lpNTStm
  999.    );
  1000.    if (hrErr != NOERROR) {
  1001.       OleDbgAssertSz(hrErr==NOERROR,"Could not create NameTable stream");
  1002.       OleDbgOutHResult("NameTable CreateStream returned", hrErr);
  1003.       sc = hrErr;
  1004.       goto error;
  1005.    }
  1006.    lpOleDoc->m_lpStg = lpStg;
  1007.    // NOTE: to be able to hold onto IStorage* pointer, we must AddRef it
  1008.    lpStg->lpVtbl->AddRef(lpStg);
  1009.    OLEDBG_END2
  1010.    return NOERROR;
  1011. error:
  1012.    OLEDBG_END2
  1013.    return sc;
  1014. }
  1015. // IPersistStorage::Load method
  1016. STDMETHODIMP SvrDoc_PStg_Load(
  1017.       LPPERSISTSTORAGE        lpThis,
  1018.       LPSTORAGE               lpStg
  1019. )
  1020. {
  1021.    LPSERVERDOC lpServerDoc =
  1022.          ((struct CDocPersistStorageImpl FAR*)lpThis)->lpServerDoc;
  1023.    LPOLEDOC lpOleDoc = (LPOLEDOC)lpServerDoc;
  1024.    LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;
  1025.    HRESULT sc;
  1026.    HRESULT hrErr;
  1027.    OLEDBG_BEGIN2("SvrDoc_PStg_Loadrn")
  1028.    if (OutlineDoc_LoadFromStg((LPOUTLINEDOC)lpServerDoc, lpStg)) {
  1029.       ((LPOUTLINEDOC)lpServerDoc)->m_docInitType = DOCTYPE_EMBEDDED;
  1030.       /* NOTE: we need to check if the ConvertStg bit is on. if
  1031.       **    so, we need to clear the ConvertStg bit and mark the
  1032.       **    document as dirty so as to force a save when the document
  1033.       **    is closed. the actual conversion of the bits should be
  1034.       **    performed when the data is loaded from the IStorage*. in
  1035.       **    our case any conversion of data formats would be done in
  1036.       **    OutlineDoc_LoadFromStg function. in reality both SVROUTL
  1037.       **    and ISVROTL read and write the same format so no actual
  1038.       **    conversion of data bits is necessary.
  1039.       */
  1040.       if (GetConvertStg(lpStg) == NOERROR) {
  1041.          SetConvertStg(lpStg, FALSE);
  1042.          OleDbgOut3("SvrDoc_PStg_Load: ConvertStg==TRUErn");
  1043.          OutlineDoc_SetModified(lpOutlineDoc, TRUE, FALSE, FALSE);
  1044.       }
  1045.    } else {
  1046.       sc = E_FAIL;
  1047.       goto error;
  1048.    }
  1049.    /* NOTE: An embedded object must guarantee that it can save
  1050.    **    even in low memory situations. it must be able to
  1051.    **    successfully save itself without consuming any additional
  1052.    **    memory. this means that a server is NOT supposed to open or
  1053.    **    create any streams or storages when
  1054.    **    IPersistStorage::Save(fSameAsLoad==TRUE) is called. thus an
  1055.    **    embedded object should hold onto its storage and pre-open and
  1056.    **    hold open any streams that it will need later when it is time
  1057.    **    to save.
  1058.    */
  1059.    if (lpOleDoc->m_lpLLStm)
  1060.       OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpLLStm);
  1061.    hrErr = lpStg->lpVtbl->OpenStream(
  1062.          lpStg,
  1063.          OLESTR("LineList"),
  1064.          NULL,
  1065.          STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  1066.          0,
  1067.          &lpOleDoc->m_lpLLStm
  1068.    );
  1069.    if (hrErr != NOERROR) {
  1070.       OleDbgAssertSz(hrErr==NOERROR,"Could not create LineList stream");
  1071.       OleDbgOutHResult("LineList CreateStream returned", hrErr);
  1072.       sc = hrErr;
  1073.       goto error;
  1074.    }
  1075.    if (lpOleDoc->m_lpNTStm)
  1076.       OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpNTStm);
  1077.    hrErr = lpStg->lpVtbl->OpenStream(
  1078.          lpStg,
  1079.          OLESTR("NameTable"),
  1080.          NULL,
  1081.          STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  1082.          0,
  1083.          &lpOleDoc->m_lpNTStm
  1084.    );
  1085.    if (hrErr != NOERROR) {
  1086.       OleDbgAssertSz(hrErr==NOERROR,"Could not create NameTable stream");
  1087.       OleDbgOutHResult("NameTable CreateStream returned", hrErr);
  1088.       sc = hrErr;
  1089.       goto error;
  1090.    }
  1091.    lpOleDoc->m_lpStg = lpStg;
  1092.    // NOTE: to be able to hold onto IStorage* pointer, we must AddRef it
  1093.    lpStg->lpVtbl->AddRef(lpStg);
  1094.    OLEDBG_END2
  1095.    return NOERROR;
  1096. error:
  1097.    OLEDBG_END2
  1098.    return sc;
  1099. }
  1100. // IPersistStorage::Save method
  1101. STDMETHODIMP SvrDoc_PStg_Save(
  1102.       LPPERSISTSTORAGE        lpThis,
  1103.       LPSTORAGE               lpStg,
  1104.       BOOL                    fSameAsLoad
  1105. )
  1106. {
  1107.    LPSERVERDOC lpServerDoc =
  1108.          ((struct CDocPersistStorageImpl FAR*)lpThis)->lpServerDoc;
  1109.    LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;
  1110.    BOOL fStatus;
  1111.    HRESULT sc;
  1112.    OLEDBG_BEGIN2("SvrDoc_PStg_Savern")
  1113.    fStatus = OutlineDoc_SaveSelToStg(
  1114.          (LPOUTLINEDOC)lpServerDoc,
  1115.          NULL,
  1116.          lpOutlineDoc->m_cfSaveFormat,
  1117.          lpStg,
  1118.          fSameAsLoad,
  1119.          FALSE
  1120.    );
  1121.    if (! fStatus) {
  1122.       OutlineApp_ErrorMessage(g_lpApp, ErrMsgPSSaveFail);
  1123.       sc = E_FAIL;
  1124.       goto error;
  1125.    }
  1126.    lpServerDoc->m_fSaveWithSameAsLoad = fSameAsLoad;
  1127.    lpServerDoc->m_fNoScribbleMode = TRUE;
  1128.    OLEDBG_END2
  1129.    return NOERROR;
  1130. error:
  1131.    OLEDBG_END2
  1132.    return sc;
  1133. }
  1134. // IPersistStorage::SaveCompleted method
  1135. STDMETHODIMP SvrDoc_PStg_SaveCompleted(
  1136.       LPPERSISTSTORAGE        lpThis,
  1137.       LPSTORAGE               lpStgNew
  1138. )
  1139. {
  1140.    LPSERVERDOC lpServerDoc =
  1141.          ((struct CDocPersistStorageImpl FAR*)lpThis)->lpServerDoc;
  1142.    LPOLEDOC lpOleDoc = (LPOLEDOC)lpServerDoc;
  1143.    LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;
  1144.    HRESULT hrErr;
  1145.    OLEDBG_BEGIN2("SvrDoc_PStg_SaveCompletedrn")
  1146.    /* NOTE: this sample application is a pure server application.
  1147.    **    a container/server application would have to call SaveCompleted
  1148.    **    for each of its contained compound document objects. if a new
  1149.    **    storage was given, then the container/server would have to
  1150.    **    open the corresponding new sub-storage for each compound
  1151.    **    document object and pass as an argument in the SaveCompleted
  1152.    **    call.
  1153.    */
  1154.    /* NOTE: it is only legal to perform a Save or SaveAs operation
  1155.    **    on an embedded object. if the document is a file-based document
  1156.    **    then we can not be changed to a IStorage-base object.
  1157.    **
  1158.    **      fSameAsLoad   lpStgNew     Type of Save     Send OnSave
  1159.    **    ---------------------------------------------------------
  1160.    **         TRUE        NULL        SAVE             YES
  1161.    **         TRUE        ! NULL      SAVE *           YES
  1162.    **         FALSE       ! NULL      SAVE AS          YES
  1163.    **         FALSE       NULL        SAVE COPY AS     NO
  1164.    **
  1165.    **    * this is a strange case that is possible. it is inefficient
  1166.    **    for the caller; it would be better to pass lpStgNew==NULL for
  1167.    **    the Save operation.
  1168.    */
  1169.    if ( ((lpServerDoc->m_fSaveWithSameAsLoad && lpStgNew==NULL) || lpStgNew)
  1170.          && (lpOutlineDoc->m_docInitType != DOCTYPE_EMBEDDED) ) {
  1171.       OLEDBG_END2
  1172.       return E_INVALIDARG;
  1173.    }
  1174.    /* NOTE: inform any linking clients that the document has been
  1175.    **    saved. in addition, any currently active pseudo objects
  1176.    **    should also inform their clients. we should only broadcast an
  1177.    **    OnSave notification if a Save or SaveAs operation was
  1178.    **    performed. we do NOT want to send the notification if a
  1179.    **    SaveCopyAs operation was performed.
  1180.    */
  1181.    if (lpStgNew || lpServerDoc->m_fSaveWithSameAsLoad) {
  1182.       /* NOTE: if IPersistStorage::Save has been called, then we
  1183.       **    need to clear the dirty bit and send OnSave notification.
  1184.       **    if HandsOffStorage is called directly without first
  1185.       **    calling Save, then we do NOT want to clear the dirty bit
  1186.       **    and send OnSave when SaveCompleted is called.
  1187.       */
  1188.       if (lpServerDoc->m_fNoScribbleMode) {
  1189.          OutlineDoc_SetModified(lpOutlineDoc, FALSE, FALSE, FALSE);
  1190.          ServerDoc_SendAdvise (
  1191.                lpServerDoc,
  1192.                OLE_ONSAVE,
  1193.                NULL,   /* lpmkDoc -- not relevant here */
  1194.                0       /* advf -- not relevant here */
  1195.          );
  1196.       }
  1197.       lpServerDoc->m_fSaveWithSameAsLoad = FALSE;
  1198.    }
  1199.    lpServerDoc->m_fNoScribbleMode = FALSE;
  1200.    /* NOTE: An embedded object must guarantee that it can save
  1201.    **    even in low memory situations. it must be able to
  1202.    **    successfully save itself without consuming any additional
  1203.    **    memory. this means that a server is NOT supposed to open or
  1204.    **    create any streams or storages when
  1205.    **    IPersistStorage::Save(fSameAsLoad==TRUE) is called. thus an
  1206.    **    embedded object should hold onto its storage and pre-open and
  1207.    **    hold open any streams that it will need later when it is time
  1208.    **    to save. if this is a SaveAs situtation, then we want to
  1209.    **    pre-open and hold open our streams to guarantee that a
  1210.    **    subsequent save will be successful in low-memory. if we fail
  1211.    **    to open these streams then we want to force ourself to close
  1212.    **    to make sure the can't make editing changes that can't be
  1213.    **    later saved.
  1214.    */
  1215.    if ( lpStgNew && !lpServerDoc->m_fSaveWithSameAsLoad ) {
  1216.       // release previous streams
  1217.       if (lpOleDoc->m_lpLLStm) {
  1218.          OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpLLStm);
  1219.          lpOleDoc->m_lpLLStm = NULL;
  1220.       }
  1221.       if (lpOleDoc->m_lpNTStm) {
  1222.          OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpNTStm);
  1223.          lpOleDoc->m_lpNTStm = NULL;
  1224.       }
  1225.       if (lpOleDoc->m_lpStg) {
  1226.          OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpStg);
  1227.          lpOleDoc->m_lpStg = NULL;
  1228.       }
  1229.       hrErr = lpStgNew->lpVtbl->OpenStream(
  1230.             lpStgNew,
  1231.             OLESTR("LineList"),
  1232.             NULL,
  1233.             STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  1234.             0,
  1235.             &lpOleDoc->m_lpLLStm
  1236.       );
  1237.       if (hrErr != NOERROR) {
  1238.          OleDbgAssertSz(hrErr==NOERROR,"Could not create LineList stream");
  1239.          OleDbgOutHResult("LineList CreateStream returned", hrErr);
  1240.          goto error;
  1241.       }
  1242.       hrErr = lpStgNew->lpVtbl->OpenStream(
  1243.             lpStgNew,
  1244.             OLESTR("NameTable"),
  1245.             NULL,
  1246.             STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  1247.             0,
  1248.             &lpOleDoc->m_lpNTStm
  1249.       );
  1250.       if (hrErr != NOERROR) {
  1251.          OleDbgAssertSz(hrErr==NOERROR,"Could not create NameTable stream");
  1252.          OleDbgOutHResult("NameTable CreateStream returned", hrErr);
  1253.          goto error;
  1254.       }
  1255.       lpOleDoc->m_lpStg = lpStgNew;
  1256.       // NOTE: to hold onto IStorage* pointer, we must AddRef it
  1257.       lpStgNew->lpVtbl->AddRef(lpStgNew);
  1258.    }
  1259.    OLEDBG_END2
  1260.    return NOERROR;
  1261. error:
  1262.    OLEDBG_END2
  1263.    return E_OUTOFMEMORY;
  1264. }
  1265. // IPersistStorage::HandsOffStorage method
  1266. STDMETHODIMP SvrDoc_PStg_HandsOffStorage(LPPERSISTSTORAGE lpThis)
  1267. {
  1268.    LPSERVERDOC lpServerDoc =
  1269.          ((struct CDocPersistStorageImpl FAR*)lpThis)->lpServerDoc;
  1270.    LPOLEDOC lpOleDoc = (LPOLEDOC)lpServerDoc;
  1271.    OLEDBG_BEGIN2("SvrDoc_PStg_HandsOffStoragern")
  1272.    /* NOTE: An embedded object must guarantee that it can save
  1273.    **    even in low memory situations. it must be able to
  1274.    **    successfully save itself without consuming any additional
  1275.    **    memory. this means that a server is NOT supposed to open or
  1276.    **    create any streams or storages when
  1277.    **    IPersistStorage::Save(fSameAsLoad==TRUE) is called. thus an
  1278.    **    embedded object should hold onto its storage and pre-open and
  1279.    **    hold open any streams that it will need later when it is time
  1280.    **    to save. Now when HandsOffStorage is called the object must
  1281.    **    release its storage and any streams that is holds open.
  1282.    **    later when SaveCompleted is called, it will be given back its
  1283.    **    storage.
  1284.    */
  1285.    if (lpOleDoc->m_lpLLStm) {
  1286.       OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpLLStm);
  1287.       lpOleDoc->m_lpLLStm = NULL;
  1288.    }
  1289.    if (lpOleDoc->m_lpNTStm) {
  1290.       OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpNTStm);
  1291.       lpOleDoc->m_lpNTStm = NULL;
  1292.    }
  1293.    if (lpOleDoc->m_lpStg) {
  1294.       OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpStg);
  1295.       lpOleDoc->m_lpStg = NULL;
  1296.    }
  1297.    OLEDBG_END2
  1298.    return NOERROR;
  1299. }
  1300. #if defined( SVR_TREATAS )
  1301. /*************************************************************************
  1302. ** ServerDoc::IStdMarshalInfo interface implementation
  1303. *************************************************************************/
  1304. // IStdMarshalInfo::QueryInterface method
  1305. STDMETHODIMP SvrDoc_StdMshl_QueryInterface(
  1306.       LPSTDMARSHALINFO        lpThis,
  1307.       REFIID                  riid,
  1308.       LPVOID FAR*             lplpvObj
  1309. )
  1310. {
  1311.    LPSERVERDOC lpServerDoc =
  1312.          ((struct CDocStdMarshalInfoImpl FAR*)lpThis)->lpServerDoc;
  1313.    return OleDoc_QueryInterface((LPOLEDOC)lpServerDoc, riid, lplpvObj);
  1314. }
  1315. // IStdMarshalInfo::AddRef method
  1316. STDMETHODIMP_(ULONG) SvrDoc_StdMshl_AddRef(LPSTDMARSHALINFO lpThis)
  1317. {
  1318.    LPSERVERDOC lpServerDoc =
  1319.          ((struct CDocStdMarshalInfoImpl FAR*)lpThis)->lpServerDoc;
  1320.    OleDbgAddRefMethod(lpThis, "IStdMarshalInfo");
  1321.    return OleDoc_AddRef((LPOLEDOC)lpServerDoc);
  1322. }
  1323. // IStdMarshalInfo::Release method
  1324. STDMETHODIMP_(ULONG) SvrDoc_StdMshl_Release(LPSTDMARSHALINFO lpThis)
  1325. {
  1326.    LPSERVERDOC lpServerDoc =
  1327.          ((struct CDocStdMarshalInfoImpl FAR*)lpThis)->lpServerDoc;
  1328.    OleDbgReleaseMethod(lpThis, "IStdMarshalInfo");
  1329.    return OleDoc_Release((LPOLEDOC)lpServerDoc);
  1330. }
  1331. // IStdMarshalInfo::GetClassForHandler
  1332. STDMETHODIMP SvrDoc_StdMshl_GetClassForHandler(
  1333.       LPSTDMARSHALINFO        lpThis,
  1334.       DWORD                   dwDestContext,
  1335.       LPVOID                  pvDestContext,
  1336.       LPCLSID                 lpClassID
  1337. )
  1338. {
  1339.    LPSERVERDOC lpServerDoc =
  1340.          ((struct CDocStdMarshalInfoImpl FAR*)lpThis)->lpServerDoc;
  1341.    OleDbgOut2("SvrDoc_StdMshl_GetClassForHandlerrn");
  1342.    // NOTE: we only handle LOCAL marshal context.
  1343.    if (dwDestContext != MSHCTX_LOCAL || pvDestContext != NULL)
  1344.       return E_INVALIDARG;
  1345.    /* NOTE: we must return our REAL clsid, NOT the clsid that we
  1346.    **    are pretending to be if a "TreatAs" is in effect.
  1347.    */
  1348.    *lpClassID = CLSID_APP;
  1349.    return NOERROR;
  1350. }
  1351. #endif  // SVR_TREATAS
  1352. /*************************************************************************
  1353. ** ServerDoc Support Functions
  1354. *************************************************************************/
  1355. /* ServerDoc_Init
  1356.  * --------------
  1357.  *
  1358.  *  Initialize the fields of a new ServerDoc object. The object is initially
  1359.  *  not associated with a file or an (Untitled) document. This function sets
  1360.  *  the docInitType to DOCTYPE_UNKNOWN. After calling this function the
  1361.  *  caller should call:
  1362.  *      1.) OutlineDoc_InitNewFile to set the ServerDoc to (Untitled)
  1363.  *      2.) OutlineDoc_LoadFromFile to associate the ServerDoc with a file.
  1364.  *  This function creates a new window for the document.
  1365.  *
  1366.  *  NOTE: the window is initially created with a NIL size. it must be
  1367.  *        sized and positioned by the caller. also the document is initially
  1368.  *        created invisible. the caller must call OutlineDoc_ShowWindow
  1369.  *        after sizing it to make the document window visible.
  1370.  */
  1371. BOOL ServerDoc_Init(LPSERVERDOC lpServerDoc, BOOL fDataTransferDoc)
  1372. {
  1373.    lpServerDoc->m_cPseudoObj                   = 0;
  1374.    lpServerDoc->m_lpOleClientSite              = NULL;
  1375.    lpServerDoc->m_lpOleAdviseHldr              = NULL;
  1376.    lpServerDoc->m_lpDataAdviseHldr             = NULL;
  1377.    // initialy doc does not have any storage
  1378.    lpServerDoc->m_fNoScribbleMode              = FALSE;
  1379.    lpServerDoc->m_fSaveWithSameAsLoad          = FALSE;
  1380.    lpServerDoc->m_szContainerApp[0]            = '';
  1381.    lpServerDoc->m_szContainerObj[0]            = '';
  1382.    lpServerDoc->m_nNextRangeNo                 = 0L;
  1383.    lpServerDoc->m_lrSrcSelOfCopy.m_nStartLine  = -1;
  1384.    lpServerDoc->m_lrSrcSelOfCopy.m_nEndLine    = -1;
  1385.    lpServerDoc->m_fDataChanged                 = FALSE;
  1386.    lpServerDoc->m_fSizeChanged                 = FALSE;
  1387.    lpServerDoc->m_fSendDataOnStop              = FALSE;
  1388. #if defined( SVR_TREATAS )
  1389.    lpServerDoc->m_clsidTreatAs                 = CLSID_NULL;
  1390.    lpServerDoc->m_lpszTreatAsType              = NULL;
  1391. #endif  // SVR_TREATAS
  1392. #if defined( INPLACE_SVR )
  1393.    lpServerDoc->m_hWndHatch                    =
  1394.          CreateHatchWindow(
  1395.                OutlineApp_GetWindow(g_lpApp),
  1396.                OutlineApp_GetInstance(g_lpApp)
  1397.          );
  1398.    if (!lpServerDoc->m_hWndHatch)
  1399.       return FALSE;
  1400.    lpServerDoc->m_fInPlaceActive               = FALSE;
  1401.    lpServerDoc->m_fInPlaceVisible              = FALSE;
  1402.    lpServerDoc->m_fUIActive                    = FALSE;
  1403.    lpServerDoc->m_lpIPData                     = NULL;
  1404.    lpServerDoc->m_fMenuHelpMode                = FALSE; // F1 pressed in menu
  1405.    INIT_INTERFACEIMPL(
  1406.          &lpServerDoc->m_OleInPlaceObject,
  1407.          &g_SvrDoc_OleInPlaceObjectVtbl,
  1408.          lpServerDoc
  1409.    );
  1410.    INIT_INTERFACEIMPL(
  1411.          &lpServerDoc->m_OleInPlaceActiveObject,
  1412.          &g_SvrDoc_OleInPlaceActiveObjectVtbl,
  1413.          lpServerDoc
  1414.    );
  1415. #endif // INPLACE_SVR
  1416.    INIT_INTERFACEIMPL(
  1417.          &lpServerDoc->m_OleObject,
  1418.          &g_SvrDoc_OleObjectVtbl,
  1419.          lpServerDoc
  1420.    );
  1421.    INIT_INTERFACEIMPL(
  1422.          &lpServerDoc->m_PersistStorage,
  1423.          &g_SvrDoc_PersistStorageVtbl,
  1424.          lpServerDoc
  1425.    );
  1426. #if defined( SVR_TREATAS )
  1427.    INIT_INTERFACEIMPL(
  1428.          &lpServerDoc->m_StdMarshalInfo,
  1429.          &g_SvrDoc_StdMarshalInfoVtbl,
  1430.          lpServerDoc
  1431.    );
  1432. #endif  // SVR_TREATAS
  1433.    return TRUE;
  1434. }
  1435. /* ServerDoc_InitNewEmbed
  1436.  * ----------------------
  1437.  *
  1438.  *  Initialize the ServerDoc object to be a new embedded object document.
  1439.  *  This function sets the docInitType to DOCTYPE_EMBED.
  1440.  */
  1441. BOOL ServerDoc_InitNewEmbed(LPSERVERDOC lpServerDoc)
  1442. {
  1443.    char szAnsiStr[256];
  1444.    LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;
  1445.    OleDbgAssert(lpOutlineDoc->m_docInitType == DOCTYPE_UNKNOWN);
  1446.    lpOutlineDoc->m_docInitType = DOCTYPE_EMBEDDED;
  1447.    /* The Window title for an embedded object is constructed as
  1448.    **    follows:
  1449.    **      <server app name> - <obj short type> in <cont. doc name>
  1450.    **
  1451.    **    here we construct the current document title portion of the
  1452.    **    name which follows the '-'. OutlineDoc_SetTitle prepends the
  1453.    **    "<server app name> - " to the document title.
  1454.    */
  1455.    // REVIEW: this string should be loaded from string resource
  1456.    wsprintf(szAnsiStr, "%s in %s",
  1457.       (LPSTR)SHORTUSERTYPENAME,
  1458.       (LPSTR)DEFCONTAINERNAME);
  1459.    A2W (szAnsiStr, lpOutlineDoc->m_szFileName, OLEUI_CCHPATHMAX);
  1460.    lpOutlineDoc->m_lpszDocTitle = lpOutlineDoc->m_szFileName;
  1461.    /* NOTE: an embedding should be marked as initially dirty so
  1462.    **    that on close we always call IOleClientSite::SaveObject.
  1463.    */
  1464.    OutlineDoc_SetModified(lpOutlineDoc, TRUE, FALSE, FALSE);
  1465.    OutlineDoc_SetTitle(lpOutlineDoc, FALSE /*fMakeUpperCase*/);
  1466.    return TRUE;
  1467. }
  1468. /* ServerDoc_SendAdvise
  1469.  * --------------------
  1470.  *
  1471.  * This function sends an advise notification on behalf of a specific
  1472.  *  doc object to all its clients.
  1473.  */
  1474. void ServerDoc_SendAdvise(
  1475.       LPSERVERDOC     lpServerDoc,
  1476.       WORD            wAdvise,
  1477.       LPMONIKER       lpmkDoc,
  1478.       DWORD           dwAdvf
  1479. )
  1480. {
  1481.    LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;
  1482.    LPOLEDOC lpOleDoc = (LPOLEDOC)lpServerDoc;
  1483.    switch (wAdvise) {
  1484.       case OLE_ONDATACHANGE:
  1485.          // inform clients that the data of the object has changed
  1486.          if (lpOutlineDoc->m_nDisableDraw == 0) {
  1487.             /* drawing is currently enabled. inform clients that
  1488.             **    the data of the object has changed
  1489.             */
  1490.             lpServerDoc->m_fDataChanged = FALSE;
  1491.             /* NOTE: we must note the time of last change
  1492.             **    for our object in the RunningObjectTable.
  1493.             **    this is used as the basis to answer
  1494.             **    IOleObject::IsUpToDate. we only want to note
  1495.             **    the change time when an actual change takes
  1496.             **    place. we do NOT want to set it when we are
  1497.             **    notifying clients of ADVF_DATAONSTOP
  1498.             */
  1499.             if (dwAdvf == 0)
  1500.                OleStdNoteObjectChangeTime(lpOleDoc->m_dwRegROT);
  1501.             if (lpServerDoc->m_lpDataAdviseHldr) {
  1502.                OLEDBG_BEGIN2("IDataAdviseHolder::SendOnDataChange calledrn");
  1503.                lpServerDoc->m_lpDataAdviseHldr->lpVtbl->SendOnDataChange(
  1504.                      lpServerDoc->m_lpDataAdviseHldr,
  1505.                      (LPDATAOBJECT)&lpOleDoc->m_DataObject,
  1506.                      0,
  1507.                      dwAdvf
  1508.                );
  1509.                OLEDBG_END2
  1510.             }
  1511. #if defined( INPLACE_SVR )
  1512.             /* NOTE: if the ServerDoc is currently in-place UI active,
  1513.             **    then is it important to renegotiate the size for the
  1514.             **    in-place document window BEFORE sending OnDataChange
  1515.             **    (which will cause the window to repaint).
  1516.             */
  1517.             if (lpServerDoc->m_fSizeChanged) {
  1518.                lpServerDoc->m_fSizeChanged = FALSE;
  1519.                if (lpServerDoc->m_fInPlaceActive)
  1520.                   ServerDoc_UpdateInPlaceWindowOnExtentChange(lpServerDoc);
  1521.             }
  1522. #endif
  1523.             /* NOTE: we do NOT need to tell our pseudo objects to
  1524.             **    broadcast OnDataChange notification because
  1525.             **    they will do it automatically when an editing
  1526.             **    change in the document affects a PseudoObj.
  1527.             **    (see OutlineNameTable_AddLineUpdate,
  1528.             **         OutlineNameTable_DeleteLineUpdate,
  1529.             **    and  ServerNameTable_EditLineUpdate)
  1530.             */
  1531.          } else {
  1532.             /* drawing is currently disabled. do not send
  1533.             **    notifications or call
  1534.             **    IOleInPlaceObject::OnPosRectChange until drawing
  1535.             **    is re-enabled.
  1536.             */
  1537.          }
  1538.          break;
  1539.       case OLE_ONCLOSE:
  1540.          // inform clients that the document is shutting down
  1541.          if (lpServerDoc->m_lpOleAdviseHldr) {
  1542.             OLEDBG_BEGIN2("IOleAdviseHolder::SendOnClose calledrn");
  1543.             lpServerDoc->m_lpOleAdviseHldr->lpVtbl->SendOnClose(
  1544.                   lpServerDoc->m_lpOleAdviseHldr
  1545.             );
  1546.             OLEDBG_END2
  1547.          }
  1548.          /* NOTE: we do NOT need to tell our pseudo objects to
  1549.          **    broadcast OnClose notification because they will do
  1550.          **    it automatically when the pseudo object is closed.
  1551.          **    (see PseudoObj_Close)
  1552.          */
  1553.          break;
  1554.       case OLE_ONSAVE:
  1555.          // inform clients that the object has been saved
  1556.          OLEDBG_BEGIN3("ServerDoc_SendAdvise ONSAVErn");
  1557.          if (lpServerDoc->m_lpOleAdviseHldr) {
  1558.             OLEDBG_BEGIN2("IOleAdviseHolder::SendOnSave calledrn");
  1559.             lpServerDoc->m_lpOleAdviseHldr->lpVtbl->SendOnSave(
  1560.                   lpServerDoc->m_lpOleAdviseHldr
  1561.             );
  1562.             OLEDBG_END2
  1563.          }
  1564.          /* NOTE: inform any clients of pseudo objects
  1565.          **    within our document, that our document has been
  1566.          **    saved.
  1567.          */
  1568.          ServerNameTable_InformAllPseudoObjectsDocSaved(
  1569.                (LPSERVERNAMETABLE)lpOutlineDoc->m_lpNameTable,
  1570.                lpmkDoc
  1571.          );
  1572.          OLEDBG_END3
  1573.          break;
  1574.       case OLE_ONRENAME:
  1575.          // inform clients that the object's name has changed
  1576.          OLEDBG_BEGIN3("ServerDoc_SendAdvise ONRENAMErn");
  1577.          if (lpmkDoc && lpServerDoc->m_lpOleAdviseHldr) {
  1578.             OLEDBG_BEGIN2("IOleAdviseHolder::SendOnRename calledrn");
  1579.             lpServerDoc->m_lpOleAdviseHldr->lpVtbl->SendOnRename(
  1580.                   lpServerDoc->m_lpOleAdviseHldr,
  1581.                   lpmkDoc
  1582.             );
  1583.             OLEDBG_END2
  1584.          }
  1585.          OLEDBG_END3
  1586.          break;
  1587.    }
  1588. }
  1589. /* ServerDoc_GetClassID
  1590. ** --------------------
  1591. **    Return the class ID corresponding to the bits in the storage.
  1592. **    normally this will be our application's given CLSID. but if a
  1593. **    "TreateAs (aka. ActivateAs)" operation is taking place, then our
  1594. **    application needs to pretend to be the class of the object that
  1595. **    we are emulating. this is also the class that will be written
  1596. **    into the storage.
  1597. */
  1598. HRESULT ServerDoc_GetClassID(LPSERVERDOC lpServerDoc, LPCLSID lpclsid)
  1599. {
  1600. #if defined( SVR_TREATAS )
  1601.    if (! IsEqualCLSID(&lpServerDoc->m_clsidTreatAs, &CLSID_NULL))
  1602.       *lpclsid = lpServerDoc->m_clsidTreatAs;
  1603.    else
  1604. #endif  // SVR_TREATAS
  1605.       *lpclsid = CLSID_APP;
  1606.    return NOERROR;
  1607. }
  1608. /* ServerDoc_UpdateMenu
  1609.  * --------------------
  1610.  *
  1611.  *  Update menu for embedding mode. the changes include:
  1612.  *      1 Remove File/New and File/Open (SDI ONLY)
  1613.  *      2 Change File/Save As.. to File/Save Copy As..
  1614.  *      3 Change File menu so it contains "Update" instead of "Save"
  1615.  *      4 Change File/Exit to File/Exit & Return to <client doc>"
  1616.  */
  1617. void ServerDoc_UpdateMenu(LPSERVERDOC lpServerDoc)
  1618. {
  1619.    char    str[256];
  1620.    HWND    hWndMain;
  1621.    HMENU   hMenu;
  1622.    char    szAnsiStr[256];
  1623.    OleDbgOut2("ServerDoc_UpdateMenurn");
  1624.    hWndMain=g_lpApp->m_hWndApp;
  1625.    hMenu=GetMenu(hWndMain);
  1626. #if defined( SDI_VERSION )
  1627.    /* SDI ONLY: Remove File/New and File/Open */
  1628.    DeleteMenu(hMenu, IDM_F_NEW, MF_BYCOMMAND);
  1629.    DeleteMenu(hMenu, IDM_F_OPEN, MF_BYCOMMAND);
  1630. #endif
  1631.    // Change File.Save As.. to File.Save Copy As.. */
  1632.    ModifyMenu(hMenu,IDM_F_SAVEAS, MF_STRING, IDM_F_SAVEAS, "Save Copy As..");
  1633.    // Change File.Save to "&Update <container doc>"
  1634.    W2A (lpServerDoc->m_szContainerObj, szAnsiStr, 256);
  1635.    wsprintf(str, g_szUpdateCntrDoc, szAnsiStr);
  1636.    ModifyMenu(hMenu, IDM_F_SAVE, MF_STRING, IDM_F_SAVE, str);
  1637.    // Change File/Exit to File/Exit & Return to <container doc>" */
  1638.    W2A (lpServerDoc->m_szContainerObj, szAnsiStr, 256);
  1639.    wsprintf(str, g_szExitNReturnToCntrDoc, szAnsiStr);
  1640.    ModifyMenu(hMenu, IDM_F_EXIT, MF_STRING, IDM_F_EXIT, str);
  1641.    DrawMenuBar(hWndMain);
  1642. }
  1643. #if defined( MDI_VERSION )
  1644. // NOTE: ServerDoc_RestoreMenu is actually redundant because the
  1645. //          app is dying when the function is called.  (In SDI, the
  1646. //          app will terminate when the ref counter of the server doc
  1647. //          is zero). However, it is important for MDI.
  1648. /* ServerDoc_RestoreMenu
  1649.  * ---------------------
  1650.  *
  1651.  *      Reset the menu to non-embedding mode
  1652.  */
  1653. void ServerDoc_RestoreMenu(LPSERVERDOC lpServerDoc)
  1654. {
  1655.    LPOUTLINEAPP    lpOutlineApp = (LPOUTLINEAPP)g_lpApp;
  1656.    HWND            hWndMain;
  1657.    HMENU           hMenu;
  1658.    OleDbgOut2("ServerDoc_RestoreMenurn");
  1659.    hWndMain = lpOutlineApp->m_hWndApp;
  1660.    hMenu = GetMenu(hWndMain);
  1661.    /* Add back File/New, File/Open.. and File/Save */
  1662.    InsertMenu(hMenu, IDM_F_SAVEAS, MF_BYCOMMAND | MF_ENABLED | MF_STRING,
  1663.       IDM_F_NEW, "&New");
  1664.    InsertMenu(hMenu, IDM_F_SAVEAS, MF_BYCOMMAND | MF_ENABLED | MF_STRING,
  1665.       IDM_F_OPEN, "&Open...");
  1666.    /* Change File menu so it contains "Save As..." instead of */
  1667.    /* "Save Copy As..." */
  1668.    ModifyMenu(hMenu, IDM_F_SAVEAS, MF_STRING, IDM_F_SAVEAS, "Save &As..");
  1669.    /* Change File menu so it contains "Save" instead of "Update" */
  1670.    ModifyMenu(hMenu, IDM_F_SAVE, MF_STRING, IDM_F_SAVE, "&Save");
  1671.    /* Change File menu so it contains "Exit" */
  1672.    /* instead of just "Exit & Return to <client doc>" */
  1673.    ModifyMenu(hMenu, IDM_F_EXIT, MF_STRING, IDM_F_EXIT, "E&xit");
  1674.    DrawMenuBar (hWndMain);
  1675. }
  1676. #endif  // MDI_VERSION