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