ole32: Cleanup IClientSecurity interface of a proxy manager.
[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         ERR("could not map object ID to stub manager, oxid=%s, oid=%s\n",
1441             wine_dbgstr_longlong(stdobjref.oxid), wine_dbgstr_longlong(stdobjref.oid));
1442         return RPC_E_INVALID_OBJREF;
1443     }
1444
1445     stub_manager_release_marshal_data(stubmgr, stdobjref.cPublicRefs, &stdobjref.ipid, stdobjref.flags & SORFP_TABLEWEAK);
1446
1447     stub_manager_int_release(stubmgr);
1448     apartment_release(apt);
1449
1450     return S_OK;
1451 }
1452
1453 static HRESULT WINAPI
1454 StdMarshalImpl_DisconnectObject(LPMARSHAL iface, DWORD dwReserved)
1455 {
1456     FIXME("(), stub!\n");
1457     return S_OK;
1458 }
1459
1460 static const IMarshalVtbl VT_StdMarshal =
1461 {
1462     StdMarshalImpl_QueryInterface,
1463     StdMarshalImpl_AddRef,
1464     StdMarshalImpl_Release,
1465     StdMarshalImpl_GetUnmarshalClass,
1466     StdMarshalImpl_GetMarshalSizeMax,
1467     StdMarshalImpl_MarshalInterface,
1468     StdMarshalImpl_UnmarshalInterface,
1469     StdMarshalImpl_ReleaseMarshalData,
1470     StdMarshalImpl_DisconnectObject
1471 };
1472
1473 static HRESULT StdMarshalImpl_Construct(REFIID riid, void** ppvObject)
1474 {
1475     StdMarshalImpl * pStdMarshal = 
1476         HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(StdMarshalImpl));
1477     if (!pStdMarshal)
1478         return E_OUTOFMEMORY;
1479     pStdMarshal->lpvtbl = &VT_StdMarshal;
1480     pStdMarshal->ref = 0;
1481     return IMarshal_QueryInterface((IMarshal*)pStdMarshal, riid, ppvObject);
1482 }
1483
1484 /***********************************************************************
1485  *              CoGetStandardMarshal    [OLE32.@]
1486  *
1487  * Gets or creates a standard marshal object.
1488  *
1489  * PARAMS
1490  *  riid          [I] Interface identifier of the pUnk object.
1491  *  pUnk          [I] Optional. Object to get the marshal object for.
1492  *  dwDestContext [I] Destination. Used to enable or disable optimizations.
1493  *  pvDestContext [I] Reserved. Must be NULL.
1494  *  mshlflags     [I] Flags affecting the marshaling process.
1495  *  ppMarshal     [O] Address where marshal object will be stored.
1496  *
1497  * RETURNS
1498  *  Success: S_OK.
1499  *  Failure: HRESULT code.
1500  *
1501  * NOTES
1502  *
1503  * The function retrieves the IMarshal object associated with an object if
1504  * that object is currently an active stub, otherwise a new marshal object is
1505  * created.
1506  */
1507 HRESULT WINAPI CoGetStandardMarshal(REFIID riid, IUnknown *pUnk,
1508                                     DWORD dwDestContext, LPVOID pvDestContext,
1509                                     DWORD mshlflags, LPMARSHAL *ppMarshal)
1510 {
1511     StdMarshalImpl *dm;
1512
1513     if (pUnk == NULL)
1514     {
1515         FIXME("(%s,NULL,%x,%p,%x,%p), unimplemented yet.\n",
1516             debugstr_guid(riid),dwDestContext,pvDestContext,mshlflags,ppMarshal);
1517         return E_NOTIMPL;
1518     }
1519     TRACE("(%s,%p,%x,%p,%x,%p)\n",
1520         debugstr_guid(riid),pUnk,dwDestContext,pvDestContext,mshlflags,ppMarshal);
1521     *ppMarshal = HeapAlloc(GetProcessHeap(),0,sizeof(StdMarshalImpl));
1522     dm = (StdMarshalImpl*) *ppMarshal;
1523     if (!dm) return E_FAIL;
1524     dm->lpvtbl          = &VT_StdMarshal;
1525     dm->ref             = 1;
1526
1527     dm->iid             = *riid;
1528     dm->dwDestContext   = dwDestContext;
1529     dm->pvDestContext   = pvDestContext;
1530     dm->mshlflags       = mshlflags;
1531     return S_OK;
1532 }
1533
1534 /***********************************************************************
1535  *              get_marshaler   [internal]
1536  *
1537  * Retrieves an IMarshal interface for an object.
1538  */
1539 static HRESULT get_marshaler(REFIID riid, IUnknown *pUnk, DWORD dwDestContext,
1540                              void *pvDestContext, DWORD mshlFlags,
1541                              LPMARSHAL *pMarshal)
1542 {
1543     HRESULT hr;
1544
1545     if (!pUnk)
1546         return E_POINTER;
1547     hr = IUnknown_QueryInterface(pUnk, &IID_IMarshal, (LPVOID*)pMarshal);
1548     if (hr != S_OK)
1549         hr = CoGetStandardMarshal(riid, pUnk, dwDestContext, pvDestContext,
1550                                   mshlFlags, pMarshal);
1551     return hr;
1552 }
1553
1554 /***********************************************************************
1555  *              get_unmarshaler_from_stream     [internal]
1556  *
1557  * Creates an IMarshal* object according to the data marshaled to the stream.
1558  * The function leaves the stream pointer at the start of the data written
1559  * to the stream by the IMarshal* object.
1560  */
1561 static HRESULT get_unmarshaler_from_stream(IStream *stream, IMarshal **marshal, IID *iid)
1562 {
1563     HRESULT hr;
1564     ULONG res;
1565     OBJREF objref;
1566
1567     /* read common OBJREF header */
1568     hr = IStream_Read(stream, &objref, FIELD_OFFSET(OBJREF, u_objref), &res);
1569     if (hr != S_OK || (res != FIELD_OFFSET(OBJREF, u_objref)))
1570     {
1571         ERR("Failed to read common OBJREF header, 0x%08x\n", hr);
1572         return STG_E_READFAULT;
1573     }
1574
1575     /* sanity check on header */
1576     if (objref.signature != OBJREF_SIGNATURE)
1577     {
1578         ERR("Bad OBJREF signature 0x%08x\n", objref.signature);
1579         return RPC_E_INVALID_OBJREF;
1580     }
1581
1582     if (iid) *iid = objref.iid;
1583
1584     /* FIXME: handler marshaling */
1585     if (objref.flags & OBJREF_STANDARD)
1586     {
1587         TRACE("Using standard unmarshaling\n");
1588         hr = StdMarshalImpl_Construct(&IID_IMarshal, (LPVOID*)marshal);
1589     }
1590     else if (objref.flags & OBJREF_CUSTOM)
1591     {
1592         ULONG custom_header_size = FIELD_OFFSET(OBJREF, u_objref.u_custom.pData) - 
1593                                    FIELD_OFFSET(OBJREF, u_objref.u_custom);
1594         TRACE("Using custom unmarshaling\n");
1595         /* read constant sized OR_CUSTOM data from stream */
1596         hr = IStream_Read(stream, &objref.u_objref.u_custom,
1597                           custom_header_size, &res);
1598         if (hr != S_OK || (res != custom_header_size))
1599         {
1600             ERR("Failed to read OR_CUSTOM header, 0x%08x\n", hr);
1601             return STG_E_READFAULT;
1602         }
1603         /* now create the marshaler specified in the stream */
1604         hr = CoCreateInstance(&objref.u_objref.u_custom.clsid, NULL,
1605                               CLSCTX_INPROC_SERVER, &IID_IMarshal,
1606                               (LPVOID*)marshal);
1607     }
1608     else
1609     {
1610         FIXME("Invalid or unimplemented marshaling type specified: %x\n",
1611             objref.flags);
1612         return RPC_E_INVALID_OBJREF;
1613     }
1614
1615     if (hr != S_OK)
1616         ERR("Failed to create marshal, 0x%08x\n", hr);
1617
1618     return hr;
1619 }
1620
1621 /***********************************************************************
1622  *              CoGetMarshalSizeMax     [OLE32.@]
1623  *
1624  * Gets the maximum amount of data that will be needed by a marshal.
1625  *
1626  * PARAMS
1627  *  pulSize       [O] Address where maximum marshal size will be stored.
1628  *  riid          [I] Identifier of the interface to marshal.
1629  *  pUnk          [I] Pointer to the object to marshal.
1630  *  dwDestContext [I] Destination. Used to enable or disable optimizations.
1631  *  pvDestContext [I] Reserved. Must be NULL.
1632  *  mshlFlags     [I] Flags that affect the marshaling. See CoMarshalInterface().
1633  *
1634  * RETURNS
1635  *  Success: S_OK.
1636  *  Failure: HRESULT code.
1637  *
1638  * SEE ALSO
1639  *  CoMarshalInterface().
1640  */
1641 HRESULT WINAPI CoGetMarshalSizeMax(ULONG *pulSize, REFIID riid, IUnknown *pUnk,
1642                                    DWORD dwDestContext, void *pvDestContext,
1643                                    DWORD mshlFlags)
1644 {
1645     HRESULT hr;
1646     LPMARSHAL pMarshal;
1647     CLSID marshaler_clsid;
1648
1649     hr = get_marshaler(riid, pUnk, dwDestContext, pvDestContext, mshlFlags, &pMarshal);
1650     if (hr != S_OK)
1651         return hr;
1652
1653     hr = IMarshal_GetUnmarshalClass(pMarshal, riid, pUnk, dwDestContext,
1654                                     pvDestContext, mshlFlags, &marshaler_clsid);
1655     if (hr != S_OK)
1656     {
1657         ERR("IMarshal::GetUnmarshalClass failed, 0x%08x\n", hr);
1658         IMarshal_Release(pMarshal);
1659         return hr;
1660     }
1661
1662     hr = IMarshal_GetMarshalSizeMax(pMarshal, riid, pUnk, dwDestContext,
1663                                     pvDestContext, mshlFlags, pulSize);
1664     if (IsEqualCLSID(&marshaler_clsid, &CLSID_DfMarshal))
1665         /* add on the size of the common header */
1666         *pulSize += FIELD_OFFSET(OBJREF, u_objref);
1667     else
1668         /* custom marshaling: add on the size of the whole OBJREF structure
1669          * like native does */
1670         *pulSize += sizeof(OBJREF);
1671
1672     IMarshal_Release(pMarshal);
1673     return hr;
1674 }
1675
1676
1677 static void dump_MSHLFLAGS(MSHLFLAGS flags)
1678 {
1679     if (flags & MSHLFLAGS_TABLESTRONG)
1680         TRACE(" MSHLFLAGS_TABLESTRONG");
1681     if (flags & MSHLFLAGS_TABLEWEAK)
1682         TRACE(" MSHLFLAGS_TABLEWEAK");
1683     if (!(flags & (MSHLFLAGS_TABLESTRONG|MSHLFLAGS_TABLEWEAK)))
1684         TRACE(" MSHLFLAGS_NORMAL");
1685     if (flags & MSHLFLAGS_NOPING)
1686         TRACE(" MSHLFLAGS_NOPING");
1687 }
1688
1689 /***********************************************************************
1690  *              CoMarshalInterface      [OLE32.@]
1691  *
1692  * Marshals an interface into a stream so that the object can then be
1693  * unmarshaled from another COM apartment and used remotely.
1694  *
1695  * PARAMS
1696  *  pStream       [I] Stream the object will be marshaled into.
1697  *  riid          [I] Identifier of the interface to marshal.
1698  *  pUnk          [I] Pointer to the object to marshal.
1699  *  dwDestContext [I] Destination. Used to enable or disable optimizations.
1700  *  pvDestContext [I] Reserved. Must be NULL.
1701  *  mshlFlags     [I] Flags that affect the marshaling. See notes.
1702  *
1703  * RETURNS
1704  *  Success: S_OK.
1705  *  Failure: HRESULT code.
1706  *
1707  * NOTES
1708  *
1709  * The mshlFlags parameter can take one or more of the following flags:
1710  *| MSHLFLAGS_NORMAL - Unmarshal once, releases stub on last proxy release.
1711  *| MSHLFLAGS_TABLESTRONG - Unmarshal many, release when CoReleaseMarshalData() called.
1712  *| MSHLFLAGS_TABLEWEAK - Unmarshal many, releases stub on last proxy release.
1713  *| MSHLFLAGS_NOPING - No automatic garbage collection (and so reduces network traffic).
1714  *
1715  * If a marshaled object is not unmarshaled, then CoReleaseMarshalData() must
1716  * be called in order to release the resources used in the marshaling.
1717  *
1718  * SEE ALSO
1719  *  CoUnmarshalInterface(), CoReleaseMarshalData().
1720  */
1721 HRESULT WINAPI CoMarshalInterface(IStream *pStream, REFIID riid, IUnknown *pUnk,
1722                                   DWORD dwDestContext, void *pvDestContext,
1723                                   DWORD mshlFlags)
1724 {
1725     HRESULT     hr;
1726     CLSID marshaler_clsid;
1727     OBJREF objref;
1728     LPMARSHAL pMarshal;
1729
1730     TRACE("(%p, %s, %p, %x, %p,", pStream, debugstr_guid(riid), pUnk,
1731         dwDestContext, pvDestContext);
1732     dump_MSHLFLAGS(mshlFlags);
1733     TRACE(")\n");
1734
1735     if (!pUnk || !pStream)
1736         return E_INVALIDARG;
1737
1738     objref.signature = OBJREF_SIGNATURE;
1739     objref.iid = *riid;
1740
1741     /* get the marshaler for the specified interface */
1742     hr = get_marshaler(riid, pUnk, dwDestContext, pvDestContext, mshlFlags, &pMarshal);
1743     if (hr != S_OK)
1744     {
1745         ERR("Failed to get marshaller, 0x%08x\n", hr);
1746         return hr;
1747     }
1748
1749     hr = IMarshal_GetUnmarshalClass(pMarshal, riid, pUnk, dwDestContext,
1750                                     pvDestContext, mshlFlags, &marshaler_clsid);
1751     if (hr != S_OK)
1752     {
1753         ERR("IMarshal::GetUnmarshalClass failed, 0x%08x\n", hr);
1754         goto cleanup;
1755     }
1756
1757     /* FIXME: implement handler marshaling too */
1758     if (IsEqualCLSID(&marshaler_clsid, &CLSID_DfMarshal))
1759     {
1760         TRACE("Using standard marshaling\n");
1761         objref.flags = OBJREF_STANDARD;
1762
1763         /* write the common OBJREF header to the stream */
1764         hr = IStream_Write(pStream, &objref, FIELD_OFFSET(OBJREF, u_objref), NULL);
1765         if (hr != S_OK)
1766         {
1767             ERR("Failed to write OBJREF header to stream, 0x%08x\n", hr);
1768             goto cleanup;
1769         }
1770     }
1771     else
1772     {
1773         TRACE("Using custom marshaling\n");
1774         objref.flags = OBJREF_CUSTOM;
1775         objref.u_objref.u_custom.clsid = marshaler_clsid;
1776         objref.u_objref.u_custom.cbExtension = 0;
1777         objref.u_objref.u_custom.size = 0;
1778         hr = IMarshal_GetMarshalSizeMax(pMarshal, riid, pUnk, dwDestContext,
1779                                         pvDestContext, mshlFlags,
1780                                         &objref.u_objref.u_custom.size);
1781         if (hr != S_OK)
1782         {
1783             ERR("Failed to get max size of marshal data, error 0x%08x\n", hr);
1784             goto cleanup;
1785         }
1786         /* write constant sized common header and OR_CUSTOM data into stream */
1787         hr = IStream_Write(pStream, &objref,
1788                           FIELD_OFFSET(OBJREF, u_objref.u_custom.pData), NULL);
1789         if (hr != S_OK)
1790         {
1791             ERR("Failed to write OR_CUSTOM header to stream with 0x%08x\n", hr);
1792             goto cleanup;
1793         }
1794     }
1795
1796     TRACE("Calling IMarshal::MarshalInterace\n");
1797     /* call helper object to do the actual marshaling */
1798     hr = IMarshal_MarshalInterface(pMarshal, pStream, riid, pUnk, dwDestContext,
1799                                    pvDestContext, mshlFlags);
1800
1801     if (hr != S_OK)
1802     {
1803         ERR("Failed to marshal the interface %s, %x\n", debugstr_guid(riid), hr);
1804         goto cleanup;
1805     }
1806
1807 cleanup:
1808     IMarshal_Release(pMarshal);
1809
1810     TRACE("completed with hr 0x%08x\n", hr);
1811     
1812     return hr;
1813 }
1814
1815 /***********************************************************************
1816  *              CoUnmarshalInterface    [OLE32.@]
1817  *
1818  * Unmarshals an object from a stream by creating a proxy to the remote
1819  * object, if necessary.
1820  *
1821  * PARAMS
1822  *
1823  *  pStream [I] Stream containing the marshaled object.
1824  *  riid    [I] Interface identifier of the object to create a proxy to.
1825  *  ppv     [O] Address where proxy will be stored.
1826  *
1827  * RETURNS
1828  *
1829  *  Success: S_OK.
1830  *  Failure: HRESULT code.
1831  *
1832  * SEE ALSO
1833  *  CoMarshalInterface().
1834  */
1835 HRESULT WINAPI CoUnmarshalInterface(IStream *pStream, REFIID riid, LPVOID *ppv)
1836 {
1837     HRESULT hr;
1838     LPMARSHAL pMarshal;
1839     IID iid;
1840     IUnknown *object;
1841
1842     TRACE("(%p, %s, %p)\n", pStream, debugstr_guid(riid), ppv);
1843
1844     if (!pStream || !ppv)
1845         return E_INVALIDARG;
1846
1847     hr = get_unmarshaler_from_stream(pStream, &pMarshal, &iid);
1848     if (hr != S_OK)
1849         return hr;
1850
1851     /* call the helper object to do the actual unmarshaling */
1852     hr = IMarshal_UnmarshalInterface(pMarshal, pStream, &iid, (LPVOID*)&object);
1853     if (hr != S_OK)
1854         ERR("IMarshal::UnmarshalInterface failed, 0x%08x\n", hr);
1855
1856     if (hr == S_OK)
1857     {
1858         /* IID_NULL means use the interface ID of the marshaled object */
1859         if (!IsEqualIID(riid, &IID_NULL) && !IsEqualIID(riid, &iid))
1860         {
1861             TRACE("requested interface != marshalled interface, additional QI needed\n");
1862             hr = IUnknown_QueryInterface(object, riid, ppv);
1863             if (hr != S_OK)
1864                 ERR("Couldn't query for interface %s, hr = 0x%08x\n",
1865                     debugstr_guid(riid), hr);
1866             IUnknown_Release(object);
1867         }
1868         else
1869         {
1870             *ppv = object;
1871         }
1872     }
1873
1874     IMarshal_Release(pMarshal);
1875
1876     TRACE("completed with hr 0x%x\n", hr);
1877     
1878     return hr;
1879 }
1880
1881 /***********************************************************************
1882  *              CoReleaseMarshalData    [OLE32.@]
1883  *
1884  * Releases resources associated with an object that has been marshaled into
1885  * a stream.
1886  *
1887  * PARAMS
1888  *
1889  *  pStream [I] The stream that the object has been marshaled into.
1890  *
1891  * RETURNS
1892  *  Success: S_OK.
1893  *  Failure: HRESULT error code.
1894  *
1895  * NOTES
1896  * 
1897  * Call this function to release resources associated with a normal or
1898  * table-weak marshal that will not be unmarshaled, and all table-strong
1899  * marshals when they are no longer needed.
1900  *
1901  * SEE ALSO
1902  *  CoMarshalInterface(), CoUnmarshalInterface().
1903  */
1904 HRESULT WINAPI CoReleaseMarshalData(IStream *pStream)
1905 {
1906     HRESULT     hr;
1907     LPMARSHAL pMarshal;
1908
1909     TRACE("(%p)\n", pStream);
1910
1911     hr = get_unmarshaler_from_stream(pStream, &pMarshal, NULL);
1912     if (hr != S_OK)
1913         return hr;
1914
1915     /* call the helper object to do the releasing of marshal data */
1916     hr = IMarshal_ReleaseMarshalData(pMarshal, pStream);
1917     if (hr != S_OK)
1918         ERR("IMarshal::ReleaseMarshalData failed with error 0x%08x\n", hr);
1919
1920     IMarshal_Release(pMarshal);
1921     return hr;
1922 }
1923
1924
1925 /***********************************************************************
1926  *              CoMarshalInterThreadInterfaceInStream   [OLE32.@]
1927  *
1928  * Marshal an interface across threads in the same process.
1929  *
1930  * PARAMS
1931  *  riid  [I] Identifier of the interface to be marshalled.
1932  *  pUnk  [I] Pointer to IUnknown-derived interface that will be marshalled.
1933  *  ppStm [O] Pointer to IStream object that is created and then used to store the marshalled interface.
1934  *
1935  * RETURNS
1936  *  Success: S_OK
1937  *  Failure: E_OUTOFMEMORY and other COM error codes
1938  *
1939  * SEE ALSO
1940  *   CoMarshalInterface(), CoUnmarshalInterface() and CoGetInterfaceAndReleaseStream()
1941  */
1942 HRESULT WINAPI CoMarshalInterThreadInterfaceInStream(
1943     REFIID riid, LPUNKNOWN pUnk, LPSTREAM * ppStm)
1944 {
1945     ULARGE_INTEGER      xpos;
1946     LARGE_INTEGER               seekto;
1947     HRESULT             hres;
1948
1949     TRACE("(%s, %p, %p)\n",debugstr_guid(riid), pUnk, ppStm);
1950
1951     hres = CreateStreamOnHGlobal(NULL, TRUE, ppStm);
1952     if (FAILED(hres)) return hres;
1953     hres = CoMarshalInterface(*ppStm, riid, pUnk, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1954
1955     if (SUCCEEDED(hres))
1956     {
1957         memset(&seekto, 0, sizeof(seekto));
1958         IStream_Seek(*ppStm, seekto, STREAM_SEEK_SET, &xpos);
1959     }
1960     else
1961     {
1962         IStream_Release(*ppStm);
1963         *ppStm = NULL;
1964     }
1965
1966     return hres;
1967 }
1968
1969 /***********************************************************************
1970  *              CoGetInterfaceAndReleaseStream  [OLE32.@]
1971  *
1972  * Unmarshalls an interface from a stream and then releases the stream.
1973  *
1974  * PARAMS
1975  *  pStm [I] Stream that contains the marshalled interface.
1976  *  riid [I] Interface identifier of the object to unmarshall.
1977  *  ppv  [O] Address of pointer where the requested interface object will be stored.
1978  *
1979  * RETURNS
1980  *  Success: S_OK
1981  *  Failure: A COM error code
1982  *
1983  * SEE ALSO
1984  *  CoMarshalInterThreadInterfaceInStream() and CoUnmarshalInterface()
1985  */
1986 HRESULT WINAPI CoGetInterfaceAndReleaseStream(LPSTREAM pStm, REFIID riid,
1987                                               LPVOID *ppv)
1988 {
1989     HRESULT hres;
1990
1991     TRACE("(%p, %s, %p)\n", pStm, debugstr_guid(riid), ppv);
1992
1993     if(!pStm) return E_INVALIDARG;
1994     hres = CoUnmarshalInterface(pStm, riid, ppv);
1995     IStream_Release(pStm);
1996     return hres;
1997 }
1998
1999 static HRESULT WINAPI StdMarshalCF_QueryInterface(LPCLASSFACTORY iface,
2000                                                   REFIID riid, LPVOID *ppv)
2001 {
2002     *ppv = NULL;
2003     if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IClassFactory))
2004     {
2005         *ppv = iface;
2006         return S_OK;
2007     }
2008     return E_NOINTERFACE;
2009 }
2010
2011 static ULONG WINAPI StdMarshalCF_AddRef(LPCLASSFACTORY iface)
2012 {
2013     return 2; /* non-heap based object */
2014 }
2015
2016 static ULONG WINAPI StdMarshalCF_Release(LPCLASSFACTORY iface)
2017 {
2018     return 1; /* non-heap based object */
2019 }
2020
2021 static HRESULT WINAPI StdMarshalCF_CreateInstance(LPCLASSFACTORY iface,
2022     LPUNKNOWN pUnk, REFIID riid, LPVOID *ppv)
2023 {
2024     if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IMarshal))
2025         return StdMarshalImpl_Construct(riid, ppv);
2026
2027     FIXME("(%s), not supported.\n",debugstr_guid(riid));
2028     return E_NOINTERFACE;
2029 }
2030
2031 static HRESULT WINAPI StdMarshalCF_LockServer(LPCLASSFACTORY iface, BOOL fLock)
2032 {
2033     FIXME("(%d), stub!\n",fLock);
2034     return S_OK;
2035 }
2036
2037 static const IClassFactoryVtbl StdMarshalCFVtbl =
2038 {
2039     StdMarshalCF_QueryInterface,
2040     StdMarshalCF_AddRef,
2041     StdMarshalCF_Release,
2042     StdMarshalCF_CreateInstance,
2043     StdMarshalCF_LockServer
2044 };
2045 static const IClassFactoryVtbl *StdMarshalCF = &StdMarshalCFVtbl;
2046
2047 HRESULT MARSHAL_GetStandardMarshalCF(LPVOID *ppv)
2048 {
2049     *ppv = &StdMarshalCF;
2050     return S_OK;
2051 }
2052
2053 /***********************************************************************
2054  *              CoMarshalHresult        [OLE32.@]
2055  *
2056  * Marshals an HRESULT value into a stream.
2057  *
2058  * PARAMS
2059  *  pStm    [I] Stream that hresult will be marshalled into.
2060  *  hresult [I] HRESULT to be marshalled.
2061  *
2062  * RETURNS
2063  *  Success: S_OK
2064  *  Failure: A COM error code
2065  *
2066  * SEE ALSO
2067  *  CoUnmarshalHresult().
2068  */
2069 HRESULT WINAPI CoMarshalHresult(LPSTREAM pStm, HRESULT hresult)
2070 {
2071     return IStream_Write(pStm, &hresult, sizeof(hresult), NULL);
2072 }
2073
2074 /***********************************************************************
2075  *              CoUnmarshalHresult      [OLE32.@]
2076  *
2077  * Unmarshals an HRESULT value from a stream.
2078  *
2079  * PARAMS
2080  *  pStm     [I] Stream that hresult will be unmarshalled from.
2081  *  phresult [I] Pointer to HRESULT where the value will be unmarshalled to.
2082  *
2083  * RETURNS
2084  *  Success: S_OK
2085  *  Failure: A COM error code
2086  *
2087  * SEE ALSO
2088  *  CoMarshalHresult().
2089  */
2090 HRESULT WINAPI CoUnmarshalHresult(LPSTREAM pStm, HRESULT * phresult)
2091 {
2092     return IStream_Read(pStm, phresult, sizeof(*phresult), NULL);
2093 }