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