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