Pass correct pointer to SHFree in case of failure in
[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         hr = S_OK;
632     }
633     else
634     {
635         hr = get_facbuf_for_iid(riid, &psfb);
636         if (hr == S_OK)
637         {
638             /* important note: the outer unknown is set to the proxy manager.
639              * This ensures the COM identity rules are not violated, by having a
640              * one-to-one mapping of objects on the proxy side to objects on the
641              * stub side, no matter which interface you view the object through */
642             hr = IPSFactoryBuffer_CreateProxy(psfb, (IUnknown *)&This->lpVtbl, riid,
643                                               &ifproxy->proxy, &ifproxy->iface);
644             IPSFactoryBuffer_Release(psfb);
645             if (hr != S_OK)
646                 ERR("Could not create proxy for interface %s, error 0x%08lx\n",
647                     debugstr_guid(riid), hr);
648         }
649         else
650             ERR("Could not get IPSFactoryBuffer for interface %s, error 0x%08lx\n",
651                 debugstr_guid(riid), hr);
652
653         if (hr == S_OK)
654             hr = IRpcProxyBuffer_Connect(ifproxy->proxy, ifproxy->chan);
655     }
656
657     /* get at least one external reference to the object to keep it alive */
658     if (hr == S_OK)
659         hr = ifproxy_get_public_ref(ifproxy);
660
661     if (hr == S_OK)
662     {
663         EnterCriticalSection(&This->cs);
664         list_add_tail(&This->interfaces, &ifproxy->entry);
665         LeaveCriticalSection(&This->cs);
666
667         *iif_out = ifproxy;
668         TRACE("ifproxy %p created for IPID %s, interface %s with %lu public refs\n",
669               ifproxy, debugstr_guid(&stdobjref->ipid), debugstr_guid(riid), stdobjref->cPublicRefs);
670     }
671     else
672         ifproxy_destroy(ifproxy);
673
674     return hr;
675 }
676
677 static HRESULT proxy_manager_find_ifproxy(struct proxy_manager * This, REFIID riid, struct ifproxy ** ifproxy_found)
678 {
679     HRESULT hr = E_NOINTERFACE; /* assume not found */
680     struct list * cursor;
681
682     EnterCriticalSection(&This->cs);
683     LIST_FOR_EACH(cursor, &This->interfaces)
684     {
685         struct ifproxy * ifproxy = LIST_ENTRY(cursor, struct ifproxy, entry);
686         if (IsEqualIID(riid, &ifproxy->iid))
687         {
688             *ifproxy_found = ifproxy;
689             hr = S_OK;
690             break;
691         }
692     }
693     LeaveCriticalSection(&This->cs);
694
695     return hr;
696 }
697
698 static void proxy_manager_disconnect(struct proxy_manager * This)
699 {
700     struct list * cursor;
701
702     TRACE("oxid = %s, oid = %s\n", wine_dbgstr_longlong(This->oxid),
703         wine_dbgstr_longlong(This->oid));
704
705     /* SORFP_NOLIFTIMEMGMT proxies (for IRemUnknown) shouldn't be
706      * disconnected - it won't do anything anyway, except cause
707      * problems for other objects that depend on this proxy always
708      * working */
709     if (This->sorflags & SORFP_NOLIFETIMEMGMT) return;
710
711     EnterCriticalSection(&This->cs);
712
713     LIST_FOR_EACH(cursor, &This->interfaces)
714     {
715         struct ifproxy * ifproxy = LIST_ENTRY(cursor, struct ifproxy, entry);
716         ifproxy_disconnect(ifproxy);
717     }
718
719     /* apartment is being destroyed so don't keep a pointer around to it */
720     This->parent = NULL;
721
722     LeaveCriticalSection(&This->cs);
723 }
724
725 static HRESULT proxy_manager_get_remunknown(struct proxy_manager * This, IRemUnknown **remunk)
726 {
727     HRESULT hr = S_OK;
728
729     /* we don't want to try and unmarshal or use IRemUnknown if we don't want
730      * lifetime management */
731     if (This->sorflags & SORFP_NOLIFETIMEMGMT)
732         return S_FALSE;
733
734     EnterCriticalSection(&This->cs);
735     if (This->remunk)
736         /* already created - return existing object */
737         *remunk = This->remunk;
738     else if (!This->parent)
739         /* disconnected - we can't create IRemUnknown */
740         hr = S_FALSE;
741     else
742     {
743         STDOBJREF stdobjref;
744         /* Don't want IRemUnknown lifetime management as this is IRemUnknown!
745          * We also don't care about whether or not the stub is still alive */
746         stdobjref.flags = SORFP_NOLIFETIMEMGMT | SORF_NOPING;
747         stdobjref.cPublicRefs = 1;
748         /* oxid of destination object */
749         stdobjref.oxid = This->oxid;
750         /* FIXME: what should be used for the oid? The DCOM draft doesn't say */
751         stdobjref.oid = (OID)-1;
752         /* FIXME: this is a hack around not having an OXID resolver yet -
753          * the OXID resolver should give us the IPID of the IRemUnknown
754          * interface */
755         stdobjref.ipid.Data1 = 0xffffffff;
756         stdobjref.ipid.Data2 = 0xffff;
757         stdobjref.ipid.Data3 = 0xffff;
758         assert(sizeof(stdobjref.ipid.Data4) == sizeof(stdobjref.oxid));
759         memcpy(&stdobjref.ipid.Data4, &stdobjref.oxid, sizeof(OXID));
760         
761         /* do the unmarshal */
762         hr = unmarshal_object(&stdobjref, This->parent, &IID_IRemUnknown, (void**)&This->remunk);
763         if (hr == S_OK)
764             *remunk = This->remunk;
765     }
766     LeaveCriticalSection(&This->cs);
767
768     TRACE("got IRemUnknown* pointer %p, hr = 0x%08lx\n", *remunk, hr);
769
770     return hr;
771 }
772
773 /* destroys a proxy manager, freeing the memory it used.
774  * Note: this function should not be called from a list iteration in the
775  * apartment, due to the fact that it removes itself from the apartment and
776  * it could add a proxy to IRemUnknown into the apartment. */
777 static void proxy_manager_destroy(struct proxy_manager * This)
778 {
779     struct list * cursor;
780
781     TRACE("oxid = %s, oid = %s\n", wine_dbgstr_longlong(This->oxid),
782         wine_dbgstr_longlong(This->oid));
783
784     if (This->parent)
785     {
786         EnterCriticalSection(&This->parent->cs);
787
788         /* remove ourself from the list of proxy objects in the apartment */
789         LIST_FOR_EACH(cursor, &This->parent->proxies)
790         {
791             if (cursor == &This->entry)
792             {
793                 list_remove(&This->entry);
794                 break;
795             }
796         }
797
798         LeaveCriticalSection(&This->parent->cs);
799     }
800
801     /* destroy all of the interface proxies */
802     while ((cursor = list_head(&This->interfaces)))
803     {
804         struct ifproxy * ifproxy = LIST_ENTRY(cursor, struct ifproxy, entry);
805         ifproxy_destroy(ifproxy);
806     }
807
808     if (This->remunk) IRemUnknown_Release(This->remunk);
809
810     DEBUG_CLEAR_CRITSEC_NAME(&This->cs);
811     DeleteCriticalSection(&This->cs);
812
813     CloseHandle(This->remoting_mutex);
814
815     HeapFree(GetProcessHeap(), 0, This);
816 }
817
818 /* finds the proxy manager corresponding to a given OXID and OID that has
819  * been unmarshaled in the specified apartment. The caller must release the
820  * reference to the proxy_manager when the object is no longer used. */
821 static BOOL find_proxy_manager(APARTMENT * apt, OXID oxid, OID oid, struct proxy_manager ** proxy_found)
822 {
823     BOOL found = FALSE;
824     struct list * cursor;
825
826     EnterCriticalSection(&apt->cs);
827     LIST_FOR_EACH(cursor, &apt->proxies)
828     {
829         struct proxy_manager * proxy = LIST_ENTRY(cursor, struct proxy_manager, entry);
830         if ((oxid == proxy->oxid) && (oid == proxy->oid))
831         {
832             *proxy_found = proxy;
833             ClientIdentity_AddRef((IMultiQI *)&proxy->lpVtbl);
834             found = TRUE;
835             break;
836         }
837     }
838     LeaveCriticalSection(&apt->cs);
839     return found;
840 }
841
842 HRESULT apartment_disconnectproxies(struct apartment *apt)
843 {
844     struct list * cursor;
845
846     LIST_FOR_EACH(cursor, &apt->proxies)
847     {
848         struct proxy_manager * proxy = LIST_ENTRY(cursor, struct proxy_manager, entry);
849         proxy_manager_disconnect(proxy);
850     }
851
852     return S_OK;
853 }
854
855 /********************** StdMarshal implementation ****************************/
856 typedef struct _StdMarshalImpl
857 {
858     const IMarshalVtbl  *lpvtbl;
859     LONG                ref;
860
861     IID                 iid;
862     DWORD               dwDestContext;
863     LPVOID              pvDestContext;
864     DWORD               mshlflags;
865 } StdMarshalImpl;
866
867 static HRESULT WINAPI 
868 StdMarshalImpl_QueryInterface(LPMARSHAL iface, REFIID riid, LPVOID *ppv)
869 {
870     *ppv = NULL;
871     if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IMarshal, riid))
872     {
873         *ppv = iface;
874         IUnknown_AddRef(iface);
875         return S_OK;
876     }
877     FIXME("No interface for %s.\n", debugstr_guid(riid));
878     return E_NOINTERFACE;
879 }
880
881 static ULONG WINAPI
882 StdMarshalImpl_AddRef(LPMARSHAL iface)
883 {
884     StdMarshalImpl *This = (StdMarshalImpl *)iface;
885     return InterlockedIncrement(&This->ref);
886 }
887
888 static ULONG WINAPI
889 StdMarshalImpl_Release(LPMARSHAL iface)
890 {
891     StdMarshalImpl *This = (StdMarshalImpl *)iface;
892     ULONG ref = InterlockedDecrement(&This->ref);
893
894     if (!ref) HeapFree(GetProcessHeap(),0,This);
895     return ref;
896 }
897
898 static HRESULT WINAPI
899 StdMarshalImpl_GetUnmarshalClass(
900     LPMARSHAL iface, REFIID riid, void* pv, DWORD dwDestContext,
901     void* pvDestContext, DWORD mshlflags, CLSID* pCid)
902 {
903     *pCid = CLSID_DfMarshal;
904     return S_OK;
905 }
906
907 static HRESULT WINAPI
908 StdMarshalImpl_GetMarshalSizeMax(
909     LPMARSHAL iface, REFIID riid, void* pv, DWORD dwDestContext,
910     void* pvDestContext, DWORD mshlflags, DWORD* pSize)
911 {
912     *pSize = sizeof(STDOBJREF);
913     return S_OK;
914 }
915
916 static HRESULT WINAPI
917 StdMarshalImpl_MarshalInterface(
918     LPMARSHAL iface, IStream *pStm,REFIID riid, void* pv, DWORD dwDestContext,
919     void* pvDestContext, DWORD mshlflags)
920 {
921     STDOBJREF             stdobjref;
922     ULONG                 res;
923     HRESULT               hres;
924     APARTMENT            *apt = COM_CurrentApt();
925
926     TRACE("(...,%s,...)\n", debugstr_guid(riid));
927
928     if (!apt)
929     {
930         ERR("Apartment not initialized\n");
931         return CO_E_NOTINITIALIZED;
932     }
933
934     /* make sure this apartment can be reached from other threads / processes */
935     RPC_StartRemoting(apt);
936
937     hres = marshal_object(apt, &stdobjref, riid, (IUnknown *)pv, mshlflags);
938     if (hres)
939     {
940         ERR("Failed to create ifstub, hres=0x%lx\n", hres);
941         return hres;
942     }
943
944     hres = IStream_Write(pStm, &stdobjref, sizeof(stdobjref), &res);
945     if (hres) return hres;
946
947     return S_OK;
948 }
949
950 /* helper for StdMarshalImpl_UnmarshalInterface - does the unmarshaling with
951  * no questions asked about the rules surrounding same-apartment unmarshals
952  * and table marshaling */
953 static HRESULT unmarshal_object(const STDOBJREF *stdobjref, APARTMENT *apt, REFIID riid, void **object)
954 {
955     struct proxy_manager *proxy_manager = NULL;
956     HRESULT hr = S_OK;
957
958     assert(apt);
959
960     TRACE("stdobjref:\n\tflags = %04lx\n\tcPublicRefs = %ld\n\toxid = %s\n\toid = %s\n\tipid = %s\n",
961         stdobjref->flags, stdobjref->cPublicRefs,
962         wine_dbgstr_longlong(stdobjref->oxid),
963         wine_dbgstr_longlong(stdobjref->oid),
964         debugstr_guid(&stdobjref->ipid));
965
966     /* create an a new proxy manager if one doesn't already exist for the
967      * object */
968     if (!find_proxy_manager(apt, stdobjref->oxid, stdobjref->oid, &proxy_manager))
969     {
970         hr = proxy_manager_construct(apt, stdobjref->flags,
971                                      stdobjref->oxid, stdobjref->oid,
972                                      &proxy_manager);
973     }
974     else
975         TRACE("proxy manager already created, using\n");
976
977     if (hr == S_OK)
978     {
979         struct ifproxy * ifproxy;
980         hr = proxy_manager_find_ifproxy(proxy_manager, riid, &ifproxy);
981         if (hr == E_NOINTERFACE)
982         {
983             IRpcChannelBuffer *chanbuf;
984             hr = RPC_CreateClientChannel(&stdobjref->oxid, &stdobjref->ipid, &chanbuf);
985             if (hr == S_OK)
986                 hr = proxy_manager_create_ifproxy(proxy_manager, stdobjref,
987                                                   riid, chanbuf, &ifproxy);
988         }
989
990         if (hr == S_OK)
991         {
992             ClientIdentity_AddRef((IMultiQI*)&proxy_manager->lpVtbl);
993             *object = ifproxy->iface;
994         }
995     }
996
997     /* release our reference to the proxy manager - the client/apartment
998      * will hold on to the remaining reference for us */
999     if (proxy_manager) ClientIdentity_Release((IMultiQI*)&proxy_manager->lpVtbl);
1000
1001     return hr;
1002 }
1003
1004 static HRESULT WINAPI
1005 StdMarshalImpl_UnmarshalInterface(LPMARSHAL iface, IStream *pStm, REFIID riid, void **ppv)
1006 {
1007     struct stub_manager  *stubmgr;
1008     STDOBJREF stdobjref;
1009     ULONG res;
1010     HRESULT hres;
1011     APARTMENT *apt = COM_CurrentApt();
1012     APARTMENT *stub_apt;
1013     OXID oxid;
1014
1015     TRACE("(...,%s,....)\n", debugstr_guid(riid));
1016
1017     /* we need an apartment to unmarshal into */
1018     if (!apt)
1019     {
1020         ERR("Apartment not initialized\n");
1021         return CO_E_NOTINITIALIZED;
1022     }
1023
1024     /* read STDOBJREF from wire */
1025     hres = IStream_Read(pStm, &stdobjref, sizeof(stdobjref), &res);
1026     if (hres) return hres;
1027
1028     hres = apartment_getoxid(apt, &oxid);
1029     if (hres) return hres;
1030
1031     /* check if we're marshalling back to ourselves */
1032     if ((oxid == stdobjref.oxid) && (stubmgr = get_stub_manager(apt, stdobjref.oid)))
1033     {
1034         TRACE("Unmarshalling object marshalled in same apartment for iid %s, "
1035               "returning original object %p\n", debugstr_guid(riid), stubmgr->object);
1036     
1037         hres = IUnknown_QueryInterface(stubmgr->object, riid, ppv);
1038       
1039         /* unref the ifstub. FIXME: only do this on success? */
1040         if (!stub_manager_is_table_marshaled(stubmgr, &stdobjref.ipid))
1041             stub_manager_ext_release(stubmgr, stdobjref.cPublicRefs);
1042
1043         stub_manager_int_release(stubmgr);
1044         return hres;
1045     }
1046
1047     /* notify stub manager about unmarshal if process-local object.
1048      * note: if the oxid is not found then we and native will quite happily
1049      * ignore table marshaling and normal marshaling rules regarding number of
1050      * unmarshals, etc, but if you abuse these rules then your proxy could end
1051      * up returning RPC_E_DISCONNECTED. */
1052     if ((stub_apt = apartment_findfromoxid(stdobjref.oxid, TRUE)))
1053     {
1054         if ((stubmgr = get_stub_manager(stub_apt, stdobjref.oid)))
1055         {
1056             if (!stub_manager_notify_unmarshal(stubmgr, &stdobjref.ipid))
1057                 hres = CO_E_OBJNOTCONNECTED;
1058
1059             stub_manager_int_release(stubmgr);
1060         }
1061         else
1062         {
1063             WARN("Couldn't find object for OXID %s, OID %s, assuming disconnected\n",
1064                 wine_dbgstr_longlong(stdobjref.oxid),
1065                 wine_dbgstr_longlong(stdobjref.oid));
1066             hres = CO_E_OBJNOTCONNECTED;
1067         }
1068
1069         apartment_release(stub_apt);
1070     }
1071     else
1072         TRACE("Treating unmarshal from OXID %s as inter-process\n",
1073             wine_dbgstr_longlong(stdobjref.oxid));
1074
1075     if (hres == S_OK)
1076         hres = unmarshal_object(&stdobjref, apt, riid, ppv);
1077
1078     if (hres) WARN("Failed with error 0x%08lx\n", hres);
1079     else TRACE("Successfully created proxy %p\n", *ppv);
1080
1081     return hres;
1082 }
1083
1084 static HRESULT WINAPI
1085 StdMarshalImpl_ReleaseMarshalData(LPMARSHAL iface, IStream *pStm)
1086 {
1087     STDOBJREF            stdobjref;
1088     ULONG                res;
1089     HRESULT              hres;
1090     struct stub_manager *stubmgr;
1091     APARTMENT           *apt;
1092
1093     TRACE("iface=%p, pStm=%p\n", iface, pStm);
1094     
1095     hres = IStream_Read(pStm, &stdobjref, sizeof(stdobjref), &res);
1096     if (hres) return hres;
1097
1098     TRACE("oxid = %s, oid = %s, ipid = %s\n",
1099         wine_dbgstr_longlong(stdobjref.oxid),
1100         wine_dbgstr_longlong(stdobjref.oid),
1101         wine_dbgstr_guid(&stdobjref.ipid));
1102
1103     if (!(apt = apartment_findfromoxid(stdobjref.oxid, TRUE)))
1104     {
1105         WARN("Could not map OXID %s to apartment object\n",
1106             wine_dbgstr_longlong(stdobjref.oxid));
1107         return RPC_E_INVALID_OBJREF;
1108     }
1109
1110     if (!(stubmgr = get_stub_manager(apt, stdobjref.oid)))
1111     {
1112         ERR("could not map MID to stub manager, oxid=%s, oid=%s\n",
1113             wine_dbgstr_longlong(stdobjref.oxid), wine_dbgstr_longlong(stdobjref.oid));
1114         return RPC_E_INVALID_OBJREF;
1115     }
1116
1117     stub_manager_release_marshal_data(stubmgr, stdobjref.cPublicRefs, &stdobjref.ipid);
1118
1119     stub_manager_int_release(stubmgr);
1120     apartment_release(apt);
1121
1122     return S_OK;
1123 }
1124
1125 static HRESULT WINAPI
1126 StdMarshalImpl_DisconnectObject(LPMARSHAL iface, DWORD dwReserved)
1127 {
1128     FIXME("(), stub!\n");
1129     return S_OK;
1130 }
1131
1132 static const IMarshalVtbl VT_StdMarshal =
1133 {
1134     StdMarshalImpl_QueryInterface,
1135     StdMarshalImpl_AddRef,
1136     StdMarshalImpl_Release,
1137     StdMarshalImpl_GetUnmarshalClass,
1138     StdMarshalImpl_GetMarshalSizeMax,
1139     StdMarshalImpl_MarshalInterface,
1140     StdMarshalImpl_UnmarshalInterface,
1141     StdMarshalImpl_ReleaseMarshalData,
1142     StdMarshalImpl_DisconnectObject
1143 };
1144
1145 static HRESULT StdMarshalImpl_Construct(REFIID riid, void** ppvObject)
1146 {
1147     StdMarshalImpl * pStdMarshal = 
1148         HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(StdMarshalImpl));
1149     if (!pStdMarshal)
1150         return E_OUTOFMEMORY;
1151     pStdMarshal->lpvtbl = &VT_StdMarshal;
1152     pStdMarshal->ref = 0;
1153     return IMarshal_QueryInterface((IMarshal*)pStdMarshal, riid, ppvObject);
1154 }
1155
1156 /***********************************************************************
1157  *              CoGetStandardMarshal    [OLE32.@]
1158  *
1159  * Gets or creates a standard marshal object.
1160  *
1161  * PARAMS
1162  *  riid          [I] Interface identifier of the pUnk object.
1163  *  pUnk          [I] Optional. Object to get the marshal object for.
1164  *  dwDestContext [I] Destination. Used to enable or disable optimizations.
1165  *  pvDestContext [I] Reserved. Must be NULL.
1166  *  mshlflags     [I] Flags affecting the marshaling process.
1167  *  ppMarshal     [O] Address where marshal object will be stored.
1168  *
1169  * RETURNS
1170  *  Success: S_OK.
1171  *  Failure: HRESULT code.
1172  *
1173  * NOTES
1174  *
1175  * The function retrieves the IMarshal object associated with an object if
1176  * that object is currently an active stub, otherwise a new marshal object is
1177  * created.
1178  */
1179 HRESULT WINAPI CoGetStandardMarshal(REFIID riid, IUnknown *pUnk,
1180                                     DWORD dwDestContext, LPVOID pvDestContext,
1181                                     DWORD mshlflags, LPMARSHAL *ppMarshal)
1182 {
1183     StdMarshalImpl *dm;
1184
1185     if (pUnk == NULL)
1186     {
1187         FIXME("(%s,NULL,%lx,%p,%lx,%p), unimplemented yet.\n",
1188             debugstr_guid(riid),dwDestContext,pvDestContext,mshlflags,ppMarshal);
1189         return E_NOTIMPL;
1190     }
1191     TRACE("(%s,%p,%lx,%p,%lx,%p)\n",
1192         debugstr_guid(riid),pUnk,dwDestContext,pvDestContext,mshlflags,ppMarshal);
1193     *ppMarshal = HeapAlloc(GetProcessHeap(),0,sizeof(StdMarshalImpl));
1194     dm = (StdMarshalImpl*) *ppMarshal;
1195     if (!dm) return E_FAIL;
1196     dm->lpvtbl          = &VT_StdMarshal;
1197     dm->ref             = 1;
1198
1199     dm->iid             = *riid;
1200     dm->dwDestContext   = dwDestContext;
1201     dm->pvDestContext   = pvDestContext;
1202     dm->mshlflags       = mshlflags;
1203     return S_OK;
1204 }
1205
1206 /***********************************************************************
1207  *              get_marshaler   [internal]
1208  *
1209  * Retrieves an IMarshal interface for an object.
1210  */
1211 static HRESULT get_marshaler(REFIID riid, IUnknown *pUnk, DWORD dwDestContext,
1212                              void *pvDestContext, DWORD mshlFlags,
1213                              LPMARSHAL *pMarshal)
1214 {
1215     HRESULT hr;
1216
1217     if (!pUnk)
1218         return E_POINTER;
1219     hr = IUnknown_QueryInterface(pUnk, &IID_IMarshal, (LPVOID*)pMarshal);
1220     if (hr)
1221         hr = CoGetStandardMarshal(riid, pUnk, dwDestContext, pvDestContext,
1222                                   mshlFlags, pMarshal);
1223     return hr;
1224 }
1225
1226 /***********************************************************************
1227  *              get_unmarshaler_from_stream     [internal]
1228  *
1229  * Creates an IMarshal* object according to the data marshaled to the stream.
1230  * The function leaves the stream pointer at the start of the data written
1231  * to the stream by the IMarshal* object.
1232  */
1233 static HRESULT get_unmarshaler_from_stream(IStream *stream, IMarshal **marshal, IID *iid)
1234 {
1235     HRESULT hr;
1236     ULONG res;
1237     OBJREF objref;
1238
1239     /* read common OBJREF header */
1240     hr = IStream_Read(stream, &objref, FIELD_OFFSET(OBJREF, u_objref), &res);
1241     if (hr || (res != FIELD_OFFSET(OBJREF, u_objref)))
1242     {
1243         ERR("Failed to read common OBJREF header, 0x%08lx\n", hr);
1244         return STG_E_READFAULT;
1245     }
1246
1247     /* sanity check on header */
1248     if (objref.signature != OBJREF_SIGNATURE)
1249     {
1250         ERR("Bad OBJREF signature 0x%08lx\n", objref.signature);
1251         return RPC_E_INVALID_OBJREF;
1252     }
1253
1254     if (iid) *iid = objref.iid;
1255
1256     /* FIXME: handler marshaling */
1257     if (objref.flags & OBJREF_STANDARD)
1258     {
1259         TRACE("Using standard unmarshaling\n");
1260         hr = StdMarshalImpl_Construct(&IID_IMarshal, (LPVOID*)marshal);
1261     }
1262     else if (objref.flags & OBJREF_CUSTOM)
1263     {
1264         ULONG custom_header_size = FIELD_OFFSET(OBJREF, u_objref.u_custom.pData) - 
1265                                    FIELD_OFFSET(OBJREF, u_objref.u_custom);
1266         TRACE("Using custom unmarshaling\n");
1267         /* read constant sized OR_CUSTOM data from stream */
1268         hr = IStream_Read(stream, &objref.u_objref.u_custom,
1269                           custom_header_size, &res);
1270         if (hr || (res != custom_header_size))
1271         {
1272             ERR("Failed to read OR_CUSTOM header, 0x%08lx\n", hr);
1273             return STG_E_READFAULT;
1274         }
1275         /* now create the marshaler specified in the stream */
1276         hr = CoCreateInstance(&objref.u_objref.u_custom.clsid, NULL,
1277                               CLSCTX_INPROC_SERVER, &IID_IMarshal,
1278                               (LPVOID*)marshal);
1279     }
1280     else
1281     {
1282         FIXME("Invalid or unimplemented marshaling type specified: %lx\n",
1283             objref.flags);
1284         return RPC_E_INVALID_OBJREF;
1285     }
1286
1287     if (hr)
1288         ERR("Failed to create marshal, 0x%08lx\n", hr);
1289
1290     return hr;
1291 }
1292
1293 /***********************************************************************
1294  *              CoGetMarshalSizeMax     [OLE32.@]
1295  *
1296  * Gets the maximum amount of data that will be needed by a marshal.
1297  *
1298  * PARAMS
1299  *  pulSize       [O] Address where maximum marshal size will be stored.
1300  *  riid          [I] Identifier of the interface to marshal.
1301  *  pUnk          [I] Pointer to the object to marshal.
1302  *  dwDestContext [I] Destination. Used to enable or disable optimizations.
1303  *  pvDestContext [I] Reserved. Must be NULL.
1304  *  mshlFlags     [I] Flags that affect the marshaling. See CoMarshalInterface().
1305  *
1306  * RETURNS
1307  *  Success: S_OK.
1308  *  Failure: HRESULT code.
1309  *
1310  * SEE ALSO
1311  *  CoMarshalInterface().
1312  */
1313 HRESULT WINAPI CoGetMarshalSizeMax(ULONG *pulSize, REFIID riid, IUnknown *pUnk,
1314                                    DWORD dwDestContext, void *pvDestContext,
1315                                    DWORD mshlFlags)
1316 {
1317     HRESULT hr;
1318     LPMARSHAL pMarshal;
1319     CLSID marshaler_clsid;
1320
1321     hr = get_marshaler(riid, pUnk, dwDestContext, pvDestContext, mshlFlags, &pMarshal);
1322     if (hr)
1323         return hr;
1324
1325     hr = IMarshal_GetUnmarshalClass(pMarshal, riid, pUnk, dwDestContext,
1326                                     pvDestContext, mshlFlags, &marshaler_clsid);
1327     if (hr)
1328     {
1329         ERR("IMarshal::GetUnmarshalClass failed, 0x%08lx\n", hr);
1330         IMarshal_Release(pMarshal);
1331         return hr;
1332     }
1333
1334     hr = IMarshal_GetMarshalSizeMax(pMarshal, riid, pUnk, dwDestContext,
1335                                     pvDestContext, mshlFlags, pulSize);
1336     /* add on the size of the common header */
1337     *pulSize += FIELD_OFFSET(OBJREF, u_objref);
1338
1339     /* if custom marshaling, add on size of custom header */
1340     if (!IsEqualCLSID(&marshaler_clsid, &CLSID_DfMarshal))
1341         *pulSize += FIELD_OFFSET(OBJREF, u_objref.u_custom.pData) - 
1342                     FIELD_OFFSET(OBJREF, u_objref.u_custom);
1343
1344     IMarshal_Release(pMarshal);
1345     return hr;
1346 }
1347
1348
1349 static void dump_MSHLFLAGS(MSHLFLAGS flags)
1350 {
1351     if (flags & MSHLFLAGS_TABLESTRONG)
1352         TRACE(" MSHLFLAGS_TABLESTRONG");
1353     if (flags & MSHLFLAGS_TABLEWEAK)
1354         TRACE(" MSHLFLAGS_TABLEWEAK");
1355     if (!(flags & (MSHLFLAGS_TABLESTRONG|MSHLFLAGS_TABLEWEAK)))
1356         TRACE(" MSHLFLAGS_NORMAL");
1357     if (flags & MSHLFLAGS_NOPING)
1358         TRACE(" MSHLFLAGS_NOPING");
1359 }
1360
1361 /***********************************************************************
1362  *              CoMarshalInterface      [OLE32.@]
1363  *
1364  * Marshals an interface into a stream so that the object can then be
1365  * unmarshaled from another COM apartment and used remotely.
1366  *
1367  * PARAMS
1368  *  pStream       [I] Stream the object will be marshaled into.
1369  *  riid          [I] Identifier of the interface to marshal.
1370  *  pUnk          [I] Pointer to the object to marshal.
1371  *  dwDestContext [I] Destination. Used to enable or disable optimizations.
1372  *  pvDestContext [I] Reserved. Must be NULL.
1373  *  mshlFlags     [I] Flags that affect the marshaling. See notes.
1374  *
1375  * RETURNS
1376  *  Success: S_OK.
1377  *  Failure: HRESULT code.
1378  *
1379  * NOTES
1380  *
1381  * The mshlFlags parameter can take one or more of the following flags:
1382  *| MSHLFLAGS_NORMAL - Unmarshal once, releases stub on last proxy release.
1383  *| MSHLFLAGS_TABLESTRONG - Unmarshal many, release when CoReleaseMarshalData() called.
1384  *| MSHLFLAGS_TABLEWEAK - Unmarshal many, releases stub on last proxy release.
1385  *| MSHLFLAGS_NOPING - No automatic garbage collection (and so reduces network traffic).
1386  *
1387  * If a marshaled object is not unmarshaled, then CoReleaseMarshalData() must
1388  * be called in order to release the resources used in the marshaling.
1389  *
1390  * SEE ALSO
1391  *  CoUnmarshalInterface(), CoReleaseMarshalData().
1392  */
1393 HRESULT WINAPI CoMarshalInterface(IStream *pStream, REFIID riid, IUnknown *pUnk,
1394                                   DWORD dwDestContext, void *pvDestContext,
1395                                   DWORD mshlFlags)
1396 {
1397     HRESULT     hr;
1398     CLSID marshaler_clsid;
1399     OBJREF objref;
1400     LPMARSHAL pMarshal;
1401
1402     TRACE("(%p, %s, %p, %lx, %p,", pStream, debugstr_guid(riid), pUnk,
1403         dwDestContext, pvDestContext);
1404     dump_MSHLFLAGS(mshlFlags);
1405     TRACE(")\n");
1406
1407     if (pUnk == NULL)
1408         return E_INVALIDARG;
1409
1410     objref.signature = OBJREF_SIGNATURE;
1411     objref.iid = *riid;
1412
1413     /* get the marshaler for the specified interface */
1414     hr = get_marshaler(riid, pUnk, dwDestContext, pvDestContext, mshlFlags, &pMarshal);
1415     if (hr)
1416     {
1417         ERR("Failed to get marshaller, 0x%08lx\n", hr);
1418         return hr;
1419     }
1420
1421     hr = IMarshal_GetUnmarshalClass(pMarshal, riid, pUnk, dwDestContext,
1422                                     pvDestContext, mshlFlags, &marshaler_clsid);
1423     if (hr)
1424     {
1425         ERR("IMarshal::GetUnmarshalClass failed, 0x%08lx\n", hr);
1426         goto cleanup;
1427     }
1428
1429     /* FIXME: implement handler marshaling too */
1430     if (IsEqualCLSID(&marshaler_clsid, &CLSID_DfMarshal))
1431     {
1432         TRACE("Using standard marshaling\n");
1433         objref.flags = OBJREF_STANDARD;
1434
1435         /* write the common OBJREF header to the stream */
1436         hr = IStream_Write(pStream, &objref, FIELD_OFFSET(OBJREF, u_objref), NULL);
1437         if (hr)
1438         {
1439             ERR("Failed to write OBJREF header to stream, 0x%08lx\n", hr);
1440             goto cleanup;
1441         }
1442     }
1443     else
1444     {
1445         TRACE("Using custom marshaling\n");
1446         objref.flags = OBJREF_CUSTOM;
1447         objref.u_objref.u_custom.clsid = marshaler_clsid;
1448         objref.u_objref.u_custom.cbExtension = 0;
1449         objref.u_objref.u_custom.size = 0;
1450         hr = IMarshal_GetMarshalSizeMax(pMarshal, riid, pUnk, dwDestContext,
1451                                         pvDestContext, mshlFlags,
1452                                         &objref.u_objref.u_custom.size);
1453         if (hr)
1454         {
1455             ERR("Failed to get max size of marshal data, error 0x%08lx\n", hr);
1456             goto cleanup;
1457         }
1458         /* write constant sized common header and OR_CUSTOM data into stream */
1459         hr = IStream_Write(pStream, &objref,
1460                           FIELD_OFFSET(OBJREF, u_objref.u_custom.pData), NULL);
1461         if (hr)
1462         {
1463             ERR("Failed to write OR_CUSTOM header to stream with 0x%08lx\n", hr);
1464             goto cleanup;
1465         }
1466     }
1467
1468     TRACE("Calling IMarshal::MarshalInterace\n");
1469     /* call helper object to do the actual marshaling */
1470     hr = IMarshal_MarshalInterface(pMarshal, pStream, riid, pUnk, dwDestContext,
1471                                    pvDestContext, mshlFlags);
1472
1473     if (hr)
1474     {
1475         ERR("Failed to marshal the interface %s, %lx\n", debugstr_guid(riid), hr);
1476         goto cleanup;
1477     }
1478
1479 cleanup:
1480     IMarshal_Release(pMarshal);
1481
1482     TRACE("completed with hr 0x%08lx\n", hr);
1483     
1484     return hr;
1485 }
1486
1487 /***********************************************************************
1488  *              CoUnmarshalInterface    [OLE32.@]
1489  *
1490  * Unmarshals an object from a stream by creating a proxy to the remote
1491  * object, if necessary.
1492  *
1493  * PARAMS
1494  *
1495  *  pStream [I] Stream containing the marshaled object.
1496  *  riid    [I] Interface identifier of the object to create a proxy to.
1497  *  ppv     [O] Address where proxy will be stored.
1498  *
1499  * RETURNS
1500  *
1501  *  Success: S_OK.
1502  *  Failure: HRESULT code.
1503  *
1504  * SEE ALSO
1505  *  CoMarshalInterface().
1506  */
1507 HRESULT WINAPI CoUnmarshalInterface(IStream *pStream, REFIID riid, LPVOID *ppv)
1508 {
1509     HRESULT hr;
1510     LPMARSHAL pMarshal;
1511     IID iid;
1512     IUnknown *object;
1513
1514     TRACE("(%p, %s, %p)\n", pStream, debugstr_guid(riid), ppv);
1515
1516     hr = get_unmarshaler_from_stream(pStream, &pMarshal, &iid);
1517     if (hr != S_OK)
1518         return hr;
1519
1520     /* call the helper object to do the actual unmarshaling */
1521     hr = IMarshal_UnmarshalInterface(pMarshal, pStream, &iid, (LPVOID*)&object);
1522     if (hr)
1523         ERR("IMarshal::UnmarshalInterface failed, 0x%08lx\n", hr);
1524
1525     /* IID_NULL means use the interface ID of the marshaled object */
1526     if (!IsEqualIID(riid, &IID_NULL))
1527         iid = *riid;
1528
1529     if (hr == S_OK)
1530     {
1531         if (!IsEqualIID(riid, &iid))
1532         {
1533             TRACE("requested interface != marshalled interface, additional QI needed\n");
1534             hr = IUnknown_QueryInterface(object, &iid, ppv);
1535             if (hr)
1536                 ERR("Couldn't query for interface %s, hr = 0x%08lx\n",
1537                     debugstr_guid(riid), hr);
1538             IUnknown_Release(object);
1539         }
1540         else
1541         {
1542             *ppv = object;
1543         }
1544     }
1545
1546     IMarshal_Release(pMarshal);
1547
1548     TRACE("completed with hr 0x%lx\n", hr);
1549     
1550     return hr;
1551 }
1552
1553 /***********************************************************************
1554  *              CoReleaseMarshalData    [OLE32.@]
1555  *
1556  * Releases resources associated with an object that has been marshaled into
1557  * a stream.
1558  *
1559  * PARAMS
1560  *
1561  *  pStream [I] The stream that the object has been marshaled into.
1562  *
1563  * RETURNS
1564  *  Success: S_OK.
1565  *  Failure: HRESULT error code.
1566  *
1567  * NOTES
1568  * 
1569  * Call this function to release resources associated with a normal or
1570  * table-weak marshal that will not be unmarshaled, and all table-strong
1571  * marshals when they are no longer needed.
1572  *
1573  * SEE ALSO
1574  *  CoMarshalInterface(), CoUnmarshalInterface().
1575  */
1576 HRESULT WINAPI CoReleaseMarshalData(IStream *pStream)
1577 {
1578     HRESULT     hr;
1579     LPMARSHAL pMarshal;
1580
1581     TRACE("(%p)\n", pStream);
1582
1583     hr = get_unmarshaler_from_stream(pStream, &pMarshal, NULL);
1584     if (hr != S_OK)
1585         return hr;
1586
1587     /* call the helper object to do the releasing of marshal data */
1588     hr = IMarshal_ReleaseMarshalData(pMarshal, pStream);
1589     if (hr)
1590         ERR("IMarshal::ReleaseMarshalData failed with error 0x%08lx\n", hr);
1591
1592     IMarshal_Release(pMarshal);
1593     return hr;
1594 }
1595
1596
1597 /***********************************************************************
1598  *              CoMarshalInterThreadInterfaceInStream   [OLE32.@]
1599  *
1600  * Marshal an interface across threads in the same process.
1601  *
1602  * PARAMS
1603  *  riid  [I] Identifier of the interface to be marshalled.
1604  *  pUnk  [I] Pointer to IUnknown-derived interface that will be marshalled.
1605  *  ppStm [O] Pointer to IStream object that is created and then used to store the marshalled inteface.
1606  *
1607  * RETURNS
1608  *  Success: S_OK
1609  *  Failure: E_OUTOFMEMORY and other COM error codes
1610  *
1611  * SEE ALSO
1612  *   CoMarshalInterface(), CoUnmarshalInterface() and CoGetInterfaceAndReleaseStream()
1613  */
1614 HRESULT WINAPI CoMarshalInterThreadInterfaceInStream(
1615     REFIID riid, LPUNKNOWN pUnk, LPSTREAM * ppStm)
1616 {
1617     ULARGE_INTEGER      xpos;
1618     LARGE_INTEGER               seekto;
1619     HRESULT             hres;
1620
1621     TRACE("(%s, %p, %p)\n",debugstr_guid(riid), pUnk, ppStm);
1622
1623     hres = CreateStreamOnHGlobal(0, TRUE, ppStm);
1624     if (FAILED(hres)) return hres;
1625     hres = CoMarshalInterface(*ppStm, riid, pUnk, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1626
1627     /* FIXME: is this needed? */
1628     memset(&seekto,0,sizeof(seekto));
1629     IStream_Seek(*ppStm,seekto,SEEK_SET,&xpos);
1630
1631     return hres;
1632 }
1633
1634 /***********************************************************************
1635  *              CoGetInterfaceAndReleaseStream  [OLE32.@]
1636  *
1637  * Unmarshalls an inteface from a stream and then releases the stream.
1638  *
1639  * PARAMS
1640  *  pStm [I] Stream that contains the marshalled inteface.
1641  *  riid [I] Interface identifier of the object to unmarshall.
1642  *  ppv  [O] Address of pointer where the requested interface object will be stored.
1643  *
1644  * RETURNS
1645  *  Success: S_OK
1646  *  Failure: A COM error code
1647  *
1648  * SEE ALSO
1649  *  CoMarshalInterThreadInterfaceInStream() and CoUnmarshalInteface()
1650  */
1651 HRESULT WINAPI CoGetInterfaceAndReleaseStream(LPSTREAM pStm, REFIID riid,
1652                                               LPVOID *ppv)
1653 {
1654     HRESULT hres;
1655
1656     TRACE("(%p, %s, %p)\n", pStm, debugstr_guid(riid), ppv);
1657
1658     hres = CoUnmarshalInterface(pStm, riid, ppv);
1659     IStream_Release(pStm);
1660     return hres;
1661 }
1662
1663 static HRESULT WINAPI StdMarshalCF_QueryInterface(LPCLASSFACTORY iface,
1664                                                   REFIID riid, LPVOID *ppv)
1665 {
1666     *ppv = NULL;
1667     if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IClassFactory))
1668     {
1669         *ppv = (LPVOID)iface;
1670         return S_OK;
1671     }
1672     return E_NOINTERFACE;
1673 }
1674
1675 static ULONG WINAPI StdMarshalCF_AddRef(LPCLASSFACTORY iface)
1676 {
1677     return 2; /* non-heap based object */
1678 }
1679
1680 static ULONG WINAPI StdMarshalCF_Release(LPCLASSFACTORY iface)
1681 {
1682     return 1; /* non-heap based object */
1683 }
1684
1685 static HRESULT WINAPI StdMarshalCF_CreateInstance(LPCLASSFACTORY iface,
1686     LPUNKNOWN pUnk, REFIID riid, LPVOID *ppv)
1687 {
1688     if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IMarshal))
1689         return StdMarshalImpl_Construct(riid, ppv);
1690
1691     FIXME("(%s), not supported.\n",debugstr_guid(riid));
1692     return E_NOINTERFACE;
1693 }
1694
1695 static HRESULT WINAPI StdMarshalCF_LockServer(LPCLASSFACTORY iface, BOOL fLock)
1696 {
1697     FIXME("(%d), stub!\n",fLock);
1698     return S_OK;
1699 }
1700
1701 static const IClassFactoryVtbl StdMarshalCFVtbl =
1702 {
1703     StdMarshalCF_QueryInterface,
1704     StdMarshalCF_AddRef,
1705     StdMarshalCF_Release,
1706     StdMarshalCF_CreateInstance,
1707     StdMarshalCF_LockServer
1708 };
1709 static const IClassFactoryVtbl *StdMarshalCF = &StdMarshalCFVtbl;
1710
1711 HRESULT MARSHAL_GetStandardMarshalCF(LPVOID *ppv)
1712 {
1713     *ppv = &StdMarshalCF;
1714     return S_OK;
1715 }
1716
1717 /***********************************************************************
1718  *              CoMarshalHresult        [OLE32.@]
1719  *
1720  * Marshals an HRESULT value into a stream.
1721  *
1722  * PARAMS
1723  *  pStm    [I] Stream that hresult will be marshalled into.
1724  *  hresult [I] HRESULT to be marshalled.
1725  *
1726  * RETURNS
1727  *  Success: S_OK
1728  *  Failure: A COM error code
1729  *
1730  * SEE ALSO
1731  *  CoUnmarshalHresult().
1732  */
1733 HRESULT WINAPI CoMarshalHresult(LPSTREAM pStm, HRESULT hresult)
1734 {
1735     return IStream_Write(pStm, &hresult, sizeof(hresult), NULL);
1736 }
1737
1738 /***********************************************************************
1739  *              CoUnmarshalHresult      [OLE32.@]
1740  *
1741  * Unmarshals an HRESULT value from a stream.
1742  *
1743  * PARAMS
1744  *  pStm     [I] Stream that hresult will be unmarshalled from.
1745  *  phresult [I] Pointer to HRESULT where the value will be unmarshalled to.
1746  *
1747  * RETURNS
1748  *  Success: S_OK
1749  *  Failure: A COM error code
1750  *
1751  * SEE ALSO
1752  *  CoMarshalHresult().
1753  */
1754 HRESULT WINAPI CoUnmarshalHresult(LPSTREAM pStm, HRESULT * phresult)
1755 {
1756     return IStream_Read(pStm, phresult, sizeof(*phresult), NULL);
1757 }