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;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|