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.
1378 lines
43 KiB
1378 lines
43 KiB
//+-------------------------------------------------------------------
|
|
//
|
|
// File: stdid.cxx
|
|
//
|
|
// Contents: identity object and creation function
|
|
//
|
|
// History: 1-Dec-93 CraigWi Created
|
|
// 13-Sep-95 Rickhi Simplified
|
|
//
|
|
//--------------------------------------------------------------------
|
|
#include <ole2int.h>
|
|
#include <stdid.hxx> // CStdIdentity
|
|
#include <marshal.hxx> // CStdMarshal
|
|
#include <idtable.hxx> // Indentity Table
|
|
|
|
#include "..\objact\objact.hxx" // used in IProxyManager::CreateServer
|
|
|
|
|
|
#if DBG==1
|
|
// head of linked list of identities for debug tracking purposes
|
|
CStdIdentity gDbgIDHead;
|
|
#endif // DBG
|
|
|
|
|
|
//+----------------------------------------------------------------
|
|
//
|
|
// Class: CStdIdentity (stdid)
|
|
//
|
|
// Purpose: To be the representative of the identity of the object.
|
|
//
|
|
// History: 11-Dec-93 CraigWi Created.
|
|
// 21-Apr-94 CraigWi Stubmgr addref's object; move strong cnt
|
|
// 10-May-94 CraigWi IEC called for strong connections
|
|
// 17-May-94 CraigWi Container weak connections
|
|
// 31-May-94 CraigWi Tell object of weak pointers
|
|
//
|
|
// Details:
|
|
//
|
|
// The identity is determined on creation of the identity object. On the
|
|
// server side a new OID is created, on the client side, the OID contained
|
|
// in the OBJREF is used.
|
|
//
|
|
// The identity pointer is typically stored in the OIDTable, NOT AddRef'd.
|
|
// SetOID adds the identity to the table, and can be called from ctor or
|
|
// from Unmarshal. RevokeOID removes the identity from the table, and can
|
|
// be called from Disconnect, or final Release.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CStdIdentity::CStdIdentity, private
|
|
//
|
|
// Synopsis: ctor for identity object
|
|
//
|
|
// Arguments: for all but the last param, see CreateIdentityHandler.
|
|
// [ppUnkInternal] --
|
|
// when aggregated, this the internal unknown;
|
|
// when not aggregated, this is the controlling unknown
|
|
//
|
|
// History: 15-Dec-93 CraigWi Created.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
CStdIdentity::CStdIdentity(DWORD flags, IUnknown *pUnkOuter,
|
|
IUnknown *pUnkControl, IUnknown **ppUnkInternal) :
|
|
m_refs(1),
|
|
m_cStrongRefs(0),
|
|
m_flags(flags),
|
|
m_pIEC(NULL),
|
|
m_moid(GUID_NULL),
|
|
m_pUnkOuter((pUnkOuter) ? pUnkOuter : (IMultiQI *)&m_InternalUnk),
|
|
m_pUnkControl((pUnkControl) ? pUnkControl : m_pUnkOuter),
|
|
CClientSecurity( this )
|
|
{
|
|
ComDebOut((DEB_MARSHAL, "CStdIdentity %s Created this:%x\n",
|
|
IsClient() ? "CLIENT" : "SERVER", this));
|
|
Win4Assert(!!IsClient() == (pUnkControl == NULL));
|
|
|
|
#if DBG==1
|
|
// Chain this identity onto the global list of instantiated identities
|
|
// so we can track even the ones that are not placed in the ID table.
|
|
LOCK
|
|
m_pNext = gDbgIDHead.m_pNext;
|
|
m_pPrev = &gDbgIDHead;
|
|
gDbgIDHead.m_pNext = this;
|
|
m_pNext->m_pPrev = this;
|
|
UNLOCK
|
|
#endif
|
|
|
|
|
|
if (pUnkOuter)
|
|
{
|
|
m_flags |= STDID_AGGREGATED;
|
|
}
|
|
|
|
CLSID clsidHandler;
|
|
DWORD dwSMFlags = SMFLAGS_CLIENT_SIDE; // assume client side
|
|
|
|
if (!IsClient())
|
|
{
|
|
#if DBG == 1
|
|
// the caller should have a strong reference and so these tests
|
|
// should not disturb the object. These just check the sanity of
|
|
// the object we are attempting to marshal.
|
|
|
|
// addref/release pUnkControl; shouldn't go away (i.e.,
|
|
// should be other ref to it).
|
|
// Do this only if it is not Excel as it always returns which will
|
|
// trigger the assert on debug builds unnecessarily!
|
|
if (!IsTaskName(L"EXCEL.EXE"))
|
|
{
|
|
pUnkControl->AddRef();
|
|
Verify(pUnkControl->Release() != 0);
|
|
|
|
// verify that pUnkControl is in fact the controlling unknown
|
|
IUnknown *pUnkT;
|
|
Verify(pUnkControl->QueryInterface(IID_IUnknown,(void **)&pUnkT)==NOERROR);
|
|
Win4Assert(pUnkControl == pUnkT);
|
|
Verify(pUnkT->Release() != 0);
|
|
}
|
|
#endif
|
|
|
|
dwSMFlags = 0; // server side
|
|
m_pUnkControl->AddRef();
|
|
|
|
// determine if we will write a standard or handler objref. we write
|
|
// standard unless the object implements IStdMarshalInfo and overrides
|
|
// the standard class. we ignore all errors from this point onward in
|
|
// order to maintain backward compatibility.
|
|
|
|
ASSERT_LOCK_RELEASED
|
|
|
|
IStdMarshalInfo *pSMI;
|
|
HRESULT hr = m_pUnkControl->QueryInterface(IID_IStdMarshalInfo,
|
|
(void **)&pSMI);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pSMI->GetClassForHandler(NULL, NULL, &clsidHandler);
|
|
if (SUCCEEDED(hr) && !IsEqualCLSID(clsidHandler, CLSID_NULL))
|
|
{
|
|
dwSMFlags |= SMFLAGS_HANDLER;
|
|
}
|
|
else
|
|
{
|
|
clsidHandler = GUID_NULL;
|
|
}
|
|
pSMI->Release();
|
|
}
|
|
|
|
// look for the IExternalConnection interface. The StdId will use
|
|
// this for Inc/DecStrongCnt. We do the QI here while we are not
|
|
// holding the LOCK.
|
|
|
|
hr = m_pUnkControl->QueryInterface(IID_IExternalConnection,
|
|
(void **)&m_pIEC);
|
|
if (FAILED(hr))
|
|
{
|
|
// make sure it is NULL
|
|
m_pIEC = NULL;
|
|
}
|
|
|
|
ASSERT_LOCK_RELEASED
|
|
}
|
|
else
|
|
{
|
|
m_cStrongRefs = 1;
|
|
}
|
|
|
|
// now intialize the standard marshaler
|
|
CStdMarshal::Init(m_pUnkControl, this, clsidHandler, dwSMFlags);
|
|
|
|
*ppUnkInternal = (IMultiQI *)&m_InternalUnk; // this is what the m_refs=1 is for
|
|
|
|
AssertValid();
|
|
}
|
|
|
|
#if DBG==1
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CStdIdentity::CStdIdentity, public
|
|
//
|
|
// Synopsis: Special Identity ctor for the debug list head.
|
|
//
|
|
//+-------------------------------------------------------------------
|
|
CStdIdentity::CStdIdentity() : CClientSecurity(this)
|
|
{
|
|
Win4Assert(this == &gDbgIDHead);
|
|
m_pNext = this;
|
|
m_pPrev = this;
|
|
}
|
|
#endif // DBG
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CStdIdentity::~CStdIdentity, private
|
|
//
|
|
// Synopsis: Final destruction of the identity object. ID has been
|
|
// revoked by now (in internal ::Release). Here we disconnect
|
|
// on server.
|
|
//
|
|
// History: 15-Dec-93 CraigWi Created.
|
|
// Rickhi Simplified
|
|
//
|
|
//--------------------------------------------------------------------
|
|
CStdIdentity::~CStdIdentity()
|
|
{
|
|
#if DBG==1
|
|
if (this != &gDbgIDHead)
|
|
{
|
|
#endif // DBG
|
|
|
|
ComDebOut((DEB_MARSHAL, "CStdIdentity %s Deleted this:%x\n",
|
|
IsClient() ? "CLIENT" : "SERVER", this));
|
|
|
|
Win4Assert(m_refs == 0);
|
|
m_refs++; // simple guard against reentry of dtor
|
|
SetNowInDestructor(); // debug flag which enables asserts to detect
|
|
|
|
// make sure we have disconnected
|
|
Disconnect();
|
|
|
|
#if DBG==1
|
|
// UnChain this identity from the global list of instantiated identities
|
|
// so we can track even the ones that are not placed in the ID table.
|
|
LOCK
|
|
m_pPrev->m_pNext = m_pNext;
|
|
m_pNext->m_pPrev = m_pPrev;
|
|
UNLOCK
|
|
}
|
|
#endif // DBG
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CStdIdentity::CInternalUnk::QueryInterface, private
|
|
//
|
|
// Synopsis: Queries for an interface. Just delegates to the common
|
|
// code in QueryMultipleInterfaces.
|
|
//
|
|
// History: 26-Feb-96 Rickhi Created
|
|
//
|
|
//--------------------------------------------------------------------
|
|
STDMETHODIMP CStdIdentity::CInternalUnk::QueryInterface(REFIID riid, VOID **ppv)
|
|
{
|
|
MULTI_QI mqi;
|
|
mqi.pIID = &riid;
|
|
mqi.pItf = NULL;
|
|
|
|
QueryMultipleInterfaces(1, &mqi);
|
|
|
|
*ppv = (void *)mqi.pItf;
|
|
return mqi.hr;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CStdIdentity::CInternalUnk::QueryMultipleInterfaces, public
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// History: 26-Feb-96 Rickhi Created
|
|
//
|
|
//--------------------------------------------------------------------
|
|
STDMETHODIMP CStdIdentity::CInternalUnk::QueryMultipleInterfaces(ULONG cMQIs,
|
|
MULTI_QI *pMQIs)
|
|
{
|
|
// Make sure TLS is initialized.
|
|
HRESULT hr;
|
|
COleTls tls(hr);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
CStdIdentity *pStdID = GETPPARENT(this, CStdIdentity, m_InternalUnk);
|
|
pStdID->AssertValid();
|
|
|
|
// allocate some space on the stack for the intermediate results. declare
|
|
// working pointers and remember the start address of the allocations.
|
|
|
|
MULTI_QI **ppMQIAlloc = (MULTI_QI **)_alloca(sizeof(MULTI_QI *) * cMQIs);
|
|
IID *pIIDAlloc = (IID *) _alloca(sizeof(IID) * cMQIs);
|
|
SQIResult *pSQIAlloc = (SQIResult *)_alloca(sizeof(SQIResult) * cMQIs);
|
|
|
|
MULTI_QI **ppMQIPending = ppMQIAlloc;
|
|
IID *pIIDPending = pIIDAlloc;
|
|
SQIResult *pSQIPending = pSQIAlloc;
|
|
|
|
|
|
// loop over the interfaces looking for locally supported interfaces,
|
|
// instantiated proxies, and unsupported interfaces. Gather up all the
|
|
// interfaces that dont fall into the above categories, and issue a
|
|
// remote query to the server.
|
|
|
|
USHORT cPending = 0;
|
|
ULONG cAcquired = 0;
|
|
MULTI_QI *pMQI = pMQIs;
|
|
|
|
for (ULONG i=0; i<cMQIs; i++, pMQI++)
|
|
{
|
|
if (pMQI->pItf != NULL)
|
|
{
|
|
// skip any entries that are not set to NULL. This allows
|
|
// progressive layers of handlers to optionally fill in the
|
|
// interfaces that they know about and pass the whole array
|
|
// on to the next level.
|
|
continue;
|
|
}
|
|
|
|
pMQI->hr = S_OK;
|
|
|
|
// always allow - IUnknown, IMarshal, IStdIdentity, Instantiated proxies
|
|
if (InlineIsEqualGUID(*(pMQI->pIID), IID_IUnknown))
|
|
{
|
|
pMQI->pItf = (IMultiQI *)this;
|
|
}
|
|
else if (InlineIsEqualGUID(*(pMQI->pIID), IID_IMarshal))
|
|
{
|
|
pMQI->pItf = (IMarshal *)pStdID;
|
|
}
|
|
else if (InlineIsEqualGUID(*(pMQI->pIID), IID_IStdIdentity))
|
|
{
|
|
pMQI->pItf = (IUnknown *)(void*)pStdID;
|
|
}
|
|
else if (InlineIsEqualGUID(*(pMQI->pIID), IID_IProxyManager))
|
|
{
|
|
// old code exposed this IID and things now depend on it.
|
|
pMQI->pItf = (IProxyManager *)pStdID;
|
|
}
|
|
else if (pStdID->InstantiatedProxy(*(pMQI->pIID),(void **)&pMQI->pItf,
|
|
&pMQI->hr))
|
|
{
|
|
// a proxy for this interface already exists
|
|
//
|
|
// NOTE: this call also set pMQI->hr = E_NOINTERFACE if the
|
|
// StId has never been connected, and to CO_E_OBJNOTCONNECTED if
|
|
// it has been connected but is not currently connected. This is
|
|
// required for backwards compatibility, and will cause us to skip
|
|
// the QueryRemoteInterface.
|
|
;
|
|
}
|
|
else if (pStdID->IsAggregated())
|
|
{
|
|
// aggregate case
|
|
// allow - IInternalUnknown
|
|
// dissallow - IMultiQI, IClientSecurity, IServerSecurity
|
|
|
|
if (InlineIsEqualGUID(*(pMQI->pIID), IID_IInternalUnknown))
|
|
{
|
|
pMQI->pItf = (IInternalUnknown *)this;
|
|
pMQI->hr = S_OK;
|
|
}
|
|
else if (InlineIsEqualGUID(*(pMQI->pIID), IID_IMultiQI) ||
|
|
InlineIsEqualGUID(*(pMQI->pIID), IID_IClientSecurity) ||
|
|
InlineIsEqualGUID(*(pMQI->pIID), IID_IServerSecurity))
|
|
{
|
|
pMQI->hr = E_NOINTERFACE;
|
|
}
|
|
else if (pMQI->hr == S_OK)
|
|
{
|
|
// InstantiatedProxy did not return E_NOINTERFACE or
|
|
// CO_E_OBJNOTCONNECTED so add this interface to the
|
|
// list to pass to the QueryRemoteInterfaces.
|
|
|
|
pMQI->hr = RPC_S_CALLPENDING;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// non-aggregate case
|
|
// allow - IClientSecurity, IMultiQI
|
|
// dissallow - IInternalUnknown, IServerSecurity
|
|
|
|
if (InlineIsEqualGUID(*(pMQI->pIID), IID_IClientSecurity))
|
|
{
|
|
pMQI->pItf = (IClientSecurity *)pStdID;
|
|
pMQI->hr = S_OK;
|
|
}
|
|
else if (InlineIsEqualGUID(*(pMQI->pIID), IID_IMultiQI))
|
|
{
|
|
pMQI->pItf = (IMultiQI *)this;
|
|
pMQI->hr = S_OK;
|
|
}
|
|
else if (InlineIsEqualGUID(*(pMQI->pIID), IID_IInternalUnknown) ||
|
|
InlineIsEqualGUID(*(pMQI->pIID), IID_IServerSecurity))
|
|
{
|
|
pMQI->hr = E_NOINTERFACE;
|
|
}
|
|
else if (pMQI->hr == S_OK)
|
|
{
|
|
// InstantiatedProxy did not return E_NOINTERFACE or
|
|
// CO_E_OBJNOTCONNECTED so add this interface to the
|
|
// list to pass to the QueryRemoteInterfaces.
|
|
|
|
pMQI->hr = RPC_S_CALLPENDING;
|
|
}
|
|
}
|
|
|
|
if (pMQI->hr == S_OK)
|
|
{
|
|
// got an interface to return, AddRef it and count one more
|
|
// interface acquired.
|
|
|
|
pMQI->pItf->AddRef();
|
|
cAcquired++;
|
|
}
|
|
else if (pMQI->hr == RPC_S_CALLPENDING)
|
|
{
|
|
// fill in a remote QI structure and count one more
|
|
// pending interface
|
|
|
|
pSQIPending->pv = NULL;
|
|
pSQIPending->hr = S_OK;
|
|
*pIIDPending = *(pMQI->pIID);
|
|
*ppMQIPending = pMQI;
|
|
|
|
pSQIPending++;
|
|
pIIDPending++;
|
|
ppMQIPending++;
|
|
cPending++;
|
|
}
|
|
}
|
|
|
|
if (cPending > 0)
|
|
{
|
|
// there are some interfaces which we dont yet know about, so
|
|
// go ask the remoting layer to Query the server and build proxies
|
|
// where possible. The results are returned in the individual
|
|
// SQIResults, so the overall return code is ignored.
|
|
|
|
pStdID->QueryRemoteInterfaces(cPending, pIIDAlloc, pSQIAlloc);
|
|
|
|
// got some interfaces, loop over the remote QI structure filling
|
|
// in the rest of the MULTI_QI structure to return to the caller.
|
|
// the proxies are already AddRef'd.
|
|
|
|
pSQIPending = pSQIAlloc;
|
|
ppMQIPending = ppMQIAlloc;
|
|
|
|
for (i=0; i<cPending; i++, pSQIPending++, ppMQIPending++)
|
|
{
|
|
pMQI = *ppMQIPending;
|
|
pMQI->pItf = (IUnknown *)(pSQIPending->pv);
|
|
pMQI->hr = pSQIPending->hr;
|
|
|
|
if (SUCCEEDED(pMQI->hr))
|
|
{
|
|
// count one more acquired interface
|
|
cAcquired++;
|
|
}
|
|
}
|
|
}
|
|
|
|
// if we got all the interfaces, return S_OK. If we got none of the
|
|
// interfaces, return E_NOINTERFACE. If we got some, but not all, of
|
|
// the interfaces, return S_FALSE;
|
|
|
|
if (cAcquired == cMQIs)
|
|
return S_OK;
|
|
else if (cAcquired > 0)
|
|
return S_FALSE;
|
|
else
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CStdIdentity::CInternalUnk::QueryInternalInterface, public
|
|
//
|
|
// Synopsis: return interfaces that are internal to the aggregated
|
|
// proxy manager.
|
|
//
|
|
// History: 26-Feb-96 Rickhi Created
|
|
//
|
|
//--------------------------------------------------------------------
|
|
STDMETHODIMP CStdIdentity::CInternalUnk::QueryInternalInterface(REFIID riid,
|
|
VOID **ppv)
|
|
{
|
|
CStdIdentity *pStdID = GETPPARENT(this, CStdIdentity, m_InternalUnk);
|
|
pStdID->AssertValid();
|
|
|
|
if (!pStdID->IsAggregated())
|
|
{
|
|
// this method is only valid when we are part of a client-side
|
|
// aggregate.
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
if (InlineIsEqualGUID(riid, IID_IUnknown) ||
|
|
InlineIsEqualGUID(riid, IID_IInternalUnknown))
|
|
{
|
|
*ppv = (IInternalUnknown *)this;
|
|
}
|
|
else if (InlineIsEqualGUID(riid, IID_IMultiQI))
|
|
{
|
|
*ppv = (IMultiQI *)this;
|
|
}
|
|
else if (InlineIsEqualGUID(riid, IID_IStdIdentity))
|
|
{
|
|
*ppv = pStdID;
|
|
}
|
|
else if (InlineIsEqualGUID(riid, IID_IClientSecurity))
|
|
{
|
|
*ppv = (IClientSecurity *)pStdID;
|
|
}
|
|
else if (InlineIsEqualGUID(riid, IID_IProxyManager))
|
|
{
|
|
*ppv = (IProxyManager *)pStdID;
|
|
}
|
|
else
|
|
{
|
|
*ppv = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
((IUnknown *)*ppv)->AddRef();
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CStdIdentity::CInternalUnk::AddRef, public
|
|
//
|
|
// Synopsis: Nothing special.
|
|
//
|
|
// History: 15-Dec-93 CraigWi Created.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
STDMETHODIMP_(ULONG) CStdIdentity::CInternalUnk::AddRef(void)
|
|
{
|
|
CStdIdentity *pStdID = GETPPARENT(this, CStdIdentity, m_InternalUnk);
|
|
pStdID->AssertValid();
|
|
|
|
AssertSz(!pStdID->IsInDestructor(), "CStdIdentity AddRef'd during destruction");
|
|
|
|
InterlockedIncrement((long *)&pStdID->m_refs);
|
|
// ComDebOut((DEB_MARSHAL, "StdId:CtrlUnk::AddRef this:%x m_refs:%x\n", pStdID, pStdID->m_refs));
|
|
return pStdID->m_refs;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CStdIdentity::CInternalUnk::Release, public
|
|
//
|
|
// Synopsis: Releases the identity object. When the ref count goes
|
|
// to zero, revokes the id and destroys the object.
|
|
//
|
|
// History: 15-Dec-93 CraigWi Created.
|
|
// 18-Apr-95 Rickhi Rewrote much faster/simpler
|
|
//
|
|
//--------------------------------------------------------------------
|
|
STDMETHODIMP_(ULONG) CStdIdentity::CInternalUnk::Release(void)
|
|
{
|
|
CStdIdentity *pStdID = GETPPARENT(this, CStdIdentity, m_InternalUnk);
|
|
pStdID->AssertValid();
|
|
|
|
DWORD refs = pStdID->m_refs - 1;
|
|
// ComDebOut((DEB_MARSHAL, "StdId:CtrlUnk::Release this:%x m_refs:%x\n", pStdID, refs));
|
|
|
|
if (InterlockedDecrement((long *)&pStdID->m_refs) == 0)
|
|
{
|
|
BOOL fDelete = FALSE;
|
|
ASSERT_LOCK_RELEASED
|
|
LOCK
|
|
|
|
// check if we are already in the dtor and skip a second destruction
|
|
// if so. The reason we need this is that some crusty old apps do
|
|
// CoMarshalInterface followed by CoLockObjectExternal(FALSE,TRUE),
|
|
// expecting this to accomplish a Disconnect. It subtracts from the
|
|
// references, but it takes away the ones that the IPIDEntry put on,
|
|
// without telling the IPIDEntry, so when we release the IPIDEntry,
|
|
// our count goes negative!!!
|
|
|
|
// the LockedInMemory flag is for the gpStdMarshal instance that we
|
|
// may hand out to clients, but which we never want to go away,
|
|
// regardless of how many times they call Release.
|
|
|
|
if (pStdID->m_refs == 0)
|
|
{
|
|
// refcnt is still zero, so the idtable did not just hand
|
|
// out a reference behind our back.
|
|
|
|
if (!pStdID->IsLockedOrInDestructor())
|
|
{
|
|
// remove from the OID table and delete the identity
|
|
// We dont delete while holding the table mutex.
|
|
|
|
pStdID->RevokeOID();
|
|
fDelete = TRUE;
|
|
}
|
|
else
|
|
{
|
|
// this object is locked in memory and we should never
|
|
// get here, but some broken test app was doing this in
|
|
// stress.
|
|
|
|
pStdID->m_refs = 100;
|
|
}
|
|
}
|
|
|
|
UNLOCK
|
|
ASSERT_LOCK_RELEASED
|
|
|
|
if (fDelete)
|
|
{
|
|
delete pStdID;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return refs;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CStdIdentity::IUnknown methods, public
|
|
//
|
|
// Synopsis: External IUnknown methods; delegates to m_pUnkOuter.
|
|
//
|
|
// History: 15-Dec-93 CraigWi Created.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
STDMETHODIMP CStdIdentity::QueryInterface(REFIID riid, VOID **ppvObj)
|
|
{
|
|
AssertValid();
|
|
return m_pUnkOuter->QueryInterface(riid, ppvObj);
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CStdIdentity::AddRef(void)
|
|
{
|
|
AssertValid();
|
|
return m_pUnkOuter->AddRef();
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CStdIdentity::Release(void)
|
|
{
|
|
AssertValid();
|
|
return m_pUnkOuter->Release();
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CStdIdentity::UnlockAndRelease, public
|
|
//
|
|
// Synopsis: Version of Release used for gpStdMarshal, that is
|
|
// currently locked in memory so nobody but us can
|
|
// release it, regardless of refcnt.
|
|
//
|
|
// History: 19-Apr-96 Rickhi Created
|
|
//
|
|
//--------------------------------------------------------------------
|
|
ULONG CStdIdentity::UnlockAndRelease(void)
|
|
{
|
|
m_flags &= ~STDID_LOCKEDINMEM;
|
|
m_refs = 1;
|
|
return m_pUnkOuter->Release();
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CStdIdentity::IncStrongCnt, public
|
|
//
|
|
// Synopsis: Increments the strong reference count on the identity.
|
|
//
|
|
// History: 15-Dec-93 Rickhi Created.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
void CStdIdentity::IncStrongCnt()
|
|
{
|
|
Win4Assert(!IsClient());
|
|
|
|
// we might be holding the lock here if this is called from
|
|
// LookupIDFromUnk, since we have to be holding the lock while
|
|
// doing the lookup. We cant release it or we could go away.
|
|
|
|
ASSERT_LOCK_DONTCARE
|
|
|
|
ComDebOut((DEB_MARSHAL,
|
|
"CStdIdentity::IncStrongCnt this:%x cStrong:%x\n",
|
|
this, m_cStrongRefs+1));
|
|
|
|
AddRef();
|
|
InterlockedIncrement(&m_cStrongRefs);
|
|
|
|
if (m_pIEC)
|
|
{
|
|
m_pIEC->AddConnection(EXTCONN_STRONG, 0);
|
|
}
|
|
|
|
ASSERT_LOCK_DONTCARE
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CStdIdentity::DecStrongCnt, public
|
|
//
|
|
// Synopsis: Decrements the strong reference count on the identity,
|
|
// and releases the object if that was the last strong
|
|
// reference.
|
|
//
|
|
// History: 15-Dec-93 Rickhi Created.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
void CStdIdentity::DecStrongCnt(BOOL fKeepAlive)
|
|
{
|
|
Win4Assert(!IsClient());
|
|
ASSERT_LOCK_RELEASED
|
|
|
|
ComDebOut((DEB_MARSHAL,
|
|
"CStdIdentity::DecStrongCnt this:%x cStrong:%x fKeepAlive:%x\n",
|
|
this, m_cStrongRefs-1, fKeepAlive));
|
|
|
|
LONG cStrongRefs = InterlockedDecrement(&m_cStrongRefs);
|
|
|
|
if (m_pIEC)
|
|
{
|
|
m_pIEC->ReleaseConnection(EXTCONN_STRONG, 0, !fKeepAlive);
|
|
}
|
|
|
|
if (cStrongRefs == 0 && !fKeepAlive && (IsWOWThread() || m_pIEC == NULL))
|
|
{
|
|
// strong count has gone to zero, disconnect.
|
|
DisconnectObject(0);
|
|
}
|
|
|
|
if (cStrongRefs >= 0)
|
|
{
|
|
// some apps call CoMarshalInterface + CoLockObjectExternal(F,T)
|
|
// and expect the object to go away. Doing that causes Release to
|
|
// be called too many times (once for each IPID, once for CLOE, and
|
|
// once for the original Lookup).
|
|
Release();
|
|
}
|
|
|
|
ASSERT_LOCK_RELEASED
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CStdIdentity::LockObjectExternal, public
|
|
//
|
|
// Synopsis: locks (or unlocks) the object so the remoting layer does
|
|
// not (or does) go away.
|
|
//
|
|
// History: 09-Oct-96 Rickhi Moved from CoLockObjectExternal.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
HRESULT CStdIdentity::LockObjectExternal(BOOL fLock, BOOL fLastUR)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (GetServer() == NULL)
|
|
{
|
|
// attempt to lock handler, return error!
|
|
hr = E_UNEXPECTED;
|
|
}
|
|
else if (fLock)
|
|
{
|
|
// lock (and ignore rundowns) so it does not go away
|
|
IncStrongCnt();
|
|
LOCK;
|
|
IncTableCnt();
|
|
UNLOCK;
|
|
}
|
|
else
|
|
{
|
|
// unlock so that it can go away
|
|
LOCK;
|
|
DecTableCnt();
|
|
UNLOCK;
|
|
DecStrongCnt(!fLastUR);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CStdIdentity::GetServer, public
|
|
//
|
|
// Synopsis: Returns a pUnk for the identified object; NULL on client side
|
|
// The pointer is optionally addrefed depending upon fAddRef
|
|
//
|
|
// Returns: The pUnk on the object.
|
|
//
|
|
// History: 15-Dec-93 CraigWi Created.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
IUnknown * CStdIdentity::GetServer()
|
|
{
|
|
if (IsClient() || m_pUnkControl == NULL)
|
|
return NULL;
|
|
|
|
// Verify validity
|
|
Win4Assert(IsValidInterface(m_pUnkControl));
|
|
return m_pUnkControl;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CStdIdentity::ReleaseCtrlUnk, public
|
|
//
|
|
// Synopsis: Releases the server side controlling unknown
|
|
// This code is safe for reentrant calls.
|
|
//
|
|
// History: 11-Jun-95 Rickhi Created
|
|
//
|
|
//--------------------------------------------------------------------
|
|
void CStdIdentity::ReleaseCtrlUnk(void)
|
|
{
|
|
AssertValid();
|
|
Win4Assert(!IsClient());
|
|
|
|
if (m_pUnkControl)
|
|
{
|
|
// server side: release the real object's m_pUnkControl;
|
|
// prevent problem on recursive disconnect
|
|
|
|
AssertSz(IsValidInterface(m_pUnkControl),
|
|
"Invalid IUnknown during disconnect");
|
|
IUnknown *pUnkControl = m_pUnkControl;
|
|
m_pUnkControl = NULL;
|
|
|
|
if (m_pIEC)
|
|
{
|
|
AssertSz(IsValidInterface(m_pIEC),
|
|
"Invalid IExternalConnection during disconnect");
|
|
m_pIEC->Release();
|
|
m_pIEC = NULL;
|
|
}
|
|
|
|
pUnkControl->Release();
|
|
}
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CStdIdentity::SetOID, public
|
|
//
|
|
// Synopsis: Associates the OID and the object (handler or server).
|
|
//
|
|
// History: 20-Feb-95 Rickhi Simplified
|
|
//
|
|
//--------------------------------------------------------------------
|
|
HRESULT CStdIdentity::SetOID(REFMOID rmoid)
|
|
{
|
|
Win4Assert(rmoid != GUID_NULL);
|
|
ASSERT_LOCK_HELD
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
if (!(m_flags & STDID_HAVEID))
|
|
{
|
|
if (!(m_flags & STDID_IGNOREID))
|
|
{
|
|
Win4Assert(!(m_flags & STDID_FREETHREADED));
|
|
hr = SetObjectID(rmoid, m_pUnkControl, this);
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
m_flags |= STDID_HAVEID;
|
|
m_moid = rmoid;
|
|
}
|
|
}
|
|
|
|
ComDebErr(hr != S_OK, "SetOID Failed. Probably OOM.\n");
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CStdIdentity::RevokeOID, public
|
|
//
|
|
// Synopsis: Disassociates the OID and the object (handler or server).
|
|
// Various other methods will fail (e.g., MarshalInterface).
|
|
//
|
|
// History: 15-Dec-93 CraigWi Created.
|
|
// 20-Feb-95 Rickhi Simplified
|
|
//
|
|
//--------------------------------------------------------------------
|
|
void CStdIdentity::RevokeOID(void)
|
|
{
|
|
AssertValid();
|
|
ASSERT_LOCK_HELD
|
|
|
|
if (m_flags & STDID_HAVEID)
|
|
{
|
|
m_flags &= ~STDID_HAVEID;
|
|
|
|
if (!(m_flags & STDID_IGNOREID))
|
|
(void)ClearObjectID(m_moid, m_pUnkControl, this);
|
|
}
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CStdIdentity::IsConnected, public
|
|
//
|
|
// Synopsis: Indicates if the client is connected to the server.
|
|
// Only the negative answer is definitive because we
|
|
// might not be able to tell if the server is connected
|
|
// and even if we could, the answer might be wrong by
|
|
// the time the caller acted on it.
|
|
//
|
|
// Returns: TRUE if the server might be connected; FALSE if
|
|
// definitely not.
|
|
//
|
|
// History: 16-Dec-93 CraigWi Created.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
STDMETHODIMP_(BOOL) CStdIdentity::IsConnected(void)
|
|
{
|
|
Win4Assert(IsClient()); // must be client side
|
|
AssertValid();
|
|
|
|
return RemIsConnected();
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CStdIdentity::Disconnect, public
|
|
//
|
|
// Synopsis: IProxyManager::Disconnect implementation, just forwards
|
|
// to the standard marshaller, which may call us back to
|
|
// revoke our OID and release our CtrlUnk.
|
|
//
|
|
// May also be called by the IDTable cleanup code.
|
|
//
|
|
// History: 11-Jun-95 Rickhi Created.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
STDMETHODIMP_(void) CStdIdentity::Disconnect(void)
|
|
{
|
|
AssertValid();
|
|
CStdMarshal::Disconnect();
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CStdIdentity::LockConnection, public
|
|
//
|
|
// Synopsis: IProxyManager::LockConnection implementation. Changes
|
|
// all interfaces to weak from strong, or strong from weak.
|
|
//
|
|
// History: 11-Jun-95 Rickhi Created.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
STDMETHODIMP CStdIdentity::LockConnection(BOOL fLock, BOOL fLastUnlockReleases)
|
|
{
|
|
AssertValid();
|
|
|
|
if (!IsClient())
|
|
{
|
|
// this operation does not make sense on the server side.
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
if (IsMTAThread())
|
|
{
|
|
// this call is not allowed if we are FreeThreaded. Report
|
|
// success, even though we did not do anything.
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
if (( fLock && (++m_cStrongRefs == 1)) ||
|
|
(!fLock && (--m_cStrongRefs == 0)))
|
|
{
|
|
// the strong count transitioned from 0 to 1 or 1 to 0, so
|
|
// call the server to change our references.
|
|
|
|
return RemoteChangeRef(fLock, fLastUnlockReleases);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CStdIdentity::CreateServer, public
|
|
//
|
|
// Synopsis: Creates the server clsid in the given context and
|
|
// attaches it to this handler.
|
|
//
|
|
// History: 16-Dec-93 CraigWi Created.
|
|
//
|
|
// CODEWORK: this code is not thread safe in the freethreading case. We
|
|
// need to decide if the thread safety is the responsibility
|
|
// of the caller, or us. In the latter case, we would check
|
|
// if we are already connected before doing UnmarshalObjRef, and
|
|
// instead do a ::ReleaseMarshalObjRef.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
STDMETHODIMP CStdIdentity::CreateServer(REFCLSID rclsid, DWORD clsctx, void *pv)
|
|
{
|
|
ComDebOut((DEB_ACTIVATE, "ScmCreateObjectInstance this:%x clsctx:%x pv:%x\n",
|
|
this, clsctx, pv));
|
|
AssertValid();
|
|
Win4Assert(IsClient()); // must be client side
|
|
Win4Assert(IsValidInterface(m_pUnkControl)); // must be valid
|
|
//Win4Assert(!IsConnected());
|
|
ASSERT_LOCK_RELEASED
|
|
|
|
// Loop trying to get object from the server. Because the server can be
|
|
// in the process of shutting down and respond with a marshaled interface,
|
|
// we will retry this call if unmarshaling fails assuming that the above
|
|
// is true.
|
|
|
|
HRESULT hr = InitChannelIfNecessary();
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
const int MAX_SERVER_TRIES = 3;
|
|
|
|
for (int i = 0; i < MAX_SERVER_TRIES; i++)
|
|
{
|
|
// create object and get back marshaled interface pointer
|
|
InterfaceData *pIFD = NULL;
|
|
|
|
// Dll ignored here since we are just doing this to get
|
|
// the remote handler.
|
|
WCHAR *pwszDllPath = NULL;
|
|
DWORD dwDllType = IsSTAThread() ? APT_THREADED : FREE_THREADED;
|
|
|
|
#ifdef DCOM
|
|
HRESULT hrinterface;
|
|
hr = gResolver.CreateInstance( NULL, (CLSID *)&rclsid, clsctx, 1,
|
|
(IID *)&IID_IUnknown, (MInterfacePointer **)&pIFD,
|
|
&hrinterface,&dwDllType, &pwszDllPath );
|
|
#else
|
|
// The first three NULLs (pwszFrom, pstgFrom, pwszNew) trigger a
|
|
// simple creation.
|
|
hr = gResolver.CreateObject(rclsid, clsctx, 0,
|
|
NULL, NULL, NULL, &pIFD, &dwDllType, &pwszDllPath, NULL);
|
|
#endif
|
|
|
|
if (pwszDllPath != NULL)
|
|
{
|
|
CoTaskMemFree(pwszDllPath);
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
// If an error occurred, return that otherwise convert a wierd
|
|
// success into E_FAIL. The point here is to return an error that
|
|
// the caller can figure out what happened.
|
|
hr = FAILED(hr) ? hr : E_FAIL;
|
|
break;
|
|
}
|
|
|
|
|
|
// make a stream out of the interface data returned, then read the
|
|
// objref from the stream. No need to find another instance of
|
|
// CStdMarshal because we already know it is for us!
|
|
|
|
CXmitRpcStream Stm(pIFD);
|
|
OBJREF objref;
|
|
hr = ReadObjRef(&Stm, objref);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// become this identity by unmarshaling the objref into this
|
|
// object. Note the objref must use standard marshaling.
|
|
Win4Assert(objref.flags & (OBJREF_HANDLER | OBJREF_STANDARD));
|
|
Win4Assert(IsEqualIID(objref.iid, IID_IUnknown));
|
|
|
|
IUnknown *pUnk = NULL;
|
|
hr = UnmarshalObjRef(objref, (void **)&pUnk);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// release the AddRef done by unmarshaling
|
|
pUnk->Release();
|
|
|
|
// Reconnect the interface proxies
|
|
CStdMarshal::ReconnectProxies();
|
|
}
|
|
|
|
// free the objref we read above.
|
|
FreeObjRef(objref);
|
|
}
|
|
|
|
CoTaskMemFree(pIFD);
|
|
|
|
|
|
// If either this worked or we got a packet we couldn't unmarshal
|
|
// at all we give up. Otherwise, we will hope that recontacting the
|
|
// SCM will fix things.
|
|
|
|
if (SUCCEEDED(hr) || (hr == E_FAIL))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
ASSERT_LOCK_RELEASED
|
|
ComDebOut((DEB_ACTIVATE, "ScmCreateObjectInstance this:%x hr:%x\n",
|
|
this, hr));
|
|
return hr;
|
|
}
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CStdIdentity::CreateServerWithHandler, public
|
|
//
|
|
// Synopsis: Creates the server clsid in the given context and
|
|
// attaches it to this handler.
|
|
//
|
|
// History: 10-Oct-95 JohannP Created
|
|
//
|
|
// CODEWORK: this code is not thread safe in the freethreading case. We
|
|
// need to decide if the thread safety is the responsibility
|
|
// of the caller, or us. In the latter case, we would check
|
|
// if we are already connected before doing UnmarshalObjRef, and
|
|
// instead do a ::ReleaseMarshalObjRef.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
STDMETHODIMP CStdIdentity::CreateServerWithHandler(REFCLSID rclsid, DWORD clsctx, void *pv,
|
|
REFCLSID rclsidHandler, IID iidSrv, void **ppv,
|
|
IID iidClnt, void *pClientSiteInterface)
|
|
{
|
|
ComDebOut((DEB_ACTIVATE, "ScmCreateObjectInstance this:%x clsctx:%x pv:%x\n",
|
|
this, clsctx, pv));
|
|
AssertValid();
|
|
Win4Assert(IsClient()); // must be client side
|
|
Win4Assert(IsValidInterface(m_pUnkControl)); // must be valid
|
|
//Win4Assert(!IsConnected());
|
|
Win4Assert(ppv != NULL);
|
|
|
|
ASSERT_LOCK_RELEASED
|
|
|
|
// Loop trying to get object from the server. Because the server can be
|
|
// in the process of shutting down and respond with a marshaled interface,
|
|
// we will retry this call if unmarshaling fails assuming that the above
|
|
// is true.
|
|
|
|
HRESULT hr = InitChannelIfNecessary();
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
IClientSiteHandler *pClientSiteHandler = (IClientSiteHandler *)pClientSiteInterface;
|
|
|
|
const int MAX_SERVER_TRIES = 3;
|
|
|
|
for (int i = 0; i < MAX_SERVER_TRIES; i++)
|
|
{
|
|
// create object and get back marshaled interface pointer
|
|
InterfaceData *pIFD = NULL;
|
|
|
|
// Dll ignored here since we are just doing this to get
|
|
// the remote handler.
|
|
WCHAR *pwszDllPath = NULL;
|
|
DWORD dwDllType = IsSTAThread() ? APT_THREADED : FREE_THREADED;
|
|
|
|
#ifdef DCOM
|
|
HRESULT hrinterface;
|
|
|
|
// marshal ClientSiteHandler
|
|
MInterfacePointer * pIFPServerHandler = NULL;
|
|
MInterfacePointer * pIFPClientSiteHandler = NULL;
|
|
|
|
if (pClientSiteHandler)
|
|
{
|
|
// addref once here - MarshalHelper calls release on the object
|
|
pClientSiteHandler->AddRef();
|
|
hr = MarshalHelper(pClientSiteHandler, IID_IClientSiteHandler,
|
|
MSHLFLAGS_NORMAL,
|
|
(InterfaceData **) &pIFPClientSiteHandler);
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = gResolver.CreateInstance( NULL, (CLSID *)&rclsid, clsctx, 1,
|
|
(IID *)&IID_IUnknown, (MInterfacePointer **)&pIFD,
|
|
&hrinterface, &dwDllType, &pwszDllPath );
|
|
|
|
if (pIFPServerHandler)
|
|
{
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
CXmitRpcStream Stm((InterfaceData *) pIFPServerHandler);
|
|
hr = CoUnmarshalInterface(&Stm, IID_IServerHandler, ppv);
|
|
}
|
|
CoTaskMemFree(pIFPServerHandler);
|
|
}
|
|
|
|
PrivMemFree(pIFPClientSiteHandler);
|
|
}
|
|
else
|
|
{
|
|
hr = gResolver.CreateInstance( NULL, (CLSID *)&rclsid, clsctx, 1,
|
|
(IID *)&IID_IUnknown, (MInterfacePointer **)&pIFD,
|
|
&hrinterface,&dwDllType, &pwszDllPath );
|
|
}
|
|
|
|
#else
|
|
// The first three NULLs (pwszFrom, pstgFrom, pwszNew) trigger a
|
|
// simple creation.
|
|
hr = gResolver.CreateObject(rclsid, clsctx, 0,
|
|
NULL, NULL, NULL, &pIFD, &dwDllType, &pwszDllPath, NULL);
|
|
#endif
|
|
|
|
if (pwszDllPath != NULL)
|
|
{
|
|
CoTaskMemFree(pwszDllPath);
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
// If an error occurred, return that otherwise convert a wierd
|
|
// success into E_FAIL. The point here is to return an error that
|
|
// the caller can figure out what happened.
|
|
hr = FAILED(hr) ? hr : E_FAIL;
|
|
break;
|
|
}
|
|
|
|
|
|
// make a stream out of the interface data returned, then read the
|
|
// objref from the stream. No need to find another instance of
|
|
// CStdMarshal because we already know it is for us!
|
|
|
|
CXmitRpcStream Stm(pIFD);
|
|
OBJREF objref;
|
|
hr = ReadObjRef(&Stm, objref);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// become this identity by unmarshaling the objref into this
|
|
// object. Note the objref must use standard marshaling.
|
|
Win4Assert(objref.flags & (OBJREF_HANDLER | OBJREF_STANDARD));
|
|
Win4Assert(IsEqualIID(objref.iid, IID_IUnknown));
|
|
|
|
IUnknown *pUnk = NULL;
|
|
hr = UnmarshalObjRef(objref, (void **)&pUnk);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// release the AddRef done by unmarshaling
|
|
pUnk->Release();
|
|
|
|
// Reconnect the interface proxies
|
|
CStdMarshal::ReconnectProxies();
|
|
}
|
|
|
|
// free the objref we read above.
|
|
FreeObjRef(objref);
|
|
}
|
|
|
|
CoTaskMemFree(pIFD);
|
|
|
|
|
|
// If either this worked or we got a packet we couldn't unmarshal
|
|
// at all we give up. Otherwise, we will hope that recontacting the
|
|
// SCM will fix things.
|
|
|
|
if (SUCCEEDED(hr) || (hr == E_FAIL))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
ASSERT_LOCK_RELEASED
|
|
ComDebOut((DEB_ACTIVATE, "ScmCreateObjectInstance this:%x hr:%x\n",
|
|
this, hr));
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
#if DBG == 1
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CStdIdentity::AssertValid
|
|
//
|
|
// Synopsis: Validates that the state of the object is consistent.
|
|
//
|
|
// History: 26-Jan-94 CraigWi Created.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
void CStdIdentity::AssertValid()
|
|
{
|
|
LOCK
|
|
AssertSz(m_refs < 0x7fff, "Identity ref count unreasonable");
|
|
|
|
// ensure we have the controlling unknown
|
|
Win4Assert(IsValidInterface(m_pUnkOuter)); // must be valid
|
|
|
|
// NOTE: don't carelessly AddRef/Release because of weak references
|
|
|
|
Win4Assert((m_flags & ~(STDID_SERVER | STDID_CLIENT | STDID_HAVEID |
|
|
STDID_FREETHREADED | STDID_INDESTRUCTOR |
|
|
STDID_IGNOREID | STDID_AGGREGATED |
|
|
STDID_LOCKEDINMEM)) == 0);
|
|
|
|
if ((m_flags & STDID_HAVEID) &&
|
|
!(m_flags & (STDID_FREETHREADED | STDID_IGNOREID)))
|
|
{
|
|
CStdIdentity *pStdID;
|
|
Verify(LookupIDFromID(m_moid, FALSE /*fAddRef*/, &pStdID) == NOERROR);
|
|
Win4Assert(pStdID == this);
|
|
// pStdID not addref'd
|
|
}
|
|
|
|
if (IsClient())
|
|
Win4Assert(m_pUnkControl == m_pUnkOuter);
|
|
|
|
// must have RH tell identity when object goes away so we can NULL this
|
|
if (m_pUnkControl != NULL)
|
|
Win4Assert(IsValidInterface(m_pUnkControl)); // must be valid
|
|
|
|
if (m_pIEC != NULL)
|
|
Win4Assert(IsValidInterface(m_pIEC)); // must be valid
|
|
|
|
UNLOCK
|
|
}
|
|
#endif // DBG == 1
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Function: CreateIdentityHandler, private
|
|
//
|
|
// Synopsis: Creates a client side identity object (one which is
|
|
// initialized by the first unmarshal).
|
|
//
|
|
// Arguments: [pUnkOuter] - controlling unknown if aggregated
|
|
// [flags] - flags (indicates free-threaded or not)
|
|
// [riid] - interface requested
|
|
// [ppv] - place for pointer to that interface.
|
|
//
|
|
// History: 16-Dec-93 CraigWi Created.
|
|
// 20-Feb-95 Rickhi Simplified
|
|
//
|
|
//--------------------------------------------------------------------
|
|
INTERNAL CreateIdentityHandler(IUnknown *pUnkOuter, DWORD flags,
|
|
REFIID riid, void **ppv)
|
|
{
|
|
#if DBG == 1
|
|
Win4Assert(IsApartmentInitialized());
|
|
|
|
// if aggregating, it must ask for IUnknown.
|
|
Win4Assert(pUnkOuter == NULL || InlineIsEqualGUID(riid, IID_IUnknown));
|
|
|
|
if (pUnkOuter != NULL)
|
|
{
|
|
// addref/release pUnkOuter; shouldn't go away (i.e.,
|
|
// should be other ref to it).
|
|
// Except Excel which always returns 0 on Release!
|
|
if (!IsTaskName(L"EXCEL.EXE"))
|
|
{
|
|
pUnkOuter->AddRef();
|
|
Verify(pUnkOuter->Release() != 0);
|
|
|
|
// verify that pUnkOuter is in fact the controlling unknown
|
|
IUnknown *pUnkT;
|
|
Verify(pUnkOuter->QueryInterface(IID_IUnknown,(void**)&pUnkT)==NOERROR);
|
|
Win4Assert(pUnkOuter == pUnkT);
|
|
Verify(pUnkT->Release() != 0);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
*ppv = NULL;
|
|
IUnknown *pUnkID;
|
|
HRESULT hr = E_OUTOFMEMORY;
|
|
|
|
DWORD StdIdFlags = (flags & SORF_FREETHREADED) ? STDID_CLIENT | STDID_FREETHREADED :
|
|
STDID_CLIENT;
|
|
|
|
CStdIdentity *pStdId = new CStdIdentity(StdIdFlags, pUnkOuter,
|
|
NULL, &pUnkID);
|
|
if (pStdId)
|
|
{
|
|
// get the interface the caller asked for.
|
|
hr = pUnkID->QueryInterface(riid, ppv);
|
|
pUnkID->Release();
|
|
}
|
|
|
|
CALLHOOKOBJECTCREATE(hr,CLSID_NULL,riid,(IUnknown **)ppv);
|
|
return hr;
|
|
}
|