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