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