NT4/private/ole32/com/remote/remhdlr.hxx
2020-09-30 17:12:29 +02:00

464 lines
14 KiB
C++

//+-------------------------------------------------------------------
//
// File: remhdlr.hxx
//
// Contents: remote object handler definition
//
// Classes: CPSIX - proxy/stub interface record
// CIXList - list of CPSIX records
// CRemoteHdlr - remote object handler
//
// History: 23-Nov-92 Rickhi Modified from Ole2 sources
//
// The general architecture is thus...
//
// [ CRemoteHdlr ]--->[ CPSIX ]-->[ CPSIX ]--->[ CPSIX ]
// |
// [ CRemoteHdlr ]--->[ CPSIX ]-->[ CPSIX ]
//
// There is one RH per remote object. The RHs are accessed via the identity
// object. The CPSIX is a wrapper class for an interface stub or proxy.
// They are chained off the RHs, one per interface.
//
// The RHs implement the IMarshal interface and take care of marshalling
// and unmarshalling interfaces on the objects.
//
// The RH is never aggregated; the identity object is the only creator of
// the RH and the two interfaces it supports (IRemoteHdlr and IMarshal) can
// *never* be passed outside the aggregate in which the identity object exists.
//
// The RH gets a punk (_punkObj below) when created. In the local case this is
// the actual server object and is addref'd always. In the remote case the
// pointer is the pointer to the controlling unknown of the aggregate in which
// the identity object exists (and is not addref'd). As mentioned, the RH is
// not aggregated, but the proxy objects are; the _punkObj becomes the
// controlling unknown of the proxy objects so their interfaces can be passed
// outside the identity (really handler) aggregate.
//
//--------------------------------------------------------------------
#ifndef __REMHDLR__
#define __REMHDLR__
// forward declaration of classes
class CPSIX; // interface wrapper
class CIXList; // list of interface wrappers
class CRemoteHdlr; // remote handler
#include <olesem.hxx> // COleCommonMutexSem, COleStaticLock
#include <dd.hxx> // doubly linked list class
#include <iface.h> // SHandlerDataHdr
#include <olerem.h> // GUIDs
#include <channelb.hxx> // CRpcChannelBuffer
//+-------------------------------------------------------------------
//
// Class: CPSIX
//
// Purpose: This class provides a wrapper around the interface
// proxies and stubs, insulating higher-level code from
// knowing whether an interface is a proxy or a stub, and
// insulating the proxies from knowing the internals of the
// remote object handling implementation.
//
// Interface:
//
// History: 23-Nov-92 Rickhi Created
//
//--------------------------------------------------------------------
class CPSIX : public CListEntry
{
friend CIXList;
public:
// Constructor & Destructor
CPSIX(REFIID riid,
IRpcProxyBuffer *pIProxy);
CPSIX(REFIID riid,
IRpcStubBuffer *pStub);
~CPSIX(void);
IRpcStubBuffer *GetIStub(void); // used by marshalling code
#if DBG == 1
void VerifyReconnect(IUnknown *);
#endif
private:
// CODEWORK: make this a union
IRpcProxyBuffer *_pIProxy; // proxy interface
IRpcStubBuffer *_pStub; // stub entry
IID _iid; // only needed for stubs
#if DBG==1
DWORD _cRefs; // number of refs held by stub
#endif
};
//+-------------------------------------------------------------------------
//
// Class: CIXListBase (xlb)
//
// Purpose: Base class for Head list of interface objects.
//
// Interface: first -- get first item in the list.
// next -- get next item in the list.
//
// History: 23-Nov-92 Rickhi Created
//
// Notes: See dd.hxx for details of this macro.
//
//--------------------------------------------------------------------------
DERIVED_LIST_HEAD(CIXListBase, CPSIX);
//+-------------------------------------------------------------------------
//
// Class: CIXList (ixl)
//
// Purpose: Head list of interface objects.
//
// Interface: AddToList -- add an entry to a list of proxies
//
// History: 23-Nov-92 Rickhi Created
//
// Notes: This class adds a few methods to its macro defined base class.
//
//--------------------------------------------------------------------------
class CIXList : public CIXListBase
{
public:
CPSIX *FindProxyIX(REFIID riid, void**ppv);
// search for proxy IX
CPSIX *FindStubIX(REFIID riid); // search for stub IX
void AddToList(CPSIX *pIXToAdd); // add IX to list
void ConnectProxies(IRpcChannelBuffer *channel);// connect proxies
DWORD CountStubRefs(); // number of refs held by stubs
void DisconnectStubs(void); // disconnect stub IXs
void DisconnectProxies(void); // disconnect proxy IXs
#if DBG == 1
void AssertValid(BOOL fLocal);
#else
void AssertValid(BOOL fLocal) { }
#endif
};
//+-------------------------------------------------------------------------
//
// Class: CRemoteHdlr (RH)
//
// Purpose: remote object handler.
//
// Interface:
//
// History: 23-Nov-92 Rickhi Created
//
//--------------------------------------------------------------------------
class CRemoteHdlr : public IRemoteHdlr, public IMarshal
{
public:
CRemoteHdlr(IUnknown *punkObj,
IStdIdentity *pStdID, DWORD dwFlags, HRESULT &hr);
// IUnknown methods. I dont inherit tracking because i have
// special processing to do when the refcnt goes to zero.
STDMETHOD(QueryInterface)(REFIID riid, void **ppv);
STDMETHOD_(ULONG,AddRef)(void);
STDMETHOD_(ULONG,Release)(void);
// IMarshal methods
STDMETHOD(GetUnmarshalClass) (REFIID riid, void *pv,
DWORD dwDestContext, LPVOID pvDestContext,
DWORD mshlflags, LPCLSID pCid);
STDMETHOD(GetMarshalSizeMax) (REFIID riid, void *pv,
DWORD dwDestContext, LPVOID pvDestContext,
DWORD mshlflags, LPDWORD pSize);
STDMETHOD(MarshalInterface) (IStream *pStm, REFIID riid, void *pv,
DWORD dwDestContext, LPVOID pvDestContext,
DWORD mshlflags);
STDMETHOD(UnmarshalInterface)(IStream *pStm, REFIID riid, void **ppv);
STDMETHOD(ReleaseMarshalData)(IStream *pStm);
STDMETHOD(DisconnectObject)(DWORD dwReserved);
// IRemoteHdlr methods
STDMETHOD_(IRpcChannelBuffer *, GetChannel)(BOOL fAddRef);
// used by the channel to lock the RH during an Rpc call.
STDMETHOD_(ULONG, LockClient)(void);
STDMETHOD_(ULONG, UnLockClient)(void);
// used during destruction of the identity object to clear the RH ptr.
STDMETHOD_(void, ClearIdentity)(void);
// returns TRUE if iid is supported; like QueryInterface except no
// interface pointer returned; also works on both client and server sides.
STDMETHOD_(BOOL, DoesSupportIID)(REFIID riid);
// add/subtract a reference; vectors to identity; may return error
STDMETHOD(AddConnection)(DWORD extconn, DWORD reserved);
STDMETHOD(ReleaseConnection)(DWORD extconn, DWORD reserved, BOOL fLastReleaseCloses);
STDMETHOD_(BOOL, IsConnected)(void);
STDMETHOD_(void, Disconnect)(void);
STDMETHOD(LockConnection)(BOOL fLock, BOOL fLastUnlockReleases);
STDMETHOD_(IRpcStubBuffer *, LookupStub)(REFIID, IUnknown **, HRESULT *phr);
STDMETHOD_(void, FinishCall)( IRpcStubBuffer *pStub, IUnknown *pUnkServer);
STDMETHOD_(void, GetObjectID)( OID * );
#if DBG == 1
void AssertValid();
#else
void AssertValid() { }
#endif
private:
// Internal methods to find or create an interface proxy or stub
CPSIX *FindIX(REFIID riid, void **ppv, DWORD dwFlag, HRESULT *phr);
// internal unmarshalling and releasing functions
STDMETHOD(Unmarshal)(IStream *pStm, REFIID riid,
SHandlerDataHdr &ifh, void **ppv);
STDMETHOD(ReleaseData)(IStream *pStm, SHandlerDataHdr &ifh);
CPSIX *CreateInterfaceProxy(REFIID riid, void **ppv, HRESULT *phr);
CPSIX *CreateInterfaceStub(REFIID riid, HRESULT *phr);
STDMETHOD_(BOOL, IsRequestedByWOW)( REFIID riid );
~CRemoteHdlr(void); // callable only from Release
DWORD _dwFlags; // internal flags
ULONG _cReferences; // reference count
LONG _cCallsInProgress;// number of calls in progress
// controlling unknown of object; if local, the object is separate and
// we addref always; if remote, the object is the handler and we never
// addref it. Disconnect on server side sets it to NULL. See more above.
IUnknown *_punkObj;
IStdIdentity *_pstdID; // identity; never addref'd
CRpcChannelBuffer *_pChannel; // ptr to channel used by ...
CIXList _IXList; // list of IXs on this interface
static COleStaticMutexSem _mxs; // global mutext
};
// Definition of values for RHFlags
typedef enum tagRHFLAGS
{
RHFLAGS_LOCAL = 1, // object is local to this process
RHFLAGS_PENDINGDISCONNECT = 2, // Disconnect during a call; delay releases
RHFLAGS_GETTINGIX = 4, // RH is busy getting a proxy or stub
RHFLAGS_DISCONNECTED = 8 // RH is really disconnected
} RHFLAGS;
// Definition of values for RFlags
typedef enum tagRFLAGS
{
FLG_QUERYINTERFACE = 1, // called from QueryInterface
FLG_MARSHAL = 2, // called from MarshalInterface
FLG_UNMARSHAL = 4 // called from UnmarshalInterface
} RFLAGS;
// macros to determine if the CRemoteHdlr is for a LOCAL or REMOTE object
#define IS_LOCAL_RH (_dwFlags & RHFLAGS_LOCAL)
#define IS_REMOTE_RH !(IS_LOCAL_RH)
//+-------------------------------------------------------------------
//
// Member: CRemoteHdlr::~CRemoteHdlr, public
//
// Synopsis: destructor for the remote handler object
//
// History: 23-Nov-93 Rickhi Created
//
//--------------------------------------------------------------------
inline CRemoteHdlr::~CRemoteHdlr(void)
{
CairoleDebugOut((DEB_MARSHAL,
"Delete CRemoteHdlr pRH:%x pChannel:%x\n",
this, _pChannel));
// don't need to disconnect here since the identity destruction did that.
Win4Assert(_cCallsInProgress == 0);
// can't assert RH valid since identity is gone; can assert channel
_pChannel->AssertValid(TRUE, FALSE);
_IXList.AssertValid(IS_LOCAL_RH);
// release the channel. note that it might still be around until
// all the proxies disconnect from it, which is done in the _IXList
// destructor.
// safe release of channel
_pChannel->Release();
_pChannel = NULL;
}
//+-------------------------------------------------------------------
//
// Member: CPSIX::CPSIX, public
//
// Synopsis: constructor for Proxy interface wrapper
//
// History: 23-Nov-92 Rickhi Created
//
// Exceptions: CException if QueryInterface fails
//
// Notes: the object interface in the case of a proxy is the
// interface on the proxy itself.
//
//--------------------------------------------------------------------
inline CPSIX::CPSIX(REFIID riid, IRpcProxyBuffer *pIProxy)
: _pIProxy(pIProxy),
_pStub(NULL),
_iid(IID_NULL)
#if DBG==1
, _cRefs((DWORD)-1)
#endif
{
// validate input parms
Win4Assert(_pIProxy && "Improperly Constructed CPSIX");
_pIProxy->AddRef(); // keep the proxy
}
//+-------------------------------------------------------------------
//
// Member: CPSIX::CPSIX, public
//
// Synopsis: constructor for stub interface wrapper
//
// History: 23-Nov-92 Rickhi Created
//
//--------------------------------------------------------------------
inline CPSIX::CPSIX(REFIID riid, IRpcStubBuffer *pStub)
: _pStub(pStub),
_pIProxy(NULL),
_iid(riid)
#if DBG==1
, _cRefs(pStub->CountRefs())
#endif
{
// validate input parms
Win4Assert(_pStub && "Improperly Constructed CPSIX");
Win4Assert(_cRefs && "Stub not connected in CPSIX ctor");
_pStub->AddRef(); // keep the stub
}
//+-------------------------------------------------------------------
//
// Member: CPSIX::~CPSIX, public
//
// Synopsis:
//
// History: 23-Nov-92 Rickhi Created
//
//--------------------------------------------------------------------
inline CPSIX::~CPSIX(void)
{
if (_pIProxy)
{
_pIProxy->Disconnect(); // disconnect the proxy from channel
ULONG ul = _pIProxy->Release(); // release interface proxy
Win4Assert(ul == 0);
}
else
{
_pStub->Release(); // release interface stub
}
}
//+-------------------------------------------------------------------
//
// Member: CPSIX::GetIStub, public
//
// Synopsis:
//
// History: 23-Nov-92 Rickhi Created
//
//--------------------------------------------------------------------
inline IRpcStubBuffer *CPSIX::GetIStub(void)
{
Win4Assert(_pIProxy == NULL);
return _pStub;
}
#if DBG == 1
//+-------------------------------------------------------------------
//
// Member: CPSIX::VerifyReconnect, public
//
// Synopsis: Verify that the stub disconnec and reconnect work and
// that the ref counts remain the same.
//
// History: 1-Jun-94 CraigWi Created
//
//--------------------------------------------------------------------
inline void CPSIX::VerifyReconnect(IUnknown *pUnkServer)
{
Win4Assert(_pIProxy == NULL); // for stub only
Win4Assert(_cRefs != -1); // for connected stubs only
_pStub->Disconnect();
Win4Assert(_pStub->Connect(pUnkServer) == NOERROR);
Win4Assert(_pStub->CountRefs() == _cRefs);
}
#endif
//+-------------------------------------------------------------------
//
// Member: CIXList::AddToList
//
// Synopsis: adds a Stub object to list of Stub objects
//
// History: 23-Nov-93 Rickhi Created
//
// Note: Thread synchronization is the responsibility of the caller.
//
//--------------------------------------------------------------------
inline void CIXList::AddToList(CPSIX *pIXToAdd)
{
// validate input parms
Win4Assert(pIXToAdd);
CairoleDebugOut((DEB_MARSHAL, "New IX addr: %x\n", pIXToAdd));
insert_at_end(pIXToAdd);
}
#endif // __REMHDLR__