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