Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

3428 lines
84 KiB

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1993 - 1993.
//
// File: ccompmon.cxx
//
// Contents: Generic Composite Monikers
//
// Classes:
//
// Functions:
//
// History: 12-27-93 ErikGav Commented
// 02-01-94 KevinRo Gagged on it, then tried to explain
// 06-14-94 Rickhi Fix type casting
// 08-08-94 BruceMa Memory sift fix
// 10-Jan-95 BruceMa Conform MonikerRelativePathTo to spec
// 03-Apr-96 BruceMa Fix ::IsEqual
// 22-May-96 BruceMa Re fix ::IsEqual
//
//
// Composite monikers are implemented here. A composite moniker is created
// as a binary tree of monikers, with the leaf nodes of the tree being
// non-composite monikers.
//
// Every composite moniker has a left and a right part (otherwise it
// wouldn't be a composite moniker). The composition of two monikers
// involves creating a new composite, and pointing left and right at
// the two parts of the composite. This is how the binary tree is
// built.
//
// (Note: This may not be the most efficient way of implementing this,
// but it is legacy code we are going to adopt. Sorry!)
//
// The ordering in the tree is left most. Therefore, there are many
// possible tree configurations, as long as the leaf nodes evaluate
// to the same order when done left to right. This is an important point
// to keep in mind when you are looking at some of the functions, such
// as AllButFirst, which creates a new composite tree. At first, it doesn't
// appear to do the correct thing, until you draw it out on paper, and
// realize that the nodes are still visited in the same order.
//
//----------------------------------------------------------------------------
#include <ole2int.h>
#include "cbasemon.hxx"
#include "ccompmon.hxx"
#include "cfilemon.hxx"
#include "mnk.h"
#include <rotdata.hxx>
#include <olepfn.hxx>
INTERNAL_(CCompositeMoniker *) IsCompositeMoniker ( LPMONIKER pmk )
{
CCompositeMoniker *pCMk;
if ((pmk->QueryInterface(CLSID_CompositeMoniker, (void **)&pCMk)) == S_OK)
{
// the Release the AddRef done by QI, but still return the ptr
pCMk->Release();
return pCMk;
}
// dont rely on user implementations to set pCMk to NULL on failed QI
return NULL;
}
CCompositeMoniker::CCompositeMoniker( void ) CONSTR_DEBUG
{
m_pmkLeft = NULL;
m_pmkRight = NULL;
m_fReduced = FALSE;
#ifdef _TRACKLINK_
_tcm.SetParent(this);
m_fReduceForced = FALSE;
#endif
//
// CoQueryReleaseObject needs to have the address of the this objects
// query interface routine.
//
if (adwQueryInterfaceTable[QI_TABLE_CCompositeMoniker] == 0)
{
adwQueryInterfaceTable[QI_TABLE_CCompositeMoniker] =
**(DWORD **)((IMoniker *)this);
}
}
/*
* Implementation of CCompositeMoniker
*/
CCompositeMoniker::~CCompositeMoniker( void )
{
mnkDebugOut((DEB_ITRACE,
"CCompositeMoniker::~CCompositeMoniker(%x)\n",
this));
// REVIEW: this is recursive deletion of what is essentially a linked
// list. A rewrite could save stack space.
if (m_pmkLeft)
{
m_pmkLeft->Release();
}
if (m_pmkRight)
{
m_pmkRight->Release();
}
}
//
// BUGBUG: (KevinRo) Other parts of the code depend on composite monikers ALWAYS
// having at two parts. This code allows zero or one part. Why?
//
// Turns out that the classfactory for this moniker will create an empty
// instance by called ::Create(NULL,NULL). The create function has been
// changed to special case this condition, and NOT call initialize.
//
INTERNAL_(BOOL) CCompositeMoniker::Initialize( LPMONIKER pmkFirst,
LPMONIKER pmkRest)
{
mnkDebugOut((DEB_ITRACE,
"CCompositeMoniker::Initialize(%x)\n",
this));
//
// Neither moniker can be NULL
//
if ((pmkFirst == NULL) || (pmkRest == NULL))
{
return(FALSE);
}
GEN_VDATEIFACE(pmkFirst, FALSE);
GEN_VDATEIFACE(pmkRest, FALSE);
m_pmkLeft = pmkFirst;
pmkFirst->AddRef();
m_pmkRight = pmkRest;
pmkRest->AddRef();
m_fReduced = IsReduced(pmkFirst) && IsReduced(pmkRest);
return TRUE;
}
//+---------------------------------------------------------------------------
//
// Method: CCompositeMoniker::Create
//
// Synopsis:
//
// Effects:
//
// Arguments: [pmkFirst] --
// [pmkRest] --
// [memLoc] --
//
// Requires:
//
// Returns:
//
// Signals:
//
// Modifies:
//
// Derivation:
//
// Algorithm:
//
// History: 2-03-94 kevinro Commented
//
// Notes:
//
// We assume that *pmkFirst is not capable of collapsing with *pmkRest;
// otherwise, this would not have been called.
//
//----------------------------------------------------------------------------
CCompositeMoniker FAR *
CCompositeMoniker::Create( LPMONIKER pmkFirst, LPMONIKER pmkRest)
{
mnkDebugOut((DEB_ITRACE,
"CCompositeMoniker::Create()\n"));
//
// Create can be called with both pointers being NULL, in which
// case the Initialize function need not be called. This is the
// case when a CompositeMoniker is being loaded from stream.
//
// Either both are NULL, or neither is NULL
//
if ((pmkFirst == NULL) || (pmkRest == NULL))
{
//
// One of them is NULL. If the other isn't NULL, return an error
//
if (pmkFirst != pmkRest)
{
return NULL;
}
}
//
// Both pointers are not NULL, initialize the moniker
//
CCompositeMoniker FAR * pCM = new CCompositeMoniker();
if (pCM != NULL)
{
pCM->AddRef();
if (pmkFirst != NULL || pmkRest != NULL)
{
if (!pCM->Initialize( pmkFirst, pmkRest ))
{
delete pCM;
return NULL;
}
}
}
CALLHOOKOBJECTCREATE(S_OK,CLSID_NULL,IID_IMoniker,(IUnknown **)&pCM);
return pCM;
}
STDMETHODIMP CCompositeMoniker::QueryInterface(THIS_ REFIID riid,
LPVOID FAR* ppvObj)
{
VDATEIID (riid);
VDATEPTROUT(ppvObj, LPVOID);
#ifdef _DEBUG
if (riid == IID_IDebug)
{
*ppvObj = &(m_Debug);
return NOERROR;
}
#endif
#ifdef _TRACKLINK_
if (IsEqualIID(riid, IID_ITrackingMoniker))
{
AddRef();
*ppvObj = (ITrackingMoniker *) & _tcm;
return(S_OK);
}
#endif
if (IsEqualIID(riid, CLSID_CompositeMoniker))
{
// called by IsCompositeMoniker.
AddRef();
*ppvObj = this;
return S_OK;
}
else if (IsEqualIID(riid, IID_IROTData))
{
AddRef();
*ppvObj = (IROTData *) this;
return S_OK;
}
return CBaseMoniker::QueryInterface(riid, ppvObj);
}
STDMETHODIMP_(ULONG) CCompositeMoniker::Release(void)
{
M_PROLOG(this);
ULONG ul = m_refs;
if (InterlockedDecrement((long *)&m_refs) == 0)
{
delete this;
return 0;
}
return ul - 1;
}
STDMETHODIMP CCompositeMoniker::GetClassID (THIS_ LPCLSID lpClassID)
{
VDATEPTROUT(lpClassID, CLSID);
*lpClassID = CLSID_CompositeMoniker;
return NOERROR;
}
//+---------------------------------------------------------------------------
//
// Method: CCompositeMoniker::Load
//
// Synopsis: Loads a composite moniker from stream
//
// Effects:
//
// Arguments: [pStm] --
//
// Requires:
//
// Returns:
//
// Signals:
//
// Modifies:
//
// Derivation:
//
// Algorithm:
//
// History: 2-03-94 kevinro Commented
//
// Notes:
// The serialized form of a composite moniker is a ULONG count of
// monikers, followed by each non-composite moniker written
// left to right.
//
// WARNING: Be very careful with the refernce counting in this routine.
//
//----------------------------------------------------------------------------
STDMETHODIMP CCompositeMoniker::Load (THIS_ LPSTREAM pStm)
{
mnkDebugOut((DEB_ITRACE,
"CCompositeMoniker::Load(%x)\n",this));
VDATEIFACE(pStm);
ULONG cMonikers = 0;
ULONG n;
LPMONIKER pmk;
LPMONIKER pmkPrev = NULL;
HRESULT hresult;
//
// Monikers are immutable, so this is called only when creating a
// moniker, and so we assert if this moniker is not newly created.
//
Assert(m_pmkLeft == NULL && m_pmkRight == NULL);
if ((m_pmkLeft != NULL) || (m_pmkRight != NULL ))
{
return(E_UNEXPECTED);
}
// There is no collapsing of successive pieces of the moniker, since
// this was once written to disk, and the collapsing would have happened
// before that.
hresult = StRead(pStm, (LPVOID)&cMonikers, sizeof(ULONG));
if (FAILED(hresult))
{
goto errRet;
}
// some plausibility checking on cMonikers might be appropriate
// if there is only one, we shouldn't have had a composite moniker
Assert( cMonikers >= 2 );
if (cMonikers < 2)
{
hresult = E_UNEXPECTED;
goto errRet;
}
//
// Note: n is used 1 based, since this loop does something special on the
// last moniker.
//
for (n = 1; n <= cMonikers; n++ )
{
//
// After loading the reference count for the new moniker will == 1
//
hresult = OleLoadFromStream(pStm, IID_IMoniker, (LPVOID FAR*)&pmk);
if (FAILED(hresult))
{
goto errRet;
}
//
// If this is the last moniker, then it will be the right moniker
// to 'this' composite moniker.
//
if (n == cMonikers) // this is the last moniker read
{
//
// Save away the pointer into the right moniker for this instance
// of the composite.
// The reference count is OK, since it was set to 1 on creation,
// and we are saving it
//
m_pmkRight = pmk;
//
// AddRef not needed, its already 1, and we are supposed to
// exit the loop
//
m_pmkLeft = pmkPrev;
Assert( pmkPrev != NULL );
}
else if (pmkPrev == NULL)
{
pmkPrev = pmk;
}
else
{
LPMONIKER pmkTemp;
//
// Warning: Here is some tricky stuff. pmkPrev has a reference
// of 1 at the moment, because thats how we created it.
//
// pmk also has a refcount == 1
//
// We are going to create another composite, of which they will
// become members. The Create function is going to increment
// both (making them 2).
//
pmkTemp = CCompositeMoniker::Create(pmkPrev,
pmk);
if (pmkTemp == NULL)
{
hresult = E_OUTOFMEMORY;
goto errRet;
}
//
// The new moniker is holding refcounts to both monikers that
// are not needed. Releasing these two sets the refcounts
// back to 1 like they should be.
//
pmkPrev->Release();
pmk->Release();
//
// Now, pmkPrev gets the new composite.
//
pmkPrev = pmkTemp;
}
//
// pmk has been given to another pointer. NULL it out in case
// there is an error later, so we don't try to release it too
// many times.
//
pmk = NULL;
}
//
// Exiting at this point leaves the moniker pointed to by pmkPrev
//
return(NOERROR);
errRet:
if (pmkPrev != NULL)
{
pmkPrev->Release();
}
if (pmk != NULL)
{
pmk->Release();
}
return hresult;
}
INTERNAL_(ULONG) CCompositeMoniker::Count(void)
{
M_PROLOG(this);
CCompositeMoniker *pCMk = IsCompositeMoniker(m_pmkLeft);
ULONG cMk = (pCMk) ? pCMk->Count() : 1;
Assert(m_pmkLeft != NULL);
pCMk = IsCompositeMoniker(m_pmkRight);
cMk += (pCMk) ? pCMk->Count() : 1;
Assert(cMk >= 2);
return cMk;
}
//+---------------------------------------------------------------------------
//
// Method: CCompositeMoniker::Save
//
// Synopsis: Save the composite to a stream
//
// Effects:
//
// Arguments: [pStm] --
// [fClearDirty] --
//
// Requires:
//
// Returns:
//
// Signals:
//
// Modifies:
//
// Derivation:
//
// Algorithm:
//
// History: 2-03-94 kevinro Commented
//
// Notes:
//
// The serialized form of a composite moniker is a ULONG count of
// monikers, followed by each non-composite moniker written
// left to right.
//
//----------------------------------------------------------------------------
STDMETHODIMP CCompositeMoniker::Save (THIS_ LPSTREAM pStm, BOOL fClearDirty)
{
mnkDebugOut((DEB_ITRACE,
"CCompositeMoniker::Save(%x)\n",this));
VDATEIFACE(pStm);
ULONG cMonikers; // count of monikers in this composite.
HRESULT hresult;
LPENUMMONIKER pEnum;
LPMONIKER pmk;
ULONG i;
cMonikers = Count();
hresult = pStm->Write(&cMonikers, sizeof(ULONG), NULL);
if (FAILED(hresult))
{
goto errRet;
}
//
// Write out left to right using enumerator.
//
hresult = Enum(TRUE, &pEnum);
if (hresult != NOERROR)
{
goto errRet;
}
if (pEnum != NULL)
{
for( i = 0; i < cMonikers; i++)
{
hresult = pEnum->Next(1, &pmk, NULL);
if (hresult != NOERROR)
{
if (S_FALSE == hresult)
{
//
// If the enumerator returns S_FALSE, then it has no more
// monikers to hand out. This is bad, since we haven't
// written out the number of monikers we were supposed to.
// Therefore, it is an E_UNEXPECTED error
//
hresult = E_UNEXPECTED;
}
goto errRet;
}
//
// If pmk is NULL, something seriously wrong happened.
//
if (pmk == NULL)
{
hresult = E_UNEXPECTED;
goto errRet;
}
hresult = OleSaveToStream( pmk, pStm );
pmk->Release();
if (hresult != NOERROR)
{
goto errRet;
}
}
pEnum->Release();
}
else
{
//
// If we get here, and cMonikers isn't 0, something else happened
//
if (cMonikers != 0)
{
hresult = E_UNEXPECTED;
}
}
errRet:
return hresult;
}
//+---------------------------------------------------------------------------
//
// Method: CCompositeMoniker::GetSizeMax
//
// Synopsis: Return the maximum size required to marshal this composite
//
// Effects:
//
// Arguments: [pcbSize] --
//
// Requires:
//
// Returns:
//
// Signals:
//
// Modifies:
//
// Derivation:
//
// Algorithm:
//
// History: 2-03-94 kevinro Commented
//
// Notes:
//
//----------------------------------------------------------------------------
STDMETHODIMP CCompositeMoniker::GetSizeMax (ULARGE_INTEGER FAR * pcbSize)
{
mnkDebugOut((DEB_ITRACE,
"CCompositeMoniker::GetSizeMax(%x)\n",this));
VDATEPTROUT(pcbSize, ULARGE_INTEGER);
LPENUMMONIKER pEnum = NULL;
LPMONIKER pmk = NULL;
HRESULT hresult;
ULARGE_INTEGER cbSize2;
//
// The composite itself writes out a CLSID and a count of monikers
//
ULONG cbSize = sizeof(CLSID) + sizeof(ULONG);
//
// Use an enumerator to walk the list of monikers
//
hresult = Enum(TRUE, &pEnum);
if (hresult != NOERROR)
{
goto errRet;
}
Assert(pEnum != NULL);
while (TRUE)
{
hresult = pEnum->Next(1, &pmk, NULL);
if (hresult != NOERROR)
{
if (hresult == S_FALSE)
{
//
// S_FALSE is the 'done' code
//
hresult = NOERROR;
}
goto errRet;
}
Assert(pmk != NULL);
cbSize2.LowPart = cbSize2.HighPart = 0;
hresult = pmk->GetSizeMax(&cbSize2);
pmk->Release();
if (hresult)
{
goto errRet;
}
//
// The sub-GetSizeMax's don't account for the GUID
// that OleSaveToStream writes on the monikers behalf.
// Therefore, we will add it in on our own.
//
cbSize += cbSize2.LowPart + sizeof(GUID);
}
errRet:
if (pEnum)
{
pEnum->Release();
}
ULISet32(*pcbSize,cbSize);
RESTORE_A5();
return hresult;
}
//+---------------------------------------------------------------------------
//
// Method: CCompositeMoniker::AllButLast
//
// Synopsis:
//
// returns a moniker that consists of all but the last moniker of this
// composite. Since a composite must have at least two pieces, this will
// never be zero, but it may not be a composite.
//
// Effects:
//
// Arguments: [void] --
//
// Requires:
//
// Returns:
//
// Signals:
//
// Modifies:
//
// Derivation:
//
// Algorithm:
//
// History: 2-03-94 kevinro Commented
// 17-May-94 AlexT Plug memory leak, check for error
//
// Notes:
//
//----------------------------------------------------------------------------
INTERNAL_(LPMONIKER)
CCompositeMoniker::AllButLast(void)
{
mnkDebugOut((DEB_ITRACE,
"CCompositeMoniker::AllButLast(%x)\n",this));
LPMONIKER pmk;
Assert(m_pmkRight != NULL );
//
// Recurse down the right branch of the tree until a non composite moniker
// is found. When a non-composite right most moniker is found, return the
// left part of the tree. As the recurse unwinds, a new composite is
// formed from each intermediate node.
//
// Yeah, I know, its seems expensive. However, composite monikers are
// fairly cheap to allocate (no strings or stuff). The average
// composite moniker only has one or two nodes, so this isn't as bad
// as you might think. In theory, there are only LOG2(n) nodes created,
// where n == number of parts in the composite.
//
CCompositeMoniker *pCMk = IsCompositeMoniker(m_pmkRight);
if (pCMk)
{
LPMONIKER pmkRight;
pmkRight = pCMk->AllButLast();
if (NULL == pmkRight)
{
// We didn't get back a moniker from AllButLast, even though
// pmkRight is a composite moniker. Probably out of memory...
mnkDebugOut((DEB_WARN,
"CCompositeMoniker::AllButLast recursive call "
"returned NULL\n"));
pmk = NULL;
}
else
{
pmk = CCompositeMoniker::Create(m_pmkLeft, pmkRight);
pmkRight->Release();
}
}
else
{
Assert(m_pmkLeft != NULL && "Bad composite moniker");
pmk = m_pmkLeft;
pmk->AddRef();
}
return pmk;
}
//+---------------------------------------------------------------------------
//
// Method: CCompositeMoniker::Last
//
// Synopsis:
// return the last moniker in the composite list. It is guaranteed to be
// non-null and non-composite
//
// Effects:
//
// Arguments: [void] --
//
// Requires:
//
// Returns:
//
// Signals:
//
// Modifies:
//
// Derivation:
//
// Algorithm:
//
// History: 2-03-94 kevinro Commented
//
// Notes:
//
//----------------------------------------------------------------------------
INTERNAL_(LPMONIKER)
CCompositeMoniker::Last(void)
{
mnkDebugOut((DEB_ITRACE,
"CCompositeMoniker::Last(%x)\n",this));
CCompositeMoniker FAR * pCM = this;
CCompositeMoniker FAR * pCMNext;
//
// Run down the right side of the tree, looking for a non-composite
// right moniker (the leaf node).
//
while ((pCMNext = IsCompositeMoniker(pCM->m_pmkRight)) != NULL)
{
pCM = pCMNext;
}
IMoniker *pmk = pCM->m_pmkRight;
Assert(pmk != NULL && (!IsCompositeMoniker(pmk)));
pmk->AddRef();
return pmk;
}
//+---------------------------------------------------------------------------
//
// Method: CCompositeMoniker::AllButFirst
//
// Synopsis:
// returns a moniker that consists of all but the first moniker of this
// composite. Since a composite must have at least two pieces, this will
// never be zero, but it may not be a composite.
//
// Effects:
//
// Arguments: [void] --
//
// Requires:
//
// Returns:
//
// Signals:
//
// Modifies:
//
// Derivation:
//
// Algorithm:
//
// History: 2-03-94 kevinro Commented
//
// Notes:
//
//----------------------------------------------------------------------------
INTERNAL_(LPMONIKER)
CCompositeMoniker::AllButFirst(void)
{
mnkDebugOut((DEB_ITRACE,
"CCompositeMoniker::AllButFirst(%x)\n",this));
LPMONIKER pmk;
//
// Run down the left side of the tree, creating a composite moniker with
// everything but the first moniker. See AllButLast for a pithy quote
// about the efficiency
//
CCompositeMoniker *pCM = IsCompositeMoniker(m_pmkLeft);
if (pCM)
{
LPMONIKER pmkABF = pCM->AllButFirst();
pmk = CCompositeMoniker::Create(pmkABF, m_pmkRight);
pmkABF->Release();
}
else
{
pmk = m_pmkRight;
pmk->AddRef();
}
return pmk;
}
//+---------------------------------------------------------------------------
//
// Method: CCompositeMoniker::First
//
// Synopsis:
// return the first moniker in the composite list. It is guaranteed to be
// non-null and non-composite
//
// Effects:
//
// Arguments: [void] --
//
// Requires:
//
// Returns:
//
// Signals:
//
// Modifies:
//
// Derivation:
//
// Algorithm:
//
// History: 2-03-94 kevinro Commented
//
// Notes:
//
//----------------------------------------------------------------------------
INTERNAL_(LPMONIKER)
CCompositeMoniker::First(void)
{
mnkDebugOut((DEB_ITRACE,
"CCompositeMoniker::First(%x)\n",this));
CCompositeMoniker *pCM = this;
CCompositeMoniker *pCMNext;
while ((pCMNext = IsCompositeMoniker(pCM->m_pmkLeft)) != NULL)
{
pCM = pCMNext;
}
IMoniker *pmk = pCM->m_pmkLeft;
Assert(pmk != NULL && (!IsCompositeMoniker(pmk)));
pmk->AddRef();
return pmk;
}
STDMETHODIMP CCompositeMoniker::BindToObject (LPBC pbc,
LPMONIKER pmkToLeft, REFIID riidResult, LPVOID FAR* ppvResult)
{
mnkDebugOut((DEB_ITRACE,
"CCompositeMoniker::BindToObject(%x)\n",this));
VDATEPTROUT(ppvResult, LPVOID);
VDATEIFACE(pbc);
VDATEIID(riidResult);
*ppvResult = NULL;
if (pmkToLeft)
{
VDATEIFACE(pmkToLeft);
}
HRESULT hresult = NOERROR;
LPRUNNINGOBJECTTABLE prot;
*ppvResult = NULL;
LPMONIKER pmkAllButLast = NULL;
LPMONIKER pmkLast = NULL;
LPMONIKER pmkNewLeft = NULL;
// Look for moniker in running objects table if there is nothing to the
// left
if (pmkToLeft == NULL)
{
hresult = pbc->GetRunningObjectTable( &prot );
if (hresult == NOERROR)
{
LPUNKNOWN pUnk;
hresult = prot->GetObject(this, &pUnk);
prot->Release();
if ((hresult == NOERROR) && (pUnk != NULL))
{
hresult = pUnk->QueryInterface(riidResult, ppvResult);
pUnk->Release();
goto errRet;
}
}
else
{
goto errRet;
}
}
pmkAllButLast = AllButLast();
if (pmkAllButLast == NULL)
{
// The creation must have failed. The only reason we could think of was
// out of memory.
hresult = E_OUTOFMEMORY;
goto errRet;
}
pmkLast = Last();
if (pmkLast == NULL)
{
// The creation must have failed. The only reason we could think of was
// out of memory.
hresult = E_OUTOFMEMORY;
goto errRet1;
}
Assert((pmkLast != NULL) && (pmkAllButLast != NULL));
if (pmkToLeft != NULL)
{
// REVIEW: check for error from ComposeWith
hresult = pmkToLeft->ComposeWith(pmkAllButLast, FALSE, &pmkNewLeft);
if (FAILED(hresult))
{
goto errRet2;
}
}
else
{
pmkNewLeft = pmkAllButLast;
pmkNewLeft->AddRef();
}
hresult = pmkLast->BindToObject(pbc, pmkNewLeft, riidResult, ppvResult);
errRet2:
pmkLast->Release();
errRet1:
pmkAllButLast->Release();
if (pmkNewLeft != NULL)
{
pmkNewLeft->Release();
}
errRet:
return hresult;
}
STDMETHODIMP CCompositeMoniker::BindToStorage (LPBC pbc, LPMONIKER pmkToLeft,
REFIID riid, LPVOID FAR* ppvObj)
{
mnkDebugOut((DEB_ITRACE,
"CCompositeMoniker::BindToStorage(%x)\n",this));
M_PROLOG(this);
VDATEPTROUT(ppvObj,LPVOID);
*ppvObj = NULL;
VDATEIFACE(pbc);
if (pmkToLeft) VDATEIFACE(pmkToLeft);
VDATEIID(riid);
HRESULT hresult = NOERROR;
LPMONIKER pmkAllButLast = AllButLast();
LPMONIKER pmkLast = Last();
LPMONIKER pmkNewLeft = NULL ;
if (pmkToLeft)
{
hresult = pmkToLeft->ComposeWith(pmkAllButLast, FALSE, &pmkNewLeft);
if (hresult) goto errRet;
}
else
{
pmkNewLeft = pmkAllButLast;
pmkNewLeft->AddRef();
}
hresult = pmkLast->BindToStorage(pbc, pmkNewLeft, riid, ppvObj);
errRet:
if (pmkAllButLast) pmkAllButLast->Release();
if (pmkLast) pmkLast->Release();
if (pmkNewLeft) pmkNewLeft->Release();
return hresult;
}
STDMETHODIMP CCompositeMoniker::Reduce (LPBC pbc,
DWORD dwReduceHowFar,
LPMONIKER FAR* ppmkToLeft,
LPMONIKER FAR * ppmkReduced)
{
mnkDebugOut((DEB_ITRACE,
"CCompositeMoniker::Reduce(%x)\n",this));
M_PROLOG(this);
VDATEPTROUT(ppmkReduced,LPMONIKER);
*ppmkReduced = NULL;
VDATEIFACE(pbc);
if (ppmkToLeft)
{
VDATEPTROUT(ppmkToLeft,LPMONIKER);
if (*ppmkToLeft) VDATEIFACE(*ppmkToLeft);
}
LPMONIKER pmkLeftReduced = NULL;
LPMONIKER pmkRightReduced = NULL;
CCompositeMoniker FAR * pmkCompositeReduced;
SCODE scode1;
SCODE scode2;
#ifdef _TRACKLINK_
if (!m_fReduceForced && m_fReduced) // already reduced maximally
#else
if (m_fReduced) // already reduced maximally
#endif
{
AddRef();
*ppmkReduced = this;
return ResultFromScode(MK_S_REDUCED_TO_SELF);
}
if (m_pmkLeft)
{
scode1 = GetScode( m_pmkLeft->Reduce(pbc,
dwReduceHowFar,
NULL,
&pmkLeftReduced));
// AssertOutPtrIface(scode1, pmkLeftReduced);
if (scode1 != S_OK && scode1 != MK_S_REDUCED_TO_SELF)
return ResultFromScode(scode1);
}
if (m_pmkRight)
{
// SPEC:
/*
ppmkToLeft
[out] On entry, ppmkToLeft points to the moniker that
prefixes this one within the composite, that is, the
moniker to the left of the current moniker. On exit, the
pointer will be NULL or non-NULL. Non-NULL indicates that
the previous prefix should be disregarded and the moniker
returned through ppmkToLeft should be used as the prefix
in its place (this is not usual). NULL indicates that the
prefix should not be replaced. Most monikers will NULL
out this parameter before returning. The ppmkToLeft
parameter is an [in,out] parameter and it must be released
before NULLing out. If an error is returned, this
parameter must be set to NULL. For more information on
[in,out] parameters, see the discussion of parameter types
in the section on Memory Management.
*/
IMoniker *pmkLeftReducedTmp = pmkLeftReduced;
pmkLeftReducedTmp->AddRef();
scode2 = GetScode( m_pmkRight->Reduce(pbc,
dwReduceHowFar,
&pmkLeftReducedTmp,
&pmkRightReduced));
// AssertOutPtrIface(scode2, pmkRightReduced);
if (pmkLeftReducedTmp == NULL)
{
// prefix should not be replaced
// we still have original ref
}
else
{
// use pmkLeftReducedTmp as the new left piece
pmkLeftReduced->Release(); // the original ref
pmkLeftReduced = pmkLeftReducedTmp;
}
if (scode2 != S_OK && scode2 != MK_S_REDUCED_TO_SELF)
{
if (pmkLeftReduced)
pmkLeftReduced->Release();
return ResultFromScode(scode2);
}
}
if (scode1 == MK_S_REDUCED_TO_SELF && scode2 == MK_S_REDUCED_TO_SELF)
{
pmkLeftReduced->Release();
pmkRightReduced->Release();
AddRef();
m_fReduced = TRUE;
*ppmkReduced = this;
return ResultFromScode(MK_S_REDUCED_TO_SELF);
}
// No error, and one of the two pieces actually reduced.
pmkCompositeReduced = CCompositeMoniker::Create(pmkLeftReduced,
pmkRightReduced );
pmkLeftReduced->Release();
pmkRightReduced->Release();
if (pmkCompositeReduced != NULL)
pmkCompositeReduced->m_fReduced = TRUE;
*ppmkReduced = pmkCompositeReduced;
return pmkCompositeReduced == NULL ? E_OUTOFMEMORY : NOERROR;
}
STDMETHODIMP CCompositeMoniker::ComposeWith (LPMONIKER pmkRight,
BOOL fOnlyIfNotGeneric, LPMONIKER FAR* ppmkComposite)
{
mnkDebugOut((DEB_ITRACE,
"CCompositeMoniker::ComposeWith(%x)\n",this));
M_PROLOG(this);
if (fOnlyIfNotGeneric)
{
return(MK_E_NEEDGENERIC);
}
return CreateGenericComposite( this, pmkRight, ppmkComposite );
}
STDMETHODIMP CCompositeMoniker::Enum (BOOL fForward, LPENUMMONIKER FAR* ppenumMoniker)
{
mnkDebugOut((DEB_ITRACE,
"CCompositeMoniker::Enum(%x)\n",this));
M_PROLOG(this);
VDATEPTROUT(ppenumMoniker,LPENUMMONIKER);
*ppenumMoniker = NULL;
*ppenumMoniker = CCompositeMonikerEnum::Create(fForward, this);
if (*ppenumMoniker) return NOERROR;
return ResultFromScode(E_OUTOFMEMORY);
}
STDMETHODIMP CCompositeMoniker::IsEqual (LPMONIKER pmkOtherMoniker)
{
mnkDebugOut((DEB_ITRACE,
"CCompositeMoniker::IsEqual(%x)\n",this));
M_PROLOG(this);
VDATEIFACE(pmkOtherMoniker);
HRESULT hr = S_FALSE;
HRESULT hr2;
LPENUMMONIKER pEnumMe;
LPENUMMONIKER pEnumOther;
LPMONIKER pMkMe;
LPMONIKER pMkOther;
// REVIEW: do we call Reduce first? No: spec isssue 330
CCompositeMoniker *pCMk = IsCompositeMoniker(pmkOtherMoniker);
if (pCMk)
{
hr = Enum(TRUE, &pEnumMe);
if (SUCCEEDED(hr))
{
hr = pmkOtherMoniker->Enum(TRUE, &pEnumOther);
if (SUCCEEDED(hr))
{
// Initialize
pEnumMe->Reset();
pEnumOther->Reset();
// Compare successive elements
for (;;)
{
// Fetch the next two elements
hr = pEnumMe->Next(1, &pMkMe, NULL);
hr2 = pEnumOther->Next(1, &pMkOther, NULL);
// Compare them
if (hr == S_OK && hr2 == S_OK)
{
if (pMkMe->IsEqual(pMkOther) == S_FALSE)
{
pMkMe->Release();
pMkOther->Release();
hr = S_FALSE;
break;
}
}
// Release the individual monikers
if (hr == S_OK)
{
pMkMe->Release();
}
if (hr2 == S_OK)
{
pMkOther->Release();
}
// All elements exhausted
if (hr == S_FALSE && hr2 == S_FALSE)
{
hr = S_OK;
break;
}
// One contained fewer elements than the other
else if (hr == S_FALSE || hr2 == S_FALSE)
{
hr = S_FALSE;
break;
}
}
pEnumOther->Release();
}
pEnumMe->Release();
}
}
return hr;
}
// the following is non-recursive version using enumerators.
#ifdef NONRECURSIVE_ISEQUAL
LPENUMMONIKER penumOther = NULL;
LPENUMMONIKER penumThis = NULL;
LPMONIKER pmkThis = NULL;
LPMONIKER pmkOther = NULL;
HRESULT hresult;
SCODE scode1;
SCODE scode2;
if (!IsCompositeMoniker(pmkOtherMoniker))
return ResultFromScode(S_FALSE);
hresult = Enum(TRUE, &penumThis);
if (hresult != NOERROR) goto errRet;
hresult = pmkOtherMoniker->Enum(TRUE, &penumOther);
if (hresult != NOERROR) goto errRet;
// now go through the enumeration, checking IsEqual on the individual
// pieces.
while (TRUE)
{
hresult = penumThis->Next( 1, &pmkThis, NULL );
scode1 = GetScode(hresult);
if ((hresult != NOERROR) && (S_FALSE != scode1))
{
goto errRet;
}
hresult = penumOther->Next( 1, &pmkOther, NULL );
scode2 = GetScode(hresult);
if ((hresult != NOERROR) && (S_FALSE != scode2))
{
goto errRet;
}
if (scode1 != scode2)
{
hresult = ResultFromScode(S_FALSE);
goto errRet;
}
if (S_FALSE == scode1)
{
hresult = NOERROR;
goto errRet;
}
hresult = pmkThis->IsEqual(pmkOther);
pmkThis->Release();
pmkOther->Release();
pmkThis = NULL;
pmkOther = NULL;
if (hresult != NOERROR) goto errRet;
}
errRet:
if (pmkThis) pmkThis->Release();
if (pmkOther) pmkOther->Release();
if (penumOther) penunOther->Release();
if (penumThis) penumThis->Release();
return hresult;
}
#endif // NONRECURSIVE_ISEQUAL
STDMETHODIMP CCompositeMoniker::Hash (LPDWORD pdwHash)
{
mnkDebugOut((DEB_ITRACE,
"CCompositeMoniker::Hash(%x)\n",this));
M_PROLOG(this);
VDATEPTROUT(pdwHash, DWORD);
DWORD dwHashLeft;
DWORD dwHashRight;
m_pmkLeft->Hash(&dwHashLeft);
// check for errors
m_pmkRight->Hash(&dwHashRight);
*pdwHash = dwHashLeft^dwHashRight;
return NOERROR;
}
STDMETHODIMP CCompositeMoniker::IsRunning
(LPBC pbc,
LPMONIKER pmkToLeft,
LPMONIKER pmkNewlyRunning)
{
mnkDebugOut((DEB_ITRACE,
"CCompositeMoniker::IsRunning(%x)\n",this));
VDATEIFACE(pbc);
if (pmkToLeft) VDATEIFACE(pmkToLeft);
if (pmkNewlyRunning) VDATEIFACE(pmkNewlyRunning);
LPMONIKER pmkFirst = First();
HRESULT hresult;
LPMONIKER pmk = NULL;
LPMONIKER pmkLast = NULL;
LPRUNNINGOBJECTTABLE prot = NULL;
CFileMoniker FAR * pCFM = IsFileMoniker(pmkFirst);
if (pCFM)
{
CLSID clsid;
if (pCFM->IsOle1Class(&clsid))
{
hresult = DdeIsRunning(clsid, pCFM->m_szPath, pbc,
pmkToLeft, pmkNewlyRunning);
goto errRet;
}
}
if (pmkToLeft != NULL)
{
hresult = pmkToLeft->ComposeWith(this, FALSE, &pmk);
if (hresult)
goto errRet;
hresult = pmk->IsRunning(pbc, NULL, pmkNewlyRunning);
}
else if (pmkNewlyRunning != NULL)
{
hresult = pmkNewlyRunning->IsEqual(this);
}
else
{
hresult = pbc->GetRunningObjectTable(&prot);
if (hresult != NOERROR)
goto errRet;
hresult = prot->IsRunning(this);
if (hresult == NOERROR)
goto errRet;
pmk = AllButLast();
pmkLast = Last();
hresult = pmkLast->IsRunning(pbc, pmk, pmkNewlyRunning);
}
errRet:
if (pmk) pmk->Release();
if (pmkLast) pmkLast->Release();
if (prot) prot->Release();
if (pmkFirst) pmkFirst->Release();
return hresult;
}
STDMETHODIMP CCompositeMoniker::GetTimeOfLastChange (LPBC pbc, LPMONIKER pmkToLeft, FILETIME FAR* pfiletime)
{
mnkDebugOut((DEB_ITRACE,
"CCompositeMoniker::GetTimeOfLastChange(%x)\n",this));
M_PROLOG(this);
VDATEIFACE(pbc);
if (pmkToLeft) VDATEIFACE(pmkToLeft);
VDATEPTROUT(pfiletime, FILETIME);
HRESULT hresult;
LPMONIKER pmkTemp = NULL;
LPMONIKER pmkABL = NULL;
LPMONIKER pmkL = NULL;
LPRUNNINGOBJECTTABLE prot = NULL;
if (pmkToLeft == NULL)
{
pmkTemp = this;
AddRef();
}
else
{
hresult = CreateGenericComposite( pmkToLeft, this, &pmkTemp );
if (hresult != NOERROR) goto errRet;
}
hresult = pbc->GetRunningObjectTable(& prot);
if (hresult != NOERROR) goto errRet;
hresult = prot->GetTimeOfLastChange( pmkTemp, pfiletime);
if (hresult != MK_E_UNAVAILABLE) goto errRet;
pmkTemp->Release(); pmkTemp = NULL;
pmkABL = AllButLast();
pmkL = Last();
Assert(pmkABL != NULL);
if (pmkToLeft == NULL)
{
pmkTemp = pmkABL;
pmkABL->AddRef();
}
else
{
hresult = CreateGenericComposite(pmkToLeft, pmkABL, &pmkTemp);
if (hresult != NOERROR) goto errRet;
}
hresult = pmkL->GetTimeOfLastChange(pbc, pmkTemp, pfiletime);
errRet:
if (pmkTemp) pmkTemp->Release();
if (pmkABL) pmkABL->Release();
if (pmkL) pmkL->Release();
if (prot) prot->Release();
return hresult;
}
STDMETHODIMP CCompositeMoniker::Inverse (LPMONIKER FAR* ppmk)
{
mnkDebugOut((DEB_ITRACE,
"CCompositeMoniker::Inverse(%x)\n",this));
M_PROLOG(this);
VDATEPTROUT(ppmk, LPMONIKER);
*ppmk = NULL;
HRESULT hresult;
LPMONIKER pmkLeftInverse;
LPMONIKER pmkRightInverse;
hresult = m_pmkLeft->Inverse(&pmkLeftInverse);
// AssertOutPtrIface(hresult, pmkLeftInverse);
if (hresult != NOERROR) return hresult;
hresult = m_pmkRight->Inverse(&pmkRightInverse);
// AssertOutPtrIface(hresult, pmkRightInverse);
if (hresult != NOERROR)
{
pmkLeftInverse->Release();
return hresult;
}
hresult = CreateGenericComposite( pmkRightInverse, pmkLeftInverse, ppmk);
pmkRightInverse->Release();
pmkLeftInverse->Release();
return hresult;
}
//+---------------------------------------------------------------------------
//
// Method: CCompositeMoniker::CommonPrefixWith
//
// Synopsis: This method determines the common prefix between this moniker
// and the provided moniker
//
// Effects:
//
// Arguments: [pmkOther] -- Moniker to determine common prefix with
// [ppmkPrefix] -- Outputs moniker with common prefix
//
// Requires:
//
// Returns:
//
// Signals:
//
// Modifies:
//
// Derivation:
//
// Algorithm:
//
// History: 2-03-94 kevinro Commented
//
// Notes:
//
//----------------------------------------------------------------------------
STDMETHODIMP CCompositeMoniker::CommonPrefixWith (LPMONIKER pmkOther,
LPMONIKER FAR* ppmkPrefix)
{
mnkDebugOut((DEB_ITRACE,
"CCompositeMoniker::CommonPrefixWith(%x)\n",this));
VDATEPTROUT(ppmkPrefix,LPMONIKER);
VDATEIFACE(pmkOther);
CCompositeMoniker FAR * pCCMOther;
LPMONIKER pmkFirst = NULL;
LPMONIKER pmkRest = NULL;
LPMONIKER pmkOtherFirst = NULL;
LPMONIKER pmkOtherRest = NULL;
LPMONIKER pmkResult = NULL;
LPMONIKER pmkResult2 = NULL;
HRESULT hresult = E_UNEXPECTED;
HRESULT hresult2;
*ppmkPrefix = NULL;
pmkFirst = First();
if (pmkFirst == NULL)
{
goto errRet;
}
//
// If the other moniker is also a composite, then we need to recurse
// down both lists to find the common prefix
//
pCCMOther = IsCompositeMoniker(pmkOther);
if (pCCMOther)
{
mnkDebugOut((DEB_ITRACE,
"::CommonPrefixWith C(%x) and C(%x)\n",
this,
pmkOther));
//
// For each element of the composite, get the common prefix
//
pmkOtherFirst = pCCMOther->First();
if(pmkOtherFirst == NULL)
{
goto errRet;
}
//
// We have both 'first' monikers from the composite.
//
hresult = pmkFirst->CommonPrefixWith(pmkOtherFirst, &pmkResult);
if (FAILED(hresult))
{
goto errRet;
}
//
// If the monikers are the same, then recurse to get the common
// prefix of the rest.
// It is possible that the rest won't be common, in which case we need
// to return just pmkResult.
//
if (MK_S_US == hresult)
{
pmkOtherRest = pCCMOther->AllButFirst();
if (pmkOtherRest == NULL)
{
goto errRet;
}
pmkRest = AllButFirst();
if (pmkRest == NULL)
{
goto errRet;
}
hresult = pmkRest->CommonPrefixWith(pmkOtherRest, &pmkResult2);
//
// If hresult == MK_E_NOPREFIX, then pmkResult holds the entire
// prefix. In this case, we need to convert the hresult into
// another error code.
//
// If hresult == MK_S_US, MK_S_HIM, or MK_S_ME, then composing
// to the end of pmkResult and returning hresult will do the
// correct thing.
//
if (hresult == MK_E_NOPREFIX)
{
//
// There was no additional prefix match, return the
// current result
//
*ppmkPrefix = pmkResult;
pmkResult->AddRef();
hresult = NOERROR;
goto errRet;
} else if (FAILED(hresult))
{
goto errRet;
}
//
// Since MK_E_NOPREFIX was not the return error, and
// the call didn't fail, then the other moniker must have returned
// a prefix. Compose it with the existing result
//
// If the compose succeeds, then return the existing hresult.
// We are either going to return MK_S_HIM, MK_S_US, MK_S_ME, or
// NOERROR (or some other error we don't know.
//
hresult2 = pmkResult->ComposeWith(pmkResult2, FALSE, ppmkPrefix);
if (FAILED(hresult2))
{
//
// Compose with failed. Convert hresult, which is the return
// value, into hresult2
//
hresult = hresult2;
}
goto errRet;
}
else if ((hresult == MK_S_HIM) || (hresult == MK_S_ME))
{
//
// The common prefix was either him or me, therefore the
// proper thing to do is to return the result. However, we
// need to change the hresult, since the result is a prefix
// of one of the composites. (Try that 3 times fast)
//
*ppmkPrefix = pmkResult;
pmkResult->AddRef();
hresult = NOERROR;
}
goto errRet;
}
else
{
hresult = pmkFirst->CommonPrefixWith(pmkOther, ppmkPrefix);
// if the first part of me is the common prefix, then the prefix
// is a subpart of me since I am composite. The actual prefix is
// NOT me, since only the first moniker was prefix
if (MK_S_ME == hresult)
{
hresult = NOERROR;
}
else if (hresult == MK_S_US)
{
//
// If the First moniker returned MK_S_US, then the actual
// return should be MK_S_HIM, since this composite has additional
// parts that weren't considered by the call.
//
hresult = MK_S_HIM;
}
}
errRet:
if (pmkFirst) pmkFirst->Release();
if (pmkRest) pmkRest->Release();
if (pmkOtherFirst) pmkOtherFirst->Release();
if (pmkOtherRest) pmkOtherRest->Release();
if (pmkResult) pmkResult->Release();
if (pmkResult2) pmkResult2->Release();
return hresult;
}
HRESULT ComposeWithEnum( LPMONIKER pmkLeft, LPENUMMONIKER penum,
LPMONIKER FAR * ppmkComposite )
{
mnkDebugOut((DEB_ITRACE,
"CCompositeMoniker::ComposeWithEnum(pmkLeft=%x,penum=%x)\n",
pmkLeft,
penum));
LPMONIKER pmk = NULL;
LPMONIKER pmkTempLeft = pmkLeft;
LPMONIKER pmkTempComp = NULL;
HRESULT hresult;
*ppmkComposite = NULL;
pmkTempLeft->AddRef();
while ((hresult = penum->Next(1, &pmk, NULL)) == NOERROR)
{
hresult = pmkTempLeft->ComposeWith(pmk, FALSE, &pmkTempComp);
pmk->Release();
pmkTempLeft->Release();
pmkTempLeft=pmkTempComp; // no need to release pmkTempComp
if (hresult != NOERROR) goto errRet;
}
errRet:
if (GetScode(hresult) == S_FALSE) hresult = NOERROR;
if (hresult == NOERROR) *ppmkComposite = pmkTempLeft;
else pmkTempLeft->Release();
return hresult;
}
HRESULT InverseFromEnum( LPENUMMONIKER penum, LPMONIKER FAR * ppmkInverse)
{
mnkDebugOut((DEB_ITRACE,
"CCompositeMoniker::InverseFromEnum(%x)\n",penum));
LPMONIKER pmk = NULL;
LPMONIKER pmkInverse = NULL;
LPMONIKER pmkTailInverse = NULL;
HRESULT hresult;
*ppmkInverse = NULL;
hresult = penum->Next(1, &pmk, NULL );
if (hresult == NOERROR)
{
hresult = InverseFromEnum( penum, &pmkTailInverse);
if (hresult != NOERROR)
goto errRet;
hresult = pmk->Inverse(&pmkInverse);
// AssertOutPtrIface(hresult, pmkInverse);
if (hresult != NOERROR) goto errRet;
if (pmkTailInverse)
hresult = pmkTailInverse->ComposeWith( pmkInverse, FALSE, ppmkInverse );
else
*ppmkInverse = pmkInverse;
}
errRet:
if (GetScode(hresult) == S_FALSE) hresult = NOERROR;
if (pmk) pmk->Release();
if (pmkTailInverse) pmkTailInverse->Release();
return hresult;
}
//+---------------------------------------------------------------------------
//
// Method: CCompositeMoniker::RelativePathTo
//
// Synopsis: Determines the relative path to pmkOther
//
// Effects:
//
// Arguments: [pmkOther] -- moniker to which to find relative path
// [ppmkRelPath] -- placeholder for returned moniker
//
// Requires:
//
// Returns: HRESULT
//
// Derivation: IMoniker
//
// Algorithm: There are two major cases - B is or is not a composite moniker.
//
// * * *
//
// If both monikers are composite monikers, we compare their
// component monikers. Using the following notation for the
// monikers A and B:
//
// (a[0], a[1], a[2], ... a[m]) and (b[0], b[1], b[2], ... b[n])
//
// We find the first pair (a[i], b[i]) such that a[i] != b[i].
//
// Case 1:
// If i == 0, then no component monikers match.
// Case 1A:
// If we can form a relative path between a[0] and b[0], we
// can construct a correct relative path between A and B by
// combining (in order):
//
// !(a[1], ... a[m]) - inverse of the remaining elements of A
// (can be NULL)
// (!a[0], b[0]) - relative path between a[0] and b[0]
// (b[1], ... b[n]) - remaining elements of B
//
// Case 1B:
// Else there is no relative path and we just return B as the
// relative path and MK_S_HIM as the HRESULT
//
// Case 2:
// Else if (a[i] != NULL) && (b[i] != NULL) then both monikers
// have leftover pieces. We can construct a correct relative
// path by combining (in order):
//
// !(a[i+1], ... a[m]) - inverse of remaining elements of A
// !a[i]
// b[i]
// (b[i+1], ... b[n]) - remaining elements of B
//
// Case 3:
// Else if (a[i] != NULL) && (b[i] == NULL) then B is a prefix
// of A. We can construct a correct relative path by combining:
//
// !(a[i+1], ... a[m]) - inverse of remaining elements of A
// !a[i]
//
// Note that this is just the first two steps of the previous
// case.
//
// Case 4:
// Else if (a[i] == NULL) && (b[i] != NULL) then A is a prefix
// of B. We can construct a correct relative path by combining:
//
// b[i]
// (b[i+1], ... b[n]) - remaining elements of B
//
// Case 5:
// Else if (a[i] == NULL) && (b[i] == NULL) then A == B. We
// return B as the relative moniker and MK_S_HIM as the HRESULT.
//
// * * *
//
// If B is not a composite moniker, we compare the first
// component of A to B. Using the following notation:
//
// (a[0], a[1], a[2], ... a[m]) and B (not a composite)
//
// Case 6:
// If a[0] == B, then B is a prefix of A. We can construct the
// correct relative path as:
//
// !(a[1], ... a[m]) - inverse of remaining elements of A
//
// Case 7:
// Else if we can form a relative path between a[0] and B, we
// can construct a relative path between A and B by combining
// (in order):
//
// !(a[1], ... a[m]) - inverse of remaining elements of A
// (!a[0], B) - relative path between a[0] and B
//
// Case 8:
// Else there is no relative path between a[0] and B so we just
// return B as the relative moniker and MK_S_HIM as the HRESULT
//
// History: 2-03-94 kevinro Commented
// 07/10/94 AlexT Handle pmkOther == this case
// 10/21/94 AlexT Rewrite, plug leaks, add Algorithm
//
// Notes: InverseFromEnum can return S_OK with an out moniker of NULL
// (if there are no more elements to enumerate)
//
//----------------------------------------------------------------------------
STDMETHODIMP CCompositeMoniker::RelativePathTo (LPMONIKER pmkOther,
LPMONIKER FAR* ppmkRelPath)
{
mnkDebugOut((DEB_TRACE,
"%p _IN CCompositeMoniker::RelativePathTo (%p, %p)\n",
this, pmkOther, ppmkRelPath));
VDATEPTROUT(ppmkRelPath,LPMONIKER);
VDATEIFACE(pmkOther);
*ppmkRelPath = NULL;
LPENUMMONIKER pEnumThis; // Enumerator for this moniker's components
HRESULT hr;
hr = Enum(TRUE, &pEnumThis);
if (NOERROR == hr)
{
LPMONIKER pmkThisElement; // Next element of this moniker
hr = pEnumThis->Next(1, &pmkThisElement, NULL);
Assert(NOERROR == hr && "Moniker enumeration failure");
if (IsCompositeMoniker(pmkOther))
{
LPENUMMONIKER pEnumOther; // Enumerator for other moniker's
// components
hr = pmkOther->Enum(TRUE, &pEnumOther);
if (NOERROR == hr)
{
LPMONIKER pmkOtherElement; // Next element of other moniker
BOOL fMatch = FALSE; // Did any components match?
// we now have enumerators for both this and pmkOther
Assert(pEnumThis && pEnumOther && "Bad return values");
hr = pEnumOther->Next(1, &pmkOtherElement, NULL);
Assert(NOERROR == hr && "Moniker enumeration failure");
// find the first element pair that aren't equal
do
{
if (pmkThisElement->IsEqual(pmkOtherElement) != NOERROR)
{
// moniker elements aren't equal
break;
}
fMatch = TRUE; // at least one element pair matched
pmkThisElement->Release();
pmkOtherElement->Release();
pEnumThis->Next(1, &pmkThisElement, NULL);
pEnumOther->Next(1, &pmkOtherElement, NULL);
} while (pmkThisElement != NULL && pmkOtherElement != NULL);
if (!fMatch)
{
// Case 1: No component monikers matched
LPMONIKER pmkBetween; // Relative path between this
// element and other element
hr = pmkThisElement->RelativePathTo(pmkOtherElement,
&pmkBetween);
if (NOERROR == hr)
{
// Case 1A: There is a relative path from first
// element of this to first element of pmkOther
LPMONIKER pmkInverse; // Inverse of remaining elements
// of this moniker
hr = InverseFromEnum(pEnumThis, &pmkInverse);
if (SUCCEEDED(hr))
{
if (NULL == pmkInverse)
{
// There were no remaining elements
hr = ComposeWithEnum(pmkBetween, pEnumOther,
ppmkRelPath);
}
else
{
LPMONIKER pmkTemp; // Inverse + Between
// + relative path from this element to
// Other element
hr = pmkInverse->ComposeWith(pmkBetween,
FALSE,
&pmkTemp);
if (SUCCEEDED(hr))
{
// + remaining elements of Other
hr = ComposeWithEnum(pmkTemp,
pEnumOther,
ppmkRelPath);
pmkTemp->Release();
}
pmkInverse->Release();
}
}
pmkBetween->Release();
}
else if (MK_S_HIM == hr)
{
// Case 1B: There is no relative path between the
// elements - return pmkOther and MK_S_HIM
pmkBetween->Release();
pmkOther->AddRef();
*ppmkRelPath = pmkOther;
Assert(MK_S_HIM == hr && "Bad logic");
}
else
{
// error case; nothing to do
Assert(FAILED(hr) && "Unexpected success!");
}
}
else if (pmkThisElement != NULL)
{
// Case 2 and 3: Both monikers have remaining pieces or
// pmkOther is a prefix of this
LPMONIKER pmkInverse; // Inverse of remaining elements
// of this moniker
hr = InverseFromEnum(pEnumThis, &pmkInverse);
if (SUCCEEDED(hr))
{
LPMONIKER pmkElementInverse; // Inverse of current
// element of this
hr = pmkThisElement->Inverse(&pmkElementInverse);
if (SUCCEEDED(hr))
{
LPMONIKER pmkTemp; // partial result
if (NULL == pmkInverse)
{
// There were no remaining elements of this
// moniker - we begin with the element inverse
pmkTemp = pmkElementInverse;
}
else
{
hr = pmkInverse->ComposeWith(
pmkElementInverse,
FALSE, &pmkTemp);
pmkElementInverse->Release();
}
if (NULL == pmkOtherElement)
{
// Case 3: pmkOther is a prefix of this
*ppmkRelPath = pmkTemp;
}
else if (SUCCEEDED(hr))
{
// Case 2: both monikers had remaining pieces
LPMONIKER pmkTemp2; // partial result
// + other element
hr = pmkTemp->ComposeWith(pmkOtherElement,
FALSE,
&pmkTemp2);
if (SUCCEEDED(hr))
{
// + remaining other elements
hr = ComposeWithEnum(pmkTemp2, pEnumOther,
ppmkRelPath);
pmkTemp2->Release();
}
pmkTemp->Release();
}
}
if (NULL != pmkInverse)
{
pmkInverse->Release();
}
}
}
else if (pmkOtherElement != NULL)
{
// Case 4: this is a prefix of pmkOther
hr = ComposeWithEnum(pmkOtherElement, pEnumOther,
ppmkRelPath);
}
else
{
// Case 5: this and pmkOther are equal
pmkOther->AddRef();
*ppmkRelPath = pmkOther;
hr = MK_S_HIM;
}
if (NULL != pmkOtherElement)
{
pmkOtherElement->Release();
}
pEnumOther->Release();
}
}
else
{
// pmkrOther is not a composite moniker
hr = pmkThisElement->IsEqual(pmkOther);
if (NOERROR == hr)
{
// Case 6: first element of this equals pmkOther; pmkOther
// is a prefix of this
hr = InverseFromEnum(pEnumThis, ppmkRelPath);
if (SUCCEEDED(hr) && (NULL == *ppmkRelPath))
{
// There were no more elements to enumerate; return
// pmkOther as the relative path
pmkOther->AddRef();
*ppmkRelPath = pmkOther;
hr = MK_S_HIM;
}
}
else
{
LPMONIKER pmkBetween;
hr = pmkThisElement->RelativePathTo(pmkOther, &pmkBetween);
if (NOERROR == hr)
{
// Case 7: There is a relative path between first element
// of this and pmkOther
LPMONIKER pmkInverse; // Inverse of remaining elements
// of this moniker
hr = InverseFromEnum(pEnumThis, &pmkInverse);
if (SUCCEEDED(hr))
{
if (NULL == pmkInverse)
{
*ppmkRelPath = pmkBetween;
pmkBetween = NULL;
}
else
{
hr = pmkInverse->ComposeWith(pmkBetween, FALSE,
ppmkRelPath);
pmkInverse->Release();
}
}
}
else if (MK_S_HIM == hr)
{
// Case 8: There is no relative path between first
// element of this and pmkOther (which is pmkBetween),
// return pmkOther and MK_S_HIM
*ppmkRelPath = pmkBetween;
pmkBetween = NULL;
Assert(NOERROR == pmkOther->IsEqual(*ppmkRelPath) &&
"Bad logic");
Assert(MK_S_HIM == hr && "Bad logic");
}
else
{
// error case; nothing to do
Assert(FAILED(hr) && "Unexpected success!");
}
if (NULL != pmkBetween)
{
pmkBetween->Release();
}
}
}
if (NULL != pmkThisElement)
{
pmkThisElement->Release();
}
pEnumThis->Release();
}
mnkDebugOut((DEB_TRACE,
"%p OUT CCompositeMoniker::RelativePathTo(%lx) [%p]\n",
this, hr, *ppmkRelPath));
return(hr);
}
STDMETHODIMP CCompositeMoniker::GetDisplayName (LPBC pbc,
LPMONIKER pmkToLeft, LPWSTR FAR* lplpszDisplayName)
{
mnkDebugOut((DEB_ITRACE,
"CCompositeMoniker::GetDisplayName(%x)\n",this));
M_PROLOG(this);
VDATEPTROUT(lplpszDisplayName, LPWSTR);
*lplpszDisplayName = NULL;
//REVIEW MM3 Find out who is calling this with pbc == NULL and get them
// to stop it.
VDATEIFACE(pbc);
if (pmkToLeft) VDATEIFACE(pmkToLeft);
LPWSTR lpszToLeft = NULL;
LPWSTR lpszLeft = NULL;
LPWSTR lpszRight = NULL;
LPWSTR lpsz;
HRESULT hresult;
int n1, n2, n3;
// No error checking yet
if (pmkToLeft)
{
hresult = pmkToLeft->GetDisplayName( pbc, NULL, &lpszToLeft );
// AssertOutPtrParam(hresult, lpszToLeft);
if (hresult != NOERROR)
goto errRtn;
}
hresult = m_pmkLeft->GetDisplayName(pbc, NULL, &lpszLeft);
// AssertOutPtrParam(hresult, lpszLeft);
if (hresult != NOERROR)
goto errRtn;
hresult = m_pmkRight->GetDisplayName(pbc, NULL, &lpszRight);
// AssertOutPtrParam(hresult, lpszRight);
if (hresult != NOERROR)
goto errRtn;
if (lpszToLeft) n1 = lstrlenW(lpszToLeft);
else n1 = 0;
n2 = lstrlenW(lpszLeft);
n3 = lstrlenW(lpszRight);
lpsz = (WCHAR *)
CoTaskMemAlloc(sizeof(WCHAR) * (n1 + n2 + n3 + 1));
if (lpsz == NULL)
{
hresult = E_OUTOFMEMORY;
goto errRtn;
}
*lplpszDisplayName = lpsz;
if (n1) _fmemmove( lpsz, lpszToLeft, n1 * sizeof(WCHAR));
lpsz += n1;
_fmemmove( lpsz, lpszLeft, n2 * sizeof(WCHAR));
lpsz += n2;
_fmemmove( lpsz, lpszRight, (n3 + 1) * sizeof(WCHAR));
errRtn:
CoTaskMemFree(lpszToLeft);
CoTaskMemFree(lpszLeft);
CoTaskMemFree(lpszRight);
return hresult;
}
STDMETHODIMP CCompositeMoniker::ParseDisplayName (LPBC pbc, LPMONIKER pmkToLeft,
LPWSTR lpszDisplayName, ULONG FAR* pchEaten, LPMONIKER FAR* ppmkOut)
{
mnkDebugOut((DEB_ITRACE,
"CCompositeMoniker::ParseDisplayName(%x)\n",this));
M_PROLOG(this);
VDATEPTROUT(ppmkOut,LPMONIKER);
*ppmkOut = NULL;
VDATEIFACE(pbc);
if (pmkToLeft) VDATEIFACE(pmkToLeft);
VDATEPTRIN(lpszDisplayName, WCHAR);
VDATEPTROUT(pchEaten,ULONG);
HRESULT hresult = NOERROR;
LPMONIKER pmkAllButLast = AllButLast();
LPMONIKER pmkLast = Last();
LPMONIKER pmkNewLeft = NULL ;
Assert((pmkLast != NULL) && (pmkAllButLast != NULL));
if (pmkToLeft) pmkToLeft->ComposeWith(pmkAllButLast, FALSE, &pmkNewLeft);
// REVIEW: check for error from ComposeWith
else
{
pmkNewLeft = pmkAllButLast;
pmkNewLeft->AddRef();
}
hresult = pmkLast->ParseDisplayName(pbc, pmkNewLeft, lpszDisplayName,
pchEaten, ppmkOut);
// AssertOutPtrIface(hresult, *ppmkOut);
pmkAllButLast->Release();
pmkLast->Release();
if (pmkNewLeft) pmkNewLeft->Release();
return hresult;
}
STDMETHODIMP CCompositeMoniker::IsSystemMoniker (THIS_ LPDWORD pdwType)
{
mnkDebugOut((DEB_ITRACE,
"CCompositeMoniker::IsSystemMoniker(%x)\n",this));
M_PROLOG(this);
VDATEPTROUT(pdwType,DWORD);
*pdwType = MKSYS_GENERICCOMPOSITE;
return NOERROR;
}
//+---------------------------------------------------------------------------
//
// Method: CCompositeMoniker::GetComparisonData
//
// Synopsis: Get comparison data for registration in the ROT
//
// Arguments: [pbData] - buffer to put the data in.
// [cbMax] - size of the buffer
// [pcbData] - count of bytes used in the buffer
//
// Returns: NOERROR
// E_OUTOFMEMORY
//
// Algorithm: First verify buffer is big enough for the composite moniker
// class id. Put that into the buffer. Then put the left part
// into the buffer. Finally put the right part into the buffer.
//
// History: 03-Feb-95 ricksa Created
//
// Note: Validating the arguments is skipped intentionally because this
// will typically be called internally by OLE with valid buffers.
//
//----------------------------------------------------------------------------
STDMETHODIMP CCompositeMoniker::GetComparisonData(
byte *pbData,
ULONG cbMax,
ULONG *pcbData)
{
HRESULT hr = E_OUTOFMEMORY;
ULONG cOrigMax = cbMax;
ULONG cSizeHolder;
BEGIN_BLOCK
// Can buffer hold the clsid?
if (cbMax < sizeof(CLSID))
{
// No - so we are out of here;
mnkDebugOut((DEB_ERROR,
"CCompositeMoniker::GetComparisonData buffer not big enough"
" for CLSID\n"));
EXIT_BLOCK;
}
cbMax -= sizeof(CLSID);
memcpy(pbData, &CLSID_CompositeMoniker, sizeof(CLSID));
pbData += sizeof(CLSID);
hr = BuildRotData(NULL, m_pmkLeft, pbData, cbMax, &cSizeHolder);
if (FAILED(hr))
{
// No - so we are out of here;
mnkDebugOut((DEB_ERROR,
"CCompositeMoniker::GetComparisonData BuildRotData of left"
" failed %lx\n", hr));
EXIT_BLOCK;
}
cbMax -= cSizeHolder;
pbData += cSizeHolder;
hr = BuildRotData(NULL, m_pmkRight, pbData, cbMax, &cSizeHolder);
#if DBG == 1
if (FAILED(hr))
{
mnkDebugOut((DEB_ERROR,
"CCompositeMoniker::GetComparisonData BuildRotData of right"
" failed %lx\n", hr));
}
#endif // DBG == 1
cbMax -= cSizeHolder;
END_BLOCK;
*pcbData = (SUCCEEDED(hr)) ? cOrigMax - cbMax : 0;
return hr;
}
/*
* Concatenate makes a composite moniker without ever calling
* ComposeWith on the individual pieces.
*/
STDAPI Concatenate( LPMONIKER pmkFirst, LPMONIKER pmkRest,
LPMONIKER FAR* ppmkComposite )
{
mnkDebugOut((DEB_ITRACE,
"CCompositeMoniker::Concatentate(pmkFirst=%x,pmkRest%x)\n",
pmkFirst,
pmkRest));
LPMONIKER pmkConcat = CCompositeMoniker::Create( pmkFirst, pmkRest);
*ppmkComposite = pmkConcat;
if (pmkConcat == NULL)
{
return ResultFromScode(S_OOM);
}
// Create did the AddRef
return NOERROR;
}
//+---------------------------------------------------------------------------
//
// Function: CreateGenericComposite
//
// Synopsis: Creates a generic composite from two other monikers
//
// Effects:
//
// Arguments: [pmkFirst] --
// [pmkRest] --
// [ppmkComposite] --
//
// Requires:
//
// Returns:
//
// Signals:
//
// Modifies:
//
// Algorithm:
//
// History: 2-03-94 kevinro Commented
//
// Notes:
//
//----------------------------------------------------------------------------
STDAPI CreateGenericComposite( LPMONIKER pmkFirst, LPMONIKER pmkRest,
LPMONIKER FAR * ppmkComposite )
{
OLETRACEIN((API_CreateGenericComposite, PARAMFMT("pmkFirst = %p, pmkRest= %p, ppmkComposite= %p"),
pmkFirst, pmkRest, ppmkComposite));
mnkDebugOut((DEB_ITRACE,
"CCompositeMoniker::CreateGenericComposite(First=%x,Rest=%x)\n",
pmkFirst,
pmkRest));
LPMONIKER pmkAllButFirstOfRest = NULL;
LPMONIKER pmkFirstOfRest = NULL;
LPMONIKER pmkAllButLastOfFirst = NULL;
LPMONIKER pmkLastOfFirst = NULL;
LPMONIKER pmk = NULL;
LPMONIKER pmk2 = NULL;
CCompositeMoniker *pCMk = NULL;
CCompositeMoniker *pCMkRest = NULL;
HRESULT hresult;
CALLHOOKOBJECT(S_OK,CLSID_NULL,IID_IMoniker,(IUnknown **)&pmkFirst);
CALLHOOKOBJECT(S_OK,CLSID_NULL,IID_IMoniker,(IUnknown **)&pmkRest);
//
// Initialize ppmkComposite. Might return in the middle of this
// routine, so be sure its NULL in the error case
//
*ppmkComposite = NULL;
//
// If both pointers are NULL, return a NULL composite
//
if ((pmkFirst == NULL) && (pmkRest == NULL))
{
hresult = NOERROR;
goto errRtn;
}
//
// Otherwise, if one pointer is NULL, return the other as the
// composite.
//
if (pmkFirst == NULL)
{
*ppmkComposite = pmkRest;
pmkRest->AddRef();
hresult = NOERROR;
goto errRtn;
}
if (pmkRest == NULL)
{
*ppmkComposite = pmkFirst;
pmkFirst->AddRef();
hresult = NOERROR;
goto errRtn;
}
//
// Handle the two cases where pmkFirst is NOT a composite
//
pCMk = IsCompositeMoniker( pmkFirst );
if (!pCMk)
{
//
// If pmkRest is not a composite, then we have two
// monikers that are considered 'simple' monikers.
//
pCMk = IsCompositeMoniker( pmkRest );
if (!pCMk)
{
mnkDebugOut((DEB_ITRACE,
"::CreateGenericComposite( S(%x) o S(%x) )\n",
pmkFirst,
pmkRest));
// Case 1: two simple monikers
hresult = pmkFirst->ComposeWith(pmkRest, TRUE, ppmkComposite);
if (hresult == MK_E_NEEDGENERIC)
{
Assert(*ppmkComposite == NULL);
hresult = Concatenate(pmkFirst, pmkRest, ppmkComposite);
goto errRtn;
}
}
else
{
//
// Case 2: S o C(b1, b2, b3).
//
// Compose S with b1,
// then
// Compose ( S o b1 ) with C( b2, b3, ...)
//
//
mnkDebugOut((DEB_ITRACE,
"::CreateGenericComposite( S(%x) o C(%x) )\n",
pmkFirst,
pmkRest));
//
// Since the right side is a composite, the following should
// always exist. It would be a severe suprise if it didn't.
//
pmkFirstOfRest = pCMk->First();
//
// However, the AllButFirst function needs to allocate memory,
// which might fail.
//
pmkAllButFirstOfRest = pCMk->AllButFirst();
if (pmkAllButFirstOfRest == NULL)
{
hresult = E_OUTOFMEMORY;
goto exitRet;
}
hresult = pmkFirst->ComposeWith(pmkFirstOfRest, TRUE, &pmk);
if ( hresult == MK_E_NEEDGENERIC)
{
Assert(pmk == NULL);
hresult = Concatenate(pmkFirst, pmkRest, ppmkComposite);
}
else if (SUCCEEDED(hresult))
{
//
// pmkFirst->ComposeWith can succeed, but return NULL.
// If it doesn't return NULL, then ( a o b1 ) is a
// moniker of some ilk. Create a generic composite with
// this result, and the rest of the moniker
//
if (pmk != NULL)
{
hresult = CreateGenericComposite(pmk,
pmkAllButFirstOfRest,
ppmkComposite);
}
else
{
//
// pmkFirst and pmkFirstOfRest annihilated each other.
// This is indicated by a success code, and a pmk == NULL,
// which is how we got here.
//
*ppmkComposite = pmkAllButFirstOfRest;
//
// pmkAllButFirstOfRest is the moniker we want to
// return.
//
pmkAllButFirstOfRest->AddRef();
hresult = NOERROR;
}
}
}
//
// We are done, goto exit routine
//
goto exitRet;
}
//
// We have determined that pmkFirst is a Composite Moniker
//
pmkAllButLastOfFirst = pCMk->AllButLast();
if (pmkAllButLastOfFirst == NULL)
{
hresult = E_OUTOFMEMORY;
goto exitRet;
}
pmkLastOfFirst = pCMk->Last();
if (pmkLastOfFirst == NULL)
{
hresult = E_OUTOFMEMORY;
goto exitRet;
}
//
// Determine if pmkRest is a composite. If not, then just
// compose the last of pmkFirst with pmkRest
//
pCMkRest = IsCompositeMoniker(pmkRest);
if (!pCMkRest)
{
// case 3: (a1 a2 a3...) o b
mnkDebugOut((DEB_ITRACE,
"::CreateGenericComposite( C(%x) o S(%x) )\n",
pmkFirst,
pmkRest));
hresult = pmkLastOfFirst->ComposeWith(pmkRest, TRUE, &pmk);
if (MK_E_NEEDGENERIC == GetScode(hresult))
{
Assert(pmk==NULL);
hresult = Concatenate(pmkFirst, pmkRest, ppmkComposite);
}
else if (SUCCEEDED(hresult))
{
//
// If pmk != NULL, create a generic composite out of
// of the results
if (pmk != NULL)
{
hresult = CreateGenericComposite(pmkAllButLastOfFirst,
pmk,
ppmkComposite);
}
else
{
//
// a3 o b resulted in NULL. Therefore, the result
// of the composition is pmkAllButLastOfFirst
//
*ppmkComposite = pmkAllButLastOfFirst;
pmkAllButLastOfFirst->AddRef();
hresult = NOERROR;
}
}
goto exitRet;
}
//
// case 4: (a1 a2 ... aN) o (b1 b2 .. bN )
//
// Compose two composite monikers. In order to compose them, we need
// to compose ( A ) with b1, then recurse to do ( A b1 ) with b2, etc
//
//
mnkDebugOut((DEB_ITRACE,
"::CreateGenericComposite( C(%x) o C(%x) )\n",
pmkFirst,
pmkRest));
pmkFirstOfRest = pCMkRest->First();
if (pmkFirstOfRest == NULL)
{
hresult = E_OUTOFMEMORY;
goto exitRet;
}
pmkAllButFirstOfRest = pCMkRest->AllButFirst();
if (pmkAllButFirstOfRest == NULL)
{
hresult = E_OUTOFMEMORY;
goto exitRet;
}
hresult = pmkLastOfFirst->ComposeWith(pmkFirstOfRest, TRUE, &pmk);
if (hresult == MK_E_NEEDGENERIC)
{
//
// In this case, aN didn't know how to compose with b1, other than
// to do it generically. The best we can do is to generically
// compose the two halves.
//
Assert(pmk == NULL);
hresult = Concatenate(pmkFirst, pmkRest, ppmkComposite);
}
else if (SUCCEEDED(hresult))
{
//
// If pmk is not NULL, then there was a result of the composition.
// Create a new composite with the first part, then compose it with
// whats left of the second part.
//
if (pmk != NULL)
{
hresult = CreateGenericComposite(pmkAllButLastOfFirst, pmk, &pmk2);
if (FAILED(hresult))
{
goto exitRet;
}
hresult = CreateGenericComposite(pmk2, pmkAllButFirstOfRest, ppmkComposite);
}
else
{
//
// pmkLastOfFirst annihilated pmkFirstOfRest
//
// Thats OK. Compose the remaining parts.
//
hresult = CreateGenericComposite(pmkAllButLastOfFirst,
pmkAllButFirstOfRest,
ppmkComposite);
}
}
exitRet:
if (pmkFirstOfRest) pmkFirstOfRest->Release();
if (pmkAllButFirstOfRest) pmkAllButFirstOfRest->Release();
if (pmkAllButLastOfFirst) pmkAllButLastOfFirst->Release();
if (pmkLastOfFirst) pmkLastOfFirst->Release();
if (pmk) pmk->Release();
if (pmk2) pmk2->Release();
CALLHOOKOBJECTCREATE(hresult, CLSID_CompositeMoniker, IID_IMoniker, (IUnknown **)ppmkComposite);
errRtn:
OLETRACEOUT((API_CreateGenericComposite, hresult));
return hresult;
}
//------------------------------------------------
// Implementation of CCompositeMonikerEnum
CCompositeMonikerEnum::CCompositeMonikerEnum( BOOL fForward,
CCompositeMoniker FAR* pCM)
{
GET_A5();
Assert(pCM != NULL);
m_refs = 0;
m_pCM = pCM;
pCM -> AddRef();
m_fForward = fForward;
m_pBase = NULL;
m_pTop = NULL;
m_pNext = GetNext(pCM); // m_pNext points to the next moniker to return
}
CCompositeMonikerEnum::~CCompositeMonikerEnum(void)
{
M_PROLOG(this);
se FAR* pse;
se FAR* pse2;
if (m_pCM)
m_pCM->Release();
for (pse = m_pBase; pse != NULL; pse = pse2)
{
pse2 = pse->m_pseNext;
pse->m_pseNext = NULL; // workaround for compiler optimization bug
delete pse;
}
}
BOOL CCompositeMonikerEnum::Push( CCompositeMoniker FAR* pCM)
// push the composite moniker onto our stack
{
M_PROLOG(this);
se FAR * pse;
pse = new se(pCM);
if (pse == NULL)
{
return FALSE;
}
pse->m_psePrev = m_pTop;
if (m_pTop) m_pTop->m_pseNext = pse;
m_pTop = pse;
if (m_pBase == NULL) m_pBase = pse;
return TRUE;
}
LPMONIKER CCompositeMonikerEnum::GetNext( LPMONIKER pmk )
{
M_PROLOG(this);
LPMONIKER pmkRover = pmk;
Assert(pmk != NULL);
if (pmk == NULL) return NULL;
CCompositeMoniker *pCMk; ;
while ((pCMk = IsCompositeMoniker(pmkRover)) != NULL)
{
if (!Push(pCMk))
{
return NULL;
}
pmkRover = (m_fForward ? pCMk->m_pmkLeft : pCMk->m_pmkRight);
}
return pmkRover;
}
LPMONIKER CCompositeMonikerEnum::Pop( void )
{
M_PROLOG(this);
CCompositeMoniker FAR* pCM;
se FAR * pse;
if (m_pTop == NULL) return NULL;
pCM = m_pTop->m_pCM;
if ((pse = m_pTop->m_psePrev) != NULL)
{
pse->m_pseNext = NULL;
}
else m_pBase = NULL;
delete m_pTop;
m_pTop = pse;
Assert(pCM->m_pmkRight != NULL);
Assert(pCM->m_pmkLeft != NULL);
return GetNext(m_fForward ? pCM->m_pmkRight : pCM->m_pmkLeft);
}
STDMETHODIMP CCompositeMonikerEnum::QueryInterface (THIS_ REFIID riid, LPVOID FAR* ppvObj)
{
M_PROLOG(this);
VDATEPTROUT(ppvObj, LPVOID);
*ppvObj = NULL;
VDATEIID(riid);
if (IsEqualIID(riid, IID_IEnumMoniker)
|| IsEqualIID(riid, IID_IUnknown))
{
*ppvObj = this;
AddRef();
return NOERROR;
}
*ppvObj = NULL;
return ResultFromScode(E_NOINTERFACE);
}
STDMETHODIMP_(ULONG) CCompositeMonikerEnum::AddRef (THIS)
{
M_PROLOG(this);
InterlockedIncrement((long *)&m_refs);
return m_refs;
}
STDMETHODIMP_(ULONG) CCompositeMonikerEnum::Release (THIS)
{
M_PROLOG(this);
Assert(m_refs != 0);
ULONG ul = m_refs;
if (InterlockedDecrement((long *)&m_refs) == 0)
{
delete this;
return 0;
}
return ul - 1;
}
STDMETHODIMP CCompositeMonikerEnum::Next (THIS_ ULONG celt, LPMONIKER FAR* reelt, ULONG FAR* pceltFetched)
{
A5_PROLOG(this);
VDATEPTROUT(reelt, LPMONIKER);
*reelt = NULL;
if (pceltFetched) VDATEPTROUT(pceltFetched, ULONG);
ULONG count = 0;
while (count < celt)
{
if (m_pNext)
{
*reelt = m_pNext;
m_pNext->AddRef();
count++;
reelt++;
m_pNext = Pop();
}
else goto ret;
}
ret:
if (pceltFetched) *pceltFetched = count;
if (count == celt){
RESTORE_A5();
return NOERROR;
}
RESTORE_A5();
return ResultFromScode(S_FALSE);
}
STDMETHODIMP CCompositeMonikerEnum::Skip (THIS_ ULONG celt)
{
M_PROLOG(this);
ULONG count = 0;
while (count < celt)
{
if (m_pNext)
{
count++;
m_pNext = Pop();
}
else return ResultFromScode(S_FALSE);
}
return NOERROR;
}
STDMETHODIMP CCompositeMonikerEnum::Reset (THIS)
{
M_PROLOG(this);
se FAR* pse;
se FAR* pse2;
for (pse=m_pBase; pse != NULL; pse = pse2)
{
pse2 = pse->m_pseNext;
pse->m_pseNext = NULL; // workaround for compiler optimization bug
delete pse;
}
m_pBase = NULL;
m_pTop = NULL;
m_pNext = GetNext(m_pCM);
if (m_pNext) return NOERROR;
return ResultFromScode(S_FALSE);
}
STDMETHODIMP CCompositeMonikerEnum::Clone (THIS_ LPENUMMONIKER FAR* ppenm)
{
M_PROLOG(this);
VDATEPTROUT(ppenm, LPENUMMONIKER);
*ppenm = NULL;
CairoleAssert(FALSE && "Clone not implemented for composite moniker enums");
return ResultFromScode(E_NOTIMPL); // Clone not implemented for composite moniker enums
}
LPENUMMONIKER CCompositeMonikerEnum::Create
(BOOL fForward, CCompositeMoniker FAR* pCM)
{
CCompositeMonikerEnum FAR* pCME =
new CCompositeMonikerEnum(fForward, pCM);
if (pCME && pCME->m_pNext)
{
pCME->AddRef();
return pCME;
}
else
{
delete pCME;
return NULL;
}
}
STDAPI MonikerCommonPrefixWith( LPMONIKER pmkThis, LPMONIKER pmkOther,
LPMONIKER FAR * ppmkPrefix)
{
OLETRACEIN((API_MonikerCommonPrefixWith, PARAMFMT("pmkThis= %p, pmkOther= %p, ppmkPrefix= %p"),
pmkThis, pmkOther, ppmkPrefix));
mnkDebugOut((DEB_ITRACE,
"CCompositeMoniker::CommonPrefixWith(pmkThis=%x,pmkOther=%x)\n",
pmkThis,
pmkOther));
HRESULT hresult;
CALLHOOKOBJECT(S_OK,CLSID_NULL,IID_IMoniker,(IUnknown **)&pmkThis);
CALLHOOKOBJECT(S_OK,CLSID_NULL,IID_IMoniker,(IUnknown **)&pmkOther);
if (IsCompositeMoniker(pmkThis))
{
hresult = pmkThis->CommonPrefixWith(pmkOther, ppmkPrefix);
// AssertOutPtrIface(hresult, *ppmkPrefix);
goto errRtn;
}
if (IsCompositeMoniker(pmkOther))
{
hresult = pmkOther->CommonPrefixWith(pmkThis, ppmkPrefix);
// AssertOutPtrIface(hresult, *ppmkPrefix);
if (MK_S_HIM == GetScode(hresult))
hresult = ResultFromScode(MK_S_ME);
else if (MK_S_ME == GetScode(hresult))
hresult = ResultFromScode(MK_S_HIM);
goto errRtn;
}
// This doesn't get called unless the monikers are atomic and unrelated
*ppmkPrefix = NULL;
hresult = ResultFromScode(MK_E_NOPREFIX);
errRtn:
OLETRACEOUT((API_MonikerCommonPrefixWith, hresult));
return hresult;
}
STDAPI MonikerRelativePathTo(LPMONIKER pmkSrc, LPMONIKER pmkDest, LPMONIKER
FAR* ppmkRelPath, BOOL dwReserved)
{
// An implementation of RelativePathTo should check to see if the
// other moniker is a type that it recognizes and handles specially.
// If not, it should call MonikerRelativePathTo, which will handle
// the generic composite cases correctly. Note that this cannot be
// done entirely in the CCompositeMoniker implementation because if the
// first moniker is not a generic composite and the second is, then
// this code is required.
// CODEWORK: This comment is obsolete. fCalledFromMethod has changed
// to dwReserved wich must always be TRUE
//
// If fCalledFromMethod is false, and if neither moniker is a generic
// composite, then this function will call pmkSrc->RelativePathTo. If
// fCalledFromMethod is true, it will not call pmkSrc->RelativePathTo,
// since the assumption is that pmkSrc->RelativePathTo has called
// MonikerRelativePathTo after determining that pmkDest is not of a type
// that it recognizes.
OLETRACEIN((API_MonikerRelativePathTo,
PARAMFMT("pmkSrc= %p, pmkDest= %p, ppmkRelPath= %p, dwReserved= %B"),
pmkSrc, pmkDest, ppmkRelPath, dwReserved));
mnkDebugOut((DEB_ITRACE,
"CCompositeMoniker::MonikerRelativePathTo(pmkSrc=%x,pmkDest=%x)\n",
pmkSrc,
pmkDest));
HRESULT hresult;
int caseId = 0;
LPMONIKER pmkFirst = NULL;
LPMONIKER pmkRest = NULL;
LPMONIKER pmkPartialRelPath = NULL;
CCompositeMoniker FAR* pccmDest;
// Check the reserved parameter, which must be TRUE
if (dwReserved != TRUE)
{
*ppmkRelPath = NULL;
hresult = E_INVALIDARG;
goto errRtn;
}
CALLHOOKOBJECT(S_OK,CLSID_NULL,IID_IMoniker,(IUnknown **)&pmkSrc);
CALLHOOKOBJECT(S_OK,CLSID_NULL,IID_IMoniker,(IUnknown **)&pmkDest);
VDATEPTROUT_LABEL(ppmkRelPath,LPMONIKER, errRtn, hresult);
*ppmkRelPath = NULL;
VDATEIFACE_LABEL(pmkSrc, errRtn, hresult);
VDATEIFACE_LABEL(pmkDest, errRtn, hresult);
pccmDest = IsCompositeMoniker(pmkDest);
if (IsCompositeMoniker(pmkSrc)) caseId++;
if (pccmDest) caseId += 2;
switch (caseId)
{
case 0: // neither moniker is composite
if (dwReserved)
{
*ppmkRelPath = pmkDest;
pmkDest->AddRef();
hresult = ResultFromScode(MK_S_HIM);
goto errRtn;
}
// fall-through to the next case if !dwReserved is
// deliberate
case 3:
case 1: // Src is composite, other might be. Let CCompositeMoniker
// implementation handle it.
hresult = pmkSrc->RelativePathTo(pmkDest, ppmkRelPath);
// AssertOutPtrIface(hresult, *ppmkRelPath);
goto errRtn;
case 2: // Src is not composite, Dest is.
pmkFirst = pccmDest->First();
pmkRest = pccmDest->AllButFirst();
if (NOERROR == pmkSrc->IsEqual(pmkFirst))
{
*ppmkRelPath = pmkRest;
pmkRest->AddRef();
hresult = NOERROR;
}
else
{
hresult = pmkSrc->RelativePathTo(pmkFirst, &pmkPartialRelPath);
// AssertOutPtrIface(hresult, pmkPartialRelPath);
if (NOERROR == hresult)
{
hresult = CreateGenericComposite(pmkPartialRelPath, pmkRest,
ppmkRelPath);
}
else
{
*ppmkRelPath = pmkDest;
pmkDest->AddRef();
hresult = ResultFromScode(MK_S_HIM);
}
}
if (pmkFirst) pmkFirst->Release();
if (pmkRest) pmkRest->Release();
if (pmkPartialRelPath) pmkPartialRelPath->Release();
}
errRtn:
OLETRACEOUT((API_MonikerRelativePathTo, hresult));
return hresult;
}
//+-------------------------------------------------------------------------
//
// Class: CTrackingCompositeMoniker
//
// Purpose: Provide implementation of ITrackingMoniker for composite
// monikers.
//
// Notes: This object responds to ITrackingMoniker and forwards other
// QI's to the composite moniker.
//
// EnableTracking currently only enables tracking on the moniker to
// left. When we expose this functionality, we will need to
// try QI to ITrackingMoniker on the right moniker and pass the
// moniker to left (as all other moniker fns do.)
//
//--------------------------------------------------------------------------
#ifdef _TRACKLINK_
VOID
CTrackingCompositeMoniker::SetParent(CCompositeMoniker *pCCM)
{
_pCCM = pCCM;
}
STDMETHODIMP CTrackingCompositeMoniker::QueryInterface(REFIID riid, void **ppv)
{
if (IsEqualIID(IID_ITrackingMoniker, riid))
{
*ppv = (ITrackingMoniker*) this;
_pCCM->AddRef();
return(S_OK);
}
else
return(_pCCM->QueryInterface(riid, ppv));
}
STDMETHODIMP_(ULONG) CTrackingCompositeMoniker::AddRef()
{
return(_pCCM->AddRef());
}
STDMETHODIMP_(ULONG) CTrackingCompositeMoniker::Release()
{
return(_pCCM->Release());
}
STDMETHODIMP CTrackingCompositeMoniker::EnableTracking( IMoniker *pmkToLeft, ULONG ulFlags )
{
ITrackingMoniker *ptm=NULL;
HRESULT hr;
hr = _pCCM->m_pmkLeft->QueryInterface(IID_ITrackingMoniker, (void**) &ptm);
if (hr == S_OK)
{
hr = ptm->EnableTracking(NULL, ulFlags);
if (hr == S_OK)
{
if (ulFlags & OT_ENABLEREDUCE)
{
_pCCM->m_fReduceForced = TRUE;
}
if (ulFlags & OT_DISABLEREDUCE)
{
_pCCM->m_fReduceForced = FALSE;
}
}
ptm->Release();
}
return(hr);
}
#endif
#ifdef _DEBUG
STDMETHODIMP_(void) NC(CCompositeMoniker,CDebug)::Dump( IDebugStream FAR * pdbstm)
{
VOID_VDATEIFACE(pdbstm);
*pdbstm << "CCompositeMoniker @" << (VOID FAR *)m_pCompositeMoniker;
*pdbstm << '\n';
pdbstm->Indent();
*pdbstm << "Refcount is " << (int)(m_pCompositeMoniker->m_refs) << '\n';
pdbstm->Indent();
*pdbstm << m_pCompositeMoniker->m_pmkLeft;
*pdbstm << m_pCompositeMoniker->m_pmkRight;
pdbstm->UnIndent();
pdbstm->UnIndent();
}
STDMETHODIMP_(BOOL) NC(CCompositeMoniker,CDebug)::IsValid( BOOL fSuspicious )
{
return ((LONG)(m_pCompositeMoniker->m_refs) > 0);
// add more later, maybe
}
#endif