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