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