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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
42 #include "wine/unicode.h"
44 #include "compobj_private.h"
46 #include "wine/debug.h"
48 WINE_DEFAULT_DEBUG_CHANNEL(ole);
50 extern const CLSID CLSID_DfMarshal;
52 /* number of refs given out for normal marshaling */
53 #define NORMALEXTREFS 1 /* FIXME: this should be 5, but we have to wait for IRemUnknown support first */
55 /* private flag indicating that the caller does not want to notify the stub
56 * when the proxy disconnects or is destroyed */
57 #define SORFP_NOLIFETIMEMGMT SORF_OXRES1
59 static HRESULT unmarshal_object(const STDOBJREF *stdobjref, APARTMENT *apt, REFIID riid, void **object);
61 /* Marshalling just passes a unique identifier to the remote client,
62 * that makes it possible to find the passed interface again.
64 * So basically we need a set of values that make it unique.
66 * Note that the IUnknown_QI(ob,xiid,&ppv) always returns the SAME ppv value!
68 * A triple is used: OXID (apt id), OID (stub manager id),
69 * IPID (interface ptr/stub id).
71 * OXIDs identify an apartment and are network scoped
72 * OIDs identify a stub manager and are apartment scoped
73 * IPIDs identify an interface stub and are apartment scoped
76 inline static HRESULT get_facbuf_for_iid(REFIID riid, IPSFactoryBuffer **facbuf)
81 if ((hr = CoGetPSClsid(riid, &clsid)))
83 return CoGetClassObject(&clsid, CLSCTX_INPROC_SERVER, NULL,
84 &IID_IPSFactoryBuffer, (LPVOID*)facbuf);
87 /* creates a new stub manager */
88 HRESULT marshal_object(APARTMENT *apt, STDOBJREF *stdobjref, REFIID riid, IUnknown *object, MSHLFLAGS mshlflags)
90 struct stub_manager *manager;
91 struct ifstub *ifstub;
93 IRpcStubBuffer *stub = NULL;
95 IUnknown *iobject = NULL; /* object of type riid */
97 hr = apartment_getoxid(apt, &stdobjref->oxid);
101 hr = IUnknown_QueryInterface(object, riid, (void **)&iobject);
104 ERR("object doesn't expose interface %s, failing with error 0x%08lx\n",
105 debugstr_guid(riid), hr);
106 return E_NOINTERFACE;
109 /* IUnknown doesn't require a stub buffer, because it never goes out on
111 if (!IsEqualIID(riid, &IID_IUnknown))
113 IPSFactoryBuffer *psfb;
115 hr = get_facbuf_for_iid(riid, &psfb);
118 ERR("couldn't get IPSFactory buffer for interface %s\n", debugstr_guid(riid));
119 IUnknown_Release(iobject);
123 hr = IPSFactoryBuffer_CreateStub(psfb, riid, iobject, &stub);
124 IPSFactoryBuffer_Release(psfb);
127 ERR("Failed to create an IRpcStubBuffer from IPSFactory for %s\n", debugstr_guid(riid));
128 IUnknown_Release(iobject);
133 if (mshlflags & MSHLFLAGS_NOPING)
134 stdobjref->flags = SORF_NOPING;
136 stdobjref->flags = SORF_NULL;
138 /* FIXME: what happens if we register an interface twice with different
139 * marshaling flags? */
140 if ((manager = get_stub_manager_from_object(apt, object)))
141 TRACE("registering new ifstub on pre-existing manager\n");
144 TRACE("constructing new stub manager\n");
146 manager = new_stub_manager(apt, object, mshlflags);
149 if (stub) IRpcStubBuffer_Release(stub);
150 IUnknown_Release(iobject);
151 return E_OUTOFMEMORY;
154 stdobjref->oid = manager->oid;
156 tablemarshal = ((mshlflags & MSHLFLAGS_TABLESTRONG) || (mshlflags & MSHLFLAGS_TABLEWEAK));
158 ifstub = stub_manager_new_ifstub(manager, stub, iobject, riid);
159 IUnknown_Release(iobject);
160 if (stub) IRpcStubBuffer_Release(stub);
163 stub_manager_int_release(manager);
164 /* FIXME: should we do another release to completely destroy the
166 return E_OUTOFMEMORY;
171 stdobjref->cPublicRefs = NORMALEXTREFS;
172 stub_manager_ext_addref(manager, stdobjref->cPublicRefs);
176 stdobjref->cPublicRefs = 0;
177 if (mshlflags & MSHLFLAGS_TABLESTRONG)
178 stub_manager_ext_addref(manager, 1);
181 /* FIXME: check return value */
182 RPC_RegisterInterface(riid);
184 stdobjref->ipid = ifstub->ipid;
186 stub_manager_int_release(manager);
192 /* Client-side identity of the server object */
194 static HRESULT proxy_manager_get_remunknown(struct proxy_manager * This, IRemUnknown **remunk);
195 static void proxy_manager_destroy(struct proxy_manager * This);
196 static HRESULT proxy_manager_find_ifproxy(struct proxy_manager * This, REFIID riid, struct ifproxy ** ifproxy_found);
197 static HRESULT proxy_manager_query_local_interface(struct proxy_manager * This, REFIID riid, void ** ppv);
199 static HRESULT WINAPI ClientIdentity_QueryInterface(IMultiQI * iface, REFIID riid, void ** ppv)
204 TRACE("%s\n", debugstr_guid(riid));
207 hr = IMultiQI_QueryMultipleInterfaces(iface, 1, &mqi);
208 *ppv = (void *)mqi.pItf;
213 static ULONG WINAPI ClientIdentity_AddRef(IMultiQI * iface)
215 struct proxy_manager * This = (struct proxy_manager *)iface;
216 TRACE("%p - before %ld\n", iface, This->refs);
217 return InterlockedIncrement(&This->refs);
220 static ULONG WINAPI ClientIdentity_Release(IMultiQI * iface)
222 struct proxy_manager * This = (struct proxy_manager *)iface;
223 ULONG refs = InterlockedDecrement(&This->refs);
224 TRACE("%p - after %ld\n", iface, refs);
226 proxy_manager_destroy(This);
230 static HRESULT WINAPI ClientIdentity_QueryMultipleInterfaces(IMultiQI *iface, ULONG cMQIs, MULTI_QI *pMQIs)
232 struct proxy_manager * This = (struct proxy_manager *)iface;
233 REMQIRESULT *qiresults = NULL;
234 ULONG nonlocal_mqis = 0;
236 ULONG successful_mqis = 0;
237 IID *iids = HeapAlloc(GetProcessHeap(), 0, cMQIs * sizeof(*iids));
238 /* mapping of RemQueryInterface index to QueryMultipleInterfaces index */
239 ULONG *mapping = HeapAlloc(GetProcessHeap(), 0, cMQIs * sizeof(*mapping));
241 TRACE("cMQIs: %ld\n", cMQIs);
243 /* try to get a local interface - this includes already active proxy
244 * interfaces and also interfaces exposed by the proxy manager */
245 for (i = 0; i < cMQIs; i++)
247 TRACE("iid[%ld] = %s\n", i, debugstr_guid(pMQIs[i].pIID));
248 pMQIs[i].hr = proxy_manager_query_local_interface(This, pMQIs[i].pIID, (void **)&pMQIs[i].pItf);
249 if (pMQIs[i].hr == S_OK)
253 iids[nonlocal_mqis] = *pMQIs[i].pIID;
254 mapping[nonlocal_mqis] = i;
259 TRACE("%ld interfaces not found locally\n", nonlocal_mqis);
261 /* if we have more than one interface not found locally then we must try
262 * to query the remote object for it */
263 if (nonlocal_mqis != 0)
269 /* get the ipid of the first entry */
270 /* FIXME: should we implement ClientIdentity on the ifproxies instead
271 * of the proxy_manager so we use the correct ipid here? */
272 ipid = &LIST_ENTRY(list_head(&This->interfaces), struct ifproxy, entry)->ipid;
274 /* get IRemUnknown proxy so we can communicate with the remote object */
275 hr = proxy_manager_get_remunknown(This, &remunk);
279 hr = IRemUnknown_RemQueryInterface(remunk, ipid, NORMALEXTREFS,
280 nonlocal_mqis, iids, &qiresults);
282 ERR("IRemUnknown_RemQueryInterface failed with error 0x%08lx\n", hr);
285 /* IRemUnknown_RemQueryInterface can return S_FALSE if only some of
286 * the interfaces were returned */
289 /* try to unmarshal each object returned to us */
290 for (i = 0; i < nonlocal_mqis; i++)
292 ULONG index = mapping[i];
293 HRESULT hrobj = qiresults[i].hResult;
295 hrobj = unmarshal_object(&qiresults[i].std, This->parent,
297 (void **)&pMQIs[index].pItf);
302 ERR("Failed to get pointer to interface %s\n", debugstr_guid(pMQIs[index].pIID));
303 pMQIs[index].hr = hrobj;
307 /* free the memory allocated by the proxy */
308 CoTaskMemFree(qiresults);
311 TRACE("%ld/%ld successfully queried\n", successful_mqis, cMQIs);
313 HeapFree(GetProcessHeap(), 0, iids);
314 HeapFree(GetProcessHeap(), 0, mapping);
316 if (successful_mqis == cMQIs)
317 return S_OK; /* we got all requested interfaces */
318 else if (successful_mqis == 0)
319 return E_NOINTERFACE; /* we didn't get any interfaces */
321 return S_FALSE; /* we got some interfaces */
324 static const IMultiQIVtbl ClientIdentity_Vtbl =
326 ClientIdentity_QueryInterface,
327 ClientIdentity_AddRef,
328 ClientIdentity_Release,
329 ClientIdentity_QueryMultipleInterfaces
332 static HRESULT ifproxy_get_public_ref(struct ifproxy * This)
336 if (WAIT_OBJECT_0 != WaitForSingleObject(This->parent->remoting_mutex, INFINITE))
338 ERR("Wait failed for ifproxy %p\n", This);
344 IRemUnknown *remunk = NULL;
346 TRACE("getting public ref for ifproxy %p\n", This);
348 hr = proxy_manager_get_remunknown(This->parent, &remunk);
353 rif.ipid = This->ipid;
354 rif.cPublicRefs = NORMALEXTREFS;
355 rif.cPrivateRefs = 0;
356 hr = IRemUnknown_RemAddRef(remunk, 1, &rif, &hrref);
357 if (hr == S_OK && hrref == S_OK)
358 This->refs += NORMALEXTREFS;
360 ERR("IRemUnknown_RemAddRef returned with 0x%08lx, hrref = 0x%08lx\n", hr, hrref);
363 ReleaseMutex(This->parent->remoting_mutex);
368 static HRESULT ifproxy_release_public_refs(struct ifproxy * This)
372 if (WAIT_OBJECT_0 != WaitForSingleObject(This->parent->remoting_mutex, INFINITE))
374 ERR("Wait failed for ifproxy %p\n", This);
380 IRemUnknown *remunk = NULL;
382 TRACE("releasing %ld refs\n", This->refs);
384 hr = proxy_manager_get_remunknown(This->parent, &remunk);
388 rif.ipid = This->ipid;
389 rif.cPublicRefs = This->refs;
390 rif.cPrivateRefs = 0;
391 hr = IRemUnknown_RemRelease(remunk, 1, &rif);
394 else if (hr == RPC_E_DISCONNECTED)
395 WARN("couldn't release references because object was "
396 "disconnected: oxid = %s, oid = %s\n",
397 wine_dbgstr_longlong(This->parent->oxid),
398 wine_dbgstr_longlong(This->parent->oid));
400 ERR("IRemUnknown_RemRelease failed with error 0x%08lx\n", hr);
403 ReleaseMutex(This->parent->remoting_mutex);
408 /* should be called inside This->parent->cs critical section */
409 static void ifproxy_disconnect(struct ifproxy * This)
411 ifproxy_release_public_refs(This);
412 if (This->proxy) IRpcProxyBuffer_Disconnect(This->proxy);
414 IRpcChannelBuffer_Release(This->chan);
418 /* should be called in This->parent->cs critical section if it is an entry in parent's list */
419 static void ifproxy_destroy(struct ifproxy * This)
423 /* release public references to this object so that the stub can know
424 * when to destroy itself */
425 ifproxy_release_public_refs(This);
427 list_remove(&This->entry);
431 IRpcChannelBuffer_Release(This->chan);
435 /* note: we don't call Release for This->proxy because its lifetime is
436 * controlled by the return value from ClientIdentity_Release, which this
437 * function is always called from */
439 HeapFree(GetProcessHeap(), 0, This);
442 static HRESULT proxy_manager_construct(
443 APARTMENT * apt, ULONG sorflags, OXID oxid, OID oid,
444 struct proxy_manager ** proxy_manager)
446 struct proxy_manager * This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
447 if (!This) return E_OUTOFMEMORY;
449 This->remoting_mutex = CreateMutexW(NULL, FALSE, NULL);
450 if (!This->remoting_mutex)
452 HeapFree(GetProcessHeap(), 0, This);
453 return HRESULT_FROM_WIN32(GetLastError());
456 This->lpVtbl = &ClientIdentity_Vtbl;
458 list_init(&This->entry);
459 list_init(&This->interfaces);
461 InitializeCriticalSection(&This->cs);
462 DEBUG_SET_CRITSEC_NAME(&This->cs, "proxy_manager");
464 /* the apartment the object was unmarshaled into */
467 /* the source apartment and id of the object */
473 /* the DCOM draft specification states that the SORF_NOPING flag is
474 * proxy manager specific, not ifproxy specific, so this implies that we
475 * should store the STDOBJREF flags here in the proxy manager. */
476 This->sorflags = sorflags;
478 /* we create the IRemUnknown proxy on demand */
481 EnterCriticalSection(&apt->cs);
482 /* FIXME: we are dependent on the ordering in here to make sure a proxy's
483 * IRemUnknown proxy doesn't get destroyed before the regual proxy does
484 * because we need the IRemUnknown proxy during the destruction of the
485 * regular proxy. Ideally, we should maintain a separate list for the
486 * IRemUnknown proxies that need late destruction */
487 list_add_tail(&apt->proxies, &This->entry);
488 LeaveCriticalSection(&apt->cs);
490 TRACE("%p created for OXID %s, OID %s\n", This,
491 wine_dbgstr_longlong(oxid), wine_dbgstr_longlong(oid));
493 *proxy_manager = This;
497 static HRESULT proxy_manager_query_local_interface(struct proxy_manager * This, REFIID riid, void ** ppv)
500 struct ifproxy * ifproxy;
502 TRACE("%s\n", debugstr_guid(riid));
504 if (IsEqualIID(riid, &IID_IUnknown) ||
505 IsEqualIID(riid, &IID_IMultiQI))
507 *ppv = (void *)&This->lpVtbl;
508 IMultiQI_AddRef((IMultiQI *)&This->lpVtbl);
512 hr = proxy_manager_find_ifproxy(This, riid, &ifproxy);
515 *ppv = ifproxy->iface;
516 IUnknown_AddRef((IUnknown *)*ppv);
521 return E_NOINTERFACE;
524 static HRESULT proxy_manager_create_ifproxy(
525 struct proxy_manager * This, const IPID *ipid, REFIID riid, ULONG cPublicRefs,
526 IRpcChannelBuffer * channel, struct ifproxy ** iif_out)
529 IPSFactoryBuffer * psfb;
530 struct ifproxy * ifproxy = HeapAlloc(GetProcessHeap(), 0, sizeof(*ifproxy));
531 if (!ifproxy) return E_OUTOFMEMORY;
533 list_init(&ifproxy->entry);
535 ifproxy->parent = This;
536 ifproxy->ipid = *ipid;
537 ifproxy->iid = *riid;
538 ifproxy->refs = cPublicRefs;
539 ifproxy->proxy = NULL;
542 ifproxy->chan = channel; /* FIXME: we should take the binding strings and construct the channel in this function */
544 /* the IUnknown interface is special because it does not have a
545 * proxy associated with the ifproxy as we handle IUnknown ourselves */
546 if (IsEqualIID(riid, &IID_IUnknown))
548 ifproxy->iface = (void *)&This->lpVtbl;
553 hr = get_facbuf_for_iid(riid, &psfb);
556 /* important note: the outer unknown is set to the proxy manager.
557 * This ensures the COM identity rules are not violated, by having a
558 * one-to-one mapping of objects on the proxy side to objects on the
559 * stub side, no matter which interface you view the object through */
560 hr = IPSFactoryBuffer_CreateProxy(psfb, (IUnknown *)&This->lpVtbl, riid,
561 &ifproxy->proxy, &ifproxy->iface);
562 IPSFactoryBuffer_Release(psfb);
564 ERR("Could not create proxy for interface %s, error 0x%08lx\n",
565 debugstr_guid(riid), hr);
568 ERR("Could not get IPSFactoryBuffer for interface %s, error 0x%08lx\n",
569 debugstr_guid(riid), hr);
572 hr = IRpcProxyBuffer_Connect(ifproxy->proxy, ifproxy->chan);
575 /* get at least one external reference to the object to keep it alive */
577 hr = ifproxy_get_public_ref(ifproxy);
581 EnterCriticalSection(&This->cs);
582 list_add_tail(&This->interfaces, &ifproxy->entry);
583 LeaveCriticalSection(&This->cs);
586 TRACE("ifproxy %p created for IPID %s, interface %s with %lu public refs\n",
587 ifproxy, debugstr_guid(ipid), debugstr_guid(riid), cPublicRefs);
590 ifproxy_destroy(ifproxy);
595 static HRESULT proxy_manager_find_ifproxy(struct proxy_manager * This, REFIID riid, struct ifproxy ** ifproxy_found)
597 HRESULT hr = E_NOINTERFACE; /* assume not found */
598 struct list * cursor;
600 EnterCriticalSection(&This->cs);
601 LIST_FOR_EACH(cursor, &This->interfaces)
603 struct ifproxy * ifproxy = LIST_ENTRY(cursor, struct ifproxy, entry);
604 if (IsEqualIID(riid, &ifproxy->iid))
606 *ifproxy_found = ifproxy;
611 LeaveCriticalSection(&This->cs);
616 static void proxy_manager_disconnect(struct proxy_manager * This)
618 struct list * cursor;
620 TRACE("oxid = %s, oid = %s\n", wine_dbgstr_longlong(This->oxid),
621 wine_dbgstr_longlong(This->oid));
623 /* SORFP_NOLIFTIMEMGMT proxies (for IRemUnknown) shouldn't be
624 * disconnected - it won't do anything anyway, except cause
625 * problems for other objects that depend on this proxy always
627 if (This->sorflags & SORFP_NOLIFETIMEMGMT) return;
629 EnterCriticalSection(&This->cs);
631 LIST_FOR_EACH(cursor, &This->interfaces)
633 struct ifproxy * ifproxy = LIST_ENTRY(cursor, struct ifproxy, entry);
634 ifproxy_disconnect(ifproxy);
637 /* apartment is being destroyed so don't keep a pointer around to it */
640 LeaveCriticalSection(&This->cs);
643 static HRESULT proxy_manager_get_remunknown(struct proxy_manager * This, IRemUnknown **remunk)
647 /* we don't want to try and unmarshal or use IRemUnknown if we don't want
648 * lifetime management */
649 if (This->sorflags & SORFP_NOLIFETIMEMGMT)
652 EnterCriticalSection(&This->cs);
654 /* already created - return existing object */
655 *remunk = This->remunk;
656 else if (!This->parent)
657 /* disconnected - we can't create IRemUnknown */
662 /* Don't want IRemUnknown lifetime management as this is IRemUnknown!
663 * We also don't care about whether or not the stub is still alive */
664 stdobjref.flags = SORFP_NOLIFETIMEMGMT | SORF_NOPING;
665 stdobjref.cPublicRefs = 1;
666 /* oxid of destination object */
667 stdobjref.oxid = This->oxid;
668 /* FIXME: what should be used for the oid? The DCOM draft doesn't say */
669 stdobjref.oid = (OID)-1;
670 /* FIXME: this is a hack around not having an OXID resolver yet -
671 * the OXID resolver should give us the IPID of the IRemUnknown
673 stdobjref.ipid.Data1 = 0xffffffff;
674 stdobjref.ipid.Data2 = 0xffff;
675 stdobjref.ipid.Data3 = 0xffff;
676 assert(sizeof(stdobjref.ipid.Data4) == sizeof(stdobjref.oxid));
677 memcpy(&stdobjref.ipid.Data4, &stdobjref.oxid, sizeof(OXID));
679 /* do the unmarshal */
680 hr = unmarshal_object(&stdobjref, This->parent, &IID_IRemUnknown, (void**)&This->remunk);
682 *remunk = This->remunk;
684 LeaveCriticalSection(&This->cs);
686 TRACE("got IRemUnknown* pointer %p, hr = 0x%08lx\n", *remunk, hr);
691 /* destroys a proxy manager, freeing the memory it used.
692 * Note: this function should not be called from a list iteration in the
693 * apartment, due to the fact that it removes itself from the apartment and
694 * it could add a proxy to IRemUnknown into the apartment. */
695 static void proxy_manager_destroy(struct proxy_manager * This)
697 struct list * cursor;
699 TRACE("oxid = %s, oid = %s\n", wine_dbgstr_longlong(This->oxid),
700 wine_dbgstr_longlong(This->oid));
704 EnterCriticalSection(&This->parent->cs);
706 /* remove ourself from the list of proxy objects in the apartment */
707 LIST_FOR_EACH(cursor, &This->parent->proxies)
709 if (cursor == &This->entry)
711 list_remove(&This->entry);
716 LeaveCriticalSection(&This->parent->cs);
719 /* destroy all of the interface proxies */
720 while ((cursor = list_head(&This->interfaces)))
722 struct ifproxy * ifproxy = LIST_ENTRY(cursor, struct ifproxy, entry);
723 ifproxy_destroy(ifproxy);
726 if (This->remunk) IRemUnknown_Release(This->remunk);
728 DEBUG_CLEAR_CRITSEC_NAME(&This->cs);
729 DeleteCriticalSection(&This->cs);
731 CloseHandle(This->remoting_mutex);
733 HeapFree(GetProcessHeap(), 0, This);
736 /* finds the proxy manager corresponding to a given OXID and OID that has
737 * been unmarshaled in the specified apartment. The caller must release the
738 * reference to the proxy_manager when the object is no longer used. */
739 static BOOL find_proxy_manager(APARTMENT * apt, OXID oxid, OID oid, struct proxy_manager ** proxy_found)
742 struct list * cursor;
744 EnterCriticalSection(&apt->cs);
745 LIST_FOR_EACH(cursor, &apt->proxies)
747 struct proxy_manager * proxy = LIST_ENTRY(cursor, struct proxy_manager, entry);
748 if ((oxid == proxy->oxid) && (oid == proxy->oid))
750 *proxy_found = proxy;
751 ClientIdentity_AddRef((IMultiQI *)&proxy->lpVtbl);
756 LeaveCriticalSection(&apt->cs);
760 HRESULT apartment_disconnectproxies(struct apartment *apt)
762 struct list * cursor;
764 LIST_FOR_EACH(cursor, &apt->proxies)
766 struct proxy_manager * proxy = LIST_ENTRY(cursor, struct proxy_manager, entry);
767 proxy_manager_disconnect(proxy);
773 /********************** StdMarshal implementation ****************************/
774 typedef struct _StdMarshalImpl
776 const IMarshalVtbl *lpvtbl;
781 LPVOID pvDestContext;
785 static HRESULT WINAPI
786 StdMarshalImpl_QueryInterface(LPMARSHAL iface, REFIID riid, LPVOID *ppv)
789 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IMarshal, riid))
792 IUnknown_AddRef(iface);
795 FIXME("No interface for %s.\n", debugstr_guid(riid));
796 return E_NOINTERFACE;
800 StdMarshalImpl_AddRef(LPMARSHAL iface)
802 StdMarshalImpl *This = (StdMarshalImpl *)iface;
803 return InterlockedIncrement(&This->ref);
807 StdMarshalImpl_Release(LPMARSHAL iface)
809 StdMarshalImpl *This = (StdMarshalImpl *)iface;
810 ULONG ref = InterlockedDecrement(&This->ref);
812 if (!ref) HeapFree(GetProcessHeap(),0,This);
816 static HRESULT WINAPI
817 StdMarshalImpl_GetUnmarshalClass(
818 LPMARSHAL iface, REFIID riid, void* pv, DWORD dwDestContext,
819 void* pvDestContext, DWORD mshlflags, CLSID* pCid)
821 *pCid = CLSID_DfMarshal;
825 static HRESULT WINAPI
826 StdMarshalImpl_GetMarshalSizeMax(
827 LPMARSHAL iface, REFIID riid, void* pv, DWORD dwDestContext,
828 void* pvDestContext, DWORD mshlflags, DWORD* pSize)
830 *pSize = sizeof(STDOBJREF);
834 static HRESULT WINAPI
835 StdMarshalImpl_MarshalInterface(
836 LPMARSHAL iface, IStream *pStm,REFIID riid, void* pv, DWORD dwDestContext,
837 void* pvDestContext, DWORD mshlflags)
842 APARTMENT *apt = COM_CurrentApt();
844 TRACE("(...,%s,...)\n", debugstr_guid(riid));
848 ERR("Apartment not initialized\n");
849 return CO_E_NOTINITIALIZED;
852 /* make sure this apartment can be reached from other threads / processes */
853 RPC_StartRemoting(apt);
855 hres = marshal_object(apt, &stdobjref, riid, (IUnknown *)pv, mshlflags);
858 ERR("Failed to create ifstub, hres=0x%lx\n", hres);
862 hres = IStream_Write(pStm, &stdobjref, sizeof(stdobjref), &res);
863 if (hres) return hres;
868 /* helper for StdMarshalImpl_UnmarshalInterface - does the unmarshaling with
869 * no questions asked about the rules surrounding same-apartment unmarshals
870 * and table marshaling */
871 static HRESULT unmarshal_object(const STDOBJREF *stdobjref, APARTMENT *apt, REFIID riid, void **object)
873 struct proxy_manager *proxy_manager = NULL;
878 TRACE("stdobjref:\n\tflags = %04lx\n\tcPublicRefs = %ld\n\toxid = %s\n\toid = %s\n\tipid = %s\n",
879 stdobjref->flags, stdobjref->cPublicRefs,
880 wine_dbgstr_longlong(stdobjref->oxid),
881 wine_dbgstr_longlong(stdobjref->oid),
882 debugstr_guid(&stdobjref->ipid));
884 /* create an a new proxy manager if one doesn't already exist for the
886 if (!find_proxy_manager(apt, stdobjref->oxid, stdobjref->oid, &proxy_manager))
888 hr = proxy_manager_construct(apt, stdobjref->flags,
889 stdobjref->oxid, stdobjref->oid,
893 TRACE("proxy manager already created, using\n");
897 struct ifproxy * ifproxy;
898 hr = proxy_manager_find_ifproxy(proxy_manager, riid, &ifproxy);
899 if (hr == E_NOINTERFACE)
901 IRpcChannelBuffer *chanbuf;
902 hr = RPC_CreateClientChannel(&stdobjref->oxid, &stdobjref->ipid, &chanbuf);
904 hr = proxy_manager_create_ifproxy(proxy_manager, &stdobjref->ipid,
905 riid, stdobjref->cPublicRefs,
911 /* FIXME: push this AddRef inside proxy_manager_find_ifproxy/create_ifproxy? */
912 ClientIdentity_AddRef((IMultiQI*)&proxy_manager->lpVtbl);
913 *object = ifproxy->iface;
917 /* release our reference to the proxy manager - the client/apartment
918 * will hold on to the remaining reference for us */
919 if (proxy_manager) ClientIdentity_Release((IMultiQI*)&proxy_manager->lpVtbl);
924 static HRESULT WINAPI
925 StdMarshalImpl_UnmarshalInterface(LPMARSHAL iface, IStream *pStm, REFIID riid, void **ppv)
927 struct stub_manager *stubmgr;
931 APARTMENT *apt = COM_CurrentApt();
935 TRACE("(...,%s,....)\n", debugstr_guid(riid));
937 /* we need an apartment to unmarshal into */
940 ERR("Apartment not initialized\n");
941 return CO_E_NOTINITIALIZED;
944 /* read STDOBJREF from wire */
945 hres = IStream_Read(pStm, &stdobjref, sizeof(stdobjref), &res);
946 if (hres) return hres;
948 hres = apartment_getoxid(apt, &oxid);
949 if (hres) return hres;
951 /* check if we're marshalling back to ourselves */
952 if ((oxid == stdobjref.oxid) && (stubmgr = get_stub_manager(apt, stdobjref.oid)))
954 TRACE("Unmarshalling object marshalled in same apartment for iid %s, "
955 "returning original object %p\n", debugstr_guid(riid), stubmgr->object);
957 hres = IUnknown_QueryInterface(stubmgr->object, riid, ppv);
959 /* unref the ifstub. FIXME: only do this on success? */
960 if (!stub_manager_is_table_marshaled(stubmgr))
961 stub_manager_ext_release(stubmgr, 1);
963 stub_manager_int_release(stubmgr);
967 /* notify stub manager about unmarshal if process-local object.
968 * note: if the oxid is not found then we and native will quite happily
969 * ignore table marshaling and normal marshaling rules regarding number of
970 * unmarshals, etc, but if you abuse these rules then your proxy could end
971 * up returning RPC_E_DISCONNECTED. */
972 if ((stub_apt = apartment_findfromoxid(stdobjref.oxid, TRUE)))
974 if ((stubmgr = get_stub_manager(stub_apt, stdobjref.oid)))
976 if (!stub_manager_notify_unmarshal(stubmgr))
977 hres = CO_E_OBJNOTCONNECTED;
979 stub_manager_int_release(stubmgr);
983 WARN("Couldn't find object for OXID %s, OID %s, assuming disconnected\n",
984 wine_dbgstr_longlong(stdobjref.oxid),
985 wine_dbgstr_longlong(stdobjref.oid));
986 hres = CO_E_OBJNOTCONNECTED;
989 apartment_release(stub_apt);
992 TRACE("Treating unmarshal from OXID %s as inter-process\n",
993 wine_dbgstr_longlong(stdobjref.oxid));
996 hres = unmarshal_object(&stdobjref, apt, riid, ppv);
998 if (hres) WARN("Failed with error 0x%08lx\n", hres);
999 else TRACE("Successfully created proxy %p\n", *ppv);
1004 static HRESULT WINAPI
1005 StdMarshalImpl_ReleaseMarshalData(LPMARSHAL iface, IStream *pStm)
1007 STDOBJREF stdobjref;
1010 struct stub_manager *stubmgr;
1013 TRACE("iface=%p, pStm=%p\n", iface, pStm);
1015 hres = IStream_Read(pStm, &stdobjref, sizeof(stdobjref), &res);
1016 if (hres) return hres;
1018 TRACE("oxid = %s, oid = %s, ipid = %s\n",
1019 wine_dbgstr_longlong(stdobjref.oxid),
1020 wine_dbgstr_longlong(stdobjref.oid),
1021 wine_dbgstr_guid(&stdobjref.ipid));
1023 if (!(apt = apartment_findfromoxid(stdobjref.oxid, TRUE)))
1025 WARN("Could not map OXID %s to apartment object\n",
1026 wine_dbgstr_longlong(stdobjref.oxid));
1027 return RPC_E_INVALID_OBJREF;
1030 if (!(stubmgr = get_stub_manager(apt, stdobjref.oid)))
1032 ERR("could not map MID to stub manager, oxid=%s, oid=%s\n",
1033 wine_dbgstr_longlong(stdobjref.oxid), wine_dbgstr_longlong(stdobjref.oid));
1034 return RPC_E_INVALID_OBJREF;
1037 stub_manager_release_marshal_data(stubmgr, stdobjref.cPublicRefs);
1039 stub_manager_int_release(stubmgr);
1040 apartment_release(apt);
1045 static HRESULT WINAPI
1046 StdMarshalImpl_DisconnectObject(LPMARSHAL iface, DWORD dwReserved)
1048 FIXME("(), stub!\n");
1052 static const IMarshalVtbl VT_StdMarshal =
1054 StdMarshalImpl_QueryInterface,
1055 StdMarshalImpl_AddRef,
1056 StdMarshalImpl_Release,
1057 StdMarshalImpl_GetUnmarshalClass,
1058 StdMarshalImpl_GetMarshalSizeMax,
1059 StdMarshalImpl_MarshalInterface,
1060 StdMarshalImpl_UnmarshalInterface,
1061 StdMarshalImpl_ReleaseMarshalData,
1062 StdMarshalImpl_DisconnectObject
1065 static HRESULT StdMarshalImpl_Construct(REFIID riid, void** ppvObject)
1067 StdMarshalImpl * pStdMarshal =
1068 HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(StdMarshalImpl));
1070 return E_OUTOFMEMORY;
1071 pStdMarshal->lpvtbl = &VT_StdMarshal;
1072 pStdMarshal->ref = 0;
1073 return IMarshal_QueryInterface((IMarshal*)pStdMarshal, riid, ppvObject);
1076 /***********************************************************************
1077 * CoGetStandardMarshal [OLE32.@]
1079 * Gets or creates a standard marshal object.
1082 * riid [I] Interface identifier of the pUnk object.
1083 * pUnk [I] Optional. Object to get the marshal object for.
1084 * dwDestContext [I] Destination. Used to enable or disable optimizations.
1085 * pvDestContext [I] Reserved. Must be NULL.
1086 * mshlflags [I] Flags affecting the marshaling process.
1087 * ppMarshal [O] Address where marshal object will be stored.
1091 * Failure: HRESULT code.
1095 * The function retrieves the IMarshal object associated with an object if
1096 * that object is currently an active stub, otherwise a new marshal object is
1099 HRESULT WINAPI CoGetStandardMarshal(REFIID riid, IUnknown *pUnk,
1100 DWORD dwDestContext, LPVOID pvDestContext,
1101 DWORD mshlflags, LPMARSHAL *ppMarshal)
1107 FIXME("(%s,NULL,%lx,%p,%lx,%p), unimplemented yet.\n",
1108 debugstr_guid(riid),dwDestContext,pvDestContext,mshlflags,ppMarshal);
1111 TRACE("(%s,%p,%lx,%p,%lx,%p)\n",
1112 debugstr_guid(riid),pUnk,dwDestContext,pvDestContext,mshlflags,ppMarshal);
1113 *ppMarshal = HeapAlloc(GetProcessHeap(),0,sizeof(StdMarshalImpl));
1114 dm = (StdMarshalImpl*) *ppMarshal;
1115 if (!dm) return E_FAIL;
1116 dm->lpvtbl = &VT_StdMarshal;
1120 dm->dwDestContext = dwDestContext;
1121 dm->pvDestContext = pvDestContext;
1122 dm->mshlflags = mshlflags;
1126 /***********************************************************************
1127 * get_marshaler [internal]
1129 * Retrieves an IMarshal interface for an object.
1131 static HRESULT get_marshaler(REFIID riid, IUnknown *pUnk, DWORD dwDestContext,
1132 void *pvDestContext, DWORD mshlFlags,
1133 LPMARSHAL *pMarshal)
1139 hr = IUnknown_QueryInterface(pUnk, &IID_IMarshal, (LPVOID*)pMarshal);
1141 hr = CoGetStandardMarshal(riid, pUnk, dwDestContext, pvDestContext,
1142 mshlFlags, pMarshal);
1146 /***********************************************************************
1147 * get_unmarshaler_from_stream [internal]
1149 * Creates an IMarshal* object according to the data marshaled to the stream.
1150 * The function leaves the stream pointer at the start of the data written
1151 * to the stream by the IMarshal* object.
1153 static HRESULT get_unmarshaler_from_stream(IStream *stream, IMarshal **marshal, IID *iid)
1159 /* read common OBJREF header */
1160 hr = IStream_Read(stream, &objref, FIELD_OFFSET(OBJREF, u_objref), &res);
1161 if (hr || (res != FIELD_OFFSET(OBJREF, u_objref)))
1163 ERR("Failed to read common OBJREF header, 0x%08lx\n", hr);
1164 return STG_E_READFAULT;
1167 /* sanity check on header */
1168 if (objref.signature != OBJREF_SIGNATURE)
1170 ERR("Bad OBJREF signature 0x%08lx\n", objref.signature);
1171 return RPC_E_INVALID_OBJREF;
1174 if (iid) *iid = objref.iid;
1176 /* FIXME: handler marshaling */
1177 if (objref.flags & OBJREF_STANDARD)
1179 TRACE("Using standard unmarshaling\n");
1180 hr = StdMarshalImpl_Construct(&IID_IMarshal, (LPVOID*)marshal);
1182 else if (objref.flags & OBJREF_CUSTOM)
1184 ULONG custom_header_size = FIELD_OFFSET(OBJREF, u_objref.u_custom.pData) -
1185 FIELD_OFFSET(OBJREF, u_objref.u_custom);
1186 TRACE("Using custom unmarshaling\n");
1187 /* read constant sized OR_CUSTOM data from stream */
1188 hr = IStream_Read(stream, &objref.u_objref.u_custom,
1189 custom_header_size, &res);
1190 if (hr || (res != custom_header_size))
1192 ERR("Failed to read OR_CUSTOM header, 0x%08lx\n", hr);
1193 return STG_E_READFAULT;
1195 /* now create the marshaler specified in the stream */
1196 hr = CoCreateInstance(&objref.u_objref.u_custom.clsid, NULL,
1197 CLSCTX_INPROC_SERVER, &IID_IMarshal,
1202 FIXME("Invalid or unimplemented marshaling type specified: %lx\n",
1204 return RPC_E_INVALID_OBJREF;
1208 ERR("Failed to create marshal, 0x%08lx\n", hr);
1213 /***********************************************************************
1214 * CoGetMarshalSizeMax [OLE32.@]
1216 * Gets the maximum amount of data that will be needed by a marshal.
1219 * pulSize [O] Address where maximum marshal size will be stored.
1220 * riid [I] Identifier of the interface to marshal.
1221 * pUnk [I] Pointer to the object to marshal.
1222 * dwDestContext [I] Destination. Used to enable or disable optimizations.
1223 * pvDestContext [I] Reserved. Must be NULL.
1224 * mshlFlags [I] Flags that affect the marshaling. See CoMarshalInterface().
1228 * Failure: HRESULT code.
1231 * CoMarshalInterface().
1233 HRESULT WINAPI CoGetMarshalSizeMax(ULONG *pulSize, REFIID riid, IUnknown *pUnk,
1234 DWORD dwDestContext, void *pvDestContext,
1239 CLSID marshaler_clsid;
1241 hr = get_marshaler(riid, pUnk, dwDestContext, pvDestContext, mshlFlags, &pMarshal);
1245 hr = IMarshal_GetUnmarshalClass(pMarshal, riid, pUnk, dwDestContext,
1246 pvDestContext, mshlFlags, &marshaler_clsid);
1249 ERR("IMarshal::GetUnmarshalClass failed, 0x%08lx\n", hr);
1250 IMarshal_Release(pMarshal);
1254 hr = IMarshal_GetMarshalSizeMax(pMarshal, riid, pUnk, dwDestContext,
1255 pvDestContext, mshlFlags, pulSize);
1256 /* add on the size of the common header */
1257 *pulSize += FIELD_OFFSET(OBJREF, u_objref);
1259 /* if custom marshaling, add on size of custom header */
1260 if (!IsEqualCLSID(&marshaler_clsid, &CLSID_DfMarshal))
1261 *pulSize += FIELD_OFFSET(OBJREF, u_objref.u_custom.pData) -
1262 FIELD_OFFSET(OBJREF, u_objref.u_custom);
1264 IMarshal_Release(pMarshal);
1269 /***********************************************************************
1270 * CoMarshalInterface [OLE32.@]
1272 * Marshals an interface into a stream so that the object can then be
1273 * unmarshaled from another COM apartment and used remotely.
1276 * pStream [I] Stream the object will be marshaled into.
1277 * riid [I] Identifier of the interface to marshal.
1278 * pUnk [I] Pointer to the object to marshal.
1279 * dwDestContext [I] Destination. Used to enable or disable optimizations.
1280 * pvDestContext [I] Reserved. Must be NULL.
1281 * mshlFlags [I] Flags that affect the marshaling. See notes.
1285 * Failure: HRESULT code.
1289 * The mshlFlags parameter can take one or more of the following flags:
1290 *| MSHLFLAGS_NORMAL - Unmarshal once, releases stub on last proxy release.
1291 *| MSHLFLAGS_TABLESTRONG - Unmarshal many, release when CoReleaseMarshalData() called.
1292 *| MSHLFLAGS_TABLEWEAK - Unmarshal many, releases stub on last proxy release.
1293 *| MSHLFLAGS_NOPING - No automatic garbage collection (and so reduces network traffic).
1295 * If a marshaled object is not unmarshaled, then CoReleaseMarshalData() must
1296 * be called in order to release the resources used in the marshaling.
1299 * CoUnmarshalInterface(), CoReleaseMarshalData().
1301 HRESULT WINAPI CoMarshalInterface(IStream *pStream, REFIID riid, IUnknown *pUnk,
1302 DWORD dwDestContext, void *pvDestContext,
1306 CLSID marshaler_clsid;
1310 TRACE("(%p, %s, %p, %lx, %p, %lx)\n", pStream, debugstr_guid(riid), pUnk,
1311 dwDestContext, pvDestContext, mshlFlags);
1314 return E_INVALIDARG;
1316 objref.signature = OBJREF_SIGNATURE;
1319 /* get the marshaler for the specified interface */
1320 hr = get_marshaler(riid, pUnk, dwDestContext, pvDestContext, mshlFlags, &pMarshal);
1323 ERR("Failed to get marshaller, 0x%08lx\n", hr);
1327 hr = IMarshal_GetUnmarshalClass(pMarshal, riid, pUnk, dwDestContext,
1328 pvDestContext, mshlFlags, &marshaler_clsid);
1331 ERR("IMarshal::GetUnmarshalClass failed, 0x%08lx\n", hr);
1335 /* FIXME: implement handler marshaling too */
1336 if (IsEqualCLSID(&marshaler_clsid, &CLSID_DfMarshal))
1338 TRACE("Using standard marshaling\n");
1339 objref.flags = OBJREF_STANDARD;
1341 /* write the common OBJREF header to the stream */
1342 hr = IStream_Write(pStream, &objref, FIELD_OFFSET(OBJREF, u_objref), NULL);
1345 ERR("Failed to write OBJREF header to stream, 0x%08lx\n", hr);
1351 TRACE("Using custom marshaling\n");
1352 objref.flags = OBJREF_CUSTOM;
1353 objref.u_objref.u_custom.clsid = marshaler_clsid;
1354 objref.u_objref.u_custom.cbExtension = 0;
1355 objref.u_objref.u_custom.size = 0;
1356 hr = IMarshal_GetMarshalSizeMax(pMarshal, riid, pUnk, dwDestContext,
1357 pvDestContext, mshlFlags,
1358 &objref.u_objref.u_custom.size);
1361 ERR("Failed to get max size of marshal data, error 0x%08lx\n", hr);
1364 /* write constant sized common header and OR_CUSTOM data into stream */
1365 hr = IStream_Write(pStream, &objref,
1366 FIELD_OFFSET(OBJREF, u_objref.u_custom.pData), NULL);
1369 ERR("Failed to write OR_CUSTOM header to stream with 0x%08lx\n", hr);
1374 TRACE("Calling IMarshal::MarshalInterace\n");
1375 /* call helper object to do the actual marshaling */
1376 hr = IMarshal_MarshalInterface(pMarshal, pStream, riid, pUnk, dwDestContext,
1377 pvDestContext, mshlFlags);
1381 ERR("Failed to marshal the interface %s, %lx\n", debugstr_guid(riid), hr);
1386 IMarshal_Release(pMarshal);
1388 TRACE("completed with hr 0x%08lx\n", hr);
1393 /***********************************************************************
1394 * CoUnmarshalInterface [OLE32.@]
1396 * Unmarshals an object from a stream by creating a proxy to the remote
1397 * object, if necessary.
1401 * pStream [I] Stream containing the marshaled object.
1402 * riid [I] Interface identifier of the object to create a proxy to.
1403 * ppv [O] Address where proxy will be stored.
1408 * Failure: HRESULT code.
1411 * CoMarshalInterface().
1413 HRESULT WINAPI CoUnmarshalInterface(IStream *pStream, REFIID riid, LPVOID *ppv)
1420 TRACE("(%p, %s, %p)\n", pStream, debugstr_guid(riid), ppv);
1422 hr = get_unmarshaler_from_stream(pStream, &pMarshal, &iid);
1426 /* call the helper object to do the actual unmarshaling */
1427 hr = IMarshal_UnmarshalInterface(pMarshal, pStream, &iid, (LPVOID*)&object);
1429 ERR("IMarshal::UnmarshalInterface failed, 0x%08lx\n", hr);
1431 /* IID_NULL means use the interface ID of the marshaled object */
1432 if (!IsEqualIID(riid, &IID_NULL))
1437 if (!IsEqualIID(riid, &iid))
1439 TRACE("requested interface != marshalled interface, additional QI needed\n");
1440 hr = IUnknown_QueryInterface(object, &iid, ppv);
1442 ERR("Couldn't query for interface %s, hr = 0x%08lx\n",
1443 debugstr_guid(riid), hr);
1444 IUnknown_Release(object);
1452 IMarshal_Release(pMarshal);
1454 TRACE("completed with hr 0x%lx\n", hr);
1459 /***********************************************************************
1460 * CoReleaseMarshalData [OLE32.@]
1462 * Releases resources associated with an object that has been marshaled into
1467 * pStream [I] The stream that the object has been marshaled into.
1471 * Failure: HRESULT error code.
1475 * Call this function to release resources associated with a normal or
1476 * table-weak marshal that will not be unmarshaled, and all table-strong
1477 * marshals when they are no longer needed.
1480 * CoMarshalInterface(), CoUnmarshalInterface().
1482 HRESULT WINAPI CoReleaseMarshalData(IStream *pStream)
1487 TRACE("(%p)\n", pStream);
1489 hr = get_unmarshaler_from_stream(pStream, &pMarshal, NULL);
1493 /* call the helper object to do the releasing of marshal data */
1494 hr = IMarshal_ReleaseMarshalData(pMarshal, pStream);
1496 ERR("IMarshal::ReleaseMarshalData failed with error 0x%08lx\n", hr);
1498 IMarshal_Release(pMarshal);
1503 /***********************************************************************
1504 * CoMarshalInterThreadInterfaceInStream [OLE32.@]
1506 * Marshal an interface across threads in the same process.
1509 * riid [I] Identifier of the interface to be marshalled.
1510 * pUnk [I] Pointer to IUnknown-derived interface that will be marshalled.
1511 * ppStm [O] Pointer to IStream object that is created and then used to store the marshalled inteface.
1515 * Failure: E_OUTOFMEMORY and other COM error codes
1518 * CoMarshalInterface(), CoUnmarshalInterface() and CoGetInterfaceAndReleaseStream()
1520 HRESULT WINAPI CoMarshalInterThreadInterfaceInStream(
1521 REFIID riid, LPUNKNOWN pUnk, LPSTREAM * ppStm)
1523 ULARGE_INTEGER xpos;
1524 LARGE_INTEGER seekto;
1527 TRACE("(%s, %p, %p)\n",debugstr_guid(riid), pUnk, ppStm);
1529 hres = CreateStreamOnHGlobal(0, TRUE, ppStm);
1530 if (FAILED(hres)) return hres;
1531 hres = CoMarshalInterface(*ppStm, riid, pUnk, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1533 /* FIXME: is this needed? */
1534 memset(&seekto,0,sizeof(seekto));
1535 IStream_Seek(*ppStm,seekto,SEEK_SET,&xpos);
1540 /***********************************************************************
1541 * CoGetInterfaceAndReleaseStream [OLE32.@]
1543 * Unmarshalls an inteface from a stream and then releases the stream.
1546 * pStm [I] Stream that contains the marshalled inteface.
1547 * riid [I] Interface identifier of the object to unmarshall.
1548 * ppv [O] Address of pointer where the requested interface object will be stored.
1552 * Failure: A COM error code
1555 * CoMarshalInterThreadInterfaceInStream() and CoUnmarshalInteface()
1557 HRESULT WINAPI CoGetInterfaceAndReleaseStream(LPSTREAM pStm, REFIID riid,
1562 TRACE("(%p, %s, %p)\n", pStm, debugstr_guid(riid), ppv);
1564 hres = CoUnmarshalInterface(pStm, riid, ppv);
1565 IStream_Release(pStm);
1569 static HRESULT WINAPI StdMarshalCF_QueryInterface(LPCLASSFACTORY iface,
1570 REFIID riid, LPVOID *ppv)
1573 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IClassFactory))
1575 *ppv = (LPVOID)iface;
1578 return E_NOINTERFACE;
1581 static ULONG WINAPI StdMarshalCF_AddRef(LPCLASSFACTORY iface)
1583 return 2; /* non-heap based object */
1586 static ULONG WINAPI StdMarshalCF_Release(LPCLASSFACTORY iface)
1588 return 1; /* non-heap based object */
1591 static HRESULT WINAPI StdMarshalCF_CreateInstance(LPCLASSFACTORY iface,
1592 LPUNKNOWN pUnk, REFIID riid, LPVOID *ppv)
1594 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IMarshal))
1595 return StdMarshalImpl_Construct(riid, ppv);
1597 FIXME("(%s), not supported.\n",debugstr_guid(riid));
1598 return E_NOINTERFACE;
1601 static HRESULT WINAPI StdMarshalCF_LockServer(LPCLASSFACTORY iface, BOOL fLock)
1603 FIXME("(%d), stub!\n",fLock);
1607 static const IClassFactoryVtbl StdMarshalCFVtbl =
1609 StdMarshalCF_QueryInterface,
1610 StdMarshalCF_AddRef,
1611 StdMarshalCF_Release,
1612 StdMarshalCF_CreateInstance,
1613 StdMarshalCF_LockServer
1615 static const IClassFactoryVtbl *StdMarshalCF = &StdMarshalCFVtbl;
1617 HRESULT MARSHAL_GetStandardMarshalCF(LPVOID *ppv)
1619 *ppv = &StdMarshalCF;
1623 /***********************************************************************
1624 * CoMarshalHresult [OLE32.@]
1626 * Marshals an HRESULT value into a stream.
1629 * pStm [I] Stream that hresult will be marshalled into.
1630 * hresult [I] HRESULT to be marshalled.
1634 * Failure: A COM error code
1637 * CoUnmarshalHresult().
1639 HRESULT WINAPI CoMarshalHresult(LPSTREAM pStm, HRESULT hresult)
1641 return IStream_Write(pStm, &hresult, sizeof(hresult), NULL);
1644 /***********************************************************************
1645 * CoUnmarshalHresult [OLE32.@]
1647 * Unmarshals an HRESULT value from a stream.
1650 * pStm [I] Stream that hresult will be unmarshalled from.
1651 * phresult [I] Pointer to HRESULT where the value will be unmarshalled to.
1655 * Failure: A COM error code
1658 * CoMarshalHresult().
1660 HRESULT WINAPI CoUnmarshalHresult(LPSTREAM pStm, HRESULT * phresult)
1662 return IStream_Read(pStm, phresult, sizeof(*phresult), NULL);