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