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