📄 marshal.c
字号:
case MSHCTX_LOCAL:
switch (dest_context)
{
case MSHCTX_INPROC:
case MSHCTX_CROSSCTX:
break;
default:
new_dest_context = dest_context;
}
break;
case MSHCTX_NOSHAREDMEM:
switch (dest_context)
{
case MSHCTX_DIFFERENTMACHINE:
new_dest_context = dest_context;
break;
default:
break;
}
break;
default:
break;
}
if (old_dest_context == new_dest_context) break;
old_dest_context = InterlockedCompareExchange((PLONG)&This->dest_context, new_dest_context, old_dest_context);
} while (new_dest_context != old_dest_context);
if (dest_context_data)
InterlockedExchangePointer(&This->dest_context_data, dest_context_data);
}
static HRESULT proxy_manager_query_local_interface(struct proxy_manager * This, REFIID riid, void ** ppv)
{
HRESULT hr;
struct ifproxy * ifproxy;
TRACE("%s\n", debugstr_guid(riid));
if (IsEqualIID(riid, &IID_IUnknown) ||
IsEqualIID(riid, &IID_IMultiQI))
{
*ppv = (void *)&This->lpVtbl;
IUnknown_AddRef((IUnknown *)*ppv);
return S_OK;
}
if (IsEqualIID(riid, &IID_IMarshal))
{
*ppv = (void *)&This->lpVtblMarshal;
IUnknown_AddRef((IUnknown *)*ppv);
return S_OK;
}
if (IsEqualIID(riid, &IID_IClientSecurity))
{
*ppv = (void *)&This->lpVtblCliSec;
IUnknown_AddRef((IUnknown *)*ppv);
return S_OK;
}
hr = proxy_manager_find_ifproxy(This, riid, &ifproxy);
if (hr == S_OK)
{
*ppv = ifproxy->iface;
IUnknown_AddRef((IUnknown *)*ppv);
return S_OK;
}
*ppv = NULL;
return E_NOINTERFACE;
}
static HRESULT proxy_manager_create_ifproxy(
struct proxy_manager * This, const STDOBJREF *stdobjref, REFIID riid,
IRpcChannelBuffer * channel, struct ifproxy ** iif_out)
{
HRESULT hr;
IPSFactoryBuffer * psfb;
struct ifproxy * ifproxy = HeapAlloc(GetProcessHeap(), 0, sizeof(*ifproxy));
if (!ifproxy) return E_OUTOFMEMORY;
list_init(&ifproxy->entry);
ifproxy->parent = This;
ifproxy->stdobjref = *stdobjref;
ifproxy->iid = *riid;
ifproxy->refs = 0;
ifproxy->proxy = NULL;
assert(channel);
ifproxy->chan = channel; /* FIXME: we should take the binding strings and construct the channel in this function */
/* the IUnknown interface is special because it does not have a
* proxy associated with the ifproxy as we handle IUnknown ourselves */
if (IsEqualIID(riid, &IID_IUnknown))
{
ifproxy->iface = (void *)&This->lpVtbl;
IMultiQI_AddRef((IMultiQI *)&This->lpVtbl);
hr = S_OK;
}
else
{
hr = get_facbuf_for_iid(riid, &psfb);
if (hr == S_OK)
{
/* important note: the outer unknown is set to the proxy manager.
* This ensures the COM identity rules are not violated, by having a
* one-to-one mapping of objects on the proxy side to objects on the
* stub side, no matter which interface you view the object through */
hr = IPSFactoryBuffer_CreateProxy(psfb, (IUnknown *)&This->lpVtbl, riid,
&ifproxy->proxy, &ifproxy->iface);
IPSFactoryBuffer_Release(psfb);
if (hr != S_OK)
ERR("Could not create proxy for interface %s, error 0x%08x\n",
debugstr_guid(riid), hr);
}
else
ERR("Could not get IPSFactoryBuffer for interface %s, error 0x%08x\n",
debugstr_guid(riid), hr);
if (hr == S_OK)
hr = IRpcProxyBuffer_Connect(ifproxy->proxy, ifproxy->chan);
}
if (hr == S_OK)
{
EnterCriticalSection(&This->cs);
list_add_tail(&This->interfaces, &ifproxy->entry);
LeaveCriticalSection(&This->cs);
*iif_out = ifproxy;
TRACE("ifproxy %p created for IPID %s, interface %s with %lu public refs\n",
ifproxy, debugstr_guid(&stdobjref->ipid), debugstr_guid(riid), stdobjref->cPublicRefs);
}
else
ifproxy_destroy(ifproxy);
return hr;
}
static HRESULT proxy_manager_find_ifproxy(struct proxy_manager * This, REFIID riid, struct ifproxy ** ifproxy_found)
{
HRESULT hr = E_NOINTERFACE; /* assume not found */
struct list * cursor;
EnterCriticalSection(&This->cs);
LIST_FOR_EACH(cursor, &This->interfaces)
{
struct ifproxy * ifproxy = LIST_ENTRY(cursor, struct ifproxy, entry);
if (IsEqualIID(riid, &ifproxy->iid))
{
*ifproxy_found = ifproxy;
hr = S_OK;
break;
}
}
LeaveCriticalSection(&This->cs);
return hr;
}
static void proxy_manager_disconnect(struct proxy_manager * This)
{
struct list * cursor;
TRACE("oxid = %s, oid = %s\n", wine_dbgstr_longlong(This->oxid),
wine_dbgstr_longlong(This->oid));
EnterCriticalSection(&This->cs);
/* SORFP_NOLIFTIMEMGMT proxies (for IRemUnknown) shouldn't be
* disconnected - it won't do anything anyway, except cause
* problems for other objects that depend on this proxy always
* working */
if (!(This->sorflags & SORFP_NOLIFETIMEMGMT))
{
LIST_FOR_EACH(cursor, &This->interfaces)
{
struct ifproxy * ifproxy = LIST_ENTRY(cursor, struct ifproxy, entry);
ifproxy_disconnect(ifproxy);
}
}
/* apartment is being destroyed so don't keep a pointer around to it */
This->parent = NULL;
LeaveCriticalSection(&This->cs);
}
static HRESULT proxy_manager_get_remunknown(struct proxy_manager * This, IRemUnknown **remunk)
{
HRESULT hr = S_OK;
struct apartment *apt;
BOOL called_in_original_apt;
/* we don't want to try and unmarshal or use IRemUnknown if we don't want
* lifetime management */
if (This->sorflags & SORFP_NOLIFETIMEMGMT)
return S_FALSE;
apt = COM_CurrentApt();
if (!apt)
return CO_E_NOTINITIALIZED;
called_in_original_apt = This->parent && (This->parent->oxid == apt->oxid);
EnterCriticalSection(&This->cs);
/* only return the cached object if called from the original apartment.
* in future, we might want to make the IRemUnknown proxy callable from any
* apartment to avoid these checks */
if (This->remunk && called_in_original_apt)
{
/* already created - return existing object */
*remunk = This->remunk;
IRemUnknown_AddRef(*remunk);
}
else if (!This->parent)
/* disconnected - we can't create IRemUnknown */
hr = S_FALSE;
else
{
STDOBJREF stdobjref;
/* Don't want IRemUnknown lifetime management as this is IRemUnknown!
* We also don't care about whether or not the stub is still alive */
stdobjref.flags = SORFP_NOLIFETIMEMGMT | SORF_NOPING;
stdobjref.cPublicRefs = 1;
/* oxid of destination object */
stdobjref.oxid = This->oxid;
/* FIXME: what should be used for the oid? The DCOM draft doesn't say */
stdobjref.oid = (OID)-1;
stdobjref.ipid = This->oxid_info.ipidRemUnknown;
/* do the unmarshal */
hr = unmarshal_object(&stdobjref, COM_CurrentApt(), This->dest_context,
This->dest_context_data, &IID_IRemUnknown,
&This->oxid_info, (void**)remunk);
if (hr == S_OK && called_in_original_apt)
{
This->remunk = *remunk;
IRemUnknown_AddRef(This->remunk);
}
}
LeaveCriticalSection(&This->cs);
TRACE("got IRemUnknown* pointer %p, hr = 0x%08x\n", *remunk, hr);
return hr;
}
/* destroys a proxy manager, freeing the memory it used.
* Note: this function should not be called from a list iteration in the
* apartment, due to the fact that it removes itself from the apartment and
* it could add a proxy to IRemUnknown into the apartment. */
static void proxy_manager_destroy(struct proxy_manager * This)
{
struct list * cursor;
TRACE("oxid = %s, oid = %s\n", wine_dbgstr_longlong(This->oxid),
wine_dbgstr_longlong(This->oid));
if (This->parent)
{
EnterCriticalSection(&This->parent->cs);
/* remove ourself from the list of proxy objects in the apartment */
LIST_FOR_EACH(cursor, &This->parent->proxies)
{
if (cursor == &This->entry)
{
list_remove(&This->entry);
break;
}
}
LeaveCriticalSection(&This->parent->cs);
}
/* destroy all of the interface proxies */
while ((cursor = list_head(&This->interfaces)))
{
struct ifproxy * ifproxy = LIST_ENTRY(cursor, struct ifproxy, entry);
ifproxy_destroy(ifproxy);
}
if (This->remunk) IRemUnknown_Release(This->remunk);
CoTaskMemFree(This->oxid_info.psa);
DEBUG_CLEAR_CRITSEC_NAME(&This->cs);
DeleteCriticalSection(&This->cs);
CloseHandle(This->remoting_mutex);
HeapFree(GetProcessHeap(), 0, This);
}
/* finds the proxy manager corresponding to a given OXID and OID that has
* been unmarshaled in the specified apartment. The caller must release the
* reference to the proxy_manager when the object is no longer used. */
static BOOL find_proxy_manager(APARTMENT * apt, OXID oxid, OID oid, struct proxy_manager ** proxy_found)
{
BOOL found = FALSE;
struct list * cursor;
EnterCriticalSection(&apt->cs);
LIST_FOR_EACH(cursor, &apt->proxies)
{
struct proxy_manager * proxy = LIST_ENTRY(cursor, struct proxy_manager, entry);
if ((oxid == proxy->oxid) && (oid == proxy->oid))
{
*proxy_found = proxy;
ClientIdentity_AddRef((IMultiQI *)&proxy->lpVtbl);
found = TRUE;
break;
}
}
LeaveCriticalSection(&apt->cs);
return found;
}
HRESULT apartment_disconnectproxies(struct apartment *apt)
{
struct list * cursor;
LIST_FOR_EACH(cursor, &apt->proxies)
{
struct proxy_manager * proxy = LIST_ENTRY(cursor, struct proxy_manager, entry);
proxy_manager_disconnect(proxy);
}
return S_OK;
}
/********************** StdMarshal implementation ****************************/
typedef struct _StdMarshalImpl
{
const IMarshalVtbl *lpvtbl;
LONG ref;
IID iid;
DWORD dwDestContext;
LPVOID pvDestContext;
DWORD mshlflags;
} StdMarshalImpl;
static HRESULT WINAPI
StdMarshalImpl_QueryInterface(LPMARSHAL iface, REFIID riid, LPVOID *ppv)
{
*ppv = NULL;
if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IMarshal, riid))
{
*ppv = iface;
IUnknown_AddRef(iface);
return S_OK;
}
FIXME("No interface for %s.\n", debugstr_guid(riid));
return E_NOINTERFACE;
}
static ULONG WINAPI
StdMarshalImpl_AddRef(LPMARSHAL iface)
{
StdMarshalImpl *This = (StdMarshalImpl *)iface;
return InterlockedIncrement(&This->ref);
}
static ULONG WINAPI
StdMarshalImpl_Release(LPMARSHAL iface)
{
StdMarshalImpl *This = (StdMarshalImpl *)iface;
ULONG ref = InterlockedDecrement(&This->ref);
if (!ref) HeapFree(GetProcessHeap(),0,This);
return ref;
}
static HRESULT WINAPI
StdMarshalImpl_GetUnmarshalClass(
LPMARSHAL iface, REFIID riid, void* pv, DWORD dwDestContext,
void* pvDestContext, DWORD mshlflags, CLSID* pCid)
{
*pCid = CLSID_DfMarshal;
return S_OK;
}
static HRESULT WINAPI
StdMarshalImpl_GetMarshalSizeMax(
LPMARSHAL iface, REFIID riid, void* pv, DWORD dwDestContext,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -