📄 stdproxy.cpp
字号:
return comSafeInc (&m_dwRefCount); }////////////////////////////////////////////////////////////////////////////// VxStdProxy::Release - implements remote reference-counting for std// marshaling. When the last reference count is released then we// must send a msg to the server task telling it so it can clear up.//ULONG VxStdProxy::Release () { DWORD n = comSafeDec (&m_dwRefCount); // Is ref-count exhausted? if (n == 0) { // Object is about to be destroyed, we need to release // all refs we have on the remote object itself. We must // release all refs on a per-IPID basis... REMINTERFACEREF* pRef=0; int nRefs=0; { VxCritSec cs (m_mutex); nRefs = m_facelets.size (); pRef = new REMINTERFACEREF [nRefs]; FACELETMAP::const_iterator i = m_facelets.begin (); for (int n=0; n < nRefs; ++n) { facelet_t* pFacelet = (facelet_t*) &((*i).second); pRef [n].ipid = pFacelet->ipid; pRef [n].cPublicRefs = pFacelet->remoteRefCount; pRef [n].cPrivateRefs = 0; ++i; } } // Make remote call, if there are any remote refs to release if (nRefs) { HRESULT hr = m_pRemUnknown->RemRelease (nRefs, pRef); if (FAILED (hr)) S_ERR (LOG_DCOM, "RemRelease failed " << hr); } // Tidy up and destroy this object... delete this; delete []pRef; } return n; }////////////////////////////////////////////////////////////////////////////// faceletFind - find a facelet for the given IID//// Searches the facelet-map for a facelet which implements <iid>, and// returns a pointer to that facelet (or NULL if not found). The// reference count of the std-proxy is the same after this operation// as before it, although it may change during it.//VxStdProxy::facelet_t * VxStdProxy::faceletFind (REFIID iid) { facelet_t *pFacelet = 0; FACELETMAP::iterator i; VxCritSec cs (m_mutex); for (i = m_facelets.begin (); i != m_facelets.end (); ++i) { void* pv; // Is it the right interface? We borrow the 'pProxy' of each // facelet in turn (no need to addref/release since its scope // is shorter than that of the facelet) and ask it... IOrpcProxy* pProxy = (*i).second.pProxy; if (pProxy) { HRESULT hr = pProxy->QueryInterface (iid, &pv); if (SUCCEEDED (hr)) { // Drop the ref-count after a successful QI, and return // this facelet instance... Release (); pFacelet = &((*i).second); break; } } } return pFacelet; }////////////////////////////////////////////////////////////////////////////// QueryInterface - implements QI functionality for the standard proxy// object, which means that it may respond to the QI for any of the// interfaces implemented by its facelets, or to IUnknown and IMarshal// which it implements directly. It may make a remote call to// IRemUnknown::RemQueryInterface() if the requested interface is not// present in the proxy currently...//HRESULT VxStdProxy::QueryInterface ( REFIID iid, void** ppv ) { // Validate args... if (! ppv) return E_INVALIDARG; // If its one of our own interfaces, we can return it directly... if ((iid == IID_IUnknown) || (iid == IID_IMarshal)) { *ppv = this; AddRef (); return S_OK; } // Is it an interface implemented by an existing facelet? If so, // then thats the interface we want -- if not, we must go remote facelet_t *pf = faceletFind (iid); if (pf) return pf->pProxy->QueryInterface (iid, ppv); // We didn't find the interface we were looking for, so we must // make a remote call to IRemUnknown::RemQueryInterface using the // most convenient IPID we have to hand, which happens to be the // first in the list... IPID ipid = (*(m_facelets.begin ())).second.ipid; REMQIRESULT* pQIResult; HRESULT hr = m_pRemUnknown->RemQueryInterface (ipid, 5, 1, &iid, &pQIResult); if (FAILED (hr)) return hr; // If the OID of the new interface isn't ours, then something went // horribly wrong... if (pQIResult->std.oid == m_oid) { hr = faceletAdd (iid, pQIResult->std.ipid, pQIResult->std.cPublicRefs, ppv); } else hr = RPC_E_INVALID_OBJECT; // Tidy up the returned results... CoTaskMemFree (pQIResult); // Tell the channel that this interface is definitely known to be // available at the other end... m_pChannel->AddKnownInterface (iid); return hr; }////////////////////////////////////////////////////////////////////////////// faceletAdd -- adds a (or operates on an existing) facelet for the// given interface (IID) to the VxStdProxy object. The// remote-ref-count for that IPID is bumped up by the given amount.//HRESULT VxStdProxy::faceletAdd ( REFIID iid, REFIPID ipid, DWORD nRefs, void** ppv ) { HRESULT hr = S_OK;; void* pvResult=0; // Look for existing facelet on this proxy with the right IID. // We need to do a linear search of m_facelets, and if we find the // right one, we need to get its 'iid' interface, too. This adds // an extra reference to the proxy, as well... facelet_t* pFacelet = faceletFind (iid); // Did we find one? If not, we need to create one... if (pFacelet) { // Get the requested interface, adding a local ref. Note that // this will *never* be called for IUnknown, since QI's for // IUnknown are handled directly by the StdProxy itself... COM_ASSERT(iid != IID_IUnknown); hr = pFacelet->pProxy->QueryInterface (iid, &pvResult); // Add the remote refs... pFacelet->remoteRefCount += nRefs; } else { // Check for explicit IUnknown special case - we must make an // entry for the IUnknown interface in the 'm_facelets' table // now it's IPID is known, but we don't give out the pointer // to the facelet, instead we return the StdProxy's IUnknown, // and the facelet is used only to count remote refs... IOrpcProxy* pProxy=0; if (iid == IID_IUnknown) { // For IUnknown, we don't create an interface-proxy, and // we return the primary IUnknown of this StdProxy... AddRef (); pvResult = static_cast<IUnknown*> (this); } else { // For other IIDs, we need to create an interface-proxy // from the factory. This results in one ref in pProxy, // which we must drop later... VxPSFactory* pPSFactory = VxPSFactory::theInstance (); hr = pPSFactory->CreateProxy (this, iid, ipid, &pProxy); if (FAILED (hr)) return hr; // QI the proxy for the desired interface... hr = pProxy->QueryInterface (iid, &pvResult); if (FAILED (hr)) { pProxy->Release (); return hr; } // Connect the proxy to the channel... pProxy->Connect (m_pChannel); } // Create a facelet to refer to the interface-proxy... VxCritSec cs (m_mutex); m_facelets [pvResult] = facelet_t (pProxy, nRefs, ipid); // Now drop the ref we got from CreateProxy()... if (pProxy) pProxy->Release (); } // Return resulting interface ptr... if (ppv) *ppv = pvResult; return hr; }////////////////////////////////////////////////////////////////////////////HRESULT VxStdProxy::GetUnmarshalClass ( REFIID, void*, DWORD, void*, DWORD, CLSID* ) { TRACE_CALL; return E_NOTIMPL; } ////////////////////////////////////////////////////////////////////////////HRESULT VxStdProxy::GetMarshalSizeMax ( REFIID iid, void* pv, DWORD dwDestContext, void* pvDestContext, DWORD mshlflags, DWORD* pSize ) { TRACE_CALL; *pSize = OBJREF_MAX; return S_OK; } ////////////////////////////////////////////////////////////////////////////// MarshalInterface -- this method hands out one of our existing// remote interface-refs to another client, so we decrement the// ref-count for that IPID. If the remaining reference count has// dropped below 2 (i.e. to one) then we must go ask for some more// refs from the real object, via RemAddRef(). It is usual to ask for// 5 at a time...//HRESULT VxStdProxy::MarshalInterface ( IStream* pStrm, REFIID iid, void* pvInterface, DWORD dwDestCtx, void* pvDestCtx, DWORD mshlflags ) { HRESULT hr = S_OK; // Look for a facelet supporting the requested interface... facelet_t* pFacelet = faceletFind (iid); if (! pFacelet) return E_NOINTERFACE; // Get one reference from the facelet - if its ref-count drops to // zero then we must request more from the original object... if (pFacelet->remoteRefCount < 2) { REMINTERFACEREF ref; HRESULT hrAddRef; // Invoke RemAddRef() to get more refs... ref.ipid = pFacelet->ipid; ref.cPublicRefs = 5; ref.cPrivateRefs = 0; hr = m_pRemUnknown->RemAddRef (1, &ref, &hrAddRef); if (FAILED (hr)) return hr; if (FAILED (hrAddRef)) return hrAddRef; pFacelet->remoteRefCount += ref.cPublicRefs; } // Now drop the one we want to give out... pFacelet->remoteRefCount -= 1; // We need to get the OXID-resolver address associated with our // remote object exporter, to fill in the OBJREF correctly. // Fortunately, we cached it when we unmarshaled our original // OBJREF... BSTR bsResAddr=0; if (m_resAddr.format (&bsResAddr, false) != 0) return E_FAIL; // Fill in the OBJREF for this object... OLECHAR wszSecInfo [] = { 0x0A, 0xFFFF, 0 }; const DWORD dsaLen = sizeof (DUALSTRINGARRAY) + (2 * SysStringLen (bsResAddr)) + (2 * vxcom_wcslen (wszSecInfo)) + 16; OBJREF* pObjRef = (OBJREF*) malloc (sizeof (OBJREF) + dsaLen); if (! pObjRef) return E_OUTOFMEMORY; pObjRef->signature = OBJREF_SIGNATURE; pObjRef->flags = OBJREF_STANDARD; pObjRef->iid = iid; pObjRef->u_objref.u_standard.std.flags = 0; pObjRef->u_objref.u_standard.std.cPublicRefs = 1; pObjRef->u_objref.u_standard.std.oxid = m_pOxid->oxid (); pObjRef->u_objref.u_standard.std.oid = m_oid; pObjRef->u_objref.u_standard.std.ipid = pFacelet->ipid; // Fill in the DSA with the address info from the resolver... hr = orpcDSAFormat (&pObjRef->u_objref.u_standard.saResAddr, dsaLen, bsResAddr, wszSecInfo); if (SUCCEEDED (hr)) { // Now marshal the OBJREF into the marshaling packet, so it can be // accessed by the proxy... NdrMarshalStream ms (NdrPhase::NOPHASE, VXDCOM_DREP_LITTLE_ENDIAN); hr = ndrMarshalOBJREF (&ms, pObjRef); if (SUCCEEDED (hr)) hr = pStrm->Write (ms.begin (), ms.size (), 0); } // Tidy up free (pObjRef); // Tidy up... return hr; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -