d3dx8: Implement D3DXMatrixRotationY.
[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 **pServerPrincName,
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, pServerPrincName, pAuthnLevel, pImpLevel, pAuthInfo,
522           pCapabilities);
523     return E_NOTIMPL;
524 }
525
526 static HRESULT WINAPI ProxyCliSec_SetBlanket(IClientSecurity *iface,
527                                              IUnknown *pProxy, DWORD AuthnSvc,
528                                              DWORD AuthzSvc,
529                                              OLECHAR *pServerPrincName,
530                                              DWORD AuthnLevel, DWORD ImpLevel,
531                                              void *pAuthInfo,
532                                              DWORD Capabilities)
533 {
534     FIXME("(%p, %d, %d, %s, %d, %d, %p, 0x%x): stub\n", pProxy, AuthnSvc,
535           AuthzSvc, debugstr_w(pServerPrincName), AuthnLevel, ImpLevel,
536           pAuthInfo, Capabilities);
537     return E_NOTIMPL;
538 }
539
540 static HRESULT WINAPI ProxyCliSec_CopyProxy(IClientSecurity *iface,
541                                             IUnknown *pProxy, IUnknown **ppCopy)
542 {
543     FIXME("(%p, %p): stub\n", pProxy, ppCopy);
544     *ppCopy = NULL;
545     return E_NOTIMPL;
546 }
547
548 static const IClientSecurityVtbl ProxyCliSec_Vtbl =
549 {
550     ProxyCliSec_QueryInterface,
551     ProxyCliSec_AddRef,
552     ProxyCliSec_Release,
553     ProxyCliSec_QueryBlanket,
554     ProxyCliSec_SetBlanket,
555     ProxyCliSec_CopyProxy
556 };
557
558 static HRESULT ifproxy_get_public_ref(struct ifproxy * This)
559 {
560     HRESULT hr = S_OK;
561
562     if (WAIT_OBJECT_0 != WaitForSingleObject(This->parent->remoting_mutex, INFINITE))
563     {
564         ERR("Wait failed for ifproxy %p\n", This);
565         return E_UNEXPECTED;
566     }
567
568     if (This->refs == 0)
569     {
570         IRemUnknown *remunk = NULL;
571
572         TRACE("getting public ref for ifproxy %p\n", This);
573
574         hr = proxy_manager_get_remunknown(This->parent, &remunk);
575         if (hr == S_OK)
576         {
577             HRESULT hrref = S_OK;
578             REMINTERFACEREF rif;
579             rif.ipid = This->stdobjref.ipid;
580             rif.cPublicRefs = NORMALEXTREFS;
581             rif.cPrivateRefs = 0;
582             hr = IRemUnknown_RemAddRef(remunk, 1, &rif, &hrref);
583             IRemUnknown_Release(remunk);
584             if (hr == S_OK && hrref == S_OK)
585                 InterlockedExchangeAdd((LONG *)&This->refs, NORMALEXTREFS);
586             else
587                 ERR("IRemUnknown_RemAddRef returned with 0x%08x, hrref = 0x%08x\n", hr, hrref);
588         }
589     }
590     ReleaseMutex(This->parent->remoting_mutex);
591
592     return hr;
593 }
594
595 static HRESULT ifproxy_release_public_refs(struct ifproxy * This)
596 {
597     HRESULT hr = S_OK;
598     LONG public_refs;
599
600     if (WAIT_OBJECT_0 != WaitForSingleObject(This->parent->remoting_mutex, INFINITE))
601     {
602         ERR("Wait failed for ifproxy %p\n", This);
603         return E_UNEXPECTED;
604     }
605
606     public_refs = This->refs;
607     if (public_refs > 0)
608     {
609         IRemUnknown *remunk = NULL;
610
611         TRACE("releasing %d refs\n", public_refs);
612
613         hr = proxy_manager_get_remunknown(This->parent, &remunk);
614         if (hr == S_OK)
615         {
616             REMINTERFACEREF rif;
617             rif.ipid = This->stdobjref.ipid;
618             rif.cPublicRefs = public_refs;
619             rif.cPrivateRefs = 0;
620             hr = IRemUnknown_RemRelease(remunk, 1, &rif);
621             IRemUnknown_Release(remunk);
622             if (hr == S_OK)
623                 InterlockedExchangeAdd((LONG *)&This->refs, -public_refs);
624             else if (hr == RPC_E_DISCONNECTED)
625                 WARN("couldn't release references because object was "
626                      "disconnected: oxid = %s, oid = %s\n",
627                      wine_dbgstr_longlong(This->parent->oxid),
628                      wine_dbgstr_longlong(This->parent->oid));
629             else
630                 ERR("IRemUnknown_RemRelease failed with error 0x%08x\n", hr);
631         }
632     }
633     ReleaseMutex(This->parent->remoting_mutex);
634
635     return hr;
636 }
637
638 /* should be called inside This->parent->cs critical section */
639 static void ifproxy_disconnect(struct ifproxy * This)
640 {
641     ifproxy_release_public_refs(This);
642     if (This->proxy) IRpcProxyBuffer_Disconnect(This->proxy);
643
644     IRpcChannelBuffer_Release(This->chan);
645     This->chan = NULL;
646 }
647
648 /* should be called in This->parent->cs critical section if it is an entry in parent's list */
649 static void ifproxy_destroy(struct ifproxy * This)
650 {
651     TRACE("%p\n", This);
652
653     /* release public references to this object so that the stub can know
654      * when to destroy itself */
655     ifproxy_release_public_refs(This);
656
657     list_remove(&This->entry);
658
659     if (This->chan)
660     {
661         IRpcChannelBuffer_Release(This->chan);
662         This->chan = NULL;
663     }
664
665     if (This->proxy) IRpcProxyBuffer_Release(This->proxy);
666
667     HeapFree(GetProcessHeap(), 0, This);
668 }
669
670 static HRESULT proxy_manager_construct(
671     APARTMENT * apt, ULONG sorflags, OXID oxid, OID oid,
672     const OXID_INFO *oxid_info, struct proxy_manager ** proxy_manager)
673 {
674     struct proxy_manager * This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
675     if (!This) return E_OUTOFMEMORY;
676
677     This->remoting_mutex = CreateMutexW(NULL, FALSE, NULL);
678     if (!This->remoting_mutex)
679     {
680         HeapFree(GetProcessHeap(), 0, This);
681         return HRESULT_FROM_WIN32(GetLastError());
682     }
683
684     if (oxid_info)
685     {
686         This->oxid_info.dwPid = oxid_info->dwPid;
687         This->oxid_info.dwTid = oxid_info->dwTid;
688         This->oxid_info.ipidRemUnknown = oxid_info->ipidRemUnknown;
689         This->oxid_info.dwAuthnHint = oxid_info->dwAuthnHint;
690         This->oxid_info.psa = NULL /* FIXME: copy from oxid_info */;
691     }
692     else
693     {
694         HRESULT hr = RPC_ResolveOxid(oxid, &This->oxid_info);
695         if (FAILED(hr))
696         {
697             CloseHandle(This->remoting_mutex);
698             HeapFree(GetProcessHeap(), 0, This);
699             return hr;
700         }
701     }
702
703     This->lpVtbl = &ClientIdentity_Vtbl;
704     This->lpVtblMarshal = &ProxyMarshal_Vtbl;
705     This->lpVtblCliSec = &ProxyCliSec_Vtbl;
706
707     list_init(&This->entry);
708     list_init(&This->interfaces);
709
710     InitializeCriticalSection(&This->cs);
711     DEBUG_SET_CRITSEC_NAME(&This->cs, "proxy_manager");
712
713     /* the apartment the object was unmarshaled into */
714     This->parent = apt;
715
716     /* the source apartment and id of the object */
717     This->oxid = oxid;
718     This->oid = oid;
719
720     This->refs = 1;
721
722     /* the DCOM draft specification states that the SORF_NOPING flag is
723      * proxy manager specific, not ifproxy specific, so this implies that we
724      * should store the STDOBJREF flags here in the proxy manager. */
725     This->sorflags = sorflags;
726
727     /* we create the IRemUnknown proxy on demand */
728     This->remunk = NULL;
729
730     /* initialise these values to the weakest values and they will be
731      * overwritten in proxy_manager_set_context */
732     This->dest_context = MSHCTX_INPROC;
733     This->dest_context_data = NULL;
734
735     EnterCriticalSection(&apt->cs);
736     /* FIXME: we are dependent on the ordering in here to make sure a proxy's
737      * IRemUnknown proxy doesn't get destroyed before the regual proxy does
738      * because we need the IRemUnknown proxy during the destruction of the
739      * regular proxy. Ideally, we should maintain a separate list for the
740      * IRemUnknown proxies that need late destruction */
741     list_add_tail(&apt->proxies, &This->entry);
742     LeaveCriticalSection(&apt->cs);
743
744     TRACE("%p created for OXID %s, OID %s\n", This,
745         wine_dbgstr_longlong(oxid), wine_dbgstr_longlong(oid));
746
747     *proxy_manager = This;
748     return S_OK;
749 }
750
751 static inline void proxy_manager_set_context(struct proxy_manager *This, MSHCTX dest_context, void *dest_context_data)
752 {
753     MSHCTX old_dest_context = This->dest_context;
754     MSHCTX new_dest_context;
755
756     do
757     {
758         new_dest_context = old_dest_context;
759         /* "stronger" values overwrite "weaker" values. stronger values are
760          * ones that disable more optimisations */
761         switch (old_dest_context)
762         {
763         case MSHCTX_INPROC:
764             new_dest_context = dest_context;
765             break;
766         case MSHCTX_CROSSCTX:
767             switch (dest_context)
768             {
769             case MSHCTX_INPROC:
770                 break;
771             default:
772                 new_dest_context = dest_context;
773             }
774             break;
775         case MSHCTX_LOCAL:
776             switch (dest_context)
777             {
778             case MSHCTX_INPROC:
779             case MSHCTX_CROSSCTX:
780                 break;
781             default:
782                 new_dest_context = dest_context;
783             }
784             break;
785         case MSHCTX_NOSHAREDMEM:
786             switch (dest_context)
787             {
788             case MSHCTX_DIFFERENTMACHINE:
789                 new_dest_context = dest_context;
790                 break;
791             default:
792                 break;
793             }
794             break;
795         default:
796             break;
797         }
798
799         if (old_dest_context == new_dest_context) break;
800
801         old_dest_context = InterlockedCompareExchange((PLONG)&This->dest_context, new_dest_context, old_dest_context);
802     } while (new_dest_context != old_dest_context);
803
804     if (dest_context_data)
805         InterlockedExchangePointer(&This->dest_context_data, dest_context_data);
806 }
807
808 static HRESULT proxy_manager_query_local_interface(struct proxy_manager * This, REFIID riid, void ** ppv)
809 {
810     HRESULT hr;
811     struct ifproxy * ifproxy;
812
813     TRACE("%s\n", debugstr_guid(riid));
814
815     if (IsEqualIID(riid, &IID_IUnknown) ||
816         IsEqualIID(riid, &IID_IMultiQI))
817     {
818         *ppv = (void *)&This->lpVtbl;
819         IUnknown_AddRef((IUnknown *)*ppv);
820         return S_OK;
821     }
822     if (IsEqualIID(riid, &IID_IMarshal))
823     {
824         *ppv = (void *)&This->lpVtblMarshal;
825         IUnknown_AddRef((IUnknown *)*ppv);
826         return S_OK;
827     }
828     if (IsEqualIID(riid, &IID_IClientSecurity))
829     {
830         *ppv = (void *)&This->lpVtblCliSec;
831         IUnknown_AddRef((IUnknown *)*ppv);
832         return S_OK;
833     }
834
835     hr = proxy_manager_find_ifproxy(This, riid, &ifproxy);
836     if (hr == S_OK)
837     {
838         *ppv = ifproxy->iface;
839         IUnknown_AddRef((IUnknown *)*ppv);
840         return S_OK;
841     }
842
843     *ppv = NULL;
844     return E_NOINTERFACE;
845 }
846
847 static HRESULT proxy_manager_create_ifproxy(
848     struct proxy_manager * This, const STDOBJREF *stdobjref, REFIID riid,
849     IRpcChannelBuffer * channel, struct ifproxy ** iif_out)
850 {
851     HRESULT hr;
852     IPSFactoryBuffer * psfb;
853     struct ifproxy * ifproxy = HeapAlloc(GetProcessHeap(), 0, sizeof(*ifproxy));
854     if (!ifproxy) return E_OUTOFMEMORY;
855
856     list_init(&ifproxy->entry);
857
858     ifproxy->parent = This;
859     ifproxy->stdobjref = *stdobjref;
860     ifproxy->iid = *riid;
861     ifproxy->refs = 0;
862     ifproxy->proxy = NULL;
863
864     assert(channel);
865     ifproxy->chan = channel; /* FIXME: we should take the binding strings and construct the channel in this function */
866
867     /* the IUnknown interface is special because it does not have a
868      * proxy associated with the ifproxy as we handle IUnknown ourselves */
869     if (IsEqualIID(riid, &IID_IUnknown))
870     {
871         ifproxy->iface = (void *)&This->lpVtbl;
872         IMultiQI_AddRef((IMultiQI *)&This->lpVtbl);
873         hr = S_OK;
874     }
875     else
876     {
877         hr = get_facbuf_for_iid(riid, &psfb);
878         if (hr == S_OK)
879         {
880             /* important note: the outer unknown is set to the proxy manager.
881              * This ensures the COM identity rules are not violated, by having a
882              * one-to-one mapping of objects on the proxy side to objects on the
883              * stub side, no matter which interface you view the object through */
884             hr = IPSFactoryBuffer_CreateProxy(psfb, (IUnknown *)&This->lpVtbl, riid,
885                                               &ifproxy->proxy, &ifproxy->iface);
886             IPSFactoryBuffer_Release(psfb);
887             if (hr != S_OK)
888                 ERR("Could not create proxy for interface %s, error 0x%08x\n",
889                     debugstr_guid(riid), hr);
890         }
891         else
892             ERR("Could not get IPSFactoryBuffer for interface %s, error 0x%08x\n",
893                 debugstr_guid(riid), hr);
894
895         if (hr == S_OK)
896             hr = IRpcProxyBuffer_Connect(ifproxy->proxy, ifproxy->chan);
897     }
898
899     if (hr == S_OK)
900     {
901         EnterCriticalSection(&This->cs);
902         list_add_tail(&This->interfaces, &ifproxy->entry);
903         LeaveCriticalSection(&This->cs);
904
905         *iif_out = ifproxy;
906         TRACE("ifproxy %p created for IPID %s, interface %s with %lu public refs\n",
907               ifproxy, debugstr_guid(&stdobjref->ipid), debugstr_guid(riid), stdobjref->cPublicRefs);
908     }
909     else
910         ifproxy_destroy(ifproxy);
911
912     return hr;
913 }
914
915 static HRESULT proxy_manager_find_ifproxy(struct proxy_manager * This, REFIID riid, struct ifproxy ** ifproxy_found)
916 {
917     HRESULT hr = E_NOINTERFACE; /* assume not found */
918     struct list * cursor;
919
920     EnterCriticalSection(&This->cs);
921     LIST_FOR_EACH(cursor, &This->interfaces)
922     {
923         struct ifproxy * ifproxy = LIST_ENTRY(cursor, struct ifproxy, entry);
924         if (IsEqualIID(riid, &ifproxy->iid))
925         {
926             *ifproxy_found = ifproxy;
927             hr = S_OK;
928             break;
929         }
930     }
931     LeaveCriticalSection(&This->cs);
932
933     return hr;
934 }
935
936 static void proxy_manager_disconnect(struct proxy_manager * This)
937 {
938     struct list * cursor;
939
940     TRACE("oxid = %s, oid = %s\n", wine_dbgstr_longlong(This->oxid),
941         wine_dbgstr_longlong(This->oid));
942
943     EnterCriticalSection(&This->cs);
944
945     /* SORFP_NOLIFTIMEMGMT proxies (for IRemUnknown) shouldn't be
946      * disconnected - it won't do anything anyway, except cause
947      * problems for other objects that depend on this proxy always
948      * working */
949     if (!(This->sorflags & SORFP_NOLIFETIMEMGMT))
950     {
951         LIST_FOR_EACH(cursor, &This->interfaces)
952         {
953             struct ifproxy * ifproxy = LIST_ENTRY(cursor, struct ifproxy, entry);
954             ifproxy_disconnect(ifproxy);
955         }
956     }
957
958     /* apartment is being destroyed so don't keep a pointer around to it */
959     This->parent = NULL;
960
961     LeaveCriticalSection(&This->cs);
962 }
963
964 static HRESULT proxy_manager_get_remunknown(struct proxy_manager * This, IRemUnknown **remunk)
965 {
966     HRESULT hr = S_OK;
967     struct apartment *apt;
968     BOOL called_in_original_apt;
969
970     /* we don't want to try and unmarshal or use IRemUnknown if we don't want
971      * lifetime management */
972     if (This->sorflags & SORFP_NOLIFETIMEMGMT)
973         return S_FALSE;
974
975     apt = COM_CurrentApt();
976     if (!apt)
977         return CO_E_NOTINITIALIZED;
978
979     called_in_original_apt = This->parent && (This->parent->oxid == apt->oxid);
980
981     EnterCriticalSection(&This->cs);
982     /* only return the cached object if called from the original apartment.
983      * in future, we might want to make the IRemUnknown proxy callable from any
984      * apartment to avoid these checks */
985     if (This->remunk && called_in_original_apt)
986     {
987         /* already created - return existing object */
988         *remunk = This->remunk;
989         IRemUnknown_AddRef(*remunk);
990     }
991     else if (!This->parent)
992         /* disconnected - we can't create IRemUnknown */
993         hr = S_FALSE;
994     else
995     {
996         STDOBJREF stdobjref;
997         /* Don't want IRemUnknown lifetime management as this is IRemUnknown!
998          * We also don't care about whether or not the stub is still alive */
999         stdobjref.flags = SORFP_NOLIFETIMEMGMT | SORF_NOPING;
1000         stdobjref.cPublicRefs = 1;
1001         /* oxid of destination object */
1002         stdobjref.oxid = This->oxid;
1003         /* FIXME: what should be used for the oid? The DCOM draft doesn't say */
1004         stdobjref.oid = (OID)-1;
1005         stdobjref.ipid = This->oxid_info.ipidRemUnknown;
1006
1007         /* do the unmarshal */
1008         hr = unmarshal_object(&stdobjref, COM_CurrentApt(), This->dest_context,
1009                               This->dest_context_data, &IID_IRemUnknown,
1010                               &This->oxid_info, (void**)remunk);
1011         if (hr == S_OK && called_in_original_apt)
1012         {
1013             This->remunk = *remunk;
1014             IRemUnknown_AddRef(This->remunk);
1015         }
1016     }
1017     LeaveCriticalSection(&This->cs);
1018
1019     TRACE("got IRemUnknown* pointer %p, hr = 0x%08x\n", *remunk, hr);
1020
1021     return hr;
1022 }
1023
1024 /* destroys a proxy manager, freeing the memory it used.
1025  * Note: this function should not be called from a list iteration in the
1026  * apartment, due to the fact that it removes itself from the apartment and
1027  * it could add a proxy to IRemUnknown into the apartment. */
1028 static void proxy_manager_destroy(struct proxy_manager * This)
1029 {
1030     struct list * cursor;
1031
1032     TRACE("oxid = %s, oid = %s\n", wine_dbgstr_longlong(This->oxid),
1033         wine_dbgstr_longlong(This->oid));
1034
1035     if (This->parent)
1036     {
1037         EnterCriticalSection(&This->parent->cs);
1038
1039         /* remove ourself from the list of proxy objects in the apartment */
1040         LIST_FOR_EACH(cursor, &This->parent->proxies)
1041         {
1042             if (cursor == &This->entry)
1043             {
1044                 list_remove(&This->entry);
1045                 break;
1046             }
1047         }
1048
1049         LeaveCriticalSection(&This->parent->cs);
1050     }
1051
1052     /* destroy all of the interface proxies */
1053     while ((cursor = list_head(&This->interfaces)))
1054     {
1055         struct ifproxy * ifproxy = LIST_ENTRY(cursor, struct ifproxy, entry);
1056         ifproxy_destroy(ifproxy);
1057     }
1058
1059     if (This->remunk) IRemUnknown_Release(This->remunk);
1060     CoTaskMemFree(This->oxid_info.psa);
1061
1062     DEBUG_CLEAR_CRITSEC_NAME(&This->cs);
1063     DeleteCriticalSection(&This->cs);
1064
1065     CloseHandle(This->remoting_mutex);
1066
1067     HeapFree(GetProcessHeap(), 0, This);
1068 }
1069
1070 /* finds the proxy manager corresponding to a given OXID and OID that has
1071  * been unmarshaled in the specified apartment. The caller must release the
1072  * reference to the proxy_manager when the object is no longer used. */
1073 static BOOL find_proxy_manager(APARTMENT * apt, OXID oxid, OID oid, struct proxy_manager ** proxy_found)
1074 {
1075     BOOL found = FALSE;
1076     struct list * cursor;
1077
1078     EnterCriticalSection(&apt->cs);
1079     LIST_FOR_EACH(cursor, &apt->proxies)
1080     {
1081         struct proxy_manager * proxy = LIST_ENTRY(cursor, struct proxy_manager, entry);
1082         if ((oxid == proxy->oxid) && (oid == proxy->oid))
1083         {
1084             *proxy_found = proxy;
1085             ClientIdentity_AddRef((IMultiQI *)&proxy->lpVtbl);
1086             found = TRUE;
1087             break;
1088         }
1089     }
1090     LeaveCriticalSection(&apt->cs);
1091     return found;
1092 }
1093
1094 HRESULT apartment_disconnectproxies(struct apartment *apt)
1095 {
1096     struct list * cursor;
1097
1098     LIST_FOR_EACH(cursor, &apt->proxies)
1099     {
1100         struct proxy_manager * proxy = LIST_ENTRY(cursor, struct proxy_manager, entry);
1101         proxy_manager_disconnect(proxy);
1102     }
1103
1104     return S_OK;
1105 }
1106
1107 /********************** StdMarshal implementation ****************************/
1108 typedef struct _StdMarshalImpl
1109 {
1110     const IMarshalVtbl  *lpvtbl;
1111     LONG                ref;
1112
1113     IID                 iid;
1114     DWORD               dwDestContext;
1115     LPVOID              pvDestContext;
1116     DWORD               mshlflags;
1117 } StdMarshalImpl;
1118
1119 static HRESULT WINAPI 
1120 StdMarshalImpl_QueryInterface(LPMARSHAL iface, REFIID riid, LPVOID *ppv)
1121 {
1122     *ppv = NULL;
1123     if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IMarshal, riid))
1124     {
1125         *ppv = iface;
1126         IUnknown_AddRef(iface);
1127         return S_OK;
1128     }
1129     FIXME("No interface for %s.\n", debugstr_guid(riid));
1130     return E_NOINTERFACE;
1131 }
1132
1133 static ULONG WINAPI
1134 StdMarshalImpl_AddRef(LPMARSHAL iface)
1135 {
1136     StdMarshalImpl *This = (StdMarshalImpl *)iface;
1137     return InterlockedIncrement(&This->ref);
1138 }
1139
1140 static ULONG WINAPI
1141 StdMarshalImpl_Release(LPMARSHAL iface)
1142 {
1143     StdMarshalImpl *This = (StdMarshalImpl *)iface;
1144     ULONG ref = InterlockedDecrement(&This->ref);
1145
1146     if (!ref) HeapFree(GetProcessHeap(),0,This);
1147     return ref;
1148 }
1149
1150 static HRESULT WINAPI
1151 StdMarshalImpl_GetUnmarshalClass(
1152     LPMARSHAL iface, REFIID riid, void* pv, DWORD dwDestContext,
1153     void* pvDestContext, DWORD mshlflags, CLSID* pCid)
1154 {
1155     *pCid = CLSID_DfMarshal;
1156     return S_OK;
1157 }
1158
1159 static HRESULT WINAPI
1160 StdMarshalImpl_GetMarshalSizeMax(
1161     LPMARSHAL iface, REFIID riid, void* pv, DWORD dwDestContext,
1162     void* pvDestContext, DWORD mshlflags, DWORD* pSize)
1163 {
1164     *pSize = sizeof(STDOBJREF);
1165     return S_OK;
1166 }
1167
1168 static HRESULT WINAPI
1169 StdMarshalImpl_MarshalInterface(
1170     LPMARSHAL iface, IStream *pStm,REFIID riid, void* pv, DWORD dwDestContext,
1171     void* pvDestContext, DWORD mshlflags)
1172 {
1173     STDOBJREF             stdobjref;
1174     ULONG                 res;
1175     HRESULT               hres;
1176     APARTMENT            *apt = COM_CurrentApt();
1177
1178     TRACE("(...,%s,...)\n", debugstr_guid(riid));
1179
1180     if (!apt)
1181     {
1182         ERR("Apartment not initialized\n");
1183         return CO_E_NOTINITIALIZED;
1184     }
1185
1186     /* make sure this apartment can be reached from other threads / processes */
1187     RPC_StartRemoting(apt);
1188
1189     hres = marshal_object(apt, &stdobjref, riid, (IUnknown *)pv, mshlflags);
1190     if (hres)
1191     {
1192         ERR("Failed to create ifstub, hres=0x%x\n", hres);
1193         return hres;
1194     }
1195
1196     hres = IStream_Write(pStm, &stdobjref, sizeof(stdobjref), &res);
1197     if (hres) return hres;
1198
1199     return S_OK;
1200 }
1201
1202 /* helper for StdMarshalImpl_UnmarshalInterface - does the unmarshaling with
1203  * no questions asked about the rules surrounding same-apartment unmarshals
1204  * and table marshaling */
1205 static HRESULT unmarshal_object(const STDOBJREF *stdobjref, APARTMENT *apt,
1206                                 MSHCTX dest_context, void *dest_context_data,
1207                                 REFIID riid, const OXID_INFO *oxid_info,
1208                                 void **object)
1209 {
1210     struct proxy_manager *proxy_manager = NULL;
1211     HRESULT hr = S_OK;
1212
1213     assert(apt);
1214
1215     TRACE("stdobjref:\n\tflags = %04lx\n\tcPublicRefs = %ld\n\toxid = %s\n\toid = %s\n\tipid = %s\n",
1216         stdobjref->flags, stdobjref->cPublicRefs,
1217         wine_dbgstr_longlong(stdobjref->oxid),
1218         wine_dbgstr_longlong(stdobjref->oid),
1219         debugstr_guid(&stdobjref->ipid));
1220
1221     /* create a new proxy manager if one doesn't already exist for the
1222      * object */
1223     if (!find_proxy_manager(apt, stdobjref->oxid, stdobjref->oid, &proxy_manager))
1224     {
1225         hr = proxy_manager_construct(apt, stdobjref->flags,
1226                                      stdobjref->oxid, stdobjref->oid, oxid_info,
1227                                      &proxy_manager);
1228     }
1229     else
1230         TRACE("proxy manager already created, using\n");
1231
1232     if (hr == S_OK)
1233     {
1234         struct ifproxy * ifproxy;
1235
1236         proxy_manager_set_context(proxy_manager, dest_context, dest_context_data);
1237
1238         hr = proxy_manager_find_ifproxy(proxy_manager, riid, &ifproxy);
1239         if (hr == E_NOINTERFACE)
1240         {
1241             IRpcChannelBuffer *chanbuf;
1242             hr = RPC_CreateClientChannel(&stdobjref->oxid, &stdobjref->ipid,
1243                                          &proxy_manager->oxid_info,
1244                                          proxy_manager->dest_context,
1245                                          proxy_manager->dest_context_data,
1246                                          &chanbuf);
1247             if (hr == S_OK)
1248                 hr = proxy_manager_create_ifproxy(proxy_manager, stdobjref,
1249                                                   riid, chanbuf, &ifproxy);
1250         }
1251         else
1252             IUnknown_AddRef((IUnknown *)ifproxy->iface);
1253
1254         if (hr == S_OK)
1255         {
1256             InterlockedExchangeAdd((LONG *)&ifproxy->refs, stdobjref->cPublicRefs);
1257             /* get at least one external reference to the object to keep it alive */
1258             hr = ifproxy_get_public_ref(ifproxy);
1259             if (FAILED(hr))
1260                 ifproxy_destroy(ifproxy);
1261         }
1262
1263         if (hr == S_OK)
1264             *object = ifproxy->iface;
1265     }
1266
1267     /* release our reference to the proxy manager - the client/apartment
1268      * will hold on to the remaining reference for us */
1269     if (proxy_manager) ClientIdentity_Release((IMultiQI*)&proxy_manager->lpVtbl);
1270
1271     return hr;
1272 }
1273
1274 static HRESULT WINAPI
1275 StdMarshalImpl_UnmarshalInterface(LPMARSHAL iface, IStream *pStm, REFIID riid, void **ppv)
1276 {
1277     StdMarshalImpl *This = (StdMarshalImpl *)iface;
1278     struct stub_manager *stubmgr = NULL;
1279     STDOBJREF stdobjref;
1280     ULONG res;
1281     HRESULT hres;
1282     APARTMENT *apt = COM_CurrentApt();
1283     APARTMENT *stub_apt;
1284     OXID oxid;
1285
1286     TRACE("(...,%s,....)\n", debugstr_guid(riid));
1287
1288     /* we need an apartment to unmarshal into */
1289     if (!apt)
1290     {
1291         ERR("Apartment not initialized\n");
1292         return CO_E_NOTINITIALIZED;
1293     }
1294
1295     /* read STDOBJREF from wire */
1296     hres = IStream_Read(pStm, &stdobjref, sizeof(stdobjref), &res);
1297     if (hres) return STG_E_READFAULT;
1298
1299     hres = apartment_getoxid(apt, &oxid);
1300     if (hres) return hres;
1301
1302     /* check if we're marshalling back to ourselves */
1303     if ((oxid == stdobjref.oxid) && (stubmgr = get_stub_manager(apt, stdobjref.oid)))
1304     {
1305         TRACE("Unmarshalling object marshalled in same apartment for iid %s, "
1306               "returning original object %p\n", debugstr_guid(riid), stubmgr->object);
1307     
1308         hres = IUnknown_QueryInterface(stubmgr->object, riid, ppv);
1309       
1310         /* unref the ifstub. FIXME: only do this on success? */
1311         if (!stub_manager_is_table_marshaled(stubmgr, &stdobjref.ipid))
1312             stub_manager_ext_release(stubmgr, stdobjref.cPublicRefs, TRUE);
1313
1314         stub_manager_int_release(stubmgr);
1315         return hres;
1316     }
1317
1318     /* notify stub manager about unmarshal if process-local object.
1319      * note: if the oxid is not found then we and native will quite happily
1320      * ignore table marshaling and normal marshaling rules regarding number of
1321      * unmarshals, etc, but if you abuse these rules then your proxy could end
1322      * up returning RPC_E_DISCONNECTED. */
1323     if ((stub_apt = apartment_findfromoxid(stdobjref.oxid, TRUE)))
1324     {
1325         if ((stubmgr = get_stub_manager(stub_apt, stdobjref.oid)))
1326         {
1327             if (!stub_manager_notify_unmarshal(stubmgr, &stdobjref.ipid))
1328                 hres = CO_E_OBJNOTCONNECTED;
1329         }
1330         else
1331         {
1332             WARN("Couldn't find object for OXID %s, OID %s, assuming disconnected\n",
1333                 wine_dbgstr_longlong(stdobjref.oxid),
1334                 wine_dbgstr_longlong(stdobjref.oid));
1335             hres = CO_E_OBJNOTCONNECTED;
1336         }
1337     }
1338     else
1339         TRACE("Treating unmarshal from OXID %s as inter-process\n",
1340             wine_dbgstr_longlong(stdobjref.oxid));
1341
1342     if (hres == S_OK)
1343         hres = unmarshal_object(&stdobjref, apt, This->dwDestContext,
1344                                 This->pvDestContext, riid,
1345                                 stubmgr ? &stubmgr->oxid_info : NULL, ppv);
1346
1347     if (stubmgr) stub_manager_int_release(stubmgr);
1348     if (stub_apt) apartment_release(stub_apt);
1349
1350     if (hres) WARN("Failed with error 0x%08x\n", hres);
1351     else TRACE("Successfully created proxy %p\n", *ppv);
1352
1353     return hres;
1354 }
1355
1356 static HRESULT WINAPI
1357 StdMarshalImpl_ReleaseMarshalData(LPMARSHAL iface, IStream *pStm)
1358 {
1359     STDOBJREF            stdobjref;
1360     ULONG                res;
1361     HRESULT              hres;
1362     struct stub_manager *stubmgr;
1363     APARTMENT           *apt;
1364
1365     TRACE("iface=%p, pStm=%p\n", iface, pStm);
1366     
1367     hres = IStream_Read(pStm, &stdobjref, sizeof(stdobjref), &res);
1368     if (hres) return STG_E_READFAULT;
1369
1370     TRACE("oxid = %s, oid = %s, ipid = %s\n",
1371         wine_dbgstr_longlong(stdobjref.oxid),
1372         wine_dbgstr_longlong(stdobjref.oid),
1373         wine_dbgstr_guid(&stdobjref.ipid));
1374
1375     if (!(apt = apartment_findfromoxid(stdobjref.oxid, TRUE)))
1376     {
1377         WARN("Could not map OXID %s to apartment object\n",
1378             wine_dbgstr_longlong(stdobjref.oxid));
1379         return RPC_E_INVALID_OBJREF;
1380     }
1381
1382     if (!(stubmgr = get_stub_manager(apt, stdobjref.oid)))
1383     {
1384         ERR("could not map object ID to stub manager, oxid=%s, oid=%s\n",
1385             wine_dbgstr_longlong(stdobjref.oxid), wine_dbgstr_longlong(stdobjref.oid));
1386         return RPC_E_INVALID_OBJREF;
1387     }
1388
1389     stub_manager_release_marshal_data(stubmgr, stdobjref.cPublicRefs, &stdobjref.ipid);
1390
1391     stub_manager_int_release(stubmgr);
1392     apartment_release(apt);
1393
1394     return S_OK;
1395 }
1396
1397 static HRESULT WINAPI
1398 StdMarshalImpl_DisconnectObject(LPMARSHAL iface, DWORD dwReserved)
1399 {
1400     FIXME("(), stub!\n");
1401     return S_OK;
1402 }
1403
1404 static const IMarshalVtbl VT_StdMarshal =
1405 {
1406     StdMarshalImpl_QueryInterface,
1407     StdMarshalImpl_AddRef,
1408     StdMarshalImpl_Release,
1409     StdMarshalImpl_GetUnmarshalClass,
1410     StdMarshalImpl_GetMarshalSizeMax,
1411     StdMarshalImpl_MarshalInterface,
1412     StdMarshalImpl_UnmarshalInterface,
1413     StdMarshalImpl_ReleaseMarshalData,
1414     StdMarshalImpl_DisconnectObject
1415 };
1416
1417 static HRESULT StdMarshalImpl_Construct(REFIID riid, void** ppvObject)
1418 {
1419     StdMarshalImpl * pStdMarshal = 
1420         HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(StdMarshalImpl));
1421     if (!pStdMarshal)
1422         return E_OUTOFMEMORY;
1423     pStdMarshal->lpvtbl = &VT_StdMarshal;
1424     pStdMarshal->ref = 0;
1425     return IMarshal_QueryInterface((IMarshal*)pStdMarshal, riid, ppvObject);
1426 }
1427
1428 /***********************************************************************
1429  *              CoGetStandardMarshal    [OLE32.@]
1430  *
1431  * Gets or creates a standard marshal object.
1432  *
1433  * PARAMS
1434  *  riid          [I] Interface identifier of the pUnk object.
1435  *  pUnk          [I] Optional. Object to get the marshal object for.
1436  *  dwDestContext [I] Destination. Used to enable or disable optimizations.
1437  *  pvDestContext [I] Reserved. Must be NULL.
1438  *  mshlflags     [I] Flags affecting the marshaling process.
1439  *  ppMarshal     [O] Address where marshal object will be stored.
1440  *
1441  * RETURNS
1442  *  Success: S_OK.
1443  *  Failure: HRESULT code.
1444  *
1445  * NOTES
1446  *
1447  * The function retrieves the IMarshal object associated with an object if
1448  * that object is currently an active stub, otherwise a new marshal object is
1449  * created.
1450  */
1451 HRESULT WINAPI CoGetStandardMarshal(REFIID riid, IUnknown *pUnk,
1452                                     DWORD dwDestContext, LPVOID pvDestContext,
1453                                     DWORD mshlflags, LPMARSHAL *ppMarshal)
1454 {
1455     StdMarshalImpl *dm;
1456
1457     if (pUnk == NULL)
1458     {
1459         FIXME("(%s,NULL,%x,%p,%x,%p), unimplemented yet.\n",
1460             debugstr_guid(riid),dwDestContext,pvDestContext,mshlflags,ppMarshal);
1461         return E_NOTIMPL;
1462     }
1463     TRACE("(%s,%p,%x,%p,%x,%p)\n",
1464         debugstr_guid(riid),pUnk,dwDestContext,pvDestContext,mshlflags,ppMarshal);
1465     *ppMarshal = HeapAlloc(GetProcessHeap(),0,sizeof(StdMarshalImpl));
1466     dm = (StdMarshalImpl*) *ppMarshal;
1467     if (!dm) return E_FAIL;
1468     dm->lpvtbl          = &VT_StdMarshal;
1469     dm->ref             = 1;
1470
1471     dm->iid             = *riid;
1472     dm->dwDestContext   = dwDestContext;
1473     dm->pvDestContext   = pvDestContext;
1474     dm->mshlflags       = mshlflags;
1475     return S_OK;
1476 }
1477
1478 /***********************************************************************
1479  *              get_marshaler   [internal]
1480  *
1481  * Retrieves an IMarshal interface for an object.
1482  */
1483 static HRESULT get_marshaler(REFIID riid, IUnknown *pUnk, DWORD dwDestContext,
1484                              void *pvDestContext, DWORD mshlFlags,
1485                              LPMARSHAL *pMarshal)
1486 {
1487     HRESULT hr;
1488
1489     if (!pUnk)
1490         return E_POINTER;
1491     hr = IUnknown_QueryInterface(pUnk, &IID_IMarshal, (LPVOID*)pMarshal);
1492     if (hr)
1493         hr = CoGetStandardMarshal(riid, pUnk, dwDestContext, pvDestContext,
1494                                   mshlFlags, pMarshal);
1495     return hr;
1496 }
1497
1498 /***********************************************************************
1499  *              get_unmarshaler_from_stream     [internal]
1500  *
1501  * Creates an IMarshal* object according to the data marshaled to the stream.
1502  * The function leaves the stream pointer at the start of the data written
1503  * to the stream by the IMarshal* object.
1504  */
1505 static HRESULT get_unmarshaler_from_stream(IStream *stream, IMarshal **marshal, IID *iid)
1506 {
1507     HRESULT hr;
1508     ULONG res;
1509     OBJREF objref;
1510
1511     /* read common OBJREF header */
1512     hr = IStream_Read(stream, &objref, FIELD_OFFSET(OBJREF, u_objref), &res);
1513     if (hr || (res != FIELD_OFFSET(OBJREF, u_objref)))
1514     {
1515         ERR("Failed to read common OBJREF header, 0x%08x\n", hr);
1516         return STG_E_READFAULT;
1517     }
1518
1519     /* sanity check on header */
1520     if (objref.signature != OBJREF_SIGNATURE)
1521     {
1522         ERR("Bad OBJREF signature 0x%08lx\n", objref.signature);
1523         return RPC_E_INVALID_OBJREF;
1524     }
1525
1526     if (iid) *iid = objref.iid;
1527
1528     /* FIXME: handler marshaling */
1529     if (objref.flags & OBJREF_STANDARD)
1530     {
1531         TRACE("Using standard unmarshaling\n");
1532         hr = StdMarshalImpl_Construct(&IID_IMarshal, (LPVOID*)marshal);
1533     }
1534     else if (objref.flags & OBJREF_CUSTOM)
1535     {
1536         ULONG custom_header_size = FIELD_OFFSET(OBJREF, u_objref.u_custom.pData) - 
1537                                    FIELD_OFFSET(OBJREF, u_objref.u_custom);
1538         TRACE("Using custom unmarshaling\n");
1539         /* read constant sized OR_CUSTOM data from stream */
1540         hr = IStream_Read(stream, &objref.u_objref.u_custom,
1541                           custom_header_size, &res);
1542         if (hr || (res != custom_header_size))
1543         {
1544             ERR("Failed to read OR_CUSTOM header, 0x%08x\n", hr);
1545             return STG_E_READFAULT;
1546         }
1547         /* now create the marshaler specified in the stream */
1548         hr = CoCreateInstance(&objref.u_objref.u_custom.clsid, NULL,
1549                               CLSCTX_INPROC_SERVER, &IID_IMarshal,
1550                               (LPVOID*)marshal);
1551     }
1552     else
1553     {
1554         FIXME("Invalid or unimplemented marshaling type specified: %lx\n",
1555             objref.flags);
1556         return RPC_E_INVALID_OBJREF;
1557     }
1558
1559     if (hr)
1560         ERR("Failed to create marshal, 0x%08x\n", hr);
1561
1562     return hr;
1563 }
1564
1565 /***********************************************************************
1566  *              CoGetMarshalSizeMax     [OLE32.@]
1567  *
1568  * Gets the maximum amount of data that will be needed by a marshal.
1569  *
1570  * PARAMS
1571  *  pulSize       [O] Address where maximum marshal size will be stored.
1572  *  riid          [I] Identifier of the interface to marshal.
1573  *  pUnk          [I] Pointer to the object to marshal.
1574  *  dwDestContext [I] Destination. Used to enable or disable optimizations.
1575  *  pvDestContext [I] Reserved. Must be NULL.
1576  *  mshlFlags     [I] Flags that affect the marshaling. See CoMarshalInterface().
1577  *
1578  * RETURNS
1579  *  Success: S_OK.
1580  *  Failure: HRESULT code.
1581  *
1582  * SEE ALSO
1583  *  CoMarshalInterface().
1584  */
1585 HRESULT WINAPI CoGetMarshalSizeMax(ULONG *pulSize, REFIID riid, IUnknown *pUnk,
1586                                    DWORD dwDestContext, void *pvDestContext,
1587                                    DWORD mshlFlags)
1588 {
1589     HRESULT hr;
1590     LPMARSHAL pMarshal;
1591     CLSID marshaler_clsid;
1592
1593     hr = get_marshaler(riid, pUnk, dwDestContext, pvDestContext, mshlFlags, &pMarshal);
1594     if (hr)
1595         return hr;
1596
1597     hr = IMarshal_GetUnmarshalClass(pMarshal, riid, pUnk, dwDestContext,
1598                                     pvDestContext, mshlFlags, &marshaler_clsid);
1599     if (hr)
1600     {
1601         ERR("IMarshal::GetUnmarshalClass failed, 0x%08x\n", hr);
1602         IMarshal_Release(pMarshal);
1603         return hr;
1604     }
1605
1606     hr = IMarshal_GetMarshalSizeMax(pMarshal, riid, pUnk, dwDestContext,
1607                                     pvDestContext, mshlFlags, pulSize);
1608     if (IsEqualCLSID(&marshaler_clsid, &CLSID_DfMarshal))
1609         /* add on the size of the common header */
1610         *pulSize += FIELD_OFFSET(OBJREF, u_objref);
1611     else
1612         /* custom marshaling: add on the size of the whole OBJREF structure
1613          * like native does */
1614         *pulSize += sizeof(OBJREF);
1615
1616     IMarshal_Release(pMarshal);
1617     return hr;
1618 }
1619
1620
1621 static void dump_MSHLFLAGS(MSHLFLAGS flags)
1622 {
1623     if (flags & MSHLFLAGS_TABLESTRONG)
1624         TRACE(" MSHLFLAGS_TABLESTRONG");
1625     if (flags & MSHLFLAGS_TABLEWEAK)
1626         TRACE(" MSHLFLAGS_TABLEWEAK");
1627     if (!(flags & (MSHLFLAGS_TABLESTRONG|MSHLFLAGS_TABLEWEAK)))
1628         TRACE(" MSHLFLAGS_NORMAL");
1629     if (flags & MSHLFLAGS_NOPING)
1630         TRACE(" MSHLFLAGS_NOPING");
1631 }
1632
1633 /***********************************************************************
1634  *              CoMarshalInterface      [OLE32.@]
1635  *
1636  * Marshals an interface into a stream so that the object can then be
1637  * unmarshaled from another COM apartment and used remotely.
1638  *
1639  * PARAMS
1640  *  pStream       [I] Stream the object will be marshaled into.
1641  *  riid          [I] Identifier of the interface to marshal.
1642  *  pUnk          [I] Pointer to the object to marshal.
1643  *  dwDestContext [I] Destination. Used to enable or disable optimizations.
1644  *  pvDestContext [I] Reserved. Must be NULL.
1645  *  mshlFlags     [I] Flags that affect the marshaling. See notes.
1646  *
1647  * RETURNS
1648  *  Success: S_OK.
1649  *  Failure: HRESULT code.
1650  *
1651  * NOTES
1652  *
1653  * The mshlFlags parameter can take one or more of the following flags:
1654  *| MSHLFLAGS_NORMAL - Unmarshal once, releases stub on last proxy release.
1655  *| MSHLFLAGS_TABLESTRONG - Unmarshal many, release when CoReleaseMarshalData() called.
1656  *| MSHLFLAGS_TABLEWEAK - Unmarshal many, releases stub on last proxy release.
1657  *| MSHLFLAGS_NOPING - No automatic garbage collection (and so reduces network traffic).
1658  *
1659  * If a marshaled object is not unmarshaled, then CoReleaseMarshalData() must
1660  * be called in order to release the resources used in the marshaling.
1661  *
1662  * SEE ALSO
1663  *  CoUnmarshalInterface(), CoReleaseMarshalData().
1664  */
1665 HRESULT WINAPI CoMarshalInterface(IStream *pStream, REFIID riid, IUnknown *pUnk,
1666                                   DWORD dwDestContext, void *pvDestContext,
1667                                   DWORD mshlFlags)
1668 {
1669     HRESULT     hr;
1670     CLSID marshaler_clsid;
1671     OBJREF objref;
1672     LPMARSHAL pMarshal;
1673
1674     TRACE("(%p, %s, %p, %x, %p,", pStream, debugstr_guid(riid), pUnk,
1675         dwDestContext, pvDestContext);
1676     dump_MSHLFLAGS(mshlFlags);
1677     TRACE(")\n");
1678
1679     if (!pUnk || !pStream)
1680         return E_INVALIDARG;
1681
1682     objref.signature = OBJREF_SIGNATURE;
1683     objref.iid = *riid;
1684
1685     /* get the marshaler for the specified interface */
1686     hr = get_marshaler(riid, pUnk, dwDestContext, pvDestContext, mshlFlags, &pMarshal);
1687     if (hr)
1688     {
1689         ERR("Failed to get marshaller, 0x%08x\n", hr);
1690         return hr;
1691     }
1692
1693     hr = IMarshal_GetUnmarshalClass(pMarshal, riid, pUnk, dwDestContext,
1694                                     pvDestContext, mshlFlags, &marshaler_clsid);
1695     if (hr)
1696     {
1697         ERR("IMarshal::GetUnmarshalClass failed, 0x%08x\n", hr);
1698         goto cleanup;
1699     }
1700
1701     /* FIXME: implement handler marshaling too */
1702     if (IsEqualCLSID(&marshaler_clsid, &CLSID_DfMarshal))
1703     {
1704         TRACE("Using standard marshaling\n");
1705         objref.flags = OBJREF_STANDARD;
1706
1707         /* write the common OBJREF header to the stream */
1708         hr = IStream_Write(pStream, &objref, FIELD_OFFSET(OBJREF, u_objref), NULL);
1709         if (hr)
1710         {
1711             ERR("Failed to write OBJREF header to stream, 0x%08x\n", hr);
1712             goto cleanup;
1713         }
1714     }
1715     else
1716     {
1717         TRACE("Using custom marshaling\n");
1718         objref.flags = OBJREF_CUSTOM;
1719         objref.u_objref.u_custom.clsid = marshaler_clsid;
1720         objref.u_objref.u_custom.cbExtension = 0;
1721         objref.u_objref.u_custom.size = 0;
1722         hr = IMarshal_GetMarshalSizeMax(pMarshal, riid, pUnk, dwDestContext,
1723                                         pvDestContext, mshlFlags,
1724                                         &objref.u_objref.u_custom.size);
1725         if (hr)
1726         {
1727             ERR("Failed to get max size of marshal data, error 0x%08x\n", hr);
1728             goto cleanup;
1729         }
1730         /* write constant sized common header and OR_CUSTOM data into stream */
1731         hr = IStream_Write(pStream, &objref,
1732                           FIELD_OFFSET(OBJREF, u_objref.u_custom.pData), NULL);
1733         if (hr)
1734         {
1735             ERR("Failed to write OR_CUSTOM header to stream with 0x%08x\n", hr);
1736             goto cleanup;
1737         }
1738     }
1739
1740     TRACE("Calling IMarshal::MarshalInterace\n");
1741     /* call helper object to do the actual marshaling */
1742     hr = IMarshal_MarshalInterface(pMarshal, pStream, riid, pUnk, dwDestContext,
1743                                    pvDestContext, mshlFlags);
1744
1745     if (hr)
1746     {
1747         ERR("Failed to marshal the interface %s, %x\n", debugstr_guid(riid), hr);
1748         goto cleanup;
1749     }
1750
1751 cleanup:
1752     IMarshal_Release(pMarshal);
1753
1754     TRACE("completed with hr 0x%08x\n", hr);
1755     
1756     return hr;
1757 }
1758
1759 /***********************************************************************
1760  *              CoUnmarshalInterface    [OLE32.@]
1761  *
1762  * Unmarshals an object from a stream by creating a proxy to the remote
1763  * object, if necessary.
1764  *
1765  * PARAMS
1766  *
1767  *  pStream [I] Stream containing the marshaled object.
1768  *  riid    [I] Interface identifier of the object to create a proxy to.
1769  *  ppv     [O] Address where proxy will be stored.
1770  *
1771  * RETURNS
1772  *
1773  *  Success: S_OK.
1774  *  Failure: HRESULT code.
1775  *
1776  * SEE ALSO
1777  *  CoMarshalInterface().
1778  */
1779 HRESULT WINAPI CoUnmarshalInterface(IStream *pStream, REFIID riid, LPVOID *ppv)
1780 {
1781     HRESULT hr;
1782     LPMARSHAL pMarshal;
1783     IID iid;
1784     IUnknown *object;
1785
1786     TRACE("(%p, %s, %p)\n", pStream, debugstr_guid(riid), ppv);
1787
1788     if (!pStream || !ppv)
1789         return E_INVALIDARG;
1790
1791     hr = get_unmarshaler_from_stream(pStream, &pMarshal, &iid);
1792     if (hr != S_OK)
1793         return hr;
1794
1795     /* call the helper object to do the actual unmarshaling */
1796     hr = IMarshal_UnmarshalInterface(pMarshal, pStream, &iid, (LPVOID*)&object);
1797     if (hr)
1798         ERR("IMarshal::UnmarshalInterface failed, 0x%08x\n", hr);
1799
1800     if (hr == S_OK)
1801     {
1802         /* IID_NULL means use the interface ID of the marshaled object */
1803         if (!IsEqualIID(riid, &IID_NULL) && !IsEqualIID(riid, &iid))
1804         {
1805             TRACE("requested interface != marshalled interface, additional QI needed\n");
1806             hr = IUnknown_QueryInterface(object, riid, ppv);
1807             if (hr)
1808                 ERR("Couldn't query for interface %s, hr = 0x%08x\n",
1809                     debugstr_guid(riid), hr);
1810             IUnknown_Release(object);
1811         }
1812         else
1813         {
1814             *ppv = object;
1815         }
1816     }
1817
1818     IMarshal_Release(pMarshal);
1819
1820     TRACE("completed with hr 0x%x\n", hr);
1821     
1822     return hr;
1823 }
1824
1825 /***********************************************************************
1826  *              CoReleaseMarshalData    [OLE32.@]
1827  *
1828  * Releases resources associated with an object that has been marshaled into
1829  * a stream.
1830  *
1831  * PARAMS
1832  *
1833  *  pStream [I] The stream that the object has been marshaled into.
1834  *
1835  * RETURNS
1836  *  Success: S_OK.
1837  *  Failure: HRESULT error code.
1838  *
1839  * NOTES
1840  * 
1841  * Call this function to release resources associated with a normal or
1842  * table-weak marshal that will not be unmarshaled, and all table-strong
1843  * marshals when they are no longer needed.
1844  *
1845  * SEE ALSO
1846  *  CoMarshalInterface(), CoUnmarshalInterface().
1847  */
1848 HRESULT WINAPI CoReleaseMarshalData(IStream *pStream)
1849 {
1850     HRESULT     hr;
1851     LPMARSHAL pMarshal;
1852
1853     TRACE("(%p)\n", pStream);
1854
1855     hr = get_unmarshaler_from_stream(pStream, &pMarshal, NULL);
1856     if (hr != S_OK)
1857         return hr;
1858
1859     /* call the helper object to do the releasing of marshal data */
1860     hr = IMarshal_ReleaseMarshalData(pMarshal, pStream);
1861     if (hr)
1862         ERR("IMarshal::ReleaseMarshalData failed with error 0x%08x\n", hr);
1863
1864     IMarshal_Release(pMarshal);
1865     return hr;
1866 }
1867
1868
1869 /***********************************************************************
1870  *              CoMarshalInterThreadInterfaceInStream   [OLE32.@]
1871  *
1872  * Marshal an interface across threads in the same process.
1873  *
1874  * PARAMS
1875  *  riid  [I] Identifier of the interface to be marshalled.
1876  *  pUnk  [I] Pointer to IUnknown-derived interface that will be marshalled.
1877  *  ppStm [O] Pointer to IStream object that is created and then used to store the marshalled interface.
1878  *
1879  * RETURNS
1880  *  Success: S_OK
1881  *  Failure: E_OUTOFMEMORY and other COM error codes
1882  *
1883  * SEE ALSO
1884  *   CoMarshalInterface(), CoUnmarshalInterface() and CoGetInterfaceAndReleaseStream()
1885  */
1886 HRESULT WINAPI CoMarshalInterThreadInterfaceInStream(
1887     REFIID riid, LPUNKNOWN pUnk, LPSTREAM * ppStm)
1888 {
1889     ULARGE_INTEGER      xpos;
1890     LARGE_INTEGER               seekto;
1891     HRESULT             hres;
1892
1893     TRACE("(%s, %p, %p)\n",debugstr_guid(riid), pUnk, ppStm);
1894
1895     hres = CreateStreamOnHGlobal(NULL, TRUE, ppStm);
1896     if (FAILED(hres)) return hres;
1897     hres = CoMarshalInterface(*ppStm, riid, pUnk, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1898
1899     if (SUCCEEDED(hres))
1900     {
1901         memset(&seekto, 0, sizeof(seekto));
1902         IStream_Seek(*ppStm, seekto, STREAM_SEEK_SET, &xpos);
1903     }
1904     else
1905     {
1906         IStream_Release(*ppStm);
1907         *ppStm = NULL;
1908     }
1909
1910     return hres;
1911 }
1912
1913 /***********************************************************************
1914  *              CoGetInterfaceAndReleaseStream  [OLE32.@]
1915  *
1916  * Unmarshalls an interface from a stream and then releases the stream.
1917  *
1918  * PARAMS
1919  *  pStm [I] Stream that contains the marshalled interface.
1920  *  riid [I] Interface identifier of the object to unmarshall.
1921  *  ppv  [O] Address of pointer where the requested interface object will be stored.
1922  *
1923  * RETURNS
1924  *  Success: S_OK
1925  *  Failure: A COM error code
1926  *
1927  * SEE ALSO
1928  *  CoMarshalInterThreadInterfaceInStream() and CoUnmarshalInterface()
1929  */
1930 HRESULT WINAPI CoGetInterfaceAndReleaseStream(LPSTREAM pStm, REFIID riid,
1931                                               LPVOID *ppv)
1932 {
1933     HRESULT hres;
1934
1935     TRACE("(%p, %s, %p)\n", pStm, debugstr_guid(riid), ppv);
1936
1937     if(!pStm) return E_INVALIDARG;
1938     hres = CoUnmarshalInterface(pStm, riid, ppv);
1939     IStream_Release(pStm);
1940     return hres;
1941 }
1942
1943 static HRESULT WINAPI StdMarshalCF_QueryInterface(LPCLASSFACTORY iface,
1944                                                   REFIID riid, LPVOID *ppv)
1945 {
1946     *ppv = NULL;
1947     if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IClassFactory))
1948     {
1949         *ppv = (LPVOID)iface;
1950         return S_OK;
1951     }
1952     return E_NOINTERFACE;
1953 }
1954
1955 static ULONG WINAPI StdMarshalCF_AddRef(LPCLASSFACTORY iface)
1956 {
1957     return 2; /* non-heap based object */
1958 }
1959
1960 static ULONG WINAPI StdMarshalCF_Release(LPCLASSFACTORY iface)
1961 {
1962     return 1; /* non-heap based object */
1963 }
1964
1965 static HRESULT WINAPI StdMarshalCF_CreateInstance(LPCLASSFACTORY iface,
1966     LPUNKNOWN pUnk, REFIID riid, LPVOID *ppv)
1967 {
1968     if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IMarshal))
1969         return StdMarshalImpl_Construct(riid, ppv);
1970
1971     FIXME("(%s), not supported.\n",debugstr_guid(riid));
1972     return E_NOINTERFACE;
1973 }
1974
1975 static HRESULT WINAPI StdMarshalCF_LockServer(LPCLASSFACTORY iface, BOOL fLock)
1976 {
1977     FIXME("(%d), stub!\n",fLock);
1978     return S_OK;
1979 }
1980
1981 static const IClassFactoryVtbl StdMarshalCFVtbl =
1982 {
1983     StdMarshalCF_QueryInterface,
1984     StdMarshalCF_AddRef,
1985     StdMarshalCF_Release,
1986     StdMarshalCF_CreateInstance,
1987     StdMarshalCF_LockServer
1988 };
1989 static const IClassFactoryVtbl *StdMarshalCF = &StdMarshalCFVtbl;
1990
1991 HRESULT MARSHAL_GetStandardMarshalCF(LPVOID *ppv)
1992 {
1993     *ppv = &StdMarshalCF;
1994     return S_OK;
1995 }
1996
1997 /***********************************************************************
1998  *              CoMarshalHresult        [OLE32.@]
1999  *
2000  * Marshals an HRESULT value into a stream.
2001  *
2002  * PARAMS
2003  *  pStm    [I] Stream that hresult will be marshalled into.
2004  *  hresult [I] HRESULT to be marshalled.
2005  *
2006  * RETURNS
2007  *  Success: S_OK
2008  *  Failure: A COM error code
2009  *
2010  * SEE ALSO
2011  *  CoUnmarshalHresult().
2012  */
2013 HRESULT WINAPI CoMarshalHresult(LPSTREAM pStm, HRESULT hresult)
2014 {
2015     return IStream_Write(pStm, &hresult, sizeof(hresult), NULL);
2016 }
2017
2018 /***********************************************************************
2019  *              CoUnmarshalHresult      [OLE32.@]
2020  *
2021  * Unmarshals an HRESULT value from a stream.
2022  *
2023  * PARAMS
2024  *  pStm     [I] Stream that hresult will be unmarshalled from.
2025  *  phresult [I] Pointer to HRESULT where the value will be unmarshalled to.
2026  *
2027  * RETURNS
2028  *  Success: S_OK
2029  *  Failure: A COM error code
2030  *
2031  * SEE ALSO
2032  *  CoMarshalHresult().
2033  */
2034 HRESULT WINAPI CoUnmarshalHresult(LPSTREAM pStm, HRESULT * phresult)
2035 {
2036     return IStream_Read(pStm, phresult, sizeof(*phresult), NULL);
2037 }