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