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