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