📄 stdproxy.cpp
字号:
/* StdProxy.cpp - COM/DCOM StdProxy class implementation *//*modification history--------------------02l,03jan02,nel Remove use of alloca.02k,17dec01,nel Add include symbold for diab build.02j,10oct01,dbs add AddKnownInterface() method to IOrpcClientChannel02i,26jul01,dbs use IOrpcClientChannel and IOrpcProxy interfaces02h,13jul01,dbs fix up includes02g,13mar01,nel SPR#35873. Modify code to search for first resovable address in dual string passed as part of marshalling an interface.02f,06mar01,nel SPR#35589. Add code to make Oxid addresses unique to prevent clash with other targets.02e,05oct00,nel SPR#34947. Correct marshling error introduced by T2 fix merge.02d,20sep00,nel Add changes made in T2 since branch.02c,28feb00,dbs fix IRemUnknown facelet so it is never Release()'ed02b,15feb00,dbs implement IRemUnknown calls directly02a,05aug99,dbs change to byte instead of char01z,09jul99,dbs implement ping functionality in SCM now01y,08jul99,dbs use SCM's oxidResolve() method always01x,06jul99,aim change from RpcBinding to RpcIfClient01w,30jun99,dbs remove const-ness warnings in dtor01v,30jun99,dbs make Facelet-map contain smart-pointers01u,30jun99,dbs fix m_facelets search in RemoteQI()01t,10jun99,dbs remove op new and delete01s,08jun99,dbs remove use of mtmap01r,07jun99,dbs change GuidMap to mtmap01q,03jun99,dbs no return value from mutex lock01p,03jun99,dbs remove refs to comSyncLib01o,27may99,dbs implement Ping functionality01n,20may99,dbs free memory using CoTaskMemFree(), and reformat01m,17may99,dbs remove IID from args of interaceInfoGet01l,13may99,dbs change BufferInit method to interfaceInfoGet01k,11may99,dbs simplify proxy remoting architecture01j,11may99,dbs rename VXCOM to VXDCOM01i,10may99,dbs simplify binding-handle usage01h,05may99,dbs update existing RemoteOxid with resolver address01g,28apr99,dbs use COM_MEM_ALLOC for all classes01f,27apr99,dbs use new allocation calls01e,26apr99,aim added TRACE_CALL01d,26apr99,dbs add mem-pool to class01c,22apr99,dbs tidy up potential leaks01b,21apr99,dbs add length arg to orpcDSAFormat()01a,20apr99,dbs created during Grand Renaming*//* DESCRIPTION: StdProxy -- */#include "StdProxy.h"#include "orpcLib.h"#include "dcomProxy.h"#include "OxidResolver.h"#include "PSFactory.h"#include "NdrStreams.h"#include "RpcStringBinding.h"#include "RpcIfClient.h"#include "SCM.h"/* Include symbol for diab */extern "C" int include_vxdcom_StdProxy (void) { return 0; }////////////////////////////////////////////////////////////////////////////// Statics / globals...//VxStdProxy::OXID2RemApartment_t VxStdProxy::s_allProxies;VxMutex VxStdProxy::s_allProxiesMutex;////////////////////////////////////////////////////////////////////////////// VxStdProxy ctor -- initialise members...//VxStdProxy::VxStdProxy () : m_dwRefCount (0), m_pOxid (0), m_oid (0), m_pRemUnknown (0), m_pRemUnkFacelet (0) { }//////////////////////////////////////////////////////////////////////////// VxStdProxy dtor -- remove this proxy from records, and remove its// OID from the ping tables in the SCM...//VxStdProxy::~VxStdProxy () { // Remove this proxy from list of all known proxies s_allProxiesMutex.lock (); OXID2RemApartment_t::iterator i = s_allProxies.find (oxid ()); if (i != s_allProxies.end ()) (*i).second.erase (oid ()); s_allProxiesMutex.unlock (); // Remove our OID from the ping list.. SCM::theSCM()->oidDel (m_resAddr, m_oid); // Disconnect all facelets belonging to this proxy-object... FACELETMAP::iterator j; VxCritSec cs (m_mutex); for (j = m_facelets.begin (); j != m_facelets.end (); ++j) { // @@@ FIXME have a fake interface-proxy for IUnknown if ((*j).second.pProxy) (*j).second.pProxy->Disconnect (); } // Free the RemUnknown facelet if (m_pRemUnkFacelet) { m_pRemUnkFacelet->pProxy->Disconnect (); delete m_pRemUnkFacelet; } }////////////////////////////////////////////////////////////////////////////// UnmarshalInterface - initialises the proxy object, newly created in// the client task, by reading the stream and extracting the OBJREF// from it. The OBJREF is always marshaled in little-endian byte// order, so it may have to be corrected.//// When unmarshaling an interface pointer, if the IID of the interface// being unmarshaled is IID_IUnknown, then we can create a VxStdProxy// and we don't need to QI since IUnknown is explicitly implemented// by VxStdProxy. If we are unmarshaling another interface (not// IUnknown), then we need to know if we already have this object (i.e.// an instance of VxStdProxy with the same OXID and OID) proxied locally.// If so, we should simply QI that object for the desired interface. If// not, then we need to create a new VxStdProxy (which gives us an// IUnknown proxy) and QI that for the desired interface. This is// not currently implemented, however -- there don't seem to be any// valid cases where we could get separately-marshaled interfaces// for the same object.//HRESULT VxStdProxy::UnmarshalInterface ( IStream* pStm, REFIID riid, void** ppv ) { TRACE_CALL; // Preset results... HRESULT hr = S_OK; *ppv = 0; // Unmarshal data from packet - first find out how big the // packet is... ULARGE_INTEGER len; pStm->Seek (0, STREAM_SEEK_END, &len); if (len > OBJREF_MAX) return RPC_E_INVALID_OBJREF; // Read the packet into a local buffer... byte mshlbuf [OBJREF_MAX]; pStm->Seek (0, STREAM_SEEK_SET, 0); pStm->Read (mshlbuf, len, 0); // Prepare an NDR stream to assist unmarshaling NdrUnmarshalStream us (NdrPhase::NOPHASE, VXDCOM_DREP_LITTLE_ENDIAN, mshlbuf, sizeof (mshlbuf)); // Unmarshal... OBJREF* pObjRef = (OBJREF*) malloc (len); hr = ndrUnmarshalOBJREF (&us, pObjRef); if (FAILED (hr)) return hr; // Record OID (Object ID), OXID (object-exporter ID - this can be // used to look up the IPID of the IRemUnknown later) and IPID of // the new interface pointer... OID oidNew = pObjRef->u_objref.u_standard.std.oid; IPID ipidNew = pObjRef->u_objref.u_standard.std.ipid; DWORD nRefs = pObjRef->u_objref.u_standard.std.cPublicRefs; OXID oxidNew = pObjRef->u_objref.u_standard.std.oxid; DUALSTRINGARRAY* pdsa = &pObjRef->u_objref.u_standard.saResAddr; // Check the DUALSTRINGARRAY entries, to find one which can be // 'resolved' into an IP address on this machine. Win2K sometimes // provides hostnames as well as the IP numbers that NT usually // sends, so we need to scan the array to find an IP number... RpcStringBinding remoteAddr = RpcStringBinding (pdsa, VXDCOM_SCM_ENDPOINT); // If we couldn't resolve any addresses, we bail out now... if (! remoteAddr.resolve ()) { free (pObjRef); return MAKE_HRESULT (SEVERITY_ERROR, FACILITY_RPC, RPC_S_INVALID_NET_ADDR); } if (remoteAddr.isLocalhost ()) { // Its on this machine, so we must find the object table entry // corresponding to the given OXID/OID/IPID combination... ObjectExporter* pExp = SCM::theSCM()->objectExporter (); if (pExp->oxid () != oxidNew) return OR_INVALID_OXID; ObjectTableEntry* pOTE = pExp->objectFindByOid (oidNew); if (! pOTE) return OR_INVALID_OID; // Now we have the right object table entry, we must find the // right interface pointer corresponding to the IPID and // IID... IUnknown* punk = pOTE->stdStub.getIUnknown (); if (! punk) return E_UNEXPECTED; // Now just QI for the requested interface... hr = punk->QueryInterface (riid, ppv); // Now we have an extra local ref, since the 'exported' // reference was never actually exported??? } else { // If the OID and OXID match that of an existing proxy, then this // interface must belong to that object. In this case, we defer // the interface to that object, adding the interface-proxy to // that object, and calling Release() for this one so it can be // destroyed when the caller is done with it... VxStdProxy* rcvr=0; // Lock 'allProxies' mutex while we search... s_allProxiesMutex.lock (); // First, find (or create, if it doesn't exist already) a // 'remote apartment' with the given OXID identifier... RemoteApartment_t& apt = s_allProxies [oxidNew]; // Now look for an object in this apartment with the same // OID -- if it exists, its the same object as far as we are // concerned... RemoteApartment_t::iterator i = apt.find (oidNew); if (i == apt.end ()) { // No extant proxy has this OID/OXID combination, so this // object must become a true proxy... rcvr = this; m_oid = oidNew; // Insert into list of all known proxies... apt [oidNew] = this; // Its now safe to unlock... s_allProxiesMutex.unlock (); // Ask the SCM to resolve the OXID and resolver-address // (from the OBJREF) into a string-binding we can use to // talk to the actual remote object... m_resAddr = remoteAddr; hr = SCM::theSCM()->oxidResolve (oxidNew, remoteAddr, m_pOxid); if (SUCCEEDED (hr)) { m_pChannel = new RpcIfClient (m_pOxid->stringBinding ()); if (m_pChannel == 0) hr = E_OUTOFMEMORY; // Now create a special facelet to handle the // IRemUnknown methods within this proxy. After // creation the interface proxy has one reference, and // when we QI it for IRemUnknown that adds a ref to // this StdProxy (since the interface-proxy delegates // its public interface's IUnknown methods to this // StdProxy object). However, we want to keep // IRemUnknown hidden, so we don't need this extra // ref. Hence, the Release() if the facelet creation // succeeds... IOrpcProxy* pProxy = 0; VxPSFactory* pPSFactory = VxPSFactory::theInstance (); hr = pPSFactory->CreateProxy (this, IID_IRemUnknown, m_pOxid->ipidRemUnknown (), &pProxy); if (SUCCEEDED (hr)) { // Connect the proxy... pProxy->Connect (m_pChannel); // Now make a special facelet, and get the actual // IRemUnknown pointer out, too... m_pRemUnkFacelet = new facelet_t (pProxy, 0, m_pOxid->ipidRemUnknown ()); // Now get the IRemUnknown interface we want... hr = pProxy->QueryInterface (IID_IRemUnknown, (void**) &m_pRemUnknown); if (SUCCEEDED (hr)) Release (); // Now the facelet has its own reference to the // interface-proxy, so we can drop the original // one we got from CreateProxy()... pProxy->Release (); } // Add our OID to the SCM's list of OIDs belonging to // the remote machine where our real object resides... SCM::theSCM()->oidAdd (m_resAddr, m_oid); } } else { // Found an object with the same OID/OXID - we must add // the new interface to it, and this object is just // serving as an unmarshaler, so can be destroyed after // this function completes its job... hr = S_OK; rcvr = (*i).second; s_allProxiesMutex.unlock (); } // If we have a std-proxy suitable to handle this interface, // then add a facelet to it for the requested interface ID - // this will take care of registering the IPID against the // interface-ptr we export to the client... if (SUCCEEDED (hr)) hr = rcvr->faceletAdd (riid, ipidNew, nRefs, ppv); } // Tidy up... free (pObjRef); return hr; } ////////////////////////////////////////////////////////////////////////////HRESULT VxStdProxy::ReleaseMarshalData ( IStream* pStm ) { TRACE_CALL; return S_OK; }////////////////////////////////////////////////////////////////////////////// VxStdProxy::DisconnectObject - disconnect all out-of-process clients//// Call Disconnect() for all interface proxies (facelets).//HRESULT VxStdProxy::DisconnectObject ( DWORD dwReserved ) { if (! m_pChannel) return CO_E_OBJNOTCONNECTED; FACELETMAP::iterator i; VxCritSec cs (m_mutex); for (i = m_facelets.begin (); i != m_facelets.end (); ++i) { (*i).second.pProxy->Disconnect (); } return S_OK; }////////////////////////////////////////////////////////////////////////////// VxStdProxy::AddRef - implements AddRef() method of IUnknown// implementation...//ULONG VxStdProxy::AddRef () {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -