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