mfmediaengine: Handle Play() when called before topology is set.
[wine.git] / dlls / combase / marshal.c
blob51b4ce241151db4f18a72ca54ee83df66d7882da
1 /*
2 * Copyright 2002 Juergen Schmied
3 * Copyright 2002 Marcus Meissner
4 * Copyright 2004 Mike Hearn, for CodeWeavers
5 * Copyright 2004 Rob Shearman, for CodeWeavers
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include <assert.h>
24 #define COBJMACROS
25 #include "objbase.h"
27 #include "dcom.h"
28 #include "combase_private.h"
30 #include "wine/debug.h"
31 #include "wine/heap.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(ole);
35 HRESULT WINAPI RPC_CreateClientChannel(const OXID *oxid, const IPID *ipid,
36 const OXID_INFO *oxid_info, const IID *iid,
37 DWORD dest_context, void *dest_context_data,
38 IRpcChannelBuffer **chan, struct apartment *apt);
40 static HRESULT unmarshal_object(const STDOBJREF *stdobjref, struct apartment *apt,
41 MSHCTX dest_context, void *dest_context_data,
42 REFIID riid, const OXID_INFO *oxid_info,
43 void **object);
45 /* number of refs given out for normal marshaling */
46 #define NORMALEXTREFS 5
48 /* private flag indicating that the object was marshaled as table-weak */
49 #define SORFP_TABLEWEAK SORF_OXRES1
50 /* private flag indicating that the caller does not want to notify the stub
51 * when the proxy disconnects or is destroyed */
52 #define SORFP_NOLIFETIMEMGMT SORF_OXRES2
54 /* imported interface proxy */
55 struct ifproxy
57 struct list entry; /* entry in proxy_manager list (CS parent->cs) */
58 struct proxy_manager *parent; /* owning proxy_manager (RO) */
59 void *iface; /* interface pointer (RO) */
60 STDOBJREF stdobjref; /* marshal data that represents this object (RO) */
61 IID iid; /* interface ID (RO) */
62 IRpcProxyBuffer *proxy; /* interface proxy (RO) */
63 ULONG refs; /* imported (public) references (LOCK) */
64 IRpcChannelBuffer *chan; /* channel to object (CS parent->cs) */
67 /* imported object / proxy manager */
68 struct proxy_manager
70 IMultiQI IMultiQI_iface;
71 IMarshal IMarshal_iface;
72 IClientSecurity IClientSecurity_iface;
73 struct apartment *parent; /* owning apartment (RO) */
74 struct list entry; /* entry in apartment (CS parent->cs) */
75 OXID oxid; /* object exported ID (RO) */
76 OXID_INFO oxid_info; /* string binding, ipid of rem unknown and other information (RO) */
77 OID oid; /* object ID (RO) */
78 struct list interfaces; /* imported interfaces (CS cs) */
79 LONG refs; /* proxy reference count (LOCK) */
80 CRITICAL_SECTION cs; /* thread safety for this object and children */
81 ULONG sorflags; /* STDOBJREF flags (RO) */
82 IRemUnknown *remunk; /* proxy to IRemUnknown used for lifecycle management (CS cs) */
83 HANDLE remoting_mutex; /* mutex used for synchronizing access to IRemUnknown */
84 MSHCTX dest_context; /* context used for activating optimisations (LOCK) */
85 void *dest_context_data; /* reserved context value (LOCK) */
88 static inline struct proxy_manager *impl_from_IMultiQI(IMultiQI *iface)
90 return CONTAINING_RECORD(iface, struct proxy_manager, IMultiQI_iface);
93 static inline struct proxy_manager *impl_from_IMarshal(IMarshal *iface)
95 return CONTAINING_RECORD(iface, struct proxy_manager, IMarshal_iface);
98 static inline struct proxy_manager *impl_from_IClientSecurity(IClientSecurity *iface)
100 return CONTAINING_RECORD(iface, struct proxy_manager, IClientSecurity_iface);
103 struct ftmarshaler
105 IUnknown IUnknown_inner;
106 IMarshal IMarshal_iface;
107 IUnknown *outer_unk;
108 LONG refcount;
111 static struct ftmarshaler *impl_ft_from_IUnknown(IUnknown *iface)
113 return CONTAINING_RECORD(iface, struct ftmarshaler, IUnknown_inner);
116 static struct ftmarshaler *impl_ft_from_IMarshal(IMarshal *iface)
118 return CONTAINING_RECORD(iface, struct ftmarshaler, IMarshal_iface);
121 /***********************************************************************
122 * CoMarshalHresult (combase.@)
124 HRESULT WINAPI CoMarshalHresult(IStream *stream, HRESULT hresult)
126 return IStream_Write(stream, &hresult, sizeof(hresult), NULL);
129 /***********************************************************************
130 * CoUnmarshalHresult (combase.@)
132 HRESULT WINAPI CoUnmarshalHresult(IStream *stream, HRESULT *phresult)
134 return IStream_Read(stream, phresult, sizeof(*phresult), NULL);
137 /***********************************************************************
138 * CoGetInterfaceAndReleaseStream (combase.@)
140 HRESULT WINAPI CoGetInterfaceAndReleaseStream(IStream *stream, REFIID riid, void **obj)
142 HRESULT hr;
144 TRACE("%p, %s, %p\n", stream, debugstr_guid(riid), obj);
146 if (!stream) return E_INVALIDARG;
147 hr = CoUnmarshalInterface(stream, riid, obj);
148 IStream_Release(stream);
149 return hr;
152 /***********************************************************************
153 * CoMarshalInterThreadInterfaceInStream (combase.@)
155 HRESULT WINAPI CoMarshalInterThreadInterfaceInStream(REFIID riid, IUnknown *unk, IStream **stream)
157 ULARGE_INTEGER xpos;
158 LARGE_INTEGER seekto;
159 HRESULT hr;
161 TRACE("%s, %p, %p\n", debugstr_guid(riid), unk, stream);
163 hr = CreateStreamOnHGlobal(NULL, TRUE, stream);
164 if (FAILED(hr)) return hr;
165 hr = CoMarshalInterface(*stream, riid, unk, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
167 if (SUCCEEDED(hr))
169 memset(&seekto, 0, sizeof(seekto));
170 IStream_Seek(*stream, seekto, STREAM_SEEK_SET, &xpos);
172 else
174 IStream_Release(*stream);
175 *stream = NULL;
178 return hr;
181 static HRESULT WINAPI ftmarshaler_inner_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
183 struct ftmarshaler *marshaler = impl_ft_from_IUnknown(iface);
185 TRACE("%p, %s, %p\n", iface, debugstr_guid(riid), obj);
187 *obj = NULL;
189 if (IsEqualIID(&IID_IUnknown, riid))
190 *obj = &marshaler->IUnknown_inner;
191 else if (IsEqualIID(&IID_IMarshal, riid))
192 *obj = &marshaler->IMarshal_iface;
193 else
195 FIXME("No interface for %s\n", debugstr_guid(riid));
196 return E_NOINTERFACE;
199 IUnknown_AddRef((IUnknown *)*obj);
201 return S_OK;
204 static ULONG WINAPI ftmarshaler_inner_AddRef(IUnknown *iface)
206 struct ftmarshaler *marshaler = impl_ft_from_IUnknown(iface);
207 ULONG refcount = InterlockedIncrement(&marshaler->refcount);
209 TRACE("%p, refcount %u\n", iface, refcount);
211 return refcount;
214 static ULONG WINAPI ftmarshaler_inner_Release(IUnknown *iface)
216 struct ftmarshaler *marshaler = impl_ft_from_IUnknown(iface);
217 ULONG refcount = InterlockedDecrement(&marshaler->refcount);
219 TRACE("%p, refcount %u\n", iface, refcount);
221 if (!refcount)
222 heap_free(marshaler);
224 return refcount;
227 static const IUnknownVtbl ftmarshaler_inner_vtbl =
229 ftmarshaler_inner_QueryInterface,
230 ftmarshaler_inner_AddRef,
231 ftmarshaler_inner_Release
234 static HRESULT WINAPI ftmarshaler_QueryInterface(IMarshal *iface, REFIID riid, void **obj)
236 struct ftmarshaler *marshaler = impl_ft_from_IMarshal(iface);
238 TRACE("%p, %s, %p\n", iface, debugstr_guid(riid), obj);
240 return IUnknown_QueryInterface(marshaler->outer_unk, riid, obj);
243 static ULONG WINAPI ftmarshaler_AddRef(IMarshal *iface)
245 struct ftmarshaler *marshaler = impl_ft_from_IMarshal(iface);
247 TRACE("%p\n", iface);
249 return IUnknown_AddRef(marshaler->outer_unk);
252 static ULONG WINAPI ftmarshaler_Release(IMarshal *iface)
254 struct ftmarshaler *marshaler = impl_ft_from_IMarshal(iface);
256 TRACE("%p\n", iface);
258 return IUnknown_Release(marshaler->outer_unk);
261 static HRESULT WINAPI ftmarshaler_GetUnmarshalClass(IMarshal *iface, REFIID riid, void *pv,
262 DWORD dest_context, void *pvDestContext, DWORD mshlflags, CLSID *clsid)
264 TRACE("%s, %p, %#x, %p, %#x, %p\n", debugstr_guid(riid), pv, dest_context, pvDestContext, mshlflags, clsid);
266 if (dest_context == MSHCTX_INPROC || dest_context == MSHCTX_CROSSCTX)
267 *clsid = CLSID_InProcFreeMarshaler;
268 else
269 *clsid = CLSID_StdMarshal;
271 return S_OK;
274 static HRESULT WINAPI ftmarshaler_GetMarshalSizeMax(IMarshal *iface, REFIID riid, void *pv,
275 DWORD dest_context, void *pvDestContext, DWORD mshlflags, DWORD *size)
277 IMarshal *marshal = NULL;
278 HRESULT hr;
280 TRACE("%s, %p, %#x, %p, %#x, %p\n", debugstr_guid(riid), pv, dest_context, pvDestContext, mshlflags, size);
282 /* If the marshalling happens inside the same process the interface pointer is
283 copied between the apartments */
284 if (dest_context == MSHCTX_INPROC || dest_context == MSHCTX_CROSSCTX)
286 *size = sizeof(mshlflags) + sizeof(pv) + sizeof(DWORD) + sizeof(GUID);
287 return S_OK;
290 /* Use the standard marshaller to handle all other cases */
291 CoGetStandardMarshal(riid, pv, dest_context, pvDestContext, mshlflags, &marshal);
292 hr = IMarshal_GetMarshalSizeMax(marshal, riid, pv, dest_context, pvDestContext, mshlflags, size);
293 IMarshal_Release(marshal);
294 return hr;
297 static HRESULT WINAPI ftmarshaler_MarshalInterface(IMarshal *iface, IStream *stream, REFIID riid,
298 void *pv, DWORD dest_context, void *pvDestContext, DWORD mshlflags)
300 IMarshal *marshal = NULL;
301 HRESULT hr;
303 TRACE("%p, %s, %p, %#x, %p, %#x\n", stream, debugstr_guid(riid), pv,
304 dest_context, pvDestContext, mshlflags);
306 /* If the marshalling happens inside the same process the interface pointer is
307 copied between the apartments */
308 if (dest_context == MSHCTX_INPROC || dest_context == MSHCTX_CROSSCTX)
310 void *object;
311 DWORD constant = 0;
312 GUID unknown_guid = { 0 };
314 hr = IUnknown_QueryInterface((IUnknown *)pv, riid, &object);
315 if (FAILED(hr))
316 return hr;
318 /* don't hold a reference to table-weak marshaled interfaces */
319 if (mshlflags & MSHLFLAGS_TABLEWEAK)
320 IUnknown_Release((IUnknown *)object);
322 hr = IStream_Write(stream, &mshlflags, sizeof(mshlflags), NULL);
323 if (hr != S_OK) return STG_E_MEDIUMFULL;
325 hr = IStream_Write(stream, &object, sizeof(object), NULL);
326 if (hr != S_OK) return STG_E_MEDIUMFULL;
328 if (sizeof(object) == sizeof(DWORD))
330 hr = IStream_Write(stream, &constant, sizeof(constant), NULL);
331 if (hr != S_OK) return STG_E_MEDIUMFULL;
334 hr = IStream_Write(stream, &unknown_guid, sizeof(unknown_guid), NULL);
335 if (hr != S_OK) return STG_E_MEDIUMFULL;
337 return S_OK;
340 /* Use the standard marshaler to handle all other cases */
341 CoGetStandardMarshal(riid, pv, dest_context, pvDestContext, mshlflags, &marshal);
342 hr = IMarshal_MarshalInterface(marshal, stream, riid, pv, dest_context, pvDestContext, mshlflags);
343 IMarshal_Release(marshal);
344 return hr;
347 static HRESULT WINAPI ftmarshaler_UnmarshalInterface(IMarshal *iface, IStream *stream, REFIID riid, void **ppv)
349 DWORD mshlflags;
350 IUnknown *object;
351 DWORD constant;
352 GUID unknown_guid;
353 HRESULT hr;
355 TRACE("%p, %s, %p\n", stream, debugstr_guid(riid), ppv);
357 hr = IStream_Read(stream, &mshlflags, sizeof(mshlflags), NULL);
358 if (hr != S_OK) return STG_E_READFAULT;
360 hr = IStream_Read(stream, &object, sizeof(object), NULL);
361 if (hr != S_OK) return STG_E_READFAULT;
363 if (sizeof(object) == sizeof(DWORD))
365 hr = IStream_Read(stream, &constant, sizeof(constant), NULL);
366 if (hr != S_OK) return STG_E_READFAULT;
367 if (constant != 0)
368 FIXME("constant is 0x%x instead of 0\n", constant);
371 hr = IStream_Read(stream, &unknown_guid, sizeof(unknown_guid), NULL);
372 if (hr != S_OK) return STG_E_READFAULT;
374 hr = IUnknown_QueryInterface(object, riid, ppv);
375 if (!(mshlflags & (MSHLFLAGS_TABLEWEAK | MSHLFLAGS_TABLESTRONG)))
376 IUnknown_Release(object);
378 return hr;
381 static HRESULT WINAPI ftmarshaler_ReleaseMarshalData(IMarshal *iface, IStream *stream)
383 DWORD mshlflags;
384 IUnknown *object;
385 DWORD constant;
386 GUID unknown_guid;
387 HRESULT hr;
389 TRACE("%p\n", stream);
391 hr = IStream_Read(stream, &mshlflags, sizeof(mshlflags), NULL);
392 if (hr != S_OK) return STG_E_READFAULT;
394 hr = IStream_Read(stream, &object, sizeof(object), NULL);
395 if (hr != S_OK) return STG_E_READFAULT;
397 if (sizeof(object) == sizeof(DWORD))
399 hr = IStream_Read(stream, &constant, sizeof(constant), NULL);
400 if (hr != S_OK) return STG_E_READFAULT;
401 if (constant != 0)
402 FIXME("constant is 0x%x instead of 0\n", constant);
405 hr = IStream_Read(stream, &unknown_guid, sizeof(unknown_guid), NULL);
406 if (hr != S_OK) return STG_E_READFAULT;
408 IUnknown_Release(object);
409 return S_OK;
412 static HRESULT WINAPI ftmarshaler_DisconnectObject(IMarshal *iface, DWORD reserved)
414 TRACE("\n");
416 /* nothing to do */
417 return S_OK;
420 static const IMarshalVtbl ftmarshaler_vtbl =
422 ftmarshaler_QueryInterface,
423 ftmarshaler_AddRef,
424 ftmarshaler_Release,
425 ftmarshaler_GetUnmarshalClass,
426 ftmarshaler_GetMarshalSizeMax,
427 ftmarshaler_MarshalInterface,
428 ftmarshaler_UnmarshalInterface,
429 ftmarshaler_ReleaseMarshalData,
430 ftmarshaler_DisconnectObject
433 /***********************************************************************
434 * CoCreateFreeThreadedMarshaler (combase.@)
436 HRESULT WINAPI CoCreateFreeThreadedMarshaler(IUnknown *outer, IUnknown **marshaler)
438 struct ftmarshaler *object;
440 TRACE("%p, %p\n", outer, marshaler);
442 object = heap_alloc(sizeof(*object));
443 if (!object)
444 return E_OUTOFMEMORY;
446 object->IUnknown_inner.lpVtbl = &ftmarshaler_inner_vtbl;
447 object->IMarshal_iface.lpVtbl = &ftmarshaler_vtbl;
448 object->refcount = 1;
449 object->outer_unk = outer ? outer : &object->IUnknown_inner;
451 *marshaler = &object->IUnknown_inner;
453 return S_OK;
456 /***********************************************************************
457 * CoGetMarshalSizeMax (combase.@)
459 HRESULT WINAPI CoGetMarshalSizeMax(ULONG *size, REFIID riid, IUnknown *unk,
460 DWORD dest_context, void *pvDestContext, DWORD mshlFlags)
462 BOOL std_marshal = FALSE;
463 IMarshal *marshal;
464 HRESULT hr;
466 if (!unk)
467 return E_POINTER;
469 hr = IUnknown_QueryInterface(unk, &IID_IMarshal, (void **)&marshal);
470 if (hr != S_OK)
472 std_marshal = TRUE;
473 hr = CoGetStandardMarshal(riid, unk, dest_context, pvDestContext, mshlFlags, &marshal);
475 if (hr != S_OK)
476 return hr;
478 hr = IMarshal_GetMarshalSizeMax(marshal, riid, unk, dest_context, pvDestContext, mshlFlags, size);
479 if (!std_marshal)
480 /* add on the size of the whole OBJREF structure like native does */
481 *size += sizeof(OBJREF);
483 IMarshal_Release(marshal);
484 return hr;
487 static void dump_mshflags(MSHLFLAGS flags)
489 if (flags & MSHLFLAGS_TABLESTRONG)
490 TRACE(" MSHLFLAGS_TABLESTRONG");
491 if (flags & MSHLFLAGS_TABLEWEAK)
492 TRACE(" MSHLFLAGS_TABLEWEAK");
493 if (!(flags & (MSHLFLAGS_TABLESTRONG|MSHLFLAGS_TABLEWEAK)))
494 TRACE(" MSHLFLAGS_NORMAL");
495 if (flags & MSHLFLAGS_NOPING)
496 TRACE(" MSHLFLAGS_NOPING");
499 /***********************************************************************
500 * CoMarshalInterface (combase.@)
502 HRESULT WINAPI CoMarshalInterface(IStream *stream, REFIID riid, IUnknown *unk,
503 DWORD dest_context, void *pvDestContext, DWORD mshlFlags)
505 CLSID marshaler_clsid;
506 IMarshal *marshal;
507 HRESULT hr;
509 TRACE("%p, %s, %p, %x, %p, ", stream, debugstr_guid(riid), unk, dest_context, pvDestContext);
510 dump_mshflags(mshlFlags);
511 TRACE("\n");
513 if (!unk || !stream)
514 return E_INVALIDARG;
516 hr = IUnknown_QueryInterface(unk, &IID_IMarshal, (void **)&marshal);
517 if (hr != S_OK)
518 hr = CoGetStandardMarshal(riid, unk, dest_context, pvDestContext, mshlFlags, &marshal);
519 if (hr != S_OK)
521 ERR("Failed to get marshaller, %#x\n", hr);
522 return hr;
525 hr = IMarshal_GetUnmarshalClass(marshal, riid, unk, dest_context, pvDestContext, mshlFlags,
526 &marshaler_clsid);
527 if (hr != S_OK)
529 ERR("IMarshal::GetUnmarshalClass failed, %#x\n", hr);
530 goto cleanup;
533 /* FIXME: implement handler marshaling too */
534 if (IsEqualCLSID(&marshaler_clsid, &CLSID_StdMarshal))
536 TRACE("Using standard marshaling\n");
538 else
540 OBJREF objref;
542 TRACE("Using custom marshaling\n");
543 objref.signature = OBJREF_SIGNATURE;
544 objref.iid = *riid;
545 objref.flags = OBJREF_CUSTOM;
546 objref.u_objref.u_custom.clsid = marshaler_clsid;
547 objref.u_objref.u_custom.cbExtension = 0;
548 objref.u_objref.u_custom.size = 0;
549 hr = IMarshal_GetMarshalSizeMax(marshal, riid, unk, dest_context, pvDestContext, mshlFlags,
550 &objref.u_objref.u_custom.size);
551 if (hr != S_OK)
553 ERR("Failed to get max size of marshal data, error %#x\n", hr);
554 goto cleanup;
556 /* write constant sized common header and OR_CUSTOM data into stream */
557 hr = IStream_Write(stream, &objref, FIELD_OFFSET(OBJREF, u_objref.u_custom.pData), NULL);
558 if (hr != S_OK)
560 ERR("Failed to write OR_CUSTOM header to stream with %#x\n", hr);
561 goto cleanup;
565 TRACE("Calling IMarshal::MarshalInterface\n");
567 hr = IMarshal_MarshalInterface(marshal, stream, riid, unk, dest_context, pvDestContext, mshlFlags);
568 if (hr != S_OK)
570 ERR("Failed to marshal the interface %s, hr %#x\n", debugstr_guid(riid), hr);
571 goto cleanup;
574 cleanup:
575 IMarshal_Release(marshal);
577 TRACE("completed with hr %#x\n", hr);
579 return hr;
582 /* Creates an IMarshal* object according to the data marshaled to the stream.
583 * The function leaves the stream pointer at the start of the data written
584 * to the stream by the IMarshal* object.
586 static HRESULT get_unmarshaler_from_stream(IStream *stream, IMarshal **marshal, IID *iid)
588 OBJREF objref;
589 HRESULT hr;
590 ULONG res;
592 /* read common OBJREF header */
593 hr = IStream_Read(stream, &objref, FIELD_OFFSET(OBJREF, u_objref), &res);
594 if (hr != S_OK || (res != FIELD_OFFSET(OBJREF, u_objref)))
596 ERR("Failed to read common OBJREF header, 0x%08x\n", hr);
597 return STG_E_READFAULT;
600 /* sanity check on header */
601 if (objref.signature != OBJREF_SIGNATURE)
603 ERR("Bad OBJREF signature 0x%08x\n", objref.signature);
604 return RPC_E_INVALID_OBJREF;
607 if (iid) *iid = objref.iid;
609 /* FIXME: handler marshaling */
610 if (objref.flags & OBJREF_STANDARD)
612 TRACE("Using standard unmarshaling\n");
613 *marshal = NULL;
614 return S_FALSE;
616 else if (objref.flags & OBJREF_CUSTOM)
618 ULONG custom_header_size = FIELD_OFFSET(OBJREF, u_objref.u_custom.pData) -
619 FIELD_OFFSET(OBJREF, u_objref.u_custom);
620 TRACE("Using custom unmarshaling\n");
621 /* read constant sized OR_CUSTOM data from stream */
622 hr = IStream_Read(stream, &objref.u_objref.u_custom,
623 custom_header_size, &res);
624 if (hr != S_OK || (res != custom_header_size))
626 ERR("Failed to read OR_CUSTOM header, 0x%08x\n", hr);
627 return STG_E_READFAULT;
629 /* now create the marshaler specified in the stream */
630 hr = CoCreateInstance(&objref.u_objref.u_custom.clsid, NULL,
631 CLSCTX_INPROC_SERVER, &IID_IMarshal,
632 (LPVOID*)marshal);
634 else
636 FIXME("Invalid or unimplemented marshaling type specified: %x\n",
637 objref.flags);
638 return RPC_E_INVALID_OBJREF;
641 if (hr != S_OK)
642 ERR("Failed to create marshal, 0x%08x\n", hr);
644 return hr;
647 static HRESULT std_release_marshal_data(IStream *stream)
649 struct stub_manager *stubmgr;
650 struct OR_STANDARD obj;
651 struct apartment *apt;
652 ULONG res;
653 HRESULT hr;
655 hr = IStream_Read(stream, &obj, FIELD_OFFSET(struct OR_STANDARD, saResAddr.aStringArray), &res);
656 if (hr != S_OK) return STG_E_READFAULT;
658 if (obj.saResAddr.wNumEntries)
660 ERR("unsupported size of DUALSTRINGARRAY\n");
661 return E_NOTIMPL;
664 TRACE("oxid = %s, oid = %s, ipid = %s\n", wine_dbgstr_longlong(obj.std.oxid),
665 wine_dbgstr_longlong(obj.std.oid), wine_dbgstr_guid(&obj.std.ipid));
667 if (!(apt = apartment_findfromoxid(obj.std.oxid)))
669 WARN("Could not map OXID %s to apartment object\n",
670 wine_dbgstr_longlong(obj.std.oxid));
671 return RPC_E_INVALID_OBJREF;
674 if (!(stubmgr = get_stub_manager(apt, obj.std.oid)))
676 apartment_release(apt);
677 ERR("could not map object ID to stub manager, oxid=%s, oid=%s\n",
678 wine_dbgstr_longlong(obj.std.oxid), wine_dbgstr_longlong(obj.std.oid));
679 return RPC_E_INVALID_OBJREF;
682 stub_manager_release_marshal_data(stubmgr, obj.std.cPublicRefs, &obj.std.ipid, obj.std.flags & SORFP_TABLEWEAK);
684 stub_manager_int_release(stubmgr);
685 apartment_release(apt);
687 return S_OK;
690 /***********************************************************************
691 * CoReleaseMarshalData (combase.@)
693 HRESULT WINAPI CoReleaseMarshalData(IStream *stream)
695 IMarshal *marshal;
696 HRESULT hr;
698 TRACE("%p\n", stream);
700 hr = get_unmarshaler_from_stream(stream, &marshal, NULL);
701 if (hr == S_FALSE)
703 hr = std_release_marshal_data(stream);
704 if (hr != S_OK)
705 ERR("StdMarshal ReleaseMarshalData failed with error %#x\n", hr);
706 return hr;
708 if (hr != S_OK)
709 return hr;
711 /* call the helper object to do the releasing of marshal data */
712 hr = IMarshal_ReleaseMarshalData(marshal, stream);
713 if (hr != S_OK)
714 ERR("IMarshal::ReleaseMarshalData failed with error %#x\n", hr);
716 IMarshal_Release(marshal);
717 return hr;
720 static HRESULT std_unmarshal_interface(MSHCTX dest_context, void *dest_context_data,
721 IStream *stream, REFIID riid, void **ppv)
723 struct stub_manager *stubmgr = NULL;
724 struct OR_STANDARD obj;
725 ULONG res;
726 HRESULT hres;
727 struct apartment *apt, *stub_apt;
729 TRACE("(...,%s,....)\n", debugstr_guid(riid));
731 /* we need an apartment to unmarshal into */
732 if (!(apt = apartment_get_current_or_mta()))
734 ERR("Apartment not initialized\n");
735 return CO_E_NOTINITIALIZED;
738 /* read STDOBJREF from wire */
739 hres = IStream_Read(stream, &obj, FIELD_OFFSET(struct OR_STANDARD, saResAddr.aStringArray), &res);
740 if (hres != S_OK)
742 apartment_release(apt);
743 return STG_E_READFAULT;
746 if (obj.saResAddr.wNumEntries)
748 ERR("unsupported size of DUALSTRINGARRAY\n");
749 return E_NOTIMPL;
752 /* check if we're marshalling back to ourselves */
753 if ((apartment_getoxid(apt) == obj.std.oxid) && (stubmgr = get_stub_manager(apt, obj.std.oid)))
755 TRACE("Unmarshalling object marshalled in same apartment for iid %s, "
756 "returning original object %p\n", debugstr_guid(riid), stubmgr->object);
758 hres = IUnknown_QueryInterface(stubmgr->object, riid, ppv);
760 /* unref the ifstub. FIXME: only do this on success? */
761 if (!stub_manager_is_table_marshaled(stubmgr, &obj.std.ipid))
762 stub_manager_ext_release(stubmgr, obj.std.cPublicRefs, obj.std.flags & SORFP_TABLEWEAK, FALSE);
764 stub_manager_int_release(stubmgr);
765 apartment_release(apt);
766 return hres;
769 /* notify stub manager about unmarshal if process-local object.
770 * note: if the oxid is not found then we and native will quite happily
771 * ignore table marshaling and normal marshaling rules regarding number of
772 * unmarshals, etc, but if you abuse these rules then your proxy could end
773 * up returning RPC_E_DISCONNECTED. */
774 if ((stub_apt = apartment_findfromoxid(obj.std.oxid)))
776 if ((stubmgr = get_stub_manager(stub_apt, obj.std.oid)))
778 if (!stub_manager_notify_unmarshal(stubmgr, &obj.std.ipid))
779 hres = CO_E_OBJNOTCONNECTED;
781 else
783 WARN("Couldn't find object for OXID %s, OID %s, assuming disconnected\n",
784 wine_dbgstr_longlong(obj.std.oxid),
785 wine_dbgstr_longlong(obj.std.oid));
786 hres = CO_E_OBJNOTCONNECTED;
789 else
790 TRACE("Treating unmarshal from OXID %s as inter-process\n",
791 wine_dbgstr_longlong(obj.std.oxid));
793 if (hres == S_OK)
794 hres = unmarshal_object(&obj.std, apt, dest_context,
795 dest_context_data, riid,
796 stubmgr ? &stubmgr->oxid_info : NULL, ppv);
798 if (stubmgr) stub_manager_int_release(stubmgr);
799 if (stub_apt) apartment_release(stub_apt);
801 if (hres != S_OK) WARN("Failed with error 0x%08x\n", hres);
802 else TRACE("Successfully created proxy %p\n", *ppv);
804 apartment_release(apt);
805 return hres;
808 /***********************************************************************
809 * CoUnmarshalInterface (combase.@)
811 HRESULT WINAPI CoUnmarshalInterface(IStream *stream, REFIID riid, void **ppv)
813 IMarshal *marshal;
814 IUnknown *object;
815 HRESULT hr;
816 IID iid;
818 TRACE("%p, %s, %p\n", stream, debugstr_guid(riid), ppv);
820 if (!stream || !ppv)
821 return E_INVALIDARG;
823 hr = get_unmarshaler_from_stream(stream, &marshal, &iid);
824 if (hr == S_FALSE)
826 hr = std_unmarshal_interface(0, NULL, stream, &iid, (void **)&object);
827 if (hr != S_OK)
828 ERR("StdMarshal UnmarshalInterface failed, hr %#x\n", hr);
830 else if (hr == S_OK)
832 /* call the helper object to do the actual unmarshaling */
833 hr = IMarshal_UnmarshalInterface(marshal, stream, &iid, (void **)&object);
834 IMarshal_Release(marshal);
835 if (hr != S_OK)
836 ERR("IMarshal::UnmarshalInterface failed, hr %#x\n", hr);
839 if (hr == S_OK)
841 /* IID_NULL means use the interface ID of the marshaled object */
842 if (!IsEqualIID(riid, &IID_NULL) && !IsEqualIID(riid, &iid))
844 TRACE("requested interface != marshalled interface, additional QI needed\n");
845 hr = IUnknown_QueryInterface(object, riid, ppv);
846 if (hr != S_OK)
847 ERR("Couldn't query for interface %s, hr %#x\n", debugstr_guid(riid), hr);
848 IUnknown_Release(object);
850 else
852 *ppv = object;
856 TRACE("completed with hr 0x%x\n", hr);
858 return hr;
861 /* Marshalling just passes a unique identifier to the remote client,
862 * that makes it possible to find the passed interface again.
864 * So basically we need a set of values that make it unique.
866 * Note that the IUnknown_QI(ob,xiid,&ppv) always returns the SAME ppv value!
868 * A triple is used: OXID (apt id), OID (stub manager id),
869 * IPID (interface ptr/stub id).
871 * OXIDs identify an apartment and are network scoped
872 * OIDs identify a stub manager and are apartment scoped
873 * IPIDs identify an interface stub and are apartment scoped
876 static inline HRESULT get_facbuf_for_iid(REFIID riid, IPSFactoryBuffer **facbuf)
878 HRESULT hr;
879 CLSID clsid;
881 hr = CoGetPSClsid(riid, &clsid);
882 if (hr != S_OK)
883 return hr;
884 return CoGetClassObject(&clsid, CLSCTX_INPROC_SERVER | CLSCTX_PS_DLL, NULL, &IID_IPSFactoryBuffer, (void **)facbuf);
887 /* marshals an object into a STDOBJREF structure */
888 HRESULT marshal_object(struct apartment *apt, STDOBJREF *stdobjref, REFIID riid, IUnknown *object,
889 DWORD dest_context, void *dest_context_data, MSHLFLAGS mshlflags)
891 struct stub_manager *manager;
892 struct ifstub *ifstub;
893 BOOL tablemarshal;
894 HRESULT hr;
896 stdobjref->oxid = apartment_getoxid(apt);
898 hr = apartment_createwindowifneeded(apt);
899 if (hr != S_OK)
900 return hr;
902 if (!(manager = get_stub_manager_from_object(apt, object, TRUE)))
903 return E_OUTOFMEMORY;
905 stdobjref->flags = SORF_NULL;
906 if (mshlflags & MSHLFLAGS_TABLEWEAK)
907 stdobjref->flags |= SORFP_TABLEWEAK;
908 if (mshlflags & MSHLFLAGS_NOPING)
909 stdobjref->flags |= SORF_NOPING;
910 stdobjref->oid = manager->oid;
912 tablemarshal = ((mshlflags & MSHLFLAGS_TABLESTRONG) || (mshlflags & MSHLFLAGS_TABLEWEAK));
914 /* make sure ifstub that we are creating is unique */
915 ifstub = stub_manager_find_ifstub(manager, riid, mshlflags);
916 if (!ifstub) {
917 IRpcStubBuffer *stub = NULL;
919 /* IUnknown doesn't require a stub buffer, because it never goes out on
920 * the wire */
921 if (!IsEqualIID(riid, &IID_IUnknown))
923 IPSFactoryBuffer *psfb;
925 hr = get_facbuf_for_iid(riid, &psfb);
926 if (hr == S_OK) {
927 hr = IPSFactoryBuffer_CreateStub(psfb, riid, manager->object, &stub);
928 IPSFactoryBuffer_Release(psfb);
929 if (hr != S_OK)
930 ERR("Failed to create an IRpcStubBuffer from IPSFactory for %s with error 0x%08x\n",
931 debugstr_guid(riid), hr);
932 }else {
933 WARN("couldn't get IPSFactory buffer for interface %s\n", debugstr_guid(riid));
934 hr = E_NOINTERFACE;
939 if (hr == S_OK) {
940 ifstub = stub_manager_new_ifstub(manager, stub, riid, dest_context, dest_context_data, mshlflags);
941 if (!ifstub)
942 hr = E_OUTOFMEMORY;
944 if (stub) IRpcStubBuffer_Release(stub);
946 if (hr != S_OK) {
947 stub_manager_int_release(manager);
948 /* destroy the stub manager if it has no ifstubs by releasing
949 * zero external references */
950 stub_manager_ext_release(manager, 0, FALSE, TRUE);
951 return hr;
955 if (!tablemarshal)
957 stdobjref->cPublicRefs = NORMALEXTREFS;
958 stub_manager_ext_addref(manager, stdobjref->cPublicRefs, FALSE);
960 else
962 stdobjref->cPublicRefs = 0;
963 if (mshlflags & MSHLFLAGS_TABLESTRONG)
964 stub_manager_ext_addref(manager, 1, FALSE);
965 else
966 stub_manager_ext_addref(manager, 0, TRUE);
969 /* FIXME: check return value */
970 rpc_register_interface(riid);
972 stdobjref->ipid = ifstub->ipid;
974 stub_manager_int_release(manager);
975 return S_OK;
978 /* Client-side identity of the server object */
980 static HRESULT proxy_manager_get_remunknown(struct proxy_manager * This, IRemUnknown **remunk);
981 static void proxy_manager_destroy(struct proxy_manager * This);
982 static HRESULT proxy_manager_find_ifproxy(struct proxy_manager * This, REFIID riid, struct ifproxy ** ifproxy_found);
983 static HRESULT proxy_manager_query_local_interface(struct proxy_manager * This, REFIID riid, void ** ppv);
985 static HRESULT WINAPI ClientIdentity_QueryInterface(IMultiQI * iface, REFIID riid, void ** ppv)
987 HRESULT hr;
988 MULTI_QI mqi;
990 TRACE("%s\n", debugstr_guid(riid));
992 mqi.pIID = riid;
993 hr = IMultiQI_QueryMultipleInterfaces(iface, 1, &mqi);
994 *ppv = mqi.pItf;
996 return hr;
999 static ULONG WINAPI ClientIdentity_AddRef(IMultiQI *iface)
1001 struct proxy_manager *This = impl_from_IMultiQI(iface);
1002 TRACE("%p - before %d\n", iface, This->refs);
1003 return InterlockedIncrement(&This->refs);
1006 static ULONG WINAPI ClientIdentity_Release(IMultiQI *iface)
1008 struct proxy_manager *This = impl_from_IMultiQI(iface);
1009 ULONG refs = InterlockedDecrement(&This->refs);
1010 TRACE("%p - after %d\n", iface, refs);
1011 if (!refs)
1012 proxy_manager_destroy(This);
1013 return refs;
1016 static HRESULT WINAPI ClientIdentity_QueryMultipleInterfaces(IMultiQI *iface, ULONG cMQIs, MULTI_QI *pMQIs)
1018 struct proxy_manager *This = impl_from_IMultiQI(iface);
1019 REMQIRESULT *qiresults = NULL;
1020 ULONG nonlocal_mqis = 0;
1021 ULONG i;
1022 ULONG successful_mqis = 0;
1023 IID *iids = HeapAlloc(GetProcessHeap(), 0, cMQIs * sizeof(*iids));
1024 /* mapping of RemQueryInterface index to QueryMultipleInterfaces index */
1025 ULONG *mapping = HeapAlloc(GetProcessHeap(), 0, cMQIs * sizeof(*mapping));
1027 TRACE("cMQIs: %d\n", cMQIs);
1029 /* try to get a local interface - this includes already active proxy
1030 * interfaces and also interfaces exposed by the proxy manager */
1031 for (i = 0; i < cMQIs; i++)
1033 TRACE("iid[%d] = %s\n", i, debugstr_guid(pMQIs[i].pIID));
1034 pMQIs[i].hr = proxy_manager_query_local_interface(This, pMQIs[i].pIID, (void **)&pMQIs[i].pItf);
1035 if (pMQIs[i].hr == S_OK)
1036 successful_mqis++;
1037 else
1039 iids[nonlocal_mqis] = *pMQIs[i].pIID;
1040 mapping[nonlocal_mqis] = i;
1041 nonlocal_mqis++;
1045 TRACE("%d interfaces not found locally\n", nonlocal_mqis);
1047 /* if we have more than one interface not found locally then we must try
1048 * to query the remote object for it */
1049 if (nonlocal_mqis != 0)
1051 IRemUnknown *remunk;
1052 HRESULT hr;
1053 IPID *ipid;
1055 /* get the ipid of the first entry */
1056 /* FIXME: should we implement ClientIdentity on the ifproxies instead
1057 * of the proxy_manager so we use the correct ipid here? */
1058 ipid = &LIST_ENTRY(list_head(&This->interfaces), struct ifproxy, entry)->stdobjref.ipid;
1060 /* get IRemUnknown proxy so we can communicate with the remote object */
1061 hr = proxy_manager_get_remunknown(This, &remunk);
1063 if (SUCCEEDED(hr))
1065 hr = IRemUnknown_RemQueryInterface(remunk, ipid, NORMALEXTREFS,
1066 nonlocal_mqis, iids, &qiresults);
1067 IRemUnknown_Release(remunk);
1068 if (FAILED(hr))
1069 WARN("IRemUnknown_RemQueryInterface failed with error 0x%08x\n", hr);
1072 /* IRemUnknown_RemQueryInterface can return S_FALSE if only some of
1073 * the interfaces were returned */
1074 if (SUCCEEDED(hr))
1076 struct apartment *apt = apartment_get_current_or_mta();
1078 /* try to unmarshal each object returned to us */
1079 for (i = 0; i < nonlocal_mqis; i++)
1081 ULONG index = mapping[i];
1082 HRESULT hrobj = qiresults[i].hResult;
1083 if (hrobj == S_OK)
1084 hrobj = unmarshal_object(&qiresults[i].std, apt,
1085 This->dest_context,
1086 This->dest_context_data,
1087 pMQIs[index].pIID, &This->oxid_info,
1088 (void **)&pMQIs[index].pItf);
1090 if (hrobj == S_OK)
1091 successful_mqis++;
1092 else
1093 ERR("Failed to get pointer to interface %s\n", debugstr_guid(pMQIs[index].pIID));
1094 pMQIs[index].hr = hrobj;
1097 apartment_release(apt);
1100 /* free the memory allocated by the proxy */
1101 CoTaskMemFree(qiresults);
1104 TRACE("%d/%d successfully queried\n", successful_mqis, cMQIs);
1106 HeapFree(GetProcessHeap(), 0, iids);
1107 HeapFree(GetProcessHeap(), 0, mapping);
1109 if (successful_mqis == cMQIs)
1110 return S_OK; /* we got all requested interfaces */
1111 else if (successful_mqis == 0)
1112 return E_NOINTERFACE; /* we didn't get any interfaces */
1113 else
1114 return S_FALSE; /* we got some interfaces */
1117 static const IMultiQIVtbl ClientIdentity_Vtbl =
1119 ClientIdentity_QueryInterface,
1120 ClientIdentity_AddRef,
1121 ClientIdentity_Release,
1122 ClientIdentity_QueryMultipleInterfaces
1125 static HRESULT StdMarshalImpl_Construct(REFIID, DWORD, void*, void**);
1127 static HRESULT WINAPI Proxy_QueryInterface(IMarshal *iface, REFIID riid, void **ppvObject)
1129 struct proxy_manager *This = impl_from_IMarshal( iface );
1130 return IMultiQI_QueryInterface(&This->IMultiQI_iface, riid, ppvObject);
1133 static ULONG WINAPI Proxy_AddRef(IMarshal *iface)
1135 struct proxy_manager *This = impl_from_IMarshal( iface );
1136 return IMultiQI_AddRef(&This->IMultiQI_iface);
1139 static ULONG WINAPI Proxy_Release(IMarshal *iface)
1141 struct proxy_manager *This = impl_from_IMarshal( iface );
1142 return IMultiQI_Release(&This->IMultiQI_iface);
1145 static HRESULT WINAPI Proxy_GetUnmarshalClass(
1146 IMarshal *iface, REFIID riid, void* pv, DWORD dwDestContext,
1147 void* pvDestContext, DWORD mshlflags, CLSID* pCid)
1149 *pCid = CLSID_StdMarshal;
1150 return S_OK;
1153 static HRESULT WINAPI Proxy_GetMarshalSizeMax(
1154 IMarshal *iface, REFIID riid, void* pv, DWORD dwDestContext,
1155 void* pvDestContext, DWORD mshlflags, DWORD* pSize)
1157 *pSize = FIELD_OFFSET(OBJREF, u_objref.u_standard.saResAddr.aStringArray);
1158 return S_OK;
1161 static void fill_std_objref(OBJREF *objref, const GUID *iid, STDOBJREF *std)
1163 objref->signature = OBJREF_SIGNATURE;
1164 objref->flags = OBJREF_STANDARD;
1165 objref->iid = *iid;
1166 if(std)
1167 objref->u_objref.u_standard.std = *std;
1168 memset(&objref->u_objref.u_standard.saResAddr, 0,
1169 sizeof(objref->u_objref.u_standard.saResAddr));
1172 static HRESULT WINAPI Proxy_MarshalInterface(
1173 LPMARSHAL iface, IStream *pStm, REFIID riid, void* pv, DWORD dwDestContext,
1174 void* pvDestContext, DWORD mshlflags)
1176 struct proxy_manager *This = impl_from_IMarshal( iface );
1177 HRESULT hr;
1178 struct ifproxy *ifproxy;
1180 TRACE("(...,%s,...)\n", debugstr_guid(riid));
1182 hr = proxy_manager_find_ifproxy(This, riid, &ifproxy);
1183 if (SUCCEEDED(hr))
1185 STDOBJREF stdobjref = ifproxy->stdobjref;
1187 stdobjref.cPublicRefs = 0;
1189 if ((mshlflags != MSHLFLAGS_TABLEWEAK) &&
1190 (mshlflags != MSHLFLAGS_TABLESTRONG))
1192 ULONG cPublicRefs = ifproxy->refs;
1193 ULONG cPublicRefsOld;
1194 /* optimization - share out proxy's public references if possible
1195 * instead of making new proxy do a roundtrip through the server */
1198 ULONG cPublicRefsNew;
1199 cPublicRefsOld = cPublicRefs;
1200 stdobjref.cPublicRefs = cPublicRefs / 2;
1201 cPublicRefsNew = cPublicRefs - stdobjref.cPublicRefs;
1202 cPublicRefs = InterlockedCompareExchange(
1203 (LONG *)&ifproxy->refs, cPublicRefsNew, cPublicRefsOld);
1204 } while (cPublicRefs != cPublicRefsOld);
1207 /* normal and table-strong marshaling need at least one reference */
1208 if (!stdobjref.cPublicRefs && (mshlflags != MSHLFLAGS_TABLEWEAK))
1210 IRemUnknown *remunk;
1211 hr = proxy_manager_get_remunknown(This, &remunk);
1212 if (hr == S_OK)
1214 HRESULT hrref = S_OK;
1215 REMINTERFACEREF rif;
1216 rif.ipid = ifproxy->stdobjref.ipid;
1217 rif.cPublicRefs = (mshlflags == MSHLFLAGS_TABLESTRONG) ? 1 : NORMALEXTREFS;
1218 rif.cPrivateRefs = 0;
1219 hr = IRemUnknown_RemAddRef(remunk, 1, &rif, &hrref);
1220 IRemUnknown_Release(remunk);
1221 if (hr == S_OK && hrref == S_OK)
1223 /* table-strong marshaling doesn't give the refs to the
1224 * client that unmarshals the STDOBJREF */
1225 if (mshlflags != MSHLFLAGS_TABLESTRONG)
1226 stdobjref.cPublicRefs = rif.cPublicRefs;
1228 else
1229 ERR("IRemUnknown_RemAddRef returned with 0x%08x, hrref = 0x%08x\n", hr, hrref);
1233 if (SUCCEEDED(hr))
1235 OBJREF objref;
1237 TRACE("writing stdobjref: flags = %04x cPublicRefs = %d oxid = %s oid = %s ipid = %s\n",
1238 stdobjref.flags, stdobjref.cPublicRefs,
1239 wine_dbgstr_longlong(stdobjref.oxid),
1240 wine_dbgstr_longlong(stdobjref.oid),
1241 debugstr_guid(&stdobjref.ipid));
1242 fill_std_objref(&objref, riid, &stdobjref);
1243 hr = IStream_Write(pStm, &objref, FIELD_OFFSET(OBJREF,
1244 u_objref.u_standard.saResAddr.aStringArray), NULL);
1247 else
1249 /* we don't have the interface already unmarshaled so we have to
1250 * request the object from the server */
1251 IRemUnknown *remunk;
1252 IPID *ipid;
1253 REMQIRESULT *qiresults = NULL;
1254 IID iid = *riid;
1256 /* get the ipid of the first entry */
1257 /* FIXME: should we implement ClientIdentity on the ifproxies instead
1258 * of the proxy_manager so we use the correct ipid here? */
1259 ipid = &LIST_ENTRY(list_head(&This->interfaces), struct ifproxy, entry)->stdobjref.ipid;
1261 /* get IRemUnknown proxy so we can communicate with the remote object */
1262 hr = proxy_manager_get_remunknown(This, &remunk);
1264 if (hr == S_OK)
1266 hr = IRemUnknown_RemQueryInterface(remunk, ipid, NORMALEXTREFS,
1267 1, &iid, &qiresults);
1268 if (SUCCEEDED(hr))
1270 OBJREF objref;
1272 fill_std_objref(&objref, riid, &qiresults->std);
1273 hr = IStream_Write(pStm, &objref, FIELD_OFFSET(OBJREF,
1274 u_objref.u_standard.saResAddr.aStringArray), NULL);
1275 if (FAILED(hr))
1277 REMINTERFACEREF rif;
1278 rif.ipid = qiresults->std.ipid;
1279 rif.cPublicRefs = qiresults->std.cPublicRefs;
1280 rif.cPrivateRefs = 0;
1281 IRemUnknown_RemRelease(remunk, 1, &rif);
1283 CoTaskMemFree(qiresults);
1285 else
1286 ERR("IRemUnknown_RemQueryInterface failed with error 0x%08x\n", hr);
1287 IRemUnknown_Release(remunk);
1291 return hr;
1294 static HRESULT WINAPI Proxy_UnmarshalInterface(
1295 IMarshal *iface, IStream *pStm, REFIID riid, void **ppv)
1297 struct proxy_manager *This = impl_from_IMarshal( iface );
1298 IMarshal *marshal;
1299 HRESULT hr;
1301 TRACE("(%p, %p, %s, %p)\n", This, pStm, wine_dbgstr_guid(riid), ppv);
1303 hr = StdMarshalImpl_Construct(&IID_IMarshal, This->dest_context,
1304 This->dest_context_data, (void**)&marshal);
1305 if(FAILED(hr))
1306 return hr;
1308 hr = IMarshal_UnmarshalInterface(marshal, pStm, riid, ppv);
1309 IMarshal_Release(marshal);
1310 return hr;
1313 static HRESULT WINAPI Proxy_ReleaseMarshalData(IMarshal *iface, IStream *pStm)
1315 struct proxy_manager *This = impl_from_IMarshal( iface );
1316 IMarshal *marshal;
1317 HRESULT hr;
1319 TRACE("(%p, %p)\n", This, pStm);
1321 hr = StdMarshalImpl_Construct(&IID_IMarshal, This->dest_context,
1322 This->dest_context_data, (void**)&marshal);
1323 if(FAILED(hr))
1324 return hr;
1326 hr = IMarshal_ReleaseMarshalData(marshal, pStm);
1327 IMarshal_Release(marshal);
1328 return hr;
1331 static HRESULT WINAPI Proxy_DisconnectObject(IMarshal *iface, DWORD dwReserved)
1333 struct proxy_manager *This = impl_from_IMarshal( iface );
1334 IMarshal *marshal;
1335 HRESULT hr;
1337 TRACE("(%p, %x)\n", This, dwReserved);
1339 hr = StdMarshalImpl_Construct(&IID_IMarshal, This->dest_context,
1340 This->dest_context_data, (void**)&marshal);
1341 if(FAILED(hr))
1342 return hr;
1344 hr = IMarshal_DisconnectObject(marshal, dwReserved);
1345 IMarshal_Release(marshal);
1346 return hr;
1349 static const IMarshalVtbl ProxyMarshal_Vtbl =
1351 Proxy_QueryInterface,
1352 Proxy_AddRef,
1353 Proxy_Release,
1354 Proxy_GetUnmarshalClass,
1355 Proxy_GetMarshalSizeMax,
1356 Proxy_MarshalInterface,
1357 Proxy_UnmarshalInterface,
1358 Proxy_ReleaseMarshalData,
1359 Proxy_DisconnectObject
1362 static HRESULT WINAPI ProxyCliSec_QueryInterface(IClientSecurity *iface, REFIID riid, void **ppvObject)
1364 struct proxy_manager *This = impl_from_IClientSecurity( iface );
1365 return IMultiQI_QueryInterface(&This->IMultiQI_iface, riid, ppvObject);
1368 static ULONG WINAPI ProxyCliSec_AddRef(IClientSecurity *iface)
1370 struct proxy_manager *This = impl_from_IClientSecurity( iface );
1371 return IMultiQI_AddRef(&This->IMultiQI_iface);
1374 static ULONG WINAPI ProxyCliSec_Release(IClientSecurity *iface)
1376 struct proxy_manager *This = impl_from_IClientSecurity( iface );
1377 return IMultiQI_Release(&This->IMultiQI_iface);
1380 static HRESULT WINAPI ProxyCliSec_QueryBlanket(IClientSecurity *iface,
1381 IUnknown *pProxy,
1382 DWORD *pAuthnSvc,
1383 DWORD *pAuthzSvc,
1384 OLECHAR **ppServerPrincName,
1385 DWORD *pAuthnLevel,
1386 DWORD *pImpLevel,
1387 void **pAuthInfo,
1388 DWORD *pCapabilities)
1390 FIXME("(%p, %p, %p, %p, %p, %p, %p, %p): stub\n", pProxy, pAuthnSvc,
1391 pAuthzSvc, ppServerPrincName, pAuthnLevel, pImpLevel, pAuthInfo,
1392 pCapabilities);
1394 if (pAuthnSvc)
1395 *pAuthnSvc = 0;
1396 if (pAuthzSvc)
1397 *pAuthzSvc = 0;
1398 if (ppServerPrincName)
1399 *ppServerPrincName = NULL;
1400 if (pAuthnLevel)
1401 *pAuthnLevel = RPC_C_AUTHN_LEVEL_DEFAULT;
1402 if (pImpLevel)
1403 *pImpLevel = RPC_C_IMP_LEVEL_DEFAULT;
1404 if (pAuthInfo)
1405 *pAuthInfo = NULL;
1406 if (pCapabilities)
1407 *pCapabilities = EOAC_NONE;
1409 return E_NOTIMPL;
1412 static HRESULT WINAPI ProxyCliSec_SetBlanket(IClientSecurity *iface,
1413 IUnknown *pProxy, DWORD AuthnSvc,
1414 DWORD AuthzSvc,
1415 OLECHAR *pServerPrincName,
1416 DWORD AuthnLevel, DWORD ImpLevel,
1417 void *pAuthInfo,
1418 DWORD Capabilities)
1420 FIXME("(%p, %d, %d, %s, %d, %d, %p, 0x%x): stub\n", pProxy, AuthnSvc, AuthzSvc,
1421 pServerPrincName == COLE_DEFAULT_PRINCIPAL ? "<default principal>" : debugstr_w(pServerPrincName),
1422 AuthnLevel, ImpLevel, pAuthInfo, Capabilities);
1423 return E_NOTIMPL;
1426 static HRESULT WINAPI ProxyCliSec_CopyProxy(IClientSecurity *iface,
1427 IUnknown *pProxy, IUnknown **ppCopy)
1429 FIXME("(%p, %p): stub\n", pProxy, ppCopy);
1430 *ppCopy = NULL;
1431 return E_NOTIMPL;
1434 static const IClientSecurityVtbl ProxyCliSec_Vtbl =
1436 ProxyCliSec_QueryInterface,
1437 ProxyCliSec_AddRef,
1438 ProxyCliSec_Release,
1439 ProxyCliSec_QueryBlanket,
1440 ProxyCliSec_SetBlanket,
1441 ProxyCliSec_CopyProxy
1444 static HRESULT ifproxy_get_public_ref(struct ifproxy * This)
1446 HRESULT hr = S_OK;
1448 if (WAIT_OBJECT_0 != WaitForSingleObject(This->parent->remoting_mutex, INFINITE))
1450 ERR("Wait failed for ifproxy %p\n", This);
1451 return E_UNEXPECTED;
1454 if (This->refs == 0)
1456 IRemUnknown *remunk = NULL;
1458 TRACE("getting public ref for ifproxy %p\n", This);
1460 hr = proxy_manager_get_remunknown(This->parent, &remunk);
1461 if (hr == S_OK)
1463 HRESULT hrref = S_OK;
1464 REMINTERFACEREF rif;
1465 rif.ipid = This->stdobjref.ipid;
1466 rif.cPublicRefs = NORMALEXTREFS;
1467 rif.cPrivateRefs = 0;
1468 hr = IRemUnknown_RemAddRef(remunk, 1, &rif, &hrref);
1469 IRemUnknown_Release(remunk);
1470 if (hr == S_OK && hrref == S_OK)
1471 InterlockedExchangeAdd((LONG *)&This->refs, NORMALEXTREFS);
1472 else
1473 ERR("IRemUnknown_RemAddRef returned with 0x%08x, hrref = 0x%08x\n", hr, hrref);
1476 ReleaseMutex(This->parent->remoting_mutex);
1478 return hr;
1481 static HRESULT ifproxy_release_public_refs(struct ifproxy * This)
1483 HRESULT hr = S_OK;
1484 LONG public_refs;
1486 if (WAIT_OBJECT_0 != WaitForSingleObject(This->parent->remoting_mutex, INFINITE))
1488 ERR("Wait failed for ifproxy %p\n", This);
1489 return E_UNEXPECTED;
1492 public_refs = This->refs;
1493 if (public_refs > 0)
1495 IRemUnknown *remunk = NULL;
1497 TRACE("releasing %d refs\n", public_refs);
1499 hr = proxy_manager_get_remunknown(This->parent, &remunk);
1500 if (hr == S_OK)
1502 REMINTERFACEREF rif;
1503 rif.ipid = This->stdobjref.ipid;
1504 rif.cPublicRefs = public_refs;
1505 rif.cPrivateRefs = 0;
1506 hr = IRemUnknown_RemRelease(remunk, 1, &rif);
1507 IRemUnknown_Release(remunk);
1508 if (hr == S_OK)
1509 InterlockedExchangeAdd((LONG *)&This->refs, -public_refs);
1510 else if (hr == RPC_E_DISCONNECTED)
1511 WARN("couldn't release references because object was "
1512 "disconnected: oxid = %s, oid = %s\n",
1513 wine_dbgstr_longlong(This->parent->oxid),
1514 wine_dbgstr_longlong(This->parent->oid));
1515 else
1516 ERR("IRemUnknown_RemRelease failed with error 0x%08x\n", hr);
1519 ReleaseMutex(This->parent->remoting_mutex);
1521 return hr;
1524 /* should be called inside This->parent->cs critical section */
1525 static void ifproxy_disconnect(struct ifproxy * This)
1527 ifproxy_release_public_refs(This);
1528 if (This->proxy) IRpcProxyBuffer_Disconnect(This->proxy);
1530 IRpcChannelBuffer_Release(This->chan);
1531 This->chan = NULL;
1534 /* should be called in This->parent->cs critical section if it is an entry in parent's list */
1535 static void ifproxy_destroy(struct ifproxy * This)
1537 TRACE("%p\n", This);
1539 /* release public references to this object so that the stub can know
1540 * when to destroy itself */
1541 ifproxy_release_public_refs(This);
1543 list_remove(&This->entry);
1545 if (This->chan)
1547 IRpcChannelBuffer_Release(This->chan);
1548 This->chan = NULL;
1551 if (This->proxy) IRpcProxyBuffer_Release(This->proxy);
1553 HeapFree(GetProcessHeap(), 0, This);
1556 static HRESULT proxy_manager_construct(
1557 struct apartment * apt, ULONG sorflags, OXID oxid, OID oid,
1558 const OXID_INFO *oxid_info, struct proxy_manager ** proxy_manager)
1560 struct proxy_manager * This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
1561 if (!This) return E_OUTOFMEMORY;
1563 This->remoting_mutex = CreateMutexW(NULL, FALSE, NULL);
1564 if (!This->remoting_mutex)
1566 HeapFree(GetProcessHeap(), 0, This);
1567 return HRESULT_FROM_WIN32(GetLastError());
1570 if (oxid_info)
1572 This->oxid_info.dwPid = oxid_info->dwPid;
1573 This->oxid_info.dwTid = oxid_info->dwTid;
1574 This->oxid_info.ipidRemUnknown = oxid_info->ipidRemUnknown;
1575 This->oxid_info.dwAuthnHint = oxid_info->dwAuthnHint;
1576 This->oxid_info.psa = NULL /* FIXME: copy from oxid_info */;
1578 else
1580 HRESULT hr = rpc_resolve_oxid(oxid, &This->oxid_info);
1581 if (FAILED(hr))
1583 CloseHandle(This->remoting_mutex);
1584 HeapFree(GetProcessHeap(), 0, This);
1585 return hr;
1589 This->IMultiQI_iface.lpVtbl = &ClientIdentity_Vtbl;
1590 This->IMarshal_iface.lpVtbl = &ProxyMarshal_Vtbl;
1591 This->IClientSecurity_iface.lpVtbl = &ProxyCliSec_Vtbl;
1593 list_init(&This->entry);
1594 list_init(&This->interfaces);
1596 InitializeCriticalSection(&This->cs);
1597 This->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": proxy_manager");
1599 /* the apartment the object was unmarshaled into */
1600 This->parent = apt;
1602 /* the source apartment and id of the object */
1603 This->oxid = oxid;
1604 This->oid = oid;
1606 This->refs = 1;
1608 /* the DCOM draft specification states that the SORF_NOPING flag is
1609 * proxy manager specific, not ifproxy specific, so this implies that we
1610 * should store the STDOBJREF flags here in the proxy manager. */
1611 This->sorflags = sorflags;
1613 /* we create the IRemUnknown proxy on demand */
1614 This->remunk = NULL;
1616 /* initialise these values to the weakest values and they will be
1617 * overwritten in proxy_manager_set_context */
1618 This->dest_context = MSHCTX_INPROC;
1619 This->dest_context_data = NULL;
1621 EnterCriticalSection(&apt->cs);
1622 /* FIXME: we are dependent on the ordering in here to make sure a proxy's
1623 * IRemUnknown proxy doesn't get destroyed before the regular proxy does
1624 * because we need the IRemUnknown proxy during the destruction of the
1625 * regular proxy. Ideally, we should maintain a separate list for the
1626 * IRemUnknown proxies that need late destruction */
1627 list_add_tail(&apt->proxies, &This->entry);
1628 LeaveCriticalSection(&apt->cs);
1630 TRACE("%p created for OXID %s, OID %s\n", This,
1631 wine_dbgstr_longlong(oxid), wine_dbgstr_longlong(oid));
1633 *proxy_manager = This;
1634 return S_OK;
1637 static inline void proxy_manager_set_context(struct proxy_manager *This, MSHCTX dest_context, void *dest_context_data)
1639 MSHCTX old_dest_context;
1640 MSHCTX new_dest_context;
1644 old_dest_context = This->dest_context;
1645 new_dest_context = old_dest_context;
1646 /* "stronger" values overwrite "weaker" values. stronger values are
1647 * ones that disable more optimisations */
1648 switch (old_dest_context)
1650 case MSHCTX_INPROC:
1651 new_dest_context = dest_context;
1652 break;
1653 case MSHCTX_CROSSCTX:
1654 switch (dest_context)
1656 case MSHCTX_INPROC:
1657 break;
1658 default:
1659 new_dest_context = dest_context;
1661 break;
1662 case MSHCTX_LOCAL:
1663 switch (dest_context)
1665 case MSHCTX_INPROC:
1666 case MSHCTX_CROSSCTX:
1667 break;
1668 default:
1669 new_dest_context = dest_context;
1671 break;
1672 case MSHCTX_NOSHAREDMEM:
1673 switch (dest_context)
1675 case MSHCTX_DIFFERENTMACHINE:
1676 new_dest_context = dest_context;
1677 break;
1678 default:
1679 break;
1681 break;
1682 default:
1683 break;
1686 if (old_dest_context == new_dest_context) break;
1688 new_dest_context = InterlockedCompareExchange((PLONG)&This->dest_context, new_dest_context, old_dest_context);
1689 } while (new_dest_context != old_dest_context);
1691 if (dest_context_data)
1692 InterlockedExchangePointer(&This->dest_context_data, dest_context_data);
1695 static HRESULT proxy_manager_query_local_interface(struct proxy_manager * This, REFIID riid, void ** ppv)
1697 HRESULT hr;
1698 struct ifproxy * ifproxy;
1700 TRACE("%s\n", debugstr_guid(riid));
1702 if (IsEqualIID(riid, &IID_IUnknown) ||
1703 IsEqualIID(riid, &IID_IMultiQI))
1705 *ppv = &This->IMultiQI_iface;
1706 IMultiQI_AddRef(&This->IMultiQI_iface);
1707 return S_OK;
1709 if (IsEqualIID(riid, &IID_IMarshal))
1711 *ppv = &This->IMarshal_iface;
1712 IMarshal_AddRef(&This->IMarshal_iface);
1713 return S_OK;
1715 if (IsEqualIID(riid, &IID_IClientSecurity))
1717 *ppv = &This->IClientSecurity_iface;
1718 IClientSecurity_AddRef(&This->IClientSecurity_iface);
1719 return S_OK;
1722 hr = proxy_manager_find_ifproxy(This, riid, &ifproxy);
1723 if (hr == S_OK)
1725 *ppv = ifproxy->iface;
1726 IUnknown_AddRef((IUnknown *)*ppv);
1727 return S_OK;
1730 *ppv = NULL;
1731 return E_NOINTERFACE;
1734 static HRESULT proxy_manager_create_ifproxy(
1735 struct proxy_manager * This, const STDOBJREF *stdobjref, REFIID riid,
1736 IRpcChannelBuffer * channel, struct ifproxy ** iif_out)
1738 HRESULT hr;
1739 IPSFactoryBuffer * psfb;
1740 struct ifproxy * ifproxy = HeapAlloc(GetProcessHeap(), 0, sizeof(*ifproxy));
1741 if (!ifproxy) return E_OUTOFMEMORY;
1743 list_init(&ifproxy->entry);
1745 ifproxy->parent = This;
1746 ifproxy->stdobjref = *stdobjref;
1747 ifproxy->iid = *riid;
1748 ifproxy->refs = 0;
1749 ifproxy->proxy = NULL;
1751 assert(channel);
1752 ifproxy->chan = channel; /* FIXME: we should take the binding strings and construct the channel in this function */
1754 /* the IUnknown interface is special because it does not have a
1755 * proxy associated with the ifproxy as we handle IUnknown ourselves */
1756 if (IsEqualIID(riid, &IID_IUnknown))
1758 ifproxy->iface = &This->IMultiQI_iface;
1759 IMultiQI_AddRef(&This->IMultiQI_iface);
1760 hr = S_OK;
1762 else
1764 hr = get_facbuf_for_iid(riid, &psfb);
1765 if (hr == S_OK)
1767 /* important note: the outer unknown is set to the proxy manager.
1768 * This ensures the COM identity rules are not violated, by having a
1769 * one-to-one mapping of objects on the proxy side to objects on the
1770 * stub side, no matter which interface you view the object through */
1771 hr = IPSFactoryBuffer_CreateProxy(psfb, (IUnknown*)&This->IMultiQI_iface, riid,
1772 &ifproxy->proxy, &ifproxy->iface);
1773 IPSFactoryBuffer_Release(psfb);
1774 if (hr != S_OK)
1775 ERR("Could not create proxy for interface %s, error 0x%08x\n",
1776 debugstr_guid(riid), hr);
1778 else
1779 ERR("Could not get IPSFactoryBuffer for interface %s, error 0x%08x\n",
1780 debugstr_guid(riid), hr);
1782 if (hr == S_OK)
1783 hr = IRpcProxyBuffer_Connect(ifproxy->proxy, ifproxy->chan);
1786 if (hr == S_OK)
1788 EnterCriticalSection(&This->cs);
1789 list_add_tail(&This->interfaces, &ifproxy->entry);
1790 LeaveCriticalSection(&This->cs);
1792 *iif_out = ifproxy;
1793 TRACE("ifproxy %p created for IPID %s, interface %s with %u public refs\n",
1794 ifproxy, debugstr_guid(&stdobjref->ipid), debugstr_guid(riid), stdobjref->cPublicRefs);
1796 else
1797 ifproxy_destroy(ifproxy);
1799 return hr;
1802 static HRESULT proxy_manager_find_ifproxy(struct proxy_manager * This, REFIID riid, struct ifproxy ** ifproxy_found)
1804 HRESULT hr = E_NOINTERFACE; /* assume not found */
1805 struct ifproxy *ifproxy;
1807 EnterCriticalSection(&This->cs);
1808 LIST_FOR_EACH_ENTRY(ifproxy, &This->interfaces, struct ifproxy, entry)
1810 if (IsEqualIID(riid, &ifproxy->iid))
1812 *ifproxy_found = ifproxy;
1813 hr = S_OK;
1814 break;
1817 LeaveCriticalSection(&This->cs);
1819 return hr;
1822 static void proxy_manager_disconnect(struct proxy_manager * This)
1824 struct ifproxy *ifproxy;
1826 TRACE("oxid = %s, oid = %s\n", wine_dbgstr_longlong(This->oxid),
1827 wine_dbgstr_longlong(This->oid));
1829 EnterCriticalSection(&This->cs);
1831 /* SORFP_NOLIFTIMEMGMT proxies (for IRemUnknown) shouldn't be
1832 * disconnected - it won't do anything anyway, except cause
1833 * problems for other objects that depend on this proxy always
1834 * working */
1835 if (!(This->sorflags & SORFP_NOLIFETIMEMGMT))
1837 LIST_FOR_EACH_ENTRY(ifproxy, &This->interfaces, struct ifproxy, entry)
1839 ifproxy_disconnect(ifproxy);
1843 /* apartment is being destroyed so don't keep a pointer around to it */
1844 This->parent = NULL;
1846 LeaveCriticalSection(&This->cs);
1849 static HRESULT proxy_manager_get_remunknown(struct proxy_manager * This, IRemUnknown **remunk)
1851 HRESULT hr = S_OK;
1852 struct apartment *apt;
1853 BOOL called_in_original_apt;
1855 /* we don't want to try and unmarshal or use IRemUnknown if we don't want
1856 * lifetime management */
1857 if (This->sorflags & SORFP_NOLIFETIMEMGMT)
1858 return S_FALSE;
1860 if (!(apt = apartment_get_current_or_mta()))
1861 return CO_E_NOTINITIALIZED;
1863 called_in_original_apt = This->parent && (This->parent->oxid == apt->oxid);
1865 EnterCriticalSection(&This->cs);
1866 /* only return the cached object if called from the original apartment.
1867 * in future, we might want to make the IRemUnknown proxy callable from any
1868 * apartment to avoid these checks */
1869 if (This->remunk && called_in_original_apt)
1871 /* already created - return existing object */
1872 *remunk = This->remunk;
1873 IRemUnknown_AddRef(*remunk);
1875 else if (!This->parent)
1877 /* disconnected - we can't create IRemUnknown */
1878 *remunk = NULL;
1879 hr = S_FALSE;
1881 else
1883 STDOBJREF stdobjref;
1884 /* Don't want IRemUnknown lifetime management as this is IRemUnknown!
1885 * We also don't care about whether or not the stub is still alive */
1886 stdobjref.flags = SORFP_NOLIFETIMEMGMT | SORF_NOPING;
1887 stdobjref.cPublicRefs = 1;
1888 /* oxid of destination object */
1889 stdobjref.oxid = This->oxid;
1890 /* FIXME: what should be used for the oid? The DCOM draft doesn't say */
1891 stdobjref.oid = (OID)-1;
1892 stdobjref.ipid = This->oxid_info.ipidRemUnknown;
1894 /* do the unmarshal */
1895 hr = unmarshal_object(&stdobjref, apt, This->dest_context,
1896 This->dest_context_data, &IID_IRemUnknown,
1897 &This->oxid_info, (void**)remunk);
1898 if (hr == S_OK && called_in_original_apt)
1900 This->remunk = *remunk;
1901 IRemUnknown_AddRef(This->remunk);
1904 LeaveCriticalSection(&This->cs);
1905 apartment_release(apt);
1907 TRACE("got IRemUnknown* pointer %p, hr = 0x%08x\n", *remunk, hr);
1909 return hr;
1912 /* destroys a proxy manager, freeing the memory it used.
1913 * Note: this function should not be called from a list iteration in the
1914 * apartment, due to the fact that it removes itself from the apartment and
1915 * it could add a proxy to IRemUnknown into the apartment. */
1916 static void proxy_manager_destroy(struct proxy_manager * This)
1918 struct list * cursor;
1920 TRACE("oxid = %s, oid = %s\n", wine_dbgstr_longlong(This->oxid),
1921 wine_dbgstr_longlong(This->oid));
1923 if (This->parent)
1925 EnterCriticalSection(&This->parent->cs);
1927 /* remove ourself from the list of proxy objects in the apartment */
1928 LIST_FOR_EACH(cursor, &This->parent->proxies)
1930 if (cursor == &This->entry)
1932 list_remove(&This->entry);
1933 break;
1937 LeaveCriticalSection(&This->parent->cs);
1940 /* destroy all of the interface proxies */
1941 while ((cursor = list_head(&This->interfaces)))
1943 struct ifproxy * ifproxy = LIST_ENTRY(cursor, struct ifproxy, entry);
1944 ifproxy_destroy(ifproxy);
1947 if (This->remunk) IRemUnknown_Release(This->remunk);
1948 CoTaskMemFree(This->oxid_info.psa);
1950 This->cs.DebugInfo->Spare[0] = 0;
1951 DeleteCriticalSection(&This->cs);
1953 CloseHandle(This->remoting_mutex);
1955 HeapFree(GetProcessHeap(), 0, This);
1958 /* finds the proxy manager corresponding to a given OXID and OID that has
1959 * been unmarshaled in the specified apartment. The caller must release the
1960 * reference to the proxy_manager when the object is no longer used. */
1961 static BOOL find_proxy_manager(struct apartment * apt, OXID oxid, OID oid, struct proxy_manager ** proxy_found)
1963 struct proxy_manager *proxy;
1964 BOOL found = FALSE;
1966 EnterCriticalSection(&apt->cs);
1967 LIST_FOR_EACH_ENTRY(proxy, &apt->proxies, struct proxy_manager, entry)
1969 if ((oxid == proxy->oxid) && (oid == proxy->oid))
1971 /* be careful of a race with ClientIdentity_Release, which would
1972 * cause us to return a proxy which is in the process of being
1973 * destroyed */
1974 if (IMultiQI_AddRef(&proxy->IMultiQI_iface) != 0)
1976 *proxy_found = proxy;
1977 found = TRUE;
1978 break;
1982 LeaveCriticalSection(&apt->cs);
1983 return found;
1986 HRESULT apartment_disconnectproxies(struct apartment *apt)
1988 struct proxy_manager *proxy;
1990 LIST_FOR_EACH_ENTRY(proxy, &apt->proxies, struct proxy_manager, entry)
1992 proxy_manager_disconnect(proxy);
1995 return S_OK;
1998 /********************** StdMarshal implementation ****************************/
2000 struct stdmarshal
2002 IMarshal IMarshal_iface;
2003 LONG refcount;
2004 DWORD dest_context;
2005 void *dest_context_data;
2008 static inline struct stdmarshal *impl_from_StdMarshal(IMarshal *iface)
2010 return CONTAINING_RECORD(iface, struct stdmarshal, IMarshal_iface);
2013 static HRESULT WINAPI StdMarshalImpl_QueryInterface(IMarshal *iface, REFIID riid, void **ppv)
2015 *ppv = NULL;
2016 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IMarshal, riid))
2018 *ppv = iface;
2019 IMarshal_AddRef(iface);
2020 return S_OK;
2022 FIXME("No interface for %s.\n", debugstr_guid(riid));
2023 return E_NOINTERFACE;
2026 static ULONG WINAPI StdMarshalImpl_AddRef(IMarshal *iface)
2028 struct stdmarshal *marshal = impl_from_StdMarshal(iface);
2029 return InterlockedIncrement(&marshal->refcount);
2032 static ULONG WINAPI StdMarshalImpl_Release(IMarshal *iface)
2034 struct stdmarshal *marshal = impl_from_StdMarshal(iface);
2035 ULONG refcount = InterlockedDecrement(&marshal->refcount);
2037 if (!refcount)
2038 heap_free(marshal);
2040 return refcount;
2043 static HRESULT WINAPI StdMarshalImpl_GetUnmarshalClass(IMarshal *iface, REFIID riid, void *pv,
2044 DWORD dwDestContext, void *pvDestContext, DWORD mshlflags, CLSID *pCid)
2046 *pCid = CLSID_StdMarshal;
2047 return S_OK;
2050 static HRESULT WINAPI StdMarshalImpl_GetMarshalSizeMax(IMarshal *iface, REFIID riid, void *pv,
2051 DWORD dwDestContext, void *pvDestContext, DWORD mshlflags, DWORD *pSize)
2053 *pSize = FIELD_OFFSET(OBJREF, u_objref.u_standard.saResAddr.aStringArray);
2054 return S_OK;
2057 static HRESULT WINAPI StdMarshalImpl_MarshalInterface(IMarshal *iface, IStream *stream, REFIID riid, void *pv,
2058 DWORD dest_context, void *dest_context_data, DWORD mshlflags)
2060 ULONG res;
2061 HRESULT hr;
2062 OBJREF objref;
2063 struct apartment *apt;
2065 TRACE("(...,%s,...)\n", debugstr_guid(riid));
2067 if (!(apt = apartment_get_current_or_mta()))
2069 ERR("Apartment not initialized\n");
2070 return CO_E_NOTINITIALIZED;
2073 /* make sure this apartment can be reached from other threads / processes */
2074 rpc_start_remoting(apt);
2076 fill_std_objref(&objref, riid, NULL);
2077 hr = marshal_object(apt, &objref.u_objref.u_standard.std, riid, pv, dest_context,
2078 dest_context_data, mshlflags);
2079 apartment_release(apt);
2080 if (hr != S_OK)
2082 ERR("Failed to create ifstub, hr %#x\n", hr);
2083 return hr;
2086 return IStream_Write(stream, &objref, FIELD_OFFSET(OBJREF, u_objref.u_standard.saResAddr.aStringArray), &res);
2089 /* helper for StdMarshalImpl_UnmarshalInterface - does the unmarshaling with
2090 * no questions asked about the rules surrounding same-apartment unmarshals
2091 * and table marshaling */
2092 static HRESULT unmarshal_object(const STDOBJREF *stdobjref, struct apartment *apt, MSHCTX dest_context,
2093 void *dest_context_data, REFIID riid, const OXID_INFO *oxid_info, void **object)
2095 struct proxy_manager *proxy_manager = NULL;
2096 HRESULT hr = S_OK;
2098 assert(apt);
2100 TRACE("stdobjref: flags = %04x cPublicRefs = %d oxid = %s oid = %s ipid = %s\n",
2101 stdobjref->flags, stdobjref->cPublicRefs,
2102 wine_dbgstr_longlong(stdobjref->oxid),
2103 wine_dbgstr_longlong(stdobjref->oid),
2104 debugstr_guid(&stdobjref->ipid));
2106 /* create a new proxy manager if one doesn't already exist for the
2107 * object */
2108 if (!find_proxy_manager(apt, stdobjref->oxid, stdobjref->oid, &proxy_manager))
2110 hr = proxy_manager_construct(apt, stdobjref->flags,
2111 stdobjref->oxid, stdobjref->oid, oxid_info,
2112 &proxy_manager);
2114 else
2115 TRACE("proxy manager already created, using\n");
2117 if (hr == S_OK)
2119 struct ifproxy * ifproxy;
2121 proxy_manager_set_context(proxy_manager, dest_context, dest_context_data);
2123 hr = proxy_manager_find_ifproxy(proxy_manager, riid, &ifproxy);
2124 if (hr == E_NOINTERFACE)
2126 IRpcChannelBuffer *chanbuf;
2127 hr = rpc_create_clientchannel(&stdobjref->oxid, &stdobjref->ipid,
2128 &proxy_manager->oxid_info, riid, proxy_manager->dest_context,
2129 proxy_manager->dest_context_data, &chanbuf, apt);
2130 if (hr == S_OK)
2131 hr = proxy_manager_create_ifproxy(proxy_manager, stdobjref, riid, chanbuf, &ifproxy);
2133 else
2134 IUnknown_AddRef((IUnknown *)ifproxy->iface);
2136 if (hr == S_OK)
2138 InterlockedExchangeAdd((LONG *)&ifproxy->refs, stdobjref->cPublicRefs);
2139 /* get at least one external reference to the object to keep it alive */
2140 hr = ifproxy_get_public_ref(ifproxy);
2141 if (FAILED(hr))
2142 ifproxy_destroy(ifproxy);
2145 if (hr == S_OK)
2146 *object = ifproxy->iface;
2149 /* release our reference to the proxy manager - the client/apartment
2150 * will hold on to the remaining reference for us */
2151 if (proxy_manager) IMultiQI_Release(&proxy_manager->IMultiQI_iface);
2153 return hr;
2156 static HRESULT WINAPI StdMarshalImpl_UnmarshalInterface(IMarshal *iface, IStream *stream, REFIID riid, void **ppv)
2158 struct stdmarshal *marshal = impl_from_StdMarshal(iface);
2159 OBJREF objref;
2160 HRESULT hr;
2161 ULONG res;
2163 hr = IStream_Read(stream, &objref, FIELD_OFFSET(OBJREF, u_objref), &res);
2164 if (hr != S_OK || (res != FIELD_OFFSET(OBJREF, u_objref)))
2166 ERR("Failed to read common OBJREF header, 0x%08x\n", hr);
2167 return STG_E_READFAULT;
2170 if (objref.signature != OBJREF_SIGNATURE)
2172 ERR("Bad OBJREF signature 0x%08x\n", objref.signature);
2173 return RPC_E_INVALID_OBJREF;
2176 if (!(objref.flags & OBJREF_STANDARD))
2178 FIXME("unsupported objref.flags = %x\n", objref.flags);
2179 return E_NOTIMPL;
2182 return std_unmarshal_interface(marshal->dest_context, marshal->dest_context_data, stream, riid, ppv);
2185 static HRESULT WINAPI StdMarshalImpl_ReleaseMarshalData(IMarshal *iface, IStream *stream)
2187 OBJREF objref;
2188 HRESULT hr;
2189 ULONG res;
2191 TRACE("%p, %p\n", iface, stream);
2193 hr = IStream_Read(stream, &objref, FIELD_OFFSET(OBJREF, u_objref), &res);
2194 if (hr != S_OK || (res != FIELD_OFFSET(OBJREF, u_objref)))
2196 ERR("Failed to read common OBJREF header, 0x%08x\n", hr);
2197 return STG_E_READFAULT;
2200 if (objref.signature != OBJREF_SIGNATURE)
2202 ERR("Bad OBJREF signature 0x%08x\n", objref.signature);
2203 return RPC_E_INVALID_OBJREF;
2206 if (!(objref.flags & OBJREF_STANDARD))
2208 FIXME("unsupported objref.flags = %x\n", objref.flags);
2209 return E_NOTIMPL;
2212 return std_release_marshal_data(stream);
2215 static HRESULT WINAPI StdMarshalImpl_DisconnectObject(IMarshal *iface, DWORD reserved)
2217 FIXME("(), stub!\n");
2218 return S_OK;
2221 static const IMarshalVtbl StdMarshalVtbl =
2223 StdMarshalImpl_QueryInterface,
2224 StdMarshalImpl_AddRef,
2225 StdMarshalImpl_Release,
2226 StdMarshalImpl_GetUnmarshalClass,
2227 StdMarshalImpl_GetMarshalSizeMax,
2228 StdMarshalImpl_MarshalInterface,
2229 StdMarshalImpl_UnmarshalInterface,
2230 StdMarshalImpl_ReleaseMarshalData,
2231 StdMarshalImpl_DisconnectObject
2234 static HRESULT StdMarshalImpl_Construct(REFIID riid, DWORD dest_context, void *dest_context_data, void **ppvObject)
2236 struct stdmarshal *object;
2237 HRESULT hr;
2239 object = heap_alloc(sizeof(*object));
2240 if (!object)
2241 return E_OUTOFMEMORY;
2243 object->IMarshal_iface.lpVtbl = &StdMarshalVtbl;
2244 object->refcount = 1;
2245 object->dest_context = dest_context;
2246 object->dest_context_data = dest_context_data;
2248 hr = IMarshal_QueryInterface(&object->IMarshal_iface, riid, ppvObject);
2249 IMarshal_Release(&object->IMarshal_iface);
2251 return hr;
2254 HRESULT WINAPI InternalCoStdMarshalObject(REFIID riid, DWORD dest_context, void *dest_context_data, void **ppvObject)
2256 return StdMarshalImpl_Construct(riid, dest_context, dest_context_data, ppvObject);
2259 /***********************************************************************
2260 * CoGetStandardMarshal (combase.@)
2262 HRESULT WINAPI CoGetStandardMarshal(REFIID riid, IUnknown *pUnk, DWORD dwDestContext,
2263 void *dest_context, DWORD flags, IMarshal **marshal)
2265 if (pUnk == NULL)
2267 FIXME("(%s,NULL,%x,%p,%x,%p), unimplemented yet.\n", debugstr_guid(riid), dwDestContext,
2268 dest_context, flags, marshal);
2269 return E_NOTIMPL;
2271 TRACE("%s, %p, %x, %p, %x, %p\n", debugstr_guid(riid), pUnk, dwDestContext, dest_context, flags, marshal);
2273 return StdMarshalImpl_Construct(&IID_IMarshal, dwDestContext, dest_context, (void **)marshal);