ole32: Fix a typo in a TRACE() message.
[wine.git] / dlls / ole32 / marshal.c
blobbdde38ba213bc4d1ff067a7260df699e272788c1
1 /*
2 * Marshalling library
4 * Copyright 2002 Marcus Meissner
5 * Copyright 2004 Mike Hearn, for CodeWeavers
6 * Copyright 2004 Rob Shearman, for CodeWeavers
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.
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.
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include <stdarg.h>
24 #include <string.h>
25 #include <assert.h>
27 #define COBJMACROS
29 #include "windef.h"
30 #include "winbase.h"
31 #include "winuser.h"
32 #include "objbase.h"
33 #include "ole2.h"
34 #include "winerror.h"
35 #include "wine/unicode.h"
37 #include "compobj_private.h"
39 #include "wine/debug.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(ole);
43 extern const CLSID CLSID_DfMarshal;
45 /* number of refs given out for normal marshaling */
46 #define NORMALEXTREFS 5
49 /* private flag indicating that the object was marshaled as table-weak */
50 #define SORFP_TABLEWEAK SORF_OXRES1
51 /* private flag indicating that the caller does not want to notify the stub
52 * when the proxy disconnects or is destroyed */
53 #define SORFP_NOLIFETIMEMGMT SORF_OXRES2
55 /* imported object / proxy manager */
56 struct proxy_manager
58 IMultiQI IMultiQI_iface;
59 IMarshal IMarshal_iface;
60 IClientSecurity IClientSecurity_iface;
61 struct apartment *parent; /* owning apartment (RO) */
62 struct list entry; /* entry in apartment (CS parent->cs) */
63 OXID oxid; /* object exported ID (RO) */
64 OXID_INFO oxid_info; /* string binding, ipid of rem unknown and other information (RO) */
65 OID oid; /* object ID (RO) */
66 struct list interfaces; /* imported interfaces (CS cs) */
67 LONG refs; /* proxy reference count (LOCK) */
68 CRITICAL_SECTION cs; /* thread safety for this object and children */
69 ULONG sorflags; /* STDOBJREF flags (RO) */
70 IRemUnknown *remunk; /* proxy to IRemUnknown used for lifecycle management (CS cs) */
71 HANDLE remoting_mutex; /* mutex used for synchronizing access to IRemUnknown */
72 MSHCTX dest_context; /* context used for activating optimisations (LOCK) */
73 void *dest_context_data; /* reserved context value (LOCK) */
76 static inline struct proxy_manager *impl_from_IMarshal( IMarshal *iface )
78 return CONTAINING_RECORD(iface, struct proxy_manager, IMarshal_iface);
81 static inline struct proxy_manager *impl_from_IClientSecurity( IClientSecurity *iface )
83 return CONTAINING_RECORD(iface, struct proxy_manager, IClientSecurity_iface);
86 static HRESULT unmarshal_object(const STDOBJREF *stdobjref, APARTMENT *apt,
87 MSHCTX dest_context, void *dest_context_data,
88 REFIID riid, const OXID_INFO *oxid_info,
89 void **object);
91 /* Marshalling just passes a unique identifier to the remote client,
92 * that makes it possible to find the passed interface again.
94 * So basically we need a set of values that make it unique.
96 * Note that the IUnknown_QI(ob,xiid,&ppv) always returns the SAME ppv value!
98 * A triple is used: OXID (apt id), OID (stub manager id),
99 * IPID (interface ptr/stub id).
101 * OXIDs identify an apartment and are network scoped
102 * OIDs identify a stub manager and are apartment scoped
103 * IPIDs identify an interface stub and are apartment scoped
106 static inline HRESULT get_facbuf_for_iid(REFIID riid, IPSFactoryBuffer **facbuf)
108 HRESULT hr;
109 CLSID clsid;
111 hr = CoGetPSClsid(riid, &clsid);
112 if (hr != S_OK)
113 return hr;
114 return CoGetClassObject(&clsid, CLSCTX_INPROC_SERVER | WINE_CLSCTX_DONT_HOST,
115 NULL, &IID_IPSFactoryBuffer, (LPVOID*)facbuf);
118 /* marshals an object into a STDOBJREF structure */
119 HRESULT marshal_object(APARTMENT *apt, STDOBJREF *stdobjref, REFIID riid, IUnknown *object,
120 DWORD dest_context, void *dest_context_data, MSHLFLAGS mshlflags)
122 struct stub_manager *manager;
123 struct ifstub *ifstub;
124 BOOL tablemarshal;
125 HRESULT hr;
127 hr = apartment_getoxid(apt, &stdobjref->oxid);
128 if (hr != S_OK)
129 return hr;
131 hr = apartment_createwindowifneeded(apt);
132 if (hr != S_OK)
133 return hr;
135 if (!(manager = get_stub_manager_from_object(apt, object, TRUE)))
136 return E_OUTOFMEMORY;
138 stdobjref->flags = SORF_NULL;
139 if (mshlflags & MSHLFLAGS_TABLEWEAK)
140 stdobjref->flags |= SORFP_TABLEWEAK;
141 if (mshlflags & MSHLFLAGS_NOPING)
142 stdobjref->flags |= SORF_NOPING;
143 stdobjref->oid = manager->oid;
145 tablemarshal = ((mshlflags & MSHLFLAGS_TABLESTRONG) || (mshlflags & MSHLFLAGS_TABLEWEAK));
147 /* make sure ifstub that we are creating is unique */
148 ifstub = stub_manager_find_ifstub(manager, riid, mshlflags);
149 if (!ifstub) {
150 IRpcStubBuffer *stub = NULL;
152 /* IUnknown doesn't require a stub buffer, because it never goes out on
153 * the wire */
154 if (!IsEqualIID(riid, &IID_IUnknown))
156 IPSFactoryBuffer *psfb;
158 hr = get_facbuf_for_iid(riid, &psfb);
159 if (hr == S_OK) {
160 hr = IPSFactoryBuffer_CreateStub(psfb, riid, manager->object, &stub);
161 IPSFactoryBuffer_Release(psfb);
162 if (hr != S_OK)
163 ERR("Failed to create an IRpcStubBuffer from IPSFactory for %s with error 0x%08x\n",
164 debugstr_guid(riid), hr);
165 }else {
166 ERR("couldn't get IPSFactory buffer for interface %s\n", debugstr_guid(riid));
167 hr = E_NOINTERFACE;
172 if (hr == S_OK) {
173 ifstub = stub_manager_new_ifstub(manager, stub, riid, dest_context, dest_context_data, mshlflags);
174 if (!ifstub)
175 hr = E_OUTOFMEMORY;
177 if (stub) IRpcStubBuffer_Release(stub);
179 if (hr != S_OK) {
180 stub_manager_int_release(manager);
181 /* destroy the stub manager if it has no ifstubs by releasing
182 * zero external references */
183 stub_manager_ext_release(manager, 0, FALSE, TRUE);
184 return hr;
188 if (!tablemarshal)
190 stdobjref->cPublicRefs = NORMALEXTREFS;
191 stub_manager_ext_addref(manager, stdobjref->cPublicRefs, FALSE);
193 else
195 stdobjref->cPublicRefs = 0;
196 if (mshlflags & MSHLFLAGS_TABLESTRONG)
197 stub_manager_ext_addref(manager, 1, FALSE);
198 else
199 stub_manager_ext_addref(manager, 0, TRUE);
202 /* FIXME: check return value */
203 RPC_RegisterInterface(riid);
205 stdobjref->ipid = ifstub->ipid;
207 stub_manager_int_release(manager);
208 return S_OK;
213 /* Client-side identity of the server object */
215 static HRESULT proxy_manager_get_remunknown(struct proxy_manager * This, IRemUnknown **remunk);
216 static void proxy_manager_destroy(struct proxy_manager * This);
217 static HRESULT proxy_manager_find_ifproxy(struct proxy_manager * This, REFIID riid, struct ifproxy ** ifproxy_found);
218 static HRESULT proxy_manager_query_local_interface(struct proxy_manager * This, REFIID riid, void ** ppv);
220 static HRESULT WINAPI ClientIdentity_QueryInterface(IMultiQI * iface, REFIID riid, void ** ppv)
222 HRESULT hr;
223 MULTI_QI mqi;
225 TRACE("%s\n", debugstr_guid(riid));
227 mqi.pIID = riid;
228 hr = IMultiQI_QueryMultipleInterfaces(iface, 1, &mqi);
229 *ppv = mqi.pItf;
231 return hr;
234 static ULONG WINAPI ClientIdentity_AddRef(IMultiQI * iface)
236 struct proxy_manager * This = (struct proxy_manager *)iface;
237 TRACE("%p - before %d\n", iface, This->refs);
238 return InterlockedIncrement(&This->refs);
241 static ULONG WINAPI ClientIdentity_Release(IMultiQI * iface)
243 struct proxy_manager * This = (struct proxy_manager *)iface;
244 ULONG refs = InterlockedDecrement(&This->refs);
245 TRACE("%p - after %d\n", iface, refs);
246 if (!refs)
247 proxy_manager_destroy(This);
248 return refs;
251 static HRESULT WINAPI ClientIdentity_QueryMultipleInterfaces(IMultiQI *iface, ULONG cMQIs, MULTI_QI *pMQIs)
253 struct proxy_manager * This = (struct proxy_manager *)iface;
254 REMQIRESULT *qiresults = NULL;
255 ULONG nonlocal_mqis = 0;
256 ULONG i;
257 ULONG successful_mqis = 0;
258 IID *iids = HeapAlloc(GetProcessHeap(), 0, cMQIs * sizeof(*iids));
259 /* mapping of RemQueryInterface index to QueryMultipleInterfaces index */
260 ULONG *mapping = HeapAlloc(GetProcessHeap(), 0, cMQIs * sizeof(*mapping));
262 TRACE("cMQIs: %d\n", cMQIs);
264 /* try to get a local interface - this includes already active proxy
265 * interfaces and also interfaces exposed by the proxy manager */
266 for (i = 0; i < cMQIs; i++)
268 TRACE("iid[%d] = %s\n", i, debugstr_guid(pMQIs[i].pIID));
269 pMQIs[i].hr = proxy_manager_query_local_interface(This, pMQIs[i].pIID, (void **)&pMQIs[i].pItf);
270 if (pMQIs[i].hr == S_OK)
271 successful_mqis++;
272 else
274 iids[nonlocal_mqis] = *pMQIs[i].pIID;
275 mapping[nonlocal_mqis] = i;
276 nonlocal_mqis++;
280 TRACE("%d interfaces not found locally\n", nonlocal_mqis);
282 /* if we have more than one interface not found locally then we must try
283 * to query the remote object for it */
284 if (nonlocal_mqis != 0)
286 IRemUnknown *remunk;
287 HRESULT hr;
288 IPID *ipid;
290 /* get the ipid of the first entry */
291 /* FIXME: should we implement ClientIdentity on the ifproxies instead
292 * of the proxy_manager so we use the correct ipid here? */
293 ipid = &LIST_ENTRY(list_head(&This->interfaces), struct ifproxy, entry)->stdobjref.ipid;
295 /* get IRemUnknown proxy so we can communicate with the remote object */
296 hr = proxy_manager_get_remunknown(This, &remunk);
298 if (SUCCEEDED(hr))
300 hr = IRemUnknown_RemQueryInterface(remunk, ipid, NORMALEXTREFS,
301 nonlocal_mqis, iids, &qiresults);
302 IRemUnknown_Release(remunk);
303 if (FAILED(hr))
304 ERR("IRemUnknown_RemQueryInterface failed with error 0x%08x\n", hr);
307 /* IRemUnknown_RemQueryInterface can return S_FALSE if only some of
308 * the interfaces were returned */
309 if (SUCCEEDED(hr))
311 /* try to unmarshal each object returned to us */
312 for (i = 0; i < nonlocal_mqis; i++)
314 ULONG index = mapping[i];
315 HRESULT hrobj = qiresults[i].hResult;
316 if (hrobj == S_OK)
317 hrobj = unmarshal_object(&qiresults[i].std, COM_CurrentApt(),
318 This->dest_context,
319 This->dest_context_data,
320 pMQIs[index].pIID, &This->oxid_info,
321 (void **)&pMQIs[index].pItf);
323 if (hrobj == S_OK)
324 successful_mqis++;
325 else
326 ERR("Failed to get pointer to interface %s\n", debugstr_guid(pMQIs[index].pIID));
327 pMQIs[index].hr = hrobj;
331 /* free the memory allocated by the proxy */
332 CoTaskMemFree(qiresults);
335 TRACE("%d/%d successfully queried\n", successful_mqis, cMQIs);
337 HeapFree(GetProcessHeap(), 0, iids);
338 HeapFree(GetProcessHeap(), 0, mapping);
340 if (successful_mqis == cMQIs)
341 return S_OK; /* we got all requested interfaces */
342 else if (successful_mqis == 0)
343 return E_NOINTERFACE; /* we didn't get any interfaces */
344 else
345 return S_FALSE; /* we got some interfaces */
348 static const IMultiQIVtbl ClientIdentity_Vtbl =
350 ClientIdentity_QueryInterface,
351 ClientIdentity_AddRef,
352 ClientIdentity_Release,
353 ClientIdentity_QueryMultipleInterfaces
356 /* FIXME: remove these */
357 static HRESULT WINAPI StdMarshalImpl_GetUnmarshalClass(LPMARSHAL iface, REFIID riid, void* pv, DWORD dwDestContext, void* pvDestContext, DWORD mshlflags, CLSID* pCid);
358 static HRESULT WINAPI StdMarshalImpl_GetMarshalSizeMax(LPMARSHAL iface, REFIID riid, void* pv, DWORD dwDestContext, void* pvDestContext, DWORD mshlflags, DWORD* pSize);
359 static HRESULT WINAPI StdMarshalImpl_UnmarshalInterface(LPMARSHAL iface, IStream *pStm, REFIID riid, void **ppv);
360 static HRESULT WINAPI StdMarshalImpl_ReleaseMarshalData(LPMARSHAL iface, IStream *pStm);
361 static HRESULT WINAPI StdMarshalImpl_DisconnectObject(LPMARSHAL iface, DWORD dwReserved);
363 static HRESULT WINAPI Proxy_QueryInterface(IMarshal *iface, REFIID riid, void **ppvObject)
365 struct proxy_manager *This = impl_from_IMarshal( iface );
366 return IMultiQI_QueryInterface(&This->IMultiQI_iface, riid, ppvObject);
369 static ULONG WINAPI Proxy_AddRef(IMarshal *iface)
371 struct proxy_manager *This = impl_from_IMarshal( iface );
372 return IMultiQI_AddRef(&This->IMultiQI_iface);
375 static ULONG WINAPI Proxy_Release(IMarshal *iface)
377 struct proxy_manager *This = impl_from_IMarshal( iface );
378 return IMultiQI_Release(&This->IMultiQI_iface);
381 static HRESULT WINAPI Proxy_MarshalInterface(
382 LPMARSHAL iface, IStream *pStm, REFIID riid, void* pv, DWORD dwDestContext,
383 void* pvDestContext, DWORD mshlflags)
385 struct proxy_manager *This = impl_from_IMarshal( iface );
386 HRESULT hr;
387 struct ifproxy *ifproxy;
389 TRACE("(...,%s,...)\n", debugstr_guid(riid));
391 hr = proxy_manager_find_ifproxy(This, riid, &ifproxy);
392 if (SUCCEEDED(hr))
394 STDOBJREF stdobjref = ifproxy->stdobjref;
396 stdobjref.cPublicRefs = 0;
398 if ((mshlflags != MSHLFLAGS_TABLEWEAK) &&
399 (mshlflags != MSHLFLAGS_TABLESTRONG))
401 ULONG cPublicRefs = ifproxy->refs;
402 ULONG cPublicRefsOld;
403 /* optimization - share out proxy's public references if possible
404 * instead of making new proxy do a roundtrip through the server */
407 ULONG cPublicRefsNew;
408 cPublicRefsOld = cPublicRefs;
409 stdobjref.cPublicRefs = cPublicRefs / 2;
410 cPublicRefsNew = cPublicRefs - stdobjref.cPublicRefs;
411 cPublicRefs = InterlockedCompareExchange(
412 (LONG *)&ifproxy->refs, cPublicRefsNew, cPublicRefsOld);
413 } while (cPublicRefs != cPublicRefsOld);
416 /* normal and table-strong marshaling need at least one reference */
417 if (!stdobjref.cPublicRefs && (mshlflags != MSHLFLAGS_TABLEWEAK))
419 IRemUnknown *remunk;
420 hr = proxy_manager_get_remunknown(This, &remunk);
421 if (hr == S_OK)
423 HRESULT hrref = S_OK;
424 REMINTERFACEREF rif;
425 rif.ipid = ifproxy->stdobjref.ipid;
426 rif.cPublicRefs = (mshlflags == MSHLFLAGS_TABLESTRONG) ? 1 : NORMALEXTREFS;
427 rif.cPrivateRefs = 0;
428 hr = IRemUnknown_RemAddRef(remunk, 1, &rif, &hrref);
429 IRemUnknown_Release(remunk);
430 if (hr == S_OK && hrref == S_OK)
432 /* table-strong marshaling doesn't give the refs to the
433 * client that unmarshals the STDOBJREF */
434 if (mshlflags != MSHLFLAGS_TABLESTRONG)
435 stdobjref.cPublicRefs = rif.cPublicRefs;
437 else
438 ERR("IRemUnknown_RemAddRef returned with 0x%08x, hrref = 0x%08x\n", hr, hrref);
442 if (SUCCEEDED(hr))
444 TRACE("writing stdobjref: flags = %04x cPublicRefs = %d oxid = %s oid = %s ipid = %s\n",
445 stdobjref.flags, stdobjref.cPublicRefs,
446 wine_dbgstr_longlong(stdobjref.oxid),
447 wine_dbgstr_longlong(stdobjref.oid),
448 debugstr_guid(&stdobjref.ipid));
449 hr = IStream_Write(pStm, &stdobjref, sizeof(stdobjref), NULL);
452 else
454 /* we don't have the interface already unmarshaled so we have to
455 * request the object from the server */
456 IRemUnknown *remunk;
457 IPID *ipid;
458 REMQIRESULT *qiresults = NULL;
459 IID iid = *riid;
461 /* get the ipid of the first entry */
462 /* FIXME: should we implement ClientIdentity on the ifproxies instead
463 * of the proxy_manager so we use the correct ipid here? */
464 ipid = &LIST_ENTRY(list_head(&This->interfaces), struct ifproxy, entry)->stdobjref.ipid;
466 /* get IRemUnknown proxy so we can communicate with the remote object */
467 hr = proxy_manager_get_remunknown(This, &remunk);
469 if (hr == S_OK)
471 hr = IRemUnknown_RemQueryInterface(remunk, ipid, NORMALEXTREFS,
472 1, &iid, &qiresults);
473 if (SUCCEEDED(hr))
475 hr = IStream_Write(pStm, &qiresults->std, sizeof(qiresults->std), NULL);
476 if (FAILED(hr))
478 REMINTERFACEREF rif;
479 rif.ipid = qiresults->std.ipid;
480 rif.cPublicRefs = qiresults->std.cPublicRefs;
481 rif.cPrivateRefs = 0;
482 IRemUnknown_RemRelease(remunk, 1, &rif);
484 CoTaskMemFree(qiresults);
486 else
487 ERR("IRemUnknown_RemQueryInterface failed with error 0x%08x\n", hr);
488 IRemUnknown_Release(remunk);
492 return hr;
495 static const IMarshalVtbl ProxyMarshal_Vtbl =
497 Proxy_QueryInterface,
498 Proxy_AddRef,
499 Proxy_Release,
500 StdMarshalImpl_GetUnmarshalClass,
501 StdMarshalImpl_GetMarshalSizeMax,
502 Proxy_MarshalInterface,
503 StdMarshalImpl_UnmarshalInterface,
504 StdMarshalImpl_ReleaseMarshalData,
505 StdMarshalImpl_DisconnectObject
508 static HRESULT WINAPI ProxyCliSec_QueryInterface(IClientSecurity *iface, REFIID riid, void **ppvObject)
510 struct proxy_manager *This = impl_from_IClientSecurity( iface );
511 return IMultiQI_QueryInterface(&This->IMultiQI_iface, riid, ppvObject);
514 static ULONG WINAPI ProxyCliSec_AddRef(IClientSecurity *iface)
516 struct proxy_manager *This = impl_from_IClientSecurity( iface );
517 return IMultiQI_AddRef(&This->IMultiQI_iface);
520 static ULONG WINAPI ProxyCliSec_Release(IClientSecurity *iface)
522 struct proxy_manager *This = impl_from_IClientSecurity( iface );
523 return IMultiQI_Release(&This->IMultiQI_iface);
526 static HRESULT WINAPI ProxyCliSec_QueryBlanket(IClientSecurity *iface,
527 IUnknown *pProxy,
528 DWORD *pAuthnSvc,
529 DWORD *pAuthzSvc,
530 OLECHAR **ppServerPrincName,
531 DWORD *pAuthnLevel,
532 DWORD *pImpLevel,
533 void **pAuthInfo,
534 DWORD *pCapabilities)
536 FIXME("(%p, %p, %p, %p, %p, %p, %p, %p): stub\n", pProxy, pAuthnSvc,
537 pAuthzSvc, ppServerPrincName, pAuthnLevel, pImpLevel, pAuthInfo,
538 pCapabilities);
540 if (pAuthnSvc)
541 *pAuthnSvc = 0;
542 if (pAuthzSvc)
543 *pAuthzSvc = 0;
544 if (ppServerPrincName)
545 *ppServerPrincName = NULL;
546 if (pAuthnLevel)
547 *pAuthnLevel = RPC_C_AUTHN_LEVEL_DEFAULT;
548 if (pImpLevel)
549 *pImpLevel = RPC_C_IMP_LEVEL_DEFAULT;
550 if (pAuthInfo)
551 *pAuthInfo = NULL;
552 if (pCapabilities)
553 *pCapabilities = EOAC_NONE;
555 return E_NOTIMPL;
558 static HRESULT WINAPI ProxyCliSec_SetBlanket(IClientSecurity *iface,
559 IUnknown *pProxy, DWORD AuthnSvc,
560 DWORD AuthzSvc,
561 OLECHAR *pServerPrincName,
562 DWORD AuthnLevel, DWORD ImpLevel,
563 void *pAuthInfo,
564 DWORD Capabilities)
566 FIXME("(%p, %d, %d, %s, %d, %d, %p, 0x%x): stub\n", pProxy, AuthnSvc, AuthzSvc,
567 pServerPrincName == COLE_DEFAULT_PRINCIPAL ? "<default principal>" : debugstr_w(pServerPrincName),
568 AuthnLevel, ImpLevel, pAuthInfo, Capabilities);
569 return E_NOTIMPL;
572 static HRESULT WINAPI ProxyCliSec_CopyProxy(IClientSecurity *iface,
573 IUnknown *pProxy, IUnknown **ppCopy)
575 FIXME("(%p, %p): stub\n", pProxy, ppCopy);
576 *ppCopy = NULL;
577 return E_NOTIMPL;
580 static const IClientSecurityVtbl ProxyCliSec_Vtbl =
582 ProxyCliSec_QueryInterface,
583 ProxyCliSec_AddRef,
584 ProxyCliSec_Release,
585 ProxyCliSec_QueryBlanket,
586 ProxyCliSec_SetBlanket,
587 ProxyCliSec_CopyProxy
590 static HRESULT ifproxy_get_public_ref(struct ifproxy * This)
592 HRESULT hr = S_OK;
594 if (WAIT_OBJECT_0 != WaitForSingleObject(This->parent->remoting_mutex, INFINITE))
596 ERR("Wait failed for ifproxy %p\n", This);
597 return E_UNEXPECTED;
600 if (This->refs == 0)
602 IRemUnknown *remunk = NULL;
604 TRACE("getting public ref for ifproxy %p\n", This);
606 hr = proxy_manager_get_remunknown(This->parent, &remunk);
607 if (hr == S_OK)
609 HRESULT hrref = S_OK;
610 REMINTERFACEREF rif;
611 rif.ipid = This->stdobjref.ipid;
612 rif.cPublicRefs = NORMALEXTREFS;
613 rif.cPrivateRefs = 0;
614 hr = IRemUnknown_RemAddRef(remunk, 1, &rif, &hrref);
615 IRemUnknown_Release(remunk);
616 if (hr == S_OK && hrref == S_OK)
617 InterlockedExchangeAdd((LONG *)&This->refs, NORMALEXTREFS);
618 else
619 ERR("IRemUnknown_RemAddRef returned with 0x%08x, hrref = 0x%08x\n", hr, hrref);
622 ReleaseMutex(This->parent->remoting_mutex);
624 return hr;
627 static HRESULT ifproxy_release_public_refs(struct ifproxy * This)
629 HRESULT hr = S_OK;
630 LONG public_refs;
632 if (WAIT_OBJECT_0 != WaitForSingleObject(This->parent->remoting_mutex, INFINITE))
634 ERR("Wait failed for ifproxy %p\n", This);
635 return E_UNEXPECTED;
638 public_refs = This->refs;
639 if (public_refs > 0)
641 IRemUnknown *remunk = NULL;
643 TRACE("releasing %d refs\n", public_refs);
645 hr = proxy_manager_get_remunknown(This->parent, &remunk);
646 if (hr == S_OK)
648 REMINTERFACEREF rif;
649 rif.ipid = This->stdobjref.ipid;
650 rif.cPublicRefs = public_refs;
651 rif.cPrivateRefs = 0;
652 hr = IRemUnknown_RemRelease(remunk, 1, &rif);
653 IRemUnknown_Release(remunk);
654 if (hr == S_OK)
655 InterlockedExchangeAdd((LONG *)&This->refs, -public_refs);
656 else if (hr == RPC_E_DISCONNECTED)
657 WARN("couldn't release references because object was "
658 "disconnected: oxid = %s, oid = %s\n",
659 wine_dbgstr_longlong(This->parent->oxid),
660 wine_dbgstr_longlong(This->parent->oid));
661 else
662 ERR("IRemUnknown_RemRelease failed with error 0x%08x\n", hr);
665 ReleaseMutex(This->parent->remoting_mutex);
667 return hr;
670 /* should be called inside This->parent->cs critical section */
671 static void ifproxy_disconnect(struct ifproxy * This)
673 ifproxy_release_public_refs(This);
674 if (This->proxy) IRpcProxyBuffer_Disconnect(This->proxy);
676 IRpcChannelBuffer_Release(This->chan);
677 This->chan = NULL;
680 /* should be called in This->parent->cs critical section if it is an entry in parent's list */
681 static void ifproxy_destroy(struct ifproxy * This)
683 TRACE("%p\n", This);
685 /* release public references to this object so that the stub can know
686 * when to destroy itself */
687 ifproxy_release_public_refs(This);
689 list_remove(&This->entry);
691 if (This->chan)
693 IRpcChannelBuffer_Release(This->chan);
694 This->chan = NULL;
697 if (This->proxy) IRpcProxyBuffer_Release(This->proxy);
699 HeapFree(GetProcessHeap(), 0, This);
702 static HRESULT proxy_manager_construct(
703 APARTMENT * apt, ULONG sorflags, OXID oxid, OID oid,
704 const OXID_INFO *oxid_info, struct proxy_manager ** proxy_manager)
706 struct proxy_manager * This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
707 if (!This) return E_OUTOFMEMORY;
709 This->remoting_mutex = CreateMutexW(NULL, FALSE, NULL);
710 if (!This->remoting_mutex)
712 HeapFree(GetProcessHeap(), 0, This);
713 return HRESULT_FROM_WIN32(GetLastError());
716 if (oxid_info)
718 This->oxid_info.dwPid = oxid_info->dwPid;
719 This->oxid_info.dwTid = oxid_info->dwTid;
720 This->oxid_info.ipidRemUnknown = oxid_info->ipidRemUnknown;
721 This->oxid_info.dwAuthnHint = oxid_info->dwAuthnHint;
722 This->oxid_info.psa = NULL /* FIXME: copy from oxid_info */;
724 else
726 HRESULT hr = RPC_ResolveOxid(oxid, &This->oxid_info);
727 if (FAILED(hr))
729 CloseHandle(This->remoting_mutex);
730 HeapFree(GetProcessHeap(), 0, This);
731 return hr;
735 This->IMultiQI_iface.lpVtbl = &ClientIdentity_Vtbl;
736 This->IMarshal_iface.lpVtbl = &ProxyMarshal_Vtbl;
737 This->IClientSecurity_iface.lpVtbl = &ProxyCliSec_Vtbl;
739 list_init(&This->entry);
740 list_init(&This->interfaces);
742 InitializeCriticalSection(&This->cs);
743 DEBUG_SET_CRITSEC_NAME(&This->cs, "proxy_manager");
745 /* the apartment the object was unmarshaled into */
746 This->parent = apt;
748 /* the source apartment and id of the object */
749 This->oxid = oxid;
750 This->oid = oid;
752 This->refs = 1;
754 /* the DCOM draft specification states that the SORF_NOPING flag is
755 * proxy manager specific, not ifproxy specific, so this implies that we
756 * should store the STDOBJREF flags here in the proxy manager. */
757 This->sorflags = sorflags;
759 /* we create the IRemUnknown proxy on demand */
760 This->remunk = NULL;
762 /* initialise these values to the weakest values and they will be
763 * overwritten in proxy_manager_set_context */
764 This->dest_context = MSHCTX_INPROC;
765 This->dest_context_data = NULL;
767 EnterCriticalSection(&apt->cs);
768 /* FIXME: we are dependent on the ordering in here to make sure a proxy's
769 * IRemUnknown proxy doesn't get destroyed before the regual proxy does
770 * because we need the IRemUnknown proxy during the destruction of the
771 * regular proxy. Ideally, we should maintain a separate list for the
772 * IRemUnknown proxies that need late destruction */
773 list_add_tail(&apt->proxies, &This->entry);
774 LeaveCriticalSection(&apt->cs);
776 TRACE("%p created for OXID %s, OID %s\n", This,
777 wine_dbgstr_longlong(oxid), wine_dbgstr_longlong(oid));
779 *proxy_manager = This;
780 return S_OK;
783 static inline void proxy_manager_set_context(struct proxy_manager *This, MSHCTX dest_context, void *dest_context_data)
785 MSHCTX old_dest_context;
786 MSHCTX new_dest_context;
790 old_dest_context = This->dest_context;
791 new_dest_context = old_dest_context;
792 /* "stronger" values overwrite "weaker" values. stronger values are
793 * ones that disable more optimisations */
794 switch (old_dest_context)
796 case MSHCTX_INPROC:
797 new_dest_context = dest_context;
798 break;
799 case MSHCTX_CROSSCTX:
800 switch (dest_context)
802 case MSHCTX_INPROC:
803 break;
804 default:
805 new_dest_context = dest_context;
807 break;
808 case MSHCTX_LOCAL:
809 switch (dest_context)
811 case MSHCTX_INPROC:
812 case MSHCTX_CROSSCTX:
813 break;
814 default:
815 new_dest_context = dest_context;
817 break;
818 case MSHCTX_NOSHAREDMEM:
819 switch (dest_context)
821 case MSHCTX_DIFFERENTMACHINE:
822 new_dest_context = dest_context;
823 break;
824 default:
825 break;
827 break;
828 default:
829 break;
832 if (old_dest_context == new_dest_context) break;
834 new_dest_context = InterlockedCompareExchange((PLONG)&This->dest_context, new_dest_context, old_dest_context);
835 } while (new_dest_context != old_dest_context);
837 if (dest_context_data)
838 InterlockedExchangePointer(&This->dest_context_data, dest_context_data);
841 static HRESULT proxy_manager_query_local_interface(struct proxy_manager * This, REFIID riid, void ** ppv)
843 HRESULT hr;
844 struct ifproxy * ifproxy;
846 TRACE("%s\n", debugstr_guid(riid));
848 if (IsEqualIID(riid, &IID_IUnknown) ||
849 IsEqualIID(riid, &IID_IMultiQI))
851 *ppv = &This->IMultiQI_iface;
852 IMultiQI_AddRef(&This->IMultiQI_iface);
853 return S_OK;
855 if (IsEqualIID(riid, &IID_IMarshal))
857 *ppv = &This->IMarshal_iface;
858 IMarshal_AddRef(&This->IMarshal_iface);
859 return S_OK;
861 if (IsEqualIID(riid, &IID_IClientSecurity))
863 *ppv = &This->IClientSecurity_iface;
864 IClientSecurity_AddRef(&This->IClientSecurity_iface);
865 return S_OK;
868 hr = proxy_manager_find_ifproxy(This, riid, &ifproxy);
869 if (hr == S_OK)
871 *ppv = ifproxy->iface;
872 IUnknown_AddRef((IUnknown *)*ppv);
873 return S_OK;
876 *ppv = NULL;
877 return E_NOINTERFACE;
880 static HRESULT proxy_manager_create_ifproxy(
881 struct proxy_manager * This, const STDOBJREF *stdobjref, REFIID riid,
882 IRpcChannelBuffer * channel, struct ifproxy ** iif_out)
884 HRESULT hr;
885 IPSFactoryBuffer * psfb;
886 struct ifproxy * ifproxy = HeapAlloc(GetProcessHeap(), 0, sizeof(*ifproxy));
887 if (!ifproxy) return E_OUTOFMEMORY;
889 list_init(&ifproxy->entry);
891 ifproxy->parent = This;
892 ifproxy->stdobjref = *stdobjref;
893 ifproxy->iid = *riid;
894 ifproxy->refs = 0;
895 ifproxy->proxy = NULL;
897 assert(channel);
898 ifproxy->chan = channel; /* FIXME: we should take the binding strings and construct the channel in this function */
900 /* the IUnknown interface is special because it does not have a
901 * proxy associated with the ifproxy as we handle IUnknown ourselves */
902 if (IsEqualIID(riid, &IID_IUnknown))
904 ifproxy->iface = &This->IMultiQI_iface;
905 IMultiQI_AddRef(&This->IMultiQI_iface);
906 hr = S_OK;
908 else
910 hr = get_facbuf_for_iid(riid, &psfb);
911 if (hr == S_OK)
913 /* important note: the outer unknown is set to the proxy manager.
914 * This ensures the COM identity rules are not violated, by having a
915 * one-to-one mapping of objects on the proxy side to objects on the
916 * stub side, no matter which interface you view the object through */
917 hr = IPSFactoryBuffer_CreateProxy(psfb, (IUnknown*)&This->IMultiQI_iface, riid,
918 &ifproxy->proxy, &ifproxy->iface);
919 IPSFactoryBuffer_Release(psfb);
920 if (hr != S_OK)
921 ERR("Could not create proxy for interface %s, error 0x%08x\n",
922 debugstr_guid(riid), hr);
924 else
925 ERR("Could not get IPSFactoryBuffer for interface %s, error 0x%08x\n",
926 debugstr_guid(riid), hr);
928 if (hr == S_OK)
929 hr = IRpcProxyBuffer_Connect(ifproxy->proxy, ifproxy->chan);
932 if (hr == S_OK)
934 EnterCriticalSection(&This->cs);
935 list_add_tail(&This->interfaces, &ifproxy->entry);
936 LeaveCriticalSection(&This->cs);
938 *iif_out = ifproxy;
939 TRACE("ifproxy %p created for IPID %s, interface %s with %u public refs\n",
940 ifproxy, debugstr_guid(&stdobjref->ipid), debugstr_guid(riid), stdobjref->cPublicRefs);
942 else
943 ifproxy_destroy(ifproxy);
945 return hr;
948 static HRESULT proxy_manager_find_ifproxy(struct proxy_manager * This, REFIID riid, struct ifproxy ** ifproxy_found)
950 HRESULT hr = E_NOINTERFACE; /* assume not found */
951 struct list * cursor;
953 EnterCriticalSection(&This->cs);
954 LIST_FOR_EACH(cursor, &This->interfaces)
956 struct ifproxy * ifproxy = LIST_ENTRY(cursor, struct ifproxy, entry);
957 if (IsEqualIID(riid, &ifproxy->iid))
959 *ifproxy_found = ifproxy;
960 hr = S_OK;
961 break;
964 LeaveCriticalSection(&This->cs);
966 return hr;
969 static void proxy_manager_disconnect(struct proxy_manager * This)
971 struct list * cursor;
973 TRACE("oxid = %s, oid = %s\n", wine_dbgstr_longlong(This->oxid),
974 wine_dbgstr_longlong(This->oid));
976 EnterCriticalSection(&This->cs);
978 /* SORFP_NOLIFTIMEMGMT proxies (for IRemUnknown) shouldn't be
979 * disconnected - it won't do anything anyway, except cause
980 * problems for other objects that depend on this proxy always
981 * working */
982 if (!(This->sorflags & SORFP_NOLIFETIMEMGMT))
984 LIST_FOR_EACH(cursor, &This->interfaces)
986 struct ifproxy * ifproxy = LIST_ENTRY(cursor, struct ifproxy, entry);
987 ifproxy_disconnect(ifproxy);
991 /* apartment is being destroyed so don't keep a pointer around to it */
992 This->parent = NULL;
994 LeaveCriticalSection(&This->cs);
997 static HRESULT proxy_manager_get_remunknown(struct proxy_manager * This, IRemUnknown **remunk)
999 HRESULT hr = S_OK;
1000 struct apartment *apt;
1001 BOOL called_in_original_apt;
1003 /* we don't want to try and unmarshal or use IRemUnknown if we don't want
1004 * lifetime management */
1005 if (This->sorflags & SORFP_NOLIFETIMEMGMT)
1006 return S_FALSE;
1008 apt = COM_CurrentApt();
1009 if (!apt)
1010 return CO_E_NOTINITIALIZED;
1012 called_in_original_apt = This->parent && (This->parent->oxid == apt->oxid);
1014 EnterCriticalSection(&This->cs);
1015 /* only return the cached object if called from the original apartment.
1016 * in future, we might want to make the IRemUnknown proxy callable from any
1017 * apartment to avoid these checks */
1018 if (This->remunk && called_in_original_apt)
1020 /* already created - return existing object */
1021 *remunk = This->remunk;
1022 IRemUnknown_AddRef(*remunk);
1024 else if (!This->parent)
1026 /* disconnected - we can't create IRemUnknown */
1027 *remunk = NULL;
1028 hr = S_FALSE;
1030 else
1032 STDOBJREF stdobjref;
1033 /* Don't want IRemUnknown lifetime management as this is IRemUnknown!
1034 * We also don't care about whether or not the stub is still alive */
1035 stdobjref.flags = SORFP_NOLIFETIMEMGMT | SORF_NOPING;
1036 stdobjref.cPublicRefs = 1;
1037 /* oxid of destination object */
1038 stdobjref.oxid = This->oxid;
1039 /* FIXME: what should be used for the oid? The DCOM draft doesn't say */
1040 stdobjref.oid = (OID)-1;
1041 stdobjref.ipid = This->oxid_info.ipidRemUnknown;
1043 /* do the unmarshal */
1044 hr = unmarshal_object(&stdobjref, COM_CurrentApt(), This->dest_context,
1045 This->dest_context_data, &IID_IRemUnknown,
1046 &This->oxid_info, (void**)remunk);
1047 if (hr == S_OK && called_in_original_apt)
1049 This->remunk = *remunk;
1050 IRemUnknown_AddRef(This->remunk);
1053 LeaveCriticalSection(&This->cs);
1055 TRACE("got IRemUnknown* pointer %p, hr = 0x%08x\n", *remunk, hr);
1057 return hr;
1060 /* destroys a proxy manager, freeing the memory it used.
1061 * Note: this function should not be called from a list iteration in the
1062 * apartment, due to the fact that it removes itself from the apartment and
1063 * it could add a proxy to IRemUnknown into the apartment. */
1064 static void proxy_manager_destroy(struct proxy_manager * This)
1066 struct list * cursor;
1068 TRACE("oxid = %s, oid = %s\n", wine_dbgstr_longlong(This->oxid),
1069 wine_dbgstr_longlong(This->oid));
1071 if (This->parent)
1073 EnterCriticalSection(&This->parent->cs);
1075 /* remove ourself from the list of proxy objects in the apartment */
1076 LIST_FOR_EACH(cursor, &This->parent->proxies)
1078 if (cursor == &This->entry)
1080 list_remove(&This->entry);
1081 break;
1085 LeaveCriticalSection(&This->parent->cs);
1088 /* destroy all of the interface proxies */
1089 while ((cursor = list_head(&This->interfaces)))
1091 struct ifproxy * ifproxy = LIST_ENTRY(cursor, struct ifproxy, entry);
1092 ifproxy_destroy(ifproxy);
1095 if (This->remunk) IRemUnknown_Release(This->remunk);
1096 CoTaskMemFree(This->oxid_info.psa);
1098 DEBUG_CLEAR_CRITSEC_NAME(&This->cs);
1099 DeleteCriticalSection(&This->cs);
1101 CloseHandle(This->remoting_mutex);
1103 HeapFree(GetProcessHeap(), 0, This);
1106 /* finds the proxy manager corresponding to a given OXID and OID that has
1107 * been unmarshaled in the specified apartment. The caller must release the
1108 * reference to the proxy_manager when the object is no longer used. */
1109 static BOOL find_proxy_manager(APARTMENT * apt, OXID oxid, OID oid, struct proxy_manager ** proxy_found)
1111 BOOL found = FALSE;
1112 struct list * cursor;
1114 EnterCriticalSection(&apt->cs);
1115 LIST_FOR_EACH(cursor, &apt->proxies)
1117 struct proxy_manager * proxy = LIST_ENTRY(cursor, struct proxy_manager, entry);
1118 if ((oxid == proxy->oxid) && (oid == proxy->oid))
1120 /* be careful of a race with ClientIdentity_Release, which would
1121 * cause us to return a proxy which is in the process of being
1122 * destroyed */
1123 if (IMultiQI_AddRef(&proxy->IMultiQI_iface) != 0)
1125 *proxy_found = proxy;
1126 found = TRUE;
1127 break;
1131 LeaveCriticalSection(&apt->cs);
1132 return found;
1135 HRESULT apartment_disconnectproxies(struct apartment *apt)
1137 struct list * cursor;
1139 LIST_FOR_EACH(cursor, &apt->proxies)
1141 struct proxy_manager * proxy = LIST_ENTRY(cursor, struct proxy_manager, entry);
1142 proxy_manager_disconnect(proxy);
1145 return S_OK;
1148 /********************** StdMarshal implementation ****************************/
1149 typedef struct _StdMarshalImpl
1151 IMarshal IMarshal_iface;
1152 LONG ref;
1153 DWORD dest_context;
1154 void *dest_context_data;
1155 } StdMarshalImpl;
1157 static inline StdMarshalImpl *impl_from_StdMarshal(IMarshal *iface)
1159 return CONTAINING_RECORD(iface, StdMarshalImpl, IMarshal_iface);
1162 static HRESULT WINAPI
1163 StdMarshalImpl_QueryInterface(IMarshal *iface, REFIID riid, void **ppv)
1165 *ppv = NULL;
1166 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IMarshal, riid))
1168 *ppv = iface;
1169 IMarshal_AddRef(iface);
1170 return S_OK;
1172 FIXME("No interface for %s.\n", debugstr_guid(riid));
1173 return E_NOINTERFACE;
1176 static ULONG WINAPI
1177 StdMarshalImpl_AddRef(IMarshal *iface)
1179 StdMarshalImpl *This = impl_from_StdMarshal(iface);
1180 return InterlockedIncrement(&This->ref);
1183 static ULONG WINAPI
1184 StdMarshalImpl_Release(IMarshal *iface)
1186 StdMarshalImpl *This = impl_from_StdMarshal(iface);
1187 ULONG ref = InterlockedDecrement(&This->ref);
1189 if (!ref) HeapFree(GetProcessHeap(),0,This);
1190 return ref;
1193 static HRESULT WINAPI
1194 StdMarshalImpl_GetUnmarshalClass(
1195 IMarshal *iface, REFIID riid, void* pv, DWORD dwDestContext,
1196 void* pvDestContext, DWORD mshlflags, CLSID* pCid)
1198 *pCid = CLSID_DfMarshal;
1199 return S_OK;
1202 static HRESULT WINAPI
1203 StdMarshalImpl_GetMarshalSizeMax(
1204 IMarshal *iface, REFIID riid, void* pv, DWORD dwDestContext,
1205 void* pvDestContext, DWORD mshlflags, DWORD* pSize)
1207 *pSize = sizeof(STDOBJREF);
1208 return S_OK;
1211 static HRESULT WINAPI
1212 StdMarshalImpl_MarshalInterface(
1213 IMarshal *iface, IStream *pStm,REFIID riid, void* pv, DWORD dest_context,
1214 void* dest_context_data, DWORD mshlflags)
1216 STDOBJREF stdobjref;
1217 ULONG res;
1218 HRESULT hres;
1219 APARTMENT *apt = COM_CurrentApt();
1221 TRACE("(...,%s,...)\n", debugstr_guid(riid));
1223 if (!apt)
1225 ERR("Apartment not initialized\n");
1226 return CO_E_NOTINITIALIZED;
1229 /* make sure this apartment can be reached from other threads / processes */
1230 RPC_StartRemoting(apt);
1232 hres = marshal_object(apt, &stdobjref, riid, pv, dest_context, dest_context_data, mshlflags);
1233 if (hres != S_OK)
1235 ERR("Failed to create ifstub, hres=0x%x\n", hres);
1236 return hres;
1239 return IStream_Write(pStm, &stdobjref, sizeof(stdobjref), &res);
1242 /* helper for StdMarshalImpl_UnmarshalInterface - does the unmarshaling with
1243 * no questions asked about the rules surrounding same-apartment unmarshals
1244 * and table marshaling */
1245 static HRESULT unmarshal_object(const STDOBJREF *stdobjref, APARTMENT *apt,
1246 MSHCTX dest_context, void *dest_context_data,
1247 REFIID riid, const OXID_INFO *oxid_info,
1248 void **object)
1250 struct proxy_manager *proxy_manager = NULL;
1251 HRESULT hr = S_OK;
1253 assert(apt);
1255 TRACE("stdobjref: flags = %04x cPublicRefs = %d oxid = %s oid = %s ipid = %s\n",
1256 stdobjref->flags, stdobjref->cPublicRefs,
1257 wine_dbgstr_longlong(stdobjref->oxid),
1258 wine_dbgstr_longlong(stdobjref->oid),
1259 debugstr_guid(&stdobjref->ipid));
1261 /* create a new proxy manager if one doesn't already exist for the
1262 * object */
1263 if (!find_proxy_manager(apt, stdobjref->oxid, stdobjref->oid, &proxy_manager))
1265 hr = proxy_manager_construct(apt, stdobjref->flags,
1266 stdobjref->oxid, stdobjref->oid, oxid_info,
1267 &proxy_manager);
1269 else
1270 TRACE("proxy manager already created, using\n");
1272 if (hr == S_OK)
1274 struct ifproxy * ifproxy;
1276 proxy_manager_set_context(proxy_manager, dest_context, dest_context_data);
1278 hr = proxy_manager_find_ifproxy(proxy_manager, riid, &ifproxy);
1279 if (hr == E_NOINTERFACE)
1281 IRpcChannelBuffer *chanbuf;
1282 hr = RPC_CreateClientChannel(&stdobjref->oxid, &stdobjref->ipid,
1283 &proxy_manager->oxid_info,
1284 proxy_manager->dest_context,
1285 proxy_manager->dest_context_data,
1286 &chanbuf);
1287 if (hr == S_OK)
1288 hr = proxy_manager_create_ifproxy(proxy_manager, stdobjref,
1289 riid, chanbuf, &ifproxy);
1291 else
1292 IUnknown_AddRef((IUnknown *)ifproxy->iface);
1294 if (hr == S_OK)
1296 InterlockedExchangeAdd((LONG *)&ifproxy->refs, stdobjref->cPublicRefs);
1297 /* get at least one external reference to the object to keep it alive */
1298 hr = ifproxy_get_public_ref(ifproxy);
1299 if (FAILED(hr))
1300 ifproxy_destroy(ifproxy);
1303 if (hr == S_OK)
1304 *object = ifproxy->iface;
1307 /* release our reference to the proxy manager - the client/apartment
1308 * will hold on to the remaining reference for us */
1309 if (proxy_manager) IMultiQI_Release(&proxy_manager->IMultiQI_iface);
1311 return hr;
1314 static HRESULT WINAPI
1315 StdMarshalImpl_UnmarshalInterface(IMarshal *iface, IStream *pStm, REFIID riid, void **ppv)
1317 StdMarshalImpl *This = impl_from_StdMarshal(iface);
1318 struct stub_manager *stubmgr = NULL;
1319 STDOBJREF stdobjref;
1320 ULONG res;
1321 HRESULT hres;
1322 APARTMENT *apt = COM_CurrentApt();
1323 APARTMENT *stub_apt;
1324 OXID oxid;
1326 TRACE("(...,%s,....)\n", debugstr_guid(riid));
1328 /* we need an apartment to unmarshal into */
1329 if (!apt)
1331 ERR("Apartment not initialized\n");
1332 return CO_E_NOTINITIALIZED;
1335 /* read STDOBJREF from wire */
1336 hres = IStream_Read(pStm, &stdobjref, sizeof(stdobjref), &res);
1337 if (hres != S_OK) return STG_E_READFAULT;
1339 hres = apartment_getoxid(apt, &oxid);
1340 if (hres != S_OK) return hres;
1342 /* check if we're marshalling back to ourselves */
1343 if ((oxid == stdobjref.oxid) && (stubmgr = get_stub_manager(apt, stdobjref.oid)))
1345 TRACE("Unmarshalling object marshalled in same apartment for iid %s, "
1346 "returning original object %p\n", debugstr_guid(riid), stubmgr->object);
1348 hres = IUnknown_QueryInterface(stubmgr->object, riid, ppv);
1350 /* unref the ifstub. FIXME: only do this on success? */
1351 if (!stub_manager_is_table_marshaled(stubmgr, &stdobjref.ipid))
1352 stub_manager_ext_release(stubmgr, stdobjref.cPublicRefs, stdobjref.flags & SORFP_TABLEWEAK, FALSE);
1354 stub_manager_int_release(stubmgr);
1355 return hres;
1358 /* notify stub manager about unmarshal if process-local object.
1359 * note: if the oxid is not found then we and native will quite happily
1360 * ignore table marshaling and normal marshaling rules regarding number of
1361 * unmarshals, etc, but if you abuse these rules then your proxy could end
1362 * up returning RPC_E_DISCONNECTED. */
1363 if ((stub_apt = apartment_findfromoxid(stdobjref.oxid, TRUE)))
1365 if ((stubmgr = get_stub_manager(stub_apt, stdobjref.oid)))
1367 if (!stub_manager_notify_unmarshal(stubmgr, &stdobjref.ipid))
1368 hres = CO_E_OBJNOTCONNECTED;
1370 else
1372 WARN("Couldn't find object for OXID %s, OID %s, assuming disconnected\n",
1373 wine_dbgstr_longlong(stdobjref.oxid),
1374 wine_dbgstr_longlong(stdobjref.oid));
1375 hres = CO_E_OBJNOTCONNECTED;
1378 else
1379 TRACE("Treating unmarshal from OXID %s as inter-process\n",
1380 wine_dbgstr_longlong(stdobjref.oxid));
1382 if (hres == S_OK)
1383 hres = unmarshal_object(&stdobjref, apt, This->dest_context,
1384 This->dest_context_data, riid,
1385 stubmgr ? &stubmgr->oxid_info : NULL, ppv);
1387 if (stubmgr) stub_manager_int_release(stubmgr);
1388 if (stub_apt) apartment_release(stub_apt);
1390 if (hres != S_OK) WARN("Failed with error 0x%08x\n", hres);
1391 else TRACE("Successfully created proxy %p\n", *ppv);
1393 return hres;
1396 static HRESULT WINAPI
1397 StdMarshalImpl_ReleaseMarshalData(IMarshal *iface, IStream *pStm)
1399 STDOBJREF stdobjref;
1400 ULONG res;
1401 HRESULT hres;
1402 struct stub_manager *stubmgr;
1403 APARTMENT *apt;
1405 TRACE("iface=%p, pStm=%p\n", iface, pStm);
1407 hres = IStream_Read(pStm, &stdobjref, sizeof(stdobjref), &res);
1408 if (hres != S_OK) return STG_E_READFAULT;
1410 TRACE("oxid = %s, oid = %s, ipid = %s\n",
1411 wine_dbgstr_longlong(stdobjref.oxid),
1412 wine_dbgstr_longlong(stdobjref.oid),
1413 wine_dbgstr_guid(&stdobjref.ipid));
1415 if (!(apt = apartment_findfromoxid(stdobjref.oxid, TRUE)))
1417 WARN("Could not map OXID %s to apartment object\n",
1418 wine_dbgstr_longlong(stdobjref.oxid));
1419 return RPC_E_INVALID_OBJREF;
1422 if (!(stubmgr = get_stub_manager(apt, stdobjref.oid)))
1424 apartment_release(apt);
1425 ERR("could not map object ID to stub manager, oxid=%s, oid=%s\n",
1426 wine_dbgstr_longlong(stdobjref.oxid), wine_dbgstr_longlong(stdobjref.oid));
1427 return RPC_E_INVALID_OBJREF;
1430 stub_manager_release_marshal_data(stubmgr, stdobjref.cPublicRefs, &stdobjref.ipid, stdobjref.flags & SORFP_TABLEWEAK);
1432 stub_manager_int_release(stubmgr);
1433 apartment_release(apt);
1435 return S_OK;
1438 static HRESULT WINAPI
1439 StdMarshalImpl_DisconnectObject(IMarshal *iface, DWORD dwReserved)
1441 FIXME("(), stub!\n");
1442 return S_OK;
1445 static const IMarshalVtbl StdMarshalVtbl =
1447 StdMarshalImpl_QueryInterface,
1448 StdMarshalImpl_AddRef,
1449 StdMarshalImpl_Release,
1450 StdMarshalImpl_GetUnmarshalClass,
1451 StdMarshalImpl_GetMarshalSizeMax,
1452 StdMarshalImpl_MarshalInterface,
1453 StdMarshalImpl_UnmarshalInterface,
1454 StdMarshalImpl_ReleaseMarshalData,
1455 StdMarshalImpl_DisconnectObject
1458 static HRESULT StdMarshalImpl_Construct(REFIID riid, DWORD dest_context, void *dest_context_data, void** ppvObject)
1460 HRESULT hr;
1462 StdMarshalImpl *pStdMarshal = HeapAlloc(GetProcessHeap(), 0, sizeof(StdMarshalImpl));
1463 if (!pStdMarshal)
1464 return E_OUTOFMEMORY;
1466 pStdMarshal->IMarshal_iface.lpVtbl = &StdMarshalVtbl;
1467 pStdMarshal->ref = 0;
1468 pStdMarshal->dest_context = dest_context;
1469 pStdMarshal->dest_context_data = dest_context_data;
1471 hr = IMarshal_QueryInterface(&pStdMarshal->IMarshal_iface, riid, ppvObject);
1472 if (FAILED(hr))
1473 HeapFree(GetProcessHeap(), 0, pStdMarshal);
1475 return hr;
1478 /***********************************************************************
1479 * CoGetStandardMarshal [OLE32.@]
1481 * Gets or creates a standard marshal object.
1483 * PARAMS
1484 * riid [I] Interface identifier of the pUnk object.
1485 * pUnk [I] Optional. Object to get the marshal object for.
1486 * dwDestContext [I] Destination. Used to enable or disable optimizations.
1487 * pvDestContext [I] Reserved. Must be NULL.
1488 * mshlflags [I] Flags affecting the marshaling process.
1489 * ppMarshal [O] Address where marshal object will be stored.
1491 * RETURNS
1492 * Success: S_OK.
1493 * Failure: HRESULT code.
1495 * NOTES
1497 * The function retrieves the IMarshal object associated with an object if
1498 * that object is currently an active stub, otherwise a new marshal object is
1499 * created.
1501 HRESULT WINAPI CoGetStandardMarshal(REFIID riid, IUnknown *pUnk,
1502 DWORD dwDestContext, LPVOID pvDestContext,
1503 DWORD mshlflags, LPMARSHAL *ppMarshal)
1505 if (pUnk == NULL)
1507 FIXME("(%s,NULL,%x,%p,%x,%p), unimplemented yet.\n",
1508 debugstr_guid(riid),dwDestContext,pvDestContext,mshlflags,ppMarshal);
1509 return E_NOTIMPL;
1511 TRACE("(%s,%p,%x,%p,%x,%p)\n",
1512 debugstr_guid(riid),pUnk,dwDestContext,pvDestContext,mshlflags,ppMarshal);
1514 return StdMarshalImpl_Construct(&IID_IMarshal, dwDestContext, pvDestContext, (void**)ppMarshal);
1517 /***********************************************************************
1518 * get_marshaler [internal]
1520 * Retrieves an IMarshal interface for an object.
1522 static HRESULT get_marshaler(REFIID riid, IUnknown *pUnk, DWORD dwDestContext,
1523 void *pvDestContext, DWORD mshlFlags,
1524 LPMARSHAL *pMarshal)
1526 HRESULT hr;
1528 if (!pUnk)
1529 return E_POINTER;
1530 hr = IUnknown_QueryInterface(pUnk, &IID_IMarshal, (LPVOID*)pMarshal);
1531 if (hr != S_OK)
1532 hr = CoGetStandardMarshal(riid, pUnk, dwDestContext, pvDestContext,
1533 mshlFlags, pMarshal);
1534 return hr;
1537 /***********************************************************************
1538 * get_unmarshaler_from_stream [internal]
1540 * Creates an IMarshal* object according to the data marshaled to the stream.
1541 * The function leaves the stream pointer at the start of the data written
1542 * to the stream by the IMarshal* object.
1544 static HRESULT get_unmarshaler_from_stream(IStream *stream, IMarshal **marshal, IID *iid)
1546 HRESULT hr;
1547 ULONG res;
1548 OBJREF objref;
1550 /* read common OBJREF header */
1551 hr = IStream_Read(stream, &objref, FIELD_OFFSET(OBJREF, u_objref), &res);
1552 if (hr != S_OK || (res != FIELD_OFFSET(OBJREF, u_objref)))
1554 ERR("Failed to read common OBJREF header, 0x%08x\n", hr);
1555 return STG_E_READFAULT;
1558 /* sanity check on header */
1559 if (objref.signature != OBJREF_SIGNATURE)
1561 ERR("Bad OBJREF signature 0x%08x\n", objref.signature);
1562 return RPC_E_INVALID_OBJREF;
1565 if (iid) *iid = objref.iid;
1567 /* FIXME: handler marshaling */
1568 if (objref.flags & OBJREF_STANDARD)
1570 TRACE("Using standard unmarshaling\n");
1571 hr = StdMarshalImpl_Construct(&IID_IMarshal, 0, NULL, (LPVOID*)marshal);
1573 else if (objref.flags & OBJREF_CUSTOM)
1575 ULONG custom_header_size = FIELD_OFFSET(OBJREF, u_objref.u_custom.pData) -
1576 FIELD_OFFSET(OBJREF, u_objref.u_custom);
1577 TRACE("Using custom unmarshaling\n");
1578 /* read constant sized OR_CUSTOM data from stream */
1579 hr = IStream_Read(stream, &objref.u_objref.u_custom,
1580 custom_header_size, &res);
1581 if (hr != S_OK || (res != custom_header_size))
1583 ERR("Failed to read OR_CUSTOM header, 0x%08x\n", hr);
1584 return STG_E_READFAULT;
1586 /* now create the marshaler specified in the stream */
1587 hr = CoCreateInstance(&objref.u_objref.u_custom.clsid, NULL,
1588 CLSCTX_INPROC_SERVER, &IID_IMarshal,
1589 (LPVOID*)marshal);
1591 else
1593 FIXME("Invalid or unimplemented marshaling type specified: %x\n",
1594 objref.flags);
1595 return RPC_E_INVALID_OBJREF;
1598 if (hr != S_OK)
1599 ERR("Failed to create marshal, 0x%08x\n", hr);
1601 return hr;
1604 /***********************************************************************
1605 * CoGetMarshalSizeMax [OLE32.@]
1607 * Gets the maximum amount of data that will be needed by a marshal.
1609 * PARAMS
1610 * pulSize [O] Address where maximum marshal size will be stored.
1611 * riid [I] Identifier of the interface to marshal.
1612 * pUnk [I] Pointer to the object to marshal.
1613 * dwDestContext [I] Destination. Used to enable or disable optimizations.
1614 * pvDestContext [I] Reserved. Must be NULL.
1615 * mshlFlags [I] Flags that affect the marshaling. See CoMarshalInterface().
1617 * RETURNS
1618 * Success: S_OK.
1619 * Failure: HRESULT code.
1621 * SEE ALSO
1622 * CoMarshalInterface().
1624 HRESULT WINAPI CoGetMarshalSizeMax(ULONG *pulSize, REFIID riid, IUnknown *pUnk,
1625 DWORD dwDestContext, void *pvDestContext,
1626 DWORD mshlFlags)
1628 HRESULT hr;
1629 LPMARSHAL pMarshal;
1630 CLSID marshaler_clsid;
1632 hr = get_marshaler(riid, pUnk, dwDestContext, pvDestContext, mshlFlags, &pMarshal);
1633 if (hr != S_OK)
1634 return hr;
1636 hr = IMarshal_GetUnmarshalClass(pMarshal, riid, pUnk, dwDestContext,
1637 pvDestContext, mshlFlags, &marshaler_clsid);
1638 if (hr != S_OK)
1640 ERR("IMarshal::GetUnmarshalClass failed, 0x%08x\n", hr);
1641 IMarshal_Release(pMarshal);
1642 return hr;
1645 hr = IMarshal_GetMarshalSizeMax(pMarshal, riid, pUnk, dwDestContext,
1646 pvDestContext, mshlFlags, pulSize);
1647 if (IsEqualCLSID(&marshaler_clsid, &CLSID_DfMarshal))
1648 /* add on the size of the common header */
1649 *pulSize += FIELD_OFFSET(OBJREF, u_objref);
1650 else
1651 /* custom marshaling: add on the size of the whole OBJREF structure
1652 * like native does */
1653 *pulSize += sizeof(OBJREF);
1655 IMarshal_Release(pMarshal);
1656 return hr;
1660 static void dump_MSHLFLAGS(MSHLFLAGS flags)
1662 if (flags & MSHLFLAGS_TABLESTRONG)
1663 TRACE(" MSHLFLAGS_TABLESTRONG");
1664 if (flags & MSHLFLAGS_TABLEWEAK)
1665 TRACE(" MSHLFLAGS_TABLEWEAK");
1666 if (!(flags & (MSHLFLAGS_TABLESTRONG|MSHLFLAGS_TABLEWEAK)))
1667 TRACE(" MSHLFLAGS_NORMAL");
1668 if (flags & MSHLFLAGS_NOPING)
1669 TRACE(" MSHLFLAGS_NOPING");
1672 /***********************************************************************
1673 * CoMarshalInterface [OLE32.@]
1675 * Marshals an interface into a stream so that the object can then be
1676 * unmarshaled from another COM apartment and used remotely.
1678 * PARAMS
1679 * pStream [I] Stream the object will be marshaled into.
1680 * riid [I] Identifier of the interface to marshal.
1681 * pUnk [I] Pointer to the object to marshal.
1682 * dwDestContext [I] Destination. Used to enable or disable optimizations.
1683 * pvDestContext [I] Reserved. Must be NULL.
1684 * mshlFlags [I] Flags that affect the marshaling. See notes.
1686 * RETURNS
1687 * Success: S_OK.
1688 * Failure: HRESULT code.
1690 * NOTES
1692 * The mshlFlags parameter can take one or more of the following flags:
1693 *| MSHLFLAGS_NORMAL - Unmarshal once, releases stub on last proxy release.
1694 *| MSHLFLAGS_TABLESTRONG - Unmarshal many, release when CoReleaseMarshalData() called.
1695 *| MSHLFLAGS_TABLEWEAK - Unmarshal many, releases stub on last proxy release.
1696 *| MSHLFLAGS_NOPING - No automatic garbage collection (and so reduces network traffic).
1698 * If a marshaled object is not unmarshaled, then CoReleaseMarshalData() must
1699 * be called in order to release the resources used in the marshaling.
1701 * SEE ALSO
1702 * CoUnmarshalInterface(), CoReleaseMarshalData().
1704 HRESULT WINAPI CoMarshalInterface(IStream *pStream, REFIID riid, IUnknown *pUnk,
1705 DWORD dwDestContext, void *pvDestContext,
1706 DWORD mshlFlags)
1708 HRESULT hr;
1709 CLSID marshaler_clsid;
1710 OBJREF objref;
1711 LPMARSHAL pMarshal;
1713 TRACE("(%p, %s, %p, %x, %p, ", pStream, debugstr_guid(riid), pUnk,
1714 dwDestContext, pvDestContext);
1715 dump_MSHLFLAGS(mshlFlags);
1716 TRACE(")\n");
1718 if (!pUnk || !pStream)
1719 return E_INVALIDARG;
1721 objref.signature = OBJREF_SIGNATURE;
1722 objref.iid = *riid;
1724 /* get the marshaler for the specified interface */
1725 hr = get_marshaler(riid, pUnk, dwDestContext, pvDestContext, mshlFlags, &pMarshal);
1726 if (hr != S_OK)
1728 ERR("Failed to get marshaller, 0x%08x\n", hr);
1729 return hr;
1732 hr = IMarshal_GetUnmarshalClass(pMarshal, riid, pUnk, dwDestContext,
1733 pvDestContext, mshlFlags, &marshaler_clsid);
1734 if (hr != S_OK)
1736 ERR("IMarshal::GetUnmarshalClass failed, 0x%08x\n", hr);
1737 goto cleanup;
1740 /* FIXME: implement handler marshaling too */
1741 if (IsEqualCLSID(&marshaler_clsid, &CLSID_DfMarshal))
1743 TRACE("Using standard marshaling\n");
1744 objref.flags = OBJREF_STANDARD;
1746 /* write the common OBJREF header to the stream */
1747 hr = IStream_Write(pStream, &objref, FIELD_OFFSET(OBJREF, u_objref), NULL);
1748 if (hr != S_OK)
1750 ERR("Failed to write OBJREF header to stream, 0x%08x\n", hr);
1751 goto cleanup;
1754 else
1756 TRACE("Using custom marshaling\n");
1757 objref.flags = OBJREF_CUSTOM;
1758 objref.u_objref.u_custom.clsid = marshaler_clsid;
1759 objref.u_objref.u_custom.cbExtension = 0;
1760 objref.u_objref.u_custom.size = 0;
1761 hr = IMarshal_GetMarshalSizeMax(pMarshal, riid, pUnk, dwDestContext,
1762 pvDestContext, mshlFlags,
1763 &objref.u_objref.u_custom.size);
1764 if (hr != S_OK)
1766 ERR("Failed to get max size of marshal data, error 0x%08x\n", hr);
1767 goto cleanup;
1769 /* write constant sized common header and OR_CUSTOM data into stream */
1770 hr = IStream_Write(pStream, &objref,
1771 FIELD_OFFSET(OBJREF, u_objref.u_custom.pData), NULL);
1772 if (hr != S_OK)
1774 ERR("Failed to write OR_CUSTOM header to stream with 0x%08x\n", hr);
1775 goto cleanup;
1779 TRACE("Calling IMarshal::MarshalInterface\n");
1780 /* call helper object to do the actual marshaling */
1781 hr = IMarshal_MarshalInterface(pMarshal, pStream, riid, pUnk, dwDestContext,
1782 pvDestContext, mshlFlags);
1784 if (hr != S_OK)
1786 ERR("Failed to marshal the interface %s, %x\n", debugstr_guid(riid), hr);
1787 goto cleanup;
1790 cleanup:
1791 IMarshal_Release(pMarshal);
1793 TRACE("completed with hr 0x%08x\n", hr);
1795 return hr;
1798 /***********************************************************************
1799 * CoUnmarshalInterface [OLE32.@]
1801 * Unmarshals an object from a stream by creating a proxy to the remote
1802 * object, if necessary.
1804 * PARAMS
1806 * pStream [I] Stream containing the marshaled object.
1807 * riid [I] Interface identifier of the object to create a proxy to.
1808 * ppv [O] Address where proxy will be stored.
1810 * RETURNS
1812 * Success: S_OK.
1813 * Failure: HRESULT code.
1815 * SEE ALSO
1816 * CoMarshalInterface().
1818 HRESULT WINAPI CoUnmarshalInterface(IStream *pStream, REFIID riid, LPVOID *ppv)
1820 HRESULT hr;
1821 LPMARSHAL pMarshal;
1822 IID iid;
1823 IUnknown *object;
1825 TRACE("(%p, %s, %p)\n", pStream, debugstr_guid(riid), ppv);
1827 if (!pStream || !ppv)
1828 return E_INVALIDARG;
1830 hr = get_unmarshaler_from_stream(pStream, &pMarshal, &iid);
1831 if (hr != S_OK)
1832 return hr;
1834 /* call the helper object to do the actual unmarshaling */
1835 hr = IMarshal_UnmarshalInterface(pMarshal, pStream, &iid, (LPVOID*)&object);
1836 if (hr != S_OK)
1837 ERR("IMarshal::UnmarshalInterface failed, 0x%08x\n", hr);
1839 if (hr == S_OK)
1841 /* IID_NULL means use the interface ID of the marshaled object */
1842 if (!IsEqualIID(riid, &IID_NULL) && !IsEqualIID(riid, &iid))
1844 TRACE("requested interface != marshalled interface, additional QI needed\n");
1845 hr = IUnknown_QueryInterface(object, riid, ppv);
1846 if (hr != S_OK)
1847 ERR("Couldn't query for interface %s, hr = 0x%08x\n",
1848 debugstr_guid(riid), hr);
1849 IUnknown_Release(object);
1851 else
1853 *ppv = object;
1857 IMarshal_Release(pMarshal);
1859 TRACE("completed with hr 0x%x\n", hr);
1861 return hr;
1864 /***********************************************************************
1865 * CoReleaseMarshalData [OLE32.@]
1867 * Releases resources associated with an object that has been marshaled into
1868 * a stream.
1870 * PARAMS
1872 * pStream [I] The stream that the object has been marshaled into.
1874 * RETURNS
1875 * Success: S_OK.
1876 * Failure: HRESULT error code.
1878 * NOTES
1880 * Call this function to release resources associated with a normal or
1881 * table-weak marshal that will not be unmarshaled, and all table-strong
1882 * marshals when they are no longer needed.
1884 * SEE ALSO
1885 * CoMarshalInterface(), CoUnmarshalInterface().
1887 HRESULT WINAPI CoReleaseMarshalData(IStream *pStream)
1889 HRESULT hr;
1890 LPMARSHAL pMarshal;
1892 TRACE("(%p)\n", pStream);
1894 hr = get_unmarshaler_from_stream(pStream, &pMarshal, NULL);
1895 if (hr != S_OK)
1896 return hr;
1898 /* call the helper object to do the releasing of marshal data */
1899 hr = IMarshal_ReleaseMarshalData(pMarshal, pStream);
1900 if (hr != S_OK)
1901 ERR("IMarshal::ReleaseMarshalData failed with error 0x%08x\n", hr);
1903 IMarshal_Release(pMarshal);
1904 return hr;
1908 /***********************************************************************
1909 * CoMarshalInterThreadInterfaceInStream [OLE32.@]
1911 * Marshal an interface across threads in the same process.
1913 * PARAMS
1914 * riid [I] Identifier of the interface to be marshalled.
1915 * pUnk [I] Pointer to IUnknown-derived interface that will be marshalled.
1916 * ppStm [O] Pointer to IStream object that is created and then used to store the marshalled interface.
1918 * RETURNS
1919 * Success: S_OK
1920 * Failure: E_OUTOFMEMORY and other COM error codes
1922 * SEE ALSO
1923 * CoMarshalInterface(), CoUnmarshalInterface() and CoGetInterfaceAndReleaseStream()
1925 HRESULT WINAPI CoMarshalInterThreadInterfaceInStream(
1926 REFIID riid, LPUNKNOWN pUnk, LPSTREAM * ppStm)
1928 ULARGE_INTEGER xpos;
1929 LARGE_INTEGER seekto;
1930 HRESULT hres;
1932 TRACE("(%s, %p, %p)\n",debugstr_guid(riid), pUnk, ppStm);
1934 hres = CreateStreamOnHGlobal(NULL, TRUE, ppStm);
1935 if (FAILED(hres)) return hres;
1936 hres = CoMarshalInterface(*ppStm, riid, pUnk, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1938 if (SUCCEEDED(hres))
1940 memset(&seekto, 0, sizeof(seekto));
1941 IStream_Seek(*ppStm, seekto, STREAM_SEEK_SET, &xpos);
1943 else
1945 IStream_Release(*ppStm);
1946 *ppStm = NULL;
1949 return hres;
1952 /***********************************************************************
1953 * CoGetInterfaceAndReleaseStream [OLE32.@]
1955 * Unmarshalls an interface from a stream and then releases the stream.
1957 * PARAMS
1958 * pStm [I] Stream that contains the marshalled interface.
1959 * riid [I] Interface identifier of the object to unmarshall.
1960 * ppv [O] Address of pointer where the requested interface object will be stored.
1962 * RETURNS
1963 * Success: S_OK
1964 * Failure: A COM error code
1966 * SEE ALSO
1967 * CoMarshalInterThreadInterfaceInStream() and CoUnmarshalInterface()
1969 HRESULT WINAPI CoGetInterfaceAndReleaseStream(LPSTREAM pStm, REFIID riid,
1970 LPVOID *ppv)
1972 HRESULT hres;
1974 TRACE("(%p, %s, %p)\n", pStm, debugstr_guid(riid), ppv);
1976 if(!pStm) return E_INVALIDARG;
1977 hres = CoUnmarshalInterface(pStm, riid, ppv);
1978 IStream_Release(pStm);
1979 return hres;
1982 static HRESULT WINAPI StdMarshalCF_QueryInterface(LPCLASSFACTORY iface,
1983 REFIID riid, LPVOID *ppv)
1985 *ppv = NULL;
1986 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IClassFactory))
1988 *ppv = iface;
1989 return S_OK;
1991 return E_NOINTERFACE;
1994 static ULONG WINAPI StdMarshalCF_AddRef(LPCLASSFACTORY iface)
1996 return 2; /* non-heap based object */
1999 static ULONG WINAPI StdMarshalCF_Release(LPCLASSFACTORY iface)
2001 return 1; /* non-heap based object */
2004 static HRESULT WINAPI StdMarshalCF_CreateInstance(LPCLASSFACTORY iface,
2005 LPUNKNOWN pUnk, REFIID riid, LPVOID *ppv)
2007 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IMarshal))
2008 return StdMarshalImpl_Construct(riid, 0, NULL, ppv);
2010 FIXME("(%s), not supported.\n",debugstr_guid(riid));
2011 return E_NOINTERFACE;
2014 static HRESULT WINAPI StdMarshalCF_LockServer(LPCLASSFACTORY iface, BOOL fLock)
2016 FIXME("(%d), stub!\n",fLock);
2017 return S_OK;
2020 static const IClassFactoryVtbl StdMarshalCFVtbl =
2022 StdMarshalCF_QueryInterface,
2023 StdMarshalCF_AddRef,
2024 StdMarshalCF_Release,
2025 StdMarshalCF_CreateInstance,
2026 StdMarshalCF_LockServer
2028 static const IClassFactoryVtbl *StdMarshalCF = &StdMarshalCFVtbl;
2030 HRESULT MARSHAL_GetStandardMarshalCF(LPVOID *ppv)
2032 *ppv = &StdMarshalCF;
2033 return S_OK;
2036 /***********************************************************************
2037 * CoMarshalHresult [OLE32.@]
2039 * Marshals an HRESULT value into a stream.
2041 * PARAMS
2042 * pStm [I] Stream that hresult will be marshalled into.
2043 * hresult [I] HRESULT to be marshalled.
2045 * RETURNS
2046 * Success: S_OK
2047 * Failure: A COM error code
2049 * SEE ALSO
2050 * CoUnmarshalHresult().
2052 HRESULT WINAPI CoMarshalHresult(LPSTREAM pStm, HRESULT hresult)
2054 return IStream_Write(pStm, &hresult, sizeof(hresult), NULL);
2057 /***********************************************************************
2058 * CoUnmarshalHresult [OLE32.@]
2060 * Unmarshals an HRESULT value from a stream.
2062 * PARAMS
2063 * pStm [I] Stream that hresult will be unmarshalled from.
2064 * phresult [I] Pointer to HRESULT where the value will be unmarshalled to.
2066 * RETURNS
2067 * Success: S_OK
2068 * Failure: A COM error code
2070 * SEE ALSO
2071 * CoMarshalHresult().
2073 HRESULT WINAPI CoUnmarshalHresult(LPSTREAM pStm, HRESULT * phresult)
2075 return IStream_Read(pStm, phresult, sizeof(*phresult), NULL);