|
|
//+-------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1993.
//
// File: defutil.cpp
//
// Contents: Implementations of utility functions for the default
// handler and default link objects
//
// Classes: none
//
// Functions: DuLockContainer
// DuSetClientSite
// DuGetClientSite
// DuCacheDelegate
//
// History: dd-mmm-yy Author Comment
// 11-Jan-94 alexgo added VDATEHEAP macros to every function
// 20-Nov-93 alexgo 32bit port
//
//--------------------------------------------------------------------------
#include <le2int.h>
#pragma SEG(defutil)
#include <olerem.h>
#include <ole2dbg.h>
ASSERTDATA NAME_SEG(defutil)
//+-------------------------------------------------------------------------
//
// Function: DuLockContainer
//
// Synopsis: Calls IOleContainer->LockContainer from the given client site
//
// Effects: Unlocking the container may release the calling object.
//
// Arguments: [pCS] -- the client site from which to get
// the IOleContainer pointer
// [fLockNew] -- TRUE == lock, FALSE == unlock
// [pfLockCur] -- pointer to a flag with the current lock
// state
//
// Requires:
//
// Returns: void
//
// Signals:
//
// Modifies:
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 20-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
#pragma SEG(DuLockContainer)
INTERNAL_(void) DuLockContainer(IOleClientSite FAR* pCS, BOOL fLockNew, BOOL FAR*pfLockCur) { VDATEHEAP();
#ifdef _DEBUG
BOOL fLocked = FALSE; // used only for debugging so don't waste
// the code space in the retail version
#endif // _DEBUG
IOleContainer FAR* pContainer;
//the double bang turns each into a true boolean
if (!!fLockNew == !!*pfLockCur) { // already locked as needed
return; }
// set flag to false first since unlocking container may release obj;
// we can just set to false since it is either already false or going
// to become false (don't set to true until we know the lock completed).
*pfLockCur = FALSE;
if (pCS == NULL) { pContainer = NULL; } else { HRESULT hresult = pCS->GetContainer(&pContainer);
// Excel 5 can return S_FALSE, pContainer == NULL
// so we can't use AssertOutPtrIface here since it
// expects all successful returns to provide a
// valid interface
if (hresult != NOERROR) { pContainer = NULL; // just in case
} } if (pContainer != NULL) { // we assume that LockContainer will succeed first and
// and set the locked flag that was passed into us. This
// way, if LockContainer succeeeds, we won't access memory
// that could have potentially been blown away.
// If it *fails*, then we handle reset the flag (as our
// memory would not have been free'd)
BOOL fLockOld = *pfLockCur; *pfLockCur = fLockNew;
if( pContainer->LockContainer(fLockNew) != NOERROR ) { //failure case, we were not deleted
*pfLockCur = fLockOld; //fLocked is FALSE
} #ifdef _DEBUG
else { fLocked = TRUE; } #endif // _DEBUG
pContainer->Release(); }
}
//+-------------------------------------------------------------------------
//
// Function: DuSetClientSite
//
// Synopsis: Called by the default handler and deflink SetClientSite
// implemenations; Releases the old client site (and unlocks
// its container), stores the client site (locking its
// container).
//
// Effects:
//
// Arguments: [fRunning] -- whether or not the delegate is running
// [pCSNew] -- the new client site
// [ppCSCur] -- a pointer to the original client site
// pointer. [*ppCSCur] will be reset
// to the new client site pointer.
// [pfLockCur] -- pointer to the fLocked flag, used by
// DuLockContainer.
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 22-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
#pragma SEG(DuSetClientSite)
INTERNAL DuSetClientSite(BOOL fRunning, IOleClientSite FAR* pCSNew, IOleClientSite FAR* FAR* ppCSCur, BOOL FAR*pfLockCur) {
VDATEHEAP();
if (pCSNew) { VDATEIFACE( pCSNew ); }
IOleClientSite FAR* pCSOldClientSite = *ppCSCur; BOOL fLockOldClientSite = *pfLockCur;
*pfLockCur = FALSE; // New ClientSite is not Locked.
if ((*ppCSCur = pCSNew) != NULL) {
// we've decided to keep the pointer that's been passed to us. So we
// must AddRef() and Lock if in Running state.
pCSNew->AddRef();
// Lock the newcontainer
if (fRunning) { DuLockContainer(pCSNew, TRUE, pfLockCur); } }
// If Already Had a ClientSite, Unlock and Free
if (pCSOldClientSite != NULL) { // Unlock the old container
if (fRunning) { DuLockContainer(pCSOldClientSite, FALSE, &fLockOldClientSite); }
pCSOldClientSite->Release(); }
return NOERROR; }
//+-------------------------------------------------------------------------
//
// Function: DuCacheDelegate
//
// Synopsis: Retrieves the requested interface from [pUnk]. If [fAgg] is
// true, we release the pointer (so ref counts to not get
// obfuscated ;-)
//
// Effects:
//
// Arguments: [ppUnk] -- the object to QueryInterface on
// [iid] -- the requested interface
// [ppv] -- where to put the pointer to the interface
// [pUnkOuter] -- controlling unknown, if non-NULL indicates
// aggregation and release is called on it
//
//
//
// Requires:
//
// Returns: void *, the requested interface pointer
//
// Signals:
//
// Modifies:
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 29-Jun-94 alexgo better handle re-entrancy
// 20-Jun-94 alexgo updated to May '94 aggregation rules
// 22-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
#pragma SEG(DuCacheDelegate)
INTERNAL_(void FAR*) DuCacheDelegate(IUnknown FAR** ppUnk, REFIID iid, LPVOID FAR* ppv, IUnknown *pUnkOuter) { VDATEHEAP();
if (*ppUnk != NULL && *ppv == NULL) { if ((*ppUnk)->QueryInterface (iid, ppv) == NOERROR) { // the QI may actually be an outgoing call so it
// is possible that ppUnk was released and set to
// NULL during our call. To make the default link
// and handler simpler, we check for that case and
// release any pointer we may have obtained
// from the QI
if( *ppUnk == NULL ) { LEDebugOut((DEB_WARN, "WARNING: Delegate " "released during QI, should be OK\n")); if( *ppv ) { // this should never be a final
// release on the default handler
// since we are calling it from
// within a method in the default
// link object. Therefore,
// we do not need to guard this
// release
//
// in the case of the link object,
// this may be the final release
// on the proxies, but since they are
// not aggregated into the link
// object, that's OK.
(*(IUnknown **)ppv)->Release(); *ppv = NULL; } } if( pUnkOuter && *ppv) { // we will keep the pointer but we don't want
// to bump the ref count of the aggregate,
// so we gotta do Release() on the controlling
// unknown.
pUnkOuter->Release(); } } }
return *ppv; }
|