ole32: Intialise some out parameters in ProxyCliSec_QueryBlanket.
[wine/wine64.git] / dlls / ole32 / marshal.c
blobfcfbd648a31810b67982c93d1c834f5ef73e0137
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
48 /* private flag indicating that the caller does not want to notify the stub
49 * when the proxy disconnects or is destroyed */
50 #define SORFP_NOLIFETIMEMGMT SORF_OXRES1
52 static HRESULT unmarshal_object(const STDOBJREF *stdobjref, APARTMENT *apt,
53 MSHCTX dest_context, void *dest_context_data,
54 REFIID riid, const OXID_INFO *oxid_info,
55 void **object);
57 /* Marshalling just passes a unique identifier to the remote client,
58 * that makes it possible to find the passed interface again.
60 * So basically we need a set of values that make it unique.
62 * Note that the IUnknown_QI(ob,xiid,&ppv) always returns the SAME ppv value!
64 * A triple is used: OXID (apt id), OID (stub manager id),
65 * IPID (interface ptr/stub id).
67 * OXIDs identify an apartment and are network scoped
68 * OIDs identify a stub manager and are apartment scoped
69 * IPIDs identify an interface stub and are apartment scoped
72 static inline HRESULT get_facbuf_for_iid(REFIID riid, IPSFactoryBuffer **facbuf)
74 HRESULT hr;
75 CLSID clsid;
77 if ((hr = CoGetPSClsid(riid, &clsid)))
78 return hr;
79 return CoGetClassObject(&clsid, CLSCTX_INPROC_SERVER, NULL,
80 &IID_IPSFactoryBuffer, (LPVOID*)facbuf);
83 /* marshals an object into a STDOBJREF structure */
84 HRESULT marshal_object(APARTMENT *apt, STDOBJREF *stdobjref, REFIID riid, IUnknown *object, MSHLFLAGS mshlflags)
86 struct stub_manager *manager;
87 struct ifstub *ifstub;
88 BOOL tablemarshal;
89 IRpcStubBuffer *stub = NULL;
90 HRESULT hr;
91 IUnknown *iobject = NULL; /* object of type riid */
93 hr = apartment_getoxid(apt, &stdobjref->oxid);
94 if (hr != S_OK)
95 return hr;
97 hr = apartment_createwindowifneeded(apt);
98 if (hr != S_OK)
99 return hr;
101 hr = IUnknown_QueryInterface(object, riid, (void **)&iobject);
102 if (hr != S_OK)
104 ERR("object doesn't expose interface %s, failing with error 0x%08x\n",
105 debugstr_guid(riid), hr);
106 return E_NOINTERFACE;
109 /* IUnknown doesn't require a stub buffer, because it never goes out on
110 * the wire */
111 if (!IsEqualIID(riid, &IID_IUnknown))
113 IPSFactoryBuffer *psfb;
115 hr = get_facbuf_for_iid(riid, &psfb);
116 if (hr != S_OK)
118 ERR("couldn't get IPSFactory buffer for interface %s\n", debugstr_guid(riid));
119 IUnknown_Release(iobject);
120 return hr;
123 hr = IPSFactoryBuffer_CreateStub(psfb, riid, iobject, &stub);
124 IPSFactoryBuffer_Release(psfb);
125 if (hr != S_OK)
127 ERR("Failed to create an IRpcStubBuffer from IPSFactory for %s with error 0x%08x\n",
128 debugstr_guid(riid), hr);
129 IUnknown_Release(iobject);
130 return hr;
134 if (mshlflags & MSHLFLAGS_NOPING)
135 stdobjref->flags = SORF_NOPING;
136 else
137 stdobjref->flags = SORF_NULL;
139 if ((manager = get_stub_manager_from_object(apt, object)))
140 TRACE("registering new ifstub on pre-existing manager\n");
141 else
143 TRACE("constructing new stub manager\n");
145 manager = new_stub_manager(apt, object);
146 if (!manager)
148 if (stub) IRpcStubBuffer_Release(stub);
149 IUnknown_Release(iobject);
150 return E_OUTOFMEMORY;
153 stdobjref->oid = manager->oid;
155 tablemarshal = ((mshlflags & MSHLFLAGS_TABLESTRONG) || (mshlflags & MSHLFLAGS_TABLEWEAK));
157 /* make sure ifstub that we are creating is unique */
158 ifstub = stub_manager_find_ifstub(manager, riid, mshlflags);
159 if (!ifstub)
160 ifstub = stub_manager_new_ifstub(manager, stub, iobject, riid, mshlflags);
162 if (stub) IRpcStubBuffer_Release(stub);
163 IUnknown_Release(iobject);
165 if (!ifstub)
167 stub_manager_int_release(manager);
168 /* destroy the stub manager if it has no ifstubs by releasing
169 * zero external references */
170 stub_manager_ext_release(manager, 0, TRUE);
171 return E_OUTOFMEMORY;
174 if (!tablemarshal)
176 stdobjref->cPublicRefs = NORMALEXTREFS;
177 stub_manager_ext_addref(manager, stdobjref->cPublicRefs);
179 else
181 stdobjref->cPublicRefs = 0;
182 if (mshlflags & MSHLFLAGS_TABLESTRONG)
183 stub_manager_ext_addref(manager, 1);
186 /* FIXME: check return value */
187 RPC_RegisterInterface(riid);
189 stdobjref->ipid = ifstub->ipid;
191 stub_manager_int_release(manager);
192 return S_OK;
197 /* Client-side identity of the server object */
199 static HRESULT proxy_manager_get_remunknown(struct proxy_manager * This, IRemUnknown **remunk);
200 static void proxy_manager_destroy(struct proxy_manager * This);
201 static HRESULT proxy_manager_find_ifproxy(struct proxy_manager * This, REFIID riid, struct ifproxy ** ifproxy_found);
202 static HRESULT proxy_manager_query_local_interface(struct proxy_manager * This, REFIID riid, void ** ppv);
204 static HRESULT WINAPI ClientIdentity_QueryInterface(IMultiQI * iface, REFIID riid, void ** ppv)
206 HRESULT hr;
207 MULTI_QI mqi;
209 TRACE("%s\n", debugstr_guid(riid));
211 mqi.pIID = riid;
212 hr = IMultiQI_QueryMultipleInterfaces(iface, 1, &mqi);
213 *ppv = (void *)mqi.pItf;
215 return hr;
218 static ULONG WINAPI ClientIdentity_AddRef(IMultiQI * iface)
220 struct proxy_manager * This = (struct proxy_manager *)iface;
221 TRACE("%p - before %d\n", iface, This->refs);
222 return InterlockedIncrement(&This->refs);
225 static ULONG WINAPI ClientIdentity_Release(IMultiQI * iface)
227 struct proxy_manager * This = (struct proxy_manager *)iface;
228 ULONG refs = InterlockedDecrement(&This->refs);
229 TRACE("%p - after %d\n", iface, refs);
230 if (!refs)
231 proxy_manager_destroy(This);
232 return refs;
235 static HRESULT WINAPI ClientIdentity_QueryMultipleInterfaces(IMultiQI *iface, ULONG cMQIs, MULTI_QI *pMQIs)
237 struct proxy_manager * This = (struct proxy_manager *)iface;
238 REMQIRESULT *qiresults = NULL;
239 ULONG nonlocal_mqis = 0;
240 ULONG i;
241 ULONG successful_mqis = 0;
242 IID *iids = HeapAlloc(GetProcessHeap(), 0, cMQIs * sizeof(*iids));
243 /* mapping of RemQueryInterface index to QueryMultipleInterfaces index */
244 ULONG *mapping = HeapAlloc(GetProcessHeap(), 0, cMQIs * sizeof(*mapping));
246 TRACE("cMQIs: %d\n", cMQIs);
248 /* try to get a local interface - this includes already active proxy
249 * interfaces and also interfaces exposed by the proxy manager */
250 for (i = 0; i < cMQIs; i++)
252 TRACE("iid[%d] = %s\n", i, debugstr_guid(pMQIs[i].pIID));
253 pMQIs[i].hr = proxy_manager_query_local_interface(This, pMQIs[i].pIID, (void **)&pMQIs[i].pItf);
254 if (pMQIs[i].hr == S_OK)
255 successful_mqis++;
256 else
258 iids[nonlocal_mqis] = *pMQIs[i].pIID;
259 mapping[nonlocal_mqis] = i;
260 nonlocal_mqis++;
264 TRACE("%d interfaces not found locally\n", nonlocal_mqis);
266 /* if we have more than one interface not found locally then we must try
267 * to query the remote object for it */
268 if (nonlocal_mqis != 0)
270 IRemUnknown *remunk;
271 HRESULT hr;
272 IPID *ipid;
274 /* get the ipid of the first entry */
275 /* FIXME: should we implement ClientIdentity on the ifproxies instead
276 * of the proxy_manager so we use the correct ipid here? */
277 ipid = &LIST_ENTRY(list_head(&This->interfaces), struct ifproxy, entry)->stdobjref.ipid;
279 /* get IRemUnknown proxy so we can communicate with the remote object */
280 hr = proxy_manager_get_remunknown(This, &remunk);
282 if (hr == S_OK)
284 hr = IRemUnknown_RemQueryInterface(remunk, ipid, NORMALEXTREFS,
285 nonlocal_mqis, iids, &qiresults);
286 IRemUnknown_Release(remunk);
287 if (FAILED(hr))
288 ERR("IRemUnknown_RemQueryInterface failed with error 0x%08x\n", hr);
291 /* IRemUnknown_RemQueryInterface can return S_FALSE if only some of
292 * the interfaces were returned */
293 if (SUCCEEDED(hr))
295 /* try to unmarshal each object returned to us */
296 for (i = 0; i < nonlocal_mqis; i++)
298 ULONG index = mapping[i];
299 HRESULT hrobj = qiresults[i].hResult;
300 if (hrobj == S_OK)
301 hrobj = unmarshal_object(&qiresults[i].std, COM_CurrentApt(),
302 This->dest_context,
303 This->dest_context_data,
304 pMQIs[index].pIID, &This->oxid_info,
305 (void **)&pMQIs[index].pItf);
307 if (hrobj == S_OK)
308 successful_mqis++;
309 else
310 ERR("Failed to get pointer to interface %s\n", debugstr_guid(pMQIs[index].pIID));
311 pMQIs[index].hr = hrobj;
315 /* free the memory allocated by the proxy */
316 CoTaskMemFree(qiresults);
319 TRACE("%d/%d successfully queried\n", successful_mqis, cMQIs);
321 HeapFree(GetProcessHeap(), 0, iids);
322 HeapFree(GetProcessHeap(), 0, mapping);
324 if (successful_mqis == cMQIs)
325 return S_OK; /* we got all requested interfaces */
326 else if (successful_mqis == 0)
327 return E_NOINTERFACE; /* we didn't get any interfaces */
328 else
329 return S_FALSE; /* we got some interfaces */
332 static const IMultiQIVtbl ClientIdentity_Vtbl =
334 ClientIdentity_QueryInterface,
335 ClientIdentity_AddRef,
336 ClientIdentity_Release,
337 ClientIdentity_QueryMultipleInterfaces
340 /* FIXME: remove these */
341 static HRESULT WINAPI StdMarshalImpl_GetUnmarshalClass(LPMARSHAL iface, REFIID riid, void* pv, DWORD dwDestContext, void* pvDestContext, DWORD mshlflags, CLSID* pCid);
342 static HRESULT WINAPI StdMarshalImpl_GetMarshalSizeMax(LPMARSHAL iface, REFIID riid, void* pv, DWORD dwDestContext, void* pvDestContext, DWORD mshlflags, DWORD* pSize);
343 static HRESULT WINAPI StdMarshalImpl_UnmarshalInterface(LPMARSHAL iface, IStream *pStm, REFIID riid, void **ppv);
344 static HRESULT WINAPI StdMarshalImpl_ReleaseMarshalData(LPMARSHAL iface, IStream *pStm);
345 static HRESULT WINAPI StdMarshalImpl_DisconnectObject(LPMARSHAL iface, DWORD dwReserved);
347 static HRESULT WINAPI Proxy_QueryInterface(IMarshal *iface, REFIID riid, void **ppvObject)
349 ICOM_THIS_MULTI(struct proxy_manager, lpVtblMarshal, iface);
350 return IMultiQI_QueryInterface((IMultiQI *)&This->lpVtbl, riid, ppvObject);
353 static ULONG WINAPI Proxy_AddRef(IMarshal *iface)
355 ICOM_THIS_MULTI(struct proxy_manager, lpVtblMarshal, iface);
356 return IMultiQI_AddRef((IMultiQI *)&This->lpVtbl);
359 static ULONG WINAPI Proxy_Release(IMarshal *iface)
361 ICOM_THIS_MULTI(struct proxy_manager, lpVtblMarshal, iface);
362 return IMultiQI_Release((IMultiQI *)&This->lpVtbl);
365 static HRESULT WINAPI Proxy_MarshalInterface(
366 LPMARSHAL iface, IStream *pStm, REFIID riid, void* pv, DWORD dwDestContext,
367 void* pvDestContext, DWORD mshlflags)
369 ICOM_THIS_MULTI(struct proxy_manager, lpVtblMarshal, iface);
370 HRESULT hr;
371 struct ifproxy *ifproxy;
373 TRACE("(...,%s,...)\n", debugstr_guid(riid));
375 hr = proxy_manager_find_ifproxy(This, riid, &ifproxy);
376 if (SUCCEEDED(hr))
378 STDOBJREF stdobjref = ifproxy->stdobjref;
380 stdobjref.cPublicRefs = 0;
382 if ((mshlflags != MSHLFLAGS_TABLEWEAK) &&
383 (mshlflags != MSHLFLAGS_TABLESTRONG))
385 ULONG cPublicRefs = ifproxy->refs;
386 ULONG cPublicRefsOld;
387 /* optimization - share out proxy's public references if possible
388 * instead of making new proxy do a roundtrip through the server */
391 ULONG cPublicRefsNew;
392 cPublicRefsOld = cPublicRefs;
393 stdobjref.cPublicRefs = cPublicRefs / 2;
394 cPublicRefsNew = cPublicRefs - stdobjref.cPublicRefs;
395 cPublicRefs = InterlockedCompareExchange(
396 (LONG *)&ifproxy->refs, cPublicRefsNew, cPublicRefsOld);
397 } while (cPublicRefs != cPublicRefsOld);
400 /* normal and table-strong marshaling need at least one reference */
401 if (!stdobjref.cPublicRefs && (mshlflags != MSHLFLAGS_TABLEWEAK))
403 IRemUnknown *remunk;
404 hr = proxy_manager_get_remunknown(This, &remunk);
405 if (hr == S_OK)
407 HRESULT hrref = S_OK;
408 REMINTERFACEREF rif;
409 rif.ipid = ifproxy->stdobjref.ipid;
410 rif.cPublicRefs = (mshlflags == MSHLFLAGS_TABLESTRONG) ? 1 : NORMALEXTREFS;
411 rif.cPrivateRefs = 0;
412 hr = IRemUnknown_RemAddRef(remunk, 1, &rif, &hrref);
413 IRemUnknown_Release(remunk);
414 if (hr == S_OK && hrref == S_OK)
416 /* table-strong marshaling doesn't give the refs to the
417 * client that unmarshals the STDOBJREF */
418 if (mshlflags != MSHLFLAGS_TABLESTRONG)
419 stdobjref.cPublicRefs = rif.cPublicRefs;
421 else
422 ERR("IRemUnknown_RemAddRef returned with 0x%08x, hrref = 0x%08x\n", hr, hrref);
426 if (SUCCEEDED(hr))
428 TRACE("writing stdobjref:\n\tflags = %04lx\n\tcPublicRefs = %ld\n\toxid = %s\n\toid = %s\n\tipid = %s\n",
429 stdobjref.flags, stdobjref.cPublicRefs,
430 wine_dbgstr_longlong(stdobjref.oxid),
431 wine_dbgstr_longlong(stdobjref.oid),
432 debugstr_guid(&stdobjref.ipid));
433 hr = IStream_Write(pStm, &stdobjref, sizeof(stdobjref), NULL);
436 else
438 /* we don't have the interface already unmarshaled so we have to
439 * request the object from the server */
440 IRemUnknown *remunk;
441 IPID *ipid;
442 REMQIRESULT *qiresults = NULL;
443 IID iid = *riid;
445 /* get the ipid of the first entry */
446 /* FIXME: should we implement ClientIdentity on the ifproxies instead
447 * of the proxy_manager so we use the correct ipid here? */
448 ipid = &LIST_ENTRY(list_head(&This->interfaces), struct ifproxy, entry)->stdobjref.ipid;
450 /* get IRemUnknown proxy so we can communicate with the remote object */
451 hr = proxy_manager_get_remunknown(This, &remunk);
453 if (hr == S_OK)
455 hr = IRemUnknown_RemQueryInterface(remunk, ipid, NORMALEXTREFS,
456 1, &iid, &qiresults);
457 if (SUCCEEDED(hr))
459 hr = IStream_Write(pStm, &qiresults->std, sizeof(qiresults->std), NULL);
460 if (FAILED(hr))
462 REMINTERFACEREF rif;
463 rif.ipid = qiresults->std.ipid;
464 rif.cPublicRefs = qiresults->std.cPublicRefs;
465 rif.cPrivateRefs = 0;
466 IRemUnknown_RemRelease(remunk, 1, &rif);
468 CoTaskMemFree(qiresults);
470 else
471 ERR("IRemUnknown_RemQueryInterface failed with error 0x%08x\n", hr);
472 IRemUnknown_Release(remunk);
476 return hr;
479 static const IMarshalVtbl ProxyMarshal_Vtbl =
481 Proxy_QueryInterface,
482 Proxy_AddRef,
483 Proxy_Release,
484 StdMarshalImpl_GetUnmarshalClass,
485 StdMarshalImpl_GetMarshalSizeMax,
486 Proxy_MarshalInterface,
487 StdMarshalImpl_UnmarshalInterface,
488 StdMarshalImpl_ReleaseMarshalData,
489 StdMarshalImpl_DisconnectObject
492 static HRESULT WINAPI ProxyCliSec_QueryInterface(IClientSecurity *iface, REFIID riid, void **ppvObject)
494 ICOM_THIS_MULTI(struct proxy_manager, lpVtblCliSec, iface);
495 return IMultiQI_QueryInterface((IMultiQI *)&This->lpVtbl, riid, ppvObject);
498 static ULONG WINAPI ProxyCliSec_AddRef(IClientSecurity *iface)
500 ICOM_THIS_MULTI(struct proxy_manager, lpVtblCliSec, iface);
501 return IMultiQI_AddRef((IMultiQI *)&This->lpVtbl);
504 static ULONG WINAPI ProxyCliSec_Release(IClientSecurity *iface)
506 ICOM_THIS_MULTI(struct proxy_manager, lpVtblCliSec, iface);
507 return IMultiQI_Release((IMultiQI *)&This->lpVtbl);
510 static HRESULT WINAPI ProxyCliSec_QueryBlanket(IClientSecurity *iface,
511 IUnknown *pProxy,
512 DWORD *pAuthnSvc,
513 DWORD *pAuthzSvc,
514 OLECHAR **ppServerPrincName,
515 DWORD *pAuthnLevel,
516 DWORD *pImpLevel,
517 void **pAuthInfo,
518 DWORD *pCapabilities)
520 FIXME("(%p, %p, %p, %p, %p, %p, %p, %p): stub\n", pProxy, pAuthnSvc,
521 pAuthzSvc, ppServerPrincName, pAuthnLevel, pImpLevel, pAuthInfo,
522 pCapabilities);
524 if (pAuthnSvc)
525 *pAuthnSvc = 0;
526 if (pAuthzSvc)
527 *pAuthzSvc = 0;
528 if (ppServerPrincName)
529 *ppServerPrincName = NULL;
530 if (pAuthnLevel)
531 *pAuthnLevel = RPC_C_AUTHN_LEVEL_DEFAULT;
532 if (pImpLevel)
533 *pImpLevel = RPC_C_IMP_LEVEL_DEFAULT;
534 if (pAuthInfo)
535 *pAuthInfo = NULL;
536 if (pCapabilities)
537 *pCapabilities = EOAC_NONE;
539 return E_NOTIMPL;
542 static HRESULT WINAPI ProxyCliSec_SetBlanket(IClientSecurity *iface,
543 IUnknown *pProxy, DWORD AuthnSvc,
544 DWORD AuthzSvc,
545 OLECHAR *pServerPrincName,
546 DWORD AuthnLevel, DWORD ImpLevel,
547 void *pAuthInfo,
548 DWORD Capabilities)
550 FIXME("(%p, %d, %d, %s, %d, %d, %p, 0x%x): stub\n", pProxy, AuthnSvc,
551 AuthzSvc, debugstr_w(pServerPrincName), AuthnLevel, ImpLevel,
552 pAuthInfo, Capabilities);
553 return E_NOTIMPL;
556 static HRESULT WINAPI ProxyCliSec_CopyProxy(IClientSecurity *iface,
557 IUnknown *pProxy, IUnknown **ppCopy)
559 FIXME("(%p, %p): stub\n", pProxy, ppCopy);
560 *ppCopy = NULL;
561 return E_NOTIMPL;
564 static const IClientSecurityVtbl ProxyCliSec_Vtbl =
566 ProxyCliSec_QueryInterface,
567 ProxyCliSec_AddRef,
568 ProxyCliSec_Release,
569 ProxyCliSec_QueryBlanket,
570 ProxyCliSec_SetBlanket,
571 ProxyCliSec_CopyProxy
574 static HRESULT ifproxy_get_public_ref(struct ifproxy * This)
576 HRESULT hr = S_OK;
578 if (WAIT_OBJECT_0 != WaitForSingleObject(This->parent->remoting_mutex, INFINITE))
580 ERR("Wait failed for ifproxy %p\n", This);
581 return E_UNEXPECTED;
584 if (This->refs == 0)
586 IRemUnknown *remunk = NULL;
588 TRACE("getting public ref for ifproxy %p\n", This);
590 hr = proxy_manager_get_remunknown(This->parent, &remunk);
591 if (hr == S_OK)
593 HRESULT hrref = S_OK;
594 REMINTERFACEREF rif;
595 rif.ipid = This->stdobjref.ipid;
596 rif.cPublicRefs = NORMALEXTREFS;
597 rif.cPrivateRefs = 0;
598 hr = IRemUnknown_RemAddRef(remunk, 1, &rif, &hrref);
599 IRemUnknown_Release(remunk);
600 if (hr == S_OK && hrref == S_OK)
601 InterlockedExchangeAdd((LONG *)&This->refs, NORMALEXTREFS);
602 else
603 ERR("IRemUnknown_RemAddRef returned with 0x%08x, hrref = 0x%08x\n", hr, hrref);
606 ReleaseMutex(This->parent->remoting_mutex);
608 return hr;
611 static HRESULT ifproxy_release_public_refs(struct ifproxy * This)
613 HRESULT hr = S_OK;
614 LONG public_refs;
616 if (WAIT_OBJECT_0 != WaitForSingleObject(This->parent->remoting_mutex, INFINITE))
618 ERR("Wait failed for ifproxy %p\n", This);
619 return E_UNEXPECTED;
622 public_refs = This->refs;
623 if (public_refs > 0)
625 IRemUnknown *remunk = NULL;
627 TRACE("releasing %d refs\n", public_refs);
629 hr = proxy_manager_get_remunknown(This->parent, &remunk);
630 if (hr == S_OK)
632 REMINTERFACEREF rif;
633 rif.ipid = This->stdobjref.ipid;
634 rif.cPublicRefs = public_refs;
635 rif.cPrivateRefs = 0;
636 hr = IRemUnknown_RemRelease(remunk, 1, &rif);
637 IRemUnknown_Release(remunk);
638 if (hr == S_OK)
639 InterlockedExchangeAdd((LONG *)&This->refs, -public_refs);
640 else if (hr == RPC_E_DISCONNECTED)
641 WARN("couldn't release references because object was "
642 "disconnected: oxid = %s, oid = %s\n",
643 wine_dbgstr_longlong(This->parent->oxid),
644 wine_dbgstr_longlong(This->parent->oid));
645 else
646 ERR("IRemUnknown_RemRelease failed with error 0x%08x\n", hr);
649 ReleaseMutex(This->parent->remoting_mutex);
651 return hr;
654 /* should be called inside This->parent->cs critical section */
655 static void ifproxy_disconnect(struct ifproxy * This)
657 ifproxy_release_public_refs(This);
658 if (This->proxy) IRpcProxyBuffer_Disconnect(This->proxy);
660 IRpcChannelBuffer_Release(This->chan);
661 This->chan = NULL;
664 /* should be called in This->parent->cs critical section if it is an entry in parent's list */
665 static void ifproxy_destroy(struct ifproxy * This)
667 TRACE("%p\n", This);
669 /* release public references to this object so that the stub can know
670 * when to destroy itself */
671 ifproxy_release_public_refs(This);
673 list_remove(&This->entry);
675 if (This->chan)
677 IRpcChannelBuffer_Release(This->chan);
678 This->chan = NULL;
681 if (This->proxy) IRpcProxyBuffer_Release(This->proxy);
683 HeapFree(GetProcessHeap(), 0, This);
686 static HRESULT proxy_manager_construct(
687 APARTMENT * apt, ULONG sorflags, OXID oxid, OID oid,
688 const OXID_INFO *oxid_info, struct proxy_manager ** proxy_manager)
690 struct proxy_manager * This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
691 if (!This) return E_OUTOFMEMORY;
693 This->remoting_mutex = CreateMutexW(NULL, FALSE, NULL);
694 if (!This->remoting_mutex)
696 HeapFree(GetProcessHeap(), 0, This);
697 return HRESULT_FROM_WIN32(GetLastError());
700 if (oxid_info)
702 This->oxid_info.dwPid = oxid_info->dwPid;
703 This->oxid_info.dwTid = oxid_info->dwTid;
704 This->oxid_info.ipidRemUnknown = oxid_info->ipidRemUnknown;
705 This->oxid_info.dwAuthnHint = oxid_info->dwAuthnHint;
706 This->oxid_info.psa = NULL /* FIXME: copy from oxid_info */;
708 else
710 HRESULT hr = RPC_ResolveOxid(oxid, &This->oxid_info);
711 if (FAILED(hr))
713 CloseHandle(This->remoting_mutex);
714 HeapFree(GetProcessHeap(), 0, This);
715 return hr;
719 This->lpVtbl = &ClientIdentity_Vtbl;
720 This->lpVtblMarshal = &ProxyMarshal_Vtbl;
721 This->lpVtblCliSec = &ProxyCliSec_Vtbl;
723 list_init(&This->entry);
724 list_init(&This->interfaces);
726 InitializeCriticalSection(&This->cs);
727 DEBUG_SET_CRITSEC_NAME(&This->cs, "proxy_manager");
729 /* the apartment the object was unmarshaled into */
730 This->parent = apt;
732 /* the source apartment and id of the object */
733 This->oxid = oxid;
734 This->oid = oid;
736 This->refs = 1;
738 /* the DCOM draft specification states that the SORF_NOPING flag is
739 * proxy manager specific, not ifproxy specific, so this implies that we
740 * should store the STDOBJREF flags here in the proxy manager. */
741 This->sorflags = sorflags;
743 /* we create the IRemUnknown proxy on demand */
744 This->remunk = NULL;
746 /* initialise these values to the weakest values and they will be
747 * overwritten in proxy_manager_set_context */
748 This->dest_context = MSHCTX_INPROC;
749 This->dest_context_data = NULL;
751 EnterCriticalSection(&apt->cs);
752 /* FIXME: we are dependent on the ordering in here to make sure a proxy's
753 * IRemUnknown proxy doesn't get destroyed before the regual proxy does
754 * because we need the IRemUnknown proxy during the destruction of the
755 * regular proxy. Ideally, we should maintain a separate list for the
756 * IRemUnknown proxies that need late destruction */
757 list_add_tail(&apt->proxies, &This->entry);
758 LeaveCriticalSection(&apt->cs);
760 TRACE("%p created for OXID %s, OID %s\n", This,
761 wine_dbgstr_longlong(oxid), wine_dbgstr_longlong(oid));
763 *proxy_manager = This;
764 return S_OK;
767 static inline void proxy_manager_set_context(struct proxy_manager *This, MSHCTX dest_context, void *dest_context_data)
769 MSHCTX old_dest_context = This->dest_context;
770 MSHCTX new_dest_context;
774 new_dest_context = old_dest_context;
775 /* "stronger" values overwrite "weaker" values. stronger values are
776 * ones that disable more optimisations */
777 switch (old_dest_context)
779 case MSHCTX_INPROC:
780 new_dest_context = dest_context;
781 break;
782 case MSHCTX_CROSSCTX:
783 switch (dest_context)
785 case MSHCTX_INPROC:
786 break;
787 default:
788 new_dest_context = dest_context;
790 break;
791 case MSHCTX_LOCAL:
792 switch (dest_context)
794 case MSHCTX_INPROC:
795 case MSHCTX_CROSSCTX:
796 break;
797 default:
798 new_dest_context = dest_context;
800 break;
801 case MSHCTX_NOSHAREDMEM:
802 switch (dest_context)
804 case MSHCTX_DIFFERENTMACHINE:
805 new_dest_context = dest_context;
806 break;
807 default:
808 break;
810 break;
811 default:
812 break;
815 if (old_dest_context == new_dest_context) break;
817 old_dest_context = InterlockedCompareExchange((PLONG)&This->dest_context, new_dest_context, old_dest_context);
818 } while (new_dest_context != old_dest_context);
820 if (dest_context_data)
821 InterlockedExchangePointer(&This->dest_context_data, dest_context_data);
824 static HRESULT proxy_manager_query_local_interface(struct proxy_manager * This, REFIID riid, void ** ppv)
826 HRESULT hr;
827 struct ifproxy * ifproxy;
829 TRACE("%s\n", debugstr_guid(riid));
831 if (IsEqualIID(riid, &IID_IUnknown) ||
832 IsEqualIID(riid, &IID_IMultiQI))
834 *ppv = (void *)&This->lpVtbl;
835 IUnknown_AddRef((IUnknown *)*ppv);
836 return S_OK;
838 if (IsEqualIID(riid, &IID_IMarshal))
840 *ppv = (void *)&This->lpVtblMarshal;
841 IUnknown_AddRef((IUnknown *)*ppv);
842 return S_OK;
844 if (IsEqualIID(riid, &IID_IClientSecurity))
846 *ppv = (void *)&This->lpVtblCliSec;
847 IUnknown_AddRef((IUnknown *)*ppv);
848 return S_OK;
851 hr = proxy_manager_find_ifproxy(This, riid, &ifproxy);
852 if (hr == S_OK)
854 *ppv = ifproxy->iface;
855 IUnknown_AddRef((IUnknown *)*ppv);
856 return S_OK;
859 *ppv = NULL;
860 return E_NOINTERFACE;
863 static HRESULT proxy_manager_create_ifproxy(
864 struct proxy_manager * This, const STDOBJREF *stdobjref, REFIID riid,
865 IRpcChannelBuffer * channel, struct ifproxy ** iif_out)
867 HRESULT hr;
868 IPSFactoryBuffer * psfb;
869 struct ifproxy * ifproxy = HeapAlloc(GetProcessHeap(), 0, sizeof(*ifproxy));
870 if (!ifproxy) return E_OUTOFMEMORY;
872 list_init(&ifproxy->entry);
874 ifproxy->parent = This;
875 ifproxy->stdobjref = *stdobjref;
876 ifproxy->iid = *riid;
877 ifproxy->refs = 0;
878 ifproxy->proxy = NULL;
880 assert(channel);
881 ifproxy->chan = channel; /* FIXME: we should take the binding strings and construct the channel in this function */
883 /* the IUnknown interface is special because it does not have a
884 * proxy associated with the ifproxy as we handle IUnknown ourselves */
885 if (IsEqualIID(riid, &IID_IUnknown))
887 ifproxy->iface = (void *)&This->lpVtbl;
888 IMultiQI_AddRef((IMultiQI *)&This->lpVtbl);
889 hr = S_OK;
891 else
893 hr = get_facbuf_for_iid(riid, &psfb);
894 if (hr == S_OK)
896 /* important note: the outer unknown is set to the proxy manager.
897 * This ensures the COM identity rules are not violated, by having a
898 * one-to-one mapping of objects on the proxy side to objects on the
899 * stub side, no matter which interface you view the object through */
900 hr = IPSFactoryBuffer_CreateProxy(psfb, (IUnknown *)&This->lpVtbl, riid,
901 &ifproxy->proxy, &ifproxy->iface);
902 IPSFactoryBuffer_Release(psfb);
903 if (hr != S_OK)
904 ERR("Could not create proxy for interface %s, error 0x%08x\n",
905 debugstr_guid(riid), hr);
907 else
908 ERR("Could not get IPSFactoryBuffer for interface %s, error 0x%08x\n",
909 debugstr_guid(riid), hr);
911 if (hr == S_OK)
912 hr = IRpcProxyBuffer_Connect(ifproxy->proxy, ifproxy->chan);
915 if (hr == S_OK)
917 EnterCriticalSection(&This->cs);
918 list_add_tail(&This->interfaces, &ifproxy->entry);
919 LeaveCriticalSection(&This->cs);
921 *iif_out = ifproxy;
922 TRACE("ifproxy %p created for IPID %s, interface %s with %lu public refs\n",
923 ifproxy, debugstr_guid(&stdobjref->ipid), debugstr_guid(riid), stdobjref->cPublicRefs);
925 else
926 ifproxy_destroy(ifproxy);
928 return hr;
931 static HRESULT proxy_manager_find_ifproxy(struct proxy_manager * This, REFIID riid, struct ifproxy ** ifproxy_found)
933 HRESULT hr = E_NOINTERFACE; /* assume not found */
934 struct list * cursor;
936 EnterCriticalSection(&This->cs);
937 LIST_FOR_EACH(cursor, &This->interfaces)
939 struct ifproxy * ifproxy = LIST_ENTRY(cursor, struct ifproxy, entry);
940 if (IsEqualIID(riid, &ifproxy->iid))
942 *ifproxy_found = ifproxy;
943 hr = S_OK;
944 break;
947 LeaveCriticalSection(&This->cs);
949 return hr;
952 static void proxy_manager_disconnect(struct proxy_manager * This)
954 struct list * cursor;
956 TRACE("oxid = %s, oid = %s\n", wine_dbgstr_longlong(This->oxid),
957 wine_dbgstr_longlong(This->oid));
959 EnterCriticalSection(&This->cs);
961 /* SORFP_NOLIFTIMEMGMT proxies (for IRemUnknown) shouldn't be
962 * disconnected - it won't do anything anyway, except cause
963 * problems for other objects that depend on this proxy always
964 * working */
965 if (!(This->sorflags & SORFP_NOLIFETIMEMGMT))
967 LIST_FOR_EACH(cursor, &This->interfaces)
969 struct ifproxy * ifproxy = LIST_ENTRY(cursor, struct ifproxy, entry);
970 ifproxy_disconnect(ifproxy);
974 /* apartment is being destroyed so don't keep a pointer around to it */
975 This->parent = NULL;
977 LeaveCriticalSection(&This->cs);
980 static HRESULT proxy_manager_get_remunknown(struct proxy_manager * This, IRemUnknown **remunk)
982 HRESULT hr = S_OK;
983 struct apartment *apt;
984 BOOL called_in_original_apt;
986 /* we don't want to try and unmarshal or use IRemUnknown if we don't want
987 * lifetime management */
988 if (This->sorflags & SORFP_NOLIFETIMEMGMT)
989 return S_FALSE;
991 apt = COM_CurrentApt();
992 if (!apt)
993 return CO_E_NOTINITIALIZED;
995 called_in_original_apt = This->parent && (This->parent->oxid == apt->oxid);
997 EnterCriticalSection(&This->cs);
998 /* only return the cached object if called from the original apartment.
999 * in future, we might want to make the IRemUnknown proxy callable from any
1000 * apartment to avoid these checks */
1001 if (This->remunk && called_in_original_apt)
1003 /* already created - return existing object */
1004 *remunk = This->remunk;
1005 IRemUnknown_AddRef(*remunk);
1007 else if (!This->parent)
1008 /* disconnected - we can't create IRemUnknown */
1009 hr = S_FALSE;
1010 else
1012 STDOBJREF stdobjref;
1013 /* Don't want IRemUnknown lifetime management as this is IRemUnknown!
1014 * We also don't care about whether or not the stub is still alive */
1015 stdobjref.flags = SORFP_NOLIFETIMEMGMT | SORF_NOPING;
1016 stdobjref.cPublicRefs = 1;
1017 /* oxid of destination object */
1018 stdobjref.oxid = This->oxid;
1019 /* FIXME: what should be used for the oid? The DCOM draft doesn't say */
1020 stdobjref.oid = (OID)-1;
1021 stdobjref.ipid = This->oxid_info.ipidRemUnknown;
1023 /* do the unmarshal */
1024 hr = unmarshal_object(&stdobjref, COM_CurrentApt(), This->dest_context,
1025 This->dest_context_data, &IID_IRemUnknown,
1026 &This->oxid_info, (void**)remunk);
1027 if (hr == S_OK && called_in_original_apt)
1029 This->remunk = *remunk;
1030 IRemUnknown_AddRef(This->remunk);
1033 LeaveCriticalSection(&This->cs);
1035 TRACE("got IRemUnknown* pointer %p, hr = 0x%08x\n", *remunk, hr);
1037 return hr;
1040 /* destroys a proxy manager, freeing the memory it used.
1041 * Note: this function should not be called from a list iteration in the
1042 * apartment, due to the fact that it removes itself from the apartment and
1043 * it could add a proxy to IRemUnknown into the apartment. */
1044 static void proxy_manager_destroy(struct proxy_manager * This)
1046 struct list * cursor;
1048 TRACE("oxid = %s, oid = %s\n", wine_dbgstr_longlong(This->oxid),
1049 wine_dbgstr_longlong(This->oid));
1051 if (This->parent)
1053 EnterCriticalSection(&This->parent->cs);
1055 /* remove ourself from the list of proxy objects in the apartment */
1056 LIST_FOR_EACH(cursor, &This->parent->proxies)
1058 if (cursor == &This->entry)
1060 list_remove(&This->entry);
1061 break;
1065 LeaveCriticalSection(&This->parent->cs);
1068 /* destroy all of the interface proxies */
1069 while ((cursor = list_head(&This->interfaces)))
1071 struct ifproxy * ifproxy = LIST_ENTRY(cursor, struct ifproxy, entry);
1072 ifproxy_destroy(ifproxy);
1075 if (This->remunk) IRemUnknown_Release(This->remunk);
1076 CoTaskMemFree(This->oxid_info.psa);
1078 DEBUG_CLEAR_CRITSEC_NAME(&This->cs);
1079 DeleteCriticalSection(&This->cs);
1081 CloseHandle(This->remoting_mutex);
1083 HeapFree(GetProcessHeap(), 0, This);
1086 /* finds the proxy manager corresponding to a given OXID and OID that has
1087 * been unmarshaled in the specified apartment. The caller must release the
1088 * reference to the proxy_manager when the object is no longer used. */
1089 static BOOL find_proxy_manager(APARTMENT * apt, OXID oxid, OID oid, struct proxy_manager ** proxy_found)
1091 BOOL found = FALSE;
1092 struct list * cursor;
1094 EnterCriticalSection(&apt->cs);
1095 LIST_FOR_EACH(cursor, &apt->proxies)
1097 struct proxy_manager * proxy = LIST_ENTRY(cursor, struct proxy_manager, entry);
1098 if ((oxid == proxy->oxid) && (oid == proxy->oid))
1100 *proxy_found = proxy;
1101 ClientIdentity_AddRef((IMultiQI *)&proxy->lpVtbl);
1102 found = TRUE;
1103 break;
1106 LeaveCriticalSection(&apt->cs);
1107 return found;
1110 HRESULT apartment_disconnectproxies(struct apartment *apt)
1112 struct list * cursor;
1114 LIST_FOR_EACH(cursor, &apt->proxies)
1116 struct proxy_manager * proxy = LIST_ENTRY(cursor, struct proxy_manager, entry);
1117 proxy_manager_disconnect(proxy);
1120 return S_OK;
1123 /********************** StdMarshal implementation ****************************/
1124 typedef struct _StdMarshalImpl
1126 const IMarshalVtbl *lpvtbl;
1127 LONG ref;
1129 IID iid;
1130 DWORD dwDestContext;
1131 LPVOID pvDestContext;
1132 DWORD mshlflags;
1133 } StdMarshalImpl;
1135 static HRESULT WINAPI
1136 StdMarshalImpl_QueryInterface(LPMARSHAL iface, REFIID riid, LPVOID *ppv)
1138 *ppv = NULL;
1139 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IMarshal, riid))
1141 *ppv = iface;
1142 IUnknown_AddRef(iface);
1143 return S_OK;
1145 FIXME("No interface for %s.\n", debugstr_guid(riid));
1146 return E_NOINTERFACE;
1149 static ULONG WINAPI
1150 StdMarshalImpl_AddRef(LPMARSHAL iface)
1152 StdMarshalImpl *This = (StdMarshalImpl *)iface;
1153 return InterlockedIncrement(&This->ref);
1156 static ULONG WINAPI
1157 StdMarshalImpl_Release(LPMARSHAL iface)
1159 StdMarshalImpl *This = (StdMarshalImpl *)iface;
1160 ULONG ref = InterlockedDecrement(&This->ref);
1162 if (!ref) HeapFree(GetProcessHeap(),0,This);
1163 return ref;
1166 static HRESULT WINAPI
1167 StdMarshalImpl_GetUnmarshalClass(
1168 LPMARSHAL iface, REFIID riid, void* pv, DWORD dwDestContext,
1169 void* pvDestContext, DWORD mshlflags, CLSID* pCid)
1171 *pCid = CLSID_DfMarshal;
1172 return S_OK;
1175 static HRESULT WINAPI
1176 StdMarshalImpl_GetMarshalSizeMax(
1177 LPMARSHAL iface, REFIID riid, void* pv, DWORD dwDestContext,
1178 void* pvDestContext, DWORD mshlflags, DWORD* pSize)
1180 *pSize = sizeof(STDOBJREF);
1181 return S_OK;
1184 static HRESULT WINAPI
1185 StdMarshalImpl_MarshalInterface(
1186 LPMARSHAL iface, IStream *pStm,REFIID riid, void* pv, DWORD dwDestContext,
1187 void* pvDestContext, DWORD mshlflags)
1189 STDOBJREF stdobjref;
1190 ULONG res;
1191 HRESULT hres;
1192 APARTMENT *apt = COM_CurrentApt();
1194 TRACE("(...,%s,...)\n", debugstr_guid(riid));
1196 if (!apt)
1198 ERR("Apartment not initialized\n");
1199 return CO_E_NOTINITIALIZED;
1202 /* make sure this apartment can be reached from other threads / processes */
1203 RPC_StartRemoting(apt);
1205 hres = marshal_object(apt, &stdobjref, riid, (IUnknown *)pv, mshlflags);
1206 if (hres)
1208 ERR("Failed to create ifstub, hres=0x%x\n", hres);
1209 return hres;
1212 hres = IStream_Write(pStm, &stdobjref, sizeof(stdobjref), &res);
1213 if (hres) return hres;
1215 return S_OK;
1218 /* helper for StdMarshalImpl_UnmarshalInterface - does the unmarshaling with
1219 * no questions asked about the rules surrounding same-apartment unmarshals
1220 * and table marshaling */
1221 static HRESULT unmarshal_object(const STDOBJREF *stdobjref, APARTMENT *apt,
1222 MSHCTX dest_context, void *dest_context_data,
1223 REFIID riid, const OXID_INFO *oxid_info,
1224 void **object)
1226 struct proxy_manager *proxy_manager = NULL;
1227 HRESULT hr = S_OK;
1229 assert(apt);
1231 TRACE("stdobjref:\n\tflags = %04lx\n\tcPublicRefs = %ld\n\toxid = %s\n\toid = %s\n\tipid = %s\n",
1232 stdobjref->flags, stdobjref->cPublicRefs,
1233 wine_dbgstr_longlong(stdobjref->oxid),
1234 wine_dbgstr_longlong(stdobjref->oid),
1235 debugstr_guid(&stdobjref->ipid));
1237 /* create a new proxy manager if one doesn't already exist for the
1238 * object */
1239 if (!find_proxy_manager(apt, stdobjref->oxid, stdobjref->oid, &proxy_manager))
1241 hr = proxy_manager_construct(apt, stdobjref->flags,
1242 stdobjref->oxid, stdobjref->oid, oxid_info,
1243 &proxy_manager);
1245 else
1246 TRACE("proxy manager already created, using\n");
1248 if (hr == S_OK)
1250 struct ifproxy * ifproxy;
1252 proxy_manager_set_context(proxy_manager, dest_context, dest_context_data);
1254 hr = proxy_manager_find_ifproxy(proxy_manager, riid, &ifproxy);
1255 if (hr == E_NOINTERFACE)
1257 IRpcChannelBuffer *chanbuf;
1258 hr = RPC_CreateClientChannel(&stdobjref->oxid, &stdobjref->ipid,
1259 &proxy_manager->oxid_info,
1260 proxy_manager->dest_context,
1261 proxy_manager->dest_context_data,
1262 &chanbuf);
1263 if (hr == S_OK)
1264 hr = proxy_manager_create_ifproxy(proxy_manager, stdobjref,
1265 riid, chanbuf, &ifproxy);
1267 else
1268 IUnknown_AddRef((IUnknown *)ifproxy->iface);
1270 if (hr == S_OK)
1272 InterlockedExchangeAdd((LONG *)&ifproxy->refs, stdobjref->cPublicRefs);
1273 /* get at least one external reference to the object to keep it alive */
1274 hr = ifproxy_get_public_ref(ifproxy);
1275 if (FAILED(hr))
1276 ifproxy_destroy(ifproxy);
1279 if (hr == S_OK)
1280 *object = ifproxy->iface;
1283 /* release our reference to the proxy manager - the client/apartment
1284 * will hold on to the remaining reference for us */
1285 if (proxy_manager) ClientIdentity_Release((IMultiQI*)&proxy_manager->lpVtbl);
1287 return hr;
1290 static HRESULT WINAPI
1291 StdMarshalImpl_UnmarshalInterface(LPMARSHAL iface, IStream *pStm, REFIID riid, void **ppv)
1293 StdMarshalImpl *This = (StdMarshalImpl *)iface;
1294 struct stub_manager *stubmgr = NULL;
1295 STDOBJREF stdobjref;
1296 ULONG res;
1297 HRESULT hres;
1298 APARTMENT *apt = COM_CurrentApt();
1299 APARTMENT *stub_apt;
1300 OXID oxid;
1302 TRACE("(...,%s,....)\n", debugstr_guid(riid));
1304 /* we need an apartment to unmarshal into */
1305 if (!apt)
1307 ERR("Apartment not initialized\n");
1308 return CO_E_NOTINITIALIZED;
1311 /* read STDOBJREF from wire */
1312 hres = IStream_Read(pStm, &stdobjref, sizeof(stdobjref), &res);
1313 if (hres) return STG_E_READFAULT;
1315 hres = apartment_getoxid(apt, &oxid);
1316 if (hres) return hres;
1318 /* check if we're marshalling back to ourselves */
1319 if ((oxid == stdobjref.oxid) && (stubmgr = get_stub_manager(apt, stdobjref.oid)))
1321 TRACE("Unmarshalling object marshalled in same apartment for iid %s, "
1322 "returning original object %p\n", debugstr_guid(riid), stubmgr->object);
1324 hres = IUnknown_QueryInterface(stubmgr->object, riid, ppv);
1326 /* unref the ifstub. FIXME: only do this on success? */
1327 if (!stub_manager_is_table_marshaled(stubmgr, &stdobjref.ipid))
1328 stub_manager_ext_release(stubmgr, stdobjref.cPublicRefs, TRUE);
1330 stub_manager_int_release(stubmgr);
1331 return hres;
1334 /* notify stub manager about unmarshal if process-local object.
1335 * note: if the oxid is not found then we and native will quite happily
1336 * ignore table marshaling and normal marshaling rules regarding number of
1337 * unmarshals, etc, but if you abuse these rules then your proxy could end
1338 * up returning RPC_E_DISCONNECTED. */
1339 if ((stub_apt = apartment_findfromoxid(stdobjref.oxid, TRUE)))
1341 if ((stubmgr = get_stub_manager(stub_apt, stdobjref.oid)))
1343 if (!stub_manager_notify_unmarshal(stubmgr, &stdobjref.ipid))
1344 hres = CO_E_OBJNOTCONNECTED;
1346 else
1348 WARN("Couldn't find object for OXID %s, OID %s, assuming disconnected\n",
1349 wine_dbgstr_longlong(stdobjref.oxid),
1350 wine_dbgstr_longlong(stdobjref.oid));
1351 hres = CO_E_OBJNOTCONNECTED;
1354 else
1355 TRACE("Treating unmarshal from OXID %s as inter-process\n",
1356 wine_dbgstr_longlong(stdobjref.oxid));
1358 if (hres == S_OK)
1359 hres = unmarshal_object(&stdobjref, apt, This->dwDestContext,
1360 This->pvDestContext, riid,
1361 stubmgr ? &stubmgr->oxid_info : NULL, ppv);
1363 if (stubmgr) stub_manager_int_release(stubmgr);
1364 if (stub_apt) apartment_release(stub_apt);
1366 if (hres) WARN("Failed with error 0x%08x\n", hres);
1367 else TRACE("Successfully created proxy %p\n", *ppv);
1369 return hres;
1372 static HRESULT WINAPI
1373 StdMarshalImpl_ReleaseMarshalData(LPMARSHAL iface, IStream *pStm)
1375 STDOBJREF stdobjref;
1376 ULONG res;
1377 HRESULT hres;
1378 struct stub_manager *stubmgr;
1379 APARTMENT *apt;
1381 TRACE("iface=%p, pStm=%p\n", iface, pStm);
1383 hres = IStream_Read(pStm, &stdobjref, sizeof(stdobjref), &res);
1384 if (hres) return STG_E_READFAULT;
1386 TRACE("oxid = %s, oid = %s, ipid = %s\n",
1387 wine_dbgstr_longlong(stdobjref.oxid),
1388 wine_dbgstr_longlong(stdobjref.oid),
1389 wine_dbgstr_guid(&stdobjref.ipid));
1391 if (!(apt = apartment_findfromoxid(stdobjref.oxid, TRUE)))
1393 WARN("Could not map OXID %s to apartment object\n",
1394 wine_dbgstr_longlong(stdobjref.oxid));
1395 return RPC_E_INVALID_OBJREF;
1398 if (!(stubmgr = get_stub_manager(apt, stdobjref.oid)))
1400 ERR("could not map object ID to stub manager, oxid=%s, oid=%s\n",
1401 wine_dbgstr_longlong(stdobjref.oxid), wine_dbgstr_longlong(stdobjref.oid));
1402 return RPC_E_INVALID_OBJREF;
1405 stub_manager_release_marshal_data(stubmgr, stdobjref.cPublicRefs, &stdobjref.ipid);
1407 stub_manager_int_release(stubmgr);
1408 apartment_release(apt);
1410 return S_OK;
1413 static HRESULT WINAPI
1414 StdMarshalImpl_DisconnectObject(LPMARSHAL iface, DWORD dwReserved)
1416 FIXME("(), stub!\n");
1417 return S_OK;
1420 static const IMarshalVtbl VT_StdMarshal =
1422 StdMarshalImpl_QueryInterface,
1423 StdMarshalImpl_AddRef,
1424 StdMarshalImpl_Release,
1425 StdMarshalImpl_GetUnmarshalClass,
1426 StdMarshalImpl_GetMarshalSizeMax,
1427 StdMarshalImpl_MarshalInterface,
1428 StdMarshalImpl_UnmarshalInterface,
1429 StdMarshalImpl_ReleaseMarshalData,
1430 StdMarshalImpl_DisconnectObject
1433 static HRESULT StdMarshalImpl_Construct(REFIID riid, void** ppvObject)
1435 StdMarshalImpl * pStdMarshal =
1436 HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(StdMarshalImpl));
1437 if (!pStdMarshal)
1438 return E_OUTOFMEMORY;
1439 pStdMarshal->lpvtbl = &VT_StdMarshal;
1440 pStdMarshal->ref = 0;
1441 return IMarshal_QueryInterface((IMarshal*)pStdMarshal, riid, ppvObject);
1444 /***********************************************************************
1445 * CoGetStandardMarshal [OLE32.@]
1447 * Gets or creates a standard marshal object.
1449 * PARAMS
1450 * riid [I] Interface identifier of the pUnk object.
1451 * pUnk [I] Optional. Object to get the marshal object for.
1452 * dwDestContext [I] Destination. Used to enable or disable optimizations.
1453 * pvDestContext [I] Reserved. Must be NULL.
1454 * mshlflags [I] Flags affecting the marshaling process.
1455 * ppMarshal [O] Address where marshal object will be stored.
1457 * RETURNS
1458 * Success: S_OK.
1459 * Failure: HRESULT code.
1461 * NOTES
1463 * The function retrieves the IMarshal object associated with an object if
1464 * that object is currently an active stub, otherwise a new marshal object is
1465 * created.
1467 HRESULT WINAPI CoGetStandardMarshal(REFIID riid, IUnknown *pUnk,
1468 DWORD dwDestContext, LPVOID pvDestContext,
1469 DWORD mshlflags, LPMARSHAL *ppMarshal)
1471 StdMarshalImpl *dm;
1473 if (pUnk == NULL)
1475 FIXME("(%s,NULL,%x,%p,%x,%p), unimplemented yet.\n",
1476 debugstr_guid(riid),dwDestContext,pvDestContext,mshlflags,ppMarshal);
1477 return E_NOTIMPL;
1479 TRACE("(%s,%p,%x,%p,%x,%p)\n",
1480 debugstr_guid(riid),pUnk,dwDestContext,pvDestContext,mshlflags,ppMarshal);
1481 *ppMarshal = HeapAlloc(GetProcessHeap(),0,sizeof(StdMarshalImpl));
1482 dm = (StdMarshalImpl*) *ppMarshal;
1483 if (!dm) return E_FAIL;
1484 dm->lpvtbl = &VT_StdMarshal;
1485 dm->ref = 1;
1487 dm->iid = *riid;
1488 dm->dwDestContext = dwDestContext;
1489 dm->pvDestContext = pvDestContext;
1490 dm->mshlflags = mshlflags;
1491 return S_OK;
1494 /***********************************************************************
1495 * get_marshaler [internal]
1497 * Retrieves an IMarshal interface for an object.
1499 static HRESULT get_marshaler(REFIID riid, IUnknown *pUnk, DWORD dwDestContext,
1500 void *pvDestContext, DWORD mshlFlags,
1501 LPMARSHAL *pMarshal)
1503 HRESULT hr;
1505 if (!pUnk)
1506 return E_POINTER;
1507 hr = IUnknown_QueryInterface(pUnk, &IID_IMarshal, (LPVOID*)pMarshal);
1508 if (hr)
1509 hr = CoGetStandardMarshal(riid, pUnk, dwDestContext, pvDestContext,
1510 mshlFlags, pMarshal);
1511 return hr;
1514 /***********************************************************************
1515 * get_unmarshaler_from_stream [internal]
1517 * Creates an IMarshal* object according to the data marshaled to the stream.
1518 * The function leaves the stream pointer at the start of the data written
1519 * to the stream by the IMarshal* object.
1521 static HRESULT get_unmarshaler_from_stream(IStream *stream, IMarshal **marshal, IID *iid)
1523 HRESULT hr;
1524 ULONG res;
1525 OBJREF objref;
1527 /* read common OBJREF header */
1528 hr = IStream_Read(stream, &objref, FIELD_OFFSET(OBJREF, u_objref), &res);
1529 if (hr || (res != FIELD_OFFSET(OBJREF, u_objref)))
1531 ERR("Failed to read common OBJREF header, 0x%08x\n", hr);
1532 return STG_E_READFAULT;
1535 /* sanity check on header */
1536 if (objref.signature != OBJREF_SIGNATURE)
1538 ERR("Bad OBJREF signature 0x%08lx\n", objref.signature);
1539 return RPC_E_INVALID_OBJREF;
1542 if (iid) *iid = objref.iid;
1544 /* FIXME: handler marshaling */
1545 if (objref.flags & OBJREF_STANDARD)
1547 TRACE("Using standard unmarshaling\n");
1548 hr = StdMarshalImpl_Construct(&IID_IMarshal, (LPVOID*)marshal);
1550 else if (objref.flags & OBJREF_CUSTOM)
1552 ULONG custom_header_size = FIELD_OFFSET(OBJREF, u_objref.u_custom.pData) -
1553 FIELD_OFFSET(OBJREF, u_objref.u_custom);
1554 TRACE("Using custom unmarshaling\n");
1555 /* read constant sized OR_CUSTOM data from stream */
1556 hr = IStream_Read(stream, &objref.u_objref.u_custom,
1557 custom_header_size, &res);
1558 if (hr || (res != custom_header_size))
1560 ERR("Failed to read OR_CUSTOM header, 0x%08x\n", hr);
1561 return STG_E_READFAULT;
1563 /* now create the marshaler specified in the stream */
1564 hr = CoCreateInstance(&objref.u_objref.u_custom.clsid, NULL,
1565 CLSCTX_INPROC_SERVER, &IID_IMarshal,
1566 (LPVOID*)marshal);
1568 else
1570 FIXME("Invalid or unimplemented marshaling type specified: %lx\n",
1571 objref.flags);
1572 return RPC_E_INVALID_OBJREF;
1575 if (hr)
1576 ERR("Failed to create marshal, 0x%08x\n", hr);
1578 return hr;
1581 /***********************************************************************
1582 * CoGetMarshalSizeMax [OLE32.@]
1584 * Gets the maximum amount of data that will be needed by a marshal.
1586 * PARAMS
1587 * pulSize [O] Address where maximum marshal size will be stored.
1588 * riid [I] Identifier of the interface to marshal.
1589 * pUnk [I] Pointer to the object to marshal.
1590 * dwDestContext [I] Destination. Used to enable or disable optimizations.
1591 * pvDestContext [I] Reserved. Must be NULL.
1592 * mshlFlags [I] Flags that affect the marshaling. See CoMarshalInterface().
1594 * RETURNS
1595 * Success: S_OK.
1596 * Failure: HRESULT code.
1598 * SEE ALSO
1599 * CoMarshalInterface().
1601 HRESULT WINAPI CoGetMarshalSizeMax(ULONG *pulSize, REFIID riid, IUnknown *pUnk,
1602 DWORD dwDestContext, void *pvDestContext,
1603 DWORD mshlFlags)
1605 HRESULT hr;
1606 LPMARSHAL pMarshal;
1607 CLSID marshaler_clsid;
1609 hr = get_marshaler(riid, pUnk, dwDestContext, pvDestContext, mshlFlags, &pMarshal);
1610 if (hr)
1611 return hr;
1613 hr = IMarshal_GetUnmarshalClass(pMarshal, riid, pUnk, dwDestContext,
1614 pvDestContext, mshlFlags, &marshaler_clsid);
1615 if (hr)
1617 ERR("IMarshal::GetUnmarshalClass failed, 0x%08x\n", hr);
1618 IMarshal_Release(pMarshal);
1619 return hr;
1622 hr = IMarshal_GetMarshalSizeMax(pMarshal, riid, pUnk, dwDestContext,
1623 pvDestContext, mshlFlags, pulSize);
1624 if (IsEqualCLSID(&marshaler_clsid, &CLSID_DfMarshal))
1625 /* add on the size of the common header */
1626 *pulSize += FIELD_OFFSET(OBJREF, u_objref);
1627 else
1628 /* custom marshaling: add on the size of the whole OBJREF structure
1629 * like native does */
1630 *pulSize += sizeof(OBJREF);
1632 IMarshal_Release(pMarshal);
1633 return hr;
1637 static void dump_MSHLFLAGS(MSHLFLAGS flags)
1639 if (flags & MSHLFLAGS_TABLESTRONG)
1640 TRACE(" MSHLFLAGS_TABLESTRONG");
1641 if (flags & MSHLFLAGS_TABLEWEAK)
1642 TRACE(" MSHLFLAGS_TABLEWEAK");
1643 if (!(flags & (MSHLFLAGS_TABLESTRONG|MSHLFLAGS_TABLEWEAK)))
1644 TRACE(" MSHLFLAGS_NORMAL");
1645 if (flags & MSHLFLAGS_NOPING)
1646 TRACE(" MSHLFLAGS_NOPING");
1649 /***********************************************************************
1650 * CoMarshalInterface [OLE32.@]
1652 * Marshals an interface into a stream so that the object can then be
1653 * unmarshaled from another COM apartment and used remotely.
1655 * PARAMS
1656 * pStream [I] Stream the object will be marshaled into.
1657 * riid [I] Identifier of the interface to marshal.
1658 * pUnk [I] Pointer to the object to marshal.
1659 * dwDestContext [I] Destination. Used to enable or disable optimizations.
1660 * pvDestContext [I] Reserved. Must be NULL.
1661 * mshlFlags [I] Flags that affect the marshaling. See notes.
1663 * RETURNS
1664 * Success: S_OK.
1665 * Failure: HRESULT code.
1667 * NOTES
1669 * The mshlFlags parameter can take one or more of the following flags:
1670 *| MSHLFLAGS_NORMAL - Unmarshal once, releases stub on last proxy release.
1671 *| MSHLFLAGS_TABLESTRONG - Unmarshal many, release when CoReleaseMarshalData() called.
1672 *| MSHLFLAGS_TABLEWEAK - Unmarshal many, releases stub on last proxy release.
1673 *| MSHLFLAGS_NOPING - No automatic garbage collection (and so reduces network traffic).
1675 * If a marshaled object is not unmarshaled, then CoReleaseMarshalData() must
1676 * be called in order to release the resources used in the marshaling.
1678 * SEE ALSO
1679 * CoUnmarshalInterface(), CoReleaseMarshalData().
1681 HRESULT WINAPI CoMarshalInterface(IStream *pStream, REFIID riid, IUnknown *pUnk,
1682 DWORD dwDestContext, void *pvDestContext,
1683 DWORD mshlFlags)
1685 HRESULT hr;
1686 CLSID marshaler_clsid;
1687 OBJREF objref;
1688 LPMARSHAL pMarshal;
1690 TRACE("(%p, %s, %p, %x, %p,", pStream, debugstr_guid(riid), pUnk,
1691 dwDestContext, pvDestContext);
1692 dump_MSHLFLAGS(mshlFlags);
1693 TRACE(")\n");
1695 if (!pUnk || !pStream)
1696 return E_INVALIDARG;
1698 objref.signature = OBJREF_SIGNATURE;
1699 objref.iid = *riid;
1701 /* get the marshaler for the specified interface */
1702 hr = get_marshaler(riid, pUnk, dwDestContext, pvDestContext, mshlFlags, &pMarshal);
1703 if (hr)
1705 ERR("Failed to get marshaller, 0x%08x\n", hr);
1706 return hr;
1709 hr = IMarshal_GetUnmarshalClass(pMarshal, riid, pUnk, dwDestContext,
1710 pvDestContext, mshlFlags, &marshaler_clsid);
1711 if (hr)
1713 ERR("IMarshal::GetUnmarshalClass failed, 0x%08x\n", hr);
1714 goto cleanup;
1717 /* FIXME: implement handler marshaling too */
1718 if (IsEqualCLSID(&marshaler_clsid, &CLSID_DfMarshal))
1720 TRACE("Using standard marshaling\n");
1721 objref.flags = OBJREF_STANDARD;
1723 /* write the common OBJREF header to the stream */
1724 hr = IStream_Write(pStream, &objref, FIELD_OFFSET(OBJREF, u_objref), NULL);
1725 if (hr)
1727 ERR("Failed to write OBJREF header to stream, 0x%08x\n", hr);
1728 goto cleanup;
1731 else
1733 TRACE("Using custom marshaling\n");
1734 objref.flags = OBJREF_CUSTOM;
1735 objref.u_objref.u_custom.clsid = marshaler_clsid;
1736 objref.u_objref.u_custom.cbExtension = 0;
1737 objref.u_objref.u_custom.size = 0;
1738 hr = IMarshal_GetMarshalSizeMax(pMarshal, riid, pUnk, dwDestContext,
1739 pvDestContext, mshlFlags,
1740 &objref.u_objref.u_custom.size);
1741 if (hr)
1743 ERR("Failed to get max size of marshal data, error 0x%08x\n", hr);
1744 goto cleanup;
1746 /* write constant sized common header and OR_CUSTOM data into stream */
1747 hr = IStream_Write(pStream, &objref,
1748 FIELD_OFFSET(OBJREF, u_objref.u_custom.pData), NULL);
1749 if (hr)
1751 ERR("Failed to write OR_CUSTOM header to stream with 0x%08x\n", hr);
1752 goto cleanup;
1756 TRACE("Calling IMarshal::MarshalInterace\n");
1757 /* call helper object to do the actual marshaling */
1758 hr = IMarshal_MarshalInterface(pMarshal, pStream, riid, pUnk, dwDestContext,
1759 pvDestContext, mshlFlags);
1761 if (hr)
1763 ERR("Failed to marshal the interface %s, %x\n", debugstr_guid(riid), hr);
1764 goto cleanup;
1767 cleanup:
1768 IMarshal_Release(pMarshal);
1770 TRACE("completed with hr 0x%08x\n", hr);
1772 return hr;
1775 /***********************************************************************
1776 * CoUnmarshalInterface [OLE32.@]
1778 * Unmarshals an object from a stream by creating a proxy to the remote
1779 * object, if necessary.
1781 * PARAMS
1783 * pStream [I] Stream containing the marshaled object.
1784 * riid [I] Interface identifier of the object to create a proxy to.
1785 * ppv [O] Address where proxy will be stored.
1787 * RETURNS
1789 * Success: S_OK.
1790 * Failure: HRESULT code.
1792 * SEE ALSO
1793 * CoMarshalInterface().
1795 HRESULT WINAPI CoUnmarshalInterface(IStream *pStream, REFIID riid, LPVOID *ppv)
1797 HRESULT hr;
1798 LPMARSHAL pMarshal;
1799 IID iid;
1800 IUnknown *object;
1802 TRACE("(%p, %s, %p)\n", pStream, debugstr_guid(riid), ppv);
1804 if (!pStream || !ppv)
1805 return E_INVALIDARG;
1807 hr = get_unmarshaler_from_stream(pStream, &pMarshal, &iid);
1808 if (hr != S_OK)
1809 return hr;
1811 /* call the helper object to do the actual unmarshaling */
1812 hr = IMarshal_UnmarshalInterface(pMarshal, pStream, &iid, (LPVOID*)&object);
1813 if (hr)
1814 ERR("IMarshal::UnmarshalInterface failed, 0x%08x\n", hr);
1816 if (hr == S_OK)
1818 /* IID_NULL means use the interface ID of the marshaled object */
1819 if (!IsEqualIID(riid, &IID_NULL) && !IsEqualIID(riid, &iid))
1821 TRACE("requested interface != marshalled interface, additional QI needed\n");
1822 hr = IUnknown_QueryInterface(object, riid, ppv);
1823 if (hr)
1824 ERR("Couldn't query for interface %s, hr = 0x%08x\n",
1825 debugstr_guid(riid), hr);
1826 IUnknown_Release(object);
1828 else
1830 *ppv = object;
1834 IMarshal_Release(pMarshal);
1836 TRACE("completed with hr 0x%x\n", hr);
1838 return hr;
1841 /***********************************************************************
1842 * CoReleaseMarshalData [OLE32.@]
1844 * Releases resources associated with an object that has been marshaled into
1845 * a stream.
1847 * PARAMS
1849 * pStream [I] The stream that the object has been marshaled into.
1851 * RETURNS
1852 * Success: S_OK.
1853 * Failure: HRESULT error code.
1855 * NOTES
1857 * Call this function to release resources associated with a normal or
1858 * table-weak marshal that will not be unmarshaled, and all table-strong
1859 * marshals when they are no longer needed.
1861 * SEE ALSO
1862 * CoMarshalInterface(), CoUnmarshalInterface().
1864 HRESULT WINAPI CoReleaseMarshalData(IStream *pStream)
1866 HRESULT hr;
1867 LPMARSHAL pMarshal;
1869 TRACE("(%p)\n", pStream);
1871 hr = get_unmarshaler_from_stream(pStream, &pMarshal, NULL);
1872 if (hr != S_OK)
1873 return hr;
1875 /* call the helper object to do the releasing of marshal data */
1876 hr = IMarshal_ReleaseMarshalData(pMarshal, pStream);
1877 if (hr)
1878 ERR("IMarshal::ReleaseMarshalData failed with error 0x%08x\n", hr);
1880 IMarshal_Release(pMarshal);
1881 return hr;
1885 /***********************************************************************
1886 * CoMarshalInterThreadInterfaceInStream [OLE32.@]
1888 * Marshal an interface across threads in the same process.
1890 * PARAMS
1891 * riid [I] Identifier of the interface to be marshalled.
1892 * pUnk [I] Pointer to IUnknown-derived interface that will be marshalled.
1893 * ppStm [O] Pointer to IStream object that is created and then used to store the marshalled interface.
1895 * RETURNS
1896 * Success: S_OK
1897 * Failure: E_OUTOFMEMORY and other COM error codes
1899 * SEE ALSO
1900 * CoMarshalInterface(), CoUnmarshalInterface() and CoGetInterfaceAndReleaseStream()
1902 HRESULT WINAPI CoMarshalInterThreadInterfaceInStream(
1903 REFIID riid, LPUNKNOWN pUnk, LPSTREAM * ppStm)
1905 ULARGE_INTEGER xpos;
1906 LARGE_INTEGER seekto;
1907 HRESULT hres;
1909 TRACE("(%s, %p, %p)\n",debugstr_guid(riid), pUnk, ppStm);
1911 hres = CreateStreamOnHGlobal(NULL, TRUE, ppStm);
1912 if (FAILED(hres)) return hres;
1913 hres = CoMarshalInterface(*ppStm, riid, pUnk, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1915 if (SUCCEEDED(hres))
1917 memset(&seekto, 0, sizeof(seekto));
1918 IStream_Seek(*ppStm, seekto, STREAM_SEEK_SET, &xpos);
1920 else
1922 IStream_Release(*ppStm);
1923 *ppStm = NULL;
1926 return hres;
1929 /***********************************************************************
1930 * CoGetInterfaceAndReleaseStream [OLE32.@]
1932 * Unmarshalls an interface from a stream and then releases the stream.
1934 * PARAMS
1935 * pStm [I] Stream that contains the marshalled interface.
1936 * riid [I] Interface identifier of the object to unmarshall.
1937 * ppv [O] Address of pointer where the requested interface object will be stored.
1939 * RETURNS
1940 * Success: S_OK
1941 * Failure: A COM error code
1943 * SEE ALSO
1944 * CoMarshalInterThreadInterfaceInStream() and CoUnmarshalInterface()
1946 HRESULT WINAPI CoGetInterfaceAndReleaseStream(LPSTREAM pStm, REFIID riid,
1947 LPVOID *ppv)
1949 HRESULT hres;
1951 TRACE("(%p, %s, %p)\n", pStm, debugstr_guid(riid), ppv);
1953 if(!pStm) return E_INVALIDARG;
1954 hres = CoUnmarshalInterface(pStm, riid, ppv);
1955 IStream_Release(pStm);
1956 return hres;
1959 static HRESULT WINAPI StdMarshalCF_QueryInterface(LPCLASSFACTORY iface,
1960 REFIID riid, LPVOID *ppv)
1962 *ppv = NULL;
1963 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IClassFactory))
1965 *ppv = (LPVOID)iface;
1966 return S_OK;
1968 return E_NOINTERFACE;
1971 static ULONG WINAPI StdMarshalCF_AddRef(LPCLASSFACTORY iface)
1973 return 2; /* non-heap based object */
1976 static ULONG WINAPI StdMarshalCF_Release(LPCLASSFACTORY iface)
1978 return 1; /* non-heap based object */
1981 static HRESULT WINAPI StdMarshalCF_CreateInstance(LPCLASSFACTORY iface,
1982 LPUNKNOWN pUnk, REFIID riid, LPVOID *ppv)
1984 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IMarshal))
1985 return StdMarshalImpl_Construct(riid, ppv);
1987 FIXME("(%s), not supported.\n",debugstr_guid(riid));
1988 return E_NOINTERFACE;
1991 static HRESULT WINAPI StdMarshalCF_LockServer(LPCLASSFACTORY iface, BOOL fLock)
1993 FIXME("(%d), stub!\n",fLock);
1994 return S_OK;
1997 static const IClassFactoryVtbl StdMarshalCFVtbl =
1999 StdMarshalCF_QueryInterface,
2000 StdMarshalCF_AddRef,
2001 StdMarshalCF_Release,
2002 StdMarshalCF_CreateInstance,
2003 StdMarshalCF_LockServer
2005 static const IClassFactoryVtbl *StdMarshalCF = &StdMarshalCFVtbl;
2007 HRESULT MARSHAL_GetStandardMarshalCF(LPVOID *ppv)
2009 *ppv = &StdMarshalCF;
2010 return S_OK;
2013 /***********************************************************************
2014 * CoMarshalHresult [OLE32.@]
2016 * Marshals an HRESULT value into a stream.
2018 * PARAMS
2019 * pStm [I] Stream that hresult will be marshalled into.
2020 * hresult [I] HRESULT to be marshalled.
2022 * RETURNS
2023 * Success: S_OK
2024 * Failure: A COM error code
2026 * SEE ALSO
2027 * CoUnmarshalHresult().
2029 HRESULT WINAPI CoMarshalHresult(LPSTREAM pStm, HRESULT hresult)
2031 return IStream_Write(pStm, &hresult, sizeof(hresult), NULL);
2034 /***********************************************************************
2035 * CoUnmarshalHresult [OLE32.@]
2037 * Unmarshals an HRESULT value from a stream.
2039 * PARAMS
2040 * pStm [I] Stream that hresult will be unmarshalled from.
2041 * phresult [I] Pointer to HRESULT where the value will be unmarshalled to.
2043 * RETURNS
2044 * Success: S_OK
2045 * Failure: A COM error code
2047 * SEE ALSO
2048 * CoMarshalHresult().
2050 HRESULT WINAPI CoUnmarshalHresult(LPSTREAM pStm, HRESULT * phresult)
2052 return IStream_Read(pStm, phresult, sizeof(*phresult), NULL);