windows-nt/Source/XPSP1/NT/com/ole32/ole232/stdimpl/deflink.cpp

7585 lines
186 KiB
C++
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
//+-------------------------------------------------------------------------
//
// 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