|
|
//+-------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1996.
//
// File: deflink.h
//
// Contents: Implementation of the standard link object
//
// Classes: CDefLink
//
// Functions:
//
// Author:
// Craig Wittenberg (craigwi) 8/12/92
//
// History: dd-mmm-yy Author Comment
// 20-Feb-95 KentCe Buffered stream i/o.
// 01-Feb-95 t-ScottH added Dump method to CDefLink
// added DumpCDefLink API
// added DLFlag to indicate if aggregated
// (_DEBUG only)
// 09-Jan-95 t-scotth changed VDATETHREAD to accept a pointer
// 09-Jan-95 alexgo fixed a ton of link tracking bugs from
// 16bit OLE.
// 21-Nov-94 alexgo memory optimization
// 28-Aug-94 alexgo added IsReallyRunning
// 02-Aug-94 alexgo added object stabilization
// 30-Jun-94 alexgo handles re-entrant shutdowns better
// 31-May-94 alexgo now recovers from crashed servers
// 06-May-94 alexgo made IsRunning work properly
// 07-Mar-94 alexgo added call tracing
// 03-Feb-94 alexgo fixed errors with SendOnLinkSrcChange
// 11-Jan-94 alexgo added VDATEHEAP macros to every function
// and method. Also fixed an aggregation bug,
// allowing linking to work.
// 22-Nov-93 alexgo removed overloaded GUID ==
// 15-Nov-93 alexgo 32bit port
//
// ChrisWe 11/09/93 Changed COleCache::Update to COleCache::UpdateCache,
// which does the same thing without an indirect fuction call
// srinik 09/11/92 Removed IOleCache implementation, as a result of
// removing voncache.cpp, and moving IViewObject
// implementation into olecache.cpp.
//
// SriniK 06/04/92 Fixed problems in IPersistStorage methods
//--------------------------------------------------------------------------
#include <le2int.h>
#include <scode.h>
#include <objerror.h>
#include "deflink.h"
#include "defutil.h"
#ifdef _DEBUG
#include <dbgdump.h>
#endif // _DEBUG
#ifdef _TRACKLINK_
#include <itrkmnk.hxx>
#endif
ASSERTDATA
/*
* IMPLEMENTATION of CDefLink */
//+-------------------------------------------------------------------------
//
// Member: CDefLink::Create
//
// Synopsis: Static function to create an instance of a link object
//
// Arguments: [pUnkOuter] -- Controlling unknown
//
// Returns: Pointer to IUnkown interface on DefLink
//
// History: dd-mmm-yy Author Comment
// 28-Jan-96 Gopalk Rewritten
//--------------------------------------------------------------------------
IUnknown *CDefLink::Create(IUnknown *pUnkOuter) { LEDebugOut((DEB_ITRACE, "%p _IN CDefLink::Create(%p)\n", NULL /* this */, pUnkOuter));
// Validation check
VDATEHEAP();
// Local variable
CDefLink *pDefLink = NULL; IUnknown *pUnk = NULL; // Create DefLink
pDefLink = new CDefLink(pUnkOuter); if(pDefLink) { // Make the ref count equal to 1
pDefLink->m_Unknown.AddRef();
// Create Ole Cache
pDefLink->m_pCOleCache = new COleCache(pDefLink->m_pUnkOuter, CLSID_NULL); if(pDefLink->m_pCOleCache) { // Create Data Advise Cache
if(CDataAdviseCache::CreateDataAdviseCache(&pDefLink->m_pDataAdvCache) == NOERROR) { pUnk = &pDefLink->m_Unknown; } } }
if(pUnk == NULL) { // Something has gone wrong. Cleanup
if(pDefLink) pDefLink->m_Unknown.Release(); }
LEDebugOut((DEB_ITRACE, "%p OUT CDefLink::Create(%p)\n", NULL /* this */, pUnk )); return pUnk; }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::CDefLink
//
// Synopsis: Constructor
//
// Arguments: [pUnkOuter] -- Controlling IUnknown
//
// History: dd-mmm-yy Author Comment
// 28-Jan-96 Gopalk Rewritten to use CRefExportCount
//--------------------------------------------------------------------------
CDefLink::CDefLink(IUnknown *pUnkOuter) : CRefExportCount(pUnkOuter) { // Validation check
VDATEHEAP();
// Initialize the controlling unknown
if(!pUnkOuter) pUnkOuter = &m_Unknown;
// Initialize member variables
m_pUnkOuter = pUnkOuter; m_clsid = CLSID_NULL; m_dwUpdateOpt = OLEUPDATE_ALWAYS; m_pStg = NULL; m_flags = 0; m_dwObjFlags = 0;
// Initialize sub objects
m_pCOleCache = NULL; m_pCOAHolder = NULL; m_dwConnOle = 0; m_pDataAdvCache = NULL; m_dwConnTime = 0;
// Initialize client site
m_pAppClientSite = NULL;
// Intialize delegates
m_pUnkDelegate = NULL; m_pDataDelegate = NULL; m_pOleDelegate = NULL; m_pRODelegate = NULL; m_pOleItemContainerDelegate = NULL;
// Initialize monikers
m_pMonikerAbs = NULL; m_pMonikerRel = NULL;
// zero out times
memset(&m_ltChangeOfUpdate, 0, sizeof(m_ltChangeOfUpdate)); memset(&m_ltKnownUpToDate, 0, sizeof(m_ltKnownUpToDate)); memset(&m_rtUpdate, 0, sizeof(m_rtUpdate));
// Initialize member variables used for caching MiscStatus bits
m_ContentSRVMSHResult = 0xFFFFFFFF; m_ContentSRVMSBits = 0; m_ContentREGMSHResult = 0xFFFFFFFF; m_ContentREGMSBits = 0;
#ifdef _DEBUG
if(pUnkOuter != &m_Unknown) m_flags |= DL_AGGREGATED; #endif // _DEBUG
}
//+-------------------------------------------------------------------------
//
// Member: CDefObject::CleanupFn, private, virtual
//
// Synopsis: This function is called by CRefExportCount when the object
// enters zombie state
//
// Arguments: None
//
// History: dd-mmm-yy Author Comment
// 28-Jan-07 Gopalk Creation
//--------------------------------------------------------------------------
void CDefLink::CleanupFn(void) { LEDebugOut((DEB_ITRACE, "%p _IN CDefLink::CleanupFn()\n", this)); // Validation check
VDATEHEAP();
// Unbind source if neccessary
UnbindSource();
// Release monikers
if(m_pMonikerAbs) { m_pMonikerAbs->Release(); m_pMonikerAbs = NULL; } if(m_pMonikerRel) { m_pMonikerRel->Release(); m_pMonikerRel = NULL; }
// Release sub objects
if(m_pCOleCache) { m_pCOleCache->m_UnkPrivate.Release(); m_pCOleCache = NULL; } if(m_pCOAHolder) { m_pCOAHolder->Release(); m_pCOAHolder = NULL; } if(m_pDataAdvCache) { delete m_pDataAdvCache; m_pDataAdvCache = NULL; }
// Release container side objects
Win4Assert(!(m_flags & DL_LOCKED_CONTAINER)); if(m_pAppClientSite) { m_pAppClientSite->Release(); m_pAppClientSite = NULL; } if(m_pStg) { m_pStg->Release(); m_pStg = NULL; }
// Update flags
m_flags &= ~(DL_DIRTY_LINK); m_flags |= DL_CLEANEDUP;
LEDebugOut((DEB_ITRACE, "%p OUT CDefLink::CleanupFn()\n", this ));
}
//+-------------------------------------------------------------------------
//
// Function: DumpSzTime
//
// Synopsis: Prints the time in the FILETIME strucutre
//
// Effects:
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Signals:
//
// Modifies:
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
//
// Notes: NYI for 32bit
//
//--------------------------------------------------------------------------
#ifdef LINK_DEBUG
INTERNAL_(void) DumpSzTime( LPOLESTR szMsg, FILETIME ft ) { VDATEHEAP();
WORD wDate, wTime; XCHAR szBuffer[24];
CoFileTimeToDosDateTime(&ft, &wDate, &wTime);
int Day = ( wDate & 0x001F); int Month = ( (wDate>>5) & 0x000F); int Year = 1980 + ((wDate>>9) & 0x007F);
int Sec = ( wTime & 0x001F); int Min = ( (wTime>>5) & 0x003F); int Hour = ( (wTime>>11) & 0x001F);
wsprintf((LPOLESTR)szBuffer, " %02d:%02d:%02d on %02d/%02d/%04d\n", Hour, Min, Sec, Month, Day, Year); OutputDebugString(szMsg); OutputDebugString(szBuffer); } #else
#define DumpSzTime(a,b)
#endif
//+-------------------------------------------------------------------------
//
// Member: CDefLink::SetUpdateTimes
//
// Synopsis: Internal function to save local and remote times for
// link->IsUpToDate calculations
//
// Effects:
//
// Arguments: void
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation:
//
// Algorithm: See notes below
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 18-Nov-93 alexgo 32bit port
//
// Notes:
// The basic problem in calculating link IsUpToDate is that
// the local clock may be different than the remote clock.
// The solution is to keep track of both times on *both*
// clocks (i.e. time now and time of change on both the local
// and remote clocks). IsUpToDate is calculated by comparing
// the differences between the times on the two clocks. This,
// of course, assumes that both clocks equivalently measure
// a second.
//
//--------------------------------------------------------------------------
INTERNAL CDefLink::SetUpdateTimes( void ) { VDATEHEAP();
FILETIME rtNewUpdate; LPMONIKER pmkAbs = NULL; HRESULT hresult; LPBINDCTX pbc = NULL;
LEDebugOut((DEB_ITRACE, "%p _IN CDefLink::SetUpdateTimes ( )\n", this ));
//use the relative moniker if it exists and if the container has a
//moniker
if (NOERROR != GetAbsMkFromRel(&pmkAbs, NULL)) { //otherwise use the absolute moniker
pmkAbs = m_pMonikerAbs; if (pmkAbs) { pmkAbs->AddRef(); } } if (pmkAbs == NULL) { hresult = E_UNSPEC; goto errRet; }
hresult = CreateBindCtx( 0, &pbc ); if (hresult != NOERROR) { goto errRet; }
//debugging aids
DumpSzTime("SetUpdateTimes (going in): rtUpdate = ",m_rtUpdate); DumpSzTime("SetUpdateTimes (going in): ltKnownUpToDate = ", m_ltKnownUpToDate); DumpSzTime("SetUpdateTimes (going in): ltChangeOfUpdate = ", m_ltChangeOfUpdate);
//get the current local time.
CoFileTimeNow(&m_ltKnownUpToDate);
//debugging aids
DumpSzTime("SetUpdateTimes: time now is ",m_ltKnownUpToDate);
//get the time of last change on the remote machine
hresult = pmkAbs->GetTimeOfLastChange(pbc, NULL, &rtNewUpdate); if (hresult == NOERROR) { //if the remote time of last change is different than
//what we previously stored as the remote time of last change,
//then we update the remote time of last change and update
//our local time of last change.
//Since the IsUpToDate algorithm relies on taking the
//differences between times on the same clock and comparing
//those differences between machines, it is important that
//the two times (local and remote) are *set* simulataneously.
if ((rtNewUpdate.dwLowDateTime != m_rtUpdate.dwLowDateTime)|| (rtNewUpdate.dwHighDateTime != m_rtUpdate.dwHighDateTime))
{ // rtUpdate value is changing
m_rtUpdate = rtNewUpdate;
//debugging aid
DumpSzTime("rtUpdate changing to ", m_rtUpdate); m_ltChangeOfUpdate = m_ltKnownUpToDate;
//debugging aid
DumpSzTime("ltChangeOfUpdate changing to ", m_ltChangeOfUpdate); m_flags |= DL_DIRTY_LINK; } } errRet: //debugging aids
DumpSzTime("SetUpdateTimes (going out): rtUpdate = ",m_rtUpdate); DumpSzTime("SetUpdateTimes (going out): ltKnownUpToDate = ", m_ltKnownUpToDate); DumpSzTime("SetUpdateTimes (going out): ltChangeOfUpdate = ", m_ltChangeOfUpdate);
if (pmkAbs) { pmkAbs->Release(); }
if (pbc) { pbc->Release(); }
LEDebugOut((DEB_ITRACE, "%p OUT CDefLink::SetUpdateTimes ( %lx )\n", this, hresult));
return(hresult); }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::UpdateUserClassID
//
// Synopsis: Grabs the class ID from the remote server (our delegate)
//
// Effects:
//
// Arguments: void
//
// Requires:
//
// Returns: void
//
// Signals:
//
// Modifies:
//
// Derivation:
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 18-Nov-93 alexgo 32bit port
//
// Notes:
//
// update clsid from server if running; necessary because link source in
// treatas case may decide to change the clsid (e.g., if features are used
// which aren't supported by the old clsid).
//--------------------------------------------------------------------------
INTERNAL_(void) CDefLink::UpdateUserClassID(void) { VDATEHEAP();
CLSID clsid; IOleObject *pOleDelegate;
LEDebugOut((DEB_ITRACE, "%p _IN CDefLink::UpdateUserClass ( )\n", this));
if( (pOleDelegate = GetOleDelegate()) != NULL && pOleDelegate->GetUserClassID(&clsid) == NOERROR) { m_clsid = clsid; }
LEDebugOut((DEB_ITRACE, "%p OUT CDefLink::UpdateUserClass ( )\n", this )); }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::~CDefLink
//
// Synopsis: Destructor
//
// Arguments: None
//
// History: dd-mmm-yy Author Comment
// 10-Jan-07 Gopalk Rewritten
//--------------------------------------------------------------------------
CDefLink::~CDefLink (void) { VDATEHEAP();
Win4Assert(m_flags & DL_CLEANEDUP); Win4Assert(!(m_flags & DL_LOCKED_CONTAINER) ); Win4Assert(!(m_flags & DL_DIRTY_LINK)); Win4Assert(m_pMonikerAbs == NULL); Win4Assert(m_pMonikerRel == NULL); Win4Assert(m_pUnkDelegate == NULL); Win4Assert(m_pStg == NULL); Win4Assert(m_pCOleCache == NULL); Win4Assert(m_pCOAHolder == NULL); Win4Assert(m_pAppClientSite == NULL); }
//+----------------------------------------------------------------------------
//
// Member:
// CDefLink::CPrivUnknown::AddRef, private
//
// Synopsis:
// implements IUnknown::AddRef
//
// Arguments:
// none
//
// Returns:
// the parent object's reference count
//
// History:
// Gopalk Rewritten Jan 28, 97
//-----------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CDefLink::CPrivUnknown::AddRef( void ) { LEDebugOut((DEB_TRACE, "%p _IN CDefLink::CPrivUnknown::AddRef()\n", this));
// Validation check
VDATEHEAP();
// Local variables
CDefLink *pDefLink = GETPPARENT(this, CDefLink, m_Unknown); ULONG cRefs;
// Addref the parent object
cRefs = pDefLink->SafeAddRef();
LEDebugOut((DEB_TRACE, "%p OUT CDefLink::CPrivUnknown::AddRef(%lu)\n", this, cRefs));
return cRefs; }
//+----------------------------------------------------------------------------
//
// Member:
// CDefLink::CPrivUnknown::Release, private
//
// Synopsis:
// implements IUnknown::Release
//
// Arguments:
// none
//
// Returns:
// the parent object's reference count
//
// History:
// Gopalk Rewritten Jan 28, 97
//-----------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CDefLink::CPrivUnknown::Release( void ) { LEDebugOut((DEB_TRACE, "%p _IN CDefLink::CPrivUnknown::Release()\n", this));
// Validation check
VDATEHEAP();
// Local variables
CDefLink *pDefLink = GETPPARENT(this, CDefLink, m_Unknown); ULONG cRefs;
// Release parent object
cRefs = pDefLink->SafeRelease();
LEDebugOut((DEB_TRACE, "%p OUT CDefLink::CPrivUnknown::Release(%lu)\n", this, cRefs));
return cRefs; }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::CPrivUnknown::QueryInterface
//
// Synopsis: The link's private QI implementation
//
// Effects:
//
// Arguments: [iid] -- the requested interface ID
// [ppv] -- where to put the pointer to the interface
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation: IUnknown
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 11-Jan-94 alexgo QI to the cache now queries to the cache's
// private IUnknown implementation
// 22-Nov-93 alexgo removed overloaded GUID ==
// 18-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
STDMETHODIMP CDefLink::CPrivUnknown::QueryInterface(REFIID iid, LPLPVOID ppv) { HRESULT hresult = NOERROR; CDefLink *pDefLink = GETPPARENT(this, CDefLink, m_Unknown);
VDATEHEAP();
LEDebugOut((DEB_TRACE, "%p _IN CDefLink::CPrivUnknown::QueryInterface" " ( %p , %p )\n", pDefLink, iid, ppv));
if (IsEqualIID(iid, IID_IUnknown)) { *ppv = (void FAR *)&pDefLink->m_Unknown; //AddRef this object (not the aggregate)
AddRef(); // hresult already set to NOERROR;
goto errRtn; } else if (IsEqualIID(iid, IID_IOleObject)) { *ppv = (void FAR *) (IOleObject *)pDefLink; } else if (IsEqualIID(iid, IID_IDataObject)) { *ppv = (void FAR *) (IDataObject *)pDefLink; } else if (IsEqualIID(iid, IID_IOleLink)) { *ppv = (void FAR *) (IOleLink *)pDefLink; } else if (IsEqualIID(iid, IID_IRunnableObject)) { *ppv = (void FAR *) (IRunnableObject *)pDefLink; } else if (IsEqualIID(iid, IID_IViewObject) || IsEqualIID(iid, IID_IOleCache) || IsEqualIID(iid, IID_IViewObject2) || IsEqualIID(iid, IID_IOleCache2) ) { hresult = pDefLink->m_pCOleCache->m_UnkPrivate.QueryInterface(iid,ppv); goto errRtn; } else if (IsEqualIID(iid, IID_IPersistStorage) || IsEqualIID(iid, IID_IPersist)) { *ppv = (void FAR *) (IPersistStorage *)pDefLink; } else { *ppv = NULL; hresult = E_NOINTERFACE; goto errRtn; }
pDefLink->m_pUnkOuter->AddRef();
errRtn:
LEDebugOut((DEB_TRACE, "%p OUT CDefLink::CPrivUnknown::QueryInterface" " ( %lx ) [ %p ]\n", pDefLink, hresult, *ppv));
return(hresult); }
/*
* IMPLEMENTATION of IUnknown methods */
//+-------------------------------------------------------------------------
//
// Member: CDefLink::QueryInterface
//
// Synopsis: QI's to the controlling IUnknown
//
// Effects:
//
// Arguments: [riid] -- the interface ID
// [ppv] -- where to put it
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation: IUnknown
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 15-Nov-94 alexgo author
//
// Notes: We do *not* need to stabilize this method as only
// one outgoing call is made and we do not use the
// 'this' pointer afterwards
//
//--------------------------------------------------------------------------
STDMETHODIMP CDefLink::QueryInterface( REFIID riid, void **ppv ) { HRESULT hresult;
VDATEHEAP();
LEDebugOut((DEB_TRACE, "%p _IN CDefLink::QueryInterface ( %lx , " "%p )\n", this, riid, ppv));
Assert(m_pUnkOuter);
hresult = m_pUnkOuter->QueryInterface(riid, ppv);
LEDebugOut((DEB_TRACE, "%p OUT CDefLink::QueryInterface ( %lx ) " "[ %p ]\n", this, hresult, *ppv));
return hresult; }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::AddRef
//
// Synopsis: delegates AddRef to the controlling IUnknown
//
// Effects:
//
// Arguments: void
//
// Requires:
//
// Returns: ULONG -- the new reference count
//
// Signals:
//
// Modifies:
//
// Derivation: IUnknown
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 15-Nov-94 alexgo author
//
// Notes:
//
//--------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CDefLink::AddRef( void ) { ULONG crefs;;
VDATEHEAP();
LEDebugOut((DEB_TRACE, "%p _IN CDefLink::AddRef ( )\n", this));
Assert(m_pUnkOuter);
crefs = m_pUnkOuter->AddRef();
LEDebugOut((DEB_TRACE, "%p OUT CDefLink::AddRef ( %ld ) ", this, crefs));
return crefs; }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::Release
//
// Synopsis: delegates Release to the controlling IUnknown
//
// Effects:
//
// Arguments: void
//
// Requires:
//
// Returns: ULONG -- the new reference count
//
// Signals:
//
// Modifies:
//
// Derivation: IUnknown
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 15-Nov-94 alexgo author
//
// Notes:
//
//--------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CDefLink::Release( void ) { ULONG crefs;;
VDATEHEAP();
LEDebugOut((DEB_TRACE, "%p _IN CDefLink::Release ( )\n", this));
Assert(m_pUnkOuter);
crefs = m_pUnkOuter->Release();
LEDebugOut((DEB_TRACE, "%p OUT CDefLink::Release ( %ld )\n", this, crefs));
return crefs; }
/*
* IMPLEMENTATION of CDataObjectImpl methods */
//+-------------------------------------------------------------------------
//
// Member: CDefLink::GetDataDelegate
//
// Synopsis: Private method to get the IDataObject interface on
// the server delegate for the link
//
// Effects:
//
// Arguments: void
//
// Requires:
//
// Returns: IDataObject *
//
// Signals:
//
// Modifies:
//
// Derivation:
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 18-Nov-93 alexgo 32bit port
//
// Notes:
// This function may return misleading information if the
// server has died (i.e., you'll return a pointer to a cached
// interface proxy). It is the responsibility of the caller
// to handler server crashes.
//
//--------------------------------------------------------------------------
INTERNAL_(IDataObject *) CDefLink::GetDataDelegate(void) { VDATEHEAP();
IDataObject *pDataDelegate;
LEDebugOut((DEB_ITRACE, "%p _IN CDefLink::GetDataDelegate ( )\n", this ));
if( !IsZombie() ) { DuCacheDelegate(&m_pUnkDelegate, IID_IDataObject, (LPLPVOID)&m_pDataDelegate, NULL); pDataDelegate = m_pDataDelegate; #if DBG == 1
if( m_pDataDelegate ) { Assert(m_pUnkDelegate); } #endif // DBG == 1
} else { pDataDelegate = NULL; }
LEDebugOut((DEB_ITRACE, "%p OUT CDefLink::GetData" "Delegate ( %p )\n", this, pDataDelegate));
return pDataDelegate; }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::ReleaseDataDelegate
//
// Synopsis: Private method to release the IDataObject pointer on the
// server to which we are linked
//
// Effects:
//
// Arguments: void
//
// Requires:
//
// Returns: void
//
// Signals:
//
// Modifies:
//
// Derivation:
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 18-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
INTERNAL_(void) CDefLink::ReleaseDataDelegate(void) { VDATEHEAP();
LEDebugOut((DEB_ITRACE, "%p _IN CDefLink::ReleaseDataDelegate ( )\n", this));
if (m_pDataDelegate) { SafeReleaseAndNULL((IUnknown **)&m_pDataDelegate); }
LEDebugOut((DEB_ITRACE, "%p OUT CDefLink::ReleaseData" "Delegate ( )\n", this )); }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::GetData
//
// Synopsis: Gets data from the server
//
// Effects:
//
// Arguments: [pfromatetcIn] -- the requested data format
// [pmedium] -- where to put the data
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation: IDataObject
//
// Algorithm: Tries the cache first, then asks the server
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 03-Aug-94 alexgo stabilized
// 18-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
STDMETHODIMP CDefLink::GetData(LPFORMATETC pformatetcIn, LPSTGMEDIUM pmedium ) { HRESULT hresult = NOERROR;
VDATEHEAP(); VDATETHREAD(this);
LEDebugOut((DEB_TRACE, "%p _IN CDefLink::GetData" " ( %p , %p )\n", this, pformatetcIn, pmedium));
VDATEPTROUT( pmedium, STGMEDIUM ); VDATEREADPTRIN( pformatetcIn, FORMATETC );
CRefStabilize stabilize(this);
if( !HasValidLINDEX(pformatetcIn) ) { return DV_E_LINDEX; }
pmedium->tymed = TYMED_NULL; pmedium->pUnkForRelease = NULL;
Assert(m_pCOleCache != NULL); if( m_pCOleCache->m_Data.GetData(pformatetcIn, pmedium) != NOERROR) { if( GetDataDelegate() ) { hresult = m_pDataDelegate->GetData(pformatetcIn, pmedium); AssertOutStgmedium(hresult, pmedium); } else { hresult = OLE_E_NOTRUNNING; } }
LEDebugOut((DEB_TRACE, "%p OUT CDefLink::GetData" " ( %lx )\n", this, hresult));
return(hresult);
}
//+-------------------------------------------------------------------------
//
// Member: CDefLink::GetDataHere
//
// Synopsis: Retrieves data into the specified pmedium
//
// Effects:
//
// Arguments: [pformatetcIn] -- the requested format
// [pmedium] -- where to put the data
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation: IDataObject
//
// Algorithm: Asks the cache first, then the server delegate
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 03-Aug-94 alexgo stabilized
// 18-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
STDMETHODIMP CDefLink::GetDataHere( LPFORMATETC pformatetcIn, LPSTGMEDIUM pmedium ) { HRESULT hresult = NOERROR;
VDATEHEAP(); VDATETHREAD(this);
LEDebugOut((DEB_TRACE, "%p _IN CDefLink::GetDataHere" " ( %p , %p )\n", this, pformatetcIn, pmedium));
VDATEREADPTRIN( pformatetcIn, FORMATETC ); VDATEREADPTRIN( pmedium, STGMEDIUM );
CRefStabilize stabilize(this);
if( !HasValidLINDEX(pformatetcIn) ) { return DV_E_LINDEX; }
Assert(m_pCOleCache != NULL); if( m_pCOleCache->m_Data.GetDataHere(pformatetcIn, pmedium) != NOERROR ) { if ( GetDataDelegate() ) { hresult = m_pDataDelegate->GetDataHere(pformatetcIn, pmedium); } else { hresult = OLE_E_NOTRUNNING; } }
LEDebugOut((DEB_TRACE, "%p OUT CDefLink::GetDataHere" " ( %lx )\n", this, hresult));
return hresult; }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::QueryGetData
//
// Synopsis: Returns whether or not a GetData call for the requested
// format would succeed.
//
// Effects:
//
// Arguments: [pformatetcIn] -- the requested data format
//
// Requires:
//
// Returns: HRESULT (NOERROR == GetData would succeed)
//
// Signals:
//
// Modifies:
//
// Derivation: IDataObject
//
// Algorithm: Asks the cache first, then the server delegate (if the
// cache call fails)
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 03-Aug-94 alexgo stabilized
// 18-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
STDMETHODIMP CDefLink::QueryGetData(LPFORMATETC pformatetcIn ) { HRESULT hresult = NOERROR;
VDATEHEAP(); VDATETHREAD(this);
LEDebugOut((DEB_TRACE, "%p _IN CDefLink::QueryGetData" " ( %p )\n", this, pformatetcIn));
VDATEREADPTRIN( pformatetcIn, FORMATETC );
CRefStabilize stabilize(this);
if( !HasValidLINDEX(pformatetcIn) ) { hresult = DV_E_LINDEX; goto errRtn; }
Assert(m_pCOleCache != NULL); if( m_pCOleCache->m_Data.QueryGetData(pformatetcIn) != NOERROR ) { if ( GetDataDelegate() ) { hresult = m_pDataDelegate->QueryGetData(pformatetcIn); } else { hresult = OLE_E_NOTRUNNING; } }
errRtn:
LEDebugOut((DEB_TRACE, "%p OUT CDefLink::QueryGetData" " ( %lx )\n", this, hresult));
return hresult; }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::GetCanonicalFormatEtc
//
// Synopsis: Gets the cannonical (or preferred) data format for the
// object (choosing from the given formats)
//
// Effects:
//
// Arguments: [pformatetc] -- the requested formats
// [pformatetcOut] -- where to to put the canonical format
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation: IDataObject
//
// Algorithm: Delegates to the server (if running)
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 03-Aug-94 alexgo stabilized
// 18-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
STDMETHODIMP CDefLink::GetCanonicalFormatEtc( LPFORMATETC pformatetc, LPFORMATETC pformatetcOut) { HRESULT hresult;
VDATEHEAP(); VDATETHREAD(this);
LEDebugOut((DEB_TRACE, "%p _IN CDefLink::Get" "CanonicalFormatetc ( %p , %p )\n", this, pformatetc, pformatetcOut));
VDATEPTROUT( pformatetcOut, FORMATETC ); VDATEREADPTRIN( pformatetc, FORMATETC );
CRefStabilize stabilize(this);
pformatetcOut->ptd = NULL; pformatetcOut->tymed = TYMED_NULL;
if (!HasValidLINDEX(pformatetc)) { return DV_E_LINDEX; }
if( GetDataDelegate() ) { hresult = m_pDataDelegate->GetCanonicalFormatEtc(pformatetc, pformatetcOut); } else { hresult = OLE_E_NOTRUNNING; }
LEDebugOut((DEB_TRACE, "%p OUT CDefLink::Get" "CanonicalFormatetc ( %lx )\n", this, hresult));
return hresult; }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::SetData
//
// Synopsis: Stuffs data into an object (such as an icon)
//
// Effects:
//
// Arguments: [pformatetc] -- the format of the data
// [pmedium] -- the data
// [fRelease] -- if TRUE, then the data should be free'd
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation: IDataObject
//
// Algorithm: Delegates to the server
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 03-Aug-94 alexgo stabilized
// 18-Nov-93 alexgo 32bit port
//
// Notes: The cache gets updated via a OnDataChange advise
//
//--------------------------------------------------------------------------
STDMETHODIMP CDefLink::SetData( LPFORMATETC pformatetc, LPSTGMEDIUM pmedium, BOOL fRelease) { HRESULT hresult;
VDATEHEAP(); VDATETHREAD(this);
LEDebugOut((DEB_TRACE, "%p _IN CDefLink::SetData" " ( %p , %p , %lu )\n", this, pformatetc, pmedium, fRelease));
VDATEREADPTRIN( pformatetc, FORMATETC ); VDATEREADPTRIN( pmedium, STGMEDIUM );
CRefStabilize stabilize(this);
if( !HasValidLINDEX(pformatetc) ) { hresult = DV_E_LINDEX; goto errRtn;
}
if( GetDataDelegate() ) { hresult = m_pDataDelegate->SetData(pformatetc, pmedium, fRelease); } else { hresult = OLE_E_NOTRUNNING; }
errRtn:
LEDebugOut((DEB_TRACE, "%p OUT CDefLink::SetData " "( %lx )\n", this, hresult));
return hresult; }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::EnumFormatEtc
//
// Synopsis: Enumerates the formats accepted for either GetData or SetData
//
// Effects:
//
// Arguments: [dwDirection] -- which formats (1 == GetData or
// 2 == SetData)
// [ppenumFormatEtc] -- where to put the enumerator
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation: IDataObject
//
// Algorithm: Delegates to the server, if not available or the server
// returns OLE_E_USEREG
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 03-Aug-94 alexgo stabilized
// 30-May-94 alexgo now handles crashed servers
// 18-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
STDMETHODIMP CDefLink::EnumFormatEtc( DWORD dwDirection, LPENUMFORMATETC *ppenumFormatEtc) { HRESULT hresult;
VDATEHEAP(); VDATETHREAD(this);
VDATEPTROUT(ppenumFormatEtc, LPENUMFORMATETC);
LEDebugOut((DEB_TRACE, "%p _IN CDefLink::EnumFormat" "Etc ( %lu , %p )\n", this, dwDirection, ppenumFormatEtc));
CRefStabilize stabilize(this);
if( GetDataDelegate() ) { hresult=m_pDataDelegate->EnumFormatEtc (dwDirection, ppenumFormatEtc);
if( !GET_FROM_REGDB(hresult) ) { if( SUCCEEDED(hresult) || IsReallyRunning() ) { // if we failed, but the server is still
// running, then go ahead and propogate the
// error to the caller.
// Note that IsReallyRunning will clean up our
// state if the server had crashed.
goto errRtn; }
// FALL-THROUGH!! This is deliberate. If
// the call failed and the server is no longer
// running, then we assume the server has crashed.
// We want to go ahead and fetch the information
// from the registry.
} }
// Not running or object wants to use reg db anyway
hresult = OleRegEnumFormatEtc(m_clsid, dwDirection, ppenumFormatEtc);
errRtn:
LEDebugOut((DEB_TRACE, "%p OUT CDefLink::EnumFormat" "Etc ( %lx ) [ %p ]\n", this, hresult, *ppenumFormatEtc));
return hresult; }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::DAdvise
//
// Synopsis: Sets up a data advise connection
//
// Effects:
//
// Arguments: [pFormatetc] -- the data format to advise on
// [advf] -- advise flags
// [pAdvSink] -- whom to notify
// [pdwConnection] -- where to put the advise connection ID
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation: IDataObject
//
// Algorithm: Delegates to the advise cache
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 03-Aug-94 alexgo stabilized
// 18-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
STDMETHODIMP CDefLink::DAdvise(FORMATETC *pFormatetc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection) { HRESULT hresult; IDataObject * pDataDelegate;
VDATEHEAP(); VDATETHREAD(this);
LEDebugOut((DEB_TRACE, "%p _IN CDefLink::DAdvise " "( %p , %lu , %p , %p )\n", this, pFormatetc, advf, pAdvSink, pdwConnection ));
VDATEREADPTRIN( pFormatetc, FORMATETC ); VDATEIFACE( pAdvSink );
if (pdwConnection) { VDATEPTROUT( pdwConnection, DWORD ); *pdwConnection = NULL; }
CRefStabilize stabilize(this);
if (!HasValidLINDEX(pFormatetc)) { hresult = DV_E_LINDEX; goto errRtn; }
pDataDelegate = GetDataDelegate(); // NULL if not running
hresult = m_pDataAdvCache->Advise(pDataDelegate, pFormatetc, advf, pAdvSink, pdwConnection);
errRtn:
LEDebugOut((DEB_TRACE, "%p OUT CDefLink::DAdvise " "( %lx ) [ %p ]\n", this, hresult, (pdwConnection) ? *pdwConnection : 0 ));
return hresult; }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::DUnadvise
//
// Synopsis: Destroys a data advise connection
//
// Effects:
//
// Arguments: [dwConnection] -- the connection to dismantle
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation: IDataObject
//
// Algorithm: delegates to the data advise cache
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 03-Aug-94 alexgo stabilized
// 18-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
STDMETHODIMP CDefLink::DUnadvise(DWORD dwConnection) { HRESULT hresult; IDataObject FAR* pDataDelegate;
VDATEHEAP(); VDATETHREAD(this);
LEDebugOut((DEB_TRACE, "%p _IN CDefLink::DUnadvise" " ( %lu )\n", this, dwConnection ));
CRefStabilize stabilize(this);
pDataDelegate = GetDataDelegate();// NULL if not running
hresult = m_pDataAdvCache->Unadvise(pDataDelegate, dwConnection);
LEDebugOut((DEB_TRACE, "%p OUT CDefLink::DUnadvise ( %lx )\n", this, hresult));
return hresult; }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::EnumDAdvise
//
// Synopsis: Enumerates the data advise connections to the object
//
// Effects:
//
// Arguments: [ppenumAdvise] -- where to put the enumerator
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation: IDataObject
//
// Algorithm: delegates to the data advise cache
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 18-Nov-93 alexgo 32bit port
//
// Notes: This method does NOT have to be stabilized as we are
// only going to be allocating memory for the enumerator
//
//--------------------------------------------------------------------------
STDMETHODIMP CDefLink::EnumDAdvise( LPENUMSTATDATA *ppenumAdvise ) { HRESULT hresult;
VDATEHEAP(); VDATETHREAD(this);
LEDebugOut((DEB_TRACE, "%p _IN CDefLink::EnumDAdvise" " ( %p )\n", this, ppenumAdvise));
hresult = m_pDataAdvCache->EnumAdvise (ppenumAdvise);
LEDebugOut((DEB_TRACE, "%p OUT CDefLink::EnumDAdvise" " ( %lx ) [ %p ]\n", this, hresult, *ppenumAdvise));
return hresult; }
/*
* IMPLEMENTATION of COleObjectImpl methods * */
//+-------------------------------------------------------------------------
//
// Member: CDefLink::GetOleDelegate
//
// Synopsis: Gets the IOleObject interface from the server, private method
//
// Effects:
//
// Arguments: [void]
//
// Requires:
//
// Returns: IOleObject *
//
// Signals:
//
// Modifies:
//
// Derivation:
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 03-Aug-94 alexgo stabilized and handled the zombie state
// 18-Nov-93 alexgo 32bit port
//
// Notes:
// This function may return misleading information if the
// server has died (i.e., you'll return a pointer to a cached
// interface proxy). It is the responsibility of the caller
// to handler server crashes.
//
//
//--------------------------------------------------------------------------
INTERNAL_(IOleObject *) CDefLink::GetOleDelegate(void) { IOleObject *pOleDelegate;
VDATEHEAP();
LEDebugOut((DEB_ITRACE, "%p _IN CDefLink::GetOle" "Delegate ( )\n", this ));
if( !IsZombie() ) { DuCacheDelegate(&m_pUnkDelegate, IID_IOleObject, (LPLPVOID)&m_pOleDelegate, NULL);
pOleDelegate = m_pOleDelegate;
#if DBG == 1
if( m_pOleDelegate ) { Assert(m_pUnkDelegate); } #endif // DBG == 1
} else { pOleDelegate = NULL; }
LEDebugOut((DEB_ITRACE, "%p OUT CDefLink::GetOle" "Delegate ( %p )\n", this, pOleDelegate));
return pOleDelegate; }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::ReleaseOleDelegate (private)
//
// Synopsis: Releases the IOleObject pointer from the server
//
// Effects:
//
// Arguments: void
//
// Requires:
//
// Returns: void
//
// Signals:
//
// Modifies:
//
// Derivation:
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 18-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
INTERNAL_(void) CDefLink::ReleaseOleDelegate(void) { VDATEHEAP();
LEDebugOut((DEB_ITRACE, "%p _IN CDefLink::ReleaseOle" "Delegate ( )\n", this ));
if (m_pOleDelegate) { SafeReleaseAndNULL((IUnknown **)&m_pOleDelegate); }
LEDebugOut((DEB_ITRACE, "%p OUT CDefLink::ReleaseOle" "Delegate ( )\n", this )); }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::SetClientSite
//
// Synopsis: Sets the client site for the object
//
// Effects:
//
// Arguments: [pClientSite] -- the client site
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation: IOleObject
//
// Algorithm: Stores the pointer; if the link is running, then
// the LockContainer is called via the client site by
// the DuSetClientSite helper function
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 03-Aug-94 alexgo stabilized and handled zombie state
// 18-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
STDMETHODIMP CDefLink::SetClientSite( IOleClientSite *pClientSite ) { HRESULT hresult;
VDATEHEAP(); VDATETHREAD(this);
LEDebugOut((DEB_TRACE, "%p _IN CDefLink::SetClientSite" " ( %p )\n", this, pClientSite));
CRefStabilize stabilize(this);
if( IsZombie() ) { // we don't want to change our state (i.e. reset the
// the client site) if we're zombied, because it's possible
// that we'd never be able to release the client site again
// resulting in memory leaks or faults.
hresult = CO_E_RELEASED; } else { BOOL fLockedContainer = (m_flags & DL_LOCKED_CONTAINER);
// here we use whether or not we've been bound to the server
// as the test for whether or not we're running (even though
// the server may have crashed since we last bound). We do
// this because DuSetClientSite will Unlock the old container
// and lock the new if we're running. Thus, if we've ever been
// running, we need to unlock the old container (even though
// we may not currently be running).
hresult = DuSetClientSite( m_pUnkDelegate ? TRUE : FALSE, pClientSite, &m_pAppClientSite, &fLockedContainer);
if(fLockedContainer) { m_flags |= DL_LOCKED_CONTAINER; } else { m_flags &= ~(DL_LOCKED_CONTAINER); } }
LEDebugOut((DEB_TRACE, "%p OUT CDefLink::SetClientSite" " ( %lx )\n", this, hresult));
return hresult; }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::GetClientSite
//
// Synopsis: Retrieves the stored client site pointer
//
// Effects:
//
// Arguments: [ppClientSite] -- where to put the client site pointer
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation: IOleObject
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 03-Aug-94 alexgo stabilized
// 22-Nov-93 alexgo inlined DuGetClientSite
// 18-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
STDMETHODIMP CDefLink::GetClientSite( IOleClientSite **ppClientSite ) { VDATEHEAP(); VDATETHREAD(this);
LEDebugOut((DEB_TRACE, "%p _IN CDefLink::GetClientSite ( %p )\n", this, ppClientSite));
VDATEPTROUT(ppClientSite, IOleClientSite *);
CRefStabilize stabilize(this);
*ppClientSite = m_pAppClientSite;
if( *ppClientSite ) { (*ppClientSite)->AddRef(); }
LEDebugOut((DEB_TRACE, "%p OUT CDefLink::GetClientSite" " ( %lx ) [ %p ] \n", this, NOERROR, *ppClientSite));
return NOERROR; }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::SetHostNames
//
// Synopsis: In principal, should set the names to be drawn for
// the server object. Not relevant for links (link servers
// are not a part of the document being edited).
//
// Effects:
//
// Arguments: [szContainerApp] -- the name of the container
// [szContainerObj] -- the container's name for the object
//
// Requires:
//
// Returns: HRESULT (NOERROR currently)
//
// Signals:
//
// Modifies:
//
// Derivation: IOleObject
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 18-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
STDMETHODIMP CDefLink::SetHostNames (LPCOLESTR szContainerApp, LPCOLESTR szContainerObj) { VDATEHEAP(); VDATETHREAD(this);
LEDebugOut((DEB_TRACE, "%p _IN CDefLink::SetHostNames" " ( %p , %p )\n", this, szContainerApp, szContainerObj));
LEDebugOut((DEB_TRACE, "%p OUT CDefLink::SetHostNames" " ( %lx )\n", this, NOERROR));
return NOERROR; // makes the embedded/link case more the same
}
//+-------------------------------------------------------------------------
//
// Member: CDefLink::Close
//
// Synopsis: Closes the object (in this case, just saves and unbinds the
// link)
//
// Effects:
//
// Arguments: [dwFlags] -- clising flags (such as SAVEIFDIRTY)
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation: IOleObject
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 03-Aug-94 alexgo stabilized
// 18-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
STDMETHODIMP CDefLink::Close( DWORD dwFlags ) { VDATEHEAP(); VDATETHREAD(this);
LEDebugOut((DEB_TRACE, "%p _IN CDefLink::Close " "( %lu )\n", this, dwFlags));
CRefStabilize stabilize(this);
if (dwFlags != OLECLOSE_NOSAVE) { AssertSz(dwFlags == OLECLOSE_SAVEIFDIRTY, "OLECLOSE_PROMPTSAVE is inappropriate\n"); if( IsDirty() == NOERROR ) { if( m_pAppClientSite ) { m_pAppClientSite->SaveObject(); } }
}
// just unbind.
UnbindSource();
LEDebugOut((DEB_TRACE, "%p OUT CDefLink::Close " "( %lx )\n", this, NOERROR));
return NOERROR; }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::SetMoniker
//
// Synopsis: Sets the moniker to the link object
//
// Effects:
//
// Arguments: [dwWhichMoniker] -- which moniker
// [pmk] -- the new moniker
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation: IOleObject
//
// Algorithm: calls utility method UpdateRelMkFromAbsMk
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 03-Aug-94 alexgo stabilized
// 18-Nov-93 alexgo 32bit port
//
// Notes:
//
// The moniker of the container is changing.
// The next time we bind, we will try using the container moniker
// composed with the relative moniker, and then, if that fails,
// the absolute moniker, so there is no real need for us to
// change these monikers.
//
// However, there are two cases when we know the absolute moniker
// is the correct one, and we can take this opportunity to
// recompute the relative moniker (which is changing because
// the container moniker is changing). The advantage of this is
// that GetDisplayName can return a better result in the interim
//
//--------------------------------------------------------------------------
STDMETHODIMP CDefLink::SetMoniker( DWORD dwWhichMoniker, LPMONIKER pmk ) { HRESULT hresult = NOERROR;
VDATEHEAP(); VDATETHREAD(this);
LEDebugOut((DEB_TRACE, "%p _IN CDefLink::SetMoniker " "( %lx , %p )\n", this, dwWhichMoniker, pmk));
CRefStabilize stabilize(this);
if( IsZombie() ) { hresult = CO_E_RELEASED; } else if (dwWhichMoniker == OLEWHICHMK_CONTAINER || dwWhichMoniker == OLEWHICHMK_OBJFULL) { if( m_pMonikerRel == NULL || m_pUnkDelegate) { UpdateRelMkFromAbsMk(pmk); } }
LEDebugOut((DEB_TRACE, "%p OUT CDefLink::SetMoniker" " ( %lx )\n", this, hresult));
return hresult; }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::GetMoniker
//
// Synopsis: Retrieves the moniker for the object
//
// Effects:
//
// Arguments: [dwAssign] -- flags (such as wether a moniker should
// be assigned to the object if none currently
// exits)
// [dwWhichMoniker]-- which moniker to get (relative/absolute/etc)
// [ppmk] -- where to put a pointer to the moniker
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation: IOleObject
//
// Algorithm: asks the client site for the moniker
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 03-Aug-94 alexgo stabilized
// 18-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
STDMETHODIMP CDefLink::GetMoniker( DWORD dwAssign, DWORD dwWhichMoniker, LPMONIKER *ppmk) { HRESULT hresult;
VDATEHEAP(); VDATETHREAD(this);
LEDebugOut((DEB_TRACE, "%p _IN CDefLink::GetMoniker " "( %lx , %lx , %p )\n", this, dwAssign, dwWhichMoniker, ppmk));
CRefStabilize stabilize(this);
if( m_pAppClientSite ) { hresult = m_pAppClientSite->GetMoniker(dwAssign, dwWhichMoniker, ppmk); } else { // no client site
*ppmk = NULL; hresult = E_UNSPEC; }
LEDebugOut((DEB_TRACE, "%p OUT CDefLink::GetMoniker " "( %lx ) [ %p ]\n", this, hresult, *ppmk ));
return hresult; }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::InitFromData
//
// Synopsis: Initializes the object from the given data
//
// Effects:
//
// Arguments: [pDataObject] -- the data object to initialize from
// [fCreation] -- TRUE indicates the object is being
// created, FALSE a data transfer
// [dwReserved] -- unused
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation: IOleObject
//
// Algorithm: Delegates to the server
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 03-Aug-94 alexgo stabilized
// 18-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
STDMETHODIMP CDefLink::InitFromData( LPDATAOBJECT pDataObject, BOOL fCreation, DWORD dwReserved) { HRESULT hresult; VDATEHEAP(); VDATETHREAD(this);
LEDebugOut((DEB_TRACE, "%p _IN CDefLink::InitFromData " "( %p , %lu , %lx )\n", this, pDataObject, fCreation, dwReserved));
CRefStabilize stabilize(this);
if( GetOleDelegate() ) { hresult = m_pOleDelegate->InitFromData(pDataObject, fCreation, dwReserved); } else { hresult = OLE_E_NOTRUNNING; }
LEDebugOut((DEB_TRACE, "%p OUT CDefLink::InitFromData " "( %lx )\n", this, hresult));
return hresult; }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::GetClipboardData
//
// Synopsis: Retrieves a data object that could be put on the clipboard
//
// Effects:
//
// Arguments: [dwReserved] -- unused
// [ppDataObject] -- where to put the pointer to the data
// object
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation: IOleObject
//
// Algorithm: Delegates to the server object
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 03-Aug-94 alexgo stabilized
// 18-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
STDMETHODIMP CDefLink::GetClipboardData( DWORD dwReserved, LPDATAOBJECT *ppDataObject) { HRESULT hresult; VDATEHEAP(); VDATETHREAD(this);
LEDebugOut((DEB_TRACE, "%p _IN CDefLink::GetClipboard" "Data ( %lx , %p )\n", this, dwReserved, ppDataObject));
CRefStabilize stabilize(this);
if ( GetOleDelegate() ) { hresult = m_pOleDelegate->GetClipboardData (dwReserved, ppDataObject); } else { hresult = OLE_E_NOTRUNNING; }
LEDebugOut((DEB_TRACE, "%p OUT CDefLink::GetClipboard" "Data ( %lx ) [ %p ]\n", this, hresult, *ppDataObject));
return hresult; }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::DoVerb
//
// Synopsis: Sends a verb to the object (such as Open)
//
// Effects:
//
// Arguments: [iVerb] -- the verb
// [lpmsg] -- the window's message that caused the verb
// [pActiveSite] -- the site where the object was activated
// [lindex] -- unused currently
// [hwndParent] -- the parent window of the container
// [lprcPosRect] -- the rectange bounding the object
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation: IOleObject
//
// Algorithm: Binds to the server and then delegates the DoVerb call
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 03-Aug-94 alexgo stabilized
// 18-Nov-93 alexgo 32bit port
//
// Notes: If we had bound to the server and it crashed, we pretend it
// was still running anyway for DoVerb (our call to BindToSource
// will re-run it). Essentially, this algorithm "fixes" the
// crash and restores the link's state.
//
//--------------------------------------------------------------------------
STDMETHODIMP CDefLink::DoVerb (LONG iVerb, LPMSG lpmsg, LPOLECLIENTSITE pActiveSite, LONG lindex, HWND hwndParent, LPCRECT lprcPosRect) { HRESULT hresult; BOOL bStartedNow = !m_pUnkDelegate;
VDATEHEAP(); VDATETHREAD(this);
LEDebugOut((DEB_TRACE, "%p _IN CDefLink::DoVerb " "( %ld , %ld , %p , %ld , %lx , %p )\n", this, iVerb, lpmsg, pActiveSite, lindex, hwndParent, lprcPosRect));
if( lpmsg ) { VDATEPTRIN( lpmsg, MSG ); }
if( pActiveSite ) { VDATEIFACE( pActiveSite ); }
if( lprcPosRect ) { VDATEPTRIN(lprcPosRect, RECT); }
CRefStabilize stabilize(this);
if( lindex != 0 && lindex != -1 ) { hresult = DV_E_LINDEX; goto errRtn; }
// if we had crashed, BindToSource will reconnect us
if ( FAILED(hresult = BindToSource(0, NULL)) ) { goto errRtn; }
// we don't propogate hide to server; this (and other behavior)
// favors the link object as serving an OLE container rather than
// a general programmability client. This leave the link running,
// possibly invisible.
if (iVerb == OLEIVERB_HIDE) { hresult = NOERROR; goto errRtn; }
if( GetOleDelegate() ) { hresult = m_pOleDelegate->DoVerb(iVerb, lpmsg, pActiveSite, lindex, hwndParent, lprcPosRect); } else { hresult = E_NOINTERFACE; }
if (bStartedNow && FAILED(hresult)) { UnbindSource(); }
errRtn:
LEDebugOut((DEB_TRACE, "%p OUT CDefLink::DoVerb " "( %lx )\n", this, hresult));
return hresult; }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::EnumVerbs
//
// Synopsis: Enumerate the verbs accepted by this object
//
// Effects:
//
// Arguments: [ppenumOleVerb] -- where to put the pointer to the enumerator
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation: IOleObject
//
// Algorithm: askes the server delegate. If not there or it returns
// OLE_E_USEREG, then we get the info from the registration
// database
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 03-Aug-94 alexgo stabilized
// 30-May-94 alexgo now handles crashed servers
// 18-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
STDMETHODIMP CDefLink::EnumVerbs( IEnumOLEVERB **ppenumOleVerb ) { HRESULT hresult;
VDATEHEAP(); VDATETHREAD(this);
LEDebugOut((DEB_TRACE, "%p _IN CDefLink::EnumVerbs " "( %p )\n", this, ppenumOleVerb));
CRefStabilize stabilize(this);
if( GetOleDelegate() ) { hresult = m_pOleDelegate->EnumVerbs(ppenumOleVerb);
if( !GET_FROM_REGDB(hresult) ) { if( SUCCEEDED(hresult) || IsReallyRunning() ) { // if we failed, but the server is still
// running, then go ahead and propogate the
// error to the caller.
// Note that IsReallyRunning will clean up our
// state if the server had crashed.
goto errRtn; } // FALL-THROUGH!! This is deliberate. If
// the call failed and the server is no longer
// running, then we assume the server has crashed.
// We want to go ahead and fetch the information
// from the registry.
} }
// Not running or object wants to use reg db anyway
hresult = OleRegEnumVerbs(m_clsid, ppenumOleVerb);
errRtn:
LEDebugOut((DEB_TRACE, "%p OUT CDefLink::EnumVerbs " "( %lx ) [ %p ]\n", this, hresult, *ppenumOleVerb));
return hresult; }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::GetUserClassID
//
// Synopsis: Retrieves the class id of the linked object
//
// Effects:
//
// Arguments: [pClassID] -- where to put the class ID
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation: IOleObject
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 18-Nov-93 alexgo 32bit port
//
// Notes: No need to stabilize as we make no outgoing calls
//
//--------------------------------------------------------------------------
STDMETHODIMP CDefLink::GetUserClassID(CLSID *pClassID) { VDATEHEAP(); VDATETHREAD(this);
LEDebugOut((DEB_TRACE, "%p _IN CDefLink::GetUserClass" "ID ( %p )\n", this, pClassID));
VDATEPTROUT(pClassID, CLSID);
*pClassID = m_clsid;
LEDebugOut((DEB_TRACE, "%p OUT CDefLink::GetUserClass" "ID ( %lx )\n", this, NOERROR ));
return NOERROR; }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::GetUserType
//
// Synopsis: Retrieves a descriptive string about the server type
//
// Effects:
//
// Arguments: [dwFormOfType] -- indicates whether a short or long string
// description is desired
// [pszUserType] -- where to put the string
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation: IOleObject
//
// Algorithm: Asks the server delegate, if that fails or the server
// returns OLE_E_USEREG, then get the info from the registration
// database
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 03-Aug-94 alexgo stabilized
// 30-May-94 alexgo now handles crashed servers
// 18-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
STDMETHODIMP CDefLink::GetUserType(DWORD dwFormOfType, LPOLESTR *ppszUserType) { HRESULT hresult;
VDATEHEAP(); VDATETHREAD(this);
LEDebugOut((DEB_TRACE, "%p _IN CDefLink::GetUserType " "( %lu , %p )\n", this, dwFormOfType, ppszUserType));
VDATEPTROUT(ppszUserType, LPOLESTR); *ppszUserType = NULL;
CRefStabilize stabilize(this);
if( GetOleDelegate() ) { hresult = m_pOleDelegate->GetUserType (dwFormOfType, ppszUserType);
if( !GET_FROM_REGDB(hresult) ) { if( SUCCEEDED(hresult) || IsReallyRunning() ) { // if we failed, but the server is still
// running, then go ahead and propogate the
// error to the caller.
// Note that IsReallyRunning will clean up our
// state if the server had crashed.
goto errRtn; } // FALL-THROUGH!! This is deliberate. If
// the call failed and the server is no longer
// running, then we assume the server has crashed.
// We want to go ahead and fetch the information
// from the registry.
} }
// Not running, or object wants to use reg db anyway
// Consult reg db
hresult = OleRegGetUserType(m_clsid, dwFormOfType, ppszUserType);
// it is not appropriate to read from the stg since the storage is
// owned by the link, not the link source (thus, the link source
// never has the opportunity to call WriteFmtUserTypeStg on the
// link object's storage).
// We also do not need to bother storing the last known user
// type because if we can get it for one particular clsid, we
// should always be able to get it. If we can't get the user type,
// then either we have never gotten a user type (and thus don't
// have a "last known") or we've changed clsid's (in which case,
// the last known user type would be wrong).
errRtn:
LEDebugOut((DEB_TRACE, "%p OUT CDefLink::GetUserType " "( %lx ) [ %p ]\n", this, hresult, *ppszUserType));
return hresult; }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::Update
//
// Synopsis: Updates the link (by calling IOleLink->Update)
//
// Effects:
//
// Arguments: void
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation: IOleObject
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 03-Aug-94 alexgo stabilized
// 18-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
STDMETHODIMP CDefLink::Update(void) { HRESULT hresult;
VDATEHEAP(); VDATETHREAD(this);
LEDebugOut((DEB_TRACE, "%p _IN CDefLink::Update ( )\n", this ));
CRefStabilize stabilize(this);
hresult = Update(NULL);
LEDebugOut((DEB_TRACE, "%p OUT CDefLink::Update ( " "%lx )\n", this, hresult));
return hresult; }
//fudge value
#define TwoSeconds 0x01312D00
//+-------------------------------------------------------------------------
//
// Member: CDefLink::IsUpToDate
//
// Synopsis: Determines whether or not a link is up-to-date
//
// Effects:
//
// Arguments: void
//
// Requires:
//
// Returns: HRESULT -- NOERROR == IsUpToDate, S_FALSE == out of date
//
// Signals:
//
// Modifies:
//
// Derivation: IOleObject
//
// Algorithm: The current time is compared with the last time known
// up-to-date on *both* machines (the process of the container
// and the process of the link). These time differences are
// compared to determine whether the link is out-of-date.
// See the UpdateTimes method.
//
// History: dd-mmm-yy Author Comment
// 09-Jan-95 alexgo correctly answer IsUpToDate now; also
// fixup monikers if needed.
// 21-Nov-94 alexgo memory optimization
// 03-Aug-94 alexgo stabilized
// 19-Nov-93 alexgo 32bit port
//
// Notes: The arithmetic calculations in this method assume
// two's complement arithmetic and a high order sign bit
// (true for most current machines)
//
//--------------------------------------------------------------------------
STDMETHODIMP CDefLink::IsUpToDate(void) { FILETIME rtTimeOfLastChange; LPMONIKER pmkAbs = NULL; IMoniker * pmkContainer = NULL; HRESULT hresult = NOERROR; LPBINDCTX pbc = NULL; FILETIME rtDiff; FILETIME ltDiff; FILETIME ftTemp; FILETIME ftNow; BOOL fHighBitSet;
VDATEHEAP(); VDATETHREAD(this);
LEDebugOut((DEB_TRACE, "%p _IN CDefLink::IsUpToDate " "( )\n", this ));
CRefStabilize stabilize(this);
if (m_dwUpdateOpt == OLEUPDATE_ALWAYS && IsRunning()) { // hresult == NOERROR from default initializer
goto errRet; }
// use the relative moniker if it exists and if the container
// has a moniker
if (NOERROR != GetAbsMkFromRel(&pmkAbs, &pmkContainer)) { // otherwise use the absolute moniker
if (pmkAbs = m_pMonikerAbs) { pmkAbs->AddRef(); } }
if (pmkAbs == NULL) { hresult = MK_E_UNAVAILABLE; goto errRet; }
hresult = CreateBindCtx( 0, &pbc ); if (hresult != NOERROR) { goto errRet; }
//get the remote time of last change
hresult = pmkAbs->GetTimeOfLastChange(pbc, NULL, &rtTimeOfLastChange); if (hresult != NOERROR) { // if GetTimeOfLastChange failed, it's possible that the moniker
// we constructed is bogus. Try again using the *real* absolute
// moniker. We do this to mimic bind behaviour. The moniker
// we use above is constructed from the relative moniker. In binding,
// if the relative moniker fails, then we fall back to the last
// known real absolute moniker.
BOOL fSuccess = FALSE;
if( m_pMonikerAbs ) { if (pmkAbs != m_pMonikerAbs) { // do this if we did the bind on the relative one.above
hresult = m_pMonikerAbs->GetTimeOfLastChange(pbc, NULL, &rtTimeOfLastChange);
if( hresult == NOERROR ) { fSuccess = TRUE; // hang onto the better absolute moniker
pmkAbs->Release(); // releases the one we contructed
// in GetAbsMkFromRel
pmkAbs = m_pMonikerAbs; pmkAbs->AddRef(); // so the Release() down below
} // doesn't hose us.
}
#ifdef _TRACKLINK_
if (!fSuccess) { // at this point we have tried either: relative then absolute OR
// just absolute. We now should try the reduced absolute one.
IMoniker *pmkReduced; EnableTracking(m_pMonikerAbs, OT_ENABLEREDUCE); hresult = m_pMonikerAbs->Reduce(pbc, MKRREDUCE_ALL, NULL, &pmkReduced); EnableTracking(m_pMonikerAbs, OT_DISABLEREDUCE); if (hresult == NOERROR) { hresult = pmkReduced->GetTimeOfLastChange(pbc, NULL, &rtTimeOfLastChange); if (hresult != NOERROR) { pmkReduced->Release(); } else { fSuccess = TRUE; pmkAbs->Release(); pmkAbs = pmkReduced; } } } #endif
} if (!fSuccess) { hresult = MK_E_UNAVAILABLE; goto errRet; } }
// once we get this far, we know that either 1. the relative moniker
// is good, or 2. the absolute moniker is good. In any event, pmkAbs
// now points to a (semi)-reasonable spot. (I say 'semi', because
// even though GetTimeOfLastChange succeeded, we aren't guaranteed that
// a Bind would be successful.
//
// check to see if we need to update the relative moniker (if we don't
// already have one, don't bother.) It is also possible that the
// absolute moniker is now bad. Use the known 'good' one and update
// both monikers
// we ignore the return code here; if this call fails, it is not
// serious.
// pmkContainer may be NULL if our container doesn't offer us one.
if( pmkContainer ) { UpdateMksFromAbs(pmkContainer, pmkAbs);
pmkContainer->Release(); }
// compute rtDiff = max(0, rtTimeOfLastChange - rtUpdate)
// possibly optimize with _fmemcopy
// debugging aid
DumpSzTime("IsUpToDate: rtTimeOfLastChange = ", rtTimeOfLastChange);
// start rtDiff calculation
rtDiff = rtTimeOfLastChange;
// debugging aid
DumpSzTime("IsUpToDate: rtUpdate = ", m_rtUpdate);
// the following subtractions rely on two's complement
if (m_rtUpdate.dwLowDateTime > rtDiff.dwLowDateTime) { //handle the carry
rtDiff.dwHighDateTime = (DWORD)((LONG)rtDiff.dwHighDateTime - 1); }
rtDiff.dwLowDateTime = (DWORD)((LONG)rtDiff.dwLowDateTime - (LONG)m_rtUpdate.dwLowDateTime); rtDiff.dwHighDateTime = (DWORD)((LONG)rtDiff.dwHighDateTime - (LONG)m_rtUpdate.dwHighDateTime);
// if rtDiff < 0, say we are out of date.
if ((LONG)rtDiff.dwHighDateTime < 0) { hresult = S_FALSE; goto errRet; }
if (rtDiff.dwHighDateTime == 0 && rtDiff.dwLowDateTime == 0) { // no time difference. could be due to large clock ticks,
// so we say we are up to date only if several seconds have
// elapsed since last known update time.
CoFileTimeNow( &ftNow ); ftTemp = m_ltKnownUpToDate;
// This bit of logic may seem strange. All we want is
// is to test the high bit in a portable fashion
// between 32/64bit machines (so a constant isn't good)
// As long as the sign bit is the high order bit, then
// this trick will do
fHighBitSet = ((LONG)ftTemp.dwLowDateTime < 0);
ftTemp.dwLowDateTime += TwoSeconds;
// if the high bit was set, and now it's zero, then we
// had a carry
if (fHighBitSet && ((LONG)ftTemp.dwLowDateTime >= 0)) { ftTemp.dwHighDateTime++; // handle the carry.
}
// compare times
if ((ftNow.dwHighDateTime > ftTemp.dwHighDateTime) || ((ftNow.dwHighDateTime == ftTemp.dwHighDateTime) && (ftNow.dwLowDateTime > ftTemp.dwLowDateTime))) { hresult = NOERROR; } else { hresult = S_FALSE; } } else { // there was a time difference
// compute ltDiff = max(0, m_ltKnownUpToDate -
// m_ltChangeOfUpdate);
// Actually, by this time we know rtDiff >= 0, so we can
// simply compare ltDiff with rtDiff -- no need to compute
// the max.
ltDiff = m_ltKnownUpToDate;
// debugging aid
DumpSzTime("IsUpToDate: ltKnownUpToDate = ",ltDiff); DumpSzTime("IsUpToDate: ltChangeOfUpdate = ", m_ltChangeOfUpdate);
// these calc's rely on two's complement.
if (m_ltChangeOfUpdate.dwLowDateTime > ltDiff.dwLowDateTime) { // handle carry
ltDiff.dwHighDateTime = (DWORD)((LONG)ltDiff.dwHighDateTime - 1); }
ltDiff.dwLowDateTime = (DWORD)((LONG)ltDiff.dwLowDateTime - (LONG)m_ltChangeOfUpdate.dwLowDateTime); ltDiff.dwHighDateTime = (DWORD)((LONG)ltDiff.dwHighDateTime - (LONG)m_ltChangeOfUpdate.dwHighDateTime);
// Now determine if rtDiff < ltDiff
if (ltDiff.dwHighDateTime > rtDiff.dwHighDateTime) { hresult = NOERROR; } else if (ltDiff.dwHighDateTime == rtDiff.dwHighDateTime) { if (ltDiff.dwLowDateTime > rtDiff.dwLowDateTime) { hresult = NOERROR; } else { hresult = S_FALSE; } } else { hresult = S_FALSE; } }
// all cases should have been handled by this point. Release
// any resources grabbed.
errRet: if (pmkAbs) { pmkAbs->Release(); } if (pbc) { pbc->Release(); }
LEDebugOut((DEB_TRACE, "%p OUT CDefLink::IsUpToDate " "( %lx )\n", this, hresult));
return hresult; }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::SetExtent
//
// Synopsis: Sets the drawing extents, not allowed for links
//
// Effects:
//
// Arguments: [dwDrawAspect] -- the drawing aspect
// [lpsizel] -- the new extents
//
// Requires:
//
// Returns: E_UNSPEC (not allowed)
//
// Signals:
//
// Modifies:
//
// Derivation: IOleObject
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 19-Nov-93 alexgo 32 bit port
//
// Notes:
//
//--------------------------------------------------------------------------
STDMETHODIMP CDefLink::SetExtent(DWORD dwDrawAspect, LPSIZEL lpsizel) { VDATEHEAP(); VDATETHREAD(this);
LEDebugOut((DEB_TRACE, "%p _IN CDefLink::SetExtent " "( %lx , %p )\n", this, dwDrawAspect, lpsizel));
LEDebugOut((DEB_WARN, "Set Extent called for links, E_UNSPEC \n"));
LEDebugOut((DEB_TRACE, "%p OUT CDefLink::SetExtent " "( %lx )\n", this, E_UNSPEC));
return E_UNSPEC; // can't call this for a link
}
//+-------------------------------------------------------------------------
//
// Member: CDefLink::GetExtent
//
// Synopsis: Get's the size (extents) of the object
//
// Effects:
//
// Arguments: [dwDrawAspect] -- the drawing aspect
// [lpsizel] -- where to put the extents
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation: IOleObject
//
// Algorithm: Asks the server first, if not running or an error
// then delegate to the cache
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 03-Aug-94 alexgo stabilized
// 19-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
STDMETHODIMP CDefLink::GetExtent( DWORD dwDrawAspect, LPSIZEL lpsizel) { HRESULT error = E_FAIL;
VDATEHEAP(); VDATETHREAD(this);
LEDebugOut((DEB_TRACE, "%p _IN CDefLink::GetExtent " "( %lx , %p )\n", this, dwDrawAspect, lpsizel));
VDATEPTROUT(lpsizel, SIZEL);
CRefStabilize stabilize(this);
lpsizel->cx = 0; lpsizel->cy = 0;
// if server is running try to get extents from the server
if( GetOleDelegate() ) { error = m_pOleDelegate->GetExtent(dwDrawAspect, lpsizel); }
// if there is error or object is not running get extents from Cache
if( error != NOERROR ) { Assert(m_pCOleCache != NULL); error = m_pCOleCache->GetExtent(dwDrawAspect, lpsizel); }
// WordArt2.0 is giving negative extents!!
if (SUCCEEDED(error)) { lpsizel->cx = LONG_ABS(lpsizel->cx); lpsizel->cy = LONG_ABS(lpsizel->cy); }
LEDebugOut((DEB_TRACE, "%p OUT CDefLink::GetExtent " "( %lx )\n", this, error ));
return error; }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::Advise
//
// Synopsis: Sets up an advise connection to the object for things like
// Close, Save, etc.
//
// Effects:
//
// Arguments: [pAdvSink] -- whom to notify
// [pdwConnection] -- where to put the connection ID
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation: IOleObject
//
// Algorithm: Creates an OleAdvise holder (if one not already present
// and then delegates to it)
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 03-Aug-94 alexgo stabilized and handle zombie case
// 19-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
STDMETHODIMP CDefLink::Advise(IAdviseSink *pAdvSink, DWORD *pdwConnection) { HRESULT hresult; VDATEHEAP(); VDATETHREAD(this);
LEDebugOut((DEB_TRACE, "%p _IN CDefLink::Advise " "( %p , %p )\n", this, pAdvSink, pdwConnection));
CRefStabilize stabilize(this);
if( IsZombie() ) { hresult = CO_E_RELEASED; goto errRtn; }
// if we haven't got an advise holder yet, allocate one
if (m_pCOAHolder == NULL) { // allocate the advise holder
m_pCOAHolder = new FAR COAHolder;
// check to make sure we got one
if (m_pCOAHolder == NULL) { hresult = E_OUTOFMEMORY; goto errRtn; } }
// delegate the call to the advise holder
hresult = m_pCOAHolder->Advise(pAdvSink, pdwConnection);
errRtn: LEDebugOut((DEB_TRACE, "%p OUT CDefLink::Advise " "( %lx ) [ %lu ]\n", this, hresult, (pdwConnection) ? *pdwConnection : 0 ));
return hresult; }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::Unadvise
//
// Synopsis: Removes an advise connection to the object
//
// Effects:
//
// Arguments: [dwConnection] -- the connection ID to remove
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation: IOleObject
//
// Algorithm: Delegates to the OleAdvise holder (which was created
// during the Advise--if it wasn't, then we are in a strange
// state).
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 03-Aug-94 alexgo stabilized
// 19-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
STDMETHODIMP CDefLink::Unadvise(DWORD dwConnection) { HRESULT hresult;
VDATEHEAP(); VDATETHREAD(this);
LEDebugOut((DEB_TRACE, "%p _IN CDefLink::Unadvise " "( %lu )\n", this, dwConnection ));
CRefStabilize stabilize(this);
if (m_pCOAHolder == NULL) { // no one registered
hresult = E_UNEXPECTED; } else { hresult = m_pCOAHolder->Unadvise(dwConnection); }
LEDebugOut((DEB_TRACE, "%p OUT CDefLink::Unadvise " "( %lx )\n", this, hresult ));
return hresult; }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::EnumAdvise
//
// Synopsis: Enumerates the advise connections on the object
//
// Effects:
//
// Arguments: [ppenumAdvise] -- where to put the pointer to the advise
// enumerator
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation: IOleObject
//
// Algorithm: Delegates to the advise holder
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 19-Nov-93 alexgo 32bit port
//
// Notes: We do not need to stabilize this method as we only allocate
// memory for hte advise enumerator
//
//--------------------------------------------------------------------------
STDMETHODIMP CDefLink::EnumAdvise( LPENUMSTATDATA *ppenumAdvise ) { HRESULT hresult;
VDATEHEAP(); VDATETHREAD(this);
LEDebugOut((DEB_TRACE, "%p _IN CDefLink::EnumAdvise " "( %p )\n", this, ppenumAdvise ));
if (m_pCOAHolder == NULL) { // no one registered
hresult = E_UNSPEC; } else { hresult = m_pCOAHolder->EnumAdvise(ppenumAdvise); }
LEDebugOut((DEB_TRACE, "%p OUT CDefLink::EnumAdvise " "( %lx ) [ %p ]\n", this, hresult, *ppenumAdvise ));
return hresult; }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::GetMiscStatus
//
// Synopsis: Gets the miscellaneous status bits (such as
// OLEMISC_ONLYICONIC)
//
// Effects:
//
// Arguments: [dwAspect] -- the drawing aspect
// [pdwStatus] -- where to put the status bits
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation: IOleObject
//
// Algorithm: Asks the server first, if not running or if it returns
// OLE_E_USEREG, then get the info from the registration
// database. We always add link-specific bits regardless
// of error conditions or what the server or regdb says.
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 03-Aug-94 alexgo stabilized
// 30-May-94 alexgo now handles crashed servers
// 19-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
STDMETHODIMP CDefLink::GetMiscStatus( DWORD dwAspect, DWORD *pdwStatus) { LEDebugOut((DEB_TRACE, "%p _IN CDefLink::GetMiscStatus(%lx, %p)\n", this, dwAspect, pdwStatus ));
// Validation checks
VDATEHEAP(); VDATETHREAD(this); VDATEPTROUT(pdwStatus, DWORD);
// Local variables
HRESULT hresult;
// Stabilize
CRefStabilize stabilize(this);
// Initialize
*pdwStatus = 0; hresult = OLE_S_USEREG;
if(GetOleDelegate()) { // Check if MiscStatus bits have been cached for this instance
// of server for DVASPECT_CONTENT
if(m_ContentSRVMSHResult != 0xFFFFFFFF && dwAspect == DVASPECT_CONTENT) { *pdwStatus = m_ContentSRVMSBits; hresult = m_ContentSRVMSHResult; } else { // Ask the running server
hresult = m_pOleDelegate->GetMiscStatus (dwAspect, pdwStatus);
// Cache the server MiscStatus bits for DVASPECT_CONTENT
if(dwAspect == DVASPECT_CONTENT) { m_ContentSRVMSBits = *pdwStatus; m_ContentSRVMSHResult = hresult; } }
if(FAILED(hresult) && !GET_FROM_REGDB(hresult)) { // Check if server is really running
BOOL fRunning = FALSE;
// Note that IsReallyRunning will cleanup if the
// server had crashed
fRunning = IsReallyRunning(); Win4Assert(fRunning); // Hit the registry if the server crashed
if(!fRunning) hresult = OLE_S_USEREG; } }
// Check if we have to obtain MiscStatus bits from the registry
if (GET_FROM_REGDB(hresult)) { // Check if registry MiscStatus bits have been cached for DVASPECT_CONTENT
if(m_ContentREGMSHResult != 0xFFFFFFFF && dwAspect == DVASPECT_CONTENT) { *pdwStatus = m_ContentREGMSBits; hresult = m_ContentREGMSHResult; } else { // Hit the registry
hresult = OleRegGetMiscStatus (m_clsid, dwAspect, pdwStatus); // Cache the registry MiscStatus bits for DVASPECT_CONTENT
if(hresult == NOERROR && dwAspect == DVASPECT_CONTENT) { m_ContentREGMSBits = *pdwStatus; m_ContentREGMSHResult = hresult; } } }
// Add link-specific bits (even if error) and return.
// we add them even if an error because in order to get here, we
// have to have instantiated this link object; thus, it is always
// valid to say OLEMISC_ISLINKOBJECT, etc.
(*pdwStatus) |= OLEMISC_CANTLINKINSIDE | OLEMISC_ISLINKOBJECT;
LEDebugOut((DEB_TRACE, "%p OUT CDefLink::GetMiscStatus (%lx)[%lx]\n", this, hresult, *pdwStatus )); return hresult; }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::SetColorScheme
//
// Synopsis: Sets the palette for the object; unused for links
//
// Effects:
//
// Arguments: [lpLogpal] -- the palette
//
// Requires:
//
// Returns: NOERROR
//
// Signals:
//
// Modifies:
//
// Derivation: IOleObject
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 19-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
STDMETHODIMP CDefLink::SetColorScheme(LPLOGPALETTE lpLogpal) { VDATEHEAP(); VDATETHREAD(this); // we ignore this always
LEDebugOut((DEB_TRACE, "%p _IN CDefLink::SetColor" "Scheme ( %p )\n", this, lpLogpal));
LEDebugOut((DEB_WARN, "Link IOO:SetColorScheme called on a link\n"));
LEDebugOut((DEB_TRACE, "%p OUT CDefLink::SetColor" "Scheme ( %lx )\n", this, NOERROR));
return NOERROR; }
/*
* IMPLEMENTATION of CLinkImpl methods * */
//+-------------------------------------------------------------------------
//
// Member: CDefLink::BeginUpdates
//
// Synopsis: Private method to update the caches and then set the update
// times
//
// Effects:
//
// Arguments: void
//
// Requires:
//
// Returns: void
//
// Signals:
//
// Modifies:
//
// Derivation:
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 19-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
INTERNAL_(void) CDefLink::BeginUpdates(void) { VDATEHEAP();
LEDebugOut((DEB_ITRACE, "%p _IN CDefLink::BeginUpdates ( )\n", this));
IDataObject FAR* pDataDelegate;
if( pDataDelegate = GetDataDelegate() ) { // inform cache that we are running
Assert(m_pCOleCache != NULL); m_pCOleCache->OnRun(pDataDelegate);
// update only the automatic local caches from the newly
// running src
m_pCOleCache->UpdateCache(pDataDelegate, UPDFCACHE_NORMALCACHE, NULL);
// we are an automatic link which is now up to date
SetUpdateTimes(); }
LEDebugOut((DEB_ITRACE, "%p OUT CDefLink::BeginUpdates ( )\n", this ));
}
//+-------------------------------------------------------------------------
//
// Member: CDefLink::EndUpdates
//
// Synopsis: Calls OnStop on the cache
//
// Effects:
//
// Arguments: void
//
// Requires:
//
// Returns: void
//
// Signals:
//
// Modifies:
//
// Derivation:
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 19-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
INTERNAL_(void) CDefLink::EndUpdates(void) { VDATEHEAP();
LEDebugOut((DEB_ITRACE, "%p _IN CDefLink::EndUpdates ( )\n", this));
Assert(m_pCOleCache != NULL); m_pCOleCache->OnStop();
LEDebugOut((DEB_ITRACE, "%p OUT CDefLink::EndUpdates ( )\n", this)); }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::UpdateAutoOnSave
//
// Synopsis: Updates caches that have been set with ADVFCACHE_ONSAVE
// and sets the update times. Private method
//
// Effects:
//
// Arguments: void
//
// Requires:
//
// Returns: void
//
// Signals:
//
// Modifies:
//
// Derivation:
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 19-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
INTERNAL_(void) CDefLink::UpdateAutoOnSave(void) { VDATEHEAP();
LEDebugOut((DEB_ITRACE, "%p _IN CDefLink::UpdateAutoOnSave ( )\n", this));
// if m_pUnkDelegate is non-NULL, assume we are running
// (we only want to take the hit of the rpc-call IsRunning
// on external entry points.
if (m_pUnkDelegate && m_dwUpdateOpt == OLEUPDATE_ALWAYS) { // update any cache which has ADVFCACHE_ONSAVE
Assert(m_pCOleCache != NULL);
//REVIEW32: I think SetUpdateTimes ought to be called
//*after* the cache has been updated (that's what
//BeginUpdates does as well)
SetUpdateTimes(); m_pCOleCache->UpdateCache(GetDataDelegate(), UPDFCACHE_IFBLANKORONSAVECACHE, NULL); }
LEDebugOut((DEB_ITRACE, "%p OUT CDefLink::UpdateAutoOnSaves ( )\n", this));
}
//+-------------------------------------------------------------------------
//
// Member: CDefLink::UpdateRelMkFromAbsMk (private)
//
// Synopsis: Creates a new relative moniker from the absolute moniker
//
// Effects:
//
// Arguments: [pmkContainer] -- the moniker to the container (may be NULL)
//
// Requires:
//
// Returns: void
//
// Signals:
//
// Modifies:
//
// Derivation:
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 03-Feb-94 alexgo check for NULL before SendOnLinkSrcChange
// 19-Nov-93 alexgo 32bit port
//
// Notes:
//
// update relative moniker from abs; always release relative moniker;
// may leave relative moniker NULL; doesn't return an error (because
// no caller wanted it); dirties the link when we get rid of an
// existing relative moniker or get a new one.
//
//--------------------------------------------------------------------------
INTERNAL_(void) CDefLink::UpdateRelMkFromAbsMk(IMoniker *pmkContainer) { LPMONIKER pmkTemp = NULL; BOOL fNeedToAdvise = FALSE; HRESULT hresult;
VDATEHEAP();
LEDebugOut((DEB_ITRACE, "%p _IN CDefLink::UpdateRelMkFromAbsMk ( %p )\n", this, pmkContainer ));
if (m_pMonikerRel) { m_pMonikerRel->Release(); m_pMonikerRel = NULL;
m_flags |= DL_DIRTY_LINK; // got rid on an existing moniker, now dirty
fNeedToAdvise = TRUE; }
// NOTE: m_pMonikerRel is now NULL and only set when if we get a
// new one
if (m_pMonikerAbs == NULL) { // no abs mk thus no relative one
goto errRtn; }
if (pmkContainer) { pmkTemp = pmkContainer; } else { hresult = GetMoniker( OLEGETMONIKER_ONLYIFTHERE, // it will be
OLEWHICHMK_CONTAINER, &pmkTemp );
AssertOutPtrIface(hresult, pmkTemp); if (hresult != NOERROR) { // no container moniker, thus no relative one to it
goto errRtn; }
Assert(pmkTemp != NULL); }
hresult = pmkTemp->RelativePathTo(m_pMonikerAbs, &m_pMonikerRel); AssertOutPtrIface(hresult, m_pMonikerRel);
if (hresult != NOERROR) { // no relationship between container and absolute, thus no
// relative
if (m_pMonikerRel) { m_pMonikerRel->Release(); m_pMonikerRel = NULL; } }
if (pmkContainer == NULL) { // new moniker was allocated and needs to be released
pmkTemp->Release(); }
if (m_pMonikerRel != NULL) { m_flags |= DL_DIRTY_LINK; // have new relative moniker; dirty
fNeedToAdvise = TRUE; }
// if there's an advise holder and we need to advise, send out
// the change notification.
if (fNeedToAdvise && m_pCOAHolder) { m_pCOAHolder->SendOnLinkSrcChange(m_pMonikerAbs); }
errRtn:
LEDebugOut((DEB_ITRACE, "%p OUT CDefLink::UpdateRelMkFromAbsMk ( %p )\n", this, pmkContainer )); }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::UpdateMksFromAbs
//
// Synopsis: make a reasonable attempt to get valid rel && absolute
// monikers
//
// Effects:
//
// Arguments: [pmkContainer] -- the moniker to the container
// [pmkAbs] -- 'good' absolute moniker
//
// Requires:
//
// Returns: S_OK
//
// Signals:
//
// Modifies:
//
// Derivation:
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 09-Jan-95 alexgo author
//
// Notes: This function should only be used when we aren't 100% sure
// of the validity of the moniker (i.e. after an IMoniker::
// TimeOfLastChange call). We do not do any error
// recovery. Basically, the idea is 'try' to put us in a
// more consistent state, but it that fails, it's OK (because
// we'd basically have OLE 16bit behaviour).
//
//--------------------------------------------------------------------------
INTERNAL CDefLink::UpdateMksFromAbs( IMoniker *pmkContainer, IMoniker *pmkAbs ) { HRESULT hresult; IMoniker *pmktempRel; BOOL fNeedToUpdate = FALSE;
VDATEHEAP();
LEDebugOut((DEB_ITRACE, "%p _IN CDefLink::UpdateMksFromAbs ( %p , %p )\n", this, pmkContainer, pmkAbs));
// try updating the relative moniker (if one exists). Basically, we
// see if the relative moniker between pmkContainer and pmkAbs is
// any different than the moniker we currently have.
if( m_pMonikerRel ) { hresult = pmkContainer->RelativePathTo(pmkAbs, &pmktempRel);
if( hresult == NOERROR ) { if( pmktempRel->IsEqual(m_pMonikerRel) == S_FALSE ) { // need to update the relative moniker.
m_pMonikerRel->Release(); m_pMonikerRel = pmktempRel; m_pMonikerRel->AddRef();
// updated relative moniker, now dirty
m_flags |= DL_DIRTY_LINK; fNeedToUpdate = TRUE; } } }
// it is also possible that the absolute moniker is now bad. Use the
// known 'good' one.
if( m_pMonikerAbs && m_pMonikerAbs->IsEqual(pmkAbs) == S_FALSE ) { m_pMonikerAbs->Release(); m_pMonikerAbs = pmkAbs; m_pMonikerAbs->AddRef();
#ifdef _TRACKLINK_
EnableTracking(m_pMonikerAbs, OT_READTRACKINGINFO); #endif
m_flags |= DL_DIRTY_LINK;
fNeedToUpdate = TRUE; }
// send out an advise to any interested parties if we changed our
// monikers. Note that we do this even if just the relative moniker
// changed because the moniker we give apps via GetSourceMoniker is
// computed from the relative.
if( fNeedToUpdate && m_pCOAHolder ) { m_pCOAHolder->SendOnLinkSrcChange(m_pMonikerAbs); }
hresult = NOERROR;
LEDebugOut((DEB_ITRACE, "%p OUT CDefLink::UpdateMksFromAbs ( %lx )\n", this, hresult));
return hresult; }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::GetAbsMkFromRel (private)
//
// Synopsis: Gets the absolute moniker from the relative moniker
// stored in the link
//
// Effects:
//
// Arguments: [ppmkAbs] -- where to put the pointer to the moniker
// [ppmkCont] -- where to put the container moniker
// (may be NULL)
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation:
//
// Algorithm: calls IMoniker->ComposeWith on the moniker to the container
//
// History: dd-mmm-yy Author Comment
// 09-Jan-95 alexgo added ppmkCont parameter
// 21-Nov-94 alexgo memory optimization
// 19-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
INTERNAL CDefLink::GetAbsMkFromRel(IMoniker **ppmkAbs, IMoniker **ppmkCont ) { LPMONIKER pmkContainer = NULL; HRESULT hresult;
VDATEHEAP(); VDATETHREAD(this);
LEDebugOut((DEB_ITRACE, "%p _IN CDefLink::GetAbsMkFromRel ( %p , %p )\n", this, ppmkAbs, ppmkCont));
*ppmkAbs = NULL; if (m_pMonikerRel == NULL) { hresult = E_FAIL; goto errRtn; }
hresult = GetMoniker( OLEGETMONIKER_ONLYIFTHERE, OLEWHICHMK_CONTAINER, &pmkContainer ); AssertOutPtrIface(hresult, pmkContainer); if (hresult != NOERROR) { goto errRtn; }
Assert(pmkContainer != NULL);
hresult = pmkContainer->ComposeWith( m_pMonikerRel, FALSE, ppmkAbs );
if (pmkContainer) { if( ppmkCont ) { *ppmkCont = pmkContainer; // no need to AddRef, just implicitly
// transfer ownership from pmkContainer
} else { pmkContainer->Release(); } }
errRtn:
LEDebugOut((DEB_ITRACE, "%p OUT CDefLink::GetAbsMkFromRel ( %lx ) " "[ %p ]\n", this, hresult, *ppmkAbs));
return hresult; }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::SetUpdateOptions
//
// Synopsis: Sets the update options for the link (such as always or
// manual)
//
// Effects:
//
// Arguments: [dwUpdateOpt] -- update options
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation: IOleLink
//
// Algorithm: If UPDATE_ALWAYS, then update the caches, otherwise
// call OnStop (via EndUpdates)
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 03-Aug-94 alexgo stabilized and handle zombie case
// 19-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
STDMETHODIMP CDefLink::SetUpdateOptions(DWORD dwUpdateOpt) { HRESULT hresult;
VDATEHEAP(); VDATETHREAD(this);
LEDebugOut((DEB_TRACE, "%p _IN CDefLink::SetUpdateOptions " "( %lx )\n", this, dwUpdateOpt));
CRefStabilize stabilize(this);
if( IsZombie() ) { hresult = CO_E_RELEASED; goto errRtn; }
switch (dwUpdateOpt) { case OLEUPDATE_ALWAYS: // make sure we are connected if running
BindIfRunning();
// if we've already are in UPDATE_ALWAYS mode,
// we don't need to reenter
if (m_pUnkDelegate && m_dwUpdateOpt != OLEUPDATE_ALWAYS) { BeginUpdates(); } break;
case OLEUPDATE_ONCALL: // if we aren't already in UPDATE_ONCALL mode, then
// enter it.
if (m_dwUpdateOpt != OLEUPDATE_ONCALL) { // inform cache that we are not running
// (even if not running)
EndUpdates(); } break; default: hresult = E_INVALIDARG; goto errRtn; }
m_dwUpdateOpt = dwUpdateOpt;
m_flags |= DL_DIRTY_LINK;
hresult = NOERROR;
errRtn: LEDebugOut((DEB_TRACE, "%p OUT CDefLink::SetUpdateOptions " "( %lx )\n", this, hresult));
return hresult; }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::GetUpdateOptions
//
// Synopsis: Retrieves the current update mode for the link
//
// Effects:
//
// Arguments: [pdwUpdateOpt] -- wehre to put the update options
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation: IOleLink
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 19-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
STDMETHODIMP CDefLink::GetUpdateOptions(LPDWORD pdwUpdateOpt) { VDATEHEAP(); VDATETHREAD(this);
LEDebugOut((DEB_TRACE, "%p _IN CDefLink::GetUpdateOptions " "( %p )\n", this, pdwUpdateOpt));
*pdwUpdateOpt = m_dwUpdateOpt;
LEDebugOut((DEB_TRACE, "%p OUT CDefLink::GetUpdateOptions " "( %lx ) [ %lx ]\n", this, NOERROR, *pdwUpdateOpt));
return NOERROR; }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::SetSourceMoniker
//
// Synopsis: Sets the link source moniker
//
// Effects:
//
// Arguments: [pmk] -- moniker to the new source (NULL used
// for CancelLink operations)
// [rclsid] -- the clsid of the source
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation: IOleLink
//
// Algorithm: Stores the new absolute moniker and creates a new relative
// moniker from the absolute moniker
//
// History: dd-mmm-yy Author Comment
// 09-Jan-95 alexgo added call to SetUpdateTimes to keep
// internal state consistent
// 21-Nov-94 alexgo memory optimization
/// 03-Aug-94 alexgo stabilized and handle zombie case
// 19-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
STDMETHODIMP CDefLink::SetSourceMoniker( LPMONIKER pmk, REFCLSID clsid ) { HRESULT hresult = NOERROR;
VDATEHEAP(); VDATETHREAD(this);
LEDebugOut((DEB_TRACE, "%p _IN CDefLink::SetSourceMoniker " "( %p , %p )\n", this, pmk, clsid));
CRefStabilize stabilize(this);
if( IsZombie() ) { hresult = CO_E_RELEASED; goto errRtn; }
if (pmk) { VDATEIFACE(pmk); }
UnbindSource();
// REVIEW: the following code appears in several places and should
// be put in a separate routine:
// SetBothMk(pmkSrcAbs, <calculated from abs>,
// TRUE/*fBind*/);
if (m_pMonikerAbs) { m_pMonikerAbs->Release(); }
if ((m_pMonikerAbs = pmk) != NULL) { pmk->AddRef();
//
// TRACKLINK
//
// -- use ITrackingMoniker to convert file moniker to
// be tracking.
//
#ifdef _TRACKLINK_
EnableTracking(pmk, OT_READTRACKINGINFO); #endif
}
UpdateRelMkFromAbsMk(NULL);
// to prevent error in BindToSource when clsid is different; i.e., we
// shouldn't fail to connect (or require OLELINKBIND_EVENIFCLASSDIFF)
// when the moniker is changed; i.e., we expect the class to change
// so don't bother the programmer.
m_clsid = CLSID_NULL;
if (BindIfRunning() != NOERROR) { // server not running -> use clsid given (even if CLSID_NULL
// and even
// if no moniker)
m_clsid = clsid; }
errRtn:
LEDebugOut((DEB_TRACE, "%p OUT CDefLink::SetSourceMoniker " "( %lx )\n", this, hresult ));
return hresult; }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::GetSourceMoniker
//
// Synopsis: Gets the moniker to the source
//
// Effects:
//
// Arguments: [ppmk] -- where to put the moniker
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation: IOleLink
//
// Algorithm: We first try to build a new absolute moniker from the
// relative one, if that fails then we return the currently
// stored absolute moniker.
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 03-Aug-94 alexgo stabilized
// 19-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
STDMETHODIMP CDefLink::GetSourceMoniker(LPMONIKER *ppmk) { LPMONIKER pmkAbs = NULL; // the absolute moniker constructed from the rel
HRESULT hresult = NOERROR;
VDATEHEAP(); VDATETHREAD(this);
LEDebugOut((DEB_TRACE, "%p _IN CDefLink::GetSourceMoniker " "( %p )\n", this, ppmk));
CRefStabilize stabilize(this);
GetAbsMkFromRel(&pmkAbs, NULL); if (pmkAbs) { *ppmk = pmkAbs; // no addref
} else if (*ppmk = m_pMonikerAbs) { // we've been asked to give the pointer so we should AddRef()
m_pMonikerAbs->AddRef(); } else { hresult = MK_E_UNAVAILABLE; }
LEDebugOut((DEB_TRACE, "%p OUT CDefLink::GetSourceMoniker " "( %lx ) [ %p ]\n", this, hresult, *ppmk));
return hresult; }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::SetSourceDisplayName
//
// Synopsis: Creates a moniker from the display name and calls
// SetSourceMoniker, thus setting the moniker to the source
//
// Effects:
//
// Arguments: [lpszStatusText] -- the display name
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation: IOleLink
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 03-Aug-94 alexgo stabilized and handle the zombie case
// 19-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
STDMETHODIMP CDefLink::SetSourceDisplayName( LPCOLESTR lpszStatusText) { HRESULT error; IBindCtx FAR* pbc; ULONG cchEaten; IMoniker FAR* pmk;
VDATEHEAP(); VDATETHREAD(this);
LEDebugOut((DEB_TRACE, "%p _IN CDefLink::SetSourceDisplay" "Name ( %p )\n", this, lpszStatusText));
CRefStabilize stabilize(this);
if( IsZombie() ) { error = CO_E_RELEASED; goto errRtn; }
if (error = CreateBindCtx(0,&pbc)) { goto errRtn; }
error = MkParseDisplayName(pbc, (LPOLESTR)lpszStatusText, &cchEaten, &pmk);
// In Daytona, we release the hidden server
// must release this now so the (possibly) hidden server goes away.
Verify(pbc->Release() == 0);
if (error != NOERROR) { goto errRtn; }
error = SetSourceMoniker(pmk, CLSID_NULL);
pmk->Release();
// NOTE: we don't bind to the link source now since that would leave
// the server running, but hidden. If the caller want to not start
// the server twice it should parse the moniker itself, call
// SetSourceMoniker and then BindToSource with the bind context of
// the parse.
errRtn:
LEDebugOut((DEB_TRACE, "%p OUT CDefLink::SetSourceDisplay" "Name ( %lx )\n", this, error ));
return error; }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::GetSourceDisplayName
//
// Synopsis: Retrieves the source display name (such as that set with
// SetSourceDisplayName)
//
// Effects:
//
// Arguments: [lplpszDisplayName] -- where to put a pointer to the
// display name
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation: IOleLink
//
// Algorithm: Gets the absolute moniker and asks it for the display name
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 03-Aug-94 alexgo stabilized
// 19-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
STDMETHODIMP CDefLink::GetSourceDisplayName( LPOLESTR *lplpszDisplayName ) { HRESULT hresult; IBindCtx FAR* pbc; LPMONIKER pmk = NULL;
VDATEHEAP(); VDATETHREAD(this);
LEDebugOut((DEB_TRACE, "%p _IN CDefLink::GetSourceDisplay" "Name ( %p )\n", this, lplpszDisplayName));
CRefStabilize stabilize(this);
*lplpszDisplayName = NULL;
GetSourceMoniker(&pmk);
if (pmk == NULL) { hresult = E_FAIL; goto errRtn; }
if (hresult = CreateBindCtx(0,&pbc)) { goto errRtn; }
hresult = pmk->GetDisplayName(pbc, NULL,lplpszDisplayName); AssertOutPtrParam(hresult, *lplpszDisplayName);
Verify(pbc->Release() == 0); errRtn: if (pmk) { pmk->Release(); }
LEDebugOut((DEB_TRACE, "%p OUT CDefLink::GetSourceDisplay" "Name ( %lx ) [ %p ]\n", this, hresult, *lplpszDisplayName));
return hresult; }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::BindToSource
//
// Synopsis: Binds to the link source
//
// Effects:
//
// Arguments: [bindflags] -- controls the binding (such as binding
// even if the class ID is different)
// [pbc] -- the bind context
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation: IOleLink
//
// Algorithm: First try binding with the relative moniker, failing that
// then try the absolute moniker. Once bound, we set up
// the advises and cache.
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 03-Aug-94 alexgo stabilize and check for zombie case
// 03-Feb-94 alexgo check for NULL before SendOnLinkSrcChange
// 11-Jan-94 alexgo cast -1's to DWORD to fix compile
// warning
// 19-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
STDMETHODIMP CDefLink::BindToSource(DWORD bindflags, LPBINDCTX pbc) { HRESULT error = S_OK; IOleObject FAR* pOleDelegate; IDataObject FAR* pDataDelegate; IBindCtx FAR* pBcUse; CLSID clsid; LPMONIKER pmkAbs = NULL; LPMONIKER pmkHold = NULL; LPRUNNABLEOBJECT pRODelegate; LPOLEITEMCONTAINER pOleCont; BOOL fLockedContainer;
VDATEHEAP(); VDATETHREAD(this);
LEDebugOut((DEB_TRACE, "%p _IN CDefLink::BindToSource " "( %lx , %p )\n", this, bindflags, pbc));
CRefStabilize stabilize(this);
// if we're zombied (e.g. in the middle of our destructor), we
// don't really want to bind the source again ;-)
if( IsZombie() ) { error = CO_E_RELEASED; goto logRtn; }
// if we're running, then we're already bound
if (IsReallyRunning()) { error = NOERROR; goto logRtn; }
// nobody to bind to
if (m_pMonikerAbs == NULL) { error = E_UNSPEC; goto logRtn; }
if ((pBcUse = pbc) == NULL && (error = CreateBindCtx(0,&pBcUse)) != NOERROR) { goto errRtn; }
{ //
// Rewritten BillMo 30 Jan 1995.
//
// Enumeration which is used to keep track of what stage of resolution
// we were successful in.
//
enum { None, Relative, Ids, Absolute } ResolveSuccess = { None }; if (m_pMonikerRel != NULL) { error = GetAbsMkFromRel(&pmkAbs, NULL); if (error == NOERROR) { error = pmkAbs->BindToObject(pBcUse, NULL, IID_IUnknown, (LPVOID FAR *) &m_pUnkDelegate); if (error == NOERROR) { ResolveSuccess = Relative; } else { pmkAbs->Release(); pmkAbs = NULL; } } }
if (ResolveSuccess == None && error != RPC_E_CALL_REJECTED) { error = m_pMonikerAbs->BindToObject(pBcUse, NULL, IID_IUnknown, (LPVOID FAR *)&m_pUnkDelegate); if (error == NOERROR) { ResolveSuccess = Absolute; (pmkAbs = m_pMonikerAbs)->AddRef(); } }
#ifdef _TRACKLINK_
if (ResolveSuccess == None && error != RPC_E_CALL_REJECTED) { HRESULT error2; Assert(pmkAbs == NULL); EnableTracking(m_pMonikerAbs, OT_ENABLEREDUCE); error2 = m_pMonikerAbs->Reduce(pBcUse, MKRREDUCE_ALL, NULL, &pmkAbs); EnableTracking(m_pMonikerAbs, OT_DISABLEREDUCE); if (error2 == NOERROR) { if (pmkAbs != NULL) { error2 = pmkAbs->BindToObject(pBcUse, NULL, IID_IUnknown, (LPVOID FAR *)&m_pUnkDelegate); if (error2 == NOERROR) { ResolveSuccess = Ids; error = NOERROR; } else { pmkAbs->Release(); pmkAbs=NULL; } } // else error contains error from m_pMonikerAbs->BindToObject
} else if (error2 == MK_S_REDUCED_TO_SELF) { if (pmkAbs != NULL) { pmkAbs->Release(); pmkAbs=NULL; } } // else error contains error from m_pMonikerAbs->BindToObject
} #endif
//
// Update the link state
//
if (ResolveSuccess == None) goto errRtn;
// Update the absolute moniker and send OnLinkSrcChange
// (may update relative if this was an Ids resolve)
if (ResolveSuccess == Relative || ResolveSuccess == Ids) { // binding succeeded with relative moniker or ids
// Update the absolute one.
// hold on to old absolute one
pmkHold = m_pMonikerAbs; if (pmkHold) { pmkHold->AddRef(); } if (m_pMonikerAbs) { m_pMonikerAbs->Release(); m_pMonikerAbs = NULL; } if (ResolveSuccess == Relative) { GetAbsMkFromRel(&m_pMonikerAbs, NULL); } else { // Ids
m_pMonikerAbs = pmkAbs; pmkAbs = NULL; UpdateRelMkFromAbsMk(NULL); } //
// test to see if we had no abs moniker before OR the
// one we had is different to the new one.
//
if (pmkHold == NULL || pmkHold->IsEqual(m_pMonikerAbs) != NOERROR ) { m_flags |= DL_DIRTY_LINK; // send change notification if the advise
// holder present.
if( m_pCOAHolder) { m_pCOAHolder->SendOnLinkSrcChange( m_pMonikerAbs); } } // have new absolute moniker; dirty
if (pmkHold) { pmkHold->Release(); } } // Update the relative
if (ResolveSuccess == Absolute) { UpdateRelMkFromAbsMk(NULL); } }
#ifdef _TRACKLINK_
EnableTracking(m_pMonikerAbs, OT_READTRACKINGINFO);
if (m_pMonikerAbs->IsDirty()) m_flags |= DL_DIRTY_LINK; #endif
// NOTE: don't need to update the relative moniker when there isn't
// one because we will do that at save time.
// Successfully bound, Lock the Object.
if ((pRODelegate = GetRODelegate()) != NULL) { // lock so invisible link source does not goes away.
Assert(0 == (m_flags & DL_LOCKED_RUNNABLEOBJECT));
if (NOERROR == pRODelegate->LockRunning(TRUE, FALSE)) { m_flags |= DL_LOCKED_RUNNABLEOBJECT; } } else if( (pOleCont = GetOleItemContainerDelegate()) != NULL) { // have container in same process or handler which doesn't
// support IRunnableObject.
Assert(0 == (m_flags & DL_LOCKED_OLEITEMCONTAINER));
if (NOERROR == pOleCont->LockContainer(TRUE)) { m_flags |= DL_LOCKED_OLEITEMCONTAINER; }
}
// Lock the container
fLockedContainer = m_flags & DL_LOCKED_CONTAINER;
DuLockContainer(m_pAppClientSite, TRUE, &fLockedContainer );
if(fLockedContainer) { m_flags |= DL_LOCKED_CONTAINER; } else { m_flags &= ~DL_LOCKED_CONTAINER; }
// By this point, we have successfully bound to the server. Now
// we take care of misc administrative tasks.
Assert(m_pUnkDelegate != NULL && "CDefLink::BindToSource expected valid m_pUnkDelegate");
// get class of link source; use NULL if it doesn't support IOleObject
// or IOleObject::GetUserClassID returns an error.
if ((pOleDelegate = GetOleDelegate()) == NULL || pOleDelegate->GetUserClassID(&clsid) != NOERROR) { clsid = CLSID_NULL; }
// if different and no flag, release and return error.
if ( IsEqualCLSID(m_clsid,CLSID_NULL)) { // m_clsid now NULL; link becomes dirty
m_flags |= DL_DIRTY_LINK; } else if ( !IsEqualCLSID(clsid, m_clsid) ) { if ((bindflags & OLELINKBIND_EVENIFCLASSDIFF) == 0) { CLSID TreatAsCLSID;
// Initialize error
error = OLE_E_CLASSDIFF; // Check for TreatAs case
if(CoGetTreatAsClass(m_clsid, &TreatAsCLSID) == S_OK) { // Check if the server clsid is same as TreatAs clsid
if(IsEqualCLSID(clsid, TreatAsCLSID)) error = NOERROR; }
if(error == OLE_E_CLASSDIFF) goto errRtn; }
// clsid's do no match; link becomes dirty
m_flags |= DL_DIRTY_LINK; }
// use new class (even if null); dirty flag set above
m_clsid = clsid;
// it is possible that a re-entrant call unbound our source
// thus making pOleDelegate invalid (since it's a local on
// the stack
LEWARN(pOleDelegate != m_pOleDelegate, "Unbind during IOL::BindToSource");
// we fetched m_pOleDelegate in the call to GetOleDelegate above.
if( m_pOleDelegate != NULL) { // set single ole advise (we multiplex)
if ((error = m_pOleDelegate->Advise( &m_AdviseSink, &m_dwConnOle)) != NOERROR) { goto errRtn; } }
// Set up advise connections for data changes
if( pDataDelegate = GetDataDelegate() ) { // setup wild card advise to get time change
FORMATETC fetc;
fetc.cfFormat = NULL; fetc.ptd = NULL; fetc.dwAspect = (DWORD)-1L; fetc.lindex = -1; fetc.tymed = (DWORD)-1L;
if ((error = pDataDelegate->DAdvise(&fetc, ADVF_NODATA, &m_AdviseSink, &m_dwConnTime)) != NOERROR) { LEDebugOut((DEB_WARN, "WARNING: server does not " "support wild card advises\n")); goto errRtn; }
// it is possible that a re-entrant call unbound our
// link server, so we need to fetch the data object
// pointer again
LEWARN(pDataDelegate != m_pDataDelegate, "Unbind during IOL::BindToSource");
// this will set up data advise connections with
// everybody in our data advise holder
// (see dacache.cpp)
error = m_pDataAdvCache->EnumAndAdvise( m_pDataDelegate, TRUE);
if( error != NOERROR ) { goto errRtn; } }
if (m_dwUpdateOpt == OLEUPDATE_ALWAYS) { // we inform the cache that we are running only if auto
// update; otherwise, we are a manual link and will call
// Update directly (which doesn't require OnRun to be called).
BeginUpdates(); }
// Our m_pUnkDelegate may have been released by an
// OnClose advise that came in while we were setting up Advise
// sinks.
if (NULL == m_pUnkDelegate) { LEDebugOut((DEB_WARN, "CDefLink::BindToSource - " "m_pUnkDelegate was released " "(probably due to OnClose)"));
error = MK_E_NOOBJECT; }
errRtn: // free used resources
if (pmkAbs) { pmkAbs->Release(); } if (error == NOERROR) { m_ContentSRVMSBits = 0; m_ContentSRVMSHResult = 0xFFFFFFFF; } else { UnbindSource(); // ClientSite will be unlocked in UnBindSource
}
if (pbc == NULL && pBcUse != NULL) { // created bind ctx locally
Verify(pBcUse->Release() == 0); }
#if DBG == 1
if( m_pUnkDelegate ) { Assert(error == NOERROR ); } else { Assert(error != NOERROR ); } #endif
AssertOutPtrIface(error, m_pUnkDelegate);
logRtn:
LEDebugOut((DEB_TRACE, "%p OUT CDefLink::BindToSource " "( %lx )\n", this, error ));
return error; }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::BindIfRunning
//
// Synopsis: Binds to the source server only if it is currently running
//
// Effects:
//
// Arguments: void
//
// Requires:
//
// Returns: HRESULT (NOERROR if connected)
//
// Signals:
//
// Modifies:
//
// Derivation: IOleLink
//
// Algorithm: Gets a good moniker to the source (first tries relative,
// then tries absolute), ask it if the server is running, if
// yes, then bind to it.
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 03-Aug-94 alexgo stabilize and handle the zombie case
// 19-Nov-93 alexgo 32bit port
//
// Notes: We may return NOERROR (connected) even if the server has
// crashed unexpectedly
//
//--------------------------------------------------------------------------
STDMETHODIMP CDefLink::BindIfRunning(void) { HRESULT error; LPBC pbc; LPMONIKER pmkAbs = NULL;
VDATEHEAP(); VDATETHREAD(this);
LEDebugOut((DEB_TRACE, "%p _IN CDefLink::BindIfRunning " "( )\n", this ));
CRefStabilize stabilize(this);
// if we're zombied (e.g. in our destructor), then we don't want
// to bind to the server!
if( IsZombie() ) { error = CO_E_RELEASED; goto errRtn; }
if (IsReallyRunning()) { error = NOERROR; goto errRtn; }
// try getting an absolute moniker from the relative moniker first
if (GetAbsMkFromRel(&pmkAbs, NULL) != NOERROR) { // can't get relative moniker; use abs if available
if ((pmkAbs = m_pMonikerAbs) == NULL) { error = E_FAIL; goto errRtn; }
pmkAbs->AddRef(); }
// NOTE: we used to try both monikers, but this caused problems if
// both would bind and the absolute one was running: we would bind
// to the wrong one or force the relative one to be running. Now,
// if we have a relative moniker, we try that one only; if we only
// have an absolute moniker, we try that one; otherwise we fail.
error = CreateBindCtx( 0, &pbc ); if (error != NOERROR) { goto errRtn; }
if ((error = pmkAbs->IsRunning(pbc, NULL, NULL)) == NOERROR) { // abs is running, but rel is not; force BindToSource to use
// the absolute moniker
error = BindToSource(0, pbc); }
// else return last error (from pmkAbs->IsRunning)
pbc->Release();
errRtn: if (pmkAbs) { pmkAbs->Release(); }
LEDebugOut((DEB_TRACE, "%p OUT CDefLink::BindIfRunning " "( %lx )\n", this, error ));
return error; }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::GetBoundSource
//
// Synopsis: Returns a pointer to the server delegate
//
// Effects:
//
// Arguments: [ppUnk] -- where to put the pointer to the server
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation: IOleLink
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 03-Aug-94 alexgo stabilized
// 19-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
STDMETHODIMP CDefLink::GetBoundSource(LPUNKNOWN *ppUnk) { HRESULT hresult;
VDATEHEAP(); VDATETHREAD(this);
LEDebugOut((DEB_TRACE, "%p _IN CDefLink::GetBoundSource " "( %p )\n", this, ppUnk));
CRefStabilize stabilize(this);
if (!IsReallyRunning()) { *ppUnk = NULL; hresult = E_FAIL; } else { (*ppUnk = m_pUnkDelegate)->AddRef(); hresult = NOERROR; }
LEDebugOut((DEB_TRACE, "%p OUT CDefLink::GetBoundSource " "( %lx ) [ %p ]\n", this, hresult, *ppUnk));
return hresult; }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::UnbindSource
//
// Synopsis: Unbinds the connection to the link source server
//
// Effects:
//
// Arguments: void
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation: IOleLink
//
// Algorithm: First unadvise all advise connections and then tickle
// the container by lock/unlocking (to handle the silent
// update case). Finally, we release all pointers to the
// server. If we were the only folks connected, the server
// will go away
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 03-Aug-94 alexgo stabilized
// 19-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
STDMETHODIMP CDefLink::UnbindSource(void) { LPDATAOBJECT pDataDelegate; LPOLEOBJECT pOleDelegate; LPRUNNABLEOBJECT pRODelegate; LPOLEITEMCONTAINER pOleCont; HRESULT hresult = NOERROR; IUnknown * pUnkDelegate; BOOL fLockedContainer;
VDATEHEAP(); VDATETHREAD(this);
LEDebugOut((DEB_TRACE, "%p _IN CDefLink::UnbindSource " "( )\n", this ));
CRefStabilize stabilize(this);
if (!m_pUnkDelegate) { // hresult == NOERROR
goto errRtn; }
// unadvise so if delegate stays around, we get the correct results
if ((pOleDelegate = GetOleDelegate()) != NULL && m_dwConnOle != 0) { pOleDelegate->Unadvise(m_dwConnOle); m_dwConnOle = 0; }
if( pDataDelegate = GetDataDelegate() ) { if (m_dwConnTime) { pDataDelegate->DUnadvise(m_dwConnTime); m_dwConnTime = 0; }
// we can actually be re-entered here, so refetch the
// IDO pointer from the server (if it's still around)
LEWARN(pDataDelegate != m_pDataDelegate, "Unbind called within IOL::UnbindSource!");
// pDataDelegate should still be good, since we still have
// an AddRef on it. Go through and do the unadvises again
// anyway.
// this will unadvise everybody registered in the data
// advise holder
m_pDataAdvCache->EnumAndAdvise( pDataDelegate, FALSE); }
// inform cache that we are not running (even if OnRun was not called)
EndUpdates();
if ( (m_flags & DL_LOCKED_RUNNABLEOBJECT) && ((pRODelegate = GetRODelegate()) != NULL) ) { // unlock so invisible link source goes away.
// do it just before release delegates so above unadvises go
m_flags &= ~DL_LOCKED_RUNNABLEOBJECT; pRODelegate->LockRunning(FALSE, TRUE); } if( (m_flags & DL_LOCKED_OLEITEMCONTAINER) && ((pOleCont = GetOleItemContainerDelegate()) != NULL) ) { // have container in same process or handler
// Unlock to shutdown.
m_flags &= ~DL_LOCKED_OLEITEMCONTAINER; pOleCont->LockContainer(FALSE); }
Assert(0 == (m_flags & (DL_LOCKED_OLEITEMCONTAINER | DL_LOCKED_RUNNABLEOBJECT)));
// release all of our pointers.
ReleaseOleDelegate(); ReleaseDataDelegate(); ReleaseRODelegate(); ReleaseOleItemContainerDelegate();
// if we are the only consumer of this data, the following will stop
// the server; set member to NULL first since release may cause this
// object to be accessed again.
pUnkDelegate = m_pUnkDelegate;
LEWARN(pUnkDelegate == NULL, "Unbind called within IOL::UnbindSource");
m_pUnkDelegate = NULL;
if( pUnkDelegate ) { pUnkDelegate->Release(); }
// make sure unlocked if we locked it
fLockedContainer = m_flags & DL_LOCKED_CONTAINER; m_flags &= ~DL_LOCKED_CONTAINER; DuLockContainer(m_pAppClientSite, FALSE, &fLockedContainer);
AssertSz( hresult == NOERROR, "Bogus code modification, check error " "paths");
errRtn:
LEDebugOut((DEB_TRACE, "%p OUT CDefLink::UnbindSource " "( %lx )\n", this, hresult));
return hresult; }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::Update
//
// Synopsis: Updates the link (fills cache, etc).
//
// Effects:
//
// Arguments: [pbc] -- the bind context
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation: IOleLink
//
// Algorithm: Bind to the server, then update the caches
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 03-Aug-94 alexgo stabilized
// 19-Nov-93 alexgo 32bit port
//
// Notes:
// As in IOO::DoVerb, we try to "fix" crashed servers by
// staying bound to them if we rebind due to a crash. See
// the Notes in IOO::DoVerb for more info.
//
//--------------------------------------------------------------------------
STDMETHODIMP CDefLink::Update(LPBINDCTX pbc) { HRESULT error = NOERROR; BOOL bStartedNow = !m_pUnkDelegate; LPBINDCTX pBcUse;
VDATEHEAP(); VDATETHREAD(this);
LEDebugOut((DEB_TRACE, "%p _IN CDefLink::Update ( %p )\n", this, pbc));
CRefStabilize stabilize(this);
if (pbc) { pBcUse = pbc; } else { if (FAILED(error = CreateBindCtx( 0, &pBcUse ))) goto errBndCtx; }
if (FAILED(error = BindToSource(0,pBcUse))) { goto errRtn; }
// store the pUnk there to allow for
// better optimization (if we didn't, file based link sources would
// be launched multiple times since the moniker code does not put
// them in the bind ctx (and probably shouldn't)).
pBcUse->RegisterObjectBound(m_pUnkDelegate);
SetUpdateTimes(); // ignore error.
if (bStartedNow && (m_dwUpdateOpt == OLEUPDATE_ALWAYS)) { // if this is an auto-link and we ran it now, then all the
// automatic caches would have been updated during the
// running process. So, here we have to update only the
// ADVFCACHE_ONSAVE caches.
error= m_pCOleCache->UpdateCache( GetDataDelegate(), UPDFCACHE_IFBLANKORONSAVECACHE, NULL); } else { // This is a manual-link or it is an auto-link then it is
// already running. In all these cases, all the caches need
// to be updated.
// (See bug 1616, to find out why we also have to update
// the autmatic caches of auto-links).
error= m_pCOleCache->UpdateCache( GetDataDelegate(), UPDFCACHE_ALLBUTNODATACACHE, NULL); }
if (bStartedNow) { UnbindSource(); }
errRtn:
// if we created a bind context release it.
if ( (NULL == pbc) && pBcUse) { pBcUse->Release(); }
errBndCtx:
LEDebugOut((DEB_TRACE, "%p OUT CDefLink::Update ( %lx )\n", this, error ));
return error; }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::EnableTracking
//
// Synopsis: Calls ITrackingMoniker::EnableTracking on the passed moniker.
//
// Arguments: [pmk] -- moniker
//
// [ulFlags]
// OT_READTRACKINGINFO -- read tracking info from source
// OT_ENABLESAVE -- enable save of tracking info
// OT_DISABLESAVE -- disable save of tracking info
//
// Algorithm: QI to ITrackingMoniker and call EnableTracking
//
//
//--------------------------------------------------------------------------
#ifdef _TRACKLINK_
INTERNAL CDefLink::EnableTracking(IMoniker *pmk, ULONG ulFlags) { ITrackingMoniker *ptm = NULL; HRESULT hr = E_FAIL;
if (pmk != NULL) { hr = pmk->QueryInterface(IID_ITrackingMoniker, (void**)&ptm); if (hr == S_OK) { hr = ptm->EnableTracking(NULL, ulFlags); LEDebugOut((DEB_TRACK, "CDefLink(%08X)::EnableTracking -- ptm->EnableTracking() = %08X\n", this, hr)); ptm->Release(); } else { LEDebugOut((DEB_TRACK, "CDefLink(%08X)::EnableTracking -- pmk->QI failed (%08X)\n", this, hr)); } } else { LEDebugOut((DEB_TRACK, "CDefLink(%08X)::EnableTracking -- pmk is NULL\n", this)); } return(hr); } #endif
/*
* IMPLEMENTATION of CROImpl methods */
//+-------------------------------------------------------------------------
//
// Member: CDefLink::GetRODelegate (private)
//
// Synopsis: gets the IRunnableObject from the interface
//
// Effects:
//
// Arguments: void
//
// Requires:
//
// Returns: IRunnableObject *
//
// Signals:
//
// Modifies:
//
// Derivation:
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 03-Aug-94 alexgo stabilized and handle the zombie case
// 19-Nov-93 alexgo 32bit port
//
// Notes:
// This function may return misleading information if the
// server has died (i.e., you'll return a pointer to a cached
// interface proxy). It is the responsibility of the caller
// to handler server crashes.
//
//--------------------------------------------------------------------------
INTERNAL_(IRunnableObject *) CDefLink::GetRODelegate(void) { IRunnableObject *pRODelegate;
VDATEHEAP();
LEDebugOut((DEB_ITRACE, "%p _IN CDefLink::GetRODelegate " "( )\n", this ));
// if we're zombied, then we don't want to QI for a new interface!!
if( !IsZombie() ) { DuCacheDelegate(&(m_pUnkDelegate), IID_IRunnableObject, (LPLPVOID)&m_pRODelegate, NULL);
pRODelegate = m_pRODelegate;
#if DBG == 1
if( m_pRODelegate ) { Assert(m_pUnkDelegate); } #endif // DBG == 1
} else { pRODelegate = NULL; }
LEDebugOut((DEB_ITRACE, "%p OUT CDefLink::GetRODelegate " "( %p )\n", this, pRODelegate));
return pRODelegate; }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::ReleaseRODelegate (private)
//
// Synopsis: Releases the IRO pointer to the server
//
// Effects:
//
// Arguments: void
//
// Requires:
//
// Returns: void
//
// Signals:
//
// Modifies:
//
// Derivation:
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 19-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
INTERNAL_(void) CDefLink::ReleaseRODelegate(void) { VDATEHEAP();
LEDebugOut((DEB_ITRACE, "%p _IN CDefLink::ReleaseRODelegate " "( )\n", this ));
if (m_pRODelegate) { SafeReleaseAndNULL((IUnknown **)&m_pRODelegate); }
LEDebugOut((DEB_ITRACE, "%p OUT CDefLink::ReleaseRODelegate " "( )\n", this )); }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::GetRunningClass
//
// Synopsis: retrieves the class of the the default link
//
// Effects:
//
// Arguments: [lpClsid] -- where to put the class id
//
// Requires:
//
// Returns: NOERROR
//
// Signals:
//
// Modifies:
//
// Derivation: IRunnableObject
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 19-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
STDMETHODIMP CDefLink::GetRunningClass(LPCLSID lpClsid) { VDATEHEAP(); VDATETHREAD(this);
LEDebugOut((DEB_TRACE, "%p _IN CDefLink::GetRunningClass " "( %p )\n", this, lpClsid));
VDATEPTROUT(lpClsid, CLSID);
*lpClsid = CLSID_StdOleLink;
LEDebugOut((DEB_TRACE, "%p OUT CDefLink::GetRunningClass " "( %lx )\n", this, NOERROR));
return NOERROR; }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::Run
//
// Synopsis: Runs the object (binds to the server)
//
// Effects:
//
// Arguments: [pbc] -- the bind context
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation: IRunnableObject
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 03-Aug-94 alexgo stabilized
// 19-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
STDMETHODIMP CDefLink::Run (LPBINDCTX pbc) { HRESULT hresult;
VDATEHEAP(); VDATETHREAD(this);
LEDebugOut((DEB_TRACE, "%p _IN CDefLink::Run ( %p )\n", this, pbc ));
CRefStabilize stabilize(this);
hresult = BindToSource(0, pbc);
LEDebugOut((DEB_TRACE, "%p OUT CDefLink::Run ( %lx )\n", this, hresult));
return hresult; }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::IsRunning
//
// Synopsis: returns whether or not we've bound to the link server
//
// Effects:
//
// Arguments: none
//
// Requires:
//
// Returns: TRUE/FALSE
//
// Signals:
//
// Modifies:
//
// Derivation: IRunnableObject
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 27-Aug-94 alexgo author
//
// Notes: 16bit OLE only ever implemented this function. We
// implement IsReallyRunning to allow links to recover
// from a crashed server.
// Unfortunately, we can't just move the IsReallyRunning
// implementation into IsRunning. Many apps (like Project)
// sit and spin calling OleIsRunning. IsReallyRunning also
// will sometimes make outgoing RPC calls; with Project,
// this causes a really cool infinite feedback loop. (the
// outgoing call resets some state in Project and they decide
// to call OleIsRunning again ;-)
//
//--------------------------------------------------------------------------
STDMETHODIMP_(BOOL) CDefLink::IsRunning (void) { BOOL fRet;
VDATEHEAP(); VDATETHREAD(this);
LEDebugOut((DEB_TRACE, "%p _IN CDefLink::IsRunning ( )\n", this ));
if( m_pUnkDelegate ) { fRet = TRUE; } else { fRet = FALSE; }
LEDebugOut((DEB_TRACE, "%p OUT CDefLink::IsRunning ( %d )\n", this, fRet));
return fRet; }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::IsReallyRunning
//
// Synopsis: Returns whether or not the link server is running
//
// Effects:
//
// Arguments: void
//
// Requires:
//
// Returns: BOOL -- TRUE == is running
//
// Signals:
//
// Modifies:
//
// Derivation:
//
// Algorithm: If we have not yet bound to the link server, then we
// are not running. If we have, we would like to verify
// that the server is still running (i.e. it hasn't crashed).
// Thus, we ask the absolute moniker if we are still running.
// (it will ping the rot, which will ping the server).
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 03-Aug-94 alexgo stabilized
// 06-May-94 alexgo now calls IMoniker::IsRunning
// 19-Nov-93 alexgo 32bit port
//
// Notes:
//
//
//--------------------------------------------------------------------------
STDMETHODIMP_(BOOL) CDefLink::IsReallyRunning (void) { BOOL fRet = FALSE; LPBC pbc; HRESULT hresult;
VDATEHEAP(); VDATETHREAD(this);
LEDebugOut((DEB_ITRACE, "%p _IN CDefLink::IsReallyRunning " "( )\n", this));
CRefStabilize stabilize(this);
if( m_pUnkDelegate != NULL ) { if( CreateBindCtx( 0, &pbc ) != NOERROR ) { // this is a bit counter-intuitive. Basically,
// the only error we'll get is OutOfMemory, but
// we have no way of returning that error.
// In order to mimimize the amount of work we need
// to do (since we are in a low-mem state), just
// return the current Running state (in this,
// TRUE, since m_pUnkDelegate is not NULL
fRet = TRUE; goto errRtn; }
if( m_pMonikerAbs ) { hresult = m_pMonikerAbs->IsRunning(pbc, NULL, NULL);
if( hresult != NOERROR ) { LEDebugOut((DEB_WARN, "WARNING: link server " "crashed or exited inappropriately " "( %lx ). Recovering...\n", hresult));
// wowsers, the server has crashed or gone
// away even though we were bound to it.
// let's go ahead and unbind.
// don't worry about errors here; we're
// just trying to cleanup as best we can
UnbindSource(); } if( hresult == NOERROR ) { fRet = TRUE; } #if DBG == 1
else { Assert(fRet == FALSE); } #endif // DBG == 1
}
#if DBG == 1
else { // we cannot have a pointer to the link server
// if we don't have a moniker to it. If we get
// to this state, something is hosed.
AssertSz(0, "Pointer to link server without a moniker"); } #endif // DBG == 1
pbc->Release(); }
errRtn:
// do some checking here. If we say we're running, then
// we should have a valid pUnkDelegate. Otherwise, it should
// be NULL. Note, however, that is *is* possible for us
// to unbind during this call even if we think we're running
//
// This occurs if during the call to IMoniker::IsRunning, we
// get another call in which does an UnbindSource; thus
// we'll think we're really running (from IMoniker::IsRunning),
// but we've really unbound.
//
// We'll check for that condition here
if( fRet == TRUE ) { if( m_pUnkDelegate == NULL ) { fRet = FALSE; LEDebugOut((DEB_WARN, "WARNING: Re-entrant Unbind" " during IsReallyRunning, should be OK\n")); } } #if DBG == 1
if( fRet == TRUE ) { Assert(m_pUnkDelegate != NULL); } else { Assert(m_pUnkDelegate == NULL); } #endif // DBG == 1
LEDebugOut((DEB_ITRACE, "%p OUT CDefLink::IsReallyRunning" "( %lu )\n", this, fRet));
return fRet; }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::SetContainedObject
//
// Synopsis: Sets the object as an embedding, not relevant for links
//
// Effects:
//
// Arguments: [fContained] -- flag to toggle embedding status
//
// Requires:
//
// Returns: HRESULT (NOERROR)
//
// Signals:
//
// Modifies:
//
// Derivation: IRunnableObject
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 19-Nov-93 alexgo 32bit port
//
// Notes:
//
// note contained object; links don't care at present
//
//--------------------------------------------------------------------------
STDMETHODIMP CDefLink::SetContainedObject(BOOL fContained) { VDATEHEAP(); VDATETHREAD(this);
return NOERROR; }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::LockRunning
//
// Synopsis: Lock/Unlock the connection to the server. Does nothing
// for links.
//
// Effects:
//
// Arguments: [fLock] -- flag to lock/unlock
// [fLastUnlockCloses] -- close if its the last unlock
//
// Requires:
//
// Returns: NOERROR
//
// Signals:
//
// Modifies:
//
// Derivation: IRunnableObject
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 19-Nov-93 alexgo 32bit port
//
// Notes:
// Links have different liveness characteristics than embeddings.
// We do not need to do anything for LockRunning for links.
//
//--------------------------------------------------------------------------
STDMETHODIMP CDefLink::LockRunning(BOOL fLock, BOOL fLastUnlockCloses) { VDATEHEAP(); VDATETHREAD(this);
return NOERROR; }
/*
* IMPLEMENTATION of CPersistStgImpl methods */
//+-------------------------------------------------------------------------
//
// Member: CDefLink::GetClassID
//
// Synopsis: Retrieves the class id of the default link
//
// Effects:
//
// Arguments: [pClassID] -- where to put the class ID
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation: IPersistStorage
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 19-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
STDMETHODIMP CDefLink::GetClassID (CLSID *pClassID) { VDATEHEAP(); VDATETHREAD(this);
*pClassID = CLSID_StdOleLink; return NOERROR; }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::IsDirty
//
// Synopsis: Returns TRUE if the linked object has changed
//
// Effects:
//
// Arguments: void
//
// Requires:
//
// Returns: NOERROR if dirty
//
// Signals:
//
// Modifies:
//
// Derivation: IPersistStorage
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 19-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
STDMETHODIMP CDefLink::IsDirty(void) { HRESULT hresult;
VDATEHEAP(); VDATETHREAD(this);
LEDebugOut((DEB_TRACE, "%p _IN CDefLink::IsDirty" " ( )\n", this));
if( (m_flags & DL_DIRTY_LINK) ) { hresult = NOERROR; } else { Assert(m_pCOleCache != NULL); hresult = m_pCOleCache->IsDirty(); }
LEDebugOut((DEB_TRACE, "%p OUT CDefLink::IsDirty " "( %lx )\n", this, hresult));
return hresult; }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::InitNew
//
// Synopsis: Initialize a new link object from the given storage
//
// Effects:
//
// Arguments: [pstg] -- the new storage for the link
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation: IPersistStorage
//
// Algorithm: Delegates to the cache
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 03-Aug-94 alexgo stabilized and handle the zombie case
// 19-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
STDMETHODIMP CDefLink::InitNew( IStorage *pstg) { HRESULT error;
VDATEHEAP(); VDATETHREAD(this);
LEDebugOut((DEB_TRACE, "%p _IN CDefLink::InitNew " "( %p )\n", this, pstg));
VDATEIFACE(pstg);
CRefStabilize stabilize(this);
if( IsZombie() ) { error = CO_E_RELEASED; } else if (m_pStg == NULL) { Assert(m_pCOleCache != NULL); if ((error = m_pCOleCache->InitNew(pstg)) == NOERROR) { m_flags |= DL_DIRTY_LINK; (m_pStg = pstg)->AddRef(); } } else { error = CO_E_ALREADYINITIALIZED; }
LEDebugOut((DEB_TRACE, "%p OUT CDefLink::InitNew " "( %lx )\n", this, error ));
return error; }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::Load
//
// Synopsis: Initializes a link from data stored in the storage
//
// Effects:
//
// Arguments: [pstg] -- the storage with link data
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation: IPersistStorage
//
// Algorithm: Read ole private data and set internal link information.
// Then delegate to the cache to load presentation data, etc.
//
// History: dd-mmm-yy Author Comment
// 20-Feb-94 KentCe Buffer internal stream i/o.
// 21-Nov-94 alexgo memory optimization
// 03-Aug-94 alexgo stabilized and handle zombie case
// 19-Nov-93 alexgo 32bit port
//
//--------------------------------------------------------------------------
STDMETHODIMP CDefLink::Load(IStorage *pstg) { HRESULT error; LPMONIKER pmk = NULL; LPMONIKER pmkSrcAbs = NULL; LPMONIKER pmkSrcRel = NULL; CLSID clsid; DWORD dwOptUpdate; LPSTREAM pstm = NULL; DWORD dummy; ULONG cbRead; CStmBufRead StmRead;
VDATEHEAP(); VDATETHREAD(this);
LEDebugOut((DEB_TRACE, "%p _IN CDefLink::CPeristStgImpl::Load " "( %p )\n", this, pstg ));
VDATEIFACE(pstg);
CRefStabilize stabilize(this);
// if we're in a zombie state, we don't want to be reloading
// our object!!
if( IsZombie() ) { error = CO_E_RELEASED; goto logRtn; }
if (m_pStg) { error = CO_E_ALREADYINITIALIZED; goto logRtn; }
//read link data from the storage
error = ReadOleStg (pstg, &m_dwObjFlags, &dwOptUpdate, NULL, &pmk, &pstm);
if (error == NOERROR) { // set the update options.
SetUpdateOptions (dwOptUpdate);
// we can get the moniker from container, so no need to
// remeber this
if (pmk) { pmk->Release(); }
Assert (pstm != NULL);
// Read relative source moniker. Write NULL for the time being
if ((error = ReadMonikerStm (pstm, &pmkSrcRel)) != NOERROR) { goto errRtn; }
// Read absolute source moniker; stored in link below
if ((error = ReadMonikerStm (pstm, &pmkSrcAbs)) != NOERROR) { goto errRtn; }
//
// Buffer the read i/o from the stream.
//
StmRead.Init(pstm);
// Read -1 followed by the last class name
if ((error = ReadM1ClassStmBuf(StmRead, &clsid)) != NOERROR) { goto errRtn; }
// Read the last display name
// Right now, this is always an empty string
LPOLESTR pstr = NULL; if ((error = ReadStringStream (StmRead, &pstr)) != NOERROR) { goto errRtn; }
if (pstr) { LEDebugOut((DEB_ERROR, "ERROR!: Link user type " "string found, unexpected\n")); PubMemFree(pstr); }
if ((error = StmRead.Read(&dummy, sizeof(DWORD))) != NOERROR) { goto errRtn; }
if ((error = StmRead.Read(&(m_ltChangeOfUpdate), sizeof(FILETIME))) != NOERROR) { goto errRtn; }
if ((error = StmRead.Read(&(m_ltKnownUpToDate), sizeof(FILETIME))) != NOERROR) { goto errRtn; }
if ((error = StmRead.Read(&(m_rtUpdate), sizeof(FILETIME))) != NOERROR) { goto errRtn; }
//
// TRACKLINK
//
// - tell the absolute moniker to convert itself
// into a tracking moniker using ITrackingMoniker::
// EnableTracking. (The composite
// moniker should pass this on to each of
// its contained monikers.)
// - if the moniker is already a tracking file moniker
// ignore the request.
//
#ifdef _TRACKLINK_
EnableTracking(pmkSrcAbs, OT_READTRACKINGINFO); #endif
m_pMonikerRel = pmkSrcRel; if (pmkSrcRel) { pmkSrcRel->AddRef(); }
m_pMonikerAbs = pmkSrcAbs; if (pmkSrcAbs) { pmkSrcAbs->AddRef(); }
m_clsid = clsid; // just loaded; thus not dirty
m_flags &= ~(DL_DIRTY_LINK);
} else if( error == STG_E_FILENOTFOUND) { // It's OK if the Ole stream doesn't exist.
error = NOERROR;
} else { return error; }
// now load cache from pstg
Assert(m_pCOleCache != NULL);
if(m_dwObjFlags & OBJFLAGS_CACHEEMPTY) { error = m_pCOleCache->Load(pstg, TRUE); if(error != NOERROR) goto errRtn; } else { error = m_pCOleCache->Load(pstg); if(error != NOERROR) goto errRtn; } (m_pStg = pstg)->AddRef();
errRtn: StmRead.Release();
if (pmkSrcAbs) { pmkSrcAbs->Release(); }
if (pmkSrcRel) { pmkSrcRel->Release(); }
if (pstm) { pstm->Release(); }
#ifdef REVIEW
if (error == NOERROR && m_pAppClientSite) { BindIfRunning(); } #endif
logRtn:
LEDebugOut((DEB_TRACE, "%p OUT CDefLink::Load " "( %lx )\n", this, error ));
return error; }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::Save
//
// Synopsis: Saves the link the given storage
//
// Effects:
//
// Arguments: [pstgSave] -- the storage to save into
// [fSameAsLoad] -- FALSE indicates SaveAs operation
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation: IPersistStorage
//
// Algorithm: Writes private ole data (such as the clsid, monikers,
// and update times) and the presentations stored in the
// cache to the given storage
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 03-Aug-94 alexgo stabilized
// 19-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
STDMETHODIMP CDefLink::Save( IStorage *pstgSave, BOOL fSameAsLoad) { HRESULT error = NOERROR; LPSTREAM pstm = NULL; DWORD cbWritten; CStmBufWrite StmWrite; DWORD ObjFlags = 0;
VDATEHEAP(); VDATETHREAD(this);
LEDebugOut((DEB_TRACE, "%p _IN CDefLink::CPeristStgImpl::Save " "( %p , %lu )\n", this, pstgSave, fSameAsLoad ));
VDATEIFACE(pstgSave);
CRefStabilize stabilize(this);
// update any cache which has ADVFCACHE_ONSAVE
UpdateAutoOnSave();
if(fSameAsLoad && !(m_flags & DL_DIRTY_LINK) && (!!(m_dwObjFlags & OBJFLAGS_CACHEEMPTY)==m_pCOleCache->IsEmpty())) { // The storage is not a new one (so we don't need to
// initialize our private data) and the link is not
// dirty, so we just need to delegate to the cache
goto LSaveCache; }
// Obtain cache status
if(m_pCOleCache->IsEmpty()) ObjFlags |= OBJFLAGS_CACHEEMPTY;
// assign object moniker (used by WriteOleStg); we don't save this
// moniker since WriteOleStg gets it again; we also don't care if
// this failes as we don't want a failure here to prevent the link
// from being saved; the assignment might fail if some container has
// yet to be saved to a file. REIVEW PERF: we could pass this mk to
// WriteOleStg. We don't get the moniker for !fSameAsLoad since the
// relative moniker is not correct for the new stg and it causes the
// container to do work in a case for which it might not be prepared.
IMoniker * pMkObjRel;
if (fSameAsLoad && GetMoniker( OLEGETMONIKER_FORCEASSIGN, OLEWHICHMK_OBJREL, &pMkObjRel) == NOERROR) { pMkObjRel->Release(); }
if ((error = WriteOleStgEx(pstgSave,(IOleObject *)this, NULL, ObjFlags, &pstm)) != NOERROR) { goto logRtn; }
Assert(pstm != NULL);
// Write relative source moniker.
// if it is NULL, try to compute it now. We may be saving a file for
// the first time, so the container now has a moniker for the first
// time.
if (m_pMonikerRel == NULL || m_pUnkDelegate) { // if the link is connected, we know that the absolute
// moniker is correct -- it was updated at bind time if
// necessary. If the link container moniker has changed
// (file/saveas) then we can exploit this opportunity to
// straighten things out and improve our link tracking
// since we know which of the two monikers is correct.
UpdateRelMkFromAbsMk(NULL); }
if ((error = WriteMonikerStm (pstm, m_pMonikerRel)) != NOERROR) { goto errRtn; }
#ifdef _TRACKLINK_
EnableTracking(m_pMonikerAbs, OT_ENABLESAVE); #endif
// Write absolute source moniker.
error = WriteMonikerStm (pstm, m_pMonikerAbs);
#ifdef _TRACKLINK_
EnableTracking(m_pMonikerAbs, OT_DISABLESAVE); #endif
if (error != NOERROR) goto errRtn; //
//
//
StmWrite.Init(pstm);
// write last class name
UpdateUserClassID(); if ((error = WriteM1ClassStmBuf(StmWrite, m_clsid)) != NOERROR) { goto errRtn; }
// write last display name, should be NULL if the moniker's are
// non-NULL. For the time being this is always NULL.
if ((error = StmWrite.WriteLong(0)) != NOERROR) { goto errRtn; }
// write -1 as the end marker, so that if we want to extend
// the file formats (ex: adding network name) it will be easier.
if ((error = StmWrite.WriteLong(-1)) != NOERROR) { goto errRtn; }
if ((error = StmWrite.Write(&(m_ltChangeOfUpdate), sizeof(FILETIME))) != NOERROR) { goto errRtn; }
if ((error = StmWrite.Write(&(m_ltKnownUpToDate), sizeof(FILETIME))) != NOERROR) { goto errRtn; }
if ((error = StmWrite.Write(&(m_rtUpdate), sizeof(FILETIME))) != NOERROR) { goto errRtn; }
if ((error = StmWrite.Flush()) != NOERROR) { goto errRtn; }
if (!fSameAsLoad) { // Copy link tracking info
static const LPOLESTR lpszLinkTracker = OLESTR("\1OleLink");
pstgSave->DestroyElement(lpszLinkTracker);
if (m_pStg) { // copy link tracking info, if one existed,
// ignore error
m_pStg->MoveElementTo(lpszLinkTracker, pstgSave, lpszLinkTracker, STGMOVE_COPY); } }
LSaveCache: // last, save cache
Assert(m_pCOleCache != NULL); error = m_pCOleCache->Save(pstgSave, fSameAsLoad);
errRtn: StmWrite.Release();
if (pstm) { pstm->Release(); }
if (error == NOERROR) { m_flags |= DL_NO_SCRIBBLE_MODE; if( fSameAsLoad ) { m_flags |= DL_SAME_AS_LOAD; m_dwObjFlags |= ObjFlags; } else { m_flags &= ~(DL_SAME_AS_LOAD); } }
logRtn:
LEDebugOut((DEB_TRACE, "%p OUT CDefLink::Save " "( %lx )\n", this, error ));
return error; }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::SaveCompleted
//
// Synopsis: Called once the save is completed (for all objects in the
// container). Clear the dirty flag and update the storage
// that we hand onto.
//
// Effects:
//
// Arguments: [pstgNew] -- the new default storage for the object
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation: IPersistStorage
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 03-Aug-94 alexgo stabilized and handle zombie case
// 20-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
STDMETHODIMP CDefLink::SaveCompleted( IStorage *pstgNew) { VDATEHEAP(); VDATETHREAD(this);
LEDebugOut((DEB_TRACE, "%p _IN CDefLink::Save" "Completed ( %p )\n", this, pstgNew ));
if (pstgNew) { VDATEIFACE(pstgNew); }
// don't hang on to the new storage if we're in a zombie state!
if (pstgNew && !IsZombie() ) { if (m_pStg) { m_pStg->Release(); }
m_pStg = pstgNew; pstgNew->AddRef(); }
// REVIEW: do we send on save???
if( (m_flags & DL_SAME_AS_LOAD) || pstgNew) { if( (m_flags & DL_NO_SCRIBBLE_MODE) ) { m_flags &= ~(DL_DIRTY_LINK); }
m_flags &= ~(DL_SAME_AS_LOAD); }
// let the cache know that the save is completed, so that it can clear
// its dirty flag in Save or SaveAs situation, as well as remember the
// new storage pointer if a new one is given
Assert(m_pCOleCache != NULL); m_pCOleCache->SaveCompleted(pstgNew);
m_flags &= ~(DL_NO_SCRIBBLE_MODE);
LEDebugOut((DEB_TRACE, "%p OUT CDefLink::Save" "Completed ( %lx )\n", this, NOERROR ));
return NOERROR; }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::HandsOffStorage
//
// Synopsis: Releases all pointers to the storage (useful for low-mem
// situations)
//
// Effects:
//
// Arguments: void
//
// Requires:
//
// Returns: HRESULT (NOERROR)
//
// Signals:
//
// Modifies:
//
// Derivation: IPersistStorage
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 20-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
STDMETHODIMP CDefLink::HandsOffStorage(void) { VDATEHEAP(); VDATETHREAD(this);
LEDebugOut((DEB_TRACE, "%p _IN CDefLink::HandsOff" "Storage ( )\n", this ));
if (m_pStg) { m_pStg->Release(); m_pStg = NULL; }
Assert(m_pCOleCache != NULL); m_pCOleCache->HandsOffStorage();
LEDebugOut((DEB_TRACE, "%p OUT CDefLink::HandsOff" "Storage ( %lx )\n", this, NOERROR));
return NOERROR; }
/*
* * IMPLEMENTATION of CAdvSinkImpl methods * */
//
// NOTE: Advise Sink is a nested object of Default Link that is exported
// for achieving some of its functionality. This introduces some lifetime
// complications. Can its lifetime be controlled by the server object to
// which it exported its Advise Sink? Ideally, only its client should
// control its lifetime alone, but it should also honor the ref counts
// placed on it by the server object by entering into a zombie state
// to prevent AV's on the incoming calls to the Advise Sink. All needed
// logic is coded into the new class "CRefExportCount" which manages
// the ref and export counts in a thread safe manner and invokes
// appropriate methods during the object's lifetime. Any server objects
// that export nested objects to other server objects should derive from
// "CRefExportCount" class and call its methods to manage their lifetime
// as exemplified in this Default Link implementation.
//
// Gopalk Jan 28, 97
//
//+-------------------------------------------------------------------------
//
// Member: CDefLink::CAdvSinkImpl::QueryInterface
//
// Synopsis: Only supports IUnknown and IAdviseSink
//
// Arguments: [iid] -- Interface requested
// [ppvObj] -- pointer to hold returned interface
//
// Returns: HRESULT
//
// History: dd-mmm-yy Author Comment
// 10-Jan-96 Gopalk Rewritten
//--------------------------------------------------------------------------
STDMETHODIMP CDefLink::CAdvSinkImpl::QueryInterface(REFIID iid, void **ppv) { LEDebugOut((DEB_TRACE,"%p _IN CDefLink::CAdvSinkImpl::QueryInterface()\n", this));
// Validation check
VDATEHEAP(); // Local variables
HRESULT hresult = NOERROR;
if(IsValidPtrOut(ppv, sizeof(void *))) { if(IsEqualIID(iid, IID_IUnknown)) { *ppv = (void *)(IUnknown *) this; } else if(IsEqualIID(iid, IID_IAdviseSink)) { *ppv = (void *)(IAdviseSink *) this; } else { *ppv = NULL; hresult = E_NOINTERFACE; } } else hresult = E_INVALIDARG;
if(hresult == NOERROR) ((IUnknown *) *ppv)->AddRef();
LEDebugOut((DEB_TRACE, "%p OUT CDefLink::CAdvSinkImpl::QueryInterface(%lx)\n", this, hresult));
return hresult; }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::CAdvSinkImpl::AddRef
//
// Synopsis: Increments export count
//
// Returns: ULONG; New export count
//
// History: dd-mmm-yy Author Comment
// 10-Jan-96 Gopalk Rewritten
//--------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CDefLink::CAdvSinkImpl::AddRef( void ) { LEDebugOut((DEB_TRACE, "%p _IN CDefLink::CAdvSinkImpl::AddRef()\n", this));
// Validation check
VDATEHEAP();
// Local variables
CDefLink *pDefLink = GETPPARENT(this, CDefLink, m_AdviseSink); ULONG cExportCount;
// Increment export count
cExportCount = pDefLink->IncrementExportCount();
LEDebugOut((DEB_TRACE, "%p OUT CDefLink::CAdvSinkImpl::AddRef(%ld)\n", this, cExportCount));
return cExportCount; }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::CAdvSinkImpl::Release
//
// Synopsis: Decerement export count and potentially destroy the Link
//
// Returns: ULONG; New export count
//
// History: dd-mmm-yy Author Comment
// 10-Jan-96 Gopalk Rewritten
//--------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CDefLink::CAdvSinkImpl::Release ( void ) { LEDebugOut((DEB_TRACE, "%p _IN CDefLink::CAdvSinkImpl::Release()\n", this)); // Validation check
VDATEHEAP();
// Local variables
CDefLink *pDefLink = GETPPARENT(this, CDefLink, m_AdviseSink); ULONG cExportCount;
// Decrement export count.
cExportCount = pDefLink->DecrementExportCount();
LEDebugOut((DEB_TRACE, "%p OUT CDefLink::CAdvSinkImpl::Release(%ld)\n", this, cExportCount));
return cExportCount; }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::CAdvSinkImpl::OnDataChange
//
// Synopsis: Updates time of change
//
// Arguments: [pFormatetc] -- Data format that changed
// [pStgmed] -- New data
//
// Returns: void
//
// History: dd-mmm-yy Author Comment
// 28-Jan-96 Gopalk Rewritten
//--------------------------------------------------------------------------
STDMETHODIMP_(void) CDefLink::CAdvSinkImpl::OnDataChange(FORMATETC *pFormatetc, STGMEDIUM *pStgmed) { LEDebugOut((DEB_TRACE, "%p _IN CDefLink::CAdvSinkImpl::OnDataChange(%p, %p)\n", this, pFormatetc, pStgmed));
// Validation checks
VDATEHEAP();
// Local variable
CDefLink *pDefLink = GETPPARENT(this, CDefLink, m_AdviseSink);
// Assert that the wild card advise prompted this notification
Win4Assert(pFormatetc->cfFormat == NULL && pFormatetc->ptd == NULL && pFormatetc->dwAspect == -1 && pFormatetc->tymed == -1); Win4Assert(pStgmed->tymed == TYMED_NULL);
// Update time of change for automatic links
if(!pDefLink->IsZombie() && pDefLink->m_dwUpdateOpt==OLEUPDATE_ALWAYS) { // Stabilize
CRefStabilize stabilize(pDefLink); pDefLink->SetUpdateTimes(); }
LEDebugOut((DEB_TRACE, "%p OUT CDefLink::CAdvSinkImpl::OnDataChange()\n", this)); return; }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::CAdvSinkImpl::OnViewChange
//
// Synopsis: Called when the view changes; should never be called for
// links
//
// Effects:
//
// Arguments: [aspects] -- drawing aspect
// [lindex] -- unused
//
// Requires:
//
// Returns: void
//
// Signals:
//
// Modifies:
//
// Derivation: IAdviseSink
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 21-Nov-94 alexgo memory optimization
// 20-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
STDMETHODIMP_(void) CDefLink::CAdvSinkImpl::OnViewChange (DWORD aspects, LONG lindex) { VDATEHEAP();
Assert(FALSE); // never received
}
//+-------------------------------------------------------------------------
//
// Member: CDefLink::CAdvSinkImpl::OnRename
//
// Synopsis: Updates internal monikers to the source object. Turns around
// and informs its advise sinks
//
// Arguments: [pmk] -- New moniker name
//
// Returns: void
//
// History: dd-mmm-yy Author Comment
// 28-Jan-96 Gopalk Rewritten
//--------------------------------------------------------------------------
STDMETHODIMP_(void) CDefLink::CAdvSinkImpl::OnRename(IMoniker *pmk) { LEDebugOut((DEB_TRACE, "%p _IN CDefLink::CAdvSinkImpl::OnRename(%p)\n", this, pmk));
// Validation check
VDATEHEAP();
// Local variable
CDefLink *pDefLink = GETPPARENT(this, CDefLink, m_AdviseSink);
if(!pDefLink->IsZombie()) { CRefStabilize stabilize(pDefLink);
// Release old absolute moniker
if(pDefLink->m_pMonikerAbs) pDefLink->m_pMonikerAbs->Release(); // Remember the new moniker
pDefLink->m_pMonikerAbs = pmk; if(pmk) { // AddRef the new moniker
pmk->AddRef();
//
// Enable tracking on the new moniker
// (this will get a new shellink if neccessary.)
//
#ifdef _TRACKLINK_
pDefLink->EnableTracking(pmk, OT_READTRACKINGINFO); #endif
}
// Update relative moniker from the new absolute moniker
pDefLink->UpdateRelMkFromAbsMk(NULL);
// Name of the link source changed. This has no bearing on the
// name of the link object itself.
if(pDefLink->m_pCOAHolder) pDefLink->m_pCOAHolder->SendOnLinkSrcChange(pmk); }
LEDebugOut((DEB_TRACE, "%p OUT CDefLink::CAdvSinkImpl::OnRename()\n", this)); return; }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::CAdvSinkImpl::OnSave
//
// Synopsis: Updates cache and turns around and informs its advise sinks
//
// Arguments: None
//
// Returns: void
//
// History: dd-mmm-yy Author Comment
// 28-Jan-96 Gopalk Rewritten
//--------------------------------------------------------------------------
STDMETHODIMP_(void) CDefLink::CAdvSinkImpl::OnSave() { LEDebugOut((DEB_TRACE, "%p _IN CDefLink::CAdvSinkImpl::OnSave()\n", this)); // Validation check
VDATEHEAP();
// Local variable
CDefLink *pDefLink = GETPPARENT(this, CDefLink, m_AdviseSink);
if(!pDefLink->IsZombie()) { // Stabilize
CRefStabilize stabilize(pDefLink);
// Turn around and send notification
if(pDefLink->m_pCOAHolder) pDefLink->m_pCOAHolder->SendOnSave();
// Update presentations cached with ADVFCACHE_ONSAVE
pDefLink->UpdateAutoOnSave();
// Update clsid
pDefLink->UpdateUserClassID(); }
LEDebugOut((DEB_TRACE, "%p OUT CDefLink::CAdvSinkImpl::OnSave()\n", this)); return; }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::CAdvSinkImpl::OnClose
//
// Synopsis: Updates time of change and turns around and informs its
// advise sinks.
//
// Arguments: void
//
// Returns: void
//
// History: dd-mmm-yy Author Comment
// 28-Jan-96 Gopalk Rewritten
//--------------------------------------------------------------------------
STDMETHODIMP_(void) CDefLink::CAdvSinkImpl::OnClose(void) { LEDebugOut((DEB_TRACE, "%p _IN CDefLink::CAdvSinkImpl::OnClose()\n", this));
// Validation check
VDATEHEAP();
// Local variable
CDefLink *pDefLink = GETPPARENT(this, CDefLink, m_AdviseSink);
if(!pDefLink->IsZombie()) { // Stabilize
CRefStabilize stabilize(pDefLink);
// Update time of change
if(pDefLink->m_dwUpdateOpt == OLEUPDATE_ALWAYS ) pDefLink->SetUpdateTimes();
// Turn around and send notification
if(pDefLink->m_pCOAHolder) pDefLink->m_pCOAHolder->SendOnClose();
// To be safe, unbind source
pDefLink->UnbindSource(); }
LEDebugOut((DEB_TRACE, "%p OUT CDefLink::CAdvSinkImpl::OnClose()\n", this)); return; }
/*
* IMPLEMENTATION of OleItemContainer methods */
//+-------------------------------------------------------------------------
//
// Member: CDefLink::GetOleItemContainerDelegate (private)
//
// Synopsis: gets the IOleItemContainer from the interface
//
// Effects:
//
// Arguments: void
//
// Requires:
//
// Returns: IOleItemContainer *
//
// Signals:
//
// Modifies:
//
// Derivation:
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
//
// Notes:
// This function may return misleading information if the
// server has died (i.e., you'll return a pointer to a cached
// interface proxy). It is the responsibility of the caller
// to handler server crashes.
//
//--------------------------------------------------------------------------
INTERNAL_(IOleItemContainer *) CDefLink::GetOleItemContainerDelegate(void) { IOleItemContainer *pOleItemContainerDelegate;
VDATEHEAP();
LEDebugOut((DEB_ITRACE, "%p _IN CDefLink::GetOleItemContainerDelegate " "( )\n", this ));
// if we're zombied, then we don't want to QI for a new interface!!
if(!IsZombie()) { DuCacheDelegate(&(m_pUnkDelegate), IID_IOleItemContainer, (LPLPVOID)&m_pOleItemContainerDelegate, NULL);
pOleItemContainerDelegate = m_pOleItemContainerDelegate;
#if DBG == 1
if( m_pOleItemContainerDelegate ) { Assert(m_pUnkDelegate); } #endif // DBG == 1
} else { m_pOleItemContainerDelegate = NULL; }
LEDebugOut((DEB_ITRACE, "%p OUT CDefLink::GetOleItemContainerDelegate " "( %p )\n", this, pOleItemContainerDelegate));
return m_pOleItemContainerDelegate; }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::ReleaseOleItemContainerDelegate (private)
//
// Synopsis: Releases the OleItemContainer pointer to the server
//
// Effects:
//
// Arguments: void
//
// Requires:
//
// Returns: void
//
// Signals:
//
// Modifies:
//
// Derivation:
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
//
// Notes:
//
//--------------------------------------------------------------------------
INTERNAL_(void) CDefLink::ReleaseOleItemContainerDelegate(void) { VDATEHEAP();
LEDebugOut((DEB_ITRACE, "%p _IN CDefLink::ReleaseOleItemContainerDelegate " "( )\n", this ));
if (m_pOleItemContainerDelegate) { SafeReleaseAndNULL((IUnknown **)&m_pOleItemContainerDelegate); }
LEDebugOut((DEB_ITRACE, "%p OUT CDefLink::ReleaseOleItemContainerDelegate " "( )\n", this )); }
//+-------------------------------------------------------------------------
//
// Member: CDefLink::Dump, public (_DEBUG only)
//
// Synopsis: return a string containing the contents of the data members
//
// Effects:
//
// Arguments: [ppszDump] - an out pointer to a null terminated character array
// [ulFlag] - flag determining prefix of all newlines of the
// out character array (default is 0 - no prefix)
// [nIndentLevel] - will add a indent prefix after the other prefix
// for ALL newlines (including those with no prefix)
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies: [ppszDump] - argument
//
// Derivation:
//
// Algorithm: use dbgstream to create a string containing information on the
// content of data structures
//
// History: dd-mmm-yy Author Comment
// 01-Feb-95 t-ScottH author
//
// Notes:
//
//--------------------------------------------------------------------------
#ifdef _DEBUG
HRESULT CDefLink::Dump(char **ppszDump, ULONG ulFlag, int nIndentLevel) { int i; char *pszPrefix; char *pszCSafeRefCount; char *pszCThreadCheck; char *pszCLSID; char *pszCOleCache; char *pszCOAHolder; char *pszDAC; char *pszFILETIME; char *pszMonikerDisplayName; dbgstream dstrPrefix; dbgstream dstrDump(5000);
// determine prefix of newlines
if ( ulFlag & DEB_VERBOSE ) { dstrPrefix << this << " _VB "; }
// determine indentation prefix for all newlines
for (i = 0; i < nIndentLevel; i++) { dstrPrefix << DUMPTAB; }
pszPrefix = dstrPrefix.str();
// put data members in stream
pszCThreadCheck = DumpCThreadCheck((CThreadCheck *)this, ulFlag, nIndentLevel + 1); dstrDump << pszPrefix << "CThreadCheck:" << endl; dstrDump << pszCThreadCheck; CoTaskMemFree(pszCThreadCheck);
// only vtable pointers (plus we don't get the right address in debugger extensions)
// dstrDump << pszPrefix << "&IUnknown = " << &m_Unknown << endl;
// dstrDump << pszPrefix << "&IAdviseSink = " << &m_AdviseSink << endl;
dstrDump << pszPrefix << "Link flags = "; if (m_flags & DL_SAME_AS_LOAD) { dstrDump << "DL_SAME_AS_LOAD "; } if (m_flags & DL_NO_SCRIBBLE_MODE) { dstrDump << "DL_NO_SCRIBBLE_MODE "; } if (m_flags & DL_DIRTY_LINK) { dstrDump << "DL_DIRTY_LINK "; } if (m_flags & DL_LOCKED_CONTAINER) { dstrDump << "DL_LOCKED_CONTAINER "; } // if none of the flags are set...
if ( !( (m_flags & DL_SAME_AS_LOAD) | (m_flags & DL_LOCKED_CONTAINER) | (m_flags & DL_NO_SCRIBBLE_MODE) | (m_flags & DL_DIRTY_LINK))) { dstrDump << "No FLAGS SET!"; } dstrDump << "(" << LongToPtr(m_flags) << ")" << endl;
dstrDump << pszPrefix << "pIOleObject Delegate = " << m_pOleDelegate << endl;
dstrDump << pszPrefix << "pIDataObject Delegate = " << m_pDataDelegate << endl;
dstrDump << pszPrefix << "pIRunnableObject Delegate = " << m_pRODelegate << endl;
dstrDump << pszPrefix << "No. of Refs. on Link = " << m_cRefsOnLink << endl;
dstrDump << pszPrefix << "pIUnknown pUnkOuter = "; if (m_flags & DL_AGGREGATED) { dstrDump << "AGGREGATED (" << m_pUnkOuter << ")" << endl; } else { dstrDump << "NO AGGREGATION (" << m_pUnkOuter << ")" << endl; }
dstrDump << pszPrefix << "pIMoniker Absolute = " << m_pMonikerAbs << endl;
if (m_pMonikerAbs != NULL) { pszMonikerDisplayName = DumpMonikerDisplayName(m_pMonikerAbs); dstrDump << pszPrefix << "pIMoniker Absolute = "; dstrDump << pszMonikerDisplayName; dstrDump << "( " << m_pMonikerAbs << " )" << endl; CoTaskMemFree(pszMonikerDisplayName); } else { dstrDump << pszPrefix << "pIMoniker Absolute = NULL or unable to resolve" << endl; }
if (m_pMonikerRel != NULL) { pszMonikerDisplayName = DumpMonikerDisplayName(m_pMonikerRel); dstrDump << pszPrefix << "pIMoniker Relative = "; dstrDump << pszMonikerDisplayName; dstrDump << "( " << m_pMonikerRel << " )" << endl; CoTaskMemFree(pszMonikerDisplayName); } else { dstrDump << pszPrefix << "pIMoniker Absolute = NULL or unable to resolve" << endl; }
dstrDump << pszPrefix << "pIUnknown Delegate = " << m_pUnkDelegate << endl;
dstrDump << pszPrefix << "OLEUPDATE flags = "; if (m_dwUpdateOpt & OLEUPDATE_ALWAYS) { dstrDump << "OLEUPDATE_ALWAYS "; } else if (m_dwUpdateOpt & OLEUPDATE_ONCALL) { dstrDump << "OLEUPDATE_ONCALL "; } else { dstrDump << "No FLAGS SET!"; } dstrDump << "(" << LongToPtr(m_flags) << ")" << endl;
pszCLSID = DumpCLSID(m_clsid); dstrDump << pszPrefix << "Last known CLSID of link = " << pszCLSID << endl; CoTaskMemFree(pszCLSID);
dstrDump << pszPrefix << "pIStorage = " << m_pStg << endl;
if (m_pCOleCache != NULL) { // pszCOleCache = DumpCOleCache(m_pCOleCache, ulFlag, nIndentLevel + 1);
dstrDump << pszPrefix << "COleCache: " << endl; // dstrDump << pszCOleCache;
// CoTaskMemFree(pszCOleCache);
} else { dstrDump << pszPrefix << "pCOleCache = " << m_pCOleCache << endl; }
if (m_pCOAHolder != NULL) { pszCOAHolder = DumpCOAHolder(m_pCOAHolder, ulFlag, nIndentLevel + 1); dstrDump << pszPrefix << "COAHolder: " << endl; dstrDump << pszCOAHolder; CoTaskMemFree(pszCOAHolder); } else { dstrDump << pszPrefix << "pCOAHolder = " << m_pCOAHolder << endl; }
dstrDump << pszPrefix << "OLE Connection Advise ID = " << m_dwConnOle << endl;
if (m_pDataAdvCache != NULL) { pszDAC = DumpCDataAdviseCache(m_pDataAdvCache, ulFlag, nIndentLevel + 1); dstrDump << pszPrefix << "CDataAdviseCache: " << endl; dstrDump << pszDAC; CoTaskMemFree(pszDAC); } else { dstrDump << pszPrefix << "pCDataAdviseCache = " << m_pDataAdvCache << endl; }
dstrDump << pszPrefix << "pIOleClientSite = " << m_pAppClientSite << endl;
dstrDump << pszPrefix << "Connection for time = " << m_dwConnTime << endl;
pszFILETIME = DumpFILETIME(&m_ltChangeOfUpdate); dstrDump << pszPrefix << "Change of update filetime = " << pszFILETIME << endl; CoTaskMemFree(pszFILETIME);
pszFILETIME = DumpFILETIME(&m_ltKnownUpToDate); dstrDump << pszPrefix << "Known up to date filetime = " << pszFILETIME << endl; CoTaskMemFree(pszFILETIME);
pszFILETIME = DumpFILETIME(&m_rtUpdate); dstrDump << pszPrefix << "Update filetime = " << pszFILETIME << endl; CoTaskMemFree(pszFILETIME);
// cleanup and provide pointer to character array
*ppszDump = dstrDump.str();
if (*ppszDump == NULL) { *ppszDump = UtDupStringA(szDumpErrorMessage); }
CoTaskMemFree(pszPrefix);
return NOERROR; }
#endif // _DEBUG
//+-------------------------------------------------------------------------
//
// Function: DumpCDefLink, public (_DEBUG only)
//
// Synopsis: calls the CDefLink::Dump method, takes care of errors and
// returns the zero terminated string
//
// Effects:
//
// Arguments: [pDL] - pointer to CDefLink
// [ulFlag] - flag determining prefix of all newlines of the
// out character array (default is 0 - no prefix)
// [nIndentLevel] - will add a indent prefix after the other prefix
// for ALL newlines (including those with no prefix)
//
// Requires:
//
// Returns: character array of structure dump or error (null terminated)
//
// Signals:
//
// Modifies:
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 01-Feb-95 t-ScottH author
//
// Notes:
//
//--------------------------------------------------------------------------
#ifdef _DEBUG
char *DumpCDefLink(CDefLink *pDL, ULONG ulFlag, int nIndentLevel) { HRESULT hresult; char *pszDump;
if (pDL == NULL) { return UtDupStringA(szDumpBadPtr); }
hresult = pDL->Dump(&pszDump, ulFlag, nIndentLevel);
if (hresult != NOERROR) { CoTaskMemFree(pszDump);
return DumpHRESULT(hresult); }
return pszDump; }
#endif // _DEBUG
|