winealsa: Use "default" as the default card name instead of "default:0".
[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 | WINE_CLSCTX_DONT_HOST,
80         NULL, &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 (SUCCEEDED(hr))
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             /* be careful of a race with ClientIdentity_Release, which would
1101              * cause us to return a proxy which is in the process of being
1102              * destroyed */
1103             if (ClientIdentity_AddRef((IMultiQI *)&proxy->lpVtbl) != 0)
1104             {
1105                 *proxy_found = proxy;
1106                 found = TRUE;
1107                 break;
1108             }
1109         }
1110     }
1111     LeaveCriticalSection(&apt->cs);
1112     return found;
1113 }
1114
1115 HRESULT apartment_disconnectproxies(struct apartment *apt)
1116 {
1117     struct list * cursor;
1118
1119     LIST_FOR_EACH(cursor, &apt->proxies)
1120     {
1121         struct proxy_manager * proxy = LIST_ENTRY(cursor, struct proxy_manager, entry);
1122         proxy_manager_disconnect(proxy);
1123     }
1124
1125     return S_OK;
1126 }
1127
1128 /********************** StdMarshal implementation ****************************/
1129 typedef struct _StdMarshalImpl
1130 {
1131     const IMarshalVtbl  *lpvtbl;
1132     LONG                ref;
1133
1134     IID                 iid;
1135     DWORD               dwDestContext;
1136     LPVOID              pvDestContext;
1137     DWORD               mshlflags;
1138 } StdMarshalImpl;
1139
1140 static HRESULT WINAPI 
1141 StdMarshalImpl_QueryInterface(LPMARSHAL iface, REFIID riid, LPVOID *ppv)
1142 {
1143     *ppv = NULL;
1144     if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IMarshal, riid))
1145     {
1146         *ppv = iface;
1147         IUnknown_AddRef(iface);
1148         return S_OK;
1149     }
1150     FIXME("No interface for %s.\n", debugstr_guid(riid));
1151     return E_NOINTERFACE;
1152 }
1153
1154 static ULONG WINAPI
1155 StdMarshalImpl_AddRef(LPMARSHAL iface)
1156 {
1157     StdMarshalImpl *This = (StdMarshalImpl *)iface;
1158     return InterlockedIncrement(&This->ref);
1159 }
1160
1161 static ULONG WINAPI
1162 StdMarshalImpl_Release(LPMARSHAL iface)
1163 {
1164     StdMarshalImpl *This = (StdMarshalImpl *)iface;
1165     ULONG ref = InterlockedDecrement(&This->ref);
1166
1167     if (!ref) HeapFree(GetProcessHeap(),0,This);
1168     return ref;
1169 }
1170
1171 static HRESULT WINAPI
1172 StdMarshalImpl_GetUnmarshalClass(
1173     LPMARSHAL iface, REFIID riid, void* pv, DWORD dwDestContext,
1174     void* pvDestContext, DWORD mshlflags, CLSID* pCid)
1175 {
1176     *pCid = CLSID_DfMarshal;
1177     return S_OK;
1178 }
1179
1180 static HRESULT WINAPI
1181 StdMarshalImpl_GetMarshalSizeMax(
1182     LPMARSHAL iface, REFIID riid, void* pv, DWORD dwDestContext,
1183     void* pvDestContext, DWORD mshlflags, DWORD* pSize)
1184 {
1185     *pSize = sizeof(STDOBJREF);
1186     return S_OK;
1187 }
1188
1189 static HRESULT WINAPI
1190 StdMarshalImpl_MarshalInterface(
1191     LPMARSHAL iface, IStream *pStm,REFIID riid, void* pv, DWORD dwDestContext,
1192     void* pvDestContext, DWORD mshlflags)
1193 {
1194     STDOBJREF             stdobjref;
1195     ULONG                 res;
1196     HRESULT               hres;
1197     APARTMENT            *apt = COM_CurrentApt();
1198
1199     TRACE("(...,%s,...)\n", debugstr_guid(riid));
1200
1201     if (!apt)
1202     {
1203         ERR("Apartment not initialized\n");
1204         return CO_E_NOTINITIALIZED;
1205     }
1206
1207     /* make sure this apartment can be reached from other threads / processes */
1208     RPC_StartRemoting(apt);
1209
1210     hres = marshal_object(apt, &stdobjref, riid, (IUnknown *)pv, mshlflags);
1211     if (hres)
1212     {
1213         ERR("Failed to create ifstub, hres=0x%x\n", hres);
1214         return hres;
1215     }
1216
1217     hres = IStream_Write(pStm, &stdobjref, sizeof(stdobjref), &res);
1218     if (hres) return hres;
1219
1220     return S_OK;
1221 }
1222
1223 /* helper for StdMarshalImpl_UnmarshalInterface - does the unmarshaling with
1224  * no questions asked about the rules surrounding same-apartment unmarshals
1225  * and table marshaling */
1226 static HRESULT unmarshal_object(const STDOBJREF *stdobjref, APARTMENT *apt,
1227                                 MSHCTX dest_context, void *dest_context_data,
1228                                 REFIID riid, const OXID_INFO *oxid_info,
1229                                 void **object)
1230 {
1231     struct proxy_manager *proxy_manager = NULL;
1232     HRESULT hr = S_OK;
1233
1234     assert(apt);
1235
1236     TRACE("stdobjref:\n\tflags = %04lx\n\tcPublicRefs = %ld\n\toxid = %s\n\toid = %s\n\tipid = %s\n",
1237         stdobjref->flags, stdobjref->cPublicRefs,
1238         wine_dbgstr_longlong(stdobjref->oxid),
1239         wine_dbgstr_longlong(stdobjref->oid),
1240         debugstr_guid(&stdobjref->ipid));
1241
1242     /* create a new proxy manager if one doesn't already exist for the
1243      * object */
1244     if (!find_proxy_manager(apt, stdobjref->oxid, stdobjref->oid, &proxy_manager))
1245     {
1246         hr = proxy_manager_construct(apt, stdobjref->flags,
1247                                      stdobjref->oxid, stdobjref->oid, oxid_info,
1248                                      &proxy_manager);
1249     }
1250     else
1251         TRACE("proxy manager already created, using\n");
1252
1253     if (hr == S_OK)
1254     {
1255         struct ifproxy * ifproxy;
1256
1257         proxy_manager_set_context(proxy_manager, dest_context, dest_context_data);
1258
1259         hr = proxy_manager_find_ifproxy(proxy_manager, riid, &ifproxy);
1260         if (hr == E_NOINTERFACE)
1261         {
1262             IRpcChannelBuffer *chanbuf;
1263             hr = RPC_CreateClientChannel(&stdobjref->oxid, &stdobjref->ipid,
1264                                          &proxy_manager->oxid_info,
1265                                          proxy_manager->dest_context,
1266                                          proxy_manager->dest_context_data,
1267                                          &chanbuf);
1268             if (hr == S_OK)
1269                 hr = proxy_manager_create_ifproxy(proxy_manager, stdobjref,
1270                                                   riid, chanbuf, &ifproxy);
1271         }
1272         else
1273             IUnknown_AddRef((IUnknown *)ifproxy->iface);
1274
1275         if (hr == S_OK)
1276         {
1277             InterlockedExchangeAdd((LONG *)&ifproxy->refs, stdobjref->cPublicRefs);
1278             /* get at least one external reference to the object to keep it alive */
1279             hr = ifproxy_get_public_ref(ifproxy);
1280             if (FAILED(hr))
1281                 ifproxy_destroy(ifproxy);
1282         }
1283
1284         if (hr == S_OK)
1285             *object = ifproxy->iface;
1286     }
1287
1288     /* release our reference to the proxy manager - the client/apartment
1289      * will hold on to the remaining reference for us */
1290     if (proxy_manager) ClientIdentity_Release((IMultiQI*)&proxy_manager->lpVtbl);
1291
1292     return hr;
1293 }
1294
1295 static HRESULT WINAPI
1296 StdMarshalImpl_UnmarshalInterface(LPMARSHAL iface, IStream *pStm, REFIID riid, void **ppv)
1297 {
1298     StdMarshalImpl *This = (StdMarshalImpl *)iface;
1299     struct stub_manager *stubmgr = NULL;
1300     STDOBJREF stdobjref;
1301     ULONG res;
1302     HRESULT hres;
1303     APARTMENT *apt = COM_CurrentApt();
1304     APARTMENT *stub_apt;
1305     OXID oxid;
1306
1307     TRACE("(...,%s,....)\n", debugstr_guid(riid));
1308
1309     /* we need an apartment to unmarshal into */
1310     if (!apt)
1311     {
1312         ERR("Apartment not initialized\n");
1313         return CO_E_NOTINITIALIZED;
1314     }
1315
1316     /* read STDOBJREF from wire */
1317     hres = IStream_Read(pStm, &stdobjref, sizeof(stdobjref), &res);
1318     if (hres) return STG_E_READFAULT;
1319
1320     hres = apartment_getoxid(apt, &oxid);
1321     if (hres) return hres;
1322
1323     /* check if we're marshalling back to ourselves */
1324     if ((oxid == stdobjref.oxid) && (stubmgr = get_stub_manager(apt, stdobjref.oid)))
1325     {
1326         TRACE("Unmarshalling object marshalled in same apartment for iid %s, "
1327               "returning original object %p\n", debugstr_guid(riid), stubmgr->object);
1328     
1329         hres = IUnknown_QueryInterface(stubmgr->object, riid, ppv);
1330       
1331         /* unref the ifstub. FIXME: only do this on success? */
1332         if (!stub_manager_is_table_marshaled(stubmgr, &stdobjref.ipid))
1333             stub_manager_ext_release(stubmgr, stdobjref.cPublicRefs, TRUE);
1334
1335         stub_manager_int_release(stubmgr);
1336         return hres;
1337     }
1338
1339     /* notify stub manager about unmarshal if process-local object.
1340      * note: if the oxid is not found then we and native will quite happily
1341      * ignore table marshaling and normal marshaling rules regarding number of
1342      * unmarshals, etc, but if you abuse these rules then your proxy could end
1343      * up returning RPC_E_DISCONNECTED. */
1344     if ((stub_apt = apartment_findfromoxid(stdobjref.oxid, TRUE)))
1345     {
1346         if ((stubmgr = get_stub_manager(stub_apt, stdobjref.oid)))
1347         {
1348             if (!stub_manager_notify_unmarshal(stubmgr, &stdobjref.ipid))
1349                 hres = CO_E_OBJNOTCONNECTED;
1350         }
1351         else
1352         {
1353             WARN("Couldn't find object for OXID %s, OID %s, assuming disconnected\n",
1354                 wine_dbgstr_longlong(stdobjref.oxid),
1355                 wine_dbgstr_longlong(stdobjref.oid));
1356             hres = CO_E_OBJNOTCONNECTED;
1357         }
1358     }
1359     else
1360         TRACE("Treating unmarshal from OXID %s as inter-process\n",
1361             wine_dbgstr_longlong(stdobjref.oxid));
1362
1363     if (hres == S_OK)
1364         hres = unmarshal_object(&stdobjref, apt, This->dwDestContext,
1365                                 This->pvDestContext, riid,
1366                                 stubmgr ? &stubmgr->oxid_info : NULL, ppv);
1367
1368     if (stubmgr) stub_manager_int_release(stubmgr);
1369     if (stub_apt) apartment_release(stub_apt);
1370
1371     if (hres) WARN("Failed with error 0x%08x\n", hres);
1372     else TRACE("Successfully created proxy %p\n", *ppv);
1373
1374     return hres;
1375 }
1376
1377 static HRESULT WINAPI
1378 StdMarshalImpl_ReleaseMarshalData(LPMARSHAL iface, IStream *pStm)
1379 {
1380     STDOBJREF            stdobjref;
1381     ULONG                res;
1382     HRESULT              hres;
1383     struct stub_manager *stubmgr;
1384     APARTMENT           *apt;
1385
1386     TRACE("iface=%p, pStm=%p\n", iface, pStm);
1387     
1388     hres = IStream_Read(pStm, &stdobjref, sizeof(stdobjref), &res);
1389     if (hres) return STG_E_READFAULT;
1390
1391     TRACE("oxid = %s, oid = %s, ipid = %s\n",
1392         wine_dbgstr_longlong(stdobjref.oxid),
1393         wine_dbgstr_longlong(stdobjref.oid),
1394         wine_dbgstr_guid(&stdobjref.ipid));
1395
1396     if (!(apt = apartment_findfromoxid(stdobjref.oxid, TRUE)))
1397     {
1398         WARN("Could not map OXID %s to apartment object\n",
1399             wine_dbgstr_longlong(stdobjref.oxid));
1400         return RPC_E_INVALID_OBJREF;
1401     }
1402
1403     if (!(stubmgr = get_stub_manager(apt, stdobjref.oid)))
1404     {
1405         ERR("could not map object ID to stub manager, oxid=%s, oid=%s\n",
1406             wine_dbgstr_longlong(stdobjref.oxid), wine_dbgstr_longlong(stdobjref.oid));
1407         return RPC_E_INVALID_OBJREF;
1408     }
1409
1410     stub_manager_release_marshal_data(stubmgr, stdobjref.cPublicRefs, &stdobjref.ipid);
1411
1412     stub_manager_int_release(stubmgr);
1413     apartment_release(apt);
1414
1415     return S_OK;
1416 }
1417
1418 static HRESULT WINAPI
1419 StdMarshalImpl_DisconnectObject(LPMARSHAL iface, DWORD dwReserved)
1420 {
1421     FIXME("(), stub!\n");
1422     return S_OK;
1423 }
1424
1425 static const IMarshalVtbl VT_StdMarshal =
1426 {
1427     StdMarshalImpl_QueryInterface,
1428     StdMarshalImpl_AddRef,
1429     StdMarshalImpl_Release,
1430     StdMarshalImpl_GetUnmarshalClass,
1431     StdMarshalImpl_GetMarshalSizeMax,
1432     StdMarshalImpl_MarshalInterface,
1433     StdMarshalImpl_UnmarshalInterface,
1434     StdMarshalImpl_ReleaseMarshalData,
1435     StdMarshalImpl_DisconnectObject
1436 };
1437
1438 static HRESULT StdMarshalImpl_Construct(REFIID riid, void** ppvObject)
1439 {
1440     StdMarshalImpl * pStdMarshal = 
1441         HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(StdMarshalImpl));
1442     if (!pStdMarshal)
1443         return E_OUTOFMEMORY;
1444     pStdMarshal->lpvtbl = &VT_StdMarshal;
1445     pStdMarshal->ref = 0;
1446     return IMarshal_QueryInterface((IMarshal*)pStdMarshal, riid, ppvObject);
1447 }
1448
1449 /***********************************************************************
1450  *              CoGetStandardMarshal    [OLE32.@]
1451  *
1452  * Gets or creates a standard marshal object.
1453  *
1454  * PARAMS
1455  *  riid          [I] Interface identifier of the pUnk object.
1456  *  pUnk          [I] Optional. Object to get the marshal object for.
1457  *  dwDestContext [I] Destination. Used to enable or disable optimizations.
1458  *  pvDestContext [I] Reserved. Must be NULL.
1459  *  mshlflags     [I] Flags affecting the marshaling process.
1460  *  ppMarshal     [O] Address where marshal object will be stored.
1461  *
1462  * RETURNS
1463  *  Success: S_OK.
1464  *  Failure: HRESULT code.
1465  *
1466  * NOTES
1467  *
1468  * The function retrieves the IMarshal object associated with an object if
1469  * that object is currently an active stub, otherwise a new marshal object is
1470  * created.
1471  */
1472 HRESULT WINAPI CoGetStandardMarshal(REFIID riid, IUnknown *pUnk,
1473                                     DWORD dwDestContext, LPVOID pvDestContext,
1474                                     DWORD mshlflags, LPMARSHAL *ppMarshal)
1475 {
1476     StdMarshalImpl *dm;
1477
1478     if (pUnk == NULL)
1479     {
1480         FIXME("(%s,NULL,%x,%p,%x,%p), unimplemented yet.\n",
1481             debugstr_guid(riid),dwDestContext,pvDestContext,mshlflags,ppMarshal);
1482         return E_NOTIMPL;
1483     }
1484     TRACE("(%s,%p,%x,%p,%x,%p)\n",
1485         debugstr_guid(riid),pUnk,dwDestContext,pvDestContext,mshlflags,ppMarshal);
1486     *ppMarshal = HeapAlloc(GetProcessHeap(),0,sizeof(StdMarshalImpl));
1487     dm = (StdMarshalImpl*) *ppMarshal;
1488     if (!dm) return E_FAIL;
1489     dm->lpvtbl          = &VT_StdMarshal;
1490     dm->ref             = 1;
1491
1492     dm->iid             = *riid;
1493     dm->dwDestContext   = dwDestContext;
1494     dm->pvDestContext   = pvDestContext;
1495     dm->mshlflags       = mshlflags;
1496     return S_OK;
1497 }
1498
1499 /***********************************************************************
1500  *              get_marshaler   [internal]
1501  *
1502  * Retrieves an IMarshal interface for an object.
1503  */
1504 static HRESULT get_marshaler(REFIID riid, IUnknown *pUnk, DWORD dwDestContext,
1505                              void *pvDestContext, DWORD mshlFlags,
1506                              LPMARSHAL *pMarshal)
1507 {
1508     HRESULT hr;
1509
1510     if (!pUnk)
1511         return E_POINTER;
1512     hr = IUnknown_QueryInterface(pUnk, &IID_IMarshal, (LPVOID*)pMarshal);
1513     if (hr)
1514         hr = CoGetStandardMarshal(riid, pUnk, dwDestContext, pvDestContext,
1515                                   mshlFlags, pMarshal);
1516     return hr;
1517 }
1518
1519 /***********************************************************************
1520  *              get_unmarshaler_from_stream     [internal]
1521  *
1522  * Creates an IMarshal* object according to the data marshaled to the stream.
1523  * The function leaves the stream pointer at the start of the data written
1524  * to the stream by the IMarshal* object.
1525  */
1526 static HRESULT get_unmarshaler_from_stream(IStream *stream, IMarshal **marshal, IID *iid)
1527 {
1528     HRESULT hr;
1529     ULONG res;
1530     OBJREF objref;
1531
1532     /* read common OBJREF header */
1533     hr = IStream_Read(stream, &objref, FIELD_OFFSET(OBJREF, u_objref), &res);
1534     if (hr || (res != FIELD_OFFSET(OBJREF, u_objref)))
1535     {
1536         ERR("Failed to read common OBJREF header, 0x%08x\n", hr);
1537         return STG_E_READFAULT;
1538     }
1539
1540     /* sanity check on header */
1541     if (objref.signature != OBJREF_SIGNATURE)
1542     {
1543         ERR("Bad OBJREF signature 0x%08lx\n", objref.signature);
1544         return RPC_E_INVALID_OBJREF;
1545     }
1546
1547     if (iid) *iid = objref.iid;
1548
1549     /* FIXME: handler marshaling */
1550     if (objref.flags & OBJREF_STANDARD)
1551     {
1552         TRACE("Using standard unmarshaling\n");
1553         hr = StdMarshalImpl_Construct(&IID_IMarshal, (LPVOID*)marshal);
1554     }
1555     else if (objref.flags & OBJREF_CUSTOM)
1556     {
1557         ULONG custom_header_size = FIELD_OFFSET(OBJREF, u_objref.u_custom.pData) - 
1558                                    FIELD_OFFSET(OBJREF, u_objref.u_custom);
1559         TRACE("Using custom unmarshaling\n");
1560         /* read constant sized OR_CUSTOM data from stream */
1561         hr = IStream_Read(stream, &objref.u_objref.u_custom,
1562                           custom_header_size, &res);
1563         if (hr || (res != custom_header_size))
1564         {
1565             ERR("Failed to read OR_CUSTOM header, 0x%08x\n", hr);
1566             return STG_E_READFAULT;
1567         }
1568         /* now create the marshaler specified in the stream */
1569         hr = CoCreateInstance(&objref.u_objref.u_custom.clsid, NULL,
1570                               CLSCTX_INPROC_SERVER, &IID_IMarshal,
1571                               (LPVOID*)marshal);
1572     }
1573     else
1574     {
1575         FIXME("Invalid or unimplemented marshaling type specified: %lx\n",
1576             objref.flags);
1577         return RPC_E_INVALID_OBJREF;
1578     }
1579
1580     if (hr)
1581         ERR("Failed to create marshal, 0x%08x\n", hr);
1582
1583     return hr;
1584 }
1585
1586 /***********************************************************************
1587  *              CoGetMarshalSizeMax     [OLE32.@]
1588  *
1589  * Gets the maximum amount of data that will be needed by a marshal.
1590  *
1591  * PARAMS
1592  *  pulSize       [O] Address where maximum marshal size will be stored.
1593  *  riid          [I] Identifier of the interface to marshal.
1594  *  pUnk          [I] Pointer to the object to marshal.
1595  *  dwDestContext [I] Destination. Used to enable or disable optimizations.
1596  *  pvDestContext [I] Reserved. Must be NULL.
1597  *  mshlFlags     [I] Flags that affect the marshaling. See CoMarshalInterface().
1598  *
1599  * RETURNS
1600  *  Success: S_OK.
1601  *  Failure: HRESULT code.
1602  *
1603  * SEE ALSO
1604  *  CoMarshalInterface().
1605  */
1606 HRESULT WINAPI CoGetMarshalSizeMax(ULONG *pulSize, REFIID riid, IUnknown *pUnk,
1607                                    DWORD dwDestContext, void *pvDestContext,
1608                                    DWORD mshlFlags)
1609 {
1610     HRESULT hr;
1611     LPMARSHAL pMarshal;
1612     CLSID marshaler_clsid;
1613
1614     hr = get_marshaler(riid, pUnk, dwDestContext, pvDestContext, mshlFlags, &pMarshal);
1615     if (hr)
1616         return hr;
1617
1618     hr = IMarshal_GetUnmarshalClass(pMarshal, riid, pUnk, dwDestContext,
1619                                     pvDestContext, mshlFlags, &marshaler_clsid);
1620     if (hr)
1621     {
1622         ERR("IMarshal::GetUnmarshalClass failed, 0x%08x\n", hr);
1623         IMarshal_Release(pMarshal);
1624         return hr;
1625     }
1626
1627     hr = IMarshal_GetMarshalSizeMax(pMarshal, riid, pUnk, dwDestContext,
1628                                     pvDestContext, mshlFlags, pulSize);
1629     if (IsEqualCLSID(&marshaler_clsid, &CLSID_DfMarshal))
1630         /* add on the size of the common header */
1631         *pulSize += FIELD_OFFSET(OBJREF, u_objref);
1632     else
1633         /* custom marshaling: add on the size of the whole OBJREF structure
1634          * like native does */
1635         *pulSize += sizeof(OBJREF);
1636
1637     IMarshal_Release(pMarshal);
1638     return hr;
1639 }
1640
1641
1642 static void dump_MSHLFLAGS(MSHLFLAGS flags)
1643 {
1644     if (flags & MSHLFLAGS_TABLESTRONG)
1645         TRACE(" MSHLFLAGS_TABLESTRONG");
1646     if (flags & MSHLFLAGS_TABLEWEAK)
1647         TRACE(" MSHLFLAGS_TABLEWEAK");
1648     if (!(flags & (MSHLFLAGS_TABLESTRONG|MSHLFLAGS_TABLEWEAK)))
1649         TRACE(" MSHLFLAGS_NORMAL");
1650     if (flags & MSHLFLAGS_NOPING)
1651         TRACE(" MSHLFLAGS_NOPING");
1652 }
1653
1654 /***********************************************************************
1655  *              CoMarshalInterface      [OLE32.@]
1656  *
1657  * Marshals an interface into a stream so that the object can then be
1658  * unmarshaled from another COM apartment and used remotely.
1659  *
1660  * PARAMS
1661  *  pStream       [I] Stream the object will be marshaled into.
1662  *  riid          [I] Identifier of the interface to marshal.
1663  *  pUnk          [I] Pointer to the object to marshal.
1664  *  dwDestContext [I] Destination. Used to enable or disable optimizations.
1665  *  pvDestContext [I] Reserved. Must be NULL.
1666  *  mshlFlags     [I] Flags that affect the marshaling. See notes.
1667  *
1668  * RETURNS
1669  *  Success: S_OK.
1670  *  Failure: HRESULT code.
1671  *
1672  * NOTES
1673  *
1674  * The mshlFlags parameter can take one or more of the following flags:
1675  *| MSHLFLAGS_NORMAL - Unmarshal once, releases stub on last proxy release.
1676  *| MSHLFLAGS_TABLESTRONG - Unmarshal many, release when CoReleaseMarshalData() called.
1677  *| MSHLFLAGS_TABLEWEAK - Unmarshal many, releases stub on last proxy release.
1678  *| MSHLFLAGS_NOPING - No automatic garbage collection (and so reduces network traffic).
1679  *
1680  * If a marshaled object is not unmarshaled, then CoReleaseMarshalData() must
1681  * be called in order to release the resources used in the marshaling.
1682  *
1683  * SEE ALSO
1684  *  CoUnmarshalInterface(), CoReleaseMarshalData().
1685  */
1686 HRESULT WINAPI CoMarshalInterface(IStream *pStream, REFIID riid, IUnknown *pUnk,
1687                                   DWORD dwDestContext, void *pvDestContext,
1688                                   DWORD mshlFlags)
1689 {
1690     HRESULT     hr;
1691     CLSID marshaler_clsid;
1692     OBJREF objref;
1693     LPMARSHAL pMarshal;
1694
1695     TRACE("(%p, %s, %p, %x, %p,", pStream, debugstr_guid(riid), pUnk,
1696         dwDestContext, pvDestContext);
1697     dump_MSHLFLAGS(mshlFlags);
1698     TRACE(")\n");
1699
1700     if (!pUnk || !pStream)
1701         return E_INVALIDARG;
1702
1703     objref.signature = OBJREF_SIGNATURE;
1704     objref.iid = *riid;
1705
1706     /* get the marshaler for the specified interface */
1707     hr = get_marshaler(riid, pUnk, dwDestContext, pvDestContext, mshlFlags, &pMarshal);
1708     if (hr)
1709     {
1710         ERR("Failed to get marshaller, 0x%08x\n", hr);
1711         return hr;
1712     }
1713
1714     hr = IMarshal_GetUnmarshalClass(pMarshal, riid, pUnk, dwDestContext,
1715                                     pvDestContext, mshlFlags, &marshaler_clsid);
1716     if (hr)
1717     {
1718         ERR("IMarshal::GetUnmarshalClass failed, 0x%08x\n", hr);
1719         goto cleanup;
1720     }
1721
1722     /* FIXME: implement handler marshaling too */
1723     if (IsEqualCLSID(&marshaler_clsid, &CLSID_DfMarshal))
1724     {
1725         TRACE("Using standard marshaling\n");
1726         objref.flags = OBJREF_STANDARD;
1727
1728         /* write the common OBJREF header to the stream */
1729         hr = IStream_Write(pStream, &objref, FIELD_OFFSET(OBJREF, u_objref), NULL);
1730         if (hr)
1731         {
1732             ERR("Failed to write OBJREF header to stream, 0x%08x\n", hr);
1733             goto cleanup;
1734         }
1735     }
1736     else
1737     {
1738         TRACE("Using custom marshaling\n");
1739         objref.flags = OBJREF_CUSTOM;
1740         objref.u_objref.u_custom.clsid = marshaler_clsid;
1741         objref.u_objref.u_custom.cbExtension = 0;
1742         objref.u_objref.u_custom.size = 0;
1743         hr = IMarshal_GetMarshalSizeMax(pMarshal, riid, pUnk, dwDestContext,
1744                                         pvDestContext, mshlFlags,
1745                                         &objref.u_objref.u_custom.size);
1746         if (hr)
1747         {
1748             ERR("Failed to get max size of marshal data, error 0x%08x\n", hr);
1749             goto cleanup;
1750         }
1751         /* write constant sized common header and OR_CUSTOM data into stream */
1752         hr = IStream_Write(pStream, &objref,
1753                           FIELD_OFFSET(OBJREF, u_objref.u_custom.pData), NULL);
1754         if (hr)
1755         {
1756             ERR("Failed to write OR_CUSTOM header to stream with 0x%08x\n", hr);
1757             goto cleanup;
1758         }
1759     }
1760
1761     TRACE("Calling IMarshal::MarshalInterace\n");
1762     /* call helper object to do the actual marshaling */
1763     hr = IMarshal_MarshalInterface(pMarshal, pStream, riid, pUnk, dwDestContext,
1764                                    pvDestContext, mshlFlags);
1765
1766     if (hr)
1767     {
1768         ERR("Failed to marshal the interface %s, %x\n", debugstr_guid(riid), hr);
1769         goto cleanup;
1770     }
1771
1772 cleanup:
1773     IMarshal_Release(pMarshal);
1774
1775     TRACE("completed with hr 0x%08x\n", hr);
1776     
1777     return hr;
1778 }
1779
1780 /***********************************************************************
1781  *              CoUnmarshalInterface    [OLE32.@]
1782  *
1783  * Unmarshals an object from a stream by creating a proxy to the remote
1784  * object, if necessary.
1785  *
1786  * PARAMS
1787  *
1788  *  pStream [I] Stream containing the marshaled object.
1789  *  riid    [I] Interface identifier of the object to create a proxy to.
1790  *  ppv     [O] Address where proxy will be stored.
1791  *
1792  * RETURNS
1793  *
1794  *  Success: S_OK.
1795  *  Failure: HRESULT code.
1796  *
1797  * SEE ALSO
1798  *  CoMarshalInterface().
1799  */
1800 HRESULT WINAPI CoUnmarshalInterface(IStream *pStream, REFIID riid, LPVOID *ppv)
1801 {
1802     HRESULT hr;
1803     LPMARSHAL pMarshal;
1804     IID iid;
1805     IUnknown *object;
1806
1807     TRACE("(%p, %s, %p)\n", pStream, debugstr_guid(riid), ppv);
1808
1809     if (!pStream || !ppv)
1810         return E_INVALIDARG;
1811
1812     hr = get_unmarshaler_from_stream(pStream, &pMarshal, &iid);
1813     if (hr != S_OK)
1814         return hr;
1815
1816     /* call the helper object to do the actual unmarshaling */
1817     hr = IMarshal_UnmarshalInterface(pMarshal, pStream, &iid, (LPVOID*)&object);
1818     if (hr)
1819         ERR("IMarshal::UnmarshalInterface failed, 0x%08x\n", hr);
1820
1821     if (hr == S_OK)
1822     {
1823         /* IID_NULL means use the interface ID of the marshaled object */
1824         if (!IsEqualIID(riid, &IID_NULL) && !IsEqualIID(riid, &iid))
1825         {
1826             TRACE("requested interface != marshalled interface, additional QI needed\n");
1827             hr = IUnknown_QueryInterface(object, riid, ppv);
1828             if (hr)
1829                 ERR("Couldn't query for interface %s, hr = 0x%08x\n",
1830                     debugstr_guid(riid), hr);
1831             IUnknown_Release(object);
1832         }
1833         else
1834         {
1835             *ppv = object;
1836         }
1837     }
1838
1839     IMarshal_Release(pMarshal);
1840
1841     TRACE("completed with hr 0x%x\n", hr);
1842     
1843     return hr;
1844 }
1845
1846 /***********************************************************************
1847  *              CoReleaseMarshalData    [OLE32.@]
1848  *
1849  * Releases resources associated with an object that has been marshaled into
1850  * a stream.
1851  *
1852  * PARAMS
1853  *
1854  *  pStream [I] The stream that the object has been marshaled into.
1855  *
1856  * RETURNS
1857  *  Success: S_OK.
1858  *  Failure: HRESULT error code.
1859  *
1860  * NOTES
1861  * 
1862  * Call this function to release resources associated with a normal or
1863  * table-weak marshal that will not be unmarshaled, and all table-strong
1864  * marshals when they are no longer needed.
1865  *
1866  * SEE ALSO
1867  *  CoMarshalInterface(), CoUnmarshalInterface().
1868  */
1869 HRESULT WINAPI CoReleaseMarshalData(IStream *pStream)
1870 {
1871     HRESULT     hr;
1872     LPMARSHAL pMarshal;
1873
1874     TRACE("(%p)\n", pStream);
1875
1876     hr = get_unmarshaler_from_stream(pStream, &pMarshal, NULL);
1877     if (hr != S_OK)
1878         return hr;
1879
1880     /* call the helper object to do the releasing of marshal data */
1881     hr = IMarshal_ReleaseMarshalData(pMarshal, pStream);
1882     if (hr)
1883         ERR("IMarshal::ReleaseMarshalData failed with error 0x%08x\n", hr);
1884
1885     IMarshal_Release(pMarshal);
1886     return hr;
1887 }
1888
1889
1890 /***********************************************************************
1891  *              CoMarshalInterThreadInterfaceInStream   [OLE32.@]
1892  *
1893  * Marshal an interface across threads in the same process.
1894  *
1895  * PARAMS
1896  *  riid  [I] Identifier of the interface to be marshalled.
1897  *  pUnk  [I] Pointer to IUnknown-derived interface that will be marshalled.
1898  *  ppStm [O] Pointer to IStream object that is created and then used to store the marshalled interface.
1899  *
1900  * RETURNS
1901  *  Success: S_OK
1902  *  Failure: E_OUTOFMEMORY and other COM error codes
1903  *
1904  * SEE ALSO
1905  *   CoMarshalInterface(), CoUnmarshalInterface() and CoGetInterfaceAndReleaseStream()
1906  */
1907 HRESULT WINAPI CoMarshalInterThreadInterfaceInStream(
1908     REFIID riid, LPUNKNOWN pUnk, LPSTREAM * ppStm)
1909 {
1910     ULARGE_INTEGER      xpos;
1911     LARGE_INTEGER               seekto;
1912     HRESULT             hres;
1913
1914     TRACE("(%s, %p, %p)\n",debugstr_guid(riid), pUnk, ppStm);
1915
1916     hres = CreateStreamOnHGlobal(NULL, TRUE, ppStm);
1917     if (FAILED(hres)) return hres;
1918     hres = CoMarshalInterface(*ppStm, riid, pUnk, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1919
1920     if (SUCCEEDED(hres))
1921     {
1922         memset(&seekto, 0, sizeof(seekto));
1923         IStream_Seek(*ppStm, seekto, STREAM_SEEK_SET, &xpos);
1924     }
1925     else
1926     {
1927         IStream_Release(*ppStm);
1928         *ppStm = NULL;
1929     }
1930
1931     return hres;
1932 }
1933
1934 /***********************************************************************
1935  *              CoGetInterfaceAndReleaseStream  [OLE32.@]
1936  *
1937  * Unmarshalls an interface from a stream and then releases the stream.
1938  *
1939  * PARAMS
1940  *  pStm [I] Stream that contains the marshalled interface.
1941  *  riid [I] Interface identifier of the object to unmarshall.
1942  *  ppv  [O] Address of pointer where the requested interface object will be stored.
1943  *
1944  * RETURNS
1945  *  Success: S_OK
1946  *  Failure: A COM error code
1947  *
1948  * SEE ALSO
1949  *  CoMarshalInterThreadInterfaceInStream() and CoUnmarshalInterface()
1950  */
1951 HRESULT WINAPI CoGetInterfaceAndReleaseStream(LPSTREAM pStm, REFIID riid,
1952                                               LPVOID *ppv)
1953 {
1954     HRESULT hres;
1955
1956     TRACE("(%p, %s, %p)\n", pStm, debugstr_guid(riid), ppv);
1957
1958     if(!pStm) return E_INVALIDARG;
1959     hres = CoUnmarshalInterface(pStm, riid, ppv);
1960     IStream_Release(pStm);
1961     return hres;
1962 }
1963
1964 static HRESULT WINAPI StdMarshalCF_QueryInterface(LPCLASSFACTORY iface,
1965                                                   REFIID riid, LPVOID *ppv)
1966 {
1967     *ppv = NULL;
1968     if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IClassFactory))
1969     {
1970         *ppv = (LPVOID)iface;
1971         return S_OK;
1972     }
1973     return E_NOINTERFACE;
1974 }
1975
1976 static ULONG WINAPI StdMarshalCF_AddRef(LPCLASSFACTORY iface)
1977 {
1978     return 2; /* non-heap based object */
1979 }
1980
1981 static ULONG WINAPI StdMarshalCF_Release(LPCLASSFACTORY iface)
1982 {
1983     return 1; /* non-heap based object */
1984 }
1985
1986 static HRESULT WINAPI StdMarshalCF_CreateInstance(LPCLASSFACTORY iface,
1987     LPUNKNOWN pUnk, REFIID riid, LPVOID *ppv)
1988 {
1989     if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IMarshal))
1990         return StdMarshalImpl_Construct(riid, ppv);
1991
1992     FIXME("(%s), not supported.\n",debugstr_guid(riid));
1993     return E_NOINTERFACE;
1994 }
1995
1996 static HRESULT WINAPI StdMarshalCF_LockServer(LPCLASSFACTORY iface, BOOL fLock)
1997 {
1998     FIXME("(%d), stub!\n",fLock);
1999     return S_OK;
2000 }
2001
2002 static const IClassFactoryVtbl StdMarshalCFVtbl =
2003 {
2004     StdMarshalCF_QueryInterface,
2005     StdMarshalCF_AddRef,
2006     StdMarshalCF_Release,
2007     StdMarshalCF_CreateInstance,
2008     StdMarshalCF_LockServer
2009 };
2010 static const IClassFactoryVtbl *StdMarshalCF = &StdMarshalCFVtbl;
2011
2012 HRESULT MARSHAL_GetStandardMarshalCF(LPVOID *ppv)
2013 {
2014     *ppv = &StdMarshalCF;
2015     return S_OK;
2016 }
2017
2018 /***********************************************************************
2019  *              CoMarshalHresult        [OLE32.@]
2020  *
2021  * Marshals an HRESULT value into a stream.
2022  *
2023  * PARAMS
2024  *  pStm    [I] Stream that hresult will be marshalled into.
2025  *  hresult [I] HRESULT to be marshalled.
2026  *
2027  * RETURNS
2028  *  Success: S_OK
2029  *  Failure: A COM error code
2030  *
2031  * SEE ALSO
2032  *  CoUnmarshalHresult().
2033  */
2034 HRESULT WINAPI CoMarshalHresult(LPSTREAM pStm, HRESULT hresult)
2035 {
2036     return IStream_Write(pStm, &hresult, sizeof(hresult), NULL);
2037 }
2038
2039 /***********************************************************************
2040  *              CoUnmarshalHresult      [OLE32.@]
2041  *
2042  * Unmarshals an HRESULT value from a stream.
2043  *
2044  * PARAMS
2045  *  pStm     [I] Stream that hresult will be unmarshalled from.
2046  *  phresult [I] Pointer to HRESULT where the value will be unmarshalled to.
2047  *
2048  * RETURNS
2049  *  Success: S_OK
2050  *  Failure: A COM error code
2051  *
2052  * SEE ALSO
2053  *  CoMarshalHresult().
2054  */
2055 HRESULT WINAPI CoUnmarshalHresult(LPSTREAM pStm, HRESULT * phresult)
2056 {
2057     return IStream_Read(pStm, phresult, sizeof(*phresult), NULL);
2058 }