ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

marshal.c
Go to the documentation of this file.
00001 /*
00002  *  Marshalling library
00003  *
00004  * Copyright 2002 Marcus Meissner
00005  * Copyright 2004 Mike Hearn, for CodeWeavers
00006  * Copyright 2004 Rob Shearman, for CodeWeavers
00007  *
00008  * This library is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU Lesser General Public
00010  * License as published by the Free Software Foundation; either
00011  * version 2.1 of the License, or (at your option) any later version.
00012  *
00013  * This library is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016  * Lesser General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU Lesser General Public
00019  * License along with this library; if not, write to the Free Software
00020  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00021  */
00022 
00023 #include <stdarg.h>
00024 #include <string.h>
00025 #include <assert.h>
00026 
00027 #define COBJMACROS
00028 
00029 #include "windef.h"
00030 #include "winbase.h"
00031 #include "winuser.h"
00032 #include "objbase.h"
00033 #include "ole2.h"
00034 #include "winerror.h"
00035 #include "wine/unicode.h"
00036 
00037 #include "compobj_private.h"
00038 
00039 #include "wine/debug.h"
00040 
00041 WINE_DEFAULT_DEBUG_CHANNEL(ole);
00042 
00043 extern const CLSID CLSID_DfMarshal;
00044 
00045 /* number of refs given out for normal marshaling */
00046 #define NORMALEXTREFS 5
00047 
00048 
00049 /* private flag indicating that the object was marshaled as table-weak */
00050 #define SORFP_TABLEWEAK SORF_OXRES1
00051 /* private flag indicating that the caller does not want to notify the stub
00052  * when the proxy disconnects or is destroyed */
00053 #define SORFP_NOLIFETIMEMGMT SORF_OXRES2
00054 
00055 /* imported object / proxy manager */
00056 struct proxy_manager
00057 {
00058   const IMultiQIVtbl *lpVtbl;
00059   const IMarshalVtbl *lpVtblMarshal;
00060   const IClientSecurityVtbl *lpVtblCliSec;
00061   struct apartment *parent; /* owning apartment (RO) */
00062   struct list entry;        /* entry in apartment (CS parent->cs) */
00063   OXID oxid;                /* object exported ID (RO) */
00064   OXID_INFO oxid_info;      /* string binding, ipid of rem unknown and other information (RO) */
00065   OID oid;                  /* object ID (RO) */
00066   struct list interfaces;   /* imported interfaces (CS cs) */
00067   LONG refs;                /* proxy reference count (LOCK) */
00068   CRITICAL_SECTION cs;      /* thread safety for this object and children */
00069   ULONG sorflags;           /* STDOBJREF flags (RO) */
00070   IRemUnknown *remunk;      /* proxy to IRemUnknown used for lifecycle management (CS cs) */
00071   HANDLE remoting_mutex;    /* mutex used for synchronizing access to IRemUnknown */
00072   MSHCTX dest_context;      /* context used for activating optimisations (LOCK) */
00073   void *dest_context_data;  /* reserved context value (LOCK) */
00074 };
00075 
00076 static inline struct proxy_manager *impl_from_IMarshal( IMarshal *iface )
00077 {
00078     return (struct proxy_manager *)((char*)iface - FIELD_OFFSET(struct proxy_manager, lpVtblMarshal));
00079 }
00080 
00081 static inline struct proxy_manager *impl_from_IClientSecurity( IClientSecurity *iface )
00082 {
00083     return (struct proxy_manager *)((char*)iface - FIELD_OFFSET(struct proxy_manager, lpVtblCliSec));
00084 }
00085 
00086 static HRESULT unmarshal_object(const STDOBJREF *stdobjref, APARTMENT *apt,
00087                                 MSHCTX dest_context, void *dest_context_data,
00088                                 REFIID riid, const OXID_INFO *oxid_info,
00089                                 void **object);
00090 
00091 /* Marshalling just passes a unique identifier to the remote client,
00092  * that makes it possible to find the passed interface again.
00093  *
00094  * So basically we need a set of values that make it unique.
00095  *
00096  * Note that the IUnknown_QI(ob,xiid,&ppv) always returns the SAME ppv value!
00097  *
00098  * A triple is used: OXID (apt id), OID (stub manager id),
00099  * IPID (interface ptr/stub id).
00100  *
00101  * OXIDs identify an apartment and are network scoped
00102  * OIDs identify a stub manager and are apartment scoped
00103  * IPIDs identify an interface stub and are apartment scoped
00104  */
00105 
00106 static inline HRESULT get_facbuf_for_iid(REFIID riid, IPSFactoryBuffer **facbuf)
00107 {
00108     HRESULT       hr;
00109     CLSID         clsid;
00110 
00111     if ((hr = CoGetPSClsid(riid, &clsid)))
00112         return hr;
00113     return CoGetClassObject(&clsid, CLSCTX_INPROC_SERVER | WINE_CLSCTX_DONT_HOST,
00114         NULL, &IID_IPSFactoryBuffer, (LPVOID*)facbuf);
00115 }
00116 
00117 /* marshals an object into a STDOBJREF structure */
00118 HRESULT marshal_object(APARTMENT *apt, STDOBJREF *stdobjref, REFIID riid, IUnknown *object, MSHLFLAGS mshlflags)
00119 {
00120     struct stub_manager *manager;
00121     struct ifstub       *ifstub;
00122     BOOL                 tablemarshal;
00123     IRpcStubBuffer      *stub = NULL;
00124     HRESULT              hr;
00125     IUnknown            *iobject = NULL; /* object of type riid */
00126 
00127     hr = apartment_getoxid(apt, &stdobjref->oxid);
00128     if (hr != S_OK)
00129         return hr;
00130 
00131     hr = apartment_createwindowifneeded(apt);
00132     if (hr != S_OK)
00133         return hr;
00134 
00135     hr = IUnknown_QueryInterface(object, riid, (void **)&iobject);
00136     if (hr != S_OK)
00137     {
00138         ERR("object doesn't expose interface %s, failing with error 0x%08x\n",
00139             debugstr_guid(riid), hr);
00140         return E_NOINTERFACE;
00141     }
00142   
00143     /* IUnknown doesn't require a stub buffer, because it never goes out on
00144      * the wire */
00145     if (!IsEqualIID(riid, &IID_IUnknown))
00146     {
00147         IPSFactoryBuffer *psfb;
00148 
00149         hr = get_facbuf_for_iid(riid, &psfb);
00150         if (hr != S_OK)
00151         {
00152             ERR("couldn't get IPSFactory buffer for interface %s\n", debugstr_guid(riid));
00153             IUnknown_Release(iobject);
00154             return hr;
00155         }
00156     
00157         hr = IPSFactoryBuffer_CreateStub(psfb, riid, iobject, &stub);
00158         IPSFactoryBuffer_Release(psfb);
00159         if (hr != S_OK)
00160         {
00161             ERR("Failed to create an IRpcStubBuffer from IPSFactory for %s with error 0x%08x\n",
00162                 debugstr_guid(riid), hr);
00163             IUnknown_Release(iobject);
00164             return hr;
00165         }
00166     }
00167 
00168     stdobjref->flags = SORF_NULL;
00169     if (mshlflags & MSHLFLAGS_TABLEWEAK)
00170         stdobjref->flags |= SORFP_TABLEWEAK;
00171     if (mshlflags & MSHLFLAGS_NOPING)
00172         stdobjref->flags |= SORF_NOPING;
00173 
00174     if ((manager = get_stub_manager_from_object(apt, object)))
00175         TRACE("registering new ifstub on pre-existing manager\n");
00176     else
00177     {
00178         TRACE("constructing new stub manager\n");
00179 
00180         manager = new_stub_manager(apt, object);
00181         if (!manager)
00182         {
00183             if (stub) IRpcStubBuffer_Release(stub);
00184             IUnknown_Release(iobject);
00185             return E_OUTOFMEMORY;
00186         }
00187     }
00188     stdobjref->oid = manager->oid;
00189 
00190     tablemarshal = ((mshlflags & MSHLFLAGS_TABLESTRONG) || (mshlflags & MSHLFLAGS_TABLEWEAK));
00191 
00192     /* make sure ifstub that we are creating is unique */
00193     ifstub = stub_manager_find_ifstub(manager, riid, mshlflags);
00194     if (!ifstub)
00195         ifstub = stub_manager_new_ifstub(manager, stub, iobject, riid, mshlflags);
00196 
00197     if (stub) IRpcStubBuffer_Release(stub);
00198     IUnknown_Release(iobject);
00199 
00200     if (!ifstub)
00201     {
00202         stub_manager_int_release(manager);
00203         /* destroy the stub manager if it has no ifstubs by releasing
00204          * zero external references */
00205         stub_manager_ext_release(manager, 0, FALSE, TRUE);
00206         return E_OUTOFMEMORY;
00207     }
00208 
00209     if (!tablemarshal)
00210     {
00211         stdobjref->cPublicRefs = NORMALEXTREFS;
00212         stub_manager_ext_addref(manager, stdobjref->cPublicRefs, FALSE);
00213     }
00214     else
00215     {
00216         stdobjref->cPublicRefs = 0;
00217         if (mshlflags & MSHLFLAGS_TABLESTRONG)
00218             stub_manager_ext_addref(manager, 1, FALSE);
00219         else
00220             stub_manager_ext_addref(manager, 0, TRUE);
00221     }
00222 
00223     /* FIXME: check return value */
00224     RPC_RegisterInterface(riid);
00225 
00226     stdobjref->ipid = ifstub->ipid;
00227 
00228     stub_manager_int_release(manager);
00229     return S_OK;
00230 }
00231 
00232 
00233 
00234 /* Client-side identity of the server object */
00235 
00236 static HRESULT proxy_manager_get_remunknown(struct proxy_manager * This, IRemUnknown **remunk);
00237 static void proxy_manager_destroy(struct proxy_manager * This);
00238 static HRESULT proxy_manager_find_ifproxy(struct proxy_manager * This, REFIID riid, struct ifproxy ** ifproxy_found);
00239 static HRESULT proxy_manager_query_local_interface(struct proxy_manager * This, REFIID riid, void ** ppv);
00240 
00241 static HRESULT WINAPI ClientIdentity_QueryInterface(IMultiQI * iface, REFIID riid, void ** ppv)
00242 {
00243     HRESULT hr;
00244     MULTI_QI mqi;
00245 
00246     TRACE("%s\n", debugstr_guid(riid));
00247 
00248     mqi.pIID = riid;
00249     hr = IMultiQI_QueryMultipleInterfaces(iface, 1, &mqi);
00250     *ppv = mqi.pItf;
00251 
00252     return hr;
00253 }
00254 
00255 static ULONG WINAPI ClientIdentity_AddRef(IMultiQI * iface)
00256 {
00257     struct proxy_manager * This = (struct proxy_manager *)iface;
00258     TRACE("%p - before %d\n", iface, This->refs);
00259     return InterlockedIncrement(&This->refs);
00260 }
00261 
00262 static ULONG WINAPI ClientIdentity_Release(IMultiQI * iface)
00263 {
00264     struct proxy_manager * This = (struct proxy_manager *)iface;
00265     ULONG refs = InterlockedDecrement(&This->refs);
00266     TRACE("%p - after %d\n", iface, refs);
00267     if (!refs)
00268         proxy_manager_destroy(This);
00269     return refs;
00270 }
00271 
00272 static HRESULT WINAPI ClientIdentity_QueryMultipleInterfaces(IMultiQI *iface, ULONG cMQIs, MULTI_QI *pMQIs)
00273 {
00274     struct proxy_manager * This = (struct proxy_manager *)iface;
00275     REMQIRESULT *qiresults = NULL;
00276     ULONG nonlocal_mqis = 0;
00277     ULONG i;
00278     ULONG successful_mqis = 0;
00279     IID *iids = HeapAlloc(GetProcessHeap(), 0, cMQIs * sizeof(*iids));
00280     /* mapping of RemQueryInterface index to QueryMultipleInterfaces index */
00281     ULONG *mapping = HeapAlloc(GetProcessHeap(), 0, cMQIs * sizeof(*mapping));
00282 
00283     TRACE("cMQIs: %d\n", cMQIs);
00284 
00285     /* try to get a local interface - this includes already active proxy
00286      * interfaces and also interfaces exposed by the proxy manager */
00287     for (i = 0; i < cMQIs; i++)
00288     {
00289         TRACE("iid[%d] = %s\n", i, debugstr_guid(pMQIs[i].pIID));
00290         pMQIs[i].hr = proxy_manager_query_local_interface(This, pMQIs[i].pIID, (void **)&pMQIs[i].pItf);
00291         if (pMQIs[i].hr == S_OK)
00292             successful_mqis++;
00293         else
00294         {
00295             iids[nonlocal_mqis] = *pMQIs[i].pIID;
00296             mapping[nonlocal_mqis] = i;
00297             nonlocal_mqis++;
00298         }
00299     }
00300 
00301     TRACE("%d interfaces not found locally\n", nonlocal_mqis);
00302 
00303     /* if we have more than one interface not found locally then we must try
00304      * to query the remote object for it */
00305     if (nonlocal_mqis != 0)
00306     {
00307         IRemUnknown *remunk;
00308         HRESULT hr;
00309         IPID *ipid;
00310 
00311         /* get the ipid of the first entry */
00312         /* FIXME: should we implement ClientIdentity on the ifproxies instead
00313          * of the proxy_manager so we use the correct ipid here? */
00314         ipid = &LIST_ENTRY(list_head(&This->interfaces), struct ifproxy, entry)->stdobjref.ipid;
00315 
00316         /* get IRemUnknown proxy so we can communicate with the remote object */
00317         hr = proxy_manager_get_remunknown(This, &remunk);
00318 
00319         if (SUCCEEDED(hr))
00320         {
00321             hr = IRemUnknown_RemQueryInterface(remunk, ipid, NORMALEXTREFS,
00322                                                nonlocal_mqis, iids, &qiresults);
00323             IRemUnknown_Release(remunk);
00324             if (FAILED(hr))
00325                 ERR("IRemUnknown_RemQueryInterface failed with error 0x%08x\n", hr);
00326         }
00327 
00328         /* IRemUnknown_RemQueryInterface can return S_FALSE if only some of
00329          * the interfaces were returned */
00330         if (SUCCEEDED(hr))
00331         {
00332             /* try to unmarshal each object returned to us */
00333             for (i = 0; i < nonlocal_mqis; i++)
00334             {
00335                 ULONG index = mapping[i];
00336                 HRESULT hrobj = qiresults[i].hResult;
00337                 if (hrobj == S_OK)
00338                     hrobj = unmarshal_object(&qiresults[i].std, COM_CurrentApt(),
00339                                              This->dest_context,
00340                                              This->dest_context_data,
00341                                              pMQIs[index].pIID, &This->oxid_info,
00342                                              (void **)&pMQIs[index].pItf);
00343 
00344                 if (hrobj == S_OK)
00345                     successful_mqis++;
00346                 else
00347                     ERR("Failed to get pointer to interface %s\n", debugstr_guid(pMQIs[index].pIID));
00348                 pMQIs[index].hr = hrobj;
00349             }
00350         }
00351 
00352         /* free the memory allocated by the proxy */
00353         CoTaskMemFree(qiresults);
00354     }
00355 
00356     TRACE("%d/%d successfully queried\n", successful_mqis, cMQIs);
00357 
00358     HeapFree(GetProcessHeap(), 0, iids);
00359     HeapFree(GetProcessHeap(), 0, mapping);
00360 
00361     if (successful_mqis == cMQIs)
00362         return S_OK; /* we got all requested interfaces */
00363     else if (successful_mqis == 0)
00364         return E_NOINTERFACE; /* we didn't get any interfaces */
00365     else
00366         return S_FALSE; /* we got some interfaces */
00367 }
00368 
00369 static const IMultiQIVtbl ClientIdentity_Vtbl =
00370 {
00371     ClientIdentity_QueryInterface,
00372     ClientIdentity_AddRef,
00373     ClientIdentity_Release,
00374     ClientIdentity_QueryMultipleInterfaces
00375 };
00376 
00377 /* FIXME: remove these */
00378 static HRESULT WINAPI StdMarshalImpl_GetUnmarshalClass(LPMARSHAL iface, REFIID riid, void* pv, DWORD dwDestContext, void* pvDestContext, DWORD mshlflags, CLSID* pCid);
00379 static HRESULT WINAPI StdMarshalImpl_GetMarshalSizeMax(LPMARSHAL iface, REFIID riid, void* pv, DWORD dwDestContext, void* pvDestContext, DWORD mshlflags, DWORD* pSize);
00380 static HRESULT WINAPI StdMarshalImpl_UnmarshalInterface(LPMARSHAL iface, IStream *pStm, REFIID riid, void **ppv);
00381 static HRESULT WINAPI StdMarshalImpl_ReleaseMarshalData(LPMARSHAL iface, IStream *pStm);
00382 static HRESULT WINAPI StdMarshalImpl_DisconnectObject(LPMARSHAL iface, DWORD dwReserved);
00383 
00384 static HRESULT WINAPI Proxy_QueryInterface(IMarshal *iface, REFIID riid, void **ppvObject)
00385 {
00386     struct proxy_manager *This = impl_from_IMarshal( iface );
00387     return IMultiQI_QueryInterface((IMultiQI *)&This->lpVtbl, riid, ppvObject);
00388 }
00389 
00390 static ULONG WINAPI Proxy_AddRef(IMarshal *iface)
00391 {
00392     struct proxy_manager *This = impl_from_IMarshal( iface );
00393     return IMultiQI_AddRef((IMultiQI *)&This->lpVtbl);
00394 }
00395 
00396 static ULONG WINAPI Proxy_Release(IMarshal *iface)
00397 {
00398     struct proxy_manager *This = impl_from_IMarshal( iface );
00399     return IMultiQI_Release((IMultiQI *)&This->lpVtbl);
00400 }
00401 
00402 static HRESULT WINAPI Proxy_MarshalInterface(
00403     LPMARSHAL iface, IStream *pStm, REFIID riid, void* pv, DWORD dwDestContext,
00404     void* pvDestContext, DWORD mshlflags)
00405 {
00406     struct proxy_manager *This = impl_from_IMarshal( iface );
00407     HRESULT hr;
00408     struct ifproxy *ifproxy;
00409 
00410     TRACE("(...,%s,...)\n", debugstr_guid(riid));
00411 
00412     hr = proxy_manager_find_ifproxy(This, riid, &ifproxy);
00413     if (SUCCEEDED(hr))
00414     {
00415         STDOBJREF stdobjref = ifproxy->stdobjref;
00416 
00417         stdobjref.cPublicRefs = 0;
00418 
00419         if ((mshlflags != MSHLFLAGS_TABLEWEAK) &&
00420             (mshlflags != MSHLFLAGS_TABLESTRONG))
00421         {
00422             ULONG cPublicRefs = ifproxy->refs;
00423             ULONG cPublicRefsOld;
00424             /* optimization - share out proxy's public references if possible
00425              * instead of making new proxy do a roundtrip through the server */
00426             do
00427             {
00428                 ULONG cPublicRefsNew;
00429                 cPublicRefsOld = cPublicRefs;
00430                 stdobjref.cPublicRefs = cPublicRefs / 2;
00431                 cPublicRefsNew = cPublicRefs - stdobjref.cPublicRefs;
00432                 cPublicRefs = InterlockedCompareExchange(
00433                     (LONG *)&ifproxy->refs, cPublicRefsNew, cPublicRefsOld);
00434             } while (cPublicRefs != cPublicRefsOld);
00435         }
00436 
00437         /* normal and table-strong marshaling need at least one reference */
00438         if (!stdobjref.cPublicRefs && (mshlflags != MSHLFLAGS_TABLEWEAK))
00439         {
00440             IRemUnknown *remunk;
00441             hr = proxy_manager_get_remunknown(This, &remunk);
00442             if (hr == S_OK)
00443             {
00444                 HRESULT hrref = S_OK;
00445                 REMINTERFACEREF rif;
00446                 rif.ipid = ifproxy->stdobjref.ipid;
00447                 rif.cPublicRefs = (mshlflags == MSHLFLAGS_TABLESTRONG) ? 1 : NORMALEXTREFS;
00448                 rif.cPrivateRefs = 0;
00449                 hr = IRemUnknown_RemAddRef(remunk, 1, &rif, &hrref);
00450                 IRemUnknown_Release(remunk);
00451                 if (hr == S_OK && hrref == S_OK)
00452                 {
00453                     /* table-strong marshaling doesn't give the refs to the
00454                      * client that unmarshals the STDOBJREF */
00455                     if (mshlflags != MSHLFLAGS_TABLESTRONG)
00456                         stdobjref.cPublicRefs = rif.cPublicRefs;
00457                 }
00458                 else
00459                     ERR("IRemUnknown_RemAddRef returned with 0x%08x, hrref = 0x%08x\n", hr, hrref);
00460             }
00461         }
00462 
00463         if (SUCCEEDED(hr))
00464         {
00465             TRACE("writing stdobjref: flags = %04x cPublicRefs = %d oxid = %s oid = %s ipid = %s\n",
00466                 stdobjref.flags, stdobjref.cPublicRefs,
00467                 wine_dbgstr_longlong(stdobjref.oxid),
00468                 wine_dbgstr_longlong(stdobjref.oid),
00469                 debugstr_guid(&stdobjref.ipid));
00470             hr = IStream_Write(pStm, &stdobjref, sizeof(stdobjref), NULL);
00471         }
00472     }
00473     else
00474     {
00475         /* we don't have the interface already unmarshaled so we have to
00476          * request the object from the server */
00477         IRemUnknown *remunk;
00478         IPID *ipid;
00479         REMQIRESULT *qiresults = NULL;
00480         IID iid = *riid;
00481 
00482         /* get the ipid of the first entry */
00483         /* FIXME: should we implement ClientIdentity on the ifproxies instead
00484          * of the proxy_manager so we use the correct ipid here? */
00485         ipid = &LIST_ENTRY(list_head(&This->interfaces), struct ifproxy, entry)->stdobjref.ipid;
00486 
00487         /* get IRemUnknown proxy so we can communicate with the remote object */
00488         hr = proxy_manager_get_remunknown(This, &remunk);
00489 
00490         if (hr == S_OK)
00491         {
00492             hr = IRemUnknown_RemQueryInterface(remunk, ipid, NORMALEXTREFS,
00493                                                1, &iid, &qiresults);
00494             if (SUCCEEDED(hr))
00495             {
00496                 hr = IStream_Write(pStm, &qiresults->std, sizeof(qiresults->std), NULL);
00497                 if (FAILED(hr))
00498                 {
00499                     REMINTERFACEREF rif;
00500                     rif.ipid = qiresults->std.ipid;
00501                     rif.cPublicRefs = qiresults->std.cPublicRefs;
00502                     rif.cPrivateRefs = 0;
00503                     IRemUnknown_RemRelease(remunk, 1, &rif);
00504                 }
00505                 CoTaskMemFree(qiresults);
00506             }
00507             else
00508                 ERR("IRemUnknown_RemQueryInterface failed with error 0x%08x\n", hr);
00509             IRemUnknown_Release(remunk);
00510         }
00511     }
00512 
00513     return hr;
00514 }
00515 
00516 static const IMarshalVtbl ProxyMarshal_Vtbl =
00517 {
00518     Proxy_QueryInterface,
00519     Proxy_AddRef,
00520     Proxy_Release,
00521     StdMarshalImpl_GetUnmarshalClass,
00522     StdMarshalImpl_GetMarshalSizeMax,
00523     Proxy_MarshalInterface,
00524     StdMarshalImpl_UnmarshalInterface,
00525     StdMarshalImpl_ReleaseMarshalData,
00526     StdMarshalImpl_DisconnectObject
00527 };
00528 
00529 static HRESULT WINAPI ProxyCliSec_QueryInterface(IClientSecurity *iface, REFIID riid, void **ppvObject)
00530 {
00531     struct proxy_manager *This = impl_from_IClientSecurity( iface );
00532     return IMultiQI_QueryInterface((IMultiQI *)&This->lpVtbl, riid, ppvObject);
00533 }
00534 
00535 static ULONG WINAPI ProxyCliSec_AddRef(IClientSecurity *iface)
00536 {
00537     struct proxy_manager *This = impl_from_IClientSecurity( iface );
00538     return IMultiQI_AddRef((IMultiQI *)&This->lpVtbl);
00539 }
00540 
00541 static ULONG WINAPI ProxyCliSec_Release(IClientSecurity *iface)
00542 {
00543     struct proxy_manager *This = impl_from_IClientSecurity( iface );
00544     return IMultiQI_Release((IMultiQI *)&This->lpVtbl);
00545 }
00546 
00547 static HRESULT WINAPI ProxyCliSec_QueryBlanket(IClientSecurity *iface,
00548                                                IUnknown *pProxy,
00549                                                DWORD *pAuthnSvc,
00550                                                DWORD *pAuthzSvc,
00551                                                OLECHAR **ppServerPrincName,
00552                                                DWORD *pAuthnLevel,
00553                                                DWORD *pImpLevel,
00554                                                void **pAuthInfo,
00555                                                DWORD *pCapabilities)
00556 {
00557     FIXME("(%p, %p, %p, %p, %p, %p, %p, %p): stub\n", pProxy, pAuthnSvc,
00558           pAuthzSvc, ppServerPrincName, pAuthnLevel, pImpLevel, pAuthInfo,
00559           pCapabilities);
00560 
00561     if (pAuthnSvc)
00562         *pAuthnSvc = 0;
00563     if (pAuthzSvc)
00564         *pAuthzSvc = 0;
00565     if (ppServerPrincName)
00566         *ppServerPrincName = NULL;
00567     if (pAuthnLevel)
00568         *pAuthnLevel = RPC_C_AUTHN_LEVEL_DEFAULT;
00569     if (pImpLevel)
00570         *pImpLevel = RPC_C_IMP_LEVEL_DEFAULT;
00571     if (pAuthInfo)
00572         *pAuthInfo = NULL;
00573     if (pCapabilities)
00574         *pCapabilities = EOAC_NONE;
00575 
00576     return E_NOTIMPL;
00577 }
00578 
00579 static HRESULT WINAPI ProxyCliSec_SetBlanket(IClientSecurity *iface,
00580                                              IUnknown *pProxy, DWORD AuthnSvc,
00581                                              DWORD AuthzSvc,
00582                                              OLECHAR *pServerPrincName,
00583                                              DWORD AuthnLevel, DWORD ImpLevel,
00584                                              void *pAuthInfo,
00585                                              DWORD Capabilities)
00586 {
00587     FIXME("(%p, %d, %d, %s, %d, %d, %p, 0x%x): stub\n", pProxy, AuthnSvc, AuthzSvc,
00588           pServerPrincName == COLE_DEFAULT_PRINCIPAL ? "<default principal>" : debugstr_w(pServerPrincName),
00589           AuthnLevel, ImpLevel, pAuthInfo, Capabilities);
00590     return E_NOTIMPL;
00591 }
00592 
00593 static HRESULT WINAPI ProxyCliSec_CopyProxy(IClientSecurity *iface,
00594                                             IUnknown *pProxy, IUnknown **ppCopy)
00595 {
00596     FIXME("(%p, %p): stub\n", pProxy, ppCopy);
00597     *ppCopy = NULL;
00598     return E_NOTIMPL;
00599 }
00600 
00601 static const IClientSecurityVtbl ProxyCliSec_Vtbl =
00602 {
00603     ProxyCliSec_QueryInterface,
00604     ProxyCliSec_AddRef,
00605     ProxyCliSec_Release,
00606     ProxyCliSec_QueryBlanket,
00607     ProxyCliSec_SetBlanket,
00608     ProxyCliSec_CopyProxy
00609 };
00610 
00611 static HRESULT ifproxy_get_public_ref(struct ifproxy * This)
00612 {
00613     HRESULT hr = S_OK;
00614 
00615     if (WAIT_OBJECT_0 != WaitForSingleObject(This->parent->remoting_mutex, INFINITE))
00616     {
00617         ERR("Wait failed for ifproxy %p\n", This);
00618         return E_UNEXPECTED;
00619     }
00620 
00621     if (This->refs == 0)
00622     {
00623         IRemUnknown *remunk = NULL;
00624 
00625         TRACE("getting public ref for ifproxy %p\n", This);
00626 
00627         hr = proxy_manager_get_remunknown(This->parent, &remunk);
00628         if (hr == S_OK)
00629         {
00630             HRESULT hrref = S_OK;
00631             REMINTERFACEREF rif;
00632             rif.ipid = This->stdobjref.ipid;
00633             rif.cPublicRefs = NORMALEXTREFS;
00634             rif.cPrivateRefs = 0;
00635             hr = IRemUnknown_RemAddRef(remunk, 1, &rif, &hrref);
00636             IRemUnknown_Release(remunk);
00637             if (hr == S_OK && hrref == S_OK)
00638                 InterlockedExchangeAdd((LONG *)&This->refs, NORMALEXTREFS);
00639             else
00640                 ERR("IRemUnknown_RemAddRef returned with 0x%08x, hrref = 0x%08x\n", hr, hrref);
00641         }
00642     }
00643     ReleaseMutex(This->parent->remoting_mutex);
00644 
00645     return hr;
00646 }
00647 
00648 static HRESULT ifproxy_release_public_refs(struct ifproxy * This)
00649 {
00650     HRESULT hr = S_OK;
00651     LONG public_refs;
00652 
00653     if (WAIT_OBJECT_0 != WaitForSingleObject(This->parent->remoting_mutex, INFINITE))
00654     {
00655         ERR("Wait failed for ifproxy %p\n", This);
00656         return E_UNEXPECTED;
00657     }
00658 
00659     public_refs = This->refs;
00660     if (public_refs > 0)
00661     {
00662         IRemUnknown *remunk = NULL;
00663 
00664         TRACE("releasing %d refs\n", public_refs);
00665 
00666         hr = proxy_manager_get_remunknown(This->parent, &remunk);
00667         if (hr == S_OK)
00668         {
00669             REMINTERFACEREF rif;
00670             rif.ipid = This->stdobjref.ipid;
00671             rif.cPublicRefs = public_refs;
00672             rif.cPrivateRefs = 0;
00673             hr = IRemUnknown_RemRelease(remunk, 1, &rif);
00674             IRemUnknown_Release(remunk);
00675             if (hr == S_OK)
00676                 InterlockedExchangeAdd((LONG *)&This->refs, -public_refs);
00677             else if (hr == RPC_E_DISCONNECTED)
00678                 WARN("couldn't release references because object was "
00679                      "disconnected: oxid = %s, oid = %s\n",
00680                      wine_dbgstr_longlong(This->parent->oxid),
00681                      wine_dbgstr_longlong(This->parent->oid));
00682             else
00683                 ERR("IRemUnknown_RemRelease failed with error 0x%08x\n", hr);
00684         }
00685     }
00686     ReleaseMutex(This->parent->remoting_mutex);
00687 
00688     return hr;
00689 }
00690 
00691 /* should be called inside This->parent->cs critical section */
00692 static void ifproxy_disconnect(struct ifproxy * This)
00693 {
00694     ifproxy_release_public_refs(This);
00695     if (This->proxy) IRpcProxyBuffer_Disconnect(This->proxy);
00696 
00697     IRpcChannelBuffer_Release(This->chan);
00698     This->chan = NULL;
00699 }
00700 
00701 /* should be called in This->parent->cs critical section if it is an entry in parent's list */
00702 static void ifproxy_destroy(struct ifproxy * This)
00703 {
00704     TRACE("%p\n", This);
00705 
00706     /* release public references to this object so that the stub can know
00707      * when to destroy itself */
00708     ifproxy_release_public_refs(This);
00709 
00710     list_remove(&This->entry);
00711 
00712     if (This->chan)
00713     {
00714         IRpcChannelBuffer_Release(This->chan);
00715         This->chan = NULL;
00716     }
00717 
00718     if (This->proxy) IRpcProxyBuffer_Release(This->proxy);
00719 
00720     HeapFree(GetProcessHeap(), 0, This);
00721 }
00722 
00723 static HRESULT proxy_manager_construct(
00724     APARTMENT * apt, ULONG sorflags, OXID oxid, OID oid,
00725     const OXID_INFO *oxid_info, struct proxy_manager ** proxy_manager)
00726 {
00727     struct proxy_manager * This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
00728     if (!This) return E_OUTOFMEMORY;
00729 
00730     This->remoting_mutex = CreateMutexW(NULL, FALSE, NULL);
00731     if (!This->remoting_mutex)
00732     {
00733         HeapFree(GetProcessHeap(), 0, This);
00734         return HRESULT_FROM_WIN32(GetLastError());
00735     }
00736 
00737     if (oxid_info)
00738     {
00739         This->oxid_info.dwPid = oxid_info->dwPid;
00740         This->oxid_info.dwTid = oxid_info->dwTid;
00741         This->oxid_info.ipidRemUnknown = oxid_info->ipidRemUnknown;
00742         This->oxid_info.dwAuthnHint = oxid_info->dwAuthnHint;
00743         This->oxid_info.psa = NULL /* FIXME: copy from oxid_info */;
00744     }
00745     else
00746     {
00747         HRESULT hr = RPC_ResolveOxid(oxid, &This->oxid_info);
00748         if (FAILED(hr))
00749         {
00750             CloseHandle(This->remoting_mutex);
00751             HeapFree(GetProcessHeap(), 0, This);
00752             return hr;
00753         }
00754     }
00755 
00756     This->lpVtbl = &ClientIdentity_Vtbl;
00757     This->lpVtblMarshal = &ProxyMarshal_Vtbl;
00758     This->lpVtblCliSec = &ProxyCliSec_Vtbl;
00759 
00760     list_init(&This->entry);
00761     list_init(&This->interfaces);
00762 
00763     InitializeCriticalSection(&This->cs);
00764     DEBUG_SET_CRITSEC_NAME(&This->cs, "proxy_manager");
00765 
00766     /* the apartment the object was unmarshaled into */
00767     This->parent = apt;
00768 
00769     /* the source apartment and id of the object */
00770     This->oxid = oxid;
00771     This->oid = oid;
00772 
00773     This->refs = 1;
00774 
00775     /* the DCOM draft specification states that the SORF_NOPING flag is
00776      * proxy manager specific, not ifproxy specific, so this implies that we
00777      * should store the STDOBJREF flags here in the proxy manager. */
00778     This->sorflags = sorflags;
00779 
00780     /* we create the IRemUnknown proxy on demand */
00781     This->remunk = NULL;
00782 
00783     /* initialise these values to the weakest values and they will be
00784      * overwritten in proxy_manager_set_context */
00785     This->dest_context = MSHCTX_INPROC;
00786     This->dest_context_data = NULL;
00787 
00788     EnterCriticalSection(&apt->cs);
00789     /* FIXME: we are dependent on the ordering in here to make sure a proxy's
00790      * IRemUnknown proxy doesn't get destroyed before the regual proxy does
00791      * because we need the IRemUnknown proxy during the destruction of the
00792      * regular proxy. Ideally, we should maintain a separate list for the
00793      * IRemUnknown proxies that need late destruction */
00794     list_add_tail(&apt->proxies, &This->entry);
00795     LeaveCriticalSection(&apt->cs);
00796 
00797     TRACE("%p created for OXID %s, OID %s\n", This,
00798         wine_dbgstr_longlong(oxid), wine_dbgstr_longlong(oid));
00799 
00800     *proxy_manager = This;
00801     return S_OK;
00802 }
00803 
00804 static inline void proxy_manager_set_context(struct proxy_manager *This, MSHCTX dest_context, void *dest_context_data)
00805 {
00806     MSHCTX old_dest_context = This->dest_context;
00807     MSHCTX new_dest_context;
00808 
00809     do
00810     {
00811         new_dest_context = old_dest_context;
00812         /* "stronger" values overwrite "weaker" values. stronger values are
00813          * ones that disable more optimisations */
00814         switch (old_dest_context)
00815         {
00816         case MSHCTX_INPROC:
00817             new_dest_context = dest_context;
00818             break;
00819         case MSHCTX_CROSSCTX:
00820             switch (dest_context)
00821             {
00822             case MSHCTX_INPROC:
00823                 break;
00824             default:
00825                 new_dest_context = dest_context;
00826             }
00827             break;
00828         case MSHCTX_LOCAL:
00829             switch (dest_context)
00830             {
00831             case MSHCTX_INPROC:
00832             case MSHCTX_CROSSCTX:
00833                 break;
00834             default:
00835                 new_dest_context = dest_context;
00836             }
00837             break;
00838         case MSHCTX_NOSHAREDMEM:
00839             switch (dest_context)
00840             {
00841             case MSHCTX_DIFFERENTMACHINE:
00842                 new_dest_context = dest_context;
00843                 break;
00844             default:
00845                 break;
00846             }
00847             break;
00848         default:
00849             break;
00850         }
00851 
00852         if (old_dest_context == new_dest_context) break;
00853 
00854         old_dest_context = InterlockedCompareExchange((PLONG)&This->dest_context, new_dest_context, old_dest_context);
00855     } while (new_dest_context != old_dest_context);
00856 
00857     if (dest_context_data)
00858         InterlockedExchangePointer(&This->dest_context_data, dest_context_data);
00859 }
00860 
00861 static HRESULT proxy_manager_query_local_interface(struct proxy_manager * This, REFIID riid, void ** ppv)
00862 {
00863     HRESULT hr;
00864     struct ifproxy * ifproxy;
00865 
00866     TRACE("%s\n", debugstr_guid(riid));
00867 
00868     if (IsEqualIID(riid, &IID_IUnknown) ||
00869         IsEqualIID(riid, &IID_IMultiQI))
00870     {
00871         *ppv = &This->lpVtbl;
00872         IUnknown_AddRef((IUnknown *)*ppv);
00873         return S_OK;
00874     }
00875     if (IsEqualIID(riid, &IID_IMarshal))
00876     {
00877         *ppv = &This->lpVtblMarshal;
00878         IUnknown_AddRef((IUnknown *)*ppv);
00879         return S_OK;
00880     }
00881     if (IsEqualIID(riid, &IID_IClientSecurity))
00882     {
00883         *ppv = &This->lpVtblCliSec;
00884         IUnknown_AddRef((IUnknown *)*ppv);
00885         return S_OK;
00886     }
00887 
00888     hr = proxy_manager_find_ifproxy(This, riid, &ifproxy);
00889     if (hr == S_OK)
00890     {
00891         *ppv = ifproxy->iface;
00892         IUnknown_AddRef((IUnknown *)*ppv);
00893         return S_OK;
00894     }
00895 
00896     *ppv = NULL;
00897     return E_NOINTERFACE;
00898 }
00899 
00900 static HRESULT proxy_manager_create_ifproxy(
00901     struct proxy_manager * This, const STDOBJREF *stdobjref, REFIID riid,
00902     IRpcChannelBuffer * channel, struct ifproxy ** iif_out)
00903 {
00904     HRESULT hr;
00905     IPSFactoryBuffer * psfb;
00906     struct ifproxy * ifproxy = HeapAlloc(GetProcessHeap(), 0, sizeof(*ifproxy));
00907     if (!ifproxy) return E_OUTOFMEMORY;
00908 
00909     list_init(&ifproxy->entry);
00910 
00911     ifproxy->parent = This;
00912     ifproxy->stdobjref = *stdobjref;
00913     ifproxy->iid = *riid;
00914     ifproxy->refs = 0;
00915     ifproxy->proxy = NULL;
00916 
00917     assert(channel);
00918     ifproxy->chan = channel; /* FIXME: we should take the binding strings and construct the channel in this function */
00919 
00920     /* the IUnknown interface is special because it does not have a
00921      * proxy associated with the ifproxy as we handle IUnknown ourselves */
00922     if (IsEqualIID(riid, &IID_IUnknown))
00923     {
00924         ifproxy->iface = &This->lpVtbl;
00925         IMultiQI_AddRef((IMultiQI *)&This->lpVtbl);
00926         hr = S_OK;
00927     }
00928     else
00929     {
00930         hr = get_facbuf_for_iid(riid, &psfb);
00931         if (hr == S_OK)
00932         {
00933             /* important note: the outer unknown is set to the proxy manager.
00934              * This ensures the COM identity rules are not violated, by having a
00935              * one-to-one mapping of objects on the proxy side to objects on the
00936              * stub side, no matter which interface you view the object through */
00937             hr = IPSFactoryBuffer_CreateProxy(psfb, (IUnknown *)&This->lpVtbl, riid,
00938                                               &ifproxy->proxy, &ifproxy->iface);
00939             IPSFactoryBuffer_Release(psfb);
00940             if (hr != S_OK)
00941                 ERR("Could not create proxy for interface %s, error 0x%08x\n",
00942                     debugstr_guid(riid), hr);
00943         }
00944         else
00945             ERR("Could not get IPSFactoryBuffer for interface %s, error 0x%08x\n",
00946                 debugstr_guid(riid), hr);
00947 
00948         if (hr == S_OK)
00949             hr = IRpcProxyBuffer_Connect(ifproxy->proxy, ifproxy->chan);
00950     }
00951 
00952     if (hr == S_OK)
00953     {
00954         EnterCriticalSection(&This->cs);
00955         list_add_tail(&This->interfaces, &ifproxy->entry);
00956         LeaveCriticalSection(&This->cs);
00957 
00958         *iif_out = ifproxy;
00959         TRACE("ifproxy %p created for IPID %s, interface %s with %u public refs\n",
00960               ifproxy, debugstr_guid(&stdobjref->ipid), debugstr_guid(riid), stdobjref->cPublicRefs);
00961     }
00962     else
00963         ifproxy_destroy(ifproxy);
00964 
00965     return hr;
00966 }
00967 
00968 static HRESULT proxy_manager_find_ifproxy(struct proxy_manager * This, REFIID riid, struct ifproxy ** ifproxy_found)
00969 {
00970     HRESULT hr = E_NOINTERFACE; /* assume not found */
00971     struct list * cursor;
00972 
00973     EnterCriticalSection(&This->cs);
00974     LIST_FOR_EACH(cursor, &This->interfaces)
00975     {
00976         struct ifproxy * ifproxy = LIST_ENTRY(cursor, struct ifproxy, entry);
00977         if (IsEqualIID(riid, &ifproxy->iid))
00978         {
00979             *ifproxy_found = ifproxy;
00980             hr = S_OK;
00981             break;
00982         }
00983     }
00984     LeaveCriticalSection(&This->cs);
00985 
00986     return hr;
00987 }
00988 
00989 static void proxy_manager_disconnect(struct proxy_manager * This)
00990 {
00991     struct list * cursor;
00992 
00993     TRACE("oxid = %s, oid = %s\n", wine_dbgstr_longlong(This->oxid),
00994         wine_dbgstr_longlong(This->oid));
00995 
00996     EnterCriticalSection(&This->cs);
00997 
00998     /* SORFP_NOLIFTIMEMGMT proxies (for IRemUnknown) shouldn't be
00999      * disconnected - it won't do anything anyway, except cause
01000      * problems for other objects that depend on this proxy always
01001      * working */
01002     if (!(This->sorflags & SORFP_NOLIFETIMEMGMT))
01003     {
01004         LIST_FOR_EACH(cursor, &This->interfaces)
01005         {
01006             struct ifproxy * ifproxy = LIST_ENTRY(cursor, struct ifproxy, entry);
01007             ifproxy_disconnect(ifproxy);
01008         }
01009     }
01010 
01011     /* apartment is being destroyed so don't keep a pointer around to it */
01012     This->parent = NULL;
01013 
01014     LeaveCriticalSection(&This->cs);
01015 }
01016 
01017 static HRESULT proxy_manager_get_remunknown(struct proxy_manager * This, IRemUnknown **remunk)
01018 {
01019     HRESULT hr = S_OK;
01020     struct apartment *apt;
01021     BOOL called_in_original_apt;
01022 
01023     /* we don't want to try and unmarshal or use IRemUnknown if we don't want
01024      * lifetime management */
01025     if (This->sorflags & SORFP_NOLIFETIMEMGMT)
01026         return S_FALSE;
01027 
01028     apt = COM_CurrentApt();
01029     if (!apt)
01030         return CO_E_NOTINITIALIZED;
01031 
01032     called_in_original_apt = This->parent && (This->parent->oxid == apt->oxid);
01033 
01034     EnterCriticalSection(&This->cs);
01035     /* only return the cached object if called from the original apartment.
01036      * in future, we might want to make the IRemUnknown proxy callable from any
01037      * apartment to avoid these checks */
01038     if (This->remunk && called_in_original_apt)
01039     {
01040         /* already created - return existing object */
01041         *remunk = This->remunk;
01042         IRemUnknown_AddRef(*remunk);
01043     }
01044     else if (!This->parent)
01045         /* disconnected - we can't create IRemUnknown */
01046         hr = S_FALSE;
01047     else
01048     {
01049         STDOBJREF stdobjref;
01050         /* Don't want IRemUnknown lifetime management as this is IRemUnknown!
01051          * We also don't care about whether or not the stub is still alive */
01052         stdobjref.flags = SORFP_NOLIFETIMEMGMT | SORF_NOPING;
01053         stdobjref.cPublicRefs = 1;
01054         /* oxid of destination object */
01055         stdobjref.oxid = This->oxid;
01056         /* FIXME: what should be used for the oid? The DCOM draft doesn't say */
01057         stdobjref.oid = (OID)-1;
01058         stdobjref.ipid = This->oxid_info.ipidRemUnknown;
01059 
01060         /* do the unmarshal */
01061         hr = unmarshal_object(&stdobjref, COM_CurrentApt(), This->dest_context,
01062                               This->dest_context_data, &IID_IRemUnknown,
01063                               &This->oxid_info, (void**)remunk);
01064         if (hr == S_OK && called_in_original_apt)
01065         {
01066             This->remunk = *remunk;
01067             IRemUnknown_AddRef(This->remunk);
01068         }
01069     }
01070     LeaveCriticalSection(&This->cs);
01071 
01072     TRACE("got IRemUnknown* pointer %p, hr = 0x%08x\n", *remunk, hr);
01073 
01074     return hr;
01075 }
01076 
01077 /* destroys a proxy manager, freeing the memory it used.
01078  * Note: this function should not be called from a list iteration in the
01079  * apartment, due to the fact that it removes itself from the apartment and
01080  * it could add a proxy to IRemUnknown into the apartment. */
01081 static void proxy_manager_destroy(struct proxy_manager * This)
01082 {
01083     struct list * cursor;
01084 
01085     TRACE("oxid = %s, oid = %s\n", wine_dbgstr_longlong(This->oxid),
01086         wine_dbgstr_longlong(This->oid));
01087 
01088     if (This->parent)
01089     {
01090         EnterCriticalSection(&This->parent->cs);
01091 
01092         /* remove ourself from the list of proxy objects in the apartment */
01093         LIST_FOR_EACH(cursor, &This->parent->proxies)
01094         {
01095             if (cursor == &This->entry)
01096             {
01097                 list_remove(&This->entry);
01098                 break;
01099             }
01100         }
01101 
01102         LeaveCriticalSection(&This->parent->cs);
01103     }
01104 
01105     /* destroy all of the interface proxies */
01106     while ((cursor = list_head(&This->interfaces)))
01107     {
01108         struct ifproxy * ifproxy = LIST_ENTRY(cursor, struct ifproxy, entry);
01109         ifproxy_destroy(ifproxy);
01110     }
01111 
01112     if (This->remunk) IRemUnknown_Release(This->remunk);
01113     CoTaskMemFree(This->oxid_info.psa);
01114 
01115     DEBUG_CLEAR_CRITSEC_NAME(&This->cs);
01116     DeleteCriticalSection(&This->cs);
01117 
01118     CloseHandle(This->remoting_mutex);
01119 
01120     HeapFree(GetProcessHeap(), 0, This);
01121 }
01122 
01123 /* finds the proxy manager corresponding to a given OXID and OID that has
01124  * been unmarshaled in the specified apartment. The caller must release the
01125  * reference to the proxy_manager when the object is no longer used. */
01126 static BOOL find_proxy_manager(APARTMENT * apt, OXID oxid, OID oid, struct proxy_manager ** proxy_found)
01127 {
01128     BOOL found = FALSE;
01129     struct list * cursor;
01130 
01131     EnterCriticalSection(&apt->cs);
01132     LIST_FOR_EACH(cursor, &apt->proxies)
01133     {
01134         struct proxy_manager * proxy = LIST_ENTRY(cursor, struct proxy_manager, entry);
01135         if ((oxid == proxy->oxid) && (oid == proxy->oid))
01136         {
01137             /* be careful of a race with ClientIdentity_Release, which would
01138              * cause us to return a proxy which is in the process of being
01139              * destroyed */
01140             if (ClientIdentity_AddRef((IMultiQI *)&proxy->lpVtbl) != 0)
01141             {
01142                 *proxy_found = proxy;
01143                 found = TRUE;
01144                 break;
01145             }
01146         }
01147     }
01148     LeaveCriticalSection(&apt->cs);
01149     return found;
01150 }
01151 
01152 HRESULT apartment_disconnectproxies(struct apartment *apt)
01153 {
01154     struct list * cursor;
01155 
01156     LIST_FOR_EACH(cursor, &apt->proxies)
01157     {
01158         struct proxy_manager * proxy = LIST_ENTRY(cursor, struct proxy_manager, entry);
01159         proxy_manager_disconnect(proxy);
01160     }
01161 
01162     return S_OK;
01163 }
01164 
01165 /********************** StdMarshal implementation ****************************/
01166 typedef struct _StdMarshalImpl
01167 {
01168     const IMarshalVtbl  *lpvtbl;
01169     LONG        ref;
01170 
01171     IID         iid;
01172     DWORD       dwDestContext;
01173     LPVOID      pvDestContext;
01174     DWORD       mshlflags;
01175 } StdMarshalImpl;
01176 
01177 static HRESULT WINAPI 
01178 StdMarshalImpl_QueryInterface(LPMARSHAL iface, REFIID riid, LPVOID *ppv)
01179 {
01180     *ppv = NULL;
01181     if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IMarshal, riid))
01182     {
01183         *ppv = iface;
01184         IUnknown_AddRef(iface);
01185         return S_OK;
01186     }
01187     FIXME("No interface for %s.\n", debugstr_guid(riid));
01188     return E_NOINTERFACE;
01189 }
01190 
01191 static ULONG WINAPI
01192 StdMarshalImpl_AddRef(LPMARSHAL iface)
01193 {
01194     StdMarshalImpl *This = (StdMarshalImpl *)iface;
01195     return InterlockedIncrement(&This->ref);
01196 }
01197 
01198 static ULONG WINAPI
01199 StdMarshalImpl_Release(LPMARSHAL iface)
01200 {
01201     StdMarshalImpl *This = (StdMarshalImpl *)iface;
01202     ULONG ref = InterlockedDecrement(&This->ref);
01203 
01204     if (!ref) HeapFree(GetProcessHeap(),0,This);
01205     return ref;
01206 }
01207 
01208 static HRESULT WINAPI
01209 StdMarshalImpl_GetUnmarshalClass(
01210     LPMARSHAL iface, REFIID riid, void* pv, DWORD dwDestContext,
01211     void* pvDestContext, DWORD mshlflags, CLSID* pCid)
01212 {
01213     *pCid = CLSID_DfMarshal;
01214     return S_OK;
01215 }
01216 
01217 static HRESULT WINAPI
01218 StdMarshalImpl_GetMarshalSizeMax(
01219     LPMARSHAL iface, REFIID riid, void* pv, DWORD dwDestContext,
01220     void* pvDestContext, DWORD mshlflags, DWORD* pSize)
01221 {
01222     *pSize = sizeof(STDOBJREF);
01223     return S_OK;
01224 }
01225 
01226 static HRESULT WINAPI
01227 StdMarshalImpl_MarshalInterface(
01228     LPMARSHAL iface, IStream *pStm,REFIID riid, void* pv, DWORD dwDestContext,
01229     void* pvDestContext, DWORD mshlflags)
01230 {
01231     STDOBJREF             stdobjref;
01232     ULONG                 res;
01233     HRESULT               hres;
01234     APARTMENT            *apt = COM_CurrentApt();
01235 
01236     TRACE("(...,%s,...)\n", debugstr_guid(riid));
01237 
01238     if (!apt)
01239     {
01240         ERR("Apartment not initialized\n");
01241         return CO_E_NOTINITIALIZED;
01242     }
01243 
01244     /* make sure this apartment can be reached from other threads / processes */
01245     RPC_StartRemoting(apt);
01246 
01247     hres = marshal_object(apt, &stdobjref, riid, pv, mshlflags);
01248     if (hres != S_OK)
01249     {
01250         ERR("Failed to create ifstub, hres=0x%x\n", hres);
01251         return hres;
01252     }
01253 
01254     return IStream_Write(pStm, &stdobjref, sizeof(stdobjref), &res);
01255 }
01256 
01257 /* helper for StdMarshalImpl_UnmarshalInterface - does the unmarshaling with
01258  * no questions asked about the rules surrounding same-apartment unmarshals
01259  * and table marshaling */
01260 static HRESULT unmarshal_object(const STDOBJREF *stdobjref, APARTMENT *apt,
01261                                 MSHCTX dest_context, void *dest_context_data,
01262                                 REFIID riid, const OXID_INFO *oxid_info,
01263                                 void **object)
01264 {
01265     struct proxy_manager *proxy_manager = NULL;
01266     HRESULT hr = S_OK;
01267 
01268     assert(apt);
01269 
01270     TRACE("stdobjref: flags = %04x cPublicRefs = %d oxid = %s oid = %s ipid = %s\n",
01271         stdobjref->flags, stdobjref->cPublicRefs,
01272         wine_dbgstr_longlong(stdobjref->oxid),
01273         wine_dbgstr_longlong(stdobjref->oid),
01274         debugstr_guid(&stdobjref->ipid));
01275 
01276     /* create a new proxy manager if one doesn't already exist for the
01277      * object */
01278     if (!find_proxy_manager(apt, stdobjref->oxid, stdobjref->oid, &proxy_manager))
01279     {
01280         hr = proxy_manager_construct(apt, stdobjref->flags,
01281                                      stdobjref->oxid, stdobjref->oid, oxid_info,
01282                                      &proxy_manager);
01283     }
01284     else
01285         TRACE("proxy manager already created, using\n");
01286 
01287     if (hr == S_OK)
01288     {
01289         struct ifproxy * ifproxy;
01290 
01291         proxy_manager_set_context(proxy_manager, dest_context, dest_context_data);
01292 
01293         hr = proxy_manager_find_ifproxy(proxy_manager, riid, &ifproxy);
01294         if (hr == E_NOINTERFACE)
01295         {
01296             IRpcChannelBuffer *chanbuf;
01297             hr = RPC_CreateClientChannel(&stdobjref->oxid, &stdobjref->ipid,
01298                                          &proxy_manager->oxid_info,
01299                                          proxy_manager->dest_context,
01300                                          proxy_manager->dest_context_data,
01301                                          &chanbuf);
01302             if (hr == S_OK)
01303                 hr = proxy_manager_create_ifproxy(proxy_manager, stdobjref,
01304                                                   riid, chanbuf, &ifproxy);
01305         }
01306         else
01307             IUnknown_AddRef((IUnknown *)ifproxy->iface);
01308 
01309         if (hr == S_OK)
01310         {
01311             InterlockedExchangeAdd((LONG *)&ifproxy->refs, stdobjref->cPublicRefs);
01312             /* get at least one external reference to the object to keep it alive */
01313             hr = ifproxy_get_public_ref(ifproxy);
01314             if (FAILED(hr))
01315                 ifproxy_destroy(ifproxy);
01316         }
01317 
01318         if (hr == S_OK)
01319             *object = ifproxy->iface;
01320     }
01321 
01322     /* release our reference to the proxy manager - the client/apartment
01323      * will hold on to the remaining reference for us */
01324     if (proxy_manager) ClientIdentity_Release((IMultiQI*)&proxy_manager->lpVtbl);
01325 
01326     return hr;
01327 }
01328 
01329 static HRESULT WINAPI
01330 StdMarshalImpl_UnmarshalInterface(LPMARSHAL iface, IStream *pStm, REFIID riid, void **ppv)
01331 {
01332     StdMarshalImpl *This = (StdMarshalImpl *)iface;
01333     struct stub_manager *stubmgr = NULL;
01334     STDOBJREF stdobjref;
01335     ULONG res;
01336     HRESULT hres;
01337     APARTMENT *apt = COM_CurrentApt();
01338     APARTMENT *stub_apt;
01339     OXID oxid;
01340 
01341     TRACE("(...,%s,....)\n", debugstr_guid(riid));
01342 
01343     /* we need an apartment to unmarshal into */
01344     if (!apt)
01345     {
01346         ERR("Apartment not initialized\n");
01347         return CO_E_NOTINITIALIZED;
01348     }
01349 
01350     /* read STDOBJREF from wire */
01351     hres = IStream_Read(pStm, &stdobjref, sizeof(stdobjref), &res);
01352     if (hres != S_OK) return STG_E_READFAULT;
01353 
01354     hres = apartment_getoxid(apt, &oxid);
01355     if (hres != S_OK) return hres;
01356 
01357     /* check if we're marshalling back to ourselves */
01358     if ((oxid == stdobjref.oxid) && (stubmgr = get_stub_manager(apt, stdobjref.oid)))
01359     {
01360         TRACE("Unmarshalling object marshalled in same apartment for iid %s, "
01361               "returning original object %p\n", debugstr_guid(riid), stubmgr->object);
01362     
01363         hres = IUnknown_QueryInterface(stubmgr->object, riid, ppv);
01364       
01365         /* unref the ifstub. FIXME: only do this on success? */
01366         if (!stub_manager_is_table_marshaled(stubmgr, &stdobjref.ipid))
01367             stub_manager_ext_release(stubmgr, stdobjref.cPublicRefs, stdobjref.flags & SORFP_TABLEWEAK, FALSE);
01368 
01369         stub_manager_int_release(stubmgr);
01370         return hres;
01371     }
01372 
01373     /* notify stub manager about unmarshal if process-local object.
01374      * note: if the oxid is not found then we and native will quite happily
01375      * ignore table marshaling and normal marshaling rules regarding number of
01376      * unmarshals, etc, but if you abuse these rules then your proxy could end
01377      * up returning RPC_E_DISCONNECTED. */
01378     if ((stub_apt = apartment_findfromoxid(stdobjref.oxid, TRUE)))
01379     {
01380         if ((stubmgr = get_stub_manager(stub_apt, stdobjref.oid)))
01381         {
01382             if (!stub_manager_notify_unmarshal(stubmgr, &stdobjref.ipid))
01383                 hres = CO_E_OBJNOTCONNECTED;
01384         }
01385         else
01386         {
01387             WARN("Couldn't find object for OXID %s, OID %s, assuming disconnected\n",
01388                 wine_dbgstr_longlong(stdobjref.oxid),
01389                 wine_dbgstr_longlong(stdobjref.oid));
01390             hres = CO_E_OBJNOTCONNECTED;
01391         }
01392     }
01393     else
01394         TRACE("Treating unmarshal from OXID %s as inter-process\n",
01395             wine_dbgstr_longlong(stdobjref.oxid));
01396 
01397     if (hres == S_OK)
01398         hres = unmarshal_object(&stdobjref, apt, This->dwDestContext,
01399                                 This->pvDestContext, riid,
01400                                 stubmgr ? &stubmgr->oxid_info : NULL, ppv);
01401 
01402     if (stubmgr) stub_manager_int_release(stubmgr);
01403     if (stub_apt) apartment_release(stub_apt);
01404 
01405     if (hres != S_OK) WARN("Failed with error 0x%08x\n", hres);
01406     else TRACE("Successfully created proxy %p\n", *ppv);
01407 
01408     return hres;
01409 }
01410 
01411 static HRESULT WINAPI
01412 StdMarshalImpl_ReleaseMarshalData(LPMARSHAL iface, IStream *pStm)
01413 {
01414     STDOBJREF            stdobjref;
01415     ULONG                res;
01416     HRESULT              hres;
01417     struct stub_manager *stubmgr;
01418     APARTMENT           *apt;
01419 
01420     TRACE("iface=%p, pStm=%p\n", iface, pStm);
01421     
01422     hres = IStream_Read(pStm, &stdobjref, sizeof(stdobjref), &res);
01423     if (hres != S_OK) return STG_E_READFAULT;
01424 
01425     TRACE("oxid = %s, oid = %s, ipid = %s\n",
01426         wine_dbgstr_longlong(stdobjref.oxid),
01427         wine_dbgstr_longlong(stdobjref.oid),
01428         wine_dbgstr_guid(&stdobjref.ipid));
01429 
01430     if (!(apt = apartment_findfromoxid(stdobjref.oxid, TRUE)))
01431     {
01432         WARN("Could not map OXID %s to apartment object\n",
01433             wine_dbgstr_longlong(stdobjref.oxid));
01434         return RPC_E_INVALID_OBJREF;
01435     }
01436 
01437     if (!(stubmgr = get_stub_manager(apt, stdobjref.oid)))
01438     {
01439         ERR("could not map object ID to stub manager, oxid=%s, oid=%s\n",
01440             wine_dbgstr_longlong(stdobjref.oxid), wine_dbgstr_longlong(stdobjref.oid));
01441         return RPC_E_INVALID_OBJREF;
01442     }
01443 
01444     stub_manager_release_marshal_data(stubmgr, stdobjref.cPublicRefs, &stdobjref.ipid, stdobjref.flags & SORFP_TABLEWEAK);
01445 
01446     stub_manager_int_release(stubmgr);
01447     apartment_release(apt);
01448 
01449     return S_OK;
01450 }
01451 
01452 static HRESULT WINAPI
01453 StdMarshalImpl_DisconnectObject(LPMARSHAL iface, DWORD dwReserved)
01454 {
01455     FIXME("(), stub!\n");
01456     return S_OK;
01457 }
01458 
01459 static const IMarshalVtbl VT_StdMarshal =
01460 {
01461     StdMarshalImpl_QueryInterface,
01462     StdMarshalImpl_AddRef,
01463     StdMarshalImpl_Release,
01464     StdMarshalImpl_GetUnmarshalClass,
01465     StdMarshalImpl_GetMarshalSizeMax,
01466     StdMarshalImpl_MarshalInterface,
01467     StdMarshalImpl_UnmarshalInterface,
01468     StdMarshalImpl_ReleaseMarshalData,
01469     StdMarshalImpl_DisconnectObject
01470 };
01471 
01472 static HRESULT StdMarshalImpl_Construct(REFIID riid, void** ppvObject)
01473 {
01474     StdMarshalImpl * pStdMarshal = 
01475         HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(StdMarshalImpl));
01476     if (!pStdMarshal)
01477         return E_OUTOFMEMORY;
01478     pStdMarshal->lpvtbl = &VT_StdMarshal;
01479     pStdMarshal->ref = 0;
01480     return IMarshal_QueryInterface((IMarshal*)pStdMarshal, riid, ppvObject);
01481 }
01482 
01483 /***********************************************************************
01484  *      CoGetStandardMarshal    [OLE32.@]
01485  *
01486  * Gets or creates a standard marshal object.
01487  *
01488  * PARAMS
01489  *  riid          [I] Interface identifier of the pUnk object.
01490  *  pUnk          [I] Optional. Object to get the marshal object for.
01491  *  dwDestContext [I] Destination. Used to enable or disable optimizations.
01492  *  pvDestContext [I] Reserved. Must be NULL.
01493  *  mshlflags     [I] Flags affecting the marshaling process.
01494  *  ppMarshal     [O] Address where marshal object will be stored.
01495  *
01496  * RETURNS
01497  *  Success: S_OK.
01498  *  Failure: HRESULT code.
01499  *
01500  * NOTES
01501  *
01502  * The function retrieves the IMarshal object associated with an object if
01503  * that object is currently an active stub, otherwise a new marshal object is
01504  * created.
01505  */
01506 HRESULT WINAPI CoGetStandardMarshal(REFIID riid, IUnknown *pUnk,
01507                                     DWORD dwDestContext, LPVOID pvDestContext,
01508                                     DWORD mshlflags, LPMARSHAL *ppMarshal)
01509 {
01510     StdMarshalImpl *dm;
01511 
01512     if (pUnk == NULL)
01513     {
01514         FIXME("(%s,NULL,%x,%p,%x,%p), unimplemented yet.\n",
01515             debugstr_guid(riid),dwDestContext,pvDestContext,mshlflags,ppMarshal);
01516         return E_NOTIMPL;
01517     }
01518     TRACE("(%s,%p,%x,%p,%x,%p)\n",
01519         debugstr_guid(riid),pUnk,dwDestContext,pvDestContext,mshlflags,ppMarshal);
01520     *ppMarshal = HeapAlloc(GetProcessHeap(),0,sizeof(StdMarshalImpl));
01521     dm = (StdMarshalImpl*) *ppMarshal;
01522     if (!dm) return E_FAIL;
01523     dm->lpvtbl      = &VT_StdMarshal;
01524     dm->ref     = 1;
01525 
01526     dm->iid     = *riid;
01527     dm->dwDestContext   = dwDestContext;
01528     dm->pvDestContext   = pvDestContext;
01529     dm->mshlflags   = mshlflags;
01530     return S_OK;
01531 }
01532 
01533 /***********************************************************************
01534  *      get_marshaler   [internal]
01535  *
01536  * Retrieves an IMarshal interface for an object.
01537  */
01538 static HRESULT get_marshaler(REFIID riid, IUnknown *pUnk, DWORD dwDestContext,
01539                              void *pvDestContext, DWORD mshlFlags,
01540                              LPMARSHAL *pMarshal)
01541 {
01542     HRESULT hr;
01543 
01544     if (!pUnk)
01545         return E_POINTER;
01546     hr = IUnknown_QueryInterface(pUnk, &IID_IMarshal, (LPVOID*)pMarshal);
01547     if (hr != S_OK)
01548         hr = CoGetStandardMarshal(riid, pUnk, dwDestContext, pvDestContext,
01549                                   mshlFlags, pMarshal);
01550     return hr;
01551 }
01552 
01553 /***********************************************************************
01554  *      get_unmarshaler_from_stream [internal]
01555  *
01556  * Creates an IMarshal* object according to the data marshaled to the stream.
01557  * The function leaves the stream pointer at the start of the data written
01558  * to the stream by the IMarshal* object.
01559  */
01560 static HRESULT get_unmarshaler_from_stream(IStream *stream, IMarshal **marshal, IID *iid)
01561 {
01562     HRESULT hr;
01563     ULONG res;
01564     OBJREF objref;
01565 
01566     /* read common OBJREF header */
01567     hr = IStream_Read(stream, &objref, FIELD_OFFSET(OBJREF, u_objref), &res);
01568     if (hr != S_OK || (res != FIELD_OFFSET(OBJREF, u_objref)))
01569     {
01570         ERR("Failed to read common OBJREF header, 0x%08x\n", hr);
01571         return STG_E_READFAULT;
01572     }
01573 
01574     /* sanity check on header */
01575     if (objref.signature != OBJREF_SIGNATURE)
01576     {
01577         ERR("Bad OBJREF signature 0x%08x\n", objref.signature);
01578         return RPC_E_INVALID_OBJREF;
01579     }
01580 
01581     if (iid) *iid = objref.iid;
01582 
01583     /* FIXME: handler marshaling */
01584     if (objref.flags & OBJREF_STANDARD)
01585     {
01586         TRACE("Using standard unmarshaling\n");
01587         hr = StdMarshalImpl_Construct(&IID_IMarshal, (LPVOID*)marshal);
01588     }
01589     else if (objref.flags & OBJREF_CUSTOM)
01590     {
01591         ULONG custom_header_size = FIELD_OFFSET(OBJREF, u_objref.u_custom.pData) - 
01592                                    FIELD_OFFSET(OBJREF, u_objref.u_custom);
01593         TRACE("Using custom unmarshaling\n");
01594         /* read constant sized OR_CUSTOM data from stream */
01595         hr = IStream_Read(stream, &objref.u_objref.u_custom,
01596                           custom_header_size, &res);
01597         if (hr != S_OK || (res != custom_header_size))
01598         {
01599             ERR("Failed to read OR_CUSTOM header, 0x%08x\n", hr);
01600             return STG_E_READFAULT;
01601         }
01602         /* now create the marshaler specified in the stream */
01603         hr = CoCreateInstance(&objref.u_objref.u_custom.clsid, NULL,
01604                               CLSCTX_INPROC_SERVER, &IID_IMarshal,
01605                               (LPVOID*)marshal);
01606     }
01607     else
01608     {
01609         FIXME("Invalid or unimplemented marshaling type specified: %x\n",
01610             objref.flags);
01611         return RPC_E_INVALID_OBJREF;
01612     }
01613 
01614     if (hr != S_OK)
01615         ERR("Failed to create marshal, 0x%08x\n", hr);
01616 
01617     return hr;
01618 }
01619 
01620 /***********************************************************************
01621  *      CoGetMarshalSizeMax [OLE32.@]
01622  *
01623  * Gets the maximum amount of data that will be needed by a marshal.
01624  *
01625  * PARAMS
01626  *  pulSize       [O] Address where maximum marshal size will be stored.
01627  *  riid          [I] Identifier of the interface to marshal.
01628  *  pUnk          [I] Pointer to the object to marshal.
01629  *  dwDestContext [I] Destination. Used to enable or disable optimizations.
01630  *  pvDestContext [I] Reserved. Must be NULL.
01631  *  mshlFlags     [I] Flags that affect the marshaling. See CoMarshalInterface().
01632  *
01633  * RETURNS
01634  *  Success: S_OK.
01635  *  Failure: HRESULT code.
01636  *
01637  * SEE ALSO
01638  *  CoMarshalInterface().
01639  */
01640 HRESULT WINAPI CoGetMarshalSizeMax(ULONG *pulSize, REFIID riid, IUnknown *pUnk,
01641                                    DWORD dwDestContext, void *pvDestContext,
01642                                    DWORD mshlFlags)
01643 {
01644     HRESULT hr;
01645     LPMARSHAL pMarshal;
01646     CLSID marshaler_clsid;
01647 
01648     hr = get_marshaler(riid, pUnk, dwDestContext, pvDestContext, mshlFlags, &pMarshal);
01649     if (hr != S_OK)
01650         return hr;
01651 
01652     hr = IMarshal_GetUnmarshalClass(pMarshal, riid, pUnk, dwDestContext,
01653                                     pvDestContext, mshlFlags, &marshaler_clsid);
01654     if (hr != S_OK)
01655     {
01656         ERR("IMarshal::GetUnmarshalClass failed, 0x%08x\n", hr);
01657         IMarshal_Release(pMarshal);
01658         return hr;
01659     }
01660 
01661     hr = IMarshal_GetMarshalSizeMax(pMarshal, riid, pUnk, dwDestContext,
01662                                     pvDestContext, mshlFlags, pulSize);
01663     if (IsEqualCLSID(&marshaler_clsid, &CLSID_DfMarshal))
01664         /* add on the size of the common header */
01665         *pulSize += FIELD_OFFSET(OBJREF, u_objref);
01666     else
01667         /* custom marshaling: add on the size of the whole OBJREF structure
01668          * like native does */
01669         *pulSize += sizeof(OBJREF);
01670 
01671     IMarshal_Release(pMarshal);
01672     return hr;
01673 }
01674 
01675 
01676 static void dump_MSHLFLAGS(MSHLFLAGS flags)
01677 {
01678     if (flags & MSHLFLAGS_TABLESTRONG)
01679         TRACE(" MSHLFLAGS_TABLESTRONG");
01680     if (flags & MSHLFLAGS_TABLEWEAK)
01681         TRACE(" MSHLFLAGS_TABLEWEAK");
01682     if (!(flags & (MSHLFLAGS_TABLESTRONG|MSHLFLAGS_TABLEWEAK)))
01683         TRACE(" MSHLFLAGS_NORMAL");
01684     if (flags & MSHLFLAGS_NOPING)
01685         TRACE(" MSHLFLAGS_NOPING");
01686 }
01687 
01688 /***********************************************************************
01689  *      CoMarshalInterface  [OLE32.@]
01690  *
01691  * Marshals an interface into a stream so that the object can then be
01692  * unmarshaled from another COM apartment and used remotely.
01693  *
01694  * PARAMS
01695  *  pStream       [I] Stream the object will be marshaled into.
01696  *  riid          [I] Identifier of the interface to marshal.
01697  *  pUnk          [I] Pointer to the object to marshal.
01698  *  dwDestContext [I] Destination. Used to enable or disable optimizations.
01699  *  pvDestContext [I] Reserved. Must be NULL.
01700  *  mshlFlags     [I] Flags that affect the marshaling. See notes.
01701  *
01702  * RETURNS
01703  *  Success: S_OK.
01704  *  Failure: HRESULT code.
01705  *
01706  * NOTES
01707  *
01708  * The mshlFlags parameter can take one or more of the following flags:
01709  *| MSHLFLAGS_NORMAL - Unmarshal once, releases stub on last proxy release.
01710  *| MSHLFLAGS_TABLESTRONG - Unmarshal many, release when CoReleaseMarshalData() called.
01711  *| MSHLFLAGS_TABLEWEAK - Unmarshal many, releases stub on last proxy release.
01712  *| MSHLFLAGS_NOPING - No automatic garbage collection (and so reduces network traffic).
01713  *
01714  * If a marshaled object is not unmarshaled, then CoReleaseMarshalData() must
01715  * be called in order to release the resources used in the marshaling.
01716  *
01717  * SEE ALSO
01718  *  CoUnmarshalInterface(), CoReleaseMarshalData().
01719  */
01720 HRESULT WINAPI CoMarshalInterface(IStream *pStream, REFIID riid, IUnknown *pUnk,
01721                                   DWORD dwDestContext, void *pvDestContext,
01722                                   DWORD mshlFlags)
01723 {
01724     HRESULT hr;
01725     CLSID marshaler_clsid;
01726     OBJREF objref;
01727     LPMARSHAL pMarshal;
01728 
01729     TRACE("(%p, %s, %p, %x, %p,", pStream, debugstr_guid(riid), pUnk,
01730         dwDestContext, pvDestContext);
01731     dump_MSHLFLAGS(mshlFlags);
01732     TRACE(")\n");
01733 
01734     if (!pUnk || !pStream)
01735         return E_INVALIDARG;
01736 
01737     objref.signature = OBJREF_SIGNATURE;
01738     objref.iid = *riid;
01739 
01740     /* get the marshaler for the specified interface */
01741     hr = get_marshaler(riid, pUnk, dwDestContext, pvDestContext, mshlFlags, &pMarshal);
01742     if (hr != S_OK)
01743     {
01744         ERR("Failed to get marshaller, 0x%08x\n", hr);
01745         return hr;
01746     }
01747 
01748     hr = IMarshal_GetUnmarshalClass(pMarshal, riid, pUnk, dwDestContext,
01749                                     pvDestContext, mshlFlags, &marshaler_clsid);
01750     if (hr != S_OK)
01751     {
01752         ERR("IMarshal::GetUnmarshalClass failed, 0x%08x\n", hr);
01753         goto cleanup;
01754     }
01755 
01756     /* FIXME: implement handler marshaling too */
01757     if (IsEqualCLSID(&marshaler_clsid, &CLSID_DfMarshal))
01758     {
01759         TRACE("Using standard marshaling\n");
01760         objref.flags = OBJREF_STANDARD;
01761 
01762         /* write the common OBJREF header to the stream */
01763         hr = IStream_Write(pStream, &objref, FIELD_OFFSET(OBJREF, u_objref), NULL);
01764         if (hr != S_OK)
01765         {
01766             ERR("Failed to write OBJREF header to stream, 0x%08x\n", hr);
01767             goto cleanup;
01768         }
01769     }
01770     else
01771     {
01772         TRACE("Using custom marshaling\n");
01773         objref.flags = OBJREF_CUSTOM;
01774         objref.u_objref.u_custom.clsid = marshaler_clsid;
01775         objref.u_objref.u_custom.cbExtension = 0;
01776         objref.u_objref.u_custom.size = 0;
01777         hr = IMarshal_GetMarshalSizeMax(pMarshal, riid, pUnk, dwDestContext,
01778                                         pvDestContext, mshlFlags,
01779                                         &objref.u_objref.u_custom.size);
01780         if (hr != S_OK)
01781         {
01782             ERR("Failed to get max size of marshal data, error 0x%08x\n", hr);
01783             goto cleanup;
01784         }
01785         /* write constant sized common header and OR_CUSTOM data into stream */
01786         hr = IStream_Write(pStream, &objref,
01787                           FIELD_OFFSET(OBJREF, u_objref.u_custom.pData), NULL);
01788         if (hr != S_OK)
01789         {
01790             ERR("Failed to write OR_CUSTOM header to stream with 0x%08x\n", hr);
01791             goto cleanup;
01792         }
01793     }
01794 
01795     TRACE("Calling IMarshal::MarshalInterace\n");
01796     /* call helper object to do the actual marshaling */
01797     hr = IMarshal_MarshalInterface(pMarshal, pStream, riid, pUnk, dwDestContext,
01798                                    pvDestContext, mshlFlags);
01799 
01800     if (hr != S_OK)
01801     {
01802         ERR("Failed to marshal the interface %s, %x\n", debugstr_guid(riid), hr);
01803         goto cleanup;
01804     }
01805 
01806 cleanup:
01807     IMarshal_Release(pMarshal);
01808 
01809     TRACE("completed with hr 0x%08x\n", hr);
01810     
01811     return hr;
01812 }
01813 
01814 /***********************************************************************
01815  *      CoUnmarshalInterface    [OLE32.@]
01816  *
01817  * Unmarshals an object from a stream by creating a proxy to the remote
01818  * object, if necessary.
01819  *
01820  * PARAMS
01821  *
01822  *  pStream [I] Stream containing the marshaled object.
01823  *  riid    [I] Interface identifier of the object to create a proxy to.
01824  *  ppv     [O] Address where proxy will be stored.
01825  *
01826  * RETURNS
01827  *
01828  *  Success: S_OK.
01829  *  Failure: HRESULT code.
01830  *
01831  * SEE ALSO
01832  *  CoMarshalInterface().
01833  */
01834 HRESULT WINAPI CoUnmarshalInterface(IStream *pStream, REFIID riid, LPVOID *ppv)
01835 {
01836     HRESULT hr;
01837     LPMARSHAL pMarshal;
01838     IID iid;
01839     IUnknown *object;
01840 
01841     TRACE("(%p, %s, %p)\n", pStream, debugstr_guid(riid), ppv);
01842 
01843     if (!pStream || !ppv)
01844         return E_INVALIDARG;
01845 
01846     hr = get_unmarshaler_from_stream(pStream, &pMarshal, &iid);
01847     if (hr != S_OK)
01848         return hr;
01849 
01850     /* call the helper object to do the actual unmarshaling */
01851     hr = IMarshal_UnmarshalInterface(pMarshal, pStream, &iid, (LPVOID*)&object);
01852     if (hr != S_OK)
01853         ERR("IMarshal::UnmarshalInterface failed, 0x%08x\n", hr);
01854 
01855     if (hr == S_OK)
01856     {
01857         /* IID_NULL means use the interface ID of the marshaled object */
01858         if (!IsEqualIID(riid, &IID_NULL) && !IsEqualIID(riid, &iid))
01859         {
01860             TRACE("requested interface != marshalled interface, additional QI needed\n");
01861             hr = IUnknown_QueryInterface(object, riid, ppv);
01862             if (hr != S_OK)
01863                 ERR("Couldn't query for interface %s, hr = 0x%08x\n",
01864                     debugstr_guid(riid), hr);
01865             IUnknown_Release(object);
01866         }
01867         else
01868         {
01869             *ppv = object;
01870         }
01871     }
01872 
01873     IMarshal_Release(pMarshal);
01874 
01875     TRACE("completed with hr 0x%x\n", hr);
01876     
01877     return hr;
01878 }
01879 
01880 /***********************************************************************
01881  *      CoReleaseMarshalData    [OLE32.@]
01882  *
01883  * Releases resources associated with an object that has been marshaled into
01884  * a stream.
01885  *
01886  * PARAMS
01887  *
01888  *  pStream [I] The stream that the object has been marshaled into.
01889  *
01890  * RETURNS
01891  *  Success: S_OK.
01892  *  Failure: HRESULT error code.
01893  *
01894  * NOTES
01895  * 
01896  * Call this function to release resources associated with a normal or
01897  * table-weak marshal that will not be unmarshaled, and all table-strong
01898  * marshals when they are no longer needed.
01899  *
01900  * SEE ALSO
01901  *  CoMarshalInterface(), CoUnmarshalInterface().
01902  */
01903 HRESULT WINAPI CoReleaseMarshalData(IStream *pStream)
01904 {
01905     HRESULT hr;
01906     LPMARSHAL pMarshal;
01907 
01908     TRACE("(%p)\n", pStream);
01909 
01910     hr = get_unmarshaler_from_stream(pStream, &pMarshal, NULL);
01911     if (hr != S_OK)
01912         return hr;
01913 
01914     /* call the helper object to do the releasing of marshal data */
01915     hr = IMarshal_ReleaseMarshalData(pMarshal, pStream);
01916     if (hr != S_OK)
01917         ERR("IMarshal::ReleaseMarshalData failed with error 0x%08x\n", hr);
01918 
01919     IMarshal_Release(pMarshal);
01920     return hr;
01921 }
01922 
01923 
01924 /***********************************************************************
01925  *      CoMarshalInterThreadInterfaceInStream   [OLE32.@]
01926  *
01927  * Marshal an interface across threads in the same process.
01928  *
01929  * PARAMS
01930  *  riid  [I] Identifier of the interface to be marshalled.
01931  *  pUnk  [I] Pointer to IUnknown-derived interface that will be marshalled.
01932  *  ppStm [O] Pointer to IStream object that is created and then used to store the marshalled interface.
01933  *
01934  * RETURNS
01935  *  Success: S_OK
01936  *  Failure: E_OUTOFMEMORY and other COM error codes
01937  *
01938  * SEE ALSO
01939  *   CoMarshalInterface(), CoUnmarshalInterface() and CoGetInterfaceAndReleaseStream()
01940  */
01941 HRESULT WINAPI CoMarshalInterThreadInterfaceInStream(
01942     REFIID riid, LPUNKNOWN pUnk, LPSTREAM * ppStm)
01943 {
01944     ULARGE_INTEGER  xpos;
01945     LARGE_INTEGER       seekto;
01946     HRESULT     hres;
01947 
01948     TRACE("(%s, %p, %p)\n",debugstr_guid(riid), pUnk, ppStm);
01949 
01950     hres = CreateStreamOnHGlobal(NULL, TRUE, ppStm);
01951     if (FAILED(hres)) return hres;
01952     hres = CoMarshalInterface(*ppStm, riid, pUnk, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
01953 
01954     if (SUCCEEDED(hres))
01955     {
01956         memset(&seekto, 0, sizeof(seekto));
01957         IStream_Seek(*ppStm, seekto, STREAM_SEEK_SET, &xpos);
01958     }
01959     else
01960     {
01961         IStream_Release(*ppStm);
01962         *ppStm = NULL;
01963     }
01964 
01965     return hres;
01966 }
01967 
01968 /***********************************************************************
01969  *      CoGetInterfaceAndReleaseStream  [OLE32.@]
01970  *
01971  * Unmarshalls an interface from a stream and then releases the stream.
01972  *
01973  * PARAMS
01974  *  pStm [I] Stream that contains the marshalled interface.
01975  *  riid [I] Interface identifier of the object to unmarshall.
01976  *  ppv  [O] Address of pointer where the requested interface object will be stored.
01977  *
01978  * RETURNS
01979  *  Success: S_OK
01980  *  Failure: A COM error code
01981  *
01982  * SEE ALSO
01983  *  CoMarshalInterThreadInterfaceInStream() and CoUnmarshalInterface()
01984  */
01985 HRESULT WINAPI CoGetInterfaceAndReleaseStream(LPSTREAM pStm, REFIID riid,
01986                                               LPVOID *ppv)
01987 {
01988     HRESULT hres;
01989 
01990     TRACE("(%p, %s, %p)\n", pStm, debugstr_guid(riid), ppv);
01991 
01992     if(!pStm) return E_INVALIDARG;
01993     hres = CoUnmarshalInterface(pStm, riid, ppv);
01994     IStream_Release(pStm);
01995     return hres;
01996 }
01997 
01998 static HRESULT WINAPI StdMarshalCF_QueryInterface(LPCLASSFACTORY iface,
01999                                                   REFIID riid, LPVOID *ppv)
02000 {
02001     *ppv = NULL;
02002     if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IClassFactory))
02003     {
02004         *ppv = iface;
02005         return S_OK;
02006     }
02007     return E_NOINTERFACE;
02008 }
02009 
02010 static ULONG WINAPI StdMarshalCF_AddRef(LPCLASSFACTORY iface)
02011 {
02012     return 2; /* non-heap based object */
02013 }
02014 
02015 static ULONG WINAPI StdMarshalCF_Release(LPCLASSFACTORY iface)
02016 {
02017     return 1; /* non-heap based object */
02018 }
02019 
02020 static HRESULT WINAPI StdMarshalCF_CreateInstance(LPCLASSFACTORY iface,
02021     LPUNKNOWN pUnk, REFIID riid, LPVOID *ppv)
02022 {
02023     if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IMarshal))
02024         return StdMarshalImpl_Construct(riid, ppv);
02025 
02026     FIXME("(%s), not supported.\n",debugstr_guid(riid));
02027     return E_NOINTERFACE;
02028 }
02029 
02030 static HRESULT WINAPI StdMarshalCF_LockServer(LPCLASSFACTORY iface, BOOL fLock)
02031 {
02032     FIXME("(%d), stub!\n",fLock);
02033     return S_OK;
02034 }
02035 
02036 static const IClassFactoryVtbl StdMarshalCFVtbl =
02037 {
02038     StdMarshalCF_QueryInterface,
02039     StdMarshalCF_AddRef,
02040     StdMarshalCF_Release,
02041     StdMarshalCF_CreateInstance,
02042     StdMarshalCF_LockServer
02043 };
02044 static const IClassFactoryVtbl *StdMarshalCF = &StdMarshalCFVtbl;
02045 
02046 HRESULT MARSHAL_GetStandardMarshalCF(LPVOID *ppv)
02047 {
02048     *ppv = &StdMarshalCF;
02049     return S_OK;
02050 }
02051 
02052 /***********************************************************************
02053  *      CoMarshalHresult    [OLE32.@]
02054  *
02055  * Marshals an HRESULT value into a stream.
02056  *
02057  * PARAMS
02058  *  pStm    [I] Stream that hresult will be marshalled into.
02059  *  hresult [I] HRESULT to be marshalled.
02060  *
02061  * RETURNS
02062  *  Success: S_OK
02063  *  Failure: A COM error code
02064  *
02065  * SEE ALSO
02066  *  CoUnmarshalHresult().
02067  */
02068 HRESULT WINAPI CoMarshalHresult(LPSTREAM pStm, HRESULT hresult)
02069 {
02070     return IStream_Write(pStm, &hresult, sizeof(hresult), NULL);
02071 }
02072 
02073 /***********************************************************************
02074  *      CoUnmarshalHresult  [OLE32.@]
02075  *
02076  * Unmarshals an HRESULT value from a stream.
02077  *
02078  * PARAMS
02079  *  pStm     [I] Stream that hresult will be unmarshalled from.
02080  *  phresult [I] Pointer to HRESULT where the value will be unmarshalled to.
02081  *
02082  * RETURNS
02083  *  Success: S_OK
02084  *  Failure: A COM error code
02085  *
02086  * SEE ALSO
02087  *  CoMarshalHresult().
02088  */
02089 HRESULT WINAPI CoUnmarshalHresult(LPSTREAM pStm, HRESULT * phresult)
02090 {
02091     return IStream_Read(pStm, phresult, sizeof(*phresult), NULL);
02092 }

Generated on Sat May 26 2012 04:24:10 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.