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