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.
 
 
 
 
 
 

788 lines
17 KiB

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1993 - 1993.
//
// File: cantimon.cxx
//
// Contents:
//
// Classes:
//
// Functions:
//
// History: 12-27-93 ErikGav Did not write this code
// 02-04-94 KevinRo Gag'd on it, then rewrote it
// 06-14-94 Rickhi Fix type casting
//
// An Anti moniker is intended to be the inverse of any moniker, such as
// an Item Moniker. When another moniker composes itself with an Anti moniker
// on the right, it is supposed to remove itself from the result.
//
// The original implementation of Anti monikers attempted to be optimal by
// collapsing itself when composed with another Anti moniker. This was an
// unfortunate decision, since other monikers decide to eliminate themselves
// (and the Anti moniker) based on whether the moniker type to the right is
// an Anti moniker.
//
// For example, File moniker (F) composed with an Anti moniker (A) should
// result in nothing. F o A == (). The previous implementation was in error
// because a composite of two anti-monikers was treated as a single anti
// moniker with a count of two, denoted A(2).
// Therefore, when the file moniker looked at the anti moniker using the
// interface, it saw only one Anti moniker, instead of a composite.
// ( F o A(2)) == (). It should have been ( F o (A o A) ) == ( A )
//
// To fix this, when we compose Anti monikers, we will always use a
// composite. We need to be careful when loading old serialized Anti
// monikers, and convert them as we see them.
//
// This actually makes this a sucky problem, since old monikers have a
// funny behaviour if loaded from stream. The way the Load() interface
// works, the client has a pointer to the Anti moniker before it is loaded.
// Therefore, we can't just magically make this work.
//
// However, we can fix this up as soon as we can during the first Reduce or
// Compose with that is called. You will find this code in the Compose
// with methods, plus in the Create(count) methods.
//
// Save() is also a problem, since the caller has already written out our
// class ID. Therefore, we can't just sneak in a composite, since it will
// break the old fellows.
//
//----------------------------------------------------------------------------
#include <ole2int.h>
#include "cbasemon.hxx"
#include "cantimon.hxx"
#include "mnk.h"
INTERNAL_(CAntiMoniker *) IsAntiMoniker( LPMONIKER pmk )
{
CAntiMoniker *pCAM;
if ((pmk->QueryInterface(CLSID_AntiMoniker, (void **)&pCAM)) == S_OK)
{
// we release the AddRef from QI but stll return the pointer.
pCAM->Release();
return pCAM;
}
// dont rely on user implementations to return NULL on failed QI
return NULL;
}
//+---------------------------------------------------------------------------
//
// Method: CAntiMoniker::Create
//
// Synopsis: Create a single AntiMoniker
//
// Effects:
//
// Arguments: (none)
//
// Requires:
//
// Returns:
//
// Signals:
//
// Modifies:
//
// Derivation:
//
// Algorithm:
//
// History: 2-04-94 kevinro Created
//
// Notes:
//
//----------------------------------------------------------------------------
CAntiMoniker FAR *CAntiMoniker::Create()
{
CAntiMoniker FAR * pCAM = new CAntiMoniker();
if (pCAM)
{
pCAM->AddRef();
}
return pCAM;
}
//+---------------------------------------------------------------------------
//
// Method: CAntiMoniker::Create
//
// Synopsis: Create a composite anti moniker.
//
// Effects: This function supports the 'old' way of creating Anti
// monikers, by creating [count] Anti monikers, and composing
// them together.
//
// Arguments: [count] -- Number of Anti monikers
//
// Requires:
//
// Returns:
// if count == 1, this routine will return an CAntiMoniker.
// if count > 1, this routine will create a composite moniker made up
// of Anti monikers.
//
// Signals:
//
// Modifies:
//
// Derivation:
//
// Algorithm:
//
// History: 2-04-94 kevinro Created
//
// Notes:
//
//----------------------------------------------------------------------------
IMoniker * CAntiMoniker::Create(ULONG count)
{
mnkDebugOut((DEB_ITRACE,
"CAntiMoniker::Create(0x%x))\n",
count));
HRESULT hr;
IMoniker *pmkComposite = NULL;
while(count--)
{
IMoniker *pmkNew;
CAntiMoniker FAR * pCAM = new CAntiMoniker();
//
// If there was failure, then releasing the old composite is
// required.
//
if (pCAM == NULL)
{
if (pmkComposite != NULL)
{
pmkComposite->Release();
}
return(NULL);
}
else
{
//
// The ref counting mechanism originally choosen makes it the
// responsibility of the Create() routine to do the AddRef on
// the newly created moniker.
//
pCAM->AddRef();
}
//
// Create a generic composite using the existing and new
// monikers. If this succeededs, then pmkNew will increment
// both reference counts.
//
//
// If there was a failure, then calling Release() on the new and
// old sections of the composite will cause both of them to be
// released, thus releasing the entire tree of monikers.
//
// If it succeeds, pmkNew will hold references to both of the
// old monikers, and life will be good.
//
// Note: First time around, pmkComposite == NULL, and
// CreateGenericComposite() will just return pCAM. It works.
//
hr = CreateGenericComposite(pmkComposite,pCAM,&pmkNew);
pCAM->Release();
//
// Watch out for the first time around the loop. This will
// cause pmkComposite to be NULL
//
if (pmkComposite != NULL)
{
pmkComposite->Release();
}
//
// If failed, then the last two releases cleaned up for us.
//
if (FAILED(hr))
{
return(NULL);
}
pmkComposite = pmkNew;
}
return pmkComposite;
}
STDMETHODIMP CAntiMoniker::QueryInterface(THIS_ REFIID riid,
LPVOID FAR* ppvObj)
{
M_PROLOG(this);
VDATEIID (riid);
VDATEPTROUT(ppvObj, LPVOID);
#ifdef _DEBUG
if (riid == IID_IDebug)
{
*ppvObj = &(m_Debug);
return NOERROR;
}
#endif
if (IsEqualIID(riid, CLSID_AntiMoniker))
{
// called by IsAntiMoniker.
AddRef();
*ppvObj = this;
return S_OK;
}
else if (IsEqualIID(riid, IID_IROTData))
{
// called by ROT
AddRef();
*ppvObj = (IROTData *)this;
return S_OK;
}
return CBaseMoniker::QueryInterface(riid, ppvObj);
}
STDMETHODIMP_(ULONG) CAntiMoniker::Release(void)
{
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 CAntiMoniker::GetClassID(LPCLSID lpClassId)
{
M_PROLOG(this);
VDATEPTROUT(lpClassId, CLSID);
*lpClassId = CLSID_AntiMoniker;
return NOERROR;
}
STDMETHODIMP CAntiMoniker::Load(LPSTREAM pStm)
{
mnkDebugOut((DEB_ITRACE,
"CAntiMoniker::Load(%x)\n",
this));
M_PROLOG(this);
VDATEIFACE(pStm);
HRESULT hresult;
ULONG count;
hresult = StRead(pStm, &count, sizeof(ULONG));
if (SUCCEEDED(hresult))
{
m_count = count;
}
return hresult;
}
STDMETHODIMP CAntiMoniker::Save(LPSTREAM pStm, BOOL fClearDirty)
{
mnkDebugOut((DEB_ITRACE,
"CAntiMoniker::Save(%x)\n",
this));
M_PROLOG(this);
VDATEIFACE(pStm);
UNREFERENCED(fClearDirty);
ULONG cbWritten;
return pStm->Write(&m_count, sizeof(ULONG), &cbWritten);
// REVIEW: what is proper error handling? Should we restore the seek
// pointer?
}
STDMETHODIMP CAntiMoniker::GetSizeMax(ULARGE_INTEGER FAR* pcbSize)
{
mnkDebugOut((DEB_ITRACE,
"CAntiMoniker::GetSizeMax(%x)\n",
this));
M_PROLOG(this);
VDATEPTROUT(pcbSize, ULONG);
ULISet32(*pcbSize, sizeof(CLSID) + sizeof(ULONG));
noError;
}
//+---------------------------------------------------------------------------
//
// Method: CAntiMoniker::ComposeWith
//
// Synopsis: Compose this moniker with another moniker.
//
// Effects:
//
// Arguments: [pmkRight] --
// [fOnlyIfNotGeneric] --
// [ppmkComposite] --
//
// Requires:
//
// Returns:
//
// Signals:
//
// Modifies:
//
// Derivation:
//
// Algorithm:
//
// History: 2-04-94 kevinro Created
//
// Notes:
//
// In the event that m_count > 1, we can use this opportunity to fixup the
// anti moniker into a composite of single anti monikers. This will help make
// the monikers work correctly.
//
//----------------------------------------------------------------------------
STDMETHODIMP CAntiMoniker::ComposeWith( LPMONIKER pmkRight,
BOOL fOnlyIfNotGeneric, LPMONIKER FAR* ppmkComposite)
{
mnkDebugOut((DEB_ITRACE,
"CAntiMoniker::ComposeWith(%x,pmkRight(%x))\n",
this,
pmkRight));
VDATEPTROUT(ppmkComposite,LPMONIKER);
*ppmkComposite = NULL;
VDATEIFACE(pmkRight);
HRESULT hresult = NOERROR;
IMoniker *pmkThis = NULL;
IMoniker *pmkRightComposite = NULL;
//
// The only way CAntiMonikers can compose is generically
//
if (fOnlyIfNotGeneric)
{
hresult = MK_E_NEEDGENERIC;
*ppmkComposite = NULL;
return hresult;
}
//
// Now, we are going to make a generic composite. This is a
// good time to determine if we need to convert this
// anti moniker into a composite
//
// If m_count > 1, create an equivalent composite moniker
//
if (m_count > 1)
{
pmkThis = Create(m_count);
}
//
// Regardless of the outcome, be sure pmkThis == a moniker to
// compose with.
//
if (pmkThis == NULL)
{
pmkThis = this;
}
//
// If the right side is an anti moniker also, then we need to
// concatenate the two Anti monikers into a composite.
//
CAntiMoniker *pmkRightAnti = IsAntiMoniker(pmkRight);
if (pmkRightAnti)
{
mnkDebugOut((DEB_ITRACE,
"::ComposeWith(%x) CAntiMoniker(%x)\n",
this,
pmkRight));
//
// The right side is also an Anti moniker. Does it need fixing
// as well? If so, then fix it up, and assign it to pmkRight
//
if (pmkRightAnti->m_count > 1 )
{
pmkRightComposite = CAntiMoniker::Create(m_count);
if (pmkRightComposite != NULL)
{
pmkRight = pmkRightComposite;
}
}
hresult = Concatenate(pmkThis,pmkRight,ppmkComposite);
}
else
{
//
// Anti monikers can only be composed using generic composites
// when they are on the left.
//
hresult = CreateGenericComposite( pmkThis,
pmkRight,
ppmkComposite );
}
//
// Clean up after possible conversions
//
if (pmkThis != this)
{
pmkThis->Release();
}
if (pmkRightComposite != NULL)
{
pmkRightComposite->Release();
}
return hresult;
}
STDMETHODIMP CAntiMoniker::Enum (THIS_ BOOL fForward, LPENUMMONIKER FAR* ppenumMoniker)
{
VDATEPTROUT(ppenumMoniker,LPENUMMONIKER);
*ppenumMoniker = NULL;
noError;
}
//+---------------------------------------------------------------------------
//
// Method: CAntiMoniker::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: Build ROT data for anti moniker.
//
// History: 03-Feb-95 kevinro Created
//
// Note: Validating the arguments is skipped intentionally because this
// will typically be called internally by OLE with valid buffers.
//
//----------------------------------------------------------------------------
STDMETHODIMP CAntiMoniker::GetComparisonData(
byte *pbData,
ULONG cbMax,
DWORD *pcbData)
{
ULONG ulLength = sizeof(CLSID_AntiMoniker) + sizeof(m_count);
Assert(pcbData != NULL);
Assert(pbData != NULL);
if (cbMax < ulLength)
{
return(E_OUTOFMEMORY);
}
memcpy(pbData,&CLSID_AntiMoniker,sizeof(CLSID_AntiMoniker));
memcpy(pbData+sizeof(CLSID_AntiMoniker),&m_count,sizeof(m_count));
*pcbData = ulLength;
return NOERROR;
}
STDMETHODIMP CAntiMoniker::IsEqual (THIS_ LPMONIKER pmkOtherMoniker)
{
mnkDebugOut((DEB_ITRACE,
"CAntiMoniker::IsEqual(%x,pmkOther(%x))\n",
this,
pmkOtherMoniker));
VDATEIFACE(pmkOtherMoniker);
CAntiMoniker *pCAM = IsAntiMoniker(pmkOtherMoniker);
if (pCAM)
{
// the other moniker is an anti moniker.
if (m_count == pCAM->m_count)
{
return NOERROR;
}
}
return ResultFromScode(S_FALSE);
}
STDMETHODIMP CAntiMoniker::Hash (THIS_ LPDWORD pdwHash)
{
VDATEPTROUT(pdwHash, DWORD);
*pdwHash = 0x80000000 + m_count;
noError;
}
STDMETHODIMP CAntiMoniker::CommonPrefixWith (LPMONIKER pmkOther, LPMONIKER FAR*
ppmkPrefix)
{
mnkDebugOut((DEB_ITRACE,
"CAntiMoniker::CommonPrefixWith(%x,pmkOther(%x))\n",
this,
pmkOther));
M_PROLOG(this);
VDATEPTROUT(ppmkPrefix,LPMONIKER);
*ppmkPrefix = NULL;
VDATEIFACE(pmkOther);
CAntiMoniker *pAntiMoniker = IsAntiMoniker(pmkOther);
if (pAntiMoniker)
{
if (m_count <= pAntiMoniker->m_count)
{
*ppmkPrefix = this;
AddRef();
if (m_count == pAntiMoniker->m_count)
return ResultFromScode(MK_S_US);
return ResultFromScode(MK_S_ME);
}
*ppmkPrefix = pmkOther;
pmkOther->AddRef();
return ResultFromScode(MK_S_HIM);
}
return MonikerCommonPrefixWith(this, pmkOther, ppmkPrefix);
// this handles the case where pmkOther is composite, as well as
// all other cases.
}
STDMETHODIMP CAntiMoniker::RelativePathTo (THIS_ LPMONIKER pmkOther, LPMONIKER FAR*
ppmkRelPath)
{
mnkDebugOut((DEB_ITRACE,
"CAntiMoniker::RelativePathTo(%x,pmkOther(%x))\n",
this,
pmkOther));
VDATEPTROUT(ppmkRelPath,LPMONIKER);
VDATEIFACE(pmkOther);
*ppmkRelPath = NULL;
*ppmkRelPath = pmkOther;
pmkOther->AddRef();
return MK_S_HIM;
}
STDMETHODIMP CAntiMoniker::GetDisplayName( LPBC pbc, LPMONIKER
pmkToLeft, LPWSTR FAR * lplpszDisplayName )
// return "\..\..\.. "
{
mnkDebugOut((DEB_ITRACE,
"CAntiMoniker::GetDisplayName(%x,pmkLeft(%x))\n",
this,
pmkToLeft));
M_PROLOG(this);
VDATEPTROUT(lplpszDisplayName, LPWSTR);
*lplpszDisplayName = NULL;
VDATEIFACE(pbc);
if (pmkToLeft) VDATEIFACE(pmkToLeft);
WCHAR FAR * lpch;
ULONG i;
ULONG ccDisplayName;
//
// ccDisplayName is the number of characters to allocate
//
// For each anti moniker, return one instance of '\..', which
// is 3 characters long. Also, add 1 for the terminating NULL
//
ccDisplayName = 1 + ( 3 * m_count );
*lplpszDisplayName = (WCHAR *)
CoTaskMemAlloc(sizeof(WCHAR) * ccDisplayName);
lpch = *lplpszDisplayName;
if (lpch == NULL)
{
return E_OUTOFMEMORY;
}
//
// Concat a whole bunch of strings forming the display name for
// the anti moniker
//
for (i = m_count; i > 0; i-- , lpch += 3)
{
memcpy(lpch, L"\\..", 3 * sizeof(WCHAR));
}
*lpch = '\0';
return NOERROR;
}
STDMETHODIMP CAntiMoniker::ParseDisplayName( LPBC pbc,
LPMONIKER pmkToLeft, LPWSTR lpszDisplayName, ULONG FAR* pchEaten,
LPMONIKER FAR* ppmkOut)
{
mnkDebugOut((DEB_ITRACE,
"CAntiMoniker::ParseDisplayName(%x,pmkLeft(%x)lpszName(%ws))\n",
this,
pmkToLeft,
WIDECHECK(lpszDisplayName)));
M_PROLOG(this);
VDATEPTROUT(ppmkOut,LPMONIKER);
*ppmkOut = NULL;
VDATEIFACE(pbc);
if (pmkToLeft) VDATEIFACE(pmkToLeft);
VDATEPTRIN(lpszDisplayName, WCHAR);
VDATEPTROUT(pchEaten,ULONG);
return ResultFromScode(E_NOTIMPL); // ParseDisplayName not implemented for AntiMonikers
}
STDMETHODIMP CAntiMoniker::IsSystemMoniker (THIS_ LPDWORD pdwType)
{
M_PROLOG(this);
*pdwType = MKSYS_ANTIMONIKER;
return NOERROR;
}
//+---------------------------------------------------------------------------
//
// Method: CAntiMoniker::EatOne
//
// Synopsis: This function creates an appropriate Anti moniker
//
// Effects:
//
// Arguments: [ppmk] --
//
// Requires:
//
// Returns:
// if m_count == 1, returns NULL
// if m_count == 2, returns a CAntiMoniker
// if m_count > 2, returns a composite made up of anti monikers.
//
// Signals:
//
// Modifies:
//
// Derivation:
//
// Algorithm:
//
// History: 2-04-94 kevinro Created
//
// Notes:
//
// Back in the days when monikers collapsed themselves, this routine was
// called in order to eat one of the counts. Now, it is used as a good place
// to throw in a conversion for composite anti-monikers.
//
//----------------------------------------------------------------------------
void CAntiMoniker::EatOne(LPMONIKER *ppmk)
{
mnkDebugOut((DEB_ITRACE,
"CAntiMoniker::EatOne(%x)\n",
this));
*ppmk = CAntiMoniker::Create(m_count - 1);
}
#ifdef _DEBUG
STDMETHODIMP_(void) NC(CAntiMoniker,CDebug)::Dump( IDebugStream FAR * pdbstm)
{
VOID_VDATEIFACE(pdbstm);
*pdbstm << "CAntiMoniker @" << (VOID FAR *)m_pAntiMoniker;
*pdbstm << '\n';
pdbstm->Indent();
*pdbstm << "Refcount is " << (int)(m_pAntiMoniker->m_refs) << '\n';
*pdbstm << "Anti count is " << (int)(m_pAntiMoniker->m_count) << '\n';
pdbstm->UnIndent();
}
STDMETHODIMP_(BOOL) NC(CAntiMoniker,CDebug)::IsValid( BOOL fSuspicious )
{
return ((LONG)(m_pAntiMoniker->m_refs) > 0);
// add more later, maybe
}
#endif