Implements OleLoadPicturePath.
[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 register_ifstub(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 = 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     /* FIXME: what happens if we register an interface twice with different
121      * marshaling flags? */
122     if ((manager = get_stub_manager_from_object(apt, obj)))
123         TRACE("registering new ifstub on pre-existing manager\n");
124     else
125     {
126         TRACE("constructing new stub manager\n");
127
128         manager = new_stub_manager(apt, obj, mshlflags);
129         if (!manager)
130             return E_OUTOFMEMORY;
131     }
132     stdobjref->oid = manager->oid;
133
134     tablemarshal = ((mshlflags & MSHLFLAGS_TABLESTRONG) || (mshlflags & MSHLFLAGS_TABLEWEAK));
135
136     ifstub = stub_manager_new_ifstub(manager, stub, obj, riid);
137     if (!ifstub)
138     {
139         IRpcStubBuffer_Release(stub);
140         stub_manager_int_release(manager);
141         /* FIXME: should we do another release to completely destroy the
142          * stub manager? */
143         return E_OUTOFMEMORY;
144     }
145
146     if (!tablemarshal)
147     {
148         stdobjref->cPublicRefs = NORMALEXTREFS;
149         stub_manager_ext_addref(manager, stdobjref->cPublicRefs);
150     }
151     else
152     {
153         stdobjref->cPublicRefs = 0;
154         if (mshlflags & MSHLFLAGS_TABLESTRONG)
155             stub_manager_ext_addref(manager, 1);
156     }
157
158     /* FIXME: check return value */
159     RPC_RegisterInterface(riid);
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, const 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   APARTMENT            *apt = COM_CurrentApt();
791     
792   TRACE("(...,%s,...)\n",debugstr_guid(riid));
793
794   if (!apt)
795   {
796       ERR("Apartment not initialized\n");
797       return CO_E_NOTINITIALIZED;
798   }
799
800   /* make sure this apartment can be reached from other threads / processes */
801   RPC_StartRemoting(apt);
802
803   hres = IUnknown_QueryInterface((LPUNKNOWN)pv, riid, (LPVOID*)&pUnk);
804   if (hres != S_OK)
805   {
806       ERR("object doesn't expose interface %s, failing with error 0x%08lx\n",
807         debugstr_guid(riid), hres);
808       return E_NOINTERFACE;
809   }
810
811   hres = register_ifstub(apt, &stdobjref, riid, pUnk, mshlflags);
812   
813   IUnknown_Release(pUnk);
814   
815   if (hres)
816   {
817     FIXME("Failed to create ifstub, hres=0x%lx\n", hres);
818     return hres;
819   }
820
821   hres = IStream_Write(pStm, &stdobjref, sizeof(stdobjref), &res);
822   if (hres) return hres;
823
824   return S_OK;
825 }
826
827 /* helper for StdMarshalImpl_UnmarshalInterface - does the unmarshaling with
828  * no questions asked about the rules surrounding same-apartment unmarshals
829  * and table marshaling */
830 static HRESULT unmarshal_object(const STDOBJREF *stdobjref, APARTMENT *apt, REFIID riid, void **object)
831 {
832     struct proxy_manager *proxy_manager = NULL;
833     HRESULT hr = S_OK;
834
835     assert(apt);
836
837     TRACE("stdobjref:\n\tflags = %04lx\n\tcPublicRefs = %ld\n\toxid = %s\n\toid = %s\n\tipid = %s\n",
838         stdobjref->flags, stdobjref->cPublicRefs,
839         wine_dbgstr_longlong(stdobjref->oxid),
840         wine_dbgstr_longlong(stdobjref->oid),
841         debugstr_guid(&stdobjref->ipid));
842
843     /* create an a new proxy manager if one doesn't already exist for the
844      * object */
845     if (!find_proxy_manager(apt, stdobjref->oxid, stdobjref->oid, &proxy_manager))
846     {
847         IRpcChannelBuffer *chanbuf;
848
849         hr = RPC_CreateClientChannel(&stdobjref->oxid, &stdobjref->ipid, &chanbuf);
850         if (hr == S_OK)
851             hr = proxy_manager_construct(apt, stdobjref->flags,
852                                          stdobjref->oxid, stdobjref->oid,
853                                          chanbuf, &proxy_manager);
854     }
855     else
856         TRACE("proxy manager already created, using\n");
857
858     if (hr == S_OK)
859     {
860         struct ifproxy * ifproxy;
861         hr = proxy_manager_find_ifproxy(proxy_manager, riid, &ifproxy);
862         if (hr == E_NOINTERFACE)
863             hr = proxy_manager_create_ifproxy(proxy_manager, &stdobjref->ipid,
864                                               riid, stdobjref->cPublicRefs,
865                                               &ifproxy);
866
867         if (hr == S_OK)
868         {
869             /* FIXME: push this AddRef inside proxy_manager_find_ifproxy/create_ifproxy? */
870             ClientIdentity_AddRef((IMultiQI*)&proxy_manager->lpVtbl);
871             *object = ifproxy->iface;
872         }
873     }
874
875     /* release our reference to the proxy manager - the client/apartment
876      * will hold on to the remaining reference for us */
877     if (proxy_manager) ClientIdentity_Release((IMultiQI*)&proxy_manager->lpVtbl);
878
879     return hr;
880 }
881
882 static HRESULT WINAPI
883 StdMarshalImpl_UnmarshalInterface(LPMARSHAL iface, IStream *pStm, REFIID riid, void **ppv)
884 {
885   struct stub_manager  *stubmgr;
886   STDOBJREF stdobjref;
887   ULONG                 res;
888   HRESULT               hres;
889   APARTMENT *apt = COM_CurrentApt();
890   APARTMENT *stub_apt;
891
892   TRACE("(...,%s,....)\n",debugstr_guid(riid));
893
894   /* we need an apartment to unmarshal into */
895   if (!apt)
896   {
897       ERR("Apartment not initialized\n");
898       return CO_E_NOTINITIALIZED;
899   }
900
901   /* read STDOBJREF from wire */
902   hres = IStream_Read(pStm, &stdobjref, sizeof(stdobjref), &res);
903   if (hres) return hres;
904   
905   /* check if we're marshalling back to ourselves */
906   if ((apt->oxid == stdobjref.oxid) && (stubmgr = get_stub_manager(apt, stdobjref.oid)))
907   {
908       TRACE("Unmarshalling object marshalled in same apartment for iid %s, "
909             "returning original object %p\n", debugstr_guid(riid), stubmgr->object);
910     
911       hres = IUnknown_QueryInterface(stubmgr->object, riid, ppv);
912       
913       /* unref the ifstub. FIXME: only do this on success? */
914       if (!stub_manager_is_table_marshaled(stubmgr))
915           stub_manager_ext_release(stubmgr, 1);
916
917       stub_manager_int_release(stubmgr);
918       return hres;
919   }
920
921   /* notify stub manager about unmarshal if process-local object.
922    * note: if the oxid is not found then we and native will quite happily
923    * ignore table marshaling and normal marshaling rules regarding number of
924    * unmarshals, etc, but if you abuse these rules then your proxy could end
925    * up returning RPC_E_DISCONNECTED. */
926   if ((stub_apt = COM_ApartmentFromOXID(stdobjref.oxid, TRUE)))
927   {
928       if ((stubmgr = get_stub_manager(stub_apt, stdobjref.oid)))
929       {
930           if (!stub_manager_notify_unmarshal(stubmgr))
931               hres = CO_E_OBJNOTCONNECTED;
932
933           stub_manager_int_release(stubmgr);
934       }
935       else
936       {
937           WARN("Couldn't find object for OXID %s, OID %s, assuming disconnected\n",
938               wine_dbgstr_longlong(stdobjref.oxid),
939               wine_dbgstr_longlong(stdobjref.oid));
940           hres = CO_E_OBJNOTCONNECTED;
941       }
942
943       COM_ApartmentRelease(stub_apt);
944   }
945   else
946       TRACE("Treating unmarshal from OXID %s as inter-process\n",
947             wine_dbgstr_longlong(stdobjref.oxid));
948
949   if (hres == S_OK)
950       hres = unmarshal_object(&stdobjref, apt, riid, ppv);
951
952   if (hres) WARN("Failed with error 0x%08lx\n", hres);
953   else TRACE("Successfully created proxy %p\n", *ppv);
954
955   return hres;
956 }
957
958 static HRESULT WINAPI
959 StdMarshalImpl_ReleaseMarshalData(LPMARSHAL iface, IStream *pStm) {
960     STDOBJREF            stdobjref;
961     ULONG                res;
962     HRESULT              hres;
963     struct stub_manager *stubmgr;
964     APARTMENT           *apt;
965
966     TRACE("iface=%p, pStm=%p\n", iface, pStm);
967     
968     hres = IStream_Read(pStm, &stdobjref, sizeof(stdobjref), &res);
969     if (hres) return hres;
970
971     if (!(apt = COM_ApartmentFromOXID(stdobjref.oxid, TRUE)))
972     {
973         WARN("Could not map OXID %s to apartment object\n",
974             wine_dbgstr_longlong(stdobjref.oxid));
975         return RPC_E_INVALID_OBJREF;
976     }
977
978     if (!(stubmgr = get_stub_manager(apt, stdobjref.oid)))
979     {
980         ERR("could not map MID to stub manager, oxid=%s, oid=%s\n",
981             wine_dbgstr_longlong(stdobjref.oxid), wine_dbgstr_longlong(stdobjref.oid));
982         return RPC_E_INVALID_OBJREF;
983     }
984
985     stub_manager_release_marshal_data(stubmgr, stdobjref.cPublicRefs);
986
987     stub_manager_int_release(stubmgr);
988     COM_ApartmentRelease(apt);
989
990     return S_OK;
991 }
992
993 static HRESULT WINAPI
994 StdMarshalImpl_DisconnectObject(LPMARSHAL iface, DWORD dwReserved) {
995   FIXME("(), stub!\n");
996   return S_OK;
997 }
998
999 IMarshalVtbl stdmvtbl = {
1000     StdMarshalImpl_QueryInterface,
1001     StdMarshalImpl_AddRef,
1002     StdMarshalImpl_Release,
1003     StdMarshalImpl_GetUnmarshalClass,
1004     StdMarshalImpl_GetMarshalSizeMax,
1005     StdMarshalImpl_MarshalInterface,
1006     StdMarshalImpl_UnmarshalInterface,
1007     StdMarshalImpl_ReleaseMarshalData,
1008     StdMarshalImpl_DisconnectObject
1009 };
1010
1011 static HRESULT StdMarshalImpl_Construct(REFIID riid, void** ppvObject)
1012 {
1013     StdMarshalImpl * pStdMarshal = 
1014         HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(StdMarshalImpl));
1015     if (!pStdMarshal)
1016         return E_OUTOFMEMORY;
1017     pStdMarshal->lpvtbl = &stdmvtbl;
1018     pStdMarshal->ref = 0;
1019     return IMarshal_QueryInterface((IMarshal*)pStdMarshal, riid, ppvObject);
1020 }
1021
1022 /***********************************************************************
1023  *              CoGetStandardMarshal    [OLE32.@]
1024  *
1025  * Gets or creates a standard marshal object.
1026  *
1027  * PARAMS
1028  *  riid          [I] Interface identifier of the pUnk object.
1029  *  pUnk          [I] Optional. Object to get the marshal object for.
1030  *  dwDestContext [I] Destination. Used to enable or disable optimizations.
1031  *  pvDestContext [I] Reserved. Must be NULL.
1032  *  mshlflags     [I] Flags affecting the marshaling process.
1033  *  ppMarshal     [O] Address where marshal object will be stored.
1034  *
1035  * RETURNS
1036  *  Success: S_OK.
1037  *  Failure: HRESULT code.
1038  *
1039  * NOTES
1040  *
1041  * The function retrieves the IMarshal object associated with an object if
1042  * that object is currently an active stub, otherwise a new marshal object is
1043  * created.
1044  */
1045 HRESULT WINAPI CoGetStandardMarshal(REFIID riid, IUnknown *pUnk,
1046                                     DWORD dwDestContext, LPVOID pvDestContext,
1047                                     DWORD mshlflags, LPMARSHAL *ppMarshal)
1048 {
1049   StdMarshalImpl *dm;
1050
1051   if (pUnk == NULL) {
1052     FIXME("(%s,NULL,%lx,%p,%lx,%p), unimplemented yet.\n",
1053       debugstr_guid(riid),dwDestContext,pvDestContext,mshlflags,ppMarshal
1054     );
1055     return E_FAIL;
1056   }
1057   TRACE("(%s,%p,%lx,%p,%lx,%p)\n",
1058     debugstr_guid(riid),pUnk,dwDestContext,pvDestContext,mshlflags,ppMarshal
1059   );
1060   *ppMarshal = HeapAlloc(GetProcessHeap(),0,sizeof(StdMarshalImpl));
1061   dm = (StdMarshalImpl*) *ppMarshal;
1062   if (!dm) return E_FAIL;
1063   dm->lpvtbl            = &stdmvtbl;
1064   dm->ref               = 1;
1065
1066   memcpy(&dm->iid,riid,sizeof(dm->iid));
1067   dm->dwDestContext     = dwDestContext;
1068   dm->pvDestContext     = pvDestContext;
1069   dm->mshlflags         = mshlflags;
1070   return S_OK;
1071 }
1072
1073 /***********************************************************************
1074  *              get_marshaler   [internal]
1075  *
1076  * Retrieves an IMarshal interface for an object.
1077  */
1078 static HRESULT get_marshaler(REFIID riid, IUnknown *pUnk, DWORD dwDestContext,
1079                              void *pvDestContext, DWORD mshlFlags,
1080                              LPMARSHAL *pMarshal)
1081 {
1082     HRESULT hr;
1083
1084     if (!pUnk)
1085         return E_POINTER;
1086     hr = IUnknown_QueryInterface(pUnk, &IID_IMarshal, (LPVOID*)pMarshal);
1087     if (hr)
1088         hr = CoGetStandardMarshal(riid, pUnk, dwDestContext, pvDestContext,
1089                                   mshlFlags, pMarshal);
1090     return hr;
1091 }
1092
1093 /***********************************************************************
1094  *              get_unmarshaler_from_stream     [internal]
1095  *
1096  * Creates an IMarshal* object according to the data marshaled to the stream.
1097  * The function leaves the stream pointer at the start of the data written
1098  * to the stream by the IMarshal* object.
1099  */
1100 static HRESULT get_unmarshaler_from_stream(IStream *stream, IMarshal **marshal, IID *iid)
1101 {
1102     HRESULT hr;
1103     ULONG res;
1104     OBJREF objref;
1105
1106     /* read common OBJREF header */
1107     hr = IStream_Read(stream, &objref, FIELD_OFFSET(OBJREF, u_objref), &res);
1108     if (hr || (res != FIELD_OFFSET(OBJREF, u_objref)))
1109     {
1110         ERR("Failed to read common OBJREF header, 0x%08lx\n", hr);
1111         return STG_E_READFAULT;
1112     }
1113
1114     /* sanity check on header */
1115     if (objref.signature != OBJREF_SIGNATURE)
1116     {
1117         ERR("Bad OBJREF signature 0x%08lx\n", objref.signature);
1118         return RPC_E_INVALID_OBJREF;
1119     }
1120
1121     if (iid) *iid = objref.iid;
1122
1123     /* FIXME: handler marshaling */
1124     if (objref.flags & OBJREF_STANDARD)
1125     {
1126         TRACE("Using standard unmarshaling\n");
1127         hr = StdMarshalImpl_Construct(&IID_IMarshal, (LPVOID*)marshal);
1128     }
1129     else if (objref.flags & OBJREF_CUSTOM)
1130     {
1131         ULONG custom_header_size = FIELD_OFFSET(OBJREF, u_objref.u_custom.size) - 
1132                                    FIELD_OFFSET(OBJREF, u_objref.u_custom);
1133         TRACE("Using custom unmarshaling\n");
1134         /* read constant sized OR_CUSTOM data from stream */
1135         hr = IStream_Read(stream, &objref.u_objref.u_custom,
1136                           custom_header_size, &res);
1137         if (hr || (res != custom_header_size))
1138         {
1139             ERR("Failed to read OR_CUSTOM header, 0x%08lx\n", hr);
1140             return STG_E_READFAULT;
1141         }
1142         /* now create the marshaler specified in the stream */
1143         hr = CoCreateInstance(&objref.u_objref.u_custom.clsid, NULL,
1144                               CLSCTX_INPROC_SERVER, &IID_IMarshal,
1145                               (LPVOID*)marshal);
1146     }
1147     else
1148     {
1149         FIXME("Invalid or unimplemented marshaling type specified: %lx\n",
1150             objref.flags);
1151         return RPC_E_INVALID_OBJREF;
1152     }
1153
1154     if (hr)
1155         ERR("Failed to create marshal, 0x%08lx\n", hr);
1156
1157     return hr;
1158 }
1159
1160 /***********************************************************************
1161  *              CoGetMarshalSizeMax     [OLE32.@]
1162  *
1163  * Gets the maximum amount of data that will be needed by a marshal.
1164  *
1165  * PARAMS
1166  *  pulSize       [O] Address where maximum marshal size will be stored.
1167  *  riid          [I] Identifier of the interface to marshal.
1168  *  pUnk          [I] Pointer to the object to marshal.
1169  *  dwDestContext [I] Destination. Used to enable or disable optimizations.
1170  *  pvDestContext [I] Reserved. Must be NULL.
1171  *  mshlFlags     [I] Flags that affect the marshaling. See CoMarshalInterface().
1172  *
1173  * RETURNS
1174  *  Success: S_OK.
1175  *  Failure: HRESULT code.
1176  *
1177  * SEE ALSO
1178  *  CoMarshalInterface().
1179  */
1180 HRESULT WINAPI CoGetMarshalSizeMax(ULONG *pulSize, REFIID riid, IUnknown *pUnk,
1181                                    DWORD dwDestContext, void *pvDestContext,
1182                                    DWORD mshlFlags)
1183 {
1184     HRESULT hr;
1185     LPMARSHAL pMarshal;
1186     CLSID marshaler_clsid;
1187
1188     hr = get_marshaler(riid, pUnk, dwDestContext, pvDestContext, mshlFlags, &pMarshal);
1189     if (hr)
1190         return hr;
1191
1192     hr = IMarshal_GetUnmarshalClass(pMarshal, riid, pUnk, dwDestContext,
1193                                     pvDestContext, mshlFlags, &marshaler_clsid);
1194     if (hr)
1195     {
1196         ERR("IMarshal::GetUnmarshalClass failed, 0x%08lx\n", hr);
1197         IMarshal_Release(pMarshal);
1198         return hr;
1199     }
1200
1201     hr = IMarshal_GetMarshalSizeMax(pMarshal, riid, pUnk, dwDestContext,
1202                                     pvDestContext, mshlFlags, pulSize);
1203     /* add on the size of the common header */
1204     *pulSize += FIELD_OFFSET(OBJREF, u_objref);
1205
1206     /* if custom marshaling, add on size of custom header */
1207     if (!IsEqualCLSID(&marshaler_clsid, &CLSID_DfMarshal))
1208         *pulSize += FIELD_OFFSET(OBJREF, u_objref.u_custom.size) - 
1209                     FIELD_OFFSET(OBJREF, u_objref.u_custom);
1210
1211     IMarshal_Release(pMarshal);
1212     return hr;
1213 }
1214
1215
1216 /***********************************************************************
1217  *              CoMarshalInterface      [OLE32.@]
1218  *
1219  * Marshals an interface into a stream so that the object can then be
1220  * unmarshaled from another COM apartment and used remotely.
1221  *
1222  * PARAMS
1223  *  pStream       [I] Stream the object will be marshaled into.
1224  *  riid          [I] Identifier of the interface to marshal.
1225  *  pUnk          [I] Pointer to the object to marshal.
1226  *  dwDestContext [I] Destination. Used to enable or disable optimizations.
1227  *  pvDestContext [I] Reserved. Must be NULL.
1228  *  mshlFlags     [I] Flags that affect the marshaling. See notes.
1229  *
1230  * RETURNS
1231  *  Success: S_OK.
1232  *  Failure: HRESULT code.
1233  *
1234  * NOTES
1235  *
1236  * The mshlFlags parameter can take one or more of the following flags:
1237  *| MSHLFLAGS_NORMAL - Unmarshal once, releases stub on last proxy release.
1238  *| MSHLFLAGS_TABLESTRONG - Unmarshal many, release when CoReleaseMarshalData() called.
1239  *| MSHLFLAGS_TABLEWEAK - Unmarshal many, releases stub on last proxy release.
1240  *| MSHLFLAGS_NOPING - No automatic garbage collection (and so reduces network traffic).
1241  *
1242  * If a marshaled object is not unmarshaled, then CoReleaseMarshalData() must
1243  * be called in order to release the resources used in the marshaling.
1244  *
1245  * SEE ALSO
1246  *  CoUnmarshalInterface(), CoReleaseMarshalData().
1247  */
1248 HRESULT WINAPI CoMarshalInterface(IStream *pStream, REFIID riid, IUnknown *pUnk,
1249                                   DWORD dwDestContext, void *pvDestContext,
1250                                   DWORD mshlFlags)
1251 {
1252     HRESULT     hr;
1253     CLSID marshaler_clsid;
1254     OBJREF objref;
1255     IStream * pMarshalStream = NULL;
1256     LPMARSHAL pMarshal;
1257
1258     TRACE("(%p, %s, %p, %lx, %p, %lx)\n", pStream, debugstr_guid(riid), pUnk,
1259         dwDestContext, pvDestContext, mshlFlags);
1260
1261     if (pUnk == NULL)
1262         return E_INVALIDARG;
1263
1264     objref.signature = OBJREF_SIGNATURE;
1265     objref.iid = *riid;
1266
1267     /* get the marshaler for the specified interface */
1268     hr = get_marshaler(riid, pUnk, dwDestContext, pvDestContext, mshlFlags, &pMarshal);
1269     if (hr)
1270     {
1271         ERR("Failed to get marshaller, 0x%08lx\n", hr);
1272         return hr;
1273     }
1274
1275     hr = IMarshal_GetUnmarshalClass(pMarshal, riid, pUnk, dwDestContext,
1276                                     pvDestContext, mshlFlags, &marshaler_clsid);
1277     if (hr)
1278     {
1279         ERR("IMarshal::GetUnmarshalClass failed, 0x%08lx\n", hr);
1280         goto cleanup;
1281     }
1282
1283     /* FIXME: implement handler marshaling too */
1284     if (IsEqualCLSID(&marshaler_clsid, &CLSID_DfMarshal))
1285     {
1286         TRACE("Using standard marshaling\n");
1287         objref.flags = OBJREF_STANDARD;
1288         pMarshalStream = pStream;
1289     }
1290     else
1291     {
1292         TRACE("Using custom marshaling\n");
1293         objref.flags = OBJREF_CUSTOM;
1294         /* we do custom marshaling into a memory stream so that we know what
1295          * size to write into the OR_CUSTOM header */
1296         hr = CreateStreamOnHGlobal(NULL, TRUE, &pMarshalStream);
1297         if (hr)
1298         {
1299             ERR("CreateStreamOnHGLOBAL failed with 0x%08lx\n", hr);
1300             goto cleanup;
1301         }
1302     }
1303
1304     /* write the common OBJREF header to the stream */
1305     hr = IStream_Write(pStream, &objref, FIELD_OFFSET(OBJREF, u_objref), NULL);
1306     if (hr)
1307     {
1308         ERR("Failed to write OBJREF header to stream, 0x%08lx\n", hr);
1309         goto cleanup;
1310     }
1311
1312     TRACE("Calling IMarshal::MarshalInterace\n");
1313     /* call helper object to do the actual marshaling */
1314     hr = IMarshal_MarshalInterface(pMarshal, pMarshalStream, riid, pUnk, dwDestContext,
1315                                    pvDestContext, mshlFlags);
1316
1317     if (hr)
1318     {
1319         ERR("Failed to marshal the interface %s, %lx\n", debugstr_guid(riid), hr);
1320         goto cleanup;
1321     }
1322
1323     if (objref.flags & OBJREF_CUSTOM)
1324     {
1325         ULONG custom_header_size = FIELD_OFFSET(OBJREF, u_objref.u_custom.size) - 
1326                                    FIELD_OFFSET(OBJREF, u_objref.u_custom);
1327         HGLOBAL hGlobal;
1328         LPVOID data;
1329         hr = GetHGlobalFromStream(pMarshalStream, &hGlobal);
1330         if (hr)
1331         {
1332             ERR("Couldn't get HGLOBAL from stream\n");
1333             hr = E_UNEXPECTED;
1334             goto cleanup;
1335         }
1336         objref.u_objref.u_custom.clsid = marshaler_clsid;
1337         objref.u_objref.u_custom.cbExtension = 0;
1338         objref.u_objref.u_custom.size = GlobalSize(hGlobal);
1339         /* write constant sized OR_CUSTOM data into stream */
1340         hr = IStream_Write(pStream, &objref.u_objref.u_custom,
1341                           custom_header_size, NULL);
1342         if (hr)
1343         {
1344             ERR("Failed to write OR_CUSTOM header to stream with 0x%08lx\n", hr);
1345             goto cleanup;
1346         }
1347
1348         data = GlobalLock(hGlobal);
1349         if (!data)
1350         {
1351             ERR("GlobalLock failed\n");
1352             hr = E_UNEXPECTED;
1353             goto cleanup;
1354         }
1355         /* write custom marshal data */
1356         hr = IStream_Write(pStream, data, objref.u_objref.u_custom.size, NULL);
1357         if (hr)
1358         {
1359             ERR("Failed to write custom marshal data with 0x%08lx\n", hr);
1360             goto cleanup;
1361         }
1362         GlobalUnlock(hGlobal);
1363     }
1364
1365 cleanup:
1366     if (pMarshalStream && (objref.flags & OBJREF_CUSTOM))
1367         IStream_Release(pMarshalStream);
1368     IMarshal_Release(pMarshal);
1369
1370     TRACE("completed with hr 0x%08lx\n", hr);
1371     
1372     return hr;
1373 }
1374
1375 /***********************************************************************
1376  *              CoUnmarshalInterface    [OLE32.@]
1377  *
1378  * Unmarshals an object from a stream by creating a proxy to the remote
1379  * object, if necessary.
1380  *
1381  * PARAMS
1382  *
1383  *  pStream [I] Stream containing the marshaled object.
1384  *  riid    [I] Interface identifier of the object to create a proxy to.
1385  *  ppv     [O] Address where proxy will be stored.
1386  *
1387  * RETURNS
1388  *
1389  *  Success: S_OK.
1390  *  Failure: HRESULT code.
1391  *
1392  * SEE ALSO
1393  *  CoMarshalInterface().
1394  */
1395 HRESULT WINAPI CoUnmarshalInterface(IStream *pStream, REFIID riid, LPVOID *ppv)
1396 {
1397     HRESULT hr;
1398     LPMARSHAL pMarshal;
1399     IID iid;
1400     IUnknown *object;
1401
1402     TRACE("(%p, %s, %p)\n", pStream, debugstr_guid(riid), ppv);
1403
1404     hr = get_unmarshaler_from_stream(pStream, &pMarshal, &iid);
1405     if (hr != S_OK)
1406         return hr;
1407
1408     /* call the helper object to do the actual unmarshaling */
1409     hr = IMarshal_UnmarshalInterface(pMarshal, pStream, &iid, (LPVOID*)&object);
1410     if (hr)
1411         ERR("IMarshal::UnmarshalInterface failed, 0x%08lx\n", hr);
1412
1413     /* IID_NULL means use the interface ID of the marshaled object */
1414     if (!IsEqualIID(riid, &IID_NULL))
1415         iid = *riid;
1416
1417     if (hr == S_OK)
1418     {
1419         if (!IsEqualIID(riid, &iid))
1420         {
1421             TRACE("requested interface != marshalled interface, additional QI needed\n");
1422             hr = IUnknown_QueryInterface(object, &iid, ppv);
1423             if (hr)
1424                 ERR("Couldn't query for interface %s, hr = 0x%08lx\n",
1425                     debugstr_guid(riid), hr);
1426             IUnknown_Release(object);
1427         }
1428         else
1429         {
1430             *ppv = object;
1431         }
1432     }
1433
1434     IMarshal_Release(pMarshal);
1435
1436     TRACE("completed with hr 0x%lx\n", hr);
1437     
1438     return hr;
1439 }
1440
1441 /***********************************************************************
1442  *              CoReleaseMarshalData    [OLE32.@]
1443  *
1444  * Releases resources associated with an object that has been marshaled into
1445  * a stream.
1446  *
1447  * PARAMS
1448  *
1449  *  pStream [I] The stream that the object has been marshaled into.
1450  *
1451  * RETURNS
1452  *  Success: S_OK.
1453  *  Failure: HRESULT error code.
1454  *
1455  * NOTES
1456  * 
1457  * Call this function to release resources associated with a normal or
1458  * table-weak marshal that will not be unmarshaled, and all table-strong
1459  * marshals when they are no longer needed.
1460  *
1461  * SEE ALSO
1462  *  CoMarshalInterface(), CoUnmarshalInterface().
1463  */
1464 HRESULT WINAPI CoReleaseMarshalData(IStream *pStream)
1465 {
1466     HRESULT     hr;
1467     LPMARSHAL pMarshal;
1468
1469     TRACE("(%p)\n", pStream);
1470
1471     hr = get_unmarshaler_from_stream(pStream, &pMarshal, NULL);
1472     if (hr != S_OK)
1473         return hr;
1474
1475     /* call the helper object to do the releasing of marshal data */
1476     hr = IMarshal_ReleaseMarshalData(pMarshal, pStream);
1477     if (hr)
1478         ERR("IMarshal::ReleaseMarshalData failed with error 0x%08lx\n", hr);
1479
1480     IMarshal_Release(pMarshal);
1481     return hr;
1482 }
1483
1484
1485 /***********************************************************************
1486  *              CoMarshalInterThreadInterfaceInStream   [OLE32.@]
1487  *
1488  * Marshal an interface across threads in the same process.
1489  *
1490  * PARAMS
1491  *  riid  [I] Identifier of the interface to be marshalled.
1492  *  pUnk  [I] Pointer to IUnknown-derived interface that will be marshalled.
1493  *  ppStm [O] Pointer to IStream object that is created and then used to store the marshalled inteface.
1494  *
1495  * RETURNS
1496  *  Success: S_OK
1497  *  Failure: E_OUTOFMEMORY and other COM error codes
1498  *
1499  * SEE ALSO
1500  *   CoMarshalInterface(), CoUnmarshalInterface() and CoGetInterfaceAndReleaseStream()
1501  */
1502 HRESULT WINAPI CoMarshalInterThreadInterfaceInStream(
1503     REFIID riid, LPUNKNOWN pUnk, LPSTREAM * ppStm)
1504 {
1505     ULARGE_INTEGER      xpos;
1506     LARGE_INTEGER               seekto;
1507     HRESULT             hres;
1508
1509     TRACE("(%s, %p, %p)\n",debugstr_guid(riid), pUnk, ppStm);
1510
1511     hres = CreateStreamOnHGlobal(0, TRUE, ppStm);
1512     if (FAILED(hres)) return hres;
1513     hres = CoMarshalInterface(*ppStm, riid, pUnk, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1514
1515     /* FIXME: is this needed? */
1516     memset(&seekto,0,sizeof(seekto));
1517     IStream_Seek(*ppStm,seekto,SEEK_SET,&xpos);
1518
1519     return hres;
1520 }
1521
1522 /***********************************************************************
1523  *              CoGetInterfaceAndReleaseStream  [OLE32.@]
1524  *
1525  * Unmarshalls an inteface from a stream and then releases the stream.
1526  *
1527  * PARAMS
1528  *  pStm [I] Stream that contains the marshalled inteface.
1529  *  riid [I] Interface identifier of the object to unmarshall.
1530  *  ppv  [O] Address of pointer where the requested interface object will be stored.
1531  *
1532  * RETURNS
1533  *  Success: S_OK
1534  *  Failure: A COM error code
1535  *
1536  * SEE ALSO
1537  *  CoMarshalInterThreadInterfaceInStream() and CoUnmarshalInteface()
1538  */
1539 HRESULT WINAPI CoGetInterfaceAndReleaseStream(LPSTREAM pStm, REFIID riid,
1540                                               LPVOID *ppv)
1541 {
1542     HRESULT hres;
1543
1544     TRACE("(%p, %s, %p)\n", pStm, debugstr_guid(riid), ppv);
1545
1546     hres = CoUnmarshalInterface(pStm, riid, ppv);
1547     IStream_Release(pStm);
1548     return hres;
1549 }
1550
1551 static HRESULT WINAPI StdMarshalCF_QueryInterface(LPCLASSFACTORY iface,
1552                                                   REFIID riid, LPVOID *ppv)
1553 {
1554     *ppv = NULL;
1555     if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IClassFactory))
1556     {
1557         *ppv = (LPVOID)iface;
1558         return S_OK;
1559     }
1560     return E_NOINTERFACE;
1561 }
1562
1563 static ULONG WINAPI StdMarshalCF_AddRef(LPCLASSFACTORY iface)
1564 {
1565     return 2; /* non-heap based object */
1566 }
1567
1568 static ULONG WINAPI StdMarshalCF_Release(LPCLASSFACTORY iface)
1569 {
1570     return 1; /* non-heap based object */
1571 }
1572
1573 static HRESULT WINAPI StdMarshalCF_CreateInstance(LPCLASSFACTORY iface,
1574     LPUNKNOWN pUnk, REFIID riid, LPVOID *ppv)
1575 {
1576   if (IsEqualIID(riid,&IID_IMarshal))
1577     return StdMarshalImpl_Construct(riid, ppv);
1578
1579   FIXME("(%s), not supported.\n",debugstr_guid(riid));
1580   return E_NOINTERFACE;
1581 }
1582
1583 static HRESULT WINAPI StdMarshalCF_LockServer(LPCLASSFACTORY iface, BOOL fLock)
1584 {
1585     FIXME("(%d), stub!\n",fLock);
1586     return S_OK;
1587 }
1588
1589 static IClassFactoryVtbl StdMarshalCFVtbl =
1590 {
1591     StdMarshalCF_QueryInterface,
1592     StdMarshalCF_AddRef,
1593     StdMarshalCF_Release,
1594     StdMarshalCF_CreateInstance,
1595     StdMarshalCF_LockServer
1596 };
1597 static IClassFactoryVtbl *StdMarshalCF = &StdMarshalCFVtbl;
1598
1599 HRESULT MARSHAL_GetStandardMarshalCF(LPVOID *ppv)
1600 {
1601     *ppv = &StdMarshalCF;
1602     return S_OK;
1603 }
1604
1605 /***********************************************************************
1606  *              CoMarshalHresult        [OLE32.@]
1607  *
1608  * Marshals an HRESULT value into a stream.
1609  *
1610  * PARAMS
1611  *  pStm    [I] Stream that hresult will be marshalled into.
1612  *  hresult [I] HRESULT to be marshalled.
1613  *
1614  * RETURNS
1615  *  Success: S_OK
1616  *  Failure: A COM error code
1617  *
1618  * SEE ALSO
1619  *  CoUnmarshalHresult().
1620  */
1621 HRESULT WINAPI CoMarshalHresult(LPSTREAM pStm, HRESULT hresult)
1622 {
1623     return IStream_Write(pStm, &hresult, sizeof(hresult), NULL);
1624 }
1625
1626 /***********************************************************************
1627  *              CoUnmarshalHresult      [OLE32.@]
1628  *
1629  * Unmarshals an HRESULT value from a stream.
1630  *
1631  * PARAMS
1632  *  pStm     [I] Stream that hresult will be unmarshalled from.
1633  *  phresult [I] Pointer to HRESULT where the value will be unmarshalled to.
1634  *
1635  * RETURNS
1636  *  Success: S_OK
1637  *  Failure: A COM error code
1638  *
1639  * SEE ALSO
1640  *  CoMarshalHresult().
1641  */
1642 HRESULT WINAPI CoUnmarshalHresult(LPSTREAM pStm, HRESULT * phresult)
1643 {
1644     return IStream_Read(pStm, phresult, sizeof(*phresult), NULL);
1645 }