NT4/private/ole32/com/rot/crot.cxx
2020-09-30 17:12:29 +02:00

2138 lines
60 KiB
C++

//+-------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1993.
//
// File: rot.cxx
//
// Contents: methods for implementation of ROT
//
// Functions:
//
//
// History: 11-Nov-92 Ricksa Created
// 25-Mar-94 brucema #8914 CRunningObjectTable::Register
// uninited variable
// 25-Mar-94 #10736 Fixed CRotMonikerEnum::Skip to
// return S_OK if skipping remainder of
// enumeration
// 07-Apr-94 brucema CRunningObjectTable::Register var init
// 24-Jun-94 BruceMa Validate ROT items when enum'ing
// 11-Jul-94 BruceMa Marshal moniker enumeration normal
// 28-Jul-94 BruceMa Memory sift fix
// 09-Jan-95 BruceMa Single thread ROT creation and enum'ing
// 30-Jan-95 Ricksa New ROT.
// 15-May-95 BruceMa Convert DDE ROT requests to UNC-based
//
//--------------------------------------------------------------------------
#include <ole2int.h>
#ifndef DCOM
#include <epid.hxx>
#endif
#include <safeif.hxx>
#include <rothelp.hxx>
#include <rotdata.hxx>
#include "crot.hxx"
// Semaphore used to protect ROT
COleStaticMutexSem g_RotSem;
// Running object table object
extern CRunningObjectTable *pROT = NULL;
#define MEM_PUB 0 // memory allocated via CoTaskMemAlloc
#define MEM_PRIV 1 // memory allocated via CPrivMemAlloc
extern INTERNAL CreateCommonDdeWindow(void);
//+-------------------------------------------------------------------------
//
// Member: GetMonikerCompareBuffer, private
//
// Synopsis: Get a buffer appropriate for comparing
//
// Arguments: [pmk] - input moniker
// [pmkeqbuf] - comparison buffer
// [pfiletime] - time of last change (optional)
// [pifdMoniker] - output marshaled moniker (optional)
//
// Returns: S_OK
// E_OUTOFMEMORY
//
// Algorithm: First reduce the input moniker. Then get the last change
// time if requested. Then we marshal the reduced moniker if
// that was requested. Finally, we build the ROT moniker
// comparison buffer.
//
// History: 27-Nov-93 Ricksa Created
//
// Notes: This is just a helper that is used to reduce code size.
//
//--------------------------------------------------------------------------
HRESULT GetMonikerCompareBuffer(
IMoniker *pmk,
CTmpMkEqBuf *ptmpmkeqbuf,
FILETIME *pfiletime,
InterfaceData **ppifdMoniker)
{
CairoleDebugOut((DEB_ROT, "%p _IN GetMonikerCompareBuffer "
"( %p , %p, %p , %p )\n", NULL, pmk, ptmpmkeqbuf, pfiletime,
ppifdMoniker));
HRESULT hr;
BEGIN_BLOCK
CSafeBindCtx sbctx;
CSafeMoniker smkReduced;
hr = CreateBindCtx(0, &sbctx);
if (hr != NOERROR)
{
CairoleDebugOut((DEB_ERROR,
"GetMonikerCompareBuffer CreateBindCtx failed %lX\n", hr));
EXIT_BLOCK;
}
// reduce the moniker
hr = pmk->Reduce(sbctx, MKRREDUCE_ALL, NULL, &smkReduced);
if (FAILED(hr))
{
CairoleDebugOut((DEB_ERROR,
"GetMonikerCompareBuffer IMoniker::Reduce failed %lX\n", hr));
EXIT_BLOCK;
}
if ((IMoniker *) smkReduced == NULL)
{
smkReduced.Set(pmk);
}
if (pfiletime != NULL)
{
// Try to get the time of last change. We ignore the error
// because this was the original behavior of OLE2.
smkReduced->GetTimeOfLastChange(sbctx, NULL, pfiletime);
}
// Marshal the moniker if so requested
if (ppifdMoniker != NULL)
{
// Stream to put marshaled interface in
CXmitRpcStream xrpc;
hr = CoMarshalInterface(&xrpc, IID_IMoniker, smkReduced,
MSHCTX_NOSHAREDMEM, NULL, MSHLFLAGS_TABLESTRONG);
if (hr != NOERROR)
{
CairoleDebugOut((DEB_ERROR,
"GetMonikerCompareBuffer CoMarshalInterface failed %lX\n",
hr));
EXIT_BLOCK;
}
xrpc.AssignSerializedInterface(ppifdMoniker);
}
hr = BuildRotData(
sbctx,
smkReduced,
ptmpmkeqbuf->GetBuf(),
ptmpmkeqbuf->GetSize(),
ptmpmkeqbuf->GetSizeAddr());
END_BLOCK;
CairoleDebugOut((DEB_ROT, "%p OUT GetMonikerCompareBuffer "
"( %lX ) [ %p ] \n", NULL, hr,
(ppifdMoniker != NULL) ? *ppifdMoniker : NULL));
return hr;
}
//+-------------------------------------------------------------------------
//
// Member: ReleaseSCMInterfaceData
//
// Synopsis: Release interface data returned by the SCM
//
// Arguments: [pifd] - interface data to release
//
// Algorithm: Create an RPC stream and then pass that stream to
// CoReleaseMarshalData to release any AddRefs and then
// free the memory that the interface data lives in.
//
// History: 27-Jan-95 Ricksa Created
//
// Notes: This is designed specifically for processing interface
// data returned by the SCM on Revoke from the ROT.
//
//--------------------------------------------------------------------------
void ReleaseInterfaceData(InterfaceData *pifd, DWORD dwMemType)
{
CairoleDebugOut((DEB_ROT, "%p _IN ReleaseInterfaceData "
"( %p )\n", NULL, pifd));
if (pifd != NULL)
{
// Make our interface into a stream
CXmitRpcStream xrpc(pifd);
// Tell RPC to release it -- error is for debugging purposes only
// since if this fails there isn't much we can do about it.
#if DBG == 1
HRESULT hr =
#endif // DBG
CoReleaseMarshalData(&xrpc);
#if DBG == 1
if (hr != NOERROR)
{
CairoleDebugOut((DEB_ERROR,
"ReleaseInterfaceData CoReleaseMarshalData failed: %lx\n", hr));
}
#endif // DBG == 1
#ifdef DCOM
if (dwMemType == MEM_PUB)
CoTaskMemFree(pifd);
else
MIDL_user_free(pifd);
#else
MIDL_user_free(pifd);
#endif // DCOM
}
CairoleDebugOut((DEB_ROT, "%p OUT ReleaseInterfaceData ", NULL));
}
//+-------------------------------------------------------------------------
//
// Member: CROTItem::~CROTItem
//
// Synopsis: Release data connected with the entry
//
// Algorithm: Clean up a rot entry by sending a revoke to the SCM for
// the entry and taking the marshaled interfaces that the
// SCM returns and releasing the data associated with them.
//
// History: 20-Nov-93 Ricksa Created
//
//--------------------------------------------------------------------------
inline CROTItem::~CROTItem(void)
{
CairoleDebugOut((DEB_ROT, "%p _IN CROTItem::~CROTItem\n", this));
// Make sure we are in the correct apt.
Win4Assert((_hApt == GetCurrentApartmentId())
&& "CROTItem::~CROTItem from wrong apartment");
// This object is going away so we mark it invalid immediately
_wItemSig = 0;
// Place to put returned marshaled interfaces
InterfaceData *pifdObject = NULL;
InterfaceData *pifdName = NULL;
HRESULT hr = gResolver.IrotRevoke(&_scmregkey, TRUE, &pifdObject, &pifdName);
if (SUCCEEDED(hr))
{
if (!_fDontCallApp)
{
ReleaseInterfaceData(pifdObject, MEM_PRIV);
ReleaseInterfaceData(pifdName, MEM_PRIV);
}
}
#if DBG == 1
else
{
CairoleDebugOut((DEB_ROT, "Revoke FAILED: %lx\n", hr));
}
#endif // DBG == 1
CairoleDebugOut((DEB_ROT, "%p OUT CROTItem::~CROTItem\n", this));
}
//+-------------------------------------------------------------------------
//
// Member: CRunningObjectTable::Create
//
// Synopsis: Create & initialize running object table object
//
// Returns: TRUE - ROT created successfully
// FALSE - an error occurred.
//
// Algorithm: Create a new running ROT and check whether the creation
// was successful.
//
// History: 11-Nov-93 Ricksa Created
//
//--------------------------------------------------------------------------
BOOL CRunningObjectTable::Create(void)
{
CairoleDebugOut((DEB_ROT, "%p _IN CRunningObjectTable::Create\n", NULL));
// Need to synchronize ROT creation in a multithreaded environment
COleStaticLock lckSem(g_RotSem);
// The ROT may have been created by now
if (pROT == NULL)
{
// Create running object table
pROT = new CRunningObjectTable();
#if DBG == 1
if (pROT == NULL)
{
CairoleDebugOut((DEB_ERROR,"Couldn't allocate ROT!\n"));
}
#endif // DBG == 1
// Initialize the array of registrations - FALSE means we couldn't
// allocate the memory.
if (pROT && !pROT->_afvRotList.SetSize(ROT_DEF_SIZE, ROT_DEF_SIZE))
{
CairoleDebugOut((DEB_ERROR,"Couldn't allocate ROT reg array!\n"));
delete pROT;
pROT = NULL;
}
}
CairoleDebugOut((DEB_ROT, "%p OUT CRunningObjectTable::Create"
"( %lX )\n", NULL, (pROT != NULL)));
return pROT != NULL;
}
//+-------------------------------------------------------------------------
//
// Member: CRunningObjectTable::~CRunningObjectTable
//
// Synopsis: Free ROT object
//
// History: 11-Nov-93 Ricksa Created
//
// Notes: This only occurs at process exit.
//
//--------------------------------------------------------------------------
CRunningObjectTable::~CRunningObjectTable(void)
{
CairoleDebugOut((DEB_ROT,
"%p _IN CRunningObjectTable::~CRunningObjectTable\n", this));
// Get the size of the table
int cMax = _afvRotList.GetSize();
// Are there any entries in the table?
if (cMax != 0)
{
CROTItem **pprot = (CROTItem **) _afvRotList.GetAt(0);
// Clear out all the registrations
for (int i = 0; i < cMax; i++)
{
if (pprot[i] != NULL)
{
delete pprot[i];
}
}
}
CairoleDebugOut((DEB_ROT,
"%p OUT CRunningObjectTable::~CRunningObjectTable\n", this));
}
//+-------------------------------------------------------------------------
//
// Member: CRunningObjectTable::QueryInterface
//
// Synopsis: Implements QI for the ROT object
//
// Arguments: [riid] - requested id
// [ppvObj] - where to put output object.
//
// Returns: S_OK - interface is suppored
// E_NOINTERFACE - requested interface is not supported
//
// History: 11-Nov-93 Ricksa Created
//
//--------------------------------------------------------------------------
STDMETHODIMP CRunningObjectTable::QueryInterface(
REFIID riid,
LPVOID FAR* ppvObj)
{
CairoleDebugOut((DEB_ROT, "%p _IN CRunningObjectTable::QueryInterface "
"( %p , %p) \n", this, &riid, ppvObj));
HRESULT hr = S_OK;
*ppvObj = NULL;
if ((IsEqualIID(riid, IID_IRunningObjectTable)) ||
(IsEqualIID(riid, IID_IUnknown)))
{
*ppvObj = this;
}
else
{
hr = E_NOINTERFACE;
}
CairoleDebugOut((DEB_ROT, "%p _IN CRunningObjectTable::QueryInterface "
"( %lX ) [ %p ]\n", this, hr, *ppvObj));
return hr;
}
//+-------------------------------------------------------------------------
//
// Member: CRunningObjectTable::AddRef
//
// Synopsis: Add to reference count
//
// Returns: Current reference count
//
// History: 11-Nov-93 Ricksa Created
//
// Notes: Reference count is ignored with respect to object deletion
// since this is a system object and does not go away until
// CoUninitialize is called.
//
//--------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CRunningObjectTable::AddRef()
{
CairoleDebugOut((DEB_ROT, "%p _IN CRunningObjectTable::AddRef\n", this));
CairoleDebugOut((DEB_ROT, "%p OUT CRunningObjectTable::AddRef\n", this));
// Since this ignored we just return a non-zero indication
return 1;
}
//+-------------------------------------------------------------------------
//
// Member: CRunningObjectTable::Release
//
// Synopsis: Dec ref count
//
// Returns: Current reference count
//
// History: 11-Nov-93 Ricksa Created
//
// Notes: Reference count is ignored with respect to object deletion
// since this is a system object and does not go away until
// CoUninitialize is called.
//
//
//--------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CRunningObjectTable::Release()
{
CairoleDebugOut((DEB_ROT, "%p _IN CRunningObjectTable::Release\n", this));
CairoleDebugOut((DEB_ROT, "%p OUT CRunningObjectTable::Release\n", this));
// Since this ignored we just return a non-zero indication
return 1;
}
//+-------------------------------------------------------------------------
//
// Member: CRunningObjectTable::CleanupApartment
//
// Synopsis: Cleans up left-over entries from the ROT when an
// apartment exits.
//
// Arguments: [hApt] - apartment to cleanup
//
// Algorithm: Walk through the list local registrations finding each entry
// that has a matching apartment and remove those entries. We
// delete them (for WOW making sure we don't call back to the
// app).
//
// History: 24-Jun-94 Rickhi Created
// 29-Jun-94 AlexT Don't make yielding calls while holding
// the mutex
//
//--------------------------------------------------------------------------
HRESULT CRunningObjectTable::CleanupApartment(HAPT hApt)
{
CairoleDebugOut((DEB_ROT, "%p _IN CRunningObjectTable::CleanupApartment"
"( %lX )\n", this, hApt));
// Make sure all threads are locked out during lookup
COleStaticLock lckSem(g_RotSem);
// Find a spot in the array for the object
CROTItem **pprotitm = (CROTItem **) _afvRotList.GetAt(0);
for (int i = 0; i < _afvRotList.GetSize(); i++)
{
CROTItem *protitm = pprotitm[i];
if ((protitm != NULL)
&& (protitm->GetAptId() == hApt))
{
// Clean up the entry
pprotitm[i] = NULL;
if (IsWOWThread())
{
// 16-bit OLE didn't clean up stale entries; we remove
// them from the ROT but we don't call back to the
// application. Who knows what the application might do
// if we called them - they already have a missing Revoke.
protitm->DontCallApp();
}
delete protitm;
}
}
CairoleDebugOut((DEB_ROT, "%p OUT CRunningObjectTable::CleanupApartment"
"( %lX )\n", this, S_OK));
return S_OK;
}
//+-------------------------------------------------------------------------
//
// Member: CRunningObjectTable::Register
//
// Synopsis: Register an item in the ROT
//
// Arguments: [grfFlags] - whether registration keeps object alive
// [punkObject] - object to register
// [pmkObjectName] - moniker for object to register
// [pdwRegister] - id for revoke
//
// Algorithm: Validate parameters input. Then create the moniker to register,
// the comparison buffer and the marshaled moniker to put in the
// ROT. Then marshal the object to put in the ROT. Create a
// new local ROT item and reserve a space for it in our local
// table. Send registration to the SCM and exit.
//
// History: 11-Nov-93 Ricksa Created
// 26-Jul-94 AndyH #20843 - restarting OLE in the shared WOW
// 27-Jan-94 Ricksa New ROT
//
//--------------------------------------------------------------------------
STDMETHODIMP CRunningObjectTable::Register(
DWORD grfFlags,
LPUNKNOWN punkObject,
LPMONIKER pmkObjectName,
DWORD FAR* pdwRegister)
{
CairoleDebugOut((DEB_ROT, "%p _IN CRunningObjectTable::Register"
"( %lX , %p , %p , %p )\n", this, grfFlags, punkObject, pmkObjectName,
pdwRegister));
COleTls Tls;
CROTItem *protitm = NULL;
HRESULT hr = S_OK;
// Place to keep marshaled moniker buffer
InterfaceData *pifdMoniker = NULL;
// Where to put pointer to marshaled object
InterfaceData *pifdObject = NULL;
// Where to put the new ROT registration - set so an invalid
// value to tell error exit whether it needs to be cleaned up
DWORD idwPutItem = 0xFFFFFFFF;
BEGIN_BLOCK
// If we want to service OLE1 clients, we need to create the
// common Dde window now if it has not already been done.
if( !(Tls->dwFlags & OLETLS_DISABLE_OLE1DDE) )
{
CreateCommonDdeWindow();
}
// Validate parameters
if ((grfFlags & ~(ROTFLAGS_REGISTRATIONKEEPSALIVE | ROTFLAGS_ALLOWANYCLIENT))
|| !IsValidInterface(punkObject)
|| !IsValidInterface(pmkObjectName)
|| IsBadWritePtr(pdwRegister, sizeof(*pdwRegister)))
{
CairoleDebugOut((DEB_ERROR,
"CRunningObjectTable:Register Invalid Paramter\n"));
hr = E_INVALIDARG;
EXIT_BLOCK;
}
*pdwRegister = 0;
// So we can fill in last change time at registration in the SCM
FILETIME filetime;
// Get the moniker comparison buffer
CTmpMkEqBuf tmeb;
hr = GetMonikerCompareBuffer(pmkObjectName, &tmeb, &filetime,
&pifdMoniker);
if (FAILED(hr))
{
CairoleDebugOut((DEB_ERROR,
"CRunningObjectTable::Register get mk compare buf failed\n"));
EXIT_BLOCK;
}
//
// Get the marshaled interface
//
// Stream to put marshaled interface in
CXmitRpcStream xrpc;
// The way we marshal this object depends on the liveness
// characteristics specified by the caller of the operation.
hr = CoMarshalInterface(&xrpc, IID_IUnknown, punkObject,
MSHCTX_NOSHAREDMEM, NULL,
grfFlags & ROTFLAGS_REGISTRATIONKEEPSALIVE
? MSHLFLAGS_TABLESTRONG : MSHLFLAGS_TABLEWEAK);
if (hr != NOERROR)
{
// Exit if there is an error
CairoleDebugOut((DEB_ERROR,
"CRunningObjectTable::Register marshal object failed\n"));
EXIT_BLOCK;
}
xrpc.AssignSerializedInterface(&pifdObject);
// Create an entry for the local registration table
CROTItem *protitm = new CROTItem();
if (protitm == NULL)
{
// Either the allocation failed, or the constructor failed
CairoleDebugOut((DEB_ERROR,
"CRunningObjectTable::Register create ROT item failed\n"));
hr = E_OUTOFMEMORY;
EXIT_BLOCK;
}
// Temporary holder for registration ID
DWORD dwRotRegId;
// ROT Table entry as opposed to the entry we are creating
// which is called protitm.
CROTItem **pprotitm;
// Put it in the table and initalize signiture.
{
COleStaticLock lckSem(g_RotSem);
// We lock here so we don't accidently pass out duplicate
// signiture. It is important to note that we need to lock
// anyway to put the item in the array.
_wSigRotItem++;
protitm->SetSig(_wSigRotItem);
// Find a spot in the array for the object
pprotitm = (CROTItem **) _afvRotList.GetAt(0);
for (idwPutItem = 0; (int) idwPutItem < _afvRotList.GetSize();
idwPutItem++)
{
if (pprotitm[idwPutItem] == NULL)
{
break;
}
}
// Was the table full?
if ((int) idwPutItem < _afvRotList.GetSize())
{
// No -- use an empty slot.
pprotitm[idwPutItem] = protitm;
}
// Grow the array to fit the next entry.
else if (!_afvRotList.InsertAt(idwPutItem, &protitm))
{
// Couldn't reallocate memory
hr = E_OUTOFMEMORY;
EXIT_BLOCK;
}
// Build the registration ID
dwRotRegId = MakeRegID(_wSigRotItem, idwPutItem);
}
#ifndef _CHICAGO_
WCHAR wszImageName[MAX_PATH];
WCHAR * pwszExeName = 0;
if ( grfFlags & ROTFLAGS_ALLOWANYCLIENT )
{
if ( ! GetModuleFileName( NULL, wszImageName, MAX_PATH ) )
{
hr = HRESULT_FROM_WIN32( GetLastError() );
EXIT_BLOCK;
}
pwszExeName = wszImageName + lstrlenW(wszImageName) - 1;
while ( (pwszExeName != wszImageName) && (pwszExeName[-1] != L'\\') )
pwszExeName--;
}
#endif
// Notify SCM of the registration
//
// Note that CoGetCurrentProcess is for supporting the DDE layer
// which needs to find objects in the same apartment only.
//
hr = gResolver.IrotRegister(
tmeb.GetMkEqBuf(),
pifdObject,
pifdMoniker,
&filetime,
CoGetCurrentProcess(),
#ifndef _CHICAGO_
pwszExeName,
#endif
protitm->GetScmRegKey());
if (SUCCEEDED(hr))
{
*pdwRegister = dwRotRegId;
}
END_BLOCK;
if (SUCCEEDED(hr))
{
// We pass the marshaled interface buffers off to the SCM so
// it actually owns the ref counting (which is why it returns
// copies of the buffer on Revoke. However, we still have
// copies of the buffer memore here which we have to free or
// leak memory.
#ifdef DCOM
CoTaskMemFree(pifdMoniker);
CoTaskMemFree(pifdObject);
#else
MIDL_user_free(pifdMoniker);
MIDL_user_free(pifdObject);
#endif
}
else
{
// Clean up marshaled interfaces since the call has failed.
ReleaseInterfaceData(pifdMoniker, MEM_PUB);
ReleaseInterfaceData(pifdObject, MEM_PUB);
// Error clean up.
if (protitm != NULL)
{
if (idwPutItem != 0xFFFFFFFF)
{
// Registration failed on the SCM so clean up our local
// registration.
COleStaticLock lckSem(g_RotSem);
// We have to use GetAt because the table could have grown
CROTItem **pprotitm = (CROTItem **)
_afvRotList.GetAt(idwPutItem);
pprotitm[idwPutItem] = NULL;
}
// Free the item for the ROT.
delete protitm;
}
}
CairoleDebugOut((DEB_ROT, "%p OUT CRunningObjectTable::Register"
"( %lX ) [ %lX ]\n", this, hr, *pdwRegister));
return hr;
}
//+-------------------------------------------------------------------------
//
// Member: CRunningObjectTable::Revoke
//
// Synopsis: Remove a previously registered item from the table.
//
// Arguments: [dwRegister] - registration id
//
// Returns: S_OK - item was revoked
// E_INVALIDARG - dwRegister is invalid
//
// Algorithm: Convert local registration to SCM registration. Send revoke
// to the SCM. Release data associated with SCM ROT entries.
//
// History: 11-Nov-93 Ricksa Created
// 27-Nov-95 Ricksa New ROT
//
//--------------------------------------------------------------------------
STDMETHODIMP CRunningObjectTable::Revoke(DWORD dwRegister)
{
CairoleDebugOut((DEB_ROT, "%p _IN CRunningObjectTable::Revoke"
"( %lX )\n", this, dwRegister));
// Default response to bad argument
HRESULT hr = E_INVALIDARG;
// Entry
CROTItem *protitm;
// Convert handle to pointer
DWORD idwIndexToEntry;
WORD wItemSig;
GetSigAndIndex(dwRegister, &wItemSig, &idwIndexToEntry);
BEGIN_BLOCK
// Lock from other processes so another simultaneous revoke
// will not cause something strange to happen.
COleStaticLock lckSem(g_RotSem);
protitm = GetRotItem(idwIndexToEntry);
if (protitm != NULL)
{
// Found an entry so verify its signiture
if (protitm->ValidSig(wItemSig))
{
// Entry is valid so clear it out from the table
CROTItem **pprotitm = (CROTItem **)
_afvRotList.GetAt(idwIndexToEntry);
*pprotitm = NULL;
hr = S_OK;
}
}
END_BLOCK;
// We get out of the block and unlock our list and then RPC the
// call to the SCM so we don't hold our lock for the duration of
// an RPC.
if (hr == S_OK)
{
// Release the ROT item's memory.
delete protitm;
}
CairoleDebugOut((DEB_ROT, "%p OUT CRunningObjectTable::Revoke"
"( %lX )\n", this, hr));
return hr;
}
//+-------------------------------------------------------------------------
//
// Member: CRunningObjectTable::IsRunning
//
// Synopsis: See if object is running
//
// Arguments: [pmkObjectName] - name of item to search for
//
// Returns: S_OK - item is running
// S_FALSE - item is not running
//
// Algorithm: Validate input parameters. Then build a moniker comparison
// buffer. Then ask the ROT if there is a registration for
// the input moniker.
//
// History: 11-Nov-93 Ricksa Created
//
//--------------------------------------------------------------------------
STDMETHODIMP CRunningObjectTable::IsRunning(LPMONIKER pmkObjectName)
{
CairoleDebugOut((DEB_ROT, "%p _IN CRunningObjectTable::IsRunning"
"( %p )\n", this, pmkObjectName));
HRESULT hr = E_INVALIDARG;
// Validate input parameters
if (IsValidInterface(pmkObjectName))
{
// Create a buffer for the comparison
CTmpMkEqBuf tmpMkEqBuf;
// Get comparison buffer
if ((hr = GetMonikerCompareBuffer(pmkObjectName, &tmpMkEqBuf, NULL,
NULL)) == NOERROR)
{
// Look into the hint table for the object
if (IsInScm(tmpMkEqBuf.GetMkEqBuf()))
{
// Ask SCM for the object
hr = gResolver.IrotIsRunning(tmpMkEqBuf.GetMkEqBuf());
}
else
{
// If it isn't in the hint table, there is no reason
// to RPC to the ROT.
hr = S_FALSE;
}
}
}
CairoleDebugOut((DEB_ROT, "%p OUT CRunningObjectTable::IsRunning"
"( %lX )\n", this, hr));
return hr;
}
//+-------------------------------------------------------------------------
//
// Member: CRunningObjectTable::GetObject
//
// Synopsis: Get an object from the ROT
//
// Arguments: [pmkObjectName] - name of object to search for
// [ppunkObject] - where to put interface pointer.
//
// Returns: S_OK - found and returned object.
// MK_E_UNAVAILABLE - not found
//
// Algorithm: Convert the local registration ID to the SCM registration
// ID. Then send the request on to the SCM.
//
// History: 11-Nov-93 Ricksa Created
//
//--------------------------------------------------------------------------
STDMETHODIMP CRunningObjectTable::GetObject(
LPMONIKER pmkObjectName,
LPUNKNOWN *ppunkObject)
{
CairoleDebugOut((DEB_ROT, "%p _IN CRunningObjectTable::GetObject "
"( %p , %p )\n", this, pmkObjectName, ppunkObject));
// Validate arguments
HRESULT hr = E_INVALIDARG;
// Validate input parameters
if (IsValidInterface(pmkObjectName)
&& !IsBadWritePtr(ppunkObject, sizeof(*ppunkObject)))
{
*ppunkObject = NULL;
// Create a buffer for the comparison
CTmpMkEqBuf tmpMkEqBuf;
// Get comparison buffer
if ((hr = GetMonikerCompareBuffer(pmkObjectName, &tmpMkEqBuf, NULL,
NULL)) == NOERROR)
{
// Note: Process ID is 0 because we don't care about the
// process any registration will do.
hr = IGetObject(tmpMkEqBuf.GetMkEqBuf(), ppunkObject, 0);
}
else
{
CairoleDebugOut((DEB_ERROR,
"CRunningObjectTable::GetObject couldn't get comp buf\n"));
}
}
CairoleDebugOut((DEB_ROT, "%p OUT CRunningObjectTable::GetObject"
"( %lX ) [ %p ]\n", this, hr, *ppunkObject));
return hr;
}
//+-------------------------------------------------------------------------
//
// Member: CRunningObjectTable::IGetObject
//
// Synopsis: Internal call to get an object from the ROT
//
// Arguments: [pmkObjectName] - name of object to search for
// [ppunkObject] - where to put interface pointer.
// [dwThreadID] - thread ID for the object
//
// Returns: S_OK - found and returned object.
// MK_E_UNAVAILABLE - not found
//
// Algorithm: Build a moniker comparison buffer. Send request to the
// SCM. Then unmarshal the result from the SCM. If the
// unmarshal fails, then notify the SCM that the registration
// is invalid.
//
// History: 30-Jan-95 Ricksa Created
//
// Notes: This exists because OLE 1.0 compatibility requires support
// for determining whether an object is already in the ROT
// for the given process.
//
// Because this is an internal call, there is no parameter
// validation.
//
//--------------------------------------------------------------------------
STDMETHODIMP CRunningObjectTable::IGetObject(
MNKEQBUF *pmkeqbuf,
LPUNKNOWN FAR* ppunkObject,
DWORD dwThreadID)
{
CairoleDebugOut((DEB_ROT, "%p _IN CRunningObjectTable::IGetObject"
"( %p , %p , %lX )\n", this, pmkeqbuf, ppunkObject, dwThreadID));
// Validate arguments
HRESULT hr = E_INVALIDARG;
BEGIN_BLOCK
// Loop because there can be multiple bad entries in the SCM
// We loop 5 because we can theoretically loop forever so we
// want to give up after we give a good long try that should
// most likely work.
for (int i = 0; i < 5; i++)
{
// Look into the hint table for the object
if (!IsInScm(pmkeqbuf))
{
// If it isn't in the hint table, there is no reason
// to RPC to the ROT.
hr = MK_E_UNAVAILABLE;
break;
}
// Ask SCM for the object
SCMREGKEY scmregkey;
InterfaceData *pifdObject = NULL;
hr = gResolver.IrotGetObject(dwThreadID, pmkeqbuf,
&scmregkey, &pifdObject);
if (FAILED(hr))
{
// SCM couldn't find it so we are done.
break;
}
if (ppunkObject == NULL)
{
// This is really an IsRunning from DDE so we can exit
// now.
hr = NOERROR;
// free the buffer allocated
MIDL_user_free(pifdObject);
// Exit because we are done.
break;
}
// Now we have to unmarshal the object to really get the
// object.
CXmitRpcStream xrpc(pifdObject);
hr = CoUnmarshalInterface(&xrpc, IID_IUnknown,
(void **) ppunkObject);
// Whether there was an error or not we need to dump the
// memory that RPC allocated on our behalf.
MIDL_user_free(pifdObject);
if (hr == NOERROR)
{
// We got our object so we are done.
break;
}
// Tell ROT that we couldn't unmarshal this object so the entry
// is bad. We ignore any errors from the SCM because there isn't
// anything we could do about it anyway.
// Dummy parameters for revoke - we don't care about these and
// the SCM will not return them because we are a client and
// can't call CoReleaseMarshalData anyway.
InterfaceData *pifdDummy1 = NULL;
InterfaceData *pifdDummy2 = NULL;
gResolver.IrotRevoke(&scmregkey, FALSE, &pifdDummy1, &pifdDummy2);
// We couldn't get the object so we try again to see if there is
// another registration that we could use.
}
END_BLOCK;
CairoleDebugOut((DEB_ROT, "%p OUT CRunningObjectTable::IGetObject"
"( %lX ) [ %p ]\n", this, hr,
((ppunkObject == NULL) ? NULL : *ppunkObject)));
return hr;
}
//+-------------------------------------------------------------------------
//
// Member: CRunningObjectTable::NoteChangeTime
//
// Synopsis: Set the time of last change in the ROT
//
// Arguments: [dwRegister] - registration id of object
// [pfiletime] - file time of change.
//
// Returns: S_OK - new time set
//
// History: 11-Nov-93 Ricksa Created
//
//--------------------------------------------------------------------------
STDMETHODIMP CRunningObjectTable::NoteChangeTime(
DWORD dwRegister,
FILETIME *pfiletime)
{
CairoleDebugOut((DEB_ROT, "%p _IN CRunningObjectTable::NoteChangeTime"
"( %lX , %p )\n", this, dwRegister, pfiletime));
// Default result to bad argument.
HRESULT hr = E_INVALIDARG;
BEGIN_BLOCK
// Validate that parameters are valid
if (IsBadReadPtr(pfiletime, sizeof(FILETIME)))
{
CairoleDebugOut((DEB_ERROR,
"CRunningObjectTable::NoteChangeTime invalid time param\n"));
EXIT_BLOCK;
}
SCMREGKEY ScmRegKey;
{
// Lock from other threads so a revoke will not cause something
// strange to happen.
COleStaticLock lckSem(g_RotSem);
// Convert handle to pointer
DWORD idwIndexToEntry;
WORD wItemSig;
GetSigAndIndex(dwRegister, &wItemSig, &idwIndexToEntry);
CROTItem *protitm = GetRotItem(idwIndexToEntry);
if ((protitm == NULL) || !protitm->ValidSig(wItemSig))
{
// Entry is valid so clear it out from the table
CairoleDebugOut((DEB_ERROR,
"CRunningObjectTable::NoteChangeTime invalid reg key\n"));
EXIT_BLOCK;
}
ScmRegKey = *(protitm->GetScmRegKey());
}
// Outside the scope of the lock, call the SCM and returns
// it's results.
hr = gResolver.IrotNoteChangeTime(&ScmRegKey, pfiletime);
END_BLOCK;
CairoleDebugOut((DEB_ROT, "%p OUT CRunningObjectTable::NoteChangeTime"
"( %lX )\n", this, hr));
return hr;
}
//+-------------------------------------------------------------------------
//
// Member: CRunningObjectTable::GetTimeOfLastChange
//
// Synopsis: Get time of last change for a given object
//
// Arguments: [pmkObjectName] - name of object
// [pfiletime] - where to put the time of change
//
// Returns: S_OK - got time of last change.
// MK_E_UNAVAILABLE - moniker is not in the table
//
// History: 11-Nov-93 Ricksa Created
//
// Notes:
//
//--------------------------------------------------------------------------
STDMETHODIMP CRunningObjectTable::GetTimeOfLastChange(
LPMONIKER pmkObjectName,
FILETIME *pfiletime)
{
CairoleDebugOut((DEB_ROT, "%p _IN CRunningObjectTable::GetTimeOfLastChange"
"( %p , %p )\n", this, pmkObjectName, pfiletime));
HRESULT hr = E_INVALIDARG;
BEGIN_BLOCK
// Validate input parameters
if (!IsValidInterface(pmkObjectName)
|| IsBadWritePtr(pfiletime, sizeof(pfiletime)))
{
CairoleDebugOut((DEB_ERROR,
"CRunningObjectTable::GetTimeOfLastChange invalid params\n"));
EXIT_BLOCK;
}
// Create a buffer for the comparison
CTmpMkEqBuf tmpMkEqBuf;
// Get comparison buffer
if ((hr = GetMonikerCompareBuffer(pmkObjectName, &tmpMkEqBuf, NULL,
NULL)) != NOERROR)
{
CairoleDebugOut((DEB_ERROR,
"CRunningObjectTable::GetTimeOfLastChange couldn't get comp buf failed\n"));
EXIT_BLOCK;
}
// Look into the hint table for the object
if (!IsInScm(tmpMkEqBuf.GetMkEqBuf()))
{
// If it isn't in the hint table, there is no reason
// to RPC to the ROT.
hr = MK_E_UNAVAILABLE;
EXIT_BLOCK;
}
// Ask SCM for the object
SCMREGKEY scmregkey;
InterfaceData *pifdObject = NULL;
hr = gResolver.IrotGetTimeOfLastChange(tmpMkEqBuf.GetMkEqBuf(), pfiletime);
END_BLOCK;
CairoleDebugOut((DEB_ROT, "%p OUT CRunningObjectTable::GetTimeOfLastChange"
"( %lX )\n", this, hr));
return hr;
}
//+-------------------------------------------------------------------------
//
// Member: CRunningObjectTable::EnumRunning
//
// Synopsis: Get an enumerator for all objects in the ROT
//
// Arguments: [ppenumMoniker] - where to put enumerator interface
//
// Returns: S_OK - successfully built enumerator
// E_OUTOFMEMORY - could not build enumerator
//
// Algorithm: Constructor an enumerator object. Then get the list of
// all running monikers from the SCM. Finally, put that list
// into the enumerator object.
//
// History: 11-Nov-93 Ricksa Created
//
//--------------------------------------------------------------------------
STDMETHODIMP CRunningObjectTable::EnumRunning(LPENUMMONIKER *ppenumMoniker)
{
CairoleDebugOut((DEB_ROT, "%p _IN CRunningObjectTable::EnumRunning"
"( %p )\n", this, ppenumMoniker));
HRESULT hr = E_INVALIDARG;
CRotMonikerEnum *protenumMoniker = NULL;
MkInterfaceList *pMkIFList = NULL;
BEGIN_BLOCK
if (IsBadWritePtr(ppenumMoniker, sizeof(*ppenumMoniker)))
{
CairoleDebugOut((DEB_ERROR,
"CRunningObjectTable::EnumRunning invalid params\n"));
EXIT_BLOCK;
}
protenumMoniker = new CRotMonikerEnum();
if ((protenumMoniker == NULL) || !protenumMoniker->CreatedOk())
{
CairoleDebugOut((DEB_ERROR,
"CRunningObjectTable::EnumRunning couldn't create enumerator\n"));
hr = E_OUTOFMEMORY;
EXIT_BLOCK;
}
hr = gResolver.IrotEnumRunning(&pMkIFList);
if (hr != NOERROR)
{
// Return the error from the SCM
CairoleDebugOut((DEB_ERROR,
"CRunningObjectTable::EnumRunning call to SCM failed\n"));
EXIT_BLOCK;
}
hr = protenumMoniker->LoadResultFromScm(pMkIFList);
if (hr == NOERROR)
{
*ppenumMoniker = protenumMoniker;
protenumMoniker = NULL;
}
END_BLOCK
if (protenumMoniker != NULL)
{
// If our local pointer is not NULL then we just delete it and
// ignore the reference count since this means an error occurred.
delete protenumMoniker;
}
if (pMkIFList != NULL)
{
// Free all the entries
for (DWORD i = 0; i < pMkIFList->dwSize; i++)
{
MIDL_user_free(pMkIFList->apIFDList[i]);
}
// Then free the structure itself
MIDL_user_free(pMkIFList);
}
CairoleDebugOut((DEB_ROT, "%p OUT CRunningObjectTable::EnumRunning"
"( %lX ) [ %p ]\n", this, hr, *ppenumMoniker));
return hr;
}
//+-------------------------------------------------------------------------
//
// Member: CRunningObjectTable::GetObjectByPath
//
// Synopsis: Locate object in ROT by path
//
// Arguments: [lpstrPath] - path to locate in the rot
// [ppunkObject] - where to put the object if requested
// [dwThreadID] - what thread the object s/b in
//
// Returns: S_OK - successfully built enumerator
// E_OUTOFMEMORY - could not build enumerator
//
// Algorithm: Build a buffer full of objects from the local table then
// consult the ROT directory.
//
// History: 30-Jan-95 Ricksa Created
//
//--------------------------------------------------------------------------
HRESULT CRunningObjectTable::IGetObjectByPath(
LPOLESTR lpstrPath,
LPUNKNOWN *ppunkObject,
DWORD dwThreadID)
{
CairoleDebugOut((DEB_ROT, "%p _IN CRunningObjectTable::IGetObjectByPath"
"( %p , %p , %lX )\n", this, lpstrPath, ppunkObject, dwThreadID));
HRESULT hr = S_FALSE;
// Where we put the moniker we use for the moniker
CSafeMoniker smk;
if (ppunkObject)
{
*ppunkObject = NULL;
}
// Create a buffer for the comparison
CTmpMkEqBuf tmpMkEqBuf;
hr = CreateFileMonikerComparisonBuffer(lpstrPath, tmpMkEqBuf.GetBuf(),
tmpMkEqBuf.GetSize(), tmpMkEqBuf.GetSizeAddr());
if (SUCCEEDED(hr))
{
hr = IGetObject(tmpMkEqBuf.GetMkEqBuf(), ppunkObject, dwThreadID);
}
CairoleDebugOut((DEB_ROT, "%p OUT CRunningObjectTable::IGetObjectByPath"
"( %lX ) [ %p ]\n", this, hr,
((ppunkObject == NULL) ? NULL : *ppunkObject)));
return hr;
}
//+-------------------------------------------------------------------------
//
// Member: GetRunningObjectTable
//
// Synopsis: Get a pointer to the ROT
//
// Arguments: [reserved] - reserved!
// [pprot] - where to put interface pointer
//
// Returns: S_OK - got pointer
// E_UNEXPECTED - table not initialized
//
// History: 11-Nov-93 Ricksa Created
//
//--------------------------------------------------------------------------
STDAPI GetRunningObjectTable(DWORD reserved, LPRUNNINGOBJECTTABLE *pprot)
{
OLETRACEIN((API_GetRunningObjectTable, PARAMFMT("reserved= %x, pprot= %p"), pprot));
CairoleDebugOut((DEB_ROT, "%p _IN GetRunningObjectTable"
"( %p )\n", NULL, pprot));
HRESULT hr = CO_E_NOTINITIALIZED;
if ((pROT == NULL) && (g_cProcessInits > 0))
{
// If we haven't created it, create it now.
CRunningObjectTable::Create();
}
*pprot = pROT; // will be NULL in error case
if (pROT != NULL)
{
hr = S_OK;
}
CALLHOOKOBJECTCREATE(hr,CLSID_NULL,IID_IRunningObjectTable,(IUnknown **)pprot);
CairoleDebugOut((DEB_ROT, "%p OUT GetRunningObjectTable"
"( %lX ) [ %p ]\n", NULL, hr, *pprot));
OLETRACEOUT((API_GetRunningObjectTable, hr));
return hr;
}
//+-------------------------------------------------------------------------
//
// Function: CleanROTForApartment
//
// Synopsis: Get rid of running object table entries for the current APT.
//
// History: 24-Jun-94 Rickhi Created
//
//--------------------------------------------------------------------------
void CleanROTForApartment(void)
{
CairoleDebugOut((DEB_ROT, "%p _IN CleanROTForApartment"
"\n", NULL));
if (pROT)
{
pROT->CleanupApartment(GetCurrentApartmentId());
}
CairoleDebugOut((DEB_ROT, "%p OUT CleanROTForApartment"
"\n", NULL));
}
//+-------------------------------------------------------------------------
//
// Function: DestroyRunningObjectTable
//
// Synopsis: Get rid of running object table
//
// History: 11-Nov-93 Ricksa Created
//
//--------------------------------------------------------------------------
void DestroyRunningObjectTable(void)
{
CairoleDebugOut((DEB_ROT, "%p _IN DestroyRunningObjectTable"
"\n", NULL));
// It doesn't matter what the ref count is, when OLE goes, the ROT goes too.
delete pROT;
pROT = NULL;
#ifndef DCOM
// Our endpoint is history. Note that this just resides here as a
// convenient place for this to happen (and for historical reasons
// since it used to serve some practical purpose for being here).
epiForProcess.MakeEndpointInvalid();
#endif
CairoleDebugOut((DEB_ROT, "%p OUT DestroyRunningObjectTable"
"\n", NULL));
}
//+-------------------------------------------------------------------------
//
// Member: CMonikerPtrBuf::CMonikerPtrBuf
//
// Synopsis: Copy constructor for the buffer
//
// Arguments: [mkptrbuf] - buffer to copy
//
// History: 20-Nov-93 Ricksa Created
//
//--------------------------------------------------------------------------
CMonikerPtrBuf::CMonikerPtrBuf(CMonikerPtrBuf& mkptrbuf)
: CMonikerBag(mkptrbuf)
{
CairoleDebugOut((DEB_ROT, "%p _IN CMonikerPtrBuf::CMonikerPtrBuf"
"( %p )\n", this, &mkptrbuf));
// Now AddRef the copied monikers so they stay around
IMoniker **ppmk = GetArrayBase();
for (DWORD i = 0; i < GetMax(); i++)
{
ppmk[i]->AddRef();
}
CairoleDebugOut((DEB_ROT, "%p OUT CMonikerPtrBuf::CMonikerPtrBuf"
"( %p )\n", this));
}
//+-------------------------------------------------------------------------
//
// Member: CMonikerPtrBuf::~CMonikerPtrBuf
//
// Synopsis: Free items
//
// History: 23-Dec-93 Ricksa Created
//
// Notes: This object assumes that it gets its monikers addref'd
// so it is up to this object to free them.
//
//--------------------------------------------------------------------------
CMonikerPtrBuf::~CMonikerPtrBuf(void)
{
CairoleDebugOut((DEB_ROT, "%p _IN CMonikerPtrBuf::~CMonikerPtrBuf"
"\n", this));
DWORD dwSize = GetMax();
if (dwSize > 0)
{
IMoniker **ppmk = GetArrayBase();
for (DWORD i = 0; i < dwSize; i++)
{
ppmk[i]->Release();
}
}
CairoleDebugOut((DEB_ROT, "%p OUT CMonikerPtrBuf::~CMonikerPtrBuf"
"\n", this));
}
//+-------------------------------------------------------------------------
//
// Member: CRotMonikerEnum::CRotMonikerEnum
//
// Synopsis: Constructor for ROT moniker enumerator
//
// History: 11-Nov-93 Ricksa Created
//
//--------------------------------------------------------------------------
CRotMonikerEnum::CRotMonikerEnum(void)
: _cRefs(1), _dwOffset(0)
{
CairoleDebugOut((DEB_ROT, "%p _IN CRotMonikerEnum::CRotMonikerEnum"
"\n", this));
// Header does the work
CairoleDebugOut((DEB_ROT, "%p OUT CRotMonikerEnum::CRotMonikerEnum"
"\n", this));
}
//+-------------------------------------------------------------------------
//
// Member: CRotMonikerEnum::CRotMonikerEnum
//
// Synopsis: Copy constructor for ROT moniker enumerator
//
// Arguments: [rotenumMoniker] - Enumerator to copy from
//
// History: 11-Nov-93 Ricksa Created
//
//--------------------------------------------------------------------------
CRotMonikerEnum::CRotMonikerEnum(CRotMonikerEnum& rotenumMoniker)
: _cRefs(1), _dwOffset(rotenumMoniker._dwOffset),
_mkptrbuf(rotenumMoniker._mkptrbuf)
{
CairoleDebugOut((DEB_ROT, "%p _IN CRotMonikerEnum::CRotMonikerEnum"
"( %p )\n", this, &rotenumMoniker));
// Header does the work
CairoleDebugOut((DEB_ROT, "%p OUT CRotMonikerEnum::CRotMonikerEnum"
"\n", this));
}
//+-------------------------------------------------------------------------
//
// Member: CRotMonikerEnum::QueryInterface
//
// Synopsis: QI for ROT moniker enumerator
//
// Arguments: [riid] - requested interface
// [ppvObj] - where to put requested interface
//
// Returns: S_OK - returned interface
// E_NOINTERFACE - requested interface is not supported
//
// History: 11-Nov-93 Ricksa Created
//
//--------------------------------------------------------------------------
STDMETHODIMP CRotMonikerEnum::QueryInterface(REFIID riid, void **ppvObj)
{
CairoleDebugOut((DEB_ROT, "%p _IN CRotMonikerEnum::QueryInterface"
"( %p , %p )\n", this, &riid, ppvObj));
HRESULT hr = S_OK;
BEGIN_BLOCK
*ppvObj = NULL;
if (IsEqualIID(riid, IID_IUnknown) ||
IsEqualIID(riid, IID_IEnumMoniker))
{
*ppvObj = (LPVOID)this;
AddRef();
EXIT_BLOCK;
}
hr = E_NOINTERFACE;
END_BLOCK
CairoleDebugOut((DEB_ROT, "%p OUT CRotMonikerEnum::QueryInterface"
"( %lX ) [ %p ]\n", this, hr, *ppvObj));
return hr;
}
//+-------------------------------------------------------------------------
//
// Member: CRotMonikerEnum::AddRef
//
// Synopsis: Add to ref count
//
// History: 11-Nov-93 Ricksa Created
//
//--------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CRotMonikerEnum::AddRef(void)
{
CairoleDebugOut((DEB_ROT, "%p _IN CRotMonikerEnum::AddRef"
"\n", this));
InterlockedIncrement((LONG *) &_cRefs);
CairoleDebugOut((DEB_ROT, "%p OUT CRotMonikerEnum::AddRef"
"( %lX )\n", this, _cRefs));
return _cRefs;
}
//+-------------------------------------------------------------------------
//
// Member: CRotMonikerEnum::Release
//
// Synopsis: Release reference count
//
// History: 11-Nov-93 Ricksa Created
//
//--------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CRotMonikerEnum::Release(void)
{
CairoleDebugOut((DEB_ROT, "%p _IN CRotMonikerEnum::Release"
"\n", this));
LONG lRefs = InterlockedDecrement((LONG *) &_cRefs);
if (0 == lRefs)
{
delete this;
}
CairoleDebugOut((DEB_ROT, "%p OUT CRotMonikerEnum::Release"
"( %lX )\n", this, lRefs));
return (ULONG) lRefs;
}
//+-------------------------------------------------------------------------
//
// Member: CRotMonikerEnum::Next
//
// Synopsis: Get next number of requested monikers from the buffer
//
// Arguments: [celt] - number of items requested
// [reelt] - where to put table of monikers
// [pceltFetched] - number of monikers retrieved
//
// Returns: S_OK - all requested monikers successfully retrieved
// S_FALSE - entire buffer not filled.
//
// Algorithm: Loop through list returning monikers.
//
// History: 11-Nov-93 Ricksa Created
//
//--------------------------------------------------------------------------
STDMETHODIMP CRotMonikerEnum::Next(
ULONG celt,
LPMONIKER *reelt,
ULONG *pceltFetched)
{
CairoleDebugOut((DEB_ROT, "%p _IN CRotMonikerEnum::Next"
"( %lX , %p , %p )\n", this, celt, reelt, pceltFetched));
// Validate pceltFetched
if ((celt != 1) && (pceltFetched != NULL))
{
*pceltFetched = 0;
}
// Loop loading monikers until request is satisfied or we run out
for (ULONG i = 0; i < celt; i++)
{
IMoniker *pmk = _mkptrbuf.GetItem(_dwOffset++);
if (pmk == NULL)
{
break;
}
reelt[i] = pmk;
}
if (pceltFetched != NULL)
{
*pceltFetched = i;
}
HRESULT hr = (i == celt) ? S_OK : S_FALSE;
CairoleDebugOut((DEB_ROT, "%p OUT CRotMonikerEnum::Next"
"( %lX )\n", this, hr));
return hr;
}
//+-------------------------------------------------------------------------
//
// Member: CRotMonikerEnum::Skip
//
// Synopsis: Skip designated number of monikers
//
// Arguments: [celt] - number to skip
//
// Returns: S_OK - skipped requested number
// S_FALSE - # skipped greater than remaining
//
// History: 11-Nov-93 Ricksa Created
//
//--------------------------------------------------------------------------
STDMETHODIMP CRotMonikerEnum::Skip(ULONG celt)
{
CairoleDebugOut((DEB_ROT, "%p _IN CRotMonikerEnum::Skip"
"( %lX )\n", this, celt));
// Error return -- assume count to skip is larger than number of items
HRESULT hr = S_FALSE;
if (_dwOffset + celt <= _mkptrbuf.GetMax())
{
_dwOffset += celt;
hr = S_OK;
}
else
{
_dwOffset = _mkptrbuf.GetMax();
}
CairoleDebugOut((DEB_ROT, "%p OUT CRotMonikerEnum::Skip"
"( %lX )\n", this, hr));
return hr;
}
//+-------------------------------------------------------------------------
//
// Member: CRotMonikerEnum::Reset
//
// Synopsis: Reset the enumerator
//
// Returns: S_OK
//
// History: 11-Nov-93 Ricksa Created
//
//--------------------------------------------------------------------------
STDMETHODIMP CRotMonikerEnum::Reset(void)
{
CairoleDebugOut((DEB_ROT, "%p _IN CRotMonikerEnum::Reset"
"\n", this));
_dwOffset = 0;
CairoleDebugOut((DEB_ROT, "%p OUT CRotMonikerEnum::Reset"
"\n", this));
return S_OK;
}
//+-------------------------------------------------------------------------
//
// Member: CRotMonikerEnum::Clone
//
// Synopsis: Make a copy of the current enumerator
//
// Arguments: [ppenumMoniker] - where to put copy
//
// Returns: S_OK - moniker successfully cloned
// E_OUTOFMEMORY - not enough memory to clone
//
// History: 11-Nov-93 Ricksa Created
//
//--------------------------------------------------------------------------
STDMETHODIMP CRotMonikerEnum::Clone(LPENUMMONIKER FAR* ppenumMoniker)
{
CairoleDebugOut((DEB_ROT, "%p _IN CRotMonikerEnum::Clone"
"( %p )\n", this, ppenumMoniker));
// Error return
HRESULT hr = S_OK;
// Use copy constructor to create duplicate enumerator
CRotMonikerEnum *pcrotenumMoniker = new CRotMonikerEnum(*this);
if ((pcrotenumMoniker == NULL) || !pcrotenumMoniker->CreatedOk())
{
delete pcrotenumMoniker;
hr = E_OUTOFMEMORY;
}
else
{
*ppenumMoniker = (LPENUMMONIKER) pcrotenumMoniker;
}
CairoleDebugOut((DEB_ROT, "%p OUT CRotMonikerEnum::Clone"
"( %lX ) [ %p ]\n", this, hr, *ppenumMoniker));
return hr;
}
//+-------------------------------------------------------------------------
//
// Member: CRotMonikerEnum::LoadResultFromScm
//
// Synopsis: Add a list of monikers to enumerator from an object server
//
// Arguments: [pMkIFList] - list to use for input
//
// Returns: S_OK - moniker added
// E_OUTOFMEMORY - could not add any more to buffer
//
// History: 11-Nov-93 Ricksa Created
// 27-Jan-95 Ricksa New ROT
//
// Note:
//
//--------------------------------------------------------------------------
HRESULT CRotMonikerEnum::LoadResultFromScm(MkInterfaceList *pMkIFList)
{
CairoleDebugOut((DEB_ROT, "%p _IN CRotMonikerEnum::LoadResultFromScm"
"( %p )\n", this, pMkIFList));
HRESULT hr = S_OK;
for (DWORD i = 0; i < pMkIFList->dwSize; i++)
{
// Where to put the unmarshaled moniker
IMoniker *pmk;
// Unmarshal the interface from the buffer
CXmitRpcStream xrpc(pMkIFList->apIFDList[i]);
hr = CoUnmarshalInterface(&xrpc, IID_IMoniker, (void **) &pmk);
if (FAILED(hr))
{
// Really two important possibilities for failure: (1) Out of
// memory or (2) Somekind of communication failure during the
// unmarshal. Out of memory means that we are pretty well dead
// so we will return that error and ignore the others since
// if the moniker is remotely served, it can actually have
// gone away before we got around to unmarshaling it.
if (hr == E_OUTOFMEMORY)
{
break;
}
continue;
}
// Put the moniker in the array
_mkptrbuf.Add(pmk);
}
CairoleDebugOut((DEB_ROT, "%p OUT CRotMonikerEnum::LoadResultFromScm"
"( %lX )\n", this, hr));
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: GetLocalRunningObjectForDde
//
// Synopsis: Searches for and optionally returns an object by path for
// the DDE layer.
//
// Effects: Attempts to find an entry in the local ROT that matches
// the provided path. If there is a hit in the table, and
// ppunkObject is not NULL, then it also returns a pointer
// to the object.
//
// Arguments: [lpstrPath] -- Path to search for
// [ppunkObject] -- Output for the object pointer
//
// Returns: S_OK - Found object in local ROT
// S_FALSE - Didn't find object in local ROT
// OTHER - Something else happened.
//
// History: 6-29-94 kevinro Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT GetLocalRunningObjectForDde(
LPOLESTR lpstrPath,
LPUNKNOWN *ppunkObject)
{
CairoleDebugOut((DEB_ROT, "%p _IN GetLocalRunningObjectForDde"
"( %p , %p )\n", NULL, lpstrPath, ppunkObject));
HRESULT hr = S_FALSE;
// POSTPPC - We're getting close to RTM for NT/PPC, so we'll make this fix
// for Chicago only for now
#ifdef _CHICAGO_
// We create a file moniker here to ensure that the name we test against
// the ROT is in UNC form
LPMONIKER pMnk;
LPBINDCTX pBc;
LPWSTR pwszDisplayName;
hr = CreateFileMoniker(lpstrPath, &pMnk);
if (FAILED(hr))
{
return hr;
}
hr = CreateBindCtx(NULL, &pBc);
if (FAILED(hr))
{
pMnk->Release();
return hr;
}
hr = pMnk->GetDisplayName(pBc, NULL, &pwszDisplayName);
if (FAILED(hr))
{
pMnk->Release();
pBc->Release();
return hr;
}
// If there currently isn't a local ROT, then the object surely isn't
// registered.
if (pROT != NULL)
{
hr = pROT->IGetObjectByPath(pwszDisplayName, ppunkObject,
CoGetCurrentProcess());
}
else
{
hr = S_FALSE;
}
// Cleanup
pMnk->Release();
pBc->Release();
CoTaskMemFree(pwszDisplayName);
#else
//
// If there currently isn't a local ROT, then the object surely isn't
// registered.
//
if (pROT != NULL)
{
hr = pROT->IGetObjectByPath(lpstrPath, ppunkObject,
CoGetCurrentProcess());
}
#endif // _CHICAGO_
CairoleDebugOut((DEB_ROT, "%p OUT GetLocalRunningObjectForDde"
"( %lX ) [ %p ]\n", NULL, hr,
((ppunkObject == NULL) ? NULL : *ppunkObject)));
return(hr);
}
//+---------------------------------------------------------------------------
//
// Function: GetObjectFromRotByPath
//
// Synopsis: Searches for and optionally returns an object by path for
// pbkect binding.
//
// Effects: Attempts to find an entry in the ROT that matches
// the provided path. If there is a hit in the table, and
// ppunkObject is not NULL, then it also returns a pointer
// to the object.
//
// Arguments: [lpstrPath] -- Path to search for
// [ppunkObject] -- Output for the object pointer
//
// Returns: S_OK - Found object in local ROT
// S_FALSE - Didn't find object in local ROT
// OTHER - Something else happened.
//
// History: 30-Jan-95 Ricksa Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT GetObjectFromRotByPath(
LPOLESTR lpstrPath,
LPUNKNOWN *ppunkObject)
{
CairoleDebugOut((DEB_ROT, "%p _IN GetObjectFromRotByPath"
"( %p , %p )\n", NULL, lpstrPath, ppunkObject));
HRESULT hr = S_FALSE;
// Is the rot in existence yet?
if (pROT == NULL)
{
// No - create the ROT. Remember that pROT is real pointer to the
// running object table. GetRunningObjectTable returns this and
// initializes it if it is NULL. This is why we don't pay very much
// attention to prot.
IRunningObjectTable *prot;
GetRunningObjectTable(0, &prot);
// Note that we don't have to release the prot because the ROT
// doesn't care about its reference count. Its lifetime is independent
// of the reference count.
}
if (pROT != NULL)
{
hr = pROT->IGetObjectByPath(lpstrPath, ppunkObject, 0);
}
CairoleDebugOut((DEB_ROT, "%p OUT GetObjectFromRotByPath"
"( %lX ) [ %p ]\n", NULL, hr, *ppunkObject));
return(hr);
}