StdProxy.cpp
上传用户:nvosite88
上传日期:2007-01-17
资源大小:4983k
文件大小:25k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* StdProxy.cpp - COM/DCOM StdProxy class implementation */
  2. /*
  3. modification history
  4. --------------------
  5. 02l,03jan02,nel  Remove use of alloca.
  6. 02k,17dec01,nel  Add include symbold for diab build.
  7. 02j,10oct01,dbs  add AddKnownInterface() method to IOrpcClientChannel
  8. 02i,26jul01,dbs  use IOrpcClientChannel and IOrpcProxy interfaces
  9. 02h,13jul01,dbs  fix up includes
  10. 02g,13mar01,nel  SPR#35873. Modify code to search for first resovable address
  11.                  in dual string passed as part of marshalling an interface.
  12. 02f,06mar01,nel  SPR#35589. Add code to make Oxid addresses unique to prevent
  13.                  clash with other targets.
  14. 02e,05oct00,nel  SPR#34947. Correct marshling error introduced by T2 fix
  15.                  merge.
  16. 02d,20sep00,nel  Add changes made in T2 since branch.
  17. 02c,28feb00,dbs  fix IRemUnknown facelet so it is never Release()'ed
  18. 02b,15feb00,dbs  implement IRemUnknown calls directly
  19. 02a,05aug99,dbs  change to byte instead of char
  20. 01z,09jul99,dbs  implement ping functionality in SCM now
  21. 01y,08jul99,dbs  use SCM's oxidResolve() method always
  22. 01x,06jul99,aim  change from RpcBinding to RpcIfClient
  23. 01w,30jun99,dbs  remove const-ness warnings in dtor
  24. 01v,30jun99,dbs  make Facelet-map contain smart-pointers
  25. 01u,30jun99,dbs  fix m_facelets search in RemoteQI()
  26. 01t,10jun99,dbs  remove op new and delete
  27. 01s,08jun99,dbs  remove use of mtmap
  28. 01r,07jun99,dbs  change GuidMap to mtmap
  29. 01q,03jun99,dbs  no return value from mutex lock
  30. 01p,03jun99,dbs  remove refs to comSyncLib
  31. 01o,27may99,dbs  implement Ping functionality
  32. 01n,20may99,dbs  free memory using CoTaskMemFree(), and reformat
  33. 01m,17may99,dbs  remove IID from args of interaceInfoGet
  34. 01l,13may99,dbs  change BufferInit method to interfaceInfoGet
  35. 01k,11may99,dbs  simplify proxy remoting architecture
  36. 01j,11may99,dbs  rename VXCOM to VXDCOM
  37. 01i,10may99,dbs  simplify binding-handle usage
  38. 01h,05may99,dbs  update existing RemoteOxid with resolver address
  39. 01g,28apr99,dbs  use COM_MEM_ALLOC for all classes
  40. 01f,27apr99,dbs  use new allocation calls
  41. 01e,26apr99,aim  added TRACE_CALL
  42. 01d,26apr99,dbs  add mem-pool to class
  43. 01c,22apr99,dbs  tidy up potential leaks
  44. 01b,21apr99,dbs  add length arg to orpcDSAFormat()
  45. 01a,20apr99,dbs  created during Grand Renaming
  46. */
  47. /*
  48.   DESCRIPTION:
  49.   StdProxy -- 
  50. */
  51. #include "StdProxy.h"
  52. #include "orpcLib.h"
  53. #include "dcomProxy.h"
  54. #include "OxidResolver.h"
  55. #include "PSFactory.h"
  56. #include "NdrStreams.h"
  57. #include "RpcStringBinding.h"
  58. #include "RpcIfClient.h"
  59. #include "SCM.h"
  60. /* Include symbol for diab */
  61. extern "C" int include_vxdcom_StdProxy (void)
  62.     {
  63.     return 0;
  64.     }
  65. //////////////////////////////////////////////////////////////////////////
  66. //
  67. // Statics / globals...
  68. //
  69. VxStdProxy::OXID2RemApartment_t VxStdProxy::s_allProxies;
  70. VxMutex                         VxStdProxy::s_allProxiesMutex;
  71. //////////////////////////////////////////////////////////////////////////
  72. //
  73. // VxStdProxy ctor -- initialise members...
  74. //
  75. VxStdProxy::VxStdProxy ()
  76.   : m_dwRefCount (0),
  77.     m_pOxid (0),
  78.     m_oid (0),
  79.     m_pRemUnknown (0),
  80.     m_pRemUnkFacelet (0)
  81.     {
  82.     }
  83. //////////////////////////////////////////////////////////////////////////
  84. // VxStdProxy dtor -- remove this proxy from records, and remove its
  85. // OID from the ping tables in the SCM...
  86. //
  87. VxStdProxy::~VxStdProxy ()
  88.     {
  89.     // Remove this proxy from list of all known proxies
  90.     s_allProxiesMutex.lock ();
  91.     OXID2RemApartment_t::iterator i = s_allProxies.find (oxid ());
  92.     if (i != s_allProxies.end ())
  93.         (*i).second.erase (oid ());
  94.     s_allProxiesMutex.unlock ();
  95.     // Remove our OID from the ping list..
  96.     SCM::theSCM()->oidDel (m_resAddr, m_oid);
  97.     // Disconnect all facelets belonging to this proxy-object...
  98.     FACELETMAP::iterator j;
  99.     VxCritSec cs (m_mutex);
  100.     
  101.     for (j = m_facelets.begin (); j != m_facelets.end (); ++j)
  102. {
  103.         // @@@ FIXME have a fake interface-proxy for IUnknown
  104.         if ((*j).second.pProxy)
  105.             (*j).second.pProxy->Disconnect ();
  106. }
  107.     // Free the RemUnknown facelet
  108.     if (m_pRemUnkFacelet)
  109.         {
  110.         m_pRemUnkFacelet->pProxy->Disconnect ();
  111.         delete m_pRemUnkFacelet;
  112.         }
  113.     }
  114. //////////////////////////////////////////////////////////////////////////
  115. //
  116. // UnmarshalInterface - initialises the proxy object, newly created in
  117. // the client task, by reading the stream and extracting the OBJREF
  118. // from it. The OBJREF is always marshaled in little-endian byte
  119. // order, so it may have to be corrected.
  120. //
  121. // When unmarshaling an interface pointer, if the IID of the interface
  122. // being unmarshaled is IID_IUnknown, then we can create a VxStdProxy
  123. // and we don't need to QI since IUnknown is explicitly implemented
  124. // by VxStdProxy. If we are unmarshaling another interface (not
  125. // IUnknown), then we need to know if we already have this object (i.e.
  126. // an instance of VxStdProxy with the same OXID and OID) proxied locally.
  127. // If so, we should simply QI that object for the desired interface. If
  128. // not, then we need to create a new VxStdProxy (which gives us an
  129. // IUnknown proxy) and QI that for the desired interface. This is
  130. // not currently implemented, however -- there don't seem to be any
  131. // valid cases where we could get separately-marshaled interfaces
  132. // for the same object.
  133. //
  134. HRESULT VxStdProxy::UnmarshalInterface
  135.     (
  136.     IStream*        pStm,
  137.     REFIID          riid,
  138.     void**          ppv
  139.     )
  140.     {
  141.     TRACE_CALL;
  142.     // Preset results...
  143.     HRESULT hr = S_OK;
  144.     *ppv = 0;
  145.     
  146.     // Unmarshal data from packet - first find out how big the
  147.     // packet is...
  148.     ULARGE_INTEGER len;
  149.     pStm->Seek (0, STREAM_SEEK_END, &len);
  150.     if (len > OBJREF_MAX)
  151.         return RPC_E_INVALID_OBJREF;
  152.     // Read the packet into a local buffer...
  153.     byte mshlbuf [OBJREF_MAX];
  154.     pStm->Seek (0, STREAM_SEEK_SET, 0);
  155.     pStm->Read (mshlbuf, len, 0);
  156.     // Prepare an NDR stream to assist unmarshaling
  157.     NdrUnmarshalStream us (NdrPhase::NOPHASE,
  158.     VXDCOM_DREP_LITTLE_ENDIAN,
  159.     mshlbuf,
  160.     sizeof (mshlbuf));
  161.     // Unmarshal...
  162.     OBJREF* pObjRef = (OBJREF*) malloc (len);
  163.     hr = ndrUnmarshalOBJREF (&us, pObjRef);
  164.     if (FAILED (hr))
  165.         return hr;
  166.     // Record OID (Object ID), OXID (object-exporter ID - this can be
  167.     // used to look up the IPID of the IRemUnknown later) and IPID of
  168.     // the new interface pointer...
  169.     OID oidNew = pObjRef->u_objref.u_standard.std.oid;
  170.     IPID ipidNew = pObjRef->u_objref.u_standard.std.ipid;
  171.     DWORD nRefs = pObjRef->u_objref.u_standard.std.cPublicRefs;
  172.     OXID oxidNew = pObjRef->u_objref.u_standard.std.oxid;
  173.     DUALSTRINGARRAY* pdsa = &pObjRef->u_objref.u_standard.saResAddr;
  174.     // Check the DUALSTRINGARRAY entries, to find one which can be
  175.     // 'resolved' into an IP address on this machine. Win2K sometimes
  176.     // provides hostnames as well as the IP numbers that NT usually
  177.     // sends, so we need to scan the array to find an IP number...
  178.     
  179.     RpcStringBinding remoteAddr = RpcStringBinding (pdsa, VXDCOM_SCM_ENDPOINT);
  180.     // If we couldn't resolve any addresses, we bail out now...
  181.     if (! remoteAddr.resolve ())
  182.         {
  183.         free (pObjRef);
  184.         return MAKE_HRESULT (SEVERITY_ERROR,
  185.                              FACILITY_RPC,
  186.                              RPC_S_INVALID_NET_ADDR);
  187.         }
  188.     if (remoteAddr.isLocalhost ())
  189. {
  190. // Its on this machine, so we must find the object table entry
  191. // corresponding to the given OXID/OID/IPID combination...
  192. ObjectExporter* pExp = SCM::theSCM()->objectExporter ();
  193. if (pExp->oxid () != oxidNew)
  194.     return OR_INVALID_OXID;
  195. ObjectTableEntry* pOTE = pExp->objectFindByOid (oidNew);
  196. if (! pOTE)
  197.     return OR_INVALID_OID;
  198. // Now we have the right object table entry, we must find the
  199. // right interface pointer corresponding to the IPID and
  200. // IID...
  201. IUnknown* punk = pOTE->stdStub.getIUnknown ();
  202. if (! punk)
  203.     return E_UNEXPECTED;
  204. // Now just QI for the requested interface...
  205. hr = punk->QueryInterface (riid, ppv);
  206. // Now we have an extra local ref, since the 'exported'
  207. // reference was never actually exported???
  208. }
  209.     else
  210. {
  211. // If the OID and OXID match that of an existing proxy, then this
  212. // interface must belong to that object. In this case, we defer
  213. // the interface to that object, adding the interface-proxy to
  214. // that object, and calling Release() for this one so it can be
  215. // destroyed when the caller is done with it...
  216. VxStdProxy* rcvr=0;
  217.         // Lock 'allProxies' mutex while we search...
  218.         s_allProxiesMutex.lock ();
  219.         // First, find (or create, if it doesn't exist already) a
  220.         // 'remote apartment' with the given OXID identifier...
  221.         RemoteApartment_t& apt = s_allProxies [oxidNew];
  222.         // Now look for an object in this apartment with the same
  223.         // OID -- if it exists, its the same object as far as we are
  224.         // concerned...
  225.         RemoteApartment_t::iterator i = apt.find (oidNew);
  226.         if (i == apt.end ())
  227.             {
  228.     // No extant proxy has this OID/OXID combination, so this
  229.     // object must become a true proxy...
  230.     rcvr = this;
  231.     m_oid = oidNew;
  232.     // Insert into list of all known proxies...
  233.             apt [oidNew] = this;
  234.             // Its now safe to unlock...
  235.             s_allProxiesMutex.unlock ();
  236.     // Ask the SCM to resolve the OXID and resolver-address
  237.     // (from the OBJREF) into a string-binding we can use to
  238.     // talk to the actual remote object...
  239.     m_resAddr = remoteAddr;
  240.     hr = SCM::theSCM()->oxidResolve (oxidNew,
  241.      remoteAddr,
  242.      m_pOxid);
  243.     if (SUCCEEDED (hr))
  244. {
  245. m_pChannel = new RpcIfClient (m_pOxid->stringBinding ());
  246. if (m_pChannel == 0)
  247.     hr = E_OUTOFMEMORY;
  248.                 // Now create a special facelet to handle the
  249.                 // IRemUnknown methods within this proxy. After
  250.                 // creation the interface proxy has one reference, and
  251.                 // when we QI it for IRemUnknown that adds a ref to
  252.                 // this StdProxy (since the interface-proxy delegates
  253.                 // its public interface's IUnknown methods to this
  254.                 // StdProxy object). However, we want to keep
  255.                 // IRemUnknown hidden, so we don't need this extra
  256.                 // ref. Hence, the Release() if the facelet creation
  257.                 // succeeds...
  258.                 IOrpcProxy* pProxy = 0;
  259.                 VxPSFactory* pPSFactory = VxPSFactory::theInstance ();
  260.                 hr = pPSFactory->CreateProxy (this, 
  261.                                               IID_IRemUnknown,
  262.                                               m_pOxid->ipidRemUnknown (),
  263.                                               &pProxy);
  264.                 if (SUCCEEDED (hr))
  265.                     {
  266.                     // Connect the proxy...
  267.                     pProxy->Connect (m_pChannel);
  268.                     
  269.                     // Now make a special facelet, and get the actual
  270.                     // IRemUnknown pointer out, too...
  271.                     m_pRemUnkFacelet = new facelet_t (pProxy,
  272.                                                       0,
  273.                                                       m_pOxid->ipidRemUnknown ()); 
  274.                     // Now get the IRemUnknown interface we want...
  275.                     hr = pProxy->QueryInterface (IID_IRemUnknown,
  276.                                                  (void**) &m_pRemUnknown);
  277.                     if (SUCCEEDED (hr))
  278.                         Release ();
  279.                     // Now the facelet has its own reference to the
  280.                     // interface-proxy, so we can drop the original
  281.                     // one we got from CreateProxy()...
  282.                     pProxy->Release ();
  283.                     }
  284. // Add our OID to the SCM's list of OIDs belonging to
  285. // the remote machine where our real object resides...
  286. SCM::theSCM()->oidAdd (m_resAddr, m_oid);
  287. }
  288.             }
  289.         else
  290.             {
  291.     // Found an object with the same OID/OXID - we must add
  292.     // the new interface to it, and this object is just
  293.     // serving as an unmarshaler, so can be destroyed after
  294.     // this function completes its job...
  295.     hr = S_OK;
  296.     rcvr = (*i).second;
  297.             s_allProxiesMutex.unlock ();
  298.     }
  299. // If we have a std-proxy suitable to handle this interface,
  300. // then add a facelet to it for the requested interface ID -
  301. // this will take care of registering the IPID against the
  302. // interface-ptr we export to the client... 
  303. if (SUCCEEDED (hr))
  304.     hr = rcvr->faceletAdd (riid, ipidNew, nRefs, ppv);
  305.         }
  306.     
  307.     // Tidy up...
  308.     free (pObjRef);
  309.     return hr;
  310.     }
  311.         
  312. //////////////////////////////////////////////////////////////////////////
  313. //
  314. HRESULT VxStdProxy::ReleaseMarshalData
  315.     (
  316.     IStream* pStm
  317.     )
  318.     {
  319.     TRACE_CALL;
  320.     return S_OK;
  321.     }
  322. //////////////////////////////////////////////////////////////////////////
  323. //
  324. // VxStdProxy::DisconnectObject - disconnect all out-of-process clients
  325. //
  326. // Call Disconnect() for all interface proxies (facelets).
  327. //
  328. HRESULT VxStdProxy::DisconnectObject
  329.     (
  330.     DWORD dwReserved
  331.     )
  332.     {
  333.     if (! m_pChannel)
  334.         return CO_E_OBJNOTCONNECTED;
  335.     FACELETMAP::iterator i;
  336.     VxCritSec cs (m_mutex);
  337.     
  338.     for (i = m_facelets.begin (); i != m_facelets.end (); ++i)
  339.         {
  340.         (*i).second.pProxy->Disconnect ();
  341.         }
  342.     return S_OK;
  343.     }
  344. //////////////////////////////////////////////////////////////////////////
  345. //
  346. // VxStdProxy::AddRef - implements AddRef() method of IUnknown
  347. // implementation...
  348. //
  349. ULONG VxStdProxy::AddRef ()
  350.     {
  351.     return comSafeInc (&m_dwRefCount);
  352.     }
  353. //////////////////////////////////////////////////////////////////////////
  354. //
  355. // VxStdProxy::Release - implements remote reference-counting for std
  356. // marshaling. When the last reference count is released then we
  357. // must send a msg to the server task telling it so it can clear up.
  358. //
  359. ULONG VxStdProxy::Release ()
  360.     {
  361.     DWORD n = comSafeDec (&m_dwRefCount);
  362.     // Is ref-count exhausted?
  363.     if (n == 0)
  364. {
  365. // Object is about to be destroyed, we need to release
  366. // all refs we have on the remote object itself. We must
  367. // release all refs on a per-IPID basis...
  368. REMINTERFACEREF* pRef=0;
  369. int nRefs=0;
  370. {
  371. VxCritSec cs (m_mutex);
  372. nRefs = m_facelets.size ();
  373. pRef = new REMINTERFACEREF [nRefs];
  374. FACELETMAP::const_iterator i = m_facelets.begin ();
  375. for (int n=0; n < nRefs; ++n)
  376.     {
  377.     facelet_t* pFacelet = (facelet_t*) &((*i).second);
  378.     pRef [n].ipid = pFacelet->ipid;
  379.     pRef [n].cPublicRefs = pFacelet->remoteRefCount;
  380.     pRef [n].cPrivateRefs = 0;
  381.     ++i;
  382.     }
  383. }
  384. // Make remote call, if there are any remote refs to release
  385. if (nRefs)
  386.     {
  387.     HRESULT hr = m_pRemUnknown->RemRelease (nRefs, pRef);
  388.     if (FAILED (hr))
  389. S_ERR (LOG_DCOM, "RemRelease failed " << hr);
  390.     }
  391. // Tidy up and destroy this object...
  392. delete this;
  393. delete []pRef;
  394. }
  395.     return n;
  396.     }
  397. //////////////////////////////////////////////////////////////////////////
  398. //
  399. // faceletFind - find a facelet for the given IID
  400. //
  401. // Searches the facelet-map for a facelet which implements <iid>, and
  402. // returns a pointer to that facelet (or NULL if not found). The
  403. // reference count of the std-proxy is the same after this operation
  404. // as before it, although it may change during it.
  405. //
  406. VxStdProxy::facelet_t * VxStdProxy::faceletFind (REFIID iid)
  407.     {
  408.     facelet_t *pFacelet = 0;
  409.     FACELETMAP::iterator i;
  410.     VxCritSec cs (m_mutex);
  411.     for (i = m_facelets.begin (); i != m_facelets.end (); ++i)
  412.         {
  413.         void* pv;
  414.         
  415.         // Is it the right interface? We borrow the 'pProxy' of each
  416.         // facelet in turn (no need to addref/release since its scope
  417.         // is shorter than that of the facelet) and ask it...
  418.         IOrpcProxy* pProxy = (*i).second.pProxy;
  419.         if (pProxy)
  420.             {
  421.             HRESULT hr = pProxy->QueryInterface (iid, &pv);
  422.             if (SUCCEEDED (hr))
  423.                 {
  424.                 // Drop the ref-count after a successful QI, and return
  425.                 // this facelet instance...
  426.                 Release ();
  427.                 pFacelet = &((*i).second);
  428.                 break;
  429.                 }
  430.             }
  431.         }
  432.     return pFacelet;
  433.     }
  434. //////////////////////////////////////////////////////////////////////////
  435. //
  436. // QueryInterface - implements QI functionality for the standard proxy
  437. // object, which means that it may respond to the QI for any of the
  438. // interfaces implemented by its facelets, or to IUnknown and IMarshal
  439. // which it implements directly. It may make a remote call to
  440. // IRemUnknown::RemQueryInterface() if the requested interface is not
  441. // present in the proxy currently...
  442. //
  443. HRESULT VxStdProxy::QueryInterface
  444.     (
  445.     REFIID              iid,
  446.     void**              ppv
  447.     )
  448.     {
  449.     // Validate args...
  450.     if (! ppv)
  451.         return E_INVALIDARG;
  452.     
  453.     // If its one of our own interfaces, we can return it directly...
  454.     if ((iid == IID_IUnknown) || (iid == IID_IMarshal))
  455.         {
  456.         *ppv = this;
  457.         AddRef ();
  458.         return S_OK;
  459.         }
  460.     // Is it an interface implemented by an existing facelet? If so,
  461.     // then thats the interface we want -- if not, we must go remote
  462.     facelet_t *pf = faceletFind (iid);
  463.     if (pf)
  464.         return pf->pProxy->QueryInterface (iid, ppv);
  465.     
  466.     // We didn't find the interface we were looking for, so we must
  467.     // make a remote call to IRemUnknown::RemQueryInterface using the
  468.     // most convenient IPID we have to hand, which happens to be the
  469.     // first in the list...
  470.     IPID ipid =  (*(m_facelets.begin ())).second.ipid;
  471.     REMQIRESULT* pQIResult;
  472.     HRESULT hr = m_pRemUnknown->RemQueryInterface (ipid,
  473.                                                    5,
  474.                                                    1,
  475.                                                    &iid,
  476.                                                    &pQIResult);
  477.     if (FAILED (hr))
  478.         return hr;
  479.     // If the OID of the new interface isn't ours, then something went
  480.     // horribly wrong...
  481.     if (pQIResult->std.oid == m_oid)
  482.         {
  483.         hr = faceletAdd (iid,
  484.                          pQIResult->std.ipid,
  485.                          pQIResult->std.cPublicRefs,
  486.                          ppv);
  487.         }
  488.     else
  489.         hr = RPC_E_INVALID_OBJECT;
  490.     // Tidy up the returned results...
  491.     CoTaskMemFree (pQIResult);
  492.     // Tell the channel that this interface is definitely known to be
  493.     // available at the other end...
  494.     m_pChannel->AddKnownInterface (iid);
  495.     return hr;
  496.     }
  497. //////////////////////////////////////////////////////////////////////////
  498. //
  499. // faceletAdd -- adds a (or operates on an existing) facelet for the
  500. // given interface (IID) to the VxStdProxy object. The
  501. // remote-ref-count for that IPID is bumped up by the given amount.
  502. //
  503. HRESULT VxStdProxy::faceletAdd
  504.     (
  505.     REFIID              iid,
  506.     REFIPID             ipid,
  507.     DWORD               nRefs,
  508.     void**              ppv
  509.     )
  510.     {
  511.     HRESULT hr = S_OK;;
  512.     void* pvResult=0;
  513.     
  514.     // Look for existing facelet on this proxy with the right IID.
  515.     // We need to do a linear search of m_facelets, and if we find the
  516.     // right one, we need to get its 'iid' interface, too. This adds
  517.     // an extra reference to the proxy, as well...
  518.     facelet_t* pFacelet = faceletFind (iid);
  519.     // Did we find one? If not, we need to create one...
  520.     if (pFacelet)
  521.         {
  522.         // Get the requested interface, adding a local ref. Note that
  523.         // this will *never* be called for IUnknown, since QI's for
  524.         // IUnknown are handled directly by the StdProxy itself...
  525.         COM_ASSERT(iid != IID_IUnknown);
  526.         hr = pFacelet->pProxy->QueryInterface (iid, &pvResult);
  527.         // Add the remote refs...
  528. pFacelet->remoteRefCount += nRefs;
  529.         }
  530.     else
  531. {
  532. // Check for explicit IUnknown special case - we must make an
  533. // entry for the IUnknown interface in the 'm_facelets' table
  534. // now it's IPID is known, but we don't give out the pointer
  535. // to the facelet, instead we return the StdProxy's IUnknown,
  536. // and the facelet is used only to count remote refs...
  537.         IOrpcProxy* pProxy=0;
  538.             
  539. if (iid == IID_IUnknown)
  540.     {
  541.             // For IUnknown, we don't create an interface-proxy, and
  542.             // we return the primary IUnknown of this StdProxy...
  543.             
  544.     AddRef ();
  545.     pvResult = static_cast<IUnknown*> (this);
  546.     }
  547. else    
  548.     {
  549.     // For other IIDs, we need to create an interface-proxy
  550.     // from the factory. This results in one ref in pProxy,
  551.             // which we must drop later...
  552.             
  553.     VxPSFactory* pPSFactory = VxPSFactory::theInstance ();
  554.             hr = pPSFactory->CreateProxy (this, iid, ipid, &pProxy);
  555.             if (FAILED (hr))
  556.                 return hr;
  557.             // QI the proxy for the desired interface...
  558.             hr = pProxy->QueryInterface (iid, &pvResult);
  559.             if (FAILED (hr))
  560.                 {
  561.                 pProxy->Release ();
  562.                 return hr;
  563.                 }
  564.             
  565.             // Connect the proxy to the channel...
  566.             pProxy->Connect (m_pChannel);
  567.             }
  568.         // Create a facelet to refer to the interface-proxy...
  569. VxCritSec cs (m_mutex);
  570. m_facelets [pvResult] = facelet_t (pProxy, nRefs, ipid);
  571.         // Now drop the ref we got from CreateProxy()...
  572.         if (pProxy)
  573.             pProxy->Release ();
  574. }
  575.     // Return resulting interface ptr...
  576.     if (ppv)
  577. *ppv = pvResult;
  578.     return hr;
  579.     }
  580. //////////////////////////////////////////////////////////////////////////
  581. //
  582. HRESULT VxStdProxy::GetUnmarshalClass
  583.     (
  584.     REFIID, 
  585.     void*, 
  586.     DWORD, 
  587.     void*, 
  588.     DWORD, 
  589.     CLSID*
  590.     )
  591.     {
  592.     TRACE_CALL;
  593.     return E_NOTIMPL; 
  594.     }
  595.         
  596. //////////////////////////////////////////////////////////////////////////
  597. //
  598. HRESULT VxStdProxy::GetMarshalSizeMax
  599.     (
  600.     REFIID          iid,
  601.     void*           pv,
  602.     DWORD           dwDestContext,
  603.     void*           pvDestContext,
  604.     DWORD           mshlflags,
  605.     DWORD*          pSize
  606.     )
  607.     {
  608.     TRACE_CALL;
  609.     *pSize = OBJREF_MAX;
  610.     return S_OK;
  611.     }
  612.         
  613. //////////////////////////////////////////////////////////////////////////
  614. //
  615. // MarshalInterface -- this method hands out one of our existing
  616. // remote interface-refs to another client, so we decrement the
  617. // ref-count for that IPID. If the remaining reference count has
  618. // dropped below 2 (i.e. to one) then we must go ask for some more
  619. // refs from the real object, via RemAddRef(). It is usual to ask for
  620. // 5 at a time...
  621. //
  622. HRESULT VxStdProxy::MarshalInterface
  623.     (
  624.     IStream*            pStrm, 
  625.     REFIID              iid,
  626.     void*               pvInterface, 
  627.     DWORD               dwDestCtx,
  628.     void*               pvDestCtx,
  629.     DWORD               mshlflags
  630.     )
  631.     {
  632.     HRESULT             hr = S_OK;
  633.     // Look for a facelet supporting the requested interface...
  634.     facelet_t* pFacelet = faceletFind (iid);
  635.     if (! pFacelet)
  636.         return E_NOINTERFACE;
  637.     // Get one reference from the facelet - if its ref-count drops to
  638.     // zero then we must request more from the original object...
  639.     if (pFacelet->remoteRefCount < 2)
  640.         {
  641.         REMINTERFACEREF ref;
  642.         HRESULT hrAddRef;
  643.         
  644.         // Invoke RemAddRef() to get more refs...
  645.         ref.ipid = pFacelet->ipid;
  646.         ref.cPublicRefs = 5;
  647.         ref.cPrivateRefs = 0;
  648.         hr = m_pRemUnknown->RemAddRef (1, &ref, &hrAddRef);
  649.         if (FAILED (hr))
  650.             return hr;
  651.         if (FAILED (hrAddRef))
  652.             return hrAddRef;
  653.         pFacelet->remoteRefCount += ref.cPublicRefs;
  654.         }
  655.     
  656.     // Now drop the one we want to give out...
  657.     pFacelet->remoteRefCount -= 1;
  658.     
  659.     // We need to get the OXID-resolver address associated with our
  660.     // remote object exporter, to fill in the OBJREF correctly.
  661.     // Fortunately, we cached it when we unmarshaled our original
  662.     // OBJREF...
  663.     BSTR bsResAddr=0;
  664.     
  665.     if (m_resAddr.format (&bsResAddr, false) != 0)
  666.         return E_FAIL;
  667.     
  668.     // Fill in the OBJREF for this object...
  669.     OLECHAR wszSecInfo [] = { 0x0A, 0xFFFF, 0 };
  670.     const DWORD dsaLen = sizeof (DUALSTRINGARRAY) +
  671.                          (2 * SysStringLen (bsResAddr)) +
  672.                          (2 * vxcom_wcslen (wszSecInfo)) +
  673.                          16;
  674.     OBJREF* pObjRef = (OBJREF*) malloc (sizeof (OBJREF) + dsaLen);
  675.     if (! pObjRef)
  676.         return E_OUTOFMEMORY;
  677.     
  678.     pObjRef->signature = OBJREF_SIGNATURE;
  679.     pObjRef->flags = OBJREF_STANDARD;
  680.     pObjRef->iid = iid;
  681.     pObjRef->u_objref.u_standard.std.flags = 0;
  682.     pObjRef->u_objref.u_standard.std.cPublicRefs = 1;
  683.     pObjRef->u_objref.u_standard.std.oxid = m_pOxid->oxid ();
  684.     pObjRef->u_objref.u_standard.std.oid = m_oid;
  685.     pObjRef->u_objref.u_standard.std.ipid = pFacelet->ipid;
  686.     // Fill in the DSA with the address info from the resolver...
  687.     hr = orpcDSAFormat (&pObjRef->u_objref.u_standard.saResAddr,
  688.                         dsaLen,
  689.                         bsResAddr,
  690.                         wszSecInfo);
  691.     if (SUCCEEDED (hr))
  692.         {
  693.         // Now marshal the OBJREF into the marshaling packet, so it can be
  694.         // accessed by the proxy...
  695.         NdrMarshalStream ms (NdrPhase::NOPHASE,
  696.                              VXDCOM_DREP_LITTLE_ENDIAN);
  697.     
  698.         hr = ndrMarshalOBJREF (&ms, pObjRef);
  699.         if (SUCCEEDED (hr))
  700.             hr = pStrm->Write (ms.begin (), ms.size (), 0);
  701.         }
  702.     // Tidy up
  703.     free (pObjRef);
  704.     // Tidy up...
  705.     return hr;
  706.     }
  707.