mirror of https://github.com/lianthony/NT4.0
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.
710 lines
21 KiB
710 lines
21 KiB
//+-------------------------------------------------------------------
|
|
//
|
|
// File: remoteu.cxx
|
|
//
|
|
// Copyright (c) 1996-1996, Microsoft Corp. All rights reserved.
|
|
//
|
|
// Contents: Remote Unknown object implementation
|
|
//
|
|
// Classes: CRemoteUnknown
|
|
//
|
|
// History: 23-Feb-95 AlexMit Created
|
|
//
|
|
//--------------------------------------------------------------------
|
|
#include <ole2int.h>
|
|
#include <remoteu.hxx> // CRemoteUnknown
|
|
#include <ipidtbl.hxx> // COXIDTable, CIPIDTable
|
|
#include <stdid.hxx> // CStdIdentity
|
|
#include <channelb.hxx> // CRpcChannelBuffer
|
|
#include <resolver.hxx> // giPingPeriod
|
|
#include <security.hxx> // FromLocalSystem
|
|
|
|
CRemoteUnknown *gpMTARemoteUnknown = NULL;
|
|
|
|
const WCHAR *gLocalName = L"\\\\\\Thread to thread";
|
|
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CRemoteUnknown::CRemoteUnknown, public
|
|
//
|
|
// Synopsis: ctor for the CRemoteUnknown
|
|
//
|
|
// History: 22-Feb-95 Rickhi Created
|
|
//
|
|
//--------------------------------------------------------------------
|
|
CRemoteUnknown::CRemoteUnknown(HRESULT &hr, IPID *pipid) :
|
|
_pStdId(NULL)
|
|
{
|
|
ASSERT_LOCK_HELD
|
|
|
|
// Marshal the remote unknown and rundown, no pinging needed. Note
|
|
// that we just marshal the IRundown interfaces since it inherits
|
|
// from IRemUnknown. This lets us use the same IPID for both
|
|
// interfaces. Also, we use the Internal version of MarshalObjRef in
|
|
// order to prevent registering the OID in the OIDTable. This allows
|
|
// us to receive Release calls during IDTableThreadUninitialize since
|
|
// we wont get cleaned up in the middle of that function. It also allows
|
|
// us to lazily create the OIDTable.
|
|
|
|
UNLOCK // release the LOCK because MarshalObjRef expects it unlocked.
|
|
|
|
OBJREF objref;
|
|
hr = MarshalInternalObjRef(objref, IID_IRundown, this, MSHLFLAGS_NOPING,
|
|
(void **)&_pStdId);
|
|
|
|
LOCK
|
|
|
|
// regardless of errors, put this object in TLS or the global. If we
|
|
// got an error marshaling, COIXIDTable::ReleaseLocalEntry still will be
|
|
// able to find us to cleanup properly.
|
|
|
|
COleTls tls;
|
|
if (tls->dwFlags & OLETLS_APARTMENTTHREADED)
|
|
{
|
|
// Store the pRemUnk in TLS so we can clean it up on CoUninitialize.
|
|
tls->pRemoteUnk = this;
|
|
}
|
|
else
|
|
{
|
|
// store the pRemUnk in the global for the MTA apartment
|
|
gpMTARemoteUnknown = this;
|
|
}
|
|
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// return the IPID to the caller, and release any allocated resources
|
|
// since all we wanted was the infrastructure, not the objref itself.
|
|
|
|
*pipid = ORSTD(objref).std.ipid;
|
|
FreeObjRef(objref);
|
|
}
|
|
|
|
ComDebOut((DEB_MARSHAL,
|
|
"CRemoteUnk::CRemoteUnk this:%x pStdId:%x hr:%x\n", this, _pStdId, hr));
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CRemoteUnknown::~CRemoteUnknown, public
|
|
//
|
|
// Synopsis: dtor for the CRemoteUnknown
|
|
//
|
|
// History: 22-Feb-95 Rickhi Created
|
|
//
|
|
//--------------------------------------------------------------------
|
|
CRemoteUnknown::~CRemoteUnknown()
|
|
{
|
|
ASSERT_LOCK_HELD
|
|
|
|
if (_pStdId)
|
|
{
|
|
UNLOCK // DisconnectObject expects lock to be released
|
|
|
|
// disconnect the standard identity and release it
|
|
_pStdId->DisconnectObject(0);
|
|
_pStdId->Release();
|
|
|
|
LOCK
|
|
}
|
|
|
|
ComDebOut((DEB_MARSHAL, "CRemoteUnk::~CRemoteUnk this:%x\n", this));
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CRemoteUnknown::QueryInterface, public
|
|
//
|
|
// Synopsis: returns supported interfaces
|
|
//
|
|
// History: 22-Feb-95 AlexMit Created
|
|
//
|
|
//--------------------------------------------------------------------
|
|
STDMETHODIMP CRemoteUnknown::QueryInterface(REFIID riid, void **ppv)
|
|
{
|
|
if (IsEqualIID(riid, IID_IRundown) || // more common than IUnknown
|
|
IsEqualIID(riid, IID_IRemUnknown) ||
|
|
IsEqualIID(riid, IID_IUnknown))
|
|
{
|
|
*ppv = (IRundown *) this;
|
|
// no need to AddRef since we dont refcount this object
|
|
return S_OK;
|
|
}
|
|
|
|
*ppv = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CRemoteUnknown::AddRef, public
|
|
//
|
|
// Synopsis: increment reference count
|
|
//
|
|
// History: 23-Feb-95 AlexMit Created
|
|
//
|
|
//--------------------------------------------------------------------
|
|
STDMETHODIMP_(ULONG) CRemoteUnknown::AddRef(void)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CRemoteUnknown::Release, public
|
|
//
|
|
// Synopsis: decrement reference count
|
|
//
|
|
// History: 23-Feb-95 AlexMit Created
|
|
//
|
|
//--------------------------------------------------------------------
|
|
STDMETHODIMP_(ULONG) CRemoteUnknown::Release(void)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Function: GetIPIDEntry, private
|
|
//
|
|
// Synopsis: find the IPIDEntry given an IPID
|
|
//
|
|
// History: 23-Feb-95 Rickhi Created
|
|
//
|
|
//--------------------------------------------------------------------
|
|
IPIDEntry *GetIPIDEntry(REFIPID ripid)
|
|
{
|
|
IPIDEntry *pEntry= gIPIDTbl.LookupIPID(ripid);
|
|
|
|
if (pEntry && !(pEntry->dwFlags & IPIDF_DISCONNECTED))
|
|
{
|
|
return pEntry;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Function: GetStdIdFromIPID, private
|
|
//
|
|
// Synopsis: find the stdid from the ipid
|
|
//
|
|
// History: 23-Feb-95 Rickhi Created
|
|
//
|
|
//--------------------------------------------------------------------
|
|
CStdIdentity *GetStdIdFromIPID(REFIPID ripid)
|
|
{
|
|
IPIDEntry *pEntry = GetIPIDEntry(ripid);
|
|
|
|
if (pEntry)
|
|
{
|
|
return pEntry->pChnl->GetStdId();
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CRemoteUnknown::RemQueryInterface, public
|
|
//
|
|
// Synopsis: returns supported interfaces
|
|
//
|
|
// History: 22-Feb-95 AlexMit Created
|
|
//
|
|
// Notes: Remote calls to QueryInterface for this OXID arrive here.
|
|
// This routine looks up the object and calls MarshalIPID on
|
|
// it for each interface requested.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
STDMETHODIMP CRemoteUnknown::RemQueryInterface(REFIPID ripid, ULONG cRefs,
|
|
USHORT cIids, IID *iids, REMQIRESULT **ppQIResults)
|
|
{
|
|
ComDebOut((DEB_MARSHAL,
|
|
"CRemUnknown::RemQueryInterface this:%x ipid:%I cRefs:%x cIids:%x iids:%x ppQIResults:%x\n",
|
|
this, &ripid, cRefs, cIids, iids, ppQIResults));
|
|
|
|
// init the out parameters
|
|
*ppQIResults = NULL;
|
|
|
|
// validate the input parameters
|
|
if (cIids == 0)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
// allocate space for the return parameters
|
|
REMQIRESULT *pQIRes = (REMQIRESULT *)CoTaskMemAlloc(cIids *
|
|
sizeof(REMQIRESULT));
|
|
|
|
if (pQIRes == NULL)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
// Remember whether the IPID is for a strong or a weak reference,
|
|
// then clear the strong/weak bit so that GetIPIDEntry will find
|
|
// the IPID. It is safe to mask off this bit because we are the
|
|
// server for this IPID and we know it's format.
|
|
|
|
DWORD mshlflags = MSHLFLAGS_NORMAL;
|
|
DWORD sorfflags = SORF_NULL;
|
|
|
|
if (ripid.Data1 & IPIDFLAG_WEAKREF)
|
|
{
|
|
mshlflags = MSHLFLAGS_WEAK;
|
|
sorfflags = SORF_WEAKREF;
|
|
((IPID &)(ripid)).Data1 &= ~IPIDFLAG_WEAKREF; // overcome the const
|
|
}
|
|
|
|
|
|
ASSERT_LOCK_RELEASED
|
|
LOCK
|
|
|
|
CStdIdentity *pStdId = GetStdIdFromIPID(ripid);
|
|
if (pStdId == NULL)
|
|
{
|
|
UNLOCK
|
|
ASSERT_LOCK_RELEASED
|
|
|
|
CoTaskMemFree(pQIRes);
|
|
return RPC_E_INVALID_OBJECT;
|
|
}
|
|
|
|
USHORT cFails = 0;
|
|
HRESULT hr = pStdId->PreventDisconnect();
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
*ppQIResults = pQIRes;
|
|
|
|
for (USHORT i=0; i < cIids; i++, pQIRes++)
|
|
{
|
|
// marshal each interface that was requested
|
|
|
|
IPIDEntry *pIPIDEntry;
|
|
pQIRes->hResult = pStdId->MarshalIPID(iids[i], cRefs, mshlflags,
|
|
&pIPIDEntry);
|
|
if (SUCCEEDED(pQIRes->hResult))
|
|
{
|
|
pStdId->FillSTD(&pQIRes->std, cRefs, mshlflags, pIPIDEntry);
|
|
pQIRes->std.flags |= sorfflags;
|
|
}
|
|
else
|
|
{
|
|
// on failure, the STDOBJREF must be NULL
|
|
memset(&pQIRes->std, 0, sizeof(pQIRes->std));
|
|
cFails++;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CoTaskMemFree(pQIRes);
|
|
}
|
|
|
|
UNLOCK
|
|
ASSERT_LOCK_RELEASED
|
|
|
|
if (cFails > 0)
|
|
{
|
|
hr = (cFails == cIids) ? E_NOINTERFACE : S_FALSE;
|
|
}
|
|
|
|
// handle any disconnects that came in while we were marshaling
|
|
// the requested interfaces.
|
|
hr = pStdId->HandlePendingDisconnect(hr);
|
|
|
|
|
|
ComDebOut((DEB_MARSHAL,
|
|
"CRemUnknown::RemQueryInterface this:%x pQIRes:%x hr:%x\n",
|
|
this, *ppQIResults, hr));
|
|
return hr;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CRemoteUnknown::GetSecBinding
|
|
//
|
|
// Synopsis: Get the security binding of the caller
|
|
//
|
|
// History: 21-Feb-96 AlexMit Created
|
|
//
|
|
//--------------------------------------------------------------------
|
|
HRESULT CRemoteUnknown::GetSecBinding( SECURITYBINDING **pSecBind )
|
|
{
|
|
HRESULT hr;
|
|
DWORD lAuthnSvc;
|
|
DWORD lAuthzSvc;
|
|
DWORD lAuthnLevel;
|
|
const WCHAR *pPrivs;
|
|
DWORD lLen;
|
|
|
|
hr = CoQueryClientBlanket( &lAuthnSvc, &lAuthzSvc, NULL,
|
|
&lAuthnLevel, NULL, (void **) &pPrivs, NULL );
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
// For thread to thread calls, make up a privilege name.
|
|
if (pPrivs == NULL && LocalCall())
|
|
pPrivs = gLocalName;
|
|
else if (lAuthnLevel == RPC_C_AUTHN_LEVEL_NONE ||
|
|
lAuthnLevel < gAuthnLevel ||
|
|
pPrivs == NULL ||
|
|
pPrivs[0] == 0)
|
|
return E_INVALIDARG;
|
|
|
|
lLen = lstrlenW( pPrivs ) * sizeof(WCHAR);
|
|
*pSecBind = (SECURITYBINDING *) PrivMemAlloc(
|
|
sizeof(SECURITYBINDING) + lLen );
|
|
if (*pSecBind != NULL)
|
|
{
|
|
// BUGBUG - Sometimes mswmsg returns authn svc 0.
|
|
if (lAuthnSvc == RPC_C_AUTHN_NONE)
|
|
lAuthnSvc = RPC_C_AUTHN_WINNT;
|
|
|
|
(*pSecBind)->wAuthnSvc = (USHORT) lAuthnSvc;
|
|
if (lAuthzSvc == RPC_C_AUTHZ_NONE)
|
|
(*pSecBind)->wAuthzSvc = COM_C_AUTHZ_NONE;
|
|
else
|
|
(*pSecBind)->wAuthzSvc = (USHORT) lAuthzSvc;
|
|
memcpy( &(*pSecBind)->aPrincName, pPrivs, lLen+2 );
|
|
return S_OK;
|
|
}
|
|
else
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CRemoteUnknown::RemAddRef, public
|
|
//
|
|
// Synopsis: increment reference count
|
|
//
|
|
// History: 22-Feb-95 AlexMit Created
|
|
//
|
|
// Description: Remote calls to AddRef for this OXID arrive
|
|
// here. This routine just looks up the correct remote
|
|
// remote handler and asks it to do the work.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
STDMETHODIMP CRemoteUnknown::RemAddRef(unsigned short cInterfaceRefs,
|
|
REMINTERFACEREF InterfaceRefs[],
|
|
HRESULT *pResults)
|
|
{
|
|
// Adjust the reference count for each entry.
|
|
|
|
ASSERT_LOCK_RELEASED
|
|
LOCK
|
|
|
|
HRESULT hr = S_OK;
|
|
HRESULT hr2;
|
|
SECURITYBINDING *pSecBind = NULL;
|
|
REMINTERFACEREF *pNext = InterfaceRefs;
|
|
|
|
for (USHORT i=0; i < cInterfaceRefs; i++, pNext++)
|
|
{
|
|
// Get the IPIDEntry for the specified IPID.
|
|
IPIDEntry *pEntry = GetIPIDEntry(pNext->ipid);
|
|
if (!pEntry)
|
|
{
|
|
// Don't assert on failure. The server can disconnect and go away
|
|
// while clients exist.
|
|
pResults[i] = hr = CO_E_OBJNOTREG;
|
|
continue;
|
|
}
|
|
|
|
// get the stdmarshal identity
|
|
CStdIdentity *pStdId = pEntry->pChnl->GetStdId();
|
|
|
|
if (pStdId)
|
|
{
|
|
ComDebOut((DEB_MARSHAL,
|
|
"CRemUnknown::RemAddRef pEntry:%x cCur:%x cAdd:%x cStdId:%x ipid:%I\n", pEntry,
|
|
pEntry->cStrongRefs, pNext->cPublicRefs, pStdId->GetRC(), &pNext->ipid));
|
|
|
|
Win4Assert(pNext->cPublicRefs > 0 ||
|
|
pNext->cPrivateRefs > 0);
|
|
|
|
// Lookup security info the first time an entry asks for
|
|
// secure references.
|
|
if (pNext->cPrivateRefs != 0 && pSecBind == NULL)
|
|
{
|
|
hr2 = GetSecBinding( &pSecBind );
|
|
if (FAILED(hr2))
|
|
{
|
|
hr = pResults[i] = hr2;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
hr2 = pStdId->IncSrvIPIDCnt(pEntry, pNext->cPublicRefs,
|
|
pNext->cPrivateRefs, pSecBind,
|
|
MSHLFLAGS_NORMAL);
|
|
if (FAILED(hr2))
|
|
hr = pResults[i] = hr2;
|
|
else
|
|
pResults[i] = S_OK;
|
|
}
|
|
else
|
|
hr = pResults[i] = CO_E_OBJNOTREG;
|
|
}
|
|
|
|
UNLOCK
|
|
ASSERT_LOCK_RELEASED
|
|
|
|
PrivMemFree( pSecBind );
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CRemoteUnknown::RemRelease, public
|
|
//
|
|
// Synopsis: decrement reference count
|
|
//
|
|
// History: 22-Feb-95 AlexMit Created
|
|
//
|
|
// Description: Remote calls to Release for this OXID arrive
|
|
// here. This routine just looks up the correct remote
|
|
// remote handler and asks it to do the work.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
STDMETHODIMP CRemoteUnknown::RemRelease(unsigned short cInterfaceRefs,
|
|
REMINTERFACEREF InterfaceRefs[])
|
|
{
|
|
REMINTERFACEREF *pNext = InterfaceRefs;
|
|
SECURITYBINDING *pSecBind = NULL;
|
|
|
|
ASSERT_LOCK_RELEASED
|
|
LOCK
|
|
|
|
// Adjust the reference count for each entry.
|
|
for (USHORT i=0; i < cInterfaceRefs; i++, pNext++)
|
|
{
|
|
// Get the entry for the requested IPID. Remember whether this
|
|
// is an IPID for a strong or a weak reference, then clear the
|
|
// strong/weak bit so that GetIPIDEntry will find the IPID.
|
|
|
|
DWORD mshlflags = (InterfaceRefs[i].ipid.Data1 & IPIDFLAG_WEAKREF)
|
|
? MSHLFLAGS_WEAK : MSHLFLAGS_NORMAL;
|
|
|
|
InterfaceRefs[i].ipid.Data1 &= ~IPIDFLAG_WEAKREF;
|
|
IPIDEntry *pEntry = GetIPIDEntry(InterfaceRefs[i].ipid);
|
|
|
|
if (pEntry)
|
|
{
|
|
// Get the entry for the requested IPID.
|
|
CStdIdentity *pStdId = pEntry->pChnl->GetStdId();
|
|
|
|
if (pStdId)
|
|
{
|
|
|
|
// Get the client's security binding on the first entry
|
|
// that releases secure references.
|
|
if (pNext->cPrivateRefs > 0 && pSecBind == NULL)
|
|
{
|
|
GetSecBinding( &pSecBind );
|
|
if (pSecBind == NULL)
|
|
continue;
|
|
}
|
|
pStdId->AddRef();
|
|
|
|
ComDebOut((DEB_MARSHAL,
|
|
"CRemUnknown::RemRelease pEntry:%x cCur:%x cStdId:%x cRel:%x mshlflags:%x ipid:%I\n", pEntry,
|
|
(mshlflags == MSHLFLAGS_WEAK) ? pEntry->cWeakRefs : pEntry->cStrongRefs,
|
|
pStdId->GetRC(), pNext->cPublicRefs, mshlflags, &pNext->ipid));
|
|
|
|
Win4Assert(pNext->cPublicRefs > 0 || pNext->cPrivateRefs > 0);
|
|
|
|
// Prevent a disconnect from occuring while releasing the
|
|
// interface since we have to yield the ORPC lock.
|
|
HRESULT hr = pStdId->PreventDisconnect();
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
pStdId->DecSrvIPIDCnt(pEntry, pNext->cPublicRefs,
|
|
pNext->cPrivateRefs, pSecBind,
|
|
mshlflags);
|
|
}
|
|
|
|
// do the final release of the object while not holding
|
|
// the lock, since it may call into the server.
|
|
|
|
UNLOCK
|
|
ASSERT_LOCK_RELEASED
|
|
|
|
// This will handle any Disconnect that came in while we were
|
|
// busy. Ignore error codes since we are releasing.
|
|
pStdId->HandlePendingDisconnect(hr);
|
|
|
|
pStdId->Release();
|
|
|
|
ASSERT_LOCK_RELEASED
|
|
LOCK
|
|
}
|
|
}
|
|
}
|
|
|
|
UNLOCK
|
|
ASSERT_LOCK_RELEASED
|
|
|
|
PrivMemFree( pSecBind );
|
|
return S_OK;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CRemoteUnknown::RemChangeRefs, public
|
|
//
|
|
// Synopsis: Change an interface reference from strong/weak or vice versa.
|
|
//
|
|
// History: 08-Nov-95 Rickhi Created
|
|
//
|
|
// Note: It is safe for this routine to ignore private refcounts
|
|
// becuase it is only called locally hence we own the client
|
|
// implementation and can guarantee they are zero.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP CRemoteUnknown::RemChangeRef(ULONG flags, USHORT cInterfaceRefs,
|
|
REMINTERFACEREF InterfaceRefs[])
|
|
{
|
|
ASSERT_LOCK_RELEASED
|
|
LOCK
|
|
|
|
// figure out the flags to pass to the Inc/DecSrvIPIDCnt
|
|
BOOL fMakeStrong = flags & IRUF_CONVERTTOSTRONG;
|
|
DWORD IncFlags = fMakeStrong ? MSHLFLAGS_NORMAL : MSHLFLAGS_WEAK;
|
|
DWORD DecFlags = fMakeStrong ? MSHLFLAGS_WEAK : MSHLFLAGS_NORMAL;
|
|
DecFlags |= (flags & IRUF_DISCONNECTIFLASTSTRONG) ? 0 : MSHLFLAGS_KEEPALIVE;
|
|
|
|
CStdIdentity *pStdId = NULL;
|
|
|
|
for (USHORT i=0; i < cInterfaceRefs; i++)
|
|
{
|
|
// Get the entry for the specified IPID.
|
|
IPIDEntry *pEntry = GetIPIDEntry(InterfaceRefs[i].ipid);
|
|
|
|
if (pEntry)
|
|
{
|
|
// find the StdId for this IPID. We assume that the client
|
|
// only gives us IPIDs for the same object, so first time
|
|
// we find a StdId we remember it and AddRef it. This is a safe
|
|
// assumption cause the client is local to this machine (ie
|
|
// we wrote the client).
|
|
|
|
CStdIdentity *pStdIdTmp = pEntry->pChnl->GetStdId();
|
|
|
|
if (pStdIdTmp != NULL)
|
|
{
|
|
if (pStdId == NULL)
|
|
{
|
|
pStdId = pStdIdTmp;
|
|
pStdId->AddRef();
|
|
}
|
|
|
|
// We assume that all IPIDs are for the same object. We
|
|
// just verify that here.
|
|
|
|
if (pStdId == pStdIdTmp)
|
|
{
|
|
// tweak the reference counts
|
|
pStdId->IncSrvIPIDCnt(
|
|
pEntry, InterfaceRefs[i].cPublicRefs,
|
|
fMakeStrong ? InterfaceRefs[i].cPrivateRefs : 0,
|
|
NULL, IncFlags);
|
|
pStdId->DecSrvIPIDCnt(
|
|
pEntry, InterfaceRefs[i].cPublicRefs,
|
|
fMakeStrong ? 0 : InterfaceRefs[i].cPrivateRefs,
|
|
NULL, DecFlags);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
UNLOCK
|
|
ASSERT_LOCK_RELEASED
|
|
|
|
if (pStdId)
|
|
{
|
|
// release the AddRef (if any) we did above
|
|
pStdId->Release();
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CRemoteUnknown::RundownOid, public
|
|
//
|
|
// Synopsis: Tell the server that no clients are using an object
|
|
//
|
|
// History: 25 May 95 AlexMit Created
|
|
//
|
|
// Description: Lookup each OID in the IDTable. If found and not
|
|
// recently marshaled, call DisconnectObject on it.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
STDMETHODIMP CRemoteUnknown::RundownOid(ULONG cOid, OID aOid[],
|
|
unsigned char afOkToRundown[])
|
|
{
|
|
DWORD iNow = GetCurrentTime();
|
|
|
|
ASSERT_LOCK_RELEASED
|
|
|
|
if (IsCallerLocalSystem())
|
|
{
|
|
LOCK
|
|
for (ULONG i = 0; i < cOid; i++)
|
|
{
|
|
afOkToRundown[i] = TRUE;
|
|
|
|
MOID moid;
|
|
MOIDFromOIDAndMID(aOid[i], gLocalMid, &moid);
|
|
|
|
CStdIdentity *pStdId;
|
|
HRESULT hr = LookupIDFromID(moid, TRUE, &pStdId);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
afOkToRundown[i] = pStdId->CanRunDown(iNow);
|
|
|
|
UNLOCK
|
|
ASSERT_LOCK_RELEASED
|
|
|
|
if (afOkToRundown[i] == TRUE)
|
|
{
|
|
pStdId->DisconnectObject( 0 );
|
|
}
|
|
pStdId->Release();
|
|
|
|
ASSERT_LOCK_RELEASED
|
|
LOCK
|
|
}
|
|
else
|
|
{
|
|
// need to look at the set of pre-registered OIDs to ensure
|
|
// we dont run these down before we use them.
|
|
|
|
afOkToRundown[i] = gResolver.ServerCanRundownOID(aOid[i]);
|
|
}
|
|
}
|
|
UNLOCK
|
|
}
|
|
|
|
// Rather then being rude and returning access denied, tell the caller
|
|
// that all the objects have been released.
|
|
else
|
|
{
|
|
ComDebOut((DEB_ERROR, "Invalid user called CRemoteUnknown::RundownOid" ));
|
|
for (ULONG i = 0; i < cOid; i++)
|
|
afOkToRundown[i] = TRUE;
|
|
}
|
|
|
|
ASSERT_LOCK_RELEASED
|
|
return S_OK;
|
|
}
|