SVRBASE.C
资源名称:MSDN_VC98.zip [点击查看]
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:65k
源码类别:
Windows编程
开发平台:
Visual C++
- /*************************************************************************
- **
- ** 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 - 1997 All Rights Reserved
- **
- *************************************************************************/
- #include "outline.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 OLECHAR ErrMsgSaving[];
- extern OLECHAR ErrMsgFormatNotSupported[];
- static OLECHAR ErrMsgPSSaveFail[] = OLESTR("PSSave failed");
- static OLECHAR ErrMsgLowMemNClose[] = OLESTR("Warning OUT OF MEMORY! We must close down");
- 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;
- // artificial AddRef in case object is destroyed during call
- SvrDoc_OleObj_AddRef(lpThis);
- OLEDBG_BEGIN2("SvrDoc_OleObj_SetClientSitern")
- // SetClientSite is only valid to call on an embedded object
- if (lpOutlineDoc->m_docInitType != DOCTYPE_EMBEDDED) {
- OleDbgAssert(lpOutlineDoc->m_docInitType == DOCTYPE_EMBEDDED);
- OLEDBG_END2
- // release artificial AddRef
- SvrDoc_OleObj_Release(lpThis);
- return 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;
- // NOTE: to be able to hold onto clientSite pointer, we must AddRef it
- if (lpclientSite)
- lpclientSite->lpVtbl->AddRef(lpclientSite);
- OLEDBG_END2
- // release artificial AddRef
- SvrDoc_OleObj_Release(lpThis);
- return NOERROR;
- }
- // IOleObject::GetClientSite method
- STDMETHODIMP SvrDoc_OleObj_GetClientSite(
- LPOLEOBJECT lpThis,
- LPOLECLIENTSITE FAR* lplpClientSite
- )
- {
- LPSERVERDOC lpServerDoc =
- ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;
- // artificial AddRef in case object is destroyed during call
- SvrDoc_OleObj_AddRef(lpThis);
- OleDbgOut2("SvrDoc_OleObj_GetClientSitern");
- /* NOTE: 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;
- // release artificial AddRef
- SvrDoc_OleObj_Release(lpThis);
- return NOERROR;
- }
- // IOleObject::SetHostNames method
- STDMETHODIMP SvrDoc_OleObj_SetHostNames(
- LPOLEOBJECT lpThis,
- LPCOLESTR szContainerApp,
- LPCOLESTR szContainerObj
- )
- {
- LPSERVERDOC lpServerDoc =
- ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;
- LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;
- char szAnsiStr1[256], szAnsiStr2[256], szAnsiStr3[256];
- // artificial AddRef in case object is destroyed during call
- SvrDoc_OleObj_AddRef(lpThis);
- OleDbgOut2("SvrDoc_OleObj_SetHostNamesrn");
- OLESTRCPY(/*(LPOLESTR)*/lpServerDoc->m_szContainerApp, szContainerApp);
- OLESTRCPY(/*(LPOLESTR)*/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
- W2A (lpServerDoc->m_szContainerObj, szAnsiStr1, 256);
- W2A (SHORTUSERTYPENAME, szAnsiStr3, 256);
- wsprintf(szAnsiStr2, "%s in %s",
- szAnsiStr3, (LPSTR)szAnsiStr1);
- A2W (szAnsiStr2, lpOutlineDoc->m_szFileName, OLEUI_CCHPATHMAX);
- lpOutlineDoc->m_lpszDocTitle = lpOutlineDoc->m_szFileName;
- OutlineDoc_SetTitle(lpOutlineDoc, FALSE /*fMakeUpperCase*/);
- /* NOTE: 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);
- // release artificial AddRef
- SvrDoc_OleObj_Release(lpThis);
- 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_Closern")
- /* NOTE: 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 failedrn");
- OLEDBG_END2
- return (fStatus ? NOERROR : 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;
- LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;
- LPMONIKER lpmkFull = NULL;
- HRESULT hrErr;
- HRESULT sc;
- // artificial AddRef in case object is destroyed during call
- SvrDoc_OleObj_AddRef(lpThis);
- OLEDBG_BEGIN2("SvrDoc_OleObj_SetMonikerrn")
- /* NOTE: if our full moniker is passed then we can use it,
- ** otherwise we must call back to our ClientSite to get our full
- ** moniker.
- */
- if (dwWhichMoniker == OLEWHICHMK_OBJFULL) {
- /* Register the document as running with the new moniker and
- ** notify any clients that our moniker has changed.
- */
- OleDoc_DocRenamedUpdate(lpOleDoc, lpmk);
- if (lpOutlineDoc->m_docInitType != DOCTYPE_EMBEDDED) {
- IBindCtx FAR *pbc = NULL;
- LPOLESTR lpszName = NULL;
- /* NOTE: if this is a FILE-based or untitled document
- ** then we should accept this new moniker as our document's
- ** moniker. we will remember this moniker instead of the
- ** FileMoniker that we have by default. this allows
- ** systems that use special monikers to track the
- ** location of documents to inform a document that is a
- ** link source of its special moniker. this enables the
- ** document to use this special moniker when building
- ** composite monikers to identify contained objects and
- ** pseudo objects (ranges).
- **
- ** we should also use the DisplayName form of this
- ** moniker as our document name in our window title.
- */
- if (lpOleDoc->m_lpFileMoniker) {
- lpOleDoc->m_lpFileMoniker->lpVtbl->Release(
- lpOleDoc->m_lpFileMoniker);
- }
- lpOleDoc->m_lpFileMoniker = lpmk;
- // we must AddRef the moniker to hold on to it
- lpmk->lpVtbl->AddRef(lpmk);
- /* we should also use the DisplayName form of this
- ** moniker as our document name in our window title.
- */
- CreateBindCtx(0, (LPBC FAR*)&pbc);
- lpmk->lpVtbl->GetDisplayName(lpmk,pbc,NULL,&lpszName);
- pbc->lpVtbl->Release(pbc);
- if (lpszName) {
- OLESTRCPY(lpOutlineDoc->m_szFileName, lpszName);
- lpOutlineDoc->m_lpszDocTitle = lpOutlineDoc->m_szFileName;
- OutlineDoc_SetTitle(lpOutlineDoc, FALSE /*fMakeUpperCase*/);
- OleStdFreeString(lpszName, NULL);
- }
- }
- OLEDBG_END2
- // release artificial AddRef
- SvrDoc_OleObj_Release(lpThis);
- return NOERROR;
- }
- /* if the passed moniker was NOT a full moniker then we must call
- ** back to our ClientSite to get our full moniker. this is
- ** needed in order to register in the RunningObjectTable. if we
- ** don't have a ClientSite then this is an error.
- */
- if (lpServerDoc->m_lpOleClientSite == NULL) {
- sc = E_FAIL;
- goto error;
- }
- hrErr = lpServerDoc->m_lpOleClientSite->lpVtbl->GetMoniker(
- lpServerDoc->m_lpOleClientSite,
- OLEGETMONIKER_ONLYIFTHERE,
- OLEWHICHMK_OBJFULL,
- &lpmkFull
- );
- if (hrErr != NOERROR) {
- sc = 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
- // release artificial AddRef
- SvrDoc_OleObj_Release(lpThis);
- return NOERROR;
- error:
- OLEDBG_END2
- // release artificial AddRef
- SvrDoc_OleObj_Release(lpThis);
- return sc;
- }
- // IOleObject::GetMoniker method
- STDMETHODIMP SvrDoc_OleObj_GetMoniker(
- LPOLEOBJECT lpThis,
- DWORD dwAssign,
- DWORD dwWhichMoniker,
- LPMONIKER FAR* lplpmk
- )
- {
- LPSERVERDOC lpServerDoc =
- ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;
- LPOLEDOC lpOleDoc = (LPOLEDOC)lpServerDoc;
- HRESULT sc;
- // artificial AddRef in case object is destroyed during call
- SvrDoc_OleObj_AddRef(lpThis);
- OLEDBG_BEGIN2("SvrDoc_OleObj_GetMonikerrn")
- /* NOTE: we must make sure to set all out parameters to NULL. */
- *lplpmk = NULL;
- if (lpServerDoc->m_lpOleClientSite) {
- /* document is an embedded object. retrieve our moniker from
- ** our container.
- */
- OLEDBG_BEGIN2("IOleClientSite::GetMoniker calledrn")
- sc = lpServerDoc->m_lpOleClientSite->lpVtbl->GetMoniker(
- lpServerDoc->m_lpOleClientSite,
- dwAssign,
- dwWhichMoniker,
- lplpmk
- ) ;
- OLEDBG_END2
- } else if (lpOleDoc->m_lpFileMoniker) {
- /* document is a top-level user document (either
- ** file-based or untitled). return the FileMoniker stored
- ** with the document; it uniquely identifies the document.
- */
- if (dwWhichMoniker == OLEWHICHMK_CONTAINER)
- sc = E_INVALIDARG; // file-based object has no CONTAINER moniker
- else {
- *lplpmk = lpOleDoc->m_lpFileMoniker;
- (*lplpmk)->lpVtbl->AddRef(*lplpmk); // must AddRef to pass out ptr
- sc = S_OK;
- }
- } else {
- // document is not yet fully initialized => no moniker
- sc = E_FAIL;
- }
- OLEDBG_END2
- // release artificial AddRef
- SvrDoc_OleObj_Release(lpThis);
- return 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_InitFromDatarn")
- // REVIEW: NOT YET IMPLEMENTED
- OLEDBG_END2
- return 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_GetClipboardDatarn")
- // REVIEW: NOT YET IMPLEMENTED
- OLEDBG_END2
- return 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;
- HRESULT sc = S_OK;
- // artificial AddRef in case object is destroyed during call
- SvrDoc_OleObj_AddRef(lpThis);
- OLEDBG_BEGIN2("SvrDoc_OleObj_DoVerbrn")
- switch (lVerb) {
- default:
- /* NOTE: 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 HRESULT (OLEOBJ_S_INVALIDVERB). BUT,
- ** we should still perform our normal primary verb action.
- */
- if (lVerb < 0) {
- OLEDBG_END2
- return E_NOTIMPL;
- } else {
- sc = OLEOBJ_S_INVALIDVERB;
- }
- // deliberatly fall through to Primary Verb
- #if !defined( INPLACE_SVR )
- case 0:
- case OLEIVERB_SHOW:
- case OLEIVERB_OPEN:
- OutlineDoc_ShowWindow(lpOutlineDoc);
- break;
- case OLEIVERB_HIDE:
- OleDoc_HideWindow((LPOLEDOC)lpServerDoc, FALSE /*fShutdown*/);
- break;
- #endif // ! INPLACE_SVR
- #if defined( INPLACE_SVR )
- case 0:
- case OLEIVERB_SHOW:
- /* NOTE: 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);
- }
- OutlineDoc_ShowWindow(lpOutlineDoc);
- break;
- case 1:
- case OLEIVERB_OPEN:
- ServerDoc_DoInPlaceDeactivate(lpServerDoc);
- OutlineDoc_ShowWindow(lpOutlineDoc);
- break;
- case OLEIVERB_HIDE:
- if (lpServerDoc->m_fInPlaceActive) {
- SvrDoc_IPObj_UIDeactivate(
- (LPOLEINPLACEOBJECT)&lpServerDoc->m_OleInPlaceObject);
- #if defined( SVR_INSIDEOUT )
- /* NOTE: 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*/);
- }
- break;
- case OLEIVERB_UIACTIVATE:
- #if defined( SVR_INSIDEOUT )
- /* NOTE: only an inside-out style object supports
- ** INPLACEACTIVATE verb
- */
- case OLEIVERB_INPLACEACTIVATE:
- #endif // SVR_INSIDEOUT
- /* NOTE: 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 = ServerDoc_DoInPlaceActivate(
- lpServerDoc, lVerb, lpmsg, lpActiveSite) ;
- if (SUCCEEDED(sc))
- OutlineDoc_ShowWindow(lpOutlineDoc);
- }
- break;
- #endif // INPLACE_SVR
- }
- OLEDBG_END2
- // release artificial AddRef
- SvrDoc_OleObj_Release(lpThis);
- return sc;
- }
- // IOleObject::EnumVerbs method
- STDMETHODIMP SvrDoc_OleObj_EnumVerbs(
- LPOLEOBJECT lpThis,
- LPENUMOLEVERB FAR* lplpenumOleVerb
- )
- {
- OleDbgOut2("SvrDoc_OleObj_EnumVerbsrn");
- /* NOTE: we must make sure to set all out parameters to NULL. */
- *lplpenumOleVerb = NULL;
- /* An object implemented as a server EXE (as this sample
- ** is) may simply return OLE_S_USEREG to instruct the OLE
- ** DefHandler to call the OleReg* helper API which uses info in
- ** the registration database. Alternatively, the OleRegEnumVerbs
- ** API may be called directly. Objects implemented as a server
- ** DLL may NOT return OLE_S_USEREG; they must call the OleReg*
- ** API or provide their own implementation. For EXE based
- ** objects it is more efficient to return OLE_S_USEREG, because
- ** in then the verb enumerator is instantiated in the callers
- ** process space and no LRPC remoting is required.
- */
- return OLE_S_USEREG;
- }
- // IOleObject::Update method
- STDMETHODIMP SvrDoc_OleObj_Update(LPOLEOBJECT lpThis)
- {
- OleDbgOut2("SvrDoc_OleObj_Updatern");
- /* NOTE: 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_IsUpToDatern");
- /* NOTE: 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_GetClassIDrn");
- /* NOTE: 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,
- LPOLESTR FAR* lpszUserType
- )
- {
- LPSERVERDOC lpServerDoc =
- ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;
- OleDbgOut2("SvrDoc_OleObj_GetUserTypern");
- /* NOTE: we must make sure to set all out parameters to NULL. */
- *lpszUserType = NULL;
- /* NOTE: we must be carefull to return the correct user type here.
- ** if we are currently preforming a "TreatAs (aka. ActivateAs)"
- ** operation then we need to return the user type name that
- ** corresponds to the class of the object we are currently
- ** emmulating. otherwise we should return our normal user type
- ** name corresponding to our own class. This routine determines
- ** the current clsid in effect.
- **
- ** An object implemented as a server EXE (as this sample
- ** is) may simply return OLE_S_USEREG to instruct the OLE
- ** DefHandler to call the OleReg* helper API which uses info in
- ** the registration database. Alternatively, the OleRegGetUserType
- ** API may be called directly. Objects implemented as a server
- ** DLL may NOT return OLE_S_USEREG; they must call the OleReg*
- ** API or provide their own implementation. For EXE based
- ** objects it is more efficient to return OLE_S_USEREG, because
- ** in then the return string is instantiated in the callers
- ** process space and no LRPC remoting is required.
- */
- #if defined( SVR_TREATAS )
- if (! IsEqualCLSID(&lpServerDoc->m_clsidTreatAs, &CLSID_NULL) )
- return OleRegGetUserType(
- (REFCLSID)&lpServerDoc->m_clsidTreatAs,dwFormOfType,lpszUserType);
- else
- #endif // SVR_TREATAS
- return OLE_S_USEREG;
- }
- // IOleObject::SetExtent method
- STDMETHODIMP SvrDoc_OleObj_SetExtent(
- LPOLEOBJECT lpThis,
- DWORD dwDrawAspect,
- LPSIZEL lplgrc
- )
- {
- OleDbgOut2("SvrDoc_OleObj_SetExtentrn");
- /* 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 E_FAIL;
- }
- // IOleObject::GetExtent method
- STDMETHODIMP SvrDoc_OleObj_GetExtent(
- LPOLEOBJECT lpThis,
- DWORD dwDrawAspect,
- LPSIZEL lpsizel
- )
- {
- LPOLEDOC lpOleDoc =
- (LPOLEDOC)((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;
- // artificial AddRef in case object is destroyed during call
- SvrDoc_OleObj_AddRef(lpThis);
- OleDbgOut2("SvrDoc_OleObj_GetExtentrn");
- /* NOTE: it is VERY important to check which aspect the caller
- ** is asking about. an object implemented by a server EXE MAY
- ** fail to return extents when asked for DVASPECT_ICON.
- */
- if (dwDrawAspect == DVASPECT_CONTENT) {
- OleDoc_GetExtent(lpOleDoc, lpsizel);
- // release artificial AddRef
- SvrDoc_OleObj_Release(lpThis);
- 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.
- **
- ** NOTE: 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);
- // release artificial AddRef
- SvrDoc_OleObj_Release(lpThis);
- return NOERROR;
- }
- #endif
- else
- {
- // release artificial AddRef
- SvrDoc_OleObj_Release(lpThis);
- return E_FAIL;
- }
- }
- // IOleObject::Advise method
- STDMETHODIMP SvrDoc_OleObj_Advise(
- LPOLEOBJECT lpThis,
- LPADVISESINK lpAdvSink,
- LPDWORD lpdwConnection
- )
- {
- LPSERVERDOC lpServerDoc =
- ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;
- HRESULT hrErr;
- HRESULT sc;
- // artificial AddRef in case object is destroyed during call
- SvrDoc_OleObj_AddRef(lpThis);
- OLEDBG_BEGIN2("SvrDoc_OleObj_Advisern");
- if (lpServerDoc->m_OleDoc.m_fObjIsClosing)
- {
- // We don't accept any more Advise's once we're closing
- sc = OLE_E_ADVISENOTSUPPORTED;
- goto error;
- }
- if (lpServerDoc->m_lpOleAdviseHldr == NULL &&
- CreateOleAdviseHolder(&lpServerDoc->m_lpOleAdviseHldr) != NOERROR) {
- sc = E_OUTOFMEMORY;
- goto error;
- }
- OLEDBG_BEGIN2("IOleAdviseHolder::Advise calledrn")
- hrErr = lpServerDoc->m_lpOleAdviseHldr->lpVtbl->Advise(
- lpServerDoc->m_lpOleAdviseHldr,
- lpAdvSink,
- lpdwConnection
- );
- OLEDBG_END2
- OLEDBG_END2
- // release artificial AddRef
- SvrDoc_OleObj_Release(lpThis);
- return hrErr;
- error:
- OLEDBG_END2
- *lpdwConnection = 0;
- // release artificial AddRef
- SvrDoc_OleObj_Release(lpThis);
- return sc;
- }
- // IOleObject::Unadvise method
- STDMETHODIMP SvrDoc_OleObj_Unadvise(LPOLEOBJECT lpThis, DWORD dwConnection)
- {
- LPSERVERDOC lpServerDoc =
- ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;
- HRESULT hrErr;
- HRESULT sc;
- // artificial AddRef in case object is destroyed during call
- SvrDoc_OleObj_AddRef(lpThis);
- OLEDBG_BEGIN2("SvrDoc_OleObj_Unadvisern");
- if (lpServerDoc->m_lpOleAdviseHldr == NULL) {
- sc = E_FAIL;
- goto error;
- }
- OLEDBG_BEGIN2("IOleAdviseHolder::Unadvise calledrn")
- hrErr = lpServerDoc->m_lpOleAdviseHldr->lpVtbl->Unadvise(
- lpServerDoc->m_lpOleAdviseHldr,
- dwConnection
- );
- OLEDBG_END2
- OLEDBG_END2
- // release artificial AddRef
- SvrDoc_OleObj_Release(lpThis);
- return hrErr;
- error:
- OLEDBG_END2
- // release artificial AddRef
- SvrDoc_OleObj_Release(lpThis);
- return sc;
- }
- // IOleObject::EnumAdvise method
- STDMETHODIMP SvrDoc_OleObj_EnumAdvise(
- LPOLEOBJECT lpThis,
- LPENUMSTATDATA FAR* lplpenumAdvise
- )
- {
- LPSERVERDOC lpServerDoc =
- ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;
- HRESULT hrErr;
- HRESULT sc;
- // artificial AddRef in case object is destroyed during call
- SvrDoc_OleObj_AddRef(lpThis);
- OLEDBG_BEGIN2("SvrDoc_OleObj_EnumAdvisern");
- /* NOTE: 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 calledrn")
- hrErr = lpServerDoc->m_lpOleAdviseHldr->lpVtbl->EnumAdvise(
- lpServerDoc->m_lpOleAdviseHldr,
- lplpenumAdvise
- );
- OLEDBG_END2
- OLEDBG_END2
- // release artificial AddRef
- SvrDoc_OleObj_Release(lpThis);
- return hrErr;
- error:
- OLEDBG_END2
- // release artificial AddRef
- SvrDoc_OleObj_Release(lpThis);
- return 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;
- // artificial AddRef in case object is destroyed during call
- SvrDoc_OleObj_AddRef(lpThis);
- OleDbgOut2("SvrDoc_OleObj_GetMiscStatusrn");
- /* Get our default MiscStatus for the given Aspect. this
- ** information is registered in the RegDB. We query the RegDB
- ** here to guarantee that the value returned from this method
- ** agrees with the values in RegDB. in this way we only have to
- ** maintain the info in one place (in the RegDB). Alternatively
- ** we could have the values hard coded here.
- */
- OleRegGetMiscStatus((REFCLSID)&CLSID_APP, dwAspect, lpdwStatus);
- /* NOTE: 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
- // release artificial AddRef
- SvrDoc_OleObj_Release(lpThis);
- return NOERROR;
- }
- // IOleObject::SetColorScheme method
- STDMETHODIMP SvrDoc_OleObj_SetColorScheme(
- LPOLEOBJECT lpThis,
- LPLOGPALETTE lpLogpal
- )
- {
- OleDbgOut2("SvrDoc_OleObj_SetColorSchemern");
- // REVIEW: NOT YET IMPLEMENTED
- return 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_GetClassIDrn");
- /* NOTE: 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_IsDirtyrn");
- if (OutlineDoc_IsModified((LPOUTLINEDOC)lpServerDoc))
- return NOERROR;
- else
- return S_FALSE;
- }
- // IPersistStorage::InitNew method
- STDMETHODIMP SvrDoc_PStg_InitNew(
- LPPERSISTSTORAGE lpThis,
- LPSTORAGE lpStg
- )
- {
- LPSERVERDOC lpServerDoc =
- ((struct CDocPersistStorageImpl FAR*)lpThis)->lpServerDoc;
- LPOLEDOC lpOleDoc = (LPOLEDOC)lpServerDoc;
- LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;
- LPOLESTR lpszUserType = /*(LPOLESTR)*/FULLUSERTYPENAME;
- HRESULT hrErr;
- HRESULT sc;
- OLEDBG_BEGIN2("SvrDoc_PStg_InitNewrn")
- #if defined( SVR_TREATAS )
- {
- LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;
- CLSID clsid;
- CLIPFORMAT cfFmt;
- LPOLESTR lpszType;
- /* NOTE: 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, /*(LPOLESTR 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;
- lpszUserType = lpServerDoc->m_lpszTreatAsType;
- OleDbgOut3("SvrDoc_PStg_InitNew: TreateAs ==> '");
- // OleDbgOutNoPrefix3(lpServerDoc->m_lpszTreatAsType);
- OleDbgOutNoPrefix3("'rn");
- } else {
- // ERROR: we ONLY support TreatAs for CF_OUTLINE format
- OleDbgOut("SvrDoc_PStg_InitNew: INVALID TreatAs Formatrn");
- OleStdFreeString(lpszType, NULL);
- }
- }
- }
- #endif // SVR_TREATAS
- /* NOTE: a server EXE object should write its format tag to its
- ** storage in InitNew so that the DefHandler can know the format
- ** of the object. this is particularly important if the objects
- ** uses CF_METATFILE or CF_DIB as its format. the DefHandler
- ** automatically avoids separately storing presentation cache
- ** data when the object's native data is a standard presentation
- ** format.
- */
- WriteFmtUserTypeStg(lpStg,(CLIPFORMAT)lpOutlineApp->m_cfOutline,lpszUserType);
- // set the doc to a new embedded object.
- if (! ServerDoc_InitNewEmbed(lpServerDoc)) {
- sc = E_FAIL;
- goto error;
- }
- /* NOTE: An embedded object must guarantee that it can save
- ** even in low memory situations. it must be able to
- ** successfully save itself without consuming any additional
- ** memory. this means that a server is NOT supposed to open or
- ** create any streams or storages when
- ** IPersistStorage::Save(fSameAsLoad==TRUE) is called. thus an
- ** embedded object should hold onto its storage and pre-open and
- ** hold open any streams that it will need later when it is time
- ** to save.
- */
- hrErr = lpStg->lpVtbl->CreateStream(
- lpStg,
- OLESTR("LineList"),
- STGM_WRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE,
- 0,
- 0,
- &lpOleDoc->m_lpLLStm
- );
- if (hrErr != NOERROR) {
- OleDbgAssertSz(hrErr==NOERROR,"Could not create LineList stream");
- OleDbgOutHResult("LineList CreateStream returned", hrErr);
- sc = hrErr;
- goto error;
- }
- hrErr = lpStg->lpVtbl->CreateStream(
- lpStg,
- OLESTR("NameTable"),
- STGM_WRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE,
- 0,
- 0,
- &lpOleDoc->m_lpNTStm
- );
- if (hrErr != NOERROR) {
- OleDbgAssertSz(hrErr==NOERROR,"Could not create NameTable stream");
- OleDbgOutHResult("NameTable CreateStream returned", hrErr);
- sc = hrErr;
- goto error;
- }
- lpOleDoc->m_lpStg = lpStg;
- // NOTE: to be able to hold onto IStorage* pointer, we must AddRef it
- lpStg->lpVtbl->AddRef(lpStg);
- OLEDBG_END2
- return NOERROR;
- error:
- OLEDBG_END2
- return sc;
- }
- // IPersistStorage::Load method
- STDMETHODIMP SvrDoc_PStg_Load(
- LPPERSISTSTORAGE lpThis,
- LPSTORAGE lpStg
- )
- {
- LPSERVERDOC lpServerDoc =
- ((struct CDocPersistStorageImpl FAR*)lpThis)->lpServerDoc;
- LPOLEDOC lpOleDoc = (LPOLEDOC)lpServerDoc;
- LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;
- HRESULT sc;
- HRESULT hrErr;
- OLEDBG_BEGIN2("SvrDoc_PStg_Loadrn")
- if (OutlineDoc_LoadFromStg((LPOUTLINEDOC)lpServerDoc, lpStg)) {
- ((LPOUTLINEDOC)lpServerDoc)->m_docInitType = DOCTYPE_EMBEDDED;
- /* NOTE: 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==TRUErn");
- OutlineDoc_SetModified(lpOutlineDoc, TRUE, FALSE, FALSE);
- }
- } else {
- sc = E_FAIL;
- goto error;
- }
- /* NOTE: An embedded object must guarantee that it can save
- ** even in low memory situations. it must be able to
- ** successfully save itself without consuming any additional
- ** memory. this means that a server is NOT supposed to open or
- ** create any streams or storages when
- ** IPersistStorage::Save(fSameAsLoad==TRUE) is called. thus an
- ** embedded object should hold onto its storage and pre-open and
- ** hold open any streams that it will need later when it is time
- ** to save.
- */
- if (lpOleDoc->m_lpLLStm)
- OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpLLStm);
- hrErr = lpStg->lpVtbl->OpenStream(
- lpStg,
- OLESTR("LineList"),
- NULL,
- STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
- 0,
- &lpOleDoc->m_lpLLStm
- );
- if (hrErr != NOERROR) {
- OleDbgAssertSz(hrErr==NOERROR,"Could not create LineList stream");
- OleDbgOutHResult("LineList CreateStream returned", hrErr);
- sc = hrErr;
- goto error;
- }
- if (lpOleDoc->m_lpNTStm)
- OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpNTStm);
- hrErr = lpStg->lpVtbl->OpenStream(
- lpStg,
- OLESTR("NameTable"),
- NULL,
- STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
- 0,
- &lpOleDoc->m_lpNTStm
- );
- if (hrErr != NOERROR) {
- OleDbgAssertSz(hrErr==NOERROR,"Could not create NameTable stream");
- OleDbgOutHResult("NameTable CreateStream returned", hrErr);
- sc = hrErr;
- goto error;
- }
- lpOleDoc->m_lpStg = lpStg;
- // NOTE: to be able to hold onto IStorage* pointer, we must AddRef it
- lpStg->lpVtbl->AddRef(lpStg);
- OLEDBG_END2
- return NOERROR;
- error:
- OLEDBG_END2
- return 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;
- HRESULT sc;
- OLEDBG_BEGIN2("SvrDoc_PStg_Savern")
- fStatus = OutlineDoc_SaveSelToStg(
- (LPOUTLINEDOC)lpServerDoc,
- NULL,
- lpOutlineDoc->m_cfSaveFormat,
- lpStg,
- fSameAsLoad,
- FALSE
- );
- if (! fStatus) {
- OutlineApp_ErrorMessage(g_lpApp, ErrMsgPSSaveFail);
- sc = E_FAIL;
- goto error;
- }
- lpServerDoc->m_fSaveWithSameAsLoad = fSameAsLoad;
- lpServerDoc->m_fNoScribbleMode = TRUE;
- OLEDBG_END2
- return NOERROR;
- error:
- OLEDBG_END2
- return sc;
- }
- // IPersistStorage::SaveCompleted method
- STDMETHODIMP SvrDoc_PStg_SaveCompleted(
- LPPERSISTSTORAGE lpThis,
- LPSTORAGE lpStgNew
- )
- {
- LPSERVERDOC lpServerDoc =
- ((struct CDocPersistStorageImpl FAR*)lpThis)->lpServerDoc;
- LPOLEDOC lpOleDoc = (LPOLEDOC)lpServerDoc;
- LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;
- HRESULT hrErr;
- OLEDBG_BEGIN2("SvrDoc_PStg_SaveCompletedrn")
- /* NOTE: this sample application is a pure server application.
- ** 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.
- */
- /* NOTE: 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 E_INVALIDARG;
- }
- /* NOTE: 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 (lpStgNew || lpServerDoc->m_fSaveWithSameAsLoad) {
- /* NOTE: if IPersistStorage::Save has been called, then we
- ** need to clear the dirty bit and send OnSave notification.
- ** if HandsOffStorage is called directly without first
- ** calling Save, then we do NOT want to clear the dirty bit
- ** and send OnSave when SaveCompleted is called.
- */
- if (lpServerDoc->m_fNoScribbleMode) {
- OutlineDoc_SetModified(lpOutlineDoc, FALSE, FALSE, FALSE);
- ServerDoc_SendAdvise (
- lpServerDoc,
- OLE_ONSAVE,
- NULL, /* lpmkDoc -- not relevant here */
- 0 /* advf -- not relevant here */
- );
- }
- lpServerDoc->m_fSaveWithSameAsLoad = FALSE;
- }
- lpServerDoc->m_fNoScribbleMode = FALSE;
- /* NOTE: An embedded object must guarantee that it can save
- ** even in low memory situations. it must be able to
- ** successfully save itself without consuming any additional
- ** memory. this means that a server is NOT supposed to open or
- ** create any streams or storages when
- ** IPersistStorage::Save(fSameAsLoad==TRUE) is called. thus an
- ** embedded object should hold onto its storage and pre-open and
- ** hold open any streams that it will need later when it is time
- ** to save. if this is a SaveAs situtation, then we want to
- ** pre-open and hold open our streams to guarantee that a
- ** subsequent save will be successful in low-memory. if we fail
- ** to open these streams then we want to force ourself to close
- ** to make sure the can't make editing changes that can't be
- ** later saved.
- */
- if ( lpStgNew && !lpServerDoc->m_fSaveWithSameAsLoad ) {
- // release previous streams
- if (lpOleDoc->m_lpLLStm) {
- OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpLLStm);
- lpOleDoc->m_lpLLStm = NULL;
- }
- if (lpOleDoc->m_lpNTStm) {
- OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpNTStm);
- lpOleDoc->m_lpNTStm = NULL;
- }
- if (lpOleDoc->m_lpStg) {
- OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpStg);
- lpOleDoc->m_lpStg = NULL;
- }
- hrErr = lpStgNew->lpVtbl->OpenStream(
- lpStgNew,
- OLESTR("LineList"),
- NULL,
- STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
- 0,
- &lpOleDoc->m_lpLLStm
- );
- if (hrErr != NOERROR) {
- OleDbgAssertSz(hrErr==NOERROR,"Could not create LineList stream");
- OleDbgOutHResult("LineList CreateStream returned", hrErr);
- goto error;
- }
- hrErr = lpStgNew->lpVtbl->OpenStream(
- lpStgNew,
- OLESTR("NameTable"),
- NULL,
- STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
- 0,
- &lpOleDoc->m_lpNTStm
- );
- if (hrErr != NOERROR) {
- OleDbgAssertSz(hrErr==NOERROR,"Could not create NameTable stream");
- OleDbgOutHResult("NameTable CreateStream returned", hrErr);
- goto error;
- }
- lpOleDoc->m_lpStg = lpStgNew;
- // NOTE: to hold onto IStorage* pointer, we must AddRef it
- lpStgNew->lpVtbl->AddRef(lpStgNew);
- }
- OLEDBG_END2
- return NOERROR;
- error:
- OLEDBG_END2
- return E_OUTOFMEMORY;
- }
- // IPersistStorage::HandsOffStorage method
- STDMETHODIMP SvrDoc_PStg_HandsOffStorage(LPPERSISTSTORAGE lpThis)
- {
- LPSERVERDOC lpServerDoc =
- ((struct CDocPersistStorageImpl FAR*)lpThis)->lpServerDoc;
- LPOLEDOC lpOleDoc = (LPOLEDOC)lpServerDoc;
- OLEDBG_BEGIN2("SvrDoc_PStg_HandsOffStoragern")
- /* NOTE: An embedded object must guarantee that it can save
- ** even in low memory situations. it must be able to
- ** successfully save itself without consuming any additional
- ** memory. this means that a server is NOT supposed to open or
- ** create any streams or storages when
- ** IPersistStorage::Save(fSameAsLoad==TRUE) is called. thus an
- ** embedded object should hold onto its storage and pre-open and
- ** hold open any streams that it will need later when it is time
- ** to save. Now when HandsOffStorage is called the object must
- ** release its storage and any streams that is holds open.
- ** later when SaveCompleted is called, it will be given back its
- ** storage.
- */
- if (lpOleDoc->m_lpLLStm) {
- OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpLLStm);
- lpOleDoc->m_lpLLStm = NULL;
- }
- if (lpOleDoc->m_lpNTStm) {
- OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpNTStm);
- lpOleDoc->m_lpNTStm = NULL;
- }
- if (lpOleDoc->m_lpStg) {
- OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpStg);
- lpOleDoc->m_lpStg = NULL;
- }
- 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_GetClassForHandlerrn");
- // NOTE: we only handle LOCAL marshal context.
- if (dwDestContext != MSHCTX_LOCAL || pvDestContext != NULL)
- return E_INVALIDARG;
- /* NOTE: 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_fNoScribbleMode = FALSE;
- lpServerDoc->m_fSaveWithSameAsLoad = FALSE;
- lpServerDoc->m_szContainerApp[0] = ' ';
- lpServerDoc->m_szContainerObj[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;
- lpServerDoc->m_fMenuHelpMode = FALSE; // F1 pressed in menu
- 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)
- {
- char szAnsiStr[256];
- 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(szAnsiStr, "%s in %s",
- (LPSTR)SHORTUSERTYPENAME,
- (LPSTR)DEFCONTAINERNAME);
- A2W (szAnsiStr, lpOutlineDoc->m_szFileName, OLEUI_CCHPATHMAX);
- lpOutlineDoc->m_lpszDocTitle = lpOutlineDoc->m_szFileName;
- /* NOTE: 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, FALSE /*fMakeUpperCase*/);
- 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;
- /* NOTE: we must note the time of last change
- ** for our object in the RunningObjectTable.
- ** this is used as the basis to answer
- ** IOleObject::IsUpToDate. we only want to note
- ** the change time when an actual change takes
- ** place. we do NOT want to set it when we are
- ** notifying clients of ADVF_DATAONSTOP
- */
- if (dwAdvf == 0)
- OleStdNoteObjectChangeTime(lpOleDoc->m_dwRegROT);
- if (lpServerDoc->m_lpDataAdviseHldr) {
- OLEDBG_BEGIN2("IDataAdviseHolder::SendOnDataChange calledrn");
- lpServerDoc->m_lpDataAdviseHldr->lpVtbl->SendOnDataChange(
- lpServerDoc->m_lpDataAdviseHldr,
- (LPDATAOBJECT)&lpOleDoc->m_DataObject,
- 0,
- dwAdvf
- );
- OLEDBG_END2
- }
- #if defined( INPLACE_SVR )
- /* NOTE: 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
- /* NOTE: 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 calledrn");
- lpServerDoc->m_lpOleAdviseHldr->lpVtbl->SendOnClose(
- lpServerDoc->m_lpOleAdviseHldr
- );
- OLEDBG_END2
- }
- /* NOTE: 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 ONSAVErn");
- if (lpServerDoc->m_lpOleAdviseHldr) {
- OLEDBG_BEGIN2("IOleAdviseHolder::SendOnSave calledrn");
- lpServerDoc->m_lpOleAdviseHldr->lpVtbl->SendOnSave(
- lpServerDoc->m_lpOleAdviseHldr
- );
- OLEDBG_END2
- }
- /* NOTE: inform any clients of pseudo objects
- ** within our document, that our document has been
- ** saved.
- */
- ServerNameTable_InformAllPseudoObjectsDocSaved(
- (LPSERVERNAMETABLE)lpOutlineDoc->m_lpNameTable,
- lpmkDoc
- );
- OLEDBG_END3
- break;
- case OLE_ONRENAME:
- // inform clients that the object's name has changed
- OLEDBG_BEGIN3("ServerDoc_SendAdvise ONRENAMErn");
- if (lpmkDoc && lpServerDoc->m_lpOleAdviseHldr) {
- OLEDBG_BEGIN2("IOleAdviseHolder::SendOnRename calledrn");
- lpServerDoc->m_lpOleAdviseHldr->lpVtbl->SendOnRename(
- lpServerDoc->m_lpOleAdviseHldr,
- lpmkDoc
- );
- OLEDBG_END2
- }
- 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;
- }
- /* 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;
- char szAnsiStr[256];
- OleDbgOut2("ServerDoc_UpdateMenurn");
- 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>"
- W2A (lpServerDoc->m_szContainerObj, szAnsiStr, 256);
- wsprintf(str, g_szUpdateCntrDoc, szAnsiStr);
- ModifyMenu(hMenu, IDM_F_SAVE, MF_STRING, IDM_F_SAVE, str);
- // Change File/Exit to File/Exit & Return to <container doc>" */
- W2A (lpServerDoc->m_szContainerObj, szAnsiStr, 256);
- wsprintf(str, g_szExitNReturnToCntrDoc, szAnsiStr);
- 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_RestoreMenurn");
- 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