📄 scm.cpp
字号:
// Now activate the requested object/class -- first we need to // know the current object-exporter so we can discover its // IRemUnknown IPID and OXID value... ObjectExporter* pExp = objectExporter (); *pOxid = pExp->oxid (); *pIpidRemUnknown = pExp->ipidRemUnknown (); HRESULT hrActivation = instanceCreate (mode, *pClsid, nInterfaces, mqi); // Check that the entire activation was successful, i.e. all // marshaling worked... DUALSTRINGARRAY* pdsa = 0; if (SUCCEEDED (hrActivation)) { // Now marshal each of the resulting interface pointers, and // output the HRESULTs. We also need to release the local // reference from each interface-ptr before it is exported. At // least one of the MQIs must have succeeded or else we return // E_NOINTERFACE as the hrActivation... bool allFailed = true; bool someFailed = false; for (DWORD k=0; k < nInterfaces; ++k) { // Marshal each individual interface ptr, or else fail it // with the appropriate error-code... HRESULT hrm = mqiMarshal (*pClsid, mqi [k], &ppItfData [k]); if (FAILED (hrm)) pResults [k] = hrm; else pResults [k] = mqi [k].hr; // Fail the overall result if any individual interface // failed to be marshaled, otherwise release the local ref // as the interface has now been remoted successfully... if (SUCCEEDED (pResults [k])) { allFailed = false; mqi [k].pItf->Release (); } else { someFailed = true; hrActivation = mqi [k].hr; } } // Decide on result -- if all failed that must take priority... if (someFailed) hrActivation = CO_S_NOTALLINTERFACES; if (allFailed) hrActivation = E_NOINTERFACE; if (SUCCEEDED (hrActivation)) { // Find the address and endpoint of the exporter that is // exporting the object that has just been marshaled BSTR bsSvrAddr; hrActivation = pExp->addressBinding (&bsSvrAddr); if (SUCCEEDED (hrActivation)) { const OLECHAR wszSecInfo [] = { 0x0A, 0xFFFF, 0 }; // Allocate memory to hold the DSA, allowing some // leeway at the end (16 bytes)... const DWORD dsaLen = sizeof (DUALSTRINGARRAY) + (2 * SysStringLen (bsSvrAddr)) + (2 * vxcom_wcslen (wszSecInfo)) + 16; pdsa = (DUALSTRINGARRAY*) CoTaskMemAlloc (dsaLen); if (pdsa) { // Format the DSA... hrActivation = orpcDSAFormat (pdsa, dsaLen, bsSvrAddr, wszSecInfo); } else // Memory ran out? hrActivation = E_OUTOFMEMORY; SysFreeString (bsSvrAddr); } } } // Activation HRESULT is an out-arg... *phr = hrActivation; *ppdsaOxidBindings = pdsa; // free up the mqi structure allocated on the heap delete []mqi; // This function always returns S_OK... return S_OK; }////////////////////////////////////////////////////////////////////////////// SCM::mqiMarshal -- marshals a single MULTI_QI entry into an// MInterfacePointer structure...//HRESULT SCM::mqiMarshal ( REFCLSID clsid, // class ID of containing object const MULTI_QI& mqi, // MULTI_QI structure MInterfacePointer** ppMIP // output is marshaled ptr ) { // Check the MQI contains a valid result... if (FAILED (mqi.hr)) { *ppMIP = 0; return mqi.hr; } // Create a stream... IStream* pStrm=0; HRESULT hr = VxRWMemStream::CreateInstance (0, IID_IStream, (void**) &pStrm); if (SUCCEEDED (hr)) { // Marshal interface-ptr into stream - we use the object // exporter to do this... ObjectExporter* pExp = objectExporter (); COM_ASSERT (pExp); hr = pExp->objectMarshal (clsid, pStrm, *(mqi.pIID), mqi.pItf, MSHCTX_DIFFERENTMACHINE, 0, MSHLFLAGS_NORMAL, 0); // Now convert the marshaled packet into a MInterfacePointer... if (SUCCEEDED (hr)) { ISimpleStream* pss=0; hr = pStrm->QueryInterface (IID_ISimpleStream, (void**) &pss); if (SUCCEEDED (hr)) { size_t strmSize = pss->size (); pss->locationSet (0); MInterfacePointer* mip = (MInterfacePointer*) CoTaskMemAlloc (sizeof (MInterfacePointer) + strmSize); if (mip) { mip->ulCntData = strmSize; pss->extract (mip->abData, strmSize); pStrm->Release (); } else hr = E_OUTOFMEMORY; *ppMIP = mip; } } pStrm->Release (); } return hr; }//////////////////////////////////////////////////////////////////////////////// IndirectActivation - activate remote server on behalf of local client////HRESULT SCM::IndirectActivation ( LPWSTR pwszServerName, // PROTSEQ + server name REFGUID clsid, // CLSID to activate DWORD mode, // all-1's == get-class-obj DWORD nItfs, // num of interfaces IID* iids, // array of IIDs MInterfacePointer** ppItfData, // returned interface(s) HRESULT* pResults // returned results per i/f ) { // Create a string-binding representing the remote SCM... RpcStringBinding sbRemoteScm (pwszServerName+1, pwszServerName[0], VXDCOM_SCM_ENDPOINT); // Prepare for RemoteActivation call... ORPCTHIS orpcThis; ORPCTHAT orpcThat; OXID oxid; IPID ipidRemUnknown; HRESULT hrActivation; DUALSTRINGARRAY* pdsaOxidBinding = 0; USHORT arProtseqs [] = { pwszServerName[0] }; COMVERSION serverVersion; DWORD authnHint; // Initialise in-args... orpcThis.version.MajorVersion = 5; orpcThis.version.MinorVersion = 1; orpcThis.flags = 0; orpcThis.reserved1 = 0; orpcThis.causality = CLSID_NULL; orpcThis.extensions = 0; // Get an RPC binding handle to the SCM on the machine where the // object (or rather its class-object) lives. We don't need to // free the binding handle later as it belongs to the RemoteSCM // object itself. First we look to see if we already have a // connection to that remote SCM... SPRemoteSCM& pscm = m_remoteScmTable [sbRemoteScm]; if (! pscm) pscm = new RemoteSCM (sbRemoteScm); IOrpcClientChannelPtr pClient = pscm->connectionGet (); // Request activation - note that this function is defined to // always return S_OK even if some of the internal activation // results are failures... HRESULT hr = IRemoteActivation_RemoteActivation_vxproxy (pClient, // Client handle &orpcThis, // ORPCTHIS &orpcThat, // [out] ORPCTHAT (CLSID*)&clsid, // CLSID 0, // pwszObjName 0, // pObjStorage 0, // imp level mode, // class-mode? nItfs, // num itfs iids, // IIDs 1, // num protseqs arProtseqs, // array of protseqs &oxid, // [out] oxid &pdsaOxidBinding, // [out] string binding &ipidRemUnknown, // [out] ipid of rem-unknown &authnHint, // [out] auth hint &serverVersion, // [out] server version &hrActivation, // [out] activation result ppItfData, // [out] resulting interfaces pResults); // [out] results for each QI // Check results... if (FAILED (hr)) return hr; if (FAILED (hrActivation)) return hrActivation; if (! pdsaOxidBinding) return E_FAIL; // Now we have discovered the OXID-resolution for the OXID that is // exporting the newly-created object, we need to tell the SCM // about it... oxidBindingUpdate (oxid, sbRemoteScm, ipidRemUnknown, RpcStringBinding (pdsaOxidBinding)); return S_OK; }//////////////////////////////////////////////////////////////////////////////// instanceCreate -- creates an instance of a class, marshals its// interface(s), and returns the whole lot in one go! This is used by// the SCM to create instances in response to external requests via// the IRemoteActivation interface.//HRESULT SCM::instanceCreate ( DWORD mode, // get-class-obj? REFCLSID clsid, // CLSID to create DWORD nInterfaces, // num i/f's to return MULTI_QI* mqi // resulting itf ptrs ) { // First create a class-factory object... cout << "In SCM::instanceCreate" << endl; IUnknown* punk=0; IClassFactory* pCF; HRESULT hr = comClassObjectGet (clsid, CLSCTX_INPROC_SERVER, "", IID_IClassFactory, (void**) &pCF); if (FAILED (hr)) { cout << "no class object" << endl; return hr; } // If we are being called in CLASS-MODE then just return the // class-factory pointer, otherwise create an instance and QI // it for all requested interfaces... if (mode == MODE_GET_CLASS_OBJECT) { punk = pCF; } else { // Create an instance of the class... hr = pCF->CreateInstance (0, IID_IUnknown, (void**) &punk); pCF->Release(); } // Now QI for each of the requested interfaces... if (SUCCEEDED (hr)) { for (ULONG n=0; n < nInterfaces; ++n) { mqi[n].hr = punk->QueryInterface (*(mqi[n].pIID), (void**) &mqi[n].pItf); if (FAILED (mqi[n].hr)) hr = CO_S_NOTALLINTERFACES; } punk->Release (); } else cout << "class-factory failed" << endl; return hr; }////////////////////////////////////////////////////////////////////////////// oxidBindingUpdate -- update our table of OXID-resolver and// RemoteOxid entries...//void SCM::oxidBindingUpdate ( OXID oxid, const RpcStringBinding& sbRemoteScm, REFIPID ipidRemUnk, const RpcStringBinding& sbRemoteOxid ) { // See if we already know about a remote SCM at this address... SPRemoteSCM& rscm = m_remoteScmTable [sbRemoteScm]; // If not, make a new one... if (! rscm) rscm = new RemoteSCM (sbRemoteScm); // Now update its knowledge of this OXID... rscm->oxidBindingUpdate (oxid, ipidRemUnk, sbRemoteOxid); }////////////////////////////////////////////////////////////////////////////// oxidResolve -- given an OXID and a string-binding to the remote// machine on which the OXID is known to exist, return the address of// the actual remote Object Exporter. The 'resAddr' may contain the// port-number 135, or may omit it...//HRESULT SCM::oxidResolve ( OXID oxid, const RpcStringBinding& resAddr, SPRemoteOxid& remOxid ) { // Create string-binding to remote SCM/OxidResolver, with explicit // port-number... RpcStringBinding sbor (resAddr.ipAddress (), resAddr.protocolSequence (), VXDCOM_SCM_ENDPOINT); // If we don't already have a RemoteSCM object representing that // network address, then create one... SPRemoteSCM rscm = 0; { VxCritSec cs1 (m_mutex); REMOTESCMMAP::const_iterator s = m_remoteScmTable.find (sbor); if (s == m_remoteScmTable.end ()) { rscm = new RemoteSCM (sbor); m_remoteScmTable [sbor] = rscm; } else rscm = (*s).second; } // Now see if it knows about the specific OXID... if (! rscm->oxidBindingLookup (oxid, remOxid)) { IPID ipidRemUnk; DWORD authnHint; DUALSTRINGARRAY* pdsa=0; OLECHAR arProtseqs [] = { NCACN_IP_TCP }; HRESULT hr = S_OK; // Need to remotely query the OXID-resolver for the answer... IOrpcClientChannelPtr pChannel = new RpcIfClient (resAddr); // Find the (remote) server, given the OXID and the string- // binding for the resolver - this will be cached and // re-used in future if the same OXID recurs... hr = IOXIDResolver_ResolveOxid_vxproxy (pChannel, &oxid, 1, arProtseqs, &pdsa, &ipidRemUnk, &authnHint); // Only S_OK is valid as a 'good' result, anything else may be // a warning that the method failed somehow... if (hr == S_OK) { // Now we have all the info, we need to record it... oxidBindingUpdate (oxid, sbor, ipidRemUnk, RpcStringBinding (pdsa)); } // Tidy up if (pdsa) CoTaskMemFree (pdsa); } // Return the new binding... if (! rscm->oxidBindingLookup (oxid, remOxid)) return OR_INVALID_OXID; return S_OK; }////////////////////////////////////////////////////////////////////////////// SCM::SimplePing -- ping all the objects whose OIDs are in the set// indicated by 'setid'...//HRESULT SCM::SimplePing ( SETID setid // [in] set ID ) { TRACE_CALL; S_INFO (LOG_SCM, "SimplePing()"); // enter critical section VxCritSec critSec (m_mutex); // Find the appropriate set... OIDSETMAP::iterator i = m_oidSets.find (setid); if (i == m_oidSets.end ()) return OR_INVALID_SET; HRESULT hr = S_OK; // Iterate over all OIDs in this set... OIDSET& oidset = (*i).second; for (OIDSET::iterator o = oidset.begin(); o != oidset.end (); ++o) { OID oid = (*o); bool pinged = false; // Ping the exporter associated with this OID - we don't know // which one it is so try them all until we hit one for (OXIDMAP::iterator j = m_exporters.begin (); j != m_exporters.end ();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -