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