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