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