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