📄 marshal.c
字号:
void* pvDestContext, DWORD mshlflags, DWORD* pSize)
{
*pSize = sizeof(STDOBJREF);
return S_OK;
}
static HRESULT WINAPI
StdMarshalImpl_MarshalInterface(
LPMARSHAL iface, IStream *pStm,REFIID riid, void* pv, DWORD dwDestContext,
void* pvDestContext, DWORD mshlflags)
{
STDOBJREF stdobjref;
ULONG res;
HRESULT hres;
APARTMENT *apt = COM_CurrentApt();
TRACE("(...,%s,...)\n", debugstr_guid(riid));
if (!apt)
{
ERR("Apartment not initialized\n");
return CO_E_NOTINITIALIZED;
}
/* make sure this apartment can be reached from other threads / processes */
RPC_StartRemoting(apt);
hres = marshal_object(apt, &stdobjref, riid, (IUnknown *)pv, mshlflags);
if (hres)
{
ERR("Failed to create ifstub, hres=0x%x\n", hres);
return hres;
}
hres = IStream_Write(pStm, &stdobjref, sizeof(stdobjref), &res);
if (hres) return hres;
return S_OK;
}
/* helper for StdMarshalImpl_UnmarshalInterface - does the unmarshaling with
* no questions asked about the rules surrounding same-apartment unmarshals
* and table marshaling */
static HRESULT unmarshal_object(const STDOBJREF *stdobjref, APARTMENT *apt,
MSHCTX dest_context, void *dest_context_data,
REFIID riid, const OXID_INFO *oxid_info,
void **object)
{
struct proxy_manager *proxy_manager = NULL;
HRESULT hr = S_OK;
assert(apt);
TRACE("stdobjref:\n\tflags = %04lx\n\tcPublicRefs = %ld\n\toxid = %s\n\toid = %s\n\tipid = %s\n",
stdobjref->flags, stdobjref->cPublicRefs,
wine_dbgstr_longlong(stdobjref->oxid),
wine_dbgstr_longlong(stdobjref->oid),
debugstr_guid(&stdobjref->ipid));
/* create a new proxy manager if one doesn't already exist for the
* object */
if (!find_proxy_manager(apt, stdobjref->oxid, stdobjref->oid, &proxy_manager))
{
hr = proxy_manager_construct(apt, stdobjref->flags,
stdobjref->oxid, stdobjref->oid, oxid_info,
&proxy_manager);
}
else
TRACE("proxy manager already created, using\n");
if (hr == S_OK)
{
struct ifproxy * ifproxy;
proxy_manager_set_context(proxy_manager, dest_context, dest_context_data);
hr = proxy_manager_find_ifproxy(proxy_manager, riid, &ifproxy);
if (hr == E_NOINTERFACE)
{
IRpcChannelBuffer *chanbuf;
hr = RPC_CreateClientChannel(&stdobjref->oxid, &stdobjref->ipid,
&proxy_manager->oxid_info,
proxy_manager->dest_context,
proxy_manager->dest_context_data,
&chanbuf);
if (hr == S_OK)
hr = proxy_manager_create_ifproxy(proxy_manager, stdobjref,
riid, chanbuf, &ifproxy);
}
else
IUnknown_AddRef((IUnknown *)ifproxy->iface);
if (hr == S_OK)
{
InterlockedExchangeAdd((LONG *)&ifproxy->refs, stdobjref->cPublicRefs);
/* get at least one external reference to the object to keep it alive */
hr = ifproxy_get_public_ref(ifproxy);
if (FAILED(hr))
ifproxy_destroy(ifproxy);
}
if (hr == S_OK)
*object = ifproxy->iface;
}
/* release our reference to the proxy manager - the client/apartment
* will hold on to the remaining reference for us */
if (proxy_manager) ClientIdentity_Release((IMultiQI*)&proxy_manager->lpVtbl);
return hr;
}
static HRESULT WINAPI
StdMarshalImpl_UnmarshalInterface(LPMARSHAL iface, IStream *pStm, REFIID riid, void **ppv)
{
StdMarshalImpl *This = (StdMarshalImpl *)iface;
struct stub_manager *stubmgr = NULL;
STDOBJREF stdobjref;
ULONG res;
HRESULT hres;
APARTMENT *apt = COM_CurrentApt();
APARTMENT *stub_apt;
OXID oxid;
TRACE("(...,%s,....)\n", debugstr_guid(riid));
/* we need an apartment to unmarshal into */
if (!apt)
{
ERR("Apartment not initialized\n");
return CO_E_NOTINITIALIZED;
}
/* read STDOBJREF from wire */
hres = IStream_Read(pStm, &stdobjref, sizeof(stdobjref), &res);
if (hres) return STG_E_READFAULT;
hres = apartment_getoxid(apt, &oxid);
if (hres) return hres;
/* check if we're marshalling back to ourselves */
if ((oxid == stdobjref.oxid) && (stubmgr = get_stub_manager(apt, stdobjref.oid)))
{
TRACE("Unmarshalling object marshalled in same apartment for iid %s, "
"returning original object %p\n", debugstr_guid(riid), stubmgr->object);
hres = IUnknown_QueryInterface(stubmgr->object, riid, ppv);
/* unref the ifstub. FIXME: only do this on success? */
if (!stub_manager_is_table_marshaled(stubmgr, &stdobjref.ipid))
stub_manager_ext_release(stubmgr, stdobjref.cPublicRefs, TRUE);
stub_manager_int_release(stubmgr);
return hres;
}
/* notify stub manager about unmarshal if process-local object.
* note: if the oxid is not found then we and native will quite happily
* ignore table marshaling and normal marshaling rules regarding number of
* unmarshals, etc, but if you abuse these rules then your proxy could end
* up returning RPC_E_DISCONNECTED. */
if ((stub_apt = apartment_findfromoxid(stdobjref.oxid, TRUE)))
{
if ((stubmgr = get_stub_manager(stub_apt, stdobjref.oid)))
{
if (!stub_manager_notify_unmarshal(stubmgr, &stdobjref.ipid))
hres = CO_E_OBJNOTCONNECTED;
}
else
{
WARN("Couldn't find object for OXID %s, OID %s, assuming disconnected\n",
wine_dbgstr_longlong(stdobjref.oxid),
wine_dbgstr_longlong(stdobjref.oid));
hres = CO_E_OBJNOTCONNECTED;
}
}
else
TRACE("Treating unmarshal from OXID %s as inter-process\n",
wine_dbgstr_longlong(stdobjref.oxid));
if (hres == S_OK)
hres = unmarshal_object(&stdobjref, apt, This->dwDestContext,
This->pvDestContext, riid,
stubmgr ? &stubmgr->oxid_info : NULL, ppv);
if (stubmgr) stub_manager_int_release(stubmgr);
if (stub_apt) apartment_release(stub_apt);
if (hres) WARN("Failed with error 0x%08x\n", hres);
else TRACE("Successfully created proxy %p\n", *ppv);
return hres;
}
static HRESULT WINAPI
StdMarshalImpl_ReleaseMarshalData(LPMARSHAL iface, IStream *pStm)
{
STDOBJREF stdobjref;
ULONG res;
HRESULT hres;
struct stub_manager *stubmgr;
APARTMENT *apt;
TRACE("iface=%p, pStm=%p\n", iface, pStm);
hres = IStream_Read(pStm, &stdobjref, sizeof(stdobjref), &res);
if (hres) return STG_E_READFAULT;
TRACE("oxid = %s, oid = %s, ipid = %s\n",
wine_dbgstr_longlong(stdobjref.oxid),
wine_dbgstr_longlong(stdobjref.oid),
wine_dbgstr_guid(&stdobjref.ipid));
if (!(apt = apartment_findfromoxid(stdobjref.oxid, TRUE)))
{
WARN("Could not map OXID %s to apartment object\n",
wine_dbgstr_longlong(stdobjref.oxid));
return RPC_E_INVALID_OBJREF;
}
if (!(stubmgr = get_stub_manager(apt, stdobjref.oid)))
{
ERR("could not map object ID to stub manager, oxid=%s, oid=%s\n",
wine_dbgstr_longlong(stdobjref.oxid), wine_dbgstr_longlong(stdobjref.oid));
return RPC_E_INVALID_OBJREF;
}
stub_manager_release_marshal_data(stubmgr, stdobjref.cPublicRefs, &stdobjref.ipid);
stub_manager_int_release(stubmgr);
apartment_release(apt);
return S_OK;
}
static HRESULT WINAPI
StdMarshalImpl_DisconnectObject(LPMARSHAL iface, DWORD dwReserved)
{
FIXME("(), stub!\n");
return S_OK;
}
static const IMarshalVtbl VT_StdMarshal =
{
StdMarshalImpl_QueryInterface,
StdMarshalImpl_AddRef,
StdMarshalImpl_Release,
StdMarshalImpl_GetUnmarshalClass,
StdMarshalImpl_GetMarshalSizeMax,
StdMarshalImpl_MarshalInterface,
StdMarshalImpl_UnmarshalInterface,
StdMarshalImpl_ReleaseMarshalData,
StdMarshalImpl_DisconnectObject
};
static HRESULT StdMarshalImpl_Construct(REFIID riid, void** ppvObject)
{
StdMarshalImpl * pStdMarshal =
HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(StdMarshalImpl));
if (!pStdMarshal)
return E_OUTOFMEMORY;
pStdMarshal->lpvtbl = &VT_StdMarshal;
pStdMarshal->ref = 0;
return IMarshal_QueryInterface((IMarshal*)pStdMarshal, riid, ppvObject);
}
/***********************************************************************
* CoGetStandardMarshal [OLE32.@]
*
* Gets or creates a standard marshal object.
*
* PARAMS
* riid [I] Interface identifier of the pUnk object.
* pUnk [I] Optional. Object to get the marshal object for.
* dwDestContext [I] Destination. Used to enable or disable optimizations.
* pvDestContext [I] Reserved. Must be NULL.
* mshlflags [I] Flags affecting the marshaling process.
* ppMarshal [O] Address where marshal object will be stored.
*
* RETURNS
* Success: S_OK.
* Failure: HRESULT code.
*
* NOTES
*
* The function retrieves the IMarshal object associated with an object if
* that object is currently an active stub, otherwise a new marshal object is
* created.
*/
HRESULT WINAPI CoGetStandardMarshal(REFIID riid, IUnknown *pUnk,
DWORD dwDestContext, LPVOID pvDestContext,
DWORD mshlflags, LPMARSHAL *ppMarshal)
{
StdMarshalImpl *dm;
if (pUnk == NULL)
{
FIXME("(%s,NULL,%x,%p,%x,%p), unimplemented yet.\n",
debugstr_guid(riid),dwDestContext,pvDestContext,mshlflags,ppMarshal);
return E_NOTIMPL;
}
TRACE("(%s,%p,%x,%p,%x,%p)\n",
debugstr_guid(riid),pUnk,dwDestContext,pvDestContext,mshlflags,ppMarshal);
*ppMarshal = HeapAlloc(GetProcessHeap(),0,sizeof(StdMarshalImpl));
dm = (StdMarshalImpl*) *ppMarshal;
if (!dm) return E_FAIL;
dm->lpvtbl = &VT_StdMarshal;
dm->ref = 1;
dm->iid = *riid;
dm->dwDestContext = dwDestContext;
dm->pvDestContext = pvDestContext;
dm->mshlflags = mshlflags;
return S_OK;
}
/***********************************************************************
* get_marshaler [internal]
*
* Retrieves an IMarshal interface for an object.
*/
static HRESULT get_marshaler(REFIID riid, IUnknown *pUnk, DWORD dwDestContext,
void *pvDestContext, DWORD mshlFlags,
LPMARSHAL *pMarshal)
{
HRESULT hr;
if (!pUnk)
return E_POINTER;
hr = IUnknown_QueryInterface(pUnk, &IID_IMarshal, (LPVOID*)pMarshal);
if (hr)
hr = CoGetStandardMarshal(riid, pUnk, dwDestContext, pvDestContext,
mshlFlags, pMarshal);
return hr;
}
/***********************************************************************
* get_unmarshaler_from_stream [internal]
*
* Creates an IMarshal* object according to the data marshaled to the stream.
* The function leaves the stream pointer at the start of the data written
* to the stream by the IMarshal* object.
*/
static HRESULT get_unmarshaler_from_stream(IStream *stream, IMarshal **marshal, IID *iid)
{
HRESULT hr;
ULONG res;
OBJREF objref;
/* read common OBJREF header */
hr = IStream_Read(stream, &objref, FIELD_OFFSET(OBJREF, u_objref), &res);
if (hr || (res != FIELD_OFFSET(OBJREF, u_objref)))
{
ERR("Failed to read common OBJREF header, 0x%08x\n", hr);
return STG_E_READFAULT;
}
/* sanity check on header */
if (objref.signature != OBJREF_SIGNATURE)
{
ERR("Bad OBJREF signature 0x%08lx\n", objref.signature);
return RPC_E_INVALID_OBJREF;
}
if (iid) *iid = objref.iid;
/* FIXME: handler marshaling */
if (objref.flags & OBJREF_STANDARD)
{
TRACE("Using standard unmarshaling\n");
hr = StdMarshalImpl_Construct(&IID_IMarshal, (LPVOID*)marshal);
}
else if (objref.flags & OBJREF_CUSTOM)
{
ULONG custom_header_size = FIELD_OFFSET(OBJREF, u_objref.u_custom.pData) -
FIELD_OFFSET(OBJREF, u_objref.u_custom);
TRACE("Using custom unmarshaling\n");
/* read constant sized OR_CUSTOM data from stream */
hr = IStream_Read(stream, &objref.u_objref.u_custom,
custom_header_size, &res);
if (hr || (res != custom_header_size))
{
ERR("Failed to read OR_CUSTOM header, 0x%08x\n", hr);
return STG_E_READFAULT;
}
/* now create the marshaler specified in the stream */
hr = CoCreateInstance(&objref.u_objref.u_custom.clsid, NULL,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -