316 lines
8.7 KiB
C++
316 lines
8.7 KiB
C++
|
||
//+-------------------------------------------------------------------------
|
||
//
|
||
// 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;
|
||
}
|
||
|
||
|
||
|