xref: /reactos/dll/win32/ole32/marshal.c (revision 845faec4)
1 /*
2  *	Marshalling library
3  *
4  * Copyright 2002 Marcus Meissner
5  * Copyright 2004 Mike Hearn, for CodeWeavers
6  * Copyright 2004 Rob Shearman, for CodeWeavers
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22 
23 #include <stdarg.h>
24 #include <string.h>
25 #include <assert.h>
26 
27 #define COBJMACROS
28 
29 #include "windef.h"
30 #include "winbase.h"
31 #include "winuser.h"
32 #include "objbase.h"
33 #include "ole2.h"
34 #include "winerror.h"
35 #include "wine/unicode.h"
36 
37 #include "compobj_private.h"
38 
39 #include "wine/debug.h"
40 
41 WINE_DEFAULT_DEBUG_CHANNEL(ole);
42 
43 extern const CLSID CLSID_DfMarshal;
44 
45 /* number of refs given out for normal marshaling */
46 #define NORMALEXTREFS 5
47 
48 
49 /* private flag indicating that the object was marshaled as table-weak */
50 #define SORFP_TABLEWEAK SORF_OXRES1
51 /* private flag indicating that the caller does not want to notify the stub
52  * when the proxy disconnects or is destroyed */
53 #define SORFP_NOLIFETIMEMGMT SORF_OXRES2
54 
55 /* imported object / proxy manager */
56 struct proxy_manager
57 {
58   IMultiQI IMultiQI_iface;
59   IMarshal IMarshal_iface;
60   IClientSecurity IClientSecurity_iface;
61   struct apartment *parent; /* owning apartment (RO) */
62   struct list entry;        /* entry in apartment (CS parent->cs) */
63   OXID oxid;                /* object exported ID (RO) */
64   OXID_INFO oxid_info;      /* string binding, ipid of rem unknown and other information (RO) */
65   OID oid;                  /* object ID (RO) */
66   struct list interfaces;   /* imported interfaces (CS cs) */
67   LONG refs;                /* proxy reference count (LOCK) */
68   CRITICAL_SECTION cs;      /* thread safety for this object and children */
69   ULONG sorflags;           /* STDOBJREF flags (RO) */
70   IRemUnknown *remunk;      /* proxy to IRemUnknown used for lifecycle management (CS cs) */
71   HANDLE remoting_mutex;    /* mutex used for synchronizing access to IRemUnknown */
72   MSHCTX dest_context;      /* context used for activating optimisations (LOCK) */
73   void *dest_context_data;  /* reserved context value (LOCK) */
74 };
75 
76 static inline struct proxy_manager *impl_from_IMultiQI( IMultiQI *iface )
77 {
78     return CONTAINING_RECORD(iface, struct proxy_manager, IMultiQI_iface);
79 }
80 
81 static inline struct proxy_manager *impl_from_IMarshal( IMarshal *iface )
82 {
83     return CONTAINING_RECORD(iface, struct proxy_manager, IMarshal_iface);
84 }
85 
86 static inline struct proxy_manager *impl_from_IClientSecurity( IClientSecurity *iface )
87 {
88     return CONTAINING_RECORD(iface, struct proxy_manager, IClientSecurity_iface);
89 }
90 
91 static HRESULT unmarshal_object(const STDOBJREF *stdobjref, APARTMENT *apt,
92                                 MSHCTX dest_context, void *dest_context_data,
93                                 REFIID riid, const OXID_INFO *oxid_info,
94                                 void **object);
95 
96 /* Marshalling just passes a unique identifier to the remote client,
97  * that makes it possible to find the passed interface again.
98  *
99  * So basically we need a set of values that make it unique.
100  *
101  * Note that the IUnknown_QI(ob,xiid,&ppv) always returns the SAME ppv value!
102  *
103  * A triple is used: OXID (apt id), OID (stub manager id),
104  * IPID (interface ptr/stub id).
105  *
106  * OXIDs identify an apartment and are network scoped
107  * OIDs identify a stub manager and are apartment scoped
108  * IPIDs identify an interface stub and are apartment scoped
109  */
110 
111 static inline HRESULT get_facbuf_for_iid(REFIID riid, IPSFactoryBuffer **facbuf)
112 {
113     HRESULT       hr;
114     CLSID         clsid;
115 
116     hr = CoGetPSClsid(riid, &clsid);
117     if (hr != S_OK)
118         return hr;
119     return CoGetClassObject(&clsid, CLSCTX_INPROC_SERVER | WINE_CLSCTX_DONT_HOST,
120         NULL, &IID_IPSFactoryBuffer, (LPVOID*)facbuf);
121 }
122 
123 /* marshals an object into a STDOBJREF structure */
124 HRESULT marshal_object(APARTMENT *apt, STDOBJREF *stdobjref, REFIID riid, IUnknown *object,
125     DWORD dest_context, void *dest_context_data, MSHLFLAGS mshlflags)
126 {
127     struct stub_manager *manager;
128     struct ifstub       *ifstub;
129     BOOL                 tablemarshal;
130     HRESULT              hr;
131 
132     hr = apartment_getoxid(apt, &stdobjref->oxid);
133     if (hr != S_OK)
134         return hr;
135 
136     hr = apartment_createwindowifneeded(apt);
137     if (hr != S_OK)
138         return hr;
139 
140     if (!(manager = get_stub_manager_from_object(apt, object, TRUE)))
141         return E_OUTOFMEMORY;
142 
143     stdobjref->flags = SORF_NULL;
144     if (mshlflags & MSHLFLAGS_TABLEWEAK)
145         stdobjref->flags |= SORFP_TABLEWEAK;
146     if (mshlflags & MSHLFLAGS_NOPING)
147         stdobjref->flags |= SORF_NOPING;
148     stdobjref->oid = manager->oid;
149 
150     tablemarshal = ((mshlflags & MSHLFLAGS_TABLESTRONG) || (mshlflags & MSHLFLAGS_TABLEWEAK));
151 
152     /* make sure ifstub that we are creating is unique */
153     ifstub = stub_manager_find_ifstub(manager, riid, mshlflags);
154     if (!ifstub) {
155         IRpcStubBuffer *stub = NULL;
156 
157         /* IUnknown doesn't require a stub buffer, because it never goes out on
158          * the wire */
159         if (!IsEqualIID(riid, &IID_IUnknown))
160         {
161             IPSFactoryBuffer *psfb;
162 
163             hr = get_facbuf_for_iid(riid, &psfb);
164             if (hr == S_OK) {
165                 hr = IPSFactoryBuffer_CreateStub(psfb, riid, manager->object, &stub);
166                 IPSFactoryBuffer_Release(psfb);
167                 if (hr != S_OK)
168                     ERR("Failed to create an IRpcStubBuffer from IPSFactory for %s with error 0x%08x\n",
169                         debugstr_guid(riid), hr);
170             }else {
171                 ERR("couldn't get IPSFactory buffer for interface %s\n", debugstr_guid(riid));
172                 hr = E_NOINTERFACE;
173             }
174 
175         }
176 
177         if (hr == S_OK) {
178             ifstub = stub_manager_new_ifstub(manager, stub, riid, dest_context, dest_context_data, mshlflags);
179             if (!ifstub)
180                 hr = E_OUTOFMEMORY;
181         }
182         if (stub) IRpcStubBuffer_Release(stub);
183 
184         if (hr != S_OK) {
185             stub_manager_int_release(manager);
186             /* destroy the stub manager if it has no ifstubs by releasing
187              * zero external references */
188             stub_manager_ext_release(manager, 0, FALSE, TRUE);
189             return hr;
190         }
191     }
192 
193     if (!tablemarshal)
194     {
195         stdobjref->cPublicRefs = NORMALEXTREFS;
196         stub_manager_ext_addref(manager, stdobjref->cPublicRefs, FALSE);
197     }
198     else
199     {
200         stdobjref->cPublicRefs = 0;
201         if (mshlflags & MSHLFLAGS_TABLESTRONG)
202             stub_manager_ext_addref(manager, 1, FALSE);
203         else
204             stub_manager_ext_addref(manager, 0, TRUE);
205     }
206 
207     /* FIXME: check return value */
208     RPC_RegisterInterface(riid);
209 
210     stdobjref->ipid = ifstub->ipid;
211 
212     stub_manager_int_release(manager);
213     return S_OK;
214 }
215 
216 
217 
218 /* Client-side identity of the server object */
219 
220 static HRESULT proxy_manager_get_remunknown(struct proxy_manager * This, IRemUnknown **remunk);
221 static void proxy_manager_destroy(struct proxy_manager * This);
222 static HRESULT proxy_manager_find_ifproxy(struct proxy_manager * This, REFIID riid, struct ifproxy ** ifproxy_found);
223 static HRESULT proxy_manager_query_local_interface(struct proxy_manager * This, REFIID riid, void ** ppv);
224 
225 static HRESULT WINAPI ClientIdentity_QueryInterface(IMultiQI * iface, REFIID riid, void ** ppv)
226 {
227     HRESULT hr;
228     MULTI_QI mqi;
229 
230     TRACE("%s\n", debugstr_guid(riid));
231 
232     mqi.pIID = riid;
233     hr = IMultiQI_QueryMultipleInterfaces(iface, 1, &mqi);
234     *ppv = mqi.pItf;
235 
236     return hr;
237 }
238 
239 static ULONG WINAPI ClientIdentity_AddRef(IMultiQI *iface)
240 {
241     struct proxy_manager *This = impl_from_IMultiQI(iface);
242     TRACE("%p - before %d\n", iface, This->refs);
243     return InterlockedIncrement(&This->refs);
244 }
245 
246 static ULONG WINAPI ClientIdentity_Release(IMultiQI *iface)
247 {
248     struct proxy_manager *This = impl_from_IMultiQI(iface);
249     ULONG refs = InterlockedDecrement(&This->refs);
250     TRACE("%p - after %d\n", iface, refs);
251     if (!refs)
252         proxy_manager_destroy(This);
253     return refs;
254 }
255 
256 static HRESULT WINAPI ClientIdentity_QueryMultipleInterfaces(IMultiQI *iface, ULONG cMQIs, MULTI_QI *pMQIs)
257 {
258     struct proxy_manager *This = impl_from_IMultiQI(iface);
259     REMQIRESULT *qiresults = NULL;
260     ULONG nonlocal_mqis = 0;
261     ULONG i;
262     ULONG successful_mqis = 0;
263     IID *iids = HeapAlloc(GetProcessHeap(), 0, cMQIs * sizeof(*iids));
264     /* mapping of RemQueryInterface index to QueryMultipleInterfaces index */
265     ULONG *mapping = HeapAlloc(GetProcessHeap(), 0, cMQIs * sizeof(*mapping));
266 
267     TRACE("cMQIs: %d\n", cMQIs);
268 
269     /* try to get a local interface - this includes already active proxy
270      * interfaces and also interfaces exposed by the proxy manager */
271     for (i = 0; i < cMQIs; i++)
272     {
273         TRACE("iid[%d] = %s\n", i, debugstr_guid(pMQIs[i].pIID));
274         pMQIs[i].hr = proxy_manager_query_local_interface(This, pMQIs[i].pIID, (void **)&pMQIs[i].pItf);
275         if (pMQIs[i].hr == S_OK)
276             successful_mqis++;
277         else
278         {
279             iids[nonlocal_mqis] = *pMQIs[i].pIID;
280             mapping[nonlocal_mqis] = i;
281             nonlocal_mqis++;
282         }
283     }
284 
285     TRACE("%d interfaces not found locally\n", nonlocal_mqis);
286 
287     /* if we have more than one interface not found locally then we must try
288      * to query the remote object for it */
289     if (nonlocal_mqis != 0)
290     {
291         IRemUnknown *remunk;
292         HRESULT hr;
293         IPID *ipid;
294 
295         /* get the ipid of the first entry */
296         /* FIXME: should we implement ClientIdentity on the ifproxies instead
297          * of the proxy_manager so we use the correct ipid here? */
298         ipid = &LIST_ENTRY(list_head(&This->interfaces), struct ifproxy, entry)->stdobjref.ipid;
299 
300         /* get IRemUnknown proxy so we can communicate with the remote object */
301         hr = proxy_manager_get_remunknown(This, &remunk);
302 
303         if (SUCCEEDED(hr))
304         {
305             hr = IRemUnknown_RemQueryInterface(remunk, ipid, NORMALEXTREFS,
306                                                nonlocal_mqis, iids, &qiresults);
307             IRemUnknown_Release(remunk);
308             if (FAILED(hr))
309                 ERR("IRemUnknown_RemQueryInterface failed with error 0x%08x\n", hr);
310         }
311 
312         /* IRemUnknown_RemQueryInterface can return S_FALSE if only some of
313          * the interfaces were returned */
314         if (SUCCEEDED(hr))
315         {
316             /* try to unmarshal each object returned to us */
317             for (i = 0; i < nonlocal_mqis; i++)
318             {
319                 ULONG index = mapping[i];
320                 HRESULT hrobj = qiresults[i].hResult;
321                 if (hrobj == S_OK)
322                     hrobj = unmarshal_object(&qiresults[i].std, COM_CurrentApt(),
323                                              This->dest_context,
324                                              This->dest_context_data,
325                                              pMQIs[index].pIID, &This->oxid_info,
326                                              (void **)&pMQIs[index].pItf);
327 
328                 if (hrobj == S_OK)
329                     successful_mqis++;
330                 else
331                     ERR("Failed to get pointer to interface %s\n", debugstr_guid(pMQIs[index].pIID));
332                 pMQIs[index].hr = hrobj;
333             }
334         }
335 
336         /* free the memory allocated by the proxy */
337         CoTaskMemFree(qiresults);
338     }
339 
340     TRACE("%d/%d successfully queried\n", successful_mqis, cMQIs);
341 
342     HeapFree(GetProcessHeap(), 0, iids);
343     HeapFree(GetProcessHeap(), 0, mapping);
344 
345     if (successful_mqis == cMQIs)
346         return S_OK; /* we got all requested interfaces */
347     else if (successful_mqis == 0)
348         return E_NOINTERFACE; /* we didn't get any interfaces */
349     else
350         return S_FALSE; /* we got some interfaces */
351 }
352 
353 static const IMultiQIVtbl ClientIdentity_Vtbl =
354 {
355     ClientIdentity_QueryInterface,
356     ClientIdentity_AddRef,
357     ClientIdentity_Release,
358     ClientIdentity_QueryMultipleInterfaces
359 };
360 
361 /* FIXME: remove these */
362 static HRESULT WINAPI StdMarshalImpl_GetUnmarshalClass(LPMARSHAL iface, REFIID riid, void* pv, DWORD dwDestContext, void* pvDestContext, DWORD mshlflags, CLSID* pCid);
363 static HRESULT WINAPI StdMarshalImpl_GetMarshalSizeMax(LPMARSHAL iface, REFIID riid, void* pv, DWORD dwDestContext, void* pvDestContext, DWORD mshlflags, DWORD* pSize);
364 static HRESULT WINAPI StdMarshalImpl_UnmarshalInterface(LPMARSHAL iface, IStream *pStm, REFIID riid, void **ppv);
365 static HRESULT WINAPI StdMarshalImpl_ReleaseMarshalData(LPMARSHAL iface, IStream *pStm);
366 static HRESULT WINAPI StdMarshalImpl_DisconnectObject(LPMARSHAL iface, DWORD dwReserved);
367 
368 static HRESULT WINAPI Proxy_QueryInterface(IMarshal *iface, REFIID riid, void **ppvObject)
369 {
370     struct proxy_manager *This = impl_from_IMarshal( iface );
371     return IMultiQI_QueryInterface(&This->IMultiQI_iface, riid, ppvObject);
372 }
373 
374 static ULONG WINAPI Proxy_AddRef(IMarshal *iface)
375 {
376     struct proxy_manager *This = impl_from_IMarshal( iface );
377     return IMultiQI_AddRef(&This->IMultiQI_iface);
378 }
379 
380 static ULONG WINAPI Proxy_Release(IMarshal *iface)
381 {
382     struct proxy_manager *This = impl_from_IMarshal( iface );
383     return IMultiQI_Release(&This->IMultiQI_iface);
384 }
385 
386 static HRESULT WINAPI Proxy_MarshalInterface(
387     LPMARSHAL iface, IStream *pStm, REFIID riid, void* pv, DWORD dwDestContext,
388     void* pvDestContext, DWORD mshlflags)
389 {
390     struct proxy_manager *This = impl_from_IMarshal( iface );
391     HRESULT hr;
392     struct ifproxy *ifproxy;
393 
394     TRACE("(...,%s,...)\n", debugstr_guid(riid));
395 
396     hr = proxy_manager_find_ifproxy(This, riid, &ifproxy);
397     if (SUCCEEDED(hr))
398     {
399         STDOBJREF stdobjref = ifproxy->stdobjref;
400 
401         stdobjref.cPublicRefs = 0;
402 
403         if ((mshlflags != MSHLFLAGS_TABLEWEAK) &&
404             (mshlflags != MSHLFLAGS_TABLESTRONG))
405         {
406             ULONG cPublicRefs = ifproxy->refs;
407             ULONG cPublicRefsOld;
408             /* optimization - share out proxy's public references if possible
409              * instead of making new proxy do a roundtrip through the server */
410             do
411             {
412                 ULONG cPublicRefsNew;
413                 cPublicRefsOld = cPublicRefs;
414                 stdobjref.cPublicRefs = cPublicRefs / 2;
415                 cPublicRefsNew = cPublicRefs - stdobjref.cPublicRefs;
416                 cPublicRefs = InterlockedCompareExchange(
417                     (LONG *)&ifproxy->refs, cPublicRefsNew, cPublicRefsOld);
418             } while (cPublicRefs != cPublicRefsOld);
419         }
420 
421         /* normal and table-strong marshaling need at least one reference */
422         if (!stdobjref.cPublicRefs && (mshlflags != MSHLFLAGS_TABLEWEAK))
423         {
424             IRemUnknown *remunk;
425             hr = proxy_manager_get_remunknown(This, &remunk);
426             if (hr == S_OK)
427             {
428                 HRESULT hrref = S_OK;
429                 REMINTERFACEREF rif;
430                 rif.ipid = ifproxy->stdobjref.ipid;
431                 rif.cPublicRefs = (mshlflags == MSHLFLAGS_TABLESTRONG) ? 1 : NORMALEXTREFS;
432                 rif.cPrivateRefs = 0;
433                 hr = IRemUnknown_RemAddRef(remunk, 1, &rif, &hrref);
434                 IRemUnknown_Release(remunk);
435                 if (hr == S_OK && hrref == S_OK)
436                 {
437                     /* table-strong marshaling doesn't give the refs to the
438                      * client that unmarshals the STDOBJREF */
439                     if (mshlflags != MSHLFLAGS_TABLESTRONG)
440                         stdobjref.cPublicRefs = rif.cPublicRefs;
441                 }
442                 else
443                     ERR("IRemUnknown_RemAddRef returned with 0x%08x, hrref = 0x%08x\n", hr, hrref);
444             }
445         }
446 
447         if (SUCCEEDED(hr))
448         {
449             TRACE("writing stdobjref: flags = %04x cPublicRefs = %d oxid = %s oid = %s ipid = %s\n",
450                 stdobjref.flags, stdobjref.cPublicRefs,
451                 wine_dbgstr_longlong(stdobjref.oxid),
452                 wine_dbgstr_longlong(stdobjref.oid),
453                 debugstr_guid(&stdobjref.ipid));
454             hr = IStream_Write(pStm, &stdobjref, sizeof(stdobjref), NULL);
455         }
456     }
457     else
458     {
459         /* we don't have the interface already unmarshaled so we have to
460          * request the object from the server */
461         IRemUnknown *remunk;
462         IPID *ipid;
463         REMQIRESULT *qiresults = NULL;
464         IID iid = *riid;
465 
466         /* get the ipid of the first entry */
467         /* FIXME: should we implement ClientIdentity on the ifproxies instead
468          * of the proxy_manager so we use the correct ipid here? */
469         ipid = &LIST_ENTRY(list_head(&This->interfaces), struct ifproxy, entry)->stdobjref.ipid;
470 
471         /* get IRemUnknown proxy so we can communicate with the remote object */
472         hr = proxy_manager_get_remunknown(This, &remunk);
473 
474         if (hr == S_OK)
475         {
476             hr = IRemUnknown_RemQueryInterface(remunk, ipid, NORMALEXTREFS,
477                                                1, &iid, &qiresults);
478             if (SUCCEEDED(hr))
479             {
480                 hr = IStream_Write(pStm, &qiresults->std, sizeof(qiresults->std), NULL);
481                 if (FAILED(hr))
482                 {
483                     REMINTERFACEREF rif;
484                     rif.ipid = qiresults->std.ipid;
485                     rif.cPublicRefs = qiresults->std.cPublicRefs;
486                     rif.cPrivateRefs = 0;
487                     IRemUnknown_RemRelease(remunk, 1, &rif);
488                 }
489                 CoTaskMemFree(qiresults);
490             }
491             else
492                 ERR("IRemUnknown_RemQueryInterface failed with error 0x%08x\n", hr);
493             IRemUnknown_Release(remunk);
494         }
495     }
496 
497     return hr;
498 }
499 
500 static const IMarshalVtbl ProxyMarshal_Vtbl =
501 {
502     Proxy_QueryInterface,
503     Proxy_AddRef,
504     Proxy_Release,
505     StdMarshalImpl_GetUnmarshalClass,
506     StdMarshalImpl_GetMarshalSizeMax,
507     Proxy_MarshalInterface,
508     StdMarshalImpl_UnmarshalInterface,
509     StdMarshalImpl_ReleaseMarshalData,
510     StdMarshalImpl_DisconnectObject
511 };
512 
513 static HRESULT WINAPI ProxyCliSec_QueryInterface(IClientSecurity *iface, REFIID riid, void **ppvObject)
514 {
515     struct proxy_manager *This = impl_from_IClientSecurity( iface );
516     return IMultiQI_QueryInterface(&This->IMultiQI_iface, riid, ppvObject);
517 }
518 
519 static ULONG WINAPI ProxyCliSec_AddRef(IClientSecurity *iface)
520 {
521     struct proxy_manager *This = impl_from_IClientSecurity( iface );
522     return IMultiQI_AddRef(&This->IMultiQI_iface);
523 }
524 
525 static ULONG WINAPI ProxyCliSec_Release(IClientSecurity *iface)
526 {
527     struct proxy_manager *This = impl_from_IClientSecurity( iface );
528     return IMultiQI_Release(&This->IMultiQI_iface);
529 }
530 
531 static HRESULT WINAPI ProxyCliSec_QueryBlanket(IClientSecurity *iface,
532                                                IUnknown *pProxy,
533                                                DWORD *pAuthnSvc,
534                                                DWORD *pAuthzSvc,
535                                                OLECHAR **ppServerPrincName,
536                                                DWORD *pAuthnLevel,
537                                                DWORD *pImpLevel,
538                                                void **pAuthInfo,
539                                                DWORD *pCapabilities)
540 {
541     FIXME("(%p, %p, %p, %p, %p, %p, %p, %p): stub\n", pProxy, pAuthnSvc,
542           pAuthzSvc, ppServerPrincName, pAuthnLevel, pImpLevel, pAuthInfo,
543           pCapabilities);
544 
545     if (pAuthnSvc)
546         *pAuthnSvc = 0;
547     if (pAuthzSvc)
548         *pAuthzSvc = 0;
549     if (ppServerPrincName)
550         *ppServerPrincName = NULL;
551     if (pAuthnLevel)
552         *pAuthnLevel = RPC_C_AUTHN_LEVEL_DEFAULT;
553     if (pImpLevel)
554         *pImpLevel = RPC_C_IMP_LEVEL_DEFAULT;
555     if (pAuthInfo)
556         *pAuthInfo = NULL;
557     if (pCapabilities)
558         *pCapabilities = EOAC_NONE;
559 
560     return E_NOTIMPL;
561 }
562 
563 static HRESULT WINAPI ProxyCliSec_SetBlanket(IClientSecurity *iface,
564                                              IUnknown *pProxy, DWORD AuthnSvc,
565                                              DWORD AuthzSvc,
566                                              OLECHAR *pServerPrincName,
567                                              DWORD AuthnLevel, DWORD ImpLevel,
568                                              void *pAuthInfo,
569                                              DWORD Capabilities)
570 {
571     FIXME("(%p, %d, %d, %s, %d, %d, %p, 0x%x): stub\n", pProxy, AuthnSvc, AuthzSvc,
572           pServerPrincName == COLE_DEFAULT_PRINCIPAL ? "<default principal>" : debugstr_w(pServerPrincName),
573           AuthnLevel, ImpLevel, pAuthInfo, Capabilities);
574     return E_NOTIMPL;
575 }
576 
577 static HRESULT WINAPI ProxyCliSec_CopyProxy(IClientSecurity *iface,
578                                             IUnknown *pProxy, IUnknown **ppCopy)
579 {
580     FIXME("(%p, %p): stub\n", pProxy, ppCopy);
581     *ppCopy = NULL;
582     return E_NOTIMPL;
583 }
584 
585 static const IClientSecurityVtbl ProxyCliSec_Vtbl =
586 {
587     ProxyCliSec_QueryInterface,
588     ProxyCliSec_AddRef,
589     ProxyCliSec_Release,
590     ProxyCliSec_QueryBlanket,
591     ProxyCliSec_SetBlanket,
592     ProxyCliSec_CopyProxy
593 };
594 
595 static HRESULT ifproxy_get_public_ref(struct ifproxy * This)
596 {
597     HRESULT hr = S_OK;
598 
599     if (WAIT_OBJECT_0 != WaitForSingleObject(This->parent->remoting_mutex, INFINITE))
600     {
601         ERR("Wait failed for ifproxy %p\n", This);
602         return E_UNEXPECTED;
603     }
604 
605     if (This->refs == 0)
606     {
607         IRemUnknown *remunk = NULL;
608 
609         TRACE("getting public ref for ifproxy %p\n", This);
610 
611         hr = proxy_manager_get_remunknown(This->parent, &remunk);
612         if (hr == S_OK)
613         {
614             HRESULT hrref = S_OK;
615             REMINTERFACEREF rif;
616             rif.ipid = This->stdobjref.ipid;
617             rif.cPublicRefs = NORMALEXTREFS;
618             rif.cPrivateRefs = 0;
619             hr = IRemUnknown_RemAddRef(remunk, 1, &rif, &hrref);
620             IRemUnknown_Release(remunk);
621             if (hr == S_OK && hrref == S_OK)
622                 InterlockedExchangeAdd((LONG *)&This->refs, NORMALEXTREFS);
623             else
624                 ERR("IRemUnknown_RemAddRef returned with 0x%08x, hrref = 0x%08x\n", hr, hrref);
625         }
626     }
627     ReleaseMutex(This->parent->remoting_mutex);
628 
629     return hr;
630 }
631 
632 static HRESULT ifproxy_release_public_refs(struct ifproxy * This)
633 {
634     HRESULT hr = S_OK;
635     LONG public_refs;
636 
637     if (WAIT_OBJECT_0 != WaitForSingleObject(This->parent->remoting_mutex, INFINITE))
638     {
639         ERR("Wait failed for ifproxy %p\n", This);
640         return E_UNEXPECTED;
641     }
642 
643     public_refs = This->refs;
644     if (public_refs > 0)
645     {
646         IRemUnknown *remunk = NULL;
647 
648         TRACE("releasing %d refs\n", public_refs);
649 
650         hr = proxy_manager_get_remunknown(This->parent, &remunk);
651         if (hr == S_OK)
652         {
653             REMINTERFACEREF rif;
654             rif.ipid = This->stdobjref.ipid;
655             rif.cPublicRefs = public_refs;
656             rif.cPrivateRefs = 0;
657             hr = IRemUnknown_RemRelease(remunk, 1, &rif);
658             IRemUnknown_Release(remunk);
659             if (hr == S_OK)
660                 InterlockedExchangeAdd((LONG *)&This->refs, -public_refs);
661             else if (hr == RPC_E_DISCONNECTED)
662                 WARN("couldn't release references because object was "
663                      "disconnected: oxid = %s, oid = %s\n",
664                      wine_dbgstr_longlong(This->parent->oxid),
665                      wine_dbgstr_longlong(This->parent->oid));
666             else
667                 ERR("IRemUnknown_RemRelease failed with error 0x%08x\n", hr);
668         }
669     }
670     ReleaseMutex(This->parent->remoting_mutex);
671 
672     return hr;
673 }
674 
675 /* should be called inside This->parent->cs critical section */
676 static void ifproxy_disconnect(struct ifproxy * This)
677 {
678     ifproxy_release_public_refs(This);
679     if (This->proxy) IRpcProxyBuffer_Disconnect(This->proxy);
680 
681     IRpcChannelBuffer_Release(This->chan);
682     This->chan = NULL;
683 }
684 
685 /* should be called in This->parent->cs critical section if it is an entry in parent's list */
686 static void ifproxy_destroy(struct ifproxy * This)
687 {
688     TRACE("%p\n", This);
689 
690     /* release public references to this object so that the stub can know
691      * when to destroy itself */
692     ifproxy_release_public_refs(This);
693 
694     list_remove(&This->entry);
695 
696     if (This->chan)
697     {
698         IRpcChannelBuffer_Release(This->chan);
699         This->chan = NULL;
700     }
701 
702     if (This->proxy) IRpcProxyBuffer_Release(This->proxy);
703 
704     HeapFree(GetProcessHeap(), 0, This);
705 }
706 
707 static HRESULT proxy_manager_construct(
708     APARTMENT * apt, ULONG sorflags, OXID oxid, OID oid,
709     const OXID_INFO *oxid_info, struct proxy_manager ** proxy_manager)
710 {
711     struct proxy_manager * This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
712     if (!This) return E_OUTOFMEMORY;
713 
714     This->remoting_mutex = CreateMutexW(NULL, FALSE, NULL);
715     if (!This->remoting_mutex)
716     {
717         HeapFree(GetProcessHeap(), 0, This);
718         return HRESULT_FROM_WIN32(GetLastError());
719     }
720 
721     if (oxid_info)
722     {
723         This->oxid_info.dwPid = oxid_info->dwPid;
724         This->oxid_info.dwTid = oxid_info->dwTid;
725         This->oxid_info.ipidRemUnknown = oxid_info->ipidRemUnknown;
726         This->oxid_info.dwAuthnHint = oxid_info->dwAuthnHint;
727         This->oxid_info.psa = NULL /* FIXME: copy from oxid_info */;
728     }
729     else
730     {
731         HRESULT hr = RPC_ResolveOxid(oxid, &This->oxid_info);
732         if (FAILED(hr))
733         {
734             CloseHandle(This->remoting_mutex);
735             HeapFree(GetProcessHeap(), 0, This);
736             return hr;
737         }
738     }
739 
740     This->IMultiQI_iface.lpVtbl = &ClientIdentity_Vtbl;
741     This->IMarshal_iface.lpVtbl = &ProxyMarshal_Vtbl;
742     This->IClientSecurity_iface.lpVtbl = &ProxyCliSec_Vtbl;
743 
744     list_init(&This->entry);
745     list_init(&This->interfaces);
746 
747     InitializeCriticalSection(&This->cs);
748     DEBUG_SET_CRITSEC_NAME(&This->cs, "proxy_manager");
749 
750     /* the apartment the object was unmarshaled into */
751     This->parent = apt;
752 
753     /* the source apartment and id of the object */
754     This->oxid = oxid;
755     This->oid = oid;
756 
757     This->refs = 1;
758 
759     /* the DCOM draft specification states that the SORF_NOPING flag is
760      * proxy manager specific, not ifproxy specific, so this implies that we
761      * should store the STDOBJREF flags here in the proxy manager. */
762     This->sorflags = sorflags;
763 
764     /* we create the IRemUnknown proxy on demand */
765     This->remunk = NULL;
766 
767     /* initialise these values to the weakest values and they will be
768      * overwritten in proxy_manager_set_context */
769     This->dest_context = MSHCTX_INPROC;
770     This->dest_context_data = NULL;
771 
772     EnterCriticalSection(&apt->cs);
773     /* FIXME: we are dependent on the ordering in here to make sure a proxy's
774      * IRemUnknown proxy doesn't get destroyed before the regular proxy does
775      * because we need the IRemUnknown proxy during the destruction of the
776      * regular proxy. Ideally, we should maintain a separate list for the
777      * IRemUnknown proxies that need late destruction */
778     list_add_tail(&apt->proxies, &This->entry);
779     LeaveCriticalSection(&apt->cs);
780 
781     TRACE("%p created for OXID %s, OID %s\n", This,
782         wine_dbgstr_longlong(oxid), wine_dbgstr_longlong(oid));
783 
784     *proxy_manager = This;
785     return S_OK;
786 }
787 
788 static inline void proxy_manager_set_context(struct proxy_manager *This, MSHCTX dest_context, void *dest_context_data)
789 {
790     MSHCTX old_dest_context;
791     MSHCTX new_dest_context;
792 
793     do
794     {
795         old_dest_context = This->dest_context;
796         new_dest_context = old_dest_context;
797         /* "stronger" values overwrite "weaker" values. stronger values are
798          * ones that disable more optimisations */
799         switch (old_dest_context)
800         {
801         case MSHCTX_INPROC:
802             new_dest_context = dest_context;
803             break;
804         case MSHCTX_CROSSCTX:
805             switch (dest_context)
806             {
807             case MSHCTX_INPROC:
808                 break;
809             default:
810                 new_dest_context = dest_context;
811             }
812             break;
813         case MSHCTX_LOCAL:
814             switch (dest_context)
815             {
816             case MSHCTX_INPROC:
817             case MSHCTX_CROSSCTX:
818                 break;
819             default:
820                 new_dest_context = dest_context;
821             }
822             break;
823         case MSHCTX_NOSHAREDMEM:
824             switch (dest_context)
825             {
826             case MSHCTX_DIFFERENTMACHINE:
827                 new_dest_context = dest_context;
828                 break;
829             default:
830                 break;
831             }
832             break;
833         default:
834             break;
835         }
836 
837         if (old_dest_context == new_dest_context) break;
838 
839         new_dest_context = InterlockedCompareExchange((PLONG)&This->dest_context, new_dest_context, old_dest_context);
840     } while (new_dest_context != old_dest_context);
841 
842     if (dest_context_data)
843         InterlockedExchangePointer(&This->dest_context_data, dest_context_data);
844 }
845 
846 static HRESULT proxy_manager_query_local_interface(struct proxy_manager * This, REFIID riid, void ** ppv)
847 {
848     HRESULT hr;
849     struct ifproxy * ifproxy;
850 
851     TRACE("%s\n", debugstr_guid(riid));
852 
853     if (IsEqualIID(riid, &IID_IUnknown) ||
854         IsEqualIID(riid, &IID_IMultiQI))
855     {
856         *ppv = &This->IMultiQI_iface;
857         IMultiQI_AddRef(&This->IMultiQI_iface);
858         return S_OK;
859     }
860     if (IsEqualIID(riid, &IID_IMarshal))
861     {
862         *ppv = &This->IMarshal_iface;
863         IMarshal_AddRef(&This->IMarshal_iface);
864         return S_OK;
865     }
866     if (IsEqualIID(riid, &IID_IClientSecurity))
867     {
868         *ppv = &This->IClientSecurity_iface;
869         IClientSecurity_AddRef(&This->IClientSecurity_iface);
870         return S_OK;
871     }
872 
873     hr = proxy_manager_find_ifproxy(This, riid, &ifproxy);
874     if (hr == S_OK)
875     {
876         *ppv = ifproxy->iface;
877         IUnknown_AddRef((IUnknown *)*ppv);
878         return S_OK;
879     }
880 
881     *ppv = NULL;
882     return E_NOINTERFACE;
883 }
884 
885 static HRESULT proxy_manager_create_ifproxy(
886     struct proxy_manager * This, const STDOBJREF *stdobjref, REFIID riid,
887     IRpcChannelBuffer * channel, struct ifproxy ** iif_out)
888 {
889     HRESULT hr;
890     IPSFactoryBuffer * psfb;
891     struct ifproxy * ifproxy = HeapAlloc(GetProcessHeap(), 0, sizeof(*ifproxy));
892     if (!ifproxy) return E_OUTOFMEMORY;
893 
894     list_init(&ifproxy->entry);
895 
896     ifproxy->parent = This;
897     ifproxy->stdobjref = *stdobjref;
898     ifproxy->iid = *riid;
899     ifproxy->refs = 0;
900     ifproxy->proxy = NULL;
901 
902     assert(channel);
903     ifproxy->chan = channel; /* FIXME: we should take the binding strings and construct the channel in this function */
904 
905     /* the IUnknown interface is special because it does not have a
906      * proxy associated with the ifproxy as we handle IUnknown ourselves */
907     if (IsEqualIID(riid, &IID_IUnknown))
908     {
909         ifproxy->iface = &This->IMultiQI_iface;
910         IMultiQI_AddRef(&This->IMultiQI_iface);
911         hr = S_OK;
912     }
913     else
914     {
915         hr = get_facbuf_for_iid(riid, &psfb);
916         if (hr == S_OK)
917         {
918             /* important note: the outer unknown is set to the proxy manager.
919              * This ensures the COM identity rules are not violated, by having a
920              * one-to-one mapping of objects on the proxy side to objects on the
921              * stub side, no matter which interface you view the object through */
922             hr = IPSFactoryBuffer_CreateProxy(psfb, (IUnknown*)&This->IMultiQI_iface, riid,
923                                               &ifproxy->proxy, &ifproxy->iface);
924             IPSFactoryBuffer_Release(psfb);
925             if (hr != S_OK)
926                 ERR("Could not create proxy for interface %s, error 0x%08x\n",
927                     debugstr_guid(riid), hr);
928         }
929         else
930             ERR("Could not get IPSFactoryBuffer for interface %s, error 0x%08x\n",
931                 debugstr_guid(riid), hr);
932 
933         if (hr == S_OK)
934             hr = IRpcProxyBuffer_Connect(ifproxy->proxy, ifproxy->chan);
935     }
936 
937     if (hr == S_OK)
938     {
939         EnterCriticalSection(&This->cs);
940         list_add_tail(&This->interfaces, &ifproxy->entry);
941         LeaveCriticalSection(&This->cs);
942 
943         *iif_out = ifproxy;
944         TRACE("ifproxy %p created for IPID %s, interface %s with %u public refs\n",
945               ifproxy, debugstr_guid(&stdobjref->ipid), debugstr_guid(riid), stdobjref->cPublicRefs);
946     }
947     else
948         ifproxy_destroy(ifproxy);
949 
950     return hr;
951 }
952 
953 static HRESULT proxy_manager_find_ifproxy(struct proxy_manager * This, REFIID riid, struct ifproxy ** ifproxy_found)
954 {
955     HRESULT hr = E_NOINTERFACE; /* assume not found */
956     struct list * cursor;
957 
958     EnterCriticalSection(&This->cs);
959     LIST_FOR_EACH(cursor, &This->interfaces)
960     {
961         struct ifproxy * ifproxy = LIST_ENTRY(cursor, struct ifproxy, entry);
962         if (IsEqualIID(riid, &ifproxy->iid))
963         {
964             *ifproxy_found = ifproxy;
965             hr = S_OK;
966             break;
967         }
968     }
969     LeaveCriticalSection(&This->cs);
970 
971     return hr;
972 }
973 
974 static void proxy_manager_disconnect(struct proxy_manager * This)
975 {
976     struct list * cursor;
977 
978     TRACE("oxid = %s, oid = %s\n", wine_dbgstr_longlong(This->oxid),
979         wine_dbgstr_longlong(This->oid));
980 
981     EnterCriticalSection(&This->cs);
982 
983     /* SORFP_NOLIFTIMEMGMT proxies (for IRemUnknown) shouldn't be
984      * disconnected - it won't do anything anyway, except cause
985      * problems for other objects that depend on this proxy always
986      * working */
987     if (!(This->sorflags & SORFP_NOLIFETIMEMGMT))
988     {
989         LIST_FOR_EACH(cursor, &This->interfaces)
990         {
991             struct ifproxy * ifproxy = LIST_ENTRY(cursor, struct ifproxy, entry);
992             ifproxy_disconnect(ifproxy);
993         }
994     }
995 
996     /* apartment is being destroyed so don't keep a pointer around to it */
997     This->parent = NULL;
998 
999     LeaveCriticalSection(&This->cs);
1000 }
1001 
1002 static HRESULT proxy_manager_get_remunknown(struct proxy_manager * This, IRemUnknown **remunk)
1003 {
1004     HRESULT hr = S_OK;
1005     struct apartment *apt;
1006     BOOL called_in_original_apt;
1007 
1008     /* we don't want to try and unmarshal or use IRemUnknown if we don't want
1009      * lifetime management */
1010     if (This->sorflags & SORFP_NOLIFETIMEMGMT)
1011         return S_FALSE;
1012 
1013     apt = COM_CurrentApt();
1014     if (!apt)
1015         return CO_E_NOTINITIALIZED;
1016 
1017     called_in_original_apt = This->parent && (This->parent->oxid == apt->oxid);
1018 
1019     EnterCriticalSection(&This->cs);
1020     /* only return the cached object if called from the original apartment.
1021      * in future, we might want to make the IRemUnknown proxy callable from any
1022      * apartment to avoid these checks */
1023     if (This->remunk && called_in_original_apt)
1024     {
1025         /* already created - return existing object */
1026         *remunk = This->remunk;
1027         IRemUnknown_AddRef(*remunk);
1028     }
1029     else if (!This->parent)
1030     {
1031         /* disconnected - we can't create IRemUnknown */
1032         *remunk = NULL;
1033         hr = S_FALSE;
1034     }
1035     else
1036     {
1037         STDOBJREF stdobjref;
1038         /* Don't want IRemUnknown lifetime management as this is IRemUnknown!
1039          * We also don't care about whether or not the stub is still alive */
1040         stdobjref.flags = SORFP_NOLIFETIMEMGMT | SORF_NOPING;
1041         stdobjref.cPublicRefs = 1;
1042         /* oxid of destination object */
1043         stdobjref.oxid = This->oxid;
1044         /* FIXME: what should be used for the oid? The DCOM draft doesn't say */
1045         stdobjref.oid = (OID)-1;
1046         stdobjref.ipid = This->oxid_info.ipidRemUnknown;
1047 
1048         /* do the unmarshal */
1049         hr = unmarshal_object(&stdobjref, COM_CurrentApt(), This->dest_context,
1050                               This->dest_context_data, &IID_IRemUnknown,
1051                               &This->oxid_info, (void**)remunk);
1052         if (hr == S_OK && called_in_original_apt)
1053         {
1054             This->remunk = *remunk;
1055             IRemUnknown_AddRef(This->remunk);
1056         }
1057     }
1058     LeaveCriticalSection(&This->cs);
1059 
1060     TRACE("got IRemUnknown* pointer %p, hr = 0x%08x\n", *remunk, hr);
1061 
1062     return hr;
1063 }
1064 
1065 /* destroys a proxy manager, freeing the memory it used.
1066  * Note: this function should not be called from a list iteration in the
1067  * apartment, due to the fact that it removes itself from the apartment and
1068  * it could add a proxy to IRemUnknown into the apartment. */
1069 static void proxy_manager_destroy(struct proxy_manager * This)
1070 {
1071     struct list * cursor;
1072 
1073     TRACE("oxid = %s, oid = %s\n", wine_dbgstr_longlong(This->oxid),
1074         wine_dbgstr_longlong(This->oid));
1075 
1076     if (This->parent)
1077     {
1078         EnterCriticalSection(&This->parent->cs);
1079 
1080         /* remove ourself from the list of proxy objects in the apartment */
1081         LIST_FOR_EACH(cursor, &This->parent->proxies)
1082         {
1083             if (cursor == &This->entry)
1084             {
1085                 list_remove(&This->entry);
1086                 break;
1087             }
1088         }
1089 
1090         LeaveCriticalSection(&This->parent->cs);
1091     }
1092 
1093     /* destroy all of the interface proxies */
1094     while ((cursor = list_head(&This->interfaces)))
1095     {
1096         struct ifproxy * ifproxy = LIST_ENTRY(cursor, struct ifproxy, entry);
1097         ifproxy_destroy(ifproxy);
1098     }
1099 
1100     if (This->remunk) IRemUnknown_Release(This->remunk);
1101     CoTaskMemFree(This->oxid_info.psa);
1102 
1103     DEBUG_CLEAR_CRITSEC_NAME(&This->cs);
1104     DeleteCriticalSection(&This->cs);
1105 
1106     CloseHandle(This->remoting_mutex);
1107 
1108     HeapFree(GetProcessHeap(), 0, This);
1109 }
1110 
1111 /* finds the proxy manager corresponding to a given OXID and OID that has
1112  * been unmarshaled in the specified apartment. The caller must release the
1113  * reference to the proxy_manager when the object is no longer used. */
1114 static BOOL find_proxy_manager(APARTMENT * apt, OXID oxid, OID oid, struct proxy_manager ** proxy_found)
1115 {
1116     BOOL found = FALSE;
1117     struct list * cursor;
1118 
1119     EnterCriticalSection(&apt->cs);
1120     LIST_FOR_EACH(cursor, &apt->proxies)
1121     {
1122         struct proxy_manager * proxy = LIST_ENTRY(cursor, struct proxy_manager, entry);
1123         if ((oxid == proxy->oxid) && (oid == proxy->oid))
1124         {
1125             /* be careful of a race with ClientIdentity_Release, which would
1126              * cause us to return a proxy which is in the process of being
1127              * destroyed */
1128             if (IMultiQI_AddRef(&proxy->IMultiQI_iface) != 0)
1129             {
1130                 *proxy_found = proxy;
1131                 found = TRUE;
1132                 break;
1133             }
1134         }
1135     }
1136     LeaveCriticalSection(&apt->cs);
1137     return found;
1138 }
1139 
1140 HRESULT apartment_disconnectproxies(struct apartment *apt)
1141 {
1142     struct list * cursor;
1143 
1144     LIST_FOR_EACH(cursor, &apt->proxies)
1145     {
1146         struct proxy_manager * proxy = LIST_ENTRY(cursor, struct proxy_manager, entry);
1147         proxy_manager_disconnect(proxy);
1148     }
1149 
1150     return S_OK;
1151 }
1152 
1153 /********************** StdMarshal implementation ****************************/
1154 typedef struct _StdMarshalImpl
1155 {
1156     IMarshal IMarshal_iface;
1157     LONG     ref;
1158     DWORD    dest_context;
1159     void    *dest_context_data;
1160 } StdMarshalImpl;
1161 
1162 static inline StdMarshalImpl *impl_from_StdMarshal(IMarshal *iface)
1163 {
1164     return CONTAINING_RECORD(iface, StdMarshalImpl, IMarshal_iface);
1165 }
1166 
1167 static HRESULT WINAPI
1168 StdMarshalImpl_QueryInterface(IMarshal *iface, REFIID riid, void **ppv)
1169 {
1170     *ppv = NULL;
1171     if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IMarshal, riid))
1172     {
1173         *ppv = iface;
1174         IMarshal_AddRef(iface);
1175         return S_OK;
1176     }
1177     FIXME("No interface for %s.\n", debugstr_guid(riid));
1178     return E_NOINTERFACE;
1179 }
1180 
1181 static ULONG WINAPI
1182 StdMarshalImpl_AddRef(IMarshal *iface)
1183 {
1184     StdMarshalImpl *This = impl_from_StdMarshal(iface);
1185     return InterlockedIncrement(&This->ref);
1186 }
1187 
1188 static ULONG WINAPI
1189 StdMarshalImpl_Release(IMarshal *iface)
1190 {
1191     StdMarshalImpl *This = impl_from_StdMarshal(iface);
1192     ULONG ref = InterlockedDecrement(&This->ref);
1193 
1194     if (!ref) HeapFree(GetProcessHeap(),0,This);
1195     return ref;
1196 }
1197 
1198 static HRESULT WINAPI
1199 StdMarshalImpl_GetUnmarshalClass(
1200     IMarshal *iface, REFIID riid, void* pv, DWORD dwDestContext,
1201     void* pvDestContext, DWORD mshlflags, CLSID* pCid)
1202 {
1203     *pCid = CLSID_DfMarshal;
1204     return S_OK;
1205 }
1206 
1207 static HRESULT WINAPI
1208 StdMarshalImpl_GetMarshalSizeMax(
1209     IMarshal *iface, REFIID riid, void* pv, DWORD dwDestContext,
1210     void* pvDestContext, DWORD mshlflags, DWORD* pSize)
1211 {
1212     *pSize = sizeof(STDOBJREF);
1213     return S_OK;
1214 }
1215 
1216 static HRESULT WINAPI
1217 StdMarshalImpl_MarshalInterface(
1218     IMarshal *iface, IStream *pStm,REFIID riid, void* pv, DWORD dest_context,
1219     void* dest_context_data, DWORD mshlflags)
1220 {
1221     STDOBJREF             stdobjref;
1222     ULONG                 res;
1223     HRESULT               hres;
1224     APARTMENT            *apt = COM_CurrentApt();
1225 
1226     TRACE("(...,%s,...)\n", debugstr_guid(riid));
1227 
1228     if (!apt)
1229     {
1230         ERR("Apartment not initialized\n");
1231         return CO_E_NOTINITIALIZED;
1232     }
1233 
1234     /* make sure this apartment can be reached from other threads / processes */
1235     RPC_StartRemoting(apt);
1236 
1237     hres = marshal_object(apt, &stdobjref, riid, pv, dest_context, dest_context_data, mshlflags);
1238     if (hres != S_OK)
1239     {
1240         ERR("Failed to create ifstub, hres=0x%x\n", hres);
1241         return hres;
1242     }
1243 
1244     return IStream_Write(pStm, &stdobjref, sizeof(stdobjref), &res);
1245 }
1246 
1247 /* helper for StdMarshalImpl_UnmarshalInterface - does the unmarshaling with
1248  * no questions asked about the rules surrounding same-apartment unmarshals
1249  * and table marshaling */
1250 static HRESULT unmarshal_object(const STDOBJREF *stdobjref, APARTMENT *apt,
1251                                 MSHCTX dest_context, void *dest_context_data,
1252                                 REFIID riid, const OXID_INFO *oxid_info,
1253                                 void **object)
1254 {
1255     struct proxy_manager *proxy_manager = NULL;
1256     HRESULT hr = S_OK;
1257 
1258     assert(apt);
1259 
1260     TRACE("stdobjref: flags = %04x cPublicRefs = %d oxid = %s oid = %s ipid = %s\n",
1261         stdobjref->flags, stdobjref->cPublicRefs,
1262         wine_dbgstr_longlong(stdobjref->oxid),
1263         wine_dbgstr_longlong(stdobjref->oid),
1264         debugstr_guid(&stdobjref->ipid));
1265 
1266     /* create a new proxy manager if one doesn't already exist for the
1267      * object */
1268     if (!find_proxy_manager(apt, stdobjref->oxid, stdobjref->oid, &proxy_manager))
1269     {
1270         hr = proxy_manager_construct(apt, stdobjref->flags,
1271                                      stdobjref->oxid, stdobjref->oid, oxid_info,
1272                                      &proxy_manager);
1273     }
1274     else
1275         TRACE("proxy manager already created, using\n");
1276 
1277     if (hr == S_OK)
1278     {
1279         struct ifproxy * ifproxy;
1280 
1281         proxy_manager_set_context(proxy_manager, dest_context, dest_context_data);
1282 
1283         hr = proxy_manager_find_ifproxy(proxy_manager, riid, &ifproxy);
1284         if (hr == E_NOINTERFACE)
1285         {
1286             IRpcChannelBuffer *chanbuf;
1287             hr = RPC_CreateClientChannel(&stdobjref->oxid, &stdobjref->ipid,
1288                                          &proxy_manager->oxid_info,
1289                                          proxy_manager->dest_context,
1290                                          proxy_manager->dest_context_data,
1291                                          &chanbuf);
1292             if (hr == S_OK)
1293                 hr = proxy_manager_create_ifproxy(proxy_manager, stdobjref,
1294                                                   riid, chanbuf, &ifproxy);
1295         }
1296         else
1297             IUnknown_AddRef((IUnknown *)ifproxy->iface);
1298 
1299         if (hr == S_OK)
1300         {
1301             InterlockedExchangeAdd((LONG *)&ifproxy->refs, stdobjref->cPublicRefs);
1302             /* get at least one external reference to the object to keep it alive */
1303             hr = ifproxy_get_public_ref(ifproxy);
1304             if (FAILED(hr))
1305                 ifproxy_destroy(ifproxy);
1306         }
1307 
1308         if (hr == S_OK)
1309             *object = ifproxy->iface;
1310     }
1311 
1312     /* release our reference to the proxy manager - the client/apartment
1313      * will hold on to the remaining reference for us */
1314     if (proxy_manager) IMultiQI_Release(&proxy_manager->IMultiQI_iface);
1315 
1316     return hr;
1317 }
1318 
1319 static HRESULT WINAPI
1320 StdMarshalImpl_UnmarshalInterface(IMarshal *iface, IStream *pStm, REFIID riid, void **ppv)
1321 {
1322     StdMarshalImpl *This = impl_from_StdMarshal(iface);
1323     struct stub_manager *stubmgr = NULL;
1324     STDOBJREF stdobjref;
1325     ULONG res;
1326     HRESULT hres;
1327     APARTMENT *apt = COM_CurrentApt();
1328     APARTMENT *stub_apt;
1329     OXID oxid;
1330 
1331     TRACE("(...,%s,....)\n", debugstr_guid(riid));
1332 
1333     /* we need an apartment to unmarshal into */
1334     if (!apt)
1335     {
1336         ERR("Apartment not initialized\n");
1337         return CO_E_NOTINITIALIZED;
1338     }
1339 
1340     /* read STDOBJREF from wire */
1341     hres = IStream_Read(pStm, &stdobjref, sizeof(stdobjref), &res);
1342     if (hres != S_OK) return STG_E_READFAULT;
1343 
1344     hres = apartment_getoxid(apt, &oxid);
1345     if (hres != S_OK) return hres;
1346 
1347     /* check if we're marshalling back to ourselves */
1348     if ((oxid == stdobjref.oxid) && (stubmgr = get_stub_manager(apt, stdobjref.oid)))
1349     {
1350         TRACE("Unmarshalling object marshalled in same apartment for iid %s, "
1351               "returning original object %p\n", debugstr_guid(riid), stubmgr->object);
1352 
1353         hres = IUnknown_QueryInterface(stubmgr->object, riid, ppv);
1354 
1355         /* unref the ifstub. FIXME: only do this on success? */
1356         if (!stub_manager_is_table_marshaled(stubmgr, &stdobjref.ipid))
1357             stub_manager_ext_release(stubmgr, stdobjref.cPublicRefs, stdobjref.flags & SORFP_TABLEWEAK, FALSE);
1358 
1359         stub_manager_int_release(stubmgr);
1360         return hres;
1361     }
1362 
1363     /* notify stub manager about unmarshal if process-local object.
1364      * note: if the oxid is not found then we and native will quite happily
1365      * ignore table marshaling and normal marshaling rules regarding number of
1366      * unmarshals, etc, but if you abuse these rules then your proxy could end
1367      * up returning RPC_E_DISCONNECTED. */
1368     if ((stub_apt = apartment_findfromoxid(stdobjref.oxid, TRUE)))
1369     {
1370         if ((stubmgr = get_stub_manager(stub_apt, stdobjref.oid)))
1371         {
1372             if (!stub_manager_notify_unmarshal(stubmgr, &stdobjref.ipid))
1373                 hres = CO_E_OBJNOTCONNECTED;
1374         }
1375         else
1376         {
1377             WARN("Couldn't find object for OXID %s, OID %s, assuming disconnected\n",
1378                 wine_dbgstr_longlong(stdobjref.oxid),
1379                 wine_dbgstr_longlong(stdobjref.oid));
1380             hres = CO_E_OBJNOTCONNECTED;
1381         }
1382     }
1383     else
1384         TRACE("Treating unmarshal from OXID %s as inter-process\n",
1385             wine_dbgstr_longlong(stdobjref.oxid));
1386 
1387     if (hres == S_OK)
1388         hres = unmarshal_object(&stdobjref, apt, This->dest_context,
1389                                 This->dest_context_data, riid,
1390                                 stubmgr ? &stubmgr->oxid_info : NULL, ppv);
1391 
1392     if (stubmgr) stub_manager_int_release(stubmgr);
1393     if (stub_apt) apartment_release(stub_apt);
1394 
1395     if (hres != S_OK) WARN("Failed with error 0x%08x\n", hres);
1396     else TRACE("Successfully created proxy %p\n", *ppv);
1397 
1398     return hres;
1399 }
1400 
1401 static HRESULT WINAPI
1402 StdMarshalImpl_ReleaseMarshalData(IMarshal *iface, IStream *pStm)
1403 {
1404     STDOBJREF            stdobjref;
1405     ULONG                res;
1406     HRESULT              hres;
1407     struct stub_manager *stubmgr;
1408     APARTMENT           *apt;
1409 
1410     TRACE("iface=%p, pStm=%p\n", iface, pStm);
1411 
1412     hres = IStream_Read(pStm, &stdobjref, sizeof(stdobjref), &res);
1413     if (hres != S_OK) return STG_E_READFAULT;
1414 
1415     TRACE("oxid = %s, oid = %s, ipid = %s\n",
1416         wine_dbgstr_longlong(stdobjref.oxid),
1417         wine_dbgstr_longlong(stdobjref.oid),
1418         wine_dbgstr_guid(&stdobjref.ipid));
1419 
1420     if (!(apt = apartment_findfromoxid(stdobjref.oxid, TRUE)))
1421     {
1422         WARN("Could not map OXID %s to apartment object\n",
1423             wine_dbgstr_longlong(stdobjref.oxid));
1424         return RPC_E_INVALID_OBJREF;
1425     }
1426 
1427     if (!(stubmgr = get_stub_manager(apt, stdobjref.oid)))
1428     {
1429         apartment_release(apt);
1430         ERR("could not map object ID to stub manager, oxid=%s, oid=%s\n",
1431             wine_dbgstr_longlong(stdobjref.oxid), wine_dbgstr_longlong(stdobjref.oid));
1432         return RPC_E_INVALID_OBJREF;
1433     }
1434 
1435     stub_manager_release_marshal_data(stubmgr, stdobjref.cPublicRefs, &stdobjref.ipid, stdobjref.flags & SORFP_TABLEWEAK);
1436 
1437     stub_manager_int_release(stubmgr);
1438     apartment_release(apt);
1439 
1440     return S_OK;
1441 }
1442 
1443 static HRESULT WINAPI
1444 StdMarshalImpl_DisconnectObject(IMarshal *iface, DWORD dwReserved)
1445 {
1446     FIXME("(), stub!\n");
1447     return S_OK;
1448 }
1449 
1450 static const IMarshalVtbl StdMarshalVtbl =
1451 {
1452     StdMarshalImpl_QueryInterface,
1453     StdMarshalImpl_AddRef,
1454     StdMarshalImpl_Release,
1455     StdMarshalImpl_GetUnmarshalClass,
1456     StdMarshalImpl_GetMarshalSizeMax,
1457     StdMarshalImpl_MarshalInterface,
1458     StdMarshalImpl_UnmarshalInterface,
1459     StdMarshalImpl_ReleaseMarshalData,
1460     StdMarshalImpl_DisconnectObject
1461 };
1462 
1463 static HRESULT StdMarshalImpl_Construct(REFIID riid, DWORD dest_context, void *dest_context_data, void** ppvObject)
1464 {
1465     HRESULT hr;
1466 
1467     StdMarshalImpl *pStdMarshal = HeapAlloc(GetProcessHeap(), 0, sizeof(StdMarshalImpl));
1468     if (!pStdMarshal)
1469         return E_OUTOFMEMORY;
1470 
1471     pStdMarshal->IMarshal_iface.lpVtbl = &StdMarshalVtbl;
1472     pStdMarshal->ref = 0;
1473     pStdMarshal->dest_context = dest_context;
1474     pStdMarshal->dest_context_data = dest_context_data;
1475 
1476     hr = IMarshal_QueryInterface(&pStdMarshal->IMarshal_iface, riid, ppvObject);
1477     if (FAILED(hr))
1478         HeapFree(GetProcessHeap(), 0, pStdMarshal);
1479 
1480     return hr;
1481 }
1482 
1483 /***********************************************************************
1484  *		CoGetStandardMarshal	[OLE32.@]
1485  *
1486  * Gets or creates a standard marshal object.
1487  *
1488  * PARAMS
1489  *  riid          [I] Interface identifier of the pUnk object.
1490  *  pUnk          [I] Optional. Object to get the marshal object for.
1491  *  dwDestContext [I] Destination. Used to enable or disable optimizations.
1492  *  pvDestContext [I] Reserved. Must be NULL.
1493  *  mshlflags     [I] Flags affecting the marshaling process.
1494  *  ppMarshal     [O] Address where marshal object will be stored.
1495  *
1496  * RETURNS
1497  *  Success: S_OK.
1498  *  Failure: HRESULT code.
1499  *
1500  * NOTES
1501  *
1502  * The function retrieves the IMarshal object associated with an object if
1503  * that object is currently an active stub, otherwise a new marshal object is
1504  * created.
1505  */
1506 HRESULT WINAPI CoGetStandardMarshal(REFIID riid, IUnknown *pUnk,
1507                                     DWORD dwDestContext, LPVOID pvDestContext,
1508                                     DWORD mshlflags, LPMARSHAL *ppMarshal)
1509 {
1510     if (pUnk == NULL)
1511     {
1512         FIXME("(%s,NULL,%x,%p,%x,%p), unimplemented yet.\n",
1513             debugstr_guid(riid),dwDestContext,pvDestContext,mshlflags,ppMarshal);
1514         return E_NOTIMPL;
1515     }
1516     TRACE("(%s,%p,%x,%p,%x,%p)\n",
1517         debugstr_guid(riid),pUnk,dwDestContext,pvDestContext,mshlflags,ppMarshal);
1518 
1519     return StdMarshalImpl_Construct(&IID_IMarshal, dwDestContext, pvDestContext, (void**)ppMarshal);
1520 }
1521 
1522 /***********************************************************************
1523  *		get_marshaler	[internal]
1524  *
1525  * Retrieves an IMarshal interface for an object.
1526  */
1527 static HRESULT get_marshaler(REFIID riid, IUnknown *pUnk, DWORD dwDestContext,
1528                              void *pvDestContext, DWORD mshlFlags,
1529                              LPMARSHAL *pMarshal)
1530 {
1531     HRESULT hr;
1532 
1533     if (!pUnk)
1534         return E_POINTER;
1535     hr = IUnknown_QueryInterface(pUnk, &IID_IMarshal, (LPVOID*)pMarshal);
1536     if (hr != S_OK)
1537         hr = CoGetStandardMarshal(riid, pUnk, dwDestContext, pvDestContext,
1538                                   mshlFlags, pMarshal);
1539     return hr;
1540 }
1541 
1542 /***********************************************************************
1543  *		get_unmarshaler_from_stream	[internal]
1544  *
1545  * Creates an IMarshal* object according to the data marshaled to the stream.
1546  * The function leaves the stream pointer at the start of the data written
1547  * to the stream by the IMarshal* object.
1548  */
1549 static HRESULT get_unmarshaler_from_stream(IStream *stream, IMarshal **marshal, IID *iid)
1550 {
1551     HRESULT hr;
1552     ULONG res;
1553     OBJREF objref;
1554 
1555     /* read common OBJREF header */
1556     hr = IStream_Read(stream, &objref, FIELD_OFFSET(OBJREF, u_objref), &res);
1557     if (hr != S_OK || (res != FIELD_OFFSET(OBJREF, u_objref)))
1558     {
1559         ERR("Failed to read common OBJREF header, 0x%08x\n", hr);
1560         return STG_E_READFAULT;
1561     }
1562 
1563     /* sanity check on header */
1564     if (objref.signature != OBJREF_SIGNATURE)
1565     {
1566         ERR("Bad OBJREF signature 0x%08x\n", objref.signature);
1567         return RPC_E_INVALID_OBJREF;
1568     }
1569 
1570     if (iid) *iid = objref.iid;
1571 
1572     /* FIXME: handler marshaling */
1573     if (objref.flags & OBJREF_STANDARD)
1574     {
1575         TRACE("Using standard unmarshaling\n");
1576         hr = StdMarshalImpl_Construct(&IID_IMarshal, 0, NULL, (LPVOID*)marshal);
1577     }
1578     else if (objref.flags & OBJREF_CUSTOM)
1579     {
1580         ULONG custom_header_size = FIELD_OFFSET(OBJREF, u_objref.u_custom.pData) -
1581                                    FIELD_OFFSET(OBJREF, u_objref.u_custom);
1582         TRACE("Using custom unmarshaling\n");
1583         /* read constant sized OR_CUSTOM data from stream */
1584         hr = IStream_Read(stream, &objref.u_objref.u_custom,
1585                           custom_header_size, &res);
1586         if (hr != S_OK || (res != custom_header_size))
1587         {
1588             ERR("Failed to read OR_CUSTOM header, 0x%08x\n", hr);
1589             return STG_E_READFAULT;
1590         }
1591         /* now create the marshaler specified in the stream */
1592         hr = CoCreateInstance(&objref.u_objref.u_custom.clsid, NULL,
1593                               CLSCTX_INPROC_SERVER, &IID_IMarshal,
1594                               (LPVOID*)marshal);
1595     }
1596     else
1597     {
1598         FIXME("Invalid or unimplemented marshaling type specified: %x\n",
1599             objref.flags);
1600         return RPC_E_INVALID_OBJREF;
1601     }
1602 
1603     if (hr != S_OK)
1604         ERR("Failed to create marshal, 0x%08x\n", hr);
1605 
1606     return hr;
1607 }
1608 
1609 /***********************************************************************
1610  *		CoGetMarshalSizeMax	[OLE32.@]
1611  *
1612  * Gets the maximum amount of data that will be needed by a marshal.
1613  *
1614  * PARAMS
1615  *  pulSize       [O] Address where maximum marshal size will be stored.
1616  *  riid          [I] Identifier of the interface to marshal.
1617  *  pUnk          [I] Pointer to the object to marshal.
1618  *  dwDestContext [I] Destination. Used to enable or disable optimizations.
1619  *  pvDestContext [I] Reserved. Must be NULL.
1620  *  mshlFlags     [I] Flags that affect the marshaling. See CoMarshalInterface().
1621  *
1622  * RETURNS
1623  *  Success: S_OK.
1624  *  Failure: HRESULT code.
1625  *
1626  * SEE ALSO
1627  *  CoMarshalInterface().
1628  */
1629 HRESULT WINAPI CoGetMarshalSizeMax(ULONG *pulSize, REFIID riid, IUnknown *pUnk,
1630                                    DWORD dwDestContext, void *pvDestContext,
1631                                    DWORD mshlFlags)
1632 {
1633     HRESULT hr;
1634     LPMARSHAL pMarshal;
1635     CLSID marshaler_clsid;
1636 
1637     hr = get_marshaler(riid, pUnk, dwDestContext, pvDestContext, mshlFlags, &pMarshal);
1638     if (hr != S_OK)
1639         return hr;
1640 
1641     hr = IMarshal_GetUnmarshalClass(pMarshal, riid, pUnk, dwDestContext,
1642                                     pvDestContext, mshlFlags, &marshaler_clsid);
1643     if (hr != S_OK)
1644     {
1645         ERR("IMarshal::GetUnmarshalClass failed, 0x%08x\n", hr);
1646         IMarshal_Release(pMarshal);
1647         return hr;
1648     }
1649 
1650     hr = IMarshal_GetMarshalSizeMax(pMarshal, riid, pUnk, dwDestContext,
1651                                     pvDestContext, mshlFlags, pulSize);
1652     if (IsEqualCLSID(&marshaler_clsid, &CLSID_DfMarshal))
1653         /* add on the size of the common header */
1654         *pulSize += FIELD_OFFSET(OBJREF, u_objref);
1655     else
1656         /* custom marshaling: add on the size of the whole OBJREF structure
1657          * like native does */
1658         *pulSize += sizeof(OBJREF);
1659 
1660     IMarshal_Release(pMarshal);
1661     return hr;
1662 }
1663 
1664 
1665 static void dump_MSHLFLAGS(MSHLFLAGS flags)
1666 {
1667     if (flags & MSHLFLAGS_TABLESTRONG)
1668         TRACE(" MSHLFLAGS_TABLESTRONG");
1669     if (flags & MSHLFLAGS_TABLEWEAK)
1670         TRACE(" MSHLFLAGS_TABLEWEAK");
1671     if (!(flags & (MSHLFLAGS_TABLESTRONG|MSHLFLAGS_TABLEWEAK)))
1672         TRACE(" MSHLFLAGS_NORMAL");
1673     if (flags & MSHLFLAGS_NOPING)
1674         TRACE(" MSHLFLAGS_NOPING");
1675 }
1676 
1677 /***********************************************************************
1678  *		CoMarshalInterface	[OLE32.@]
1679  *
1680  * Marshals an interface into a stream so that the object can then be
1681  * unmarshaled from another COM apartment and used remotely.
1682  *
1683  * PARAMS
1684  *  pStream       [I] Stream the object will be marshaled into.
1685  *  riid          [I] Identifier of the interface to marshal.
1686  *  pUnk          [I] Pointer to the object to marshal.
1687  *  dwDestContext [I] Destination. Used to enable or disable optimizations.
1688  *  pvDestContext [I] Reserved. Must be NULL.
1689  *  mshlFlags     [I] Flags that affect the marshaling. See notes.
1690  *
1691  * RETURNS
1692  *  Success: S_OK.
1693  *  Failure: HRESULT code.
1694  *
1695  * NOTES
1696  *
1697  * The mshlFlags parameter can take one or more of the following flags:
1698  *| MSHLFLAGS_NORMAL - Unmarshal once, releases stub on last proxy release.
1699  *| MSHLFLAGS_TABLESTRONG - Unmarshal many, release when CoReleaseMarshalData() called.
1700  *| MSHLFLAGS_TABLEWEAK - Unmarshal many, releases stub on last proxy release.
1701  *| MSHLFLAGS_NOPING - No automatic garbage collection (and so reduces network traffic).
1702  *
1703  * If a marshaled object is not unmarshaled, then CoReleaseMarshalData() must
1704  * be called in order to release the resources used in the marshaling.
1705  *
1706  * SEE ALSO
1707  *  CoUnmarshalInterface(), CoReleaseMarshalData().
1708  */
1709 HRESULT WINAPI CoMarshalInterface(IStream *pStream, REFIID riid, IUnknown *pUnk,
1710                                   DWORD dwDestContext, void *pvDestContext,
1711                                   DWORD mshlFlags)
1712 {
1713     HRESULT	hr;
1714     CLSID marshaler_clsid;
1715     OBJREF objref;
1716     LPMARSHAL pMarshal;
1717 
1718     TRACE("(%p, %s, %p, %x, %p, ", pStream, debugstr_guid(riid), pUnk,
1719         dwDestContext, pvDestContext);
1720     dump_MSHLFLAGS(mshlFlags);
1721     TRACE(")\n");
1722 
1723     if (!pUnk || !pStream)
1724         return E_INVALIDARG;
1725 
1726     objref.signature = OBJREF_SIGNATURE;
1727     objref.iid = *riid;
1728 
1729     /* get the marshaler for the specified interface */
1730     hr = get_marshaler(riid, pUnk, dwDestContext, pvDestContext, mshlFlags, &pMarshal);
1731     if (hr != S_OK)
1732     {
1733         ERR("Failed to get marshaller, 0x%08x\n", hr);
1734         return hr;
1735     }
1736 
1737     hr = IMarshal_GetUnmarshalClass(pMarshal, riid, pUnk, dwDestContext,
1738                                     pvDestContext, mshlFlags, &marshaler_clsid);
1739     if (hr != S_OK)
1740     {
1741         ERR("IMarshal::GetUnmarshalClass failed, 0x%08x\n", hr);
1742         goto cleanup;
1743     }
1744 
1745     /* FIXME: implement handler marshaling too */
1746     if (IsEqualCLSID(&marshaler_clsid, &CLSID_DfMarshal))
1747     {
1748         TRACE("Using standard marshaling\n");
1749         objref.flags = OBJREF_STANDARD;
1750 
1751         /* write the common OBJREF header to the stream */
1752         hr = IStream_Write(pStream, &objref, FIELD_OFFSET(OBJREF, u_objref), NULL);
1753         if (hr != S_OK)
1754         {
1755             ERR("Failed to write OBJREF header to stream, 0x%08x\n", hr);
1756             goto cleanup;
1757         }
1758     }
1759     else
1760     {
1761         TRACE("Using custom marshaling\n");
1762         objref.flags = OBJREF_CUSTOM;
1763         objref.u_objref.u_custom.clsid = marshaler_clsid;
1764         objref.u_objref.u_custom.cbExtension = 0;
1765         objref.u_objref.u_custom.size = 0;
1766         hr = IMarshal_GetMarshalSizeMax(pMarshal, riid, pUnk, dwDestContext,
1767                                         pvDestContext, mshlFlags,
1768                                         &objref.u_objref.u_custom.size);
1769         if (hr != S_OK)
1770         {
1771             ERR("Failed to get max size of marshal data, error 0x%08x\n", hr);
1772             goto cleanup;
1773         }
1774         /* write constant sized common header and OR_CUSTOM data into stream */
1775         hr = IStream_Write(pStream, &objref,
1776                           FIELD_OFFSET(OBJREF, u_objref.u_custom.pData), NULL);
1777         if (hr != S_OK)
1778         {
1779             ERR("Failed to write OR_CUSTOM header to stream with 0x%08x\n", hr);
1780             goto cleanup;
1781         }
1782     }
1783 
1784     TRACE("Calling IMarshal::MarshalInterface\n");
1785     /* call helper object to do the actual marshaling */
1786     hr = IMarshal_MarshalInterface(pMarshal, pStream, riid, pUnk, dwDestContext,
1787                                    pvDestContext, mshlFlags);
1788 
1789     if (hr != S_OK)
1790     {
1791         ERR("Failed to marshal the interface %s, %x\n", debugstr_guid(riid), hr);
1792         goto cleanup;
1793     }
1794 
1795 cleanup:
1796     IMarshal_Release(pMarshal);
1797 
1798     TRACE("completed with hr 0x%08x\n", hr);
1799 
1800     return hr;
1801 }
1802 
1803 /***********************************************************************
1804  *		CoUnmarshalInterface	[OLE32.@]
1805  *
1806  * Unmarshals an object from a stream by creating a proxy to the remote
1807  * object, if necessary.
1808  *
1809  * PARAMS
1810  *
1811  *  pStream [I] Stream containing the marshaled object.
1812  *  riid    [I] Interface identifier of the object to create a proxy to.
1813  *  ppv     [O] Address where proxy will be stored.
1814  *
1815  * RETURNS
1816  *
1817  *  Success: S_OK.
1818  *  Failure: HRESULT code.
1819  *
1820  * SEE ALSO
1821  *  CoMarshalInterface().
1822  */
1823 HRESULT WINAPI CoUnmarshalInterface(IStream *pStream, REFIID riid, LPVOID *ppv)
1824 {
1825     HRESULT hr;
1826     LPMARSHAL pMarshal;
1827     IID iid;
1828     IUnknown *object;
1829 
1830     TRACE("(%p, %s, %p)\n", pStream, debugstr_guid(riid), ppv);
1831 
1832     if (!pStream || !ppv)
1833         return E_INVALIDARG;
1834 
1835     hr = get_unmarshaler_from_stream(pStream, &pMarshal, &iid);
1836     if (hr != S_OK)
1837         return hr;
1838 
1839     /* call the helper object to do the actual unmarshaling */
1840     hr = IMarshal_UnmarshalInterface(pMarshal, pStream, &iid, (LPVOID*)&object);
1841     if (hr != S_OK)
1842         ERR("IMarshal::UnmarshalInterface failed, 0x%08x\n", hr);
1843 
1844     if (hr == S_OK)
1845     {
1846         /* IID_NULL means use the interface ID of the marshaled object */
1847         if (!IsEqualIID(riid, &IID_NULL) && !IsEqualIID(riid, &iid))
1848         {
1849             TRACE("requested interface != marshalled interface, additional QI needed\n");
1850             hr = IUnknown_QueryInterface(object, riid, ppv);
1851             if (hr != S_OK)
1852                 ERR("Couldn't query for interface %s, hr = 0x%08x\n",
1853                     debugstr_guid(riid), hr);
1854             IUnknown_Release(object);
1855         }
1856         else
1857         {
1858             *ppv = object;
1859         }
1860     }
1861 
1862     IMarshal_Release(pMarshal);
1863 
1864     TRACE("completed with hr 0x%x\n", hr);
1865 
1866     return hr;
1867 }
1868 
1869 /***********************************************************************
1870  *		CoReleaseMarshalData	[OLE32.@]
1871  *
1872  * Releases resources associated with an object that has been marshaled into
1873  * a stream.
1874  *
1875  * PARAMS
1876  *
1877  *  pStream [I] The stream that the object has been marshaled into.
1878  *
1879  * RETURNS
1880  *  Success: S_OK.
1881  *  Failure: HRESULT error code.
1882  *
1883  * NOTES
1884  *
1885  * Call this function to release resources associated with a normal or
1886  * table-weak marshal that will not be unmarshaled, and all table-strong
1887  * marshals when they are no longer needed.
1888  *
1889  * SEE ALSO
1890  *  CoMarshalInterface(), CoUnmarshalInterface().
1891  */
1892 HRESULT WINAPI CoReleaseMarshalData(IStream *pStream)
1893 {
1894     HRESULT	hr;
1895     LPMARSHAL pMarshal;
1896 
1897     TRACE("(%p)\n", pStream);
1898 
1899     hr = get_unmarshaler_from_stream(pStream, &pMarshal, NULL);
1900     if (hr != S_OK)
1901         return hr;
1902 
1903     /* call the helper object to do the releasing of marshal data */
1904     hr = IMarshal_ReleaseMarshalData(pMarshal, pStream);
1905     if (hr != S_OK)
1906         ERR("IMarshal::ReleaseMarshalData failed with error 0x%08x\n", hr);
1907 
1908     IMarshal_Release(pMarshal);
1909     return hr;
1910 }
1911 
1912 
1913 /***********************************************************************
1914  *		CoMarshalInterThreadInterfaceInStream	[OLE32.@]
1915  *
1916  * Marshal an interface across threads in the same process.
1917  *
1918  * PARAMS
1919  *  riid  [I] Identifier of the interface to be marshalled.
1920  *  pUnk  [I] Pointer to IUnknown-derived interface that will be marshalled.
1921  *  ppStm [O] Pointer to IStream object that is created and then used to store the marshalled interface.
1922  *
1923  * RETURNS
1924  *  Success: S_OK
1925  *  Failure: E_OUTOFMEMORY and other COM error codes
1926  *
1927  * SEE ALSO
1928  *   CoMarshalInterface(), CoUnmarshalInterface() and CoGetInterfaceAndReleaseStream()
1929  */
1930 HRESULT WINAPI CoMarshalInterThreadInterfaceInStream(
1931     REFIID riid, LPUNKNOWN pUnk, LPSTREAM * ppStm)
1932 {
1933     ULARGE_INTEGER	xpos;
1934     LARGE_INTEGER		seekto;
1935     HRESULT		hres;
1936 
1937     TRACE("(%s, %p, %p)\n",debugstr_guid(riid), pUnk, ppStm);
1938 
1939     hres = CreateStreamOnHGlobal(NULL, TRUE, ppStm);
1940     if (FAILED(hres)) return hres;
1941     hres = CoMarshalInterface(*ppStm, riid, pUnk, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1942 
1943     if (SUCCEEDED(hres))
1944     {
1945         memset(&seekto, 0, sizeof(seekto));
1946         IStream_Seek(*ppStm, seekto, STREAM_SEEK_SET, &xpos);
1947     }
1948     else
1949     {
1950         IStream_Release(*ppStm);
1951         *ppStm = NULL;
1952     }
1953 
1954     return hres;
1955 }
1956 
1957 /***********************************************************************
1958  *		CoGetInterfaceAndReleaseStream	[OLE32.@]
1959  *
1960  * Unmarshalls an interface from a stream and then releases the stream.
1961  *
1962  * PARAMS
1963  *  pStm [I] Stream that contains the marshalled interface.
1964  *  riid [I] Interface identifier of the object to unmarshall.
1965  *  ppv  [O] Address of pointer where the requested interface object will be stored.
1966  *
1967  * RETURNS
1968  *  Success: S_OK
1969  *  Failure: A COM error code
1970  *
1971  * SEE ALSO
1972  *  CoMarshalInterThreadInterfaceInStream() and CoUnmarshalInterface()
1973  */
1974 HRESULT WINAPI CoGetInterfaceAndReleaseStream(LPSTREAM pStm, REFIID riid,
1975                                               LPVOID *ppv)
1976 {
1977     HRESULT hres;
1978 
1979     TRACE("(%p, %s, %p)\n", pStm, debugstr_guid(riid), ppv);
1980 
1981     if(!pStm) return E_INVALIDARG;
1982     hres = CoUnmarshalInterface(pStm, riid, ppv);
1983     IStream_Release(pStm);
1984     return hres;
1985 }
1986 
1987 static HRESULT WINAPI StdMarshalCF_QueryInterface(LPCLASSFACTORY iface,
1988                                                   REFIID riid, LPVOID *ppv)
1989 {
1990     *ppv = NULL;
1991     if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IClassFactory))
1992     {
1993         *ppv = iface;
1994         return S_OK;
1995     }
1996     return E_NOINTERFACE;
1997 }
1998 
1999 static ULONG WINAPI StdMarshalCF_AddRef(LPCLASSFACTORY iface)
2000 {
2001     return 2; /* non-heap based object */
2002 }
2003 
2004 static ULONG WINAPI StdMarshalCF_Release(LPCLASSFACTORY iface)
2005 {
2006     return 1; /* non-heap based object */
2007 }
2008 
2009 static HRESULT WINAPI StdMarshalCF_CreateInstance(LPCLASSFACTORY iface,
2010     LPUNKNOWN pUnk, REFIID riid, LPVOID *ppv)
2011 {
2012     if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IMarshal))
2013         return StdMarshalImpl_Construct(riid, 0, NULL, ppv);
2014 
2015     FIXME("(%s), not supported.\n",debugstr_guid(riid));
2016     return E_NOINTERFACE;
2017 }
2018 
2019 static HRESULT WINAPI StdMarshalCF_LockServer(LPCLASSFACTORY iface, BOOL fLock)
2020 {
2021     FIXME("(%d), stub!\n",fLock);
2022     return S_OK;
2023 }
2024 
2025 static const IClassFactoryVtbl StdMarshalCFVtbl =
2026 {
2027     StdMarshalCF_QueryInterface,
2028     StdMarshalCF_AddRef,
2029     StdMarshalCF_Release,
2030     StdMarshalCF_CreateInstance,
2031     StdMarshalCF_LockServer
2032 };
2033 static const IClassFactoryVtbl *StdMarshalCF = &StdMarshalCFVtbl;
2034 
2035 HRESULT MARSHAL_GetStandardMarshalCF(LPVOID *ppv)
2036 {
2037     *ppv = &StdMarshalCF;
2038     return S_OK;
2039 }
2040 
2041 /***********************************************************************
2042  *		CoMarshalHresult	[OLE32.@]
2043  *
2044  * Marshals an HRESULT value into a stream.
2045  *
2046  * PARAMS
2047  *  pStm    [I] Stream that hresult will be marshalled into.
2048  *  hresult [I] HRESULT to be marshalled.
2049  *
2050  * RETURNS
2051  *  Success: S_OK
2052  *  Failure: A COM error code
2053  *
2054  * SEE ALSO
2055  *  CoUnmarshalHresult().
2056  */
2057 HRESULT WINAPI CoMarshalHresult(LPSTREAM pStm, HRESULT hresult)
2058 {
2059     return IStream_Write(pStm, &hresult, sizeof(hresult), NULL);
2060 }
2061 
2062 /***********************************************************************
2063  *		CoUnmarshalHresult	[OLE32.@]
2064  *
2065  * Unmarshals an HRESULT value from a stream.
2066  *
2067  * PARAMS
2068  *  pStm     [I] Stream that hresult will be unmarshalled from.
2069  *  phresult [I] Pointer to HRESULT where the value will be unmarshalled to.
2070  *
2071  * RETURNS
2072  *  Success: S_OK
2073  *  Failure: A COM error code
2074  *
2075  * SEE ALSO
2076  *  CoMarshalHresult().
2077  */
2078 HRESULT WINAPI CoUnmarshalHresult(LPSTREAM pStm, HRESULT * phresult)
2079 {
2080     return IStream_Read(pStm, phresult, sizeof(*phresult), NULL);
2081 }
2082