Commit 4c8d59dd authored by Robert Shearman's avatar Robert Shearman Committed by Alexandre Julliard

Implement table marshaling.

parent 049e75a3
...@@ -48,10 +48,8 @@ ...@@ -48,10 +48,8 @@
* *
* - Implement IRemUnknown and marshalling for it, then use that for * - Implement IRemUnknown and marshalling for it, then use that for
* reffing/unreffing the stub manager from a proxy instead of our * reffing/unreffing the stub manager from a proxy instead of our
* current hack of simply reffing the stub manager once when it's * current hack of simply reaching into local process memory to do it,
* registered. * which obviously doesn't work inter-process.
* - Implement table marshalling, then use it to let us do the final
* rework of the threading
* *
* - Make our custom marshalling use NDR to be wire compatible with * - Make our custom marshalling use NDR to be wire compatible with
* native DCOM * native DCOM
......
...@@ -51,6 +51,13 @@ typedef struct apartment APARTMENT; ...@@ -51,6 +51,13 @@ typedef struct apartment APARTMENT;
* must be used. * must be used.
*/ */
typedef enum ifstub_state
{
IFSTUB_STATE_NORMAL_MARSHALED,
IFSTUB_STATE_NORMAL_UNMARSHALED,
IFSTUB_STATE_TABLE_MARSHALED
} IFSTUB_STATE;
/* an interface stub */ /* an interface stub */
struct ifstub struct ifstub
{ {
...@@ -59,7 +66,7 @@ struct ifstub ...@@ -59,7 +66,7 @@ struct ifstub
IID iid; /* RO */ IID iid; /* RO */
IPID ipid; /* RO */ IPID ipid; /* RO */
IUnknown *iface; /* RO */ IUnknown *iface; /* RO */
BOOL table; /* CS stub_manager->lock */ IFSTUB_STATE state; /* CS stub_manager->lock */
}; };
...@@ -81,12 +88,13 @@ struct stub_manager ...@@ -81,12 +88,13 @@ struct stub_manager
/* imported interface proxy */ /* imported interface proxy */
struct ifproxy struct ifproxy
{ {
struct list entry; struct list entry; /* entry in proxy_manager list (CS parent->cs) */
struct proxy_manager *parent; /* owning proxy_manager (RO) */
LPVOID iface; /* interface pointer (RO) */ LPVOID iface; /* interface pointer (RO) */
IID iid; /* interface ID (RO) */ IID iid; /* interface ID (RO) */
IPID ipid; /* imported interface ID (RO) */ IPID ipid; /* imported interface ID (RO) */
LPRPCPROXYBUFFER proxy; /* interface proxy (RO) */ LPRPCPROXYBUFFER proxy; /* interface proxy (RO) */
DWORD refs; /* imported (public) references (CS ?) */ DWORD refs; /* imported (public) references (CS parent->cs) */
}; };
/* imported object / proxy manager */ /* imported object / proxy manager */
...@@ -168,10 +176,12 @@ ULONG stub_manager_int_release(struct stub_manager *This); ...@@ -168,10 +176,12 @@ ULONG stub_manager_int_release(struct stub_manager *This);
struct stub_manager *new_stub_manager(APARTMENT *apt, IUnknown *object); struct stub_manager *new_stub_manager(APARTMENT *apt, IUnknown *object);
ULONG stub_manager_ext_addref(struct stub_manager *m, ULONG refs); ULONG stub_manager_ext_addref(struct stub_manager *m, ULONG refs);
ULONG stub_manager_ext_release(struct stub_manager *m, ULONG refs); ULONG stub_manager_ext_release(struct stub_manager *m, ULONG refs);
IRpcStubBuffer *stub_manager_ipid_to_stubbuffer(struct stub_manager *m, const IPID *iid); IRpcStubBuffer *stub_manager_ipid_to_stubbuffer(struct stub_manager *m, const IPID *ipid);
struct ifstub *stub_manager_new_ifstub(struct stub_manager *m, IRpcStubBuffer *sb, IUnknown *iptr, REFIID iid, BOOL tablemarshal); struct ifstub *stub_manager_new_ifstub(struct stub_manager *m, IRpcStubBuffer *sb, IUnknown *iptr, REFIID iid, BOOL tablemarshal);
struct stub_manager *get_stub_manager(APARTMENT *apt, OID oid); struct stub_manager *get_stub_manager(APARTMENT *apt, OID oid);
struct stub_manager *get_stub_manager_from_object(APARTMENT *apt, void *object); struct stub_manager *get_stub_manager_from_object(APARTMENT *apt, void *object);
BOOL stub_manager_notify_unmarshal(struct stub_manager *m, const IPID *ipid);
BOOL stub_manager_is_table_marshaled(struct stub_manager *m, const IPID *ipid);
IRpcStubBuffer *mid_to_stubbuffer(wine_marshal_id *mid); IRpcStubBuffer *mid_to_stubbuffer(wine_marshal_id *mid);
......
...@@ -104,11 +104,12 @@ IRpcStubBuffer *mid_to_stubbuffer(wine_marshal_id *mid) ...@@ -104,11 +104,12 @@ IRpcStubBuffer *mid_to_stubbuffer(wine_marshal_id *mid)
} }
/* creates a new stub manager and sets mid->oid when mid->oid == 0 */ /* creates a new stub manager and sets mid->oid when mid->oid == 0 */
static HRESULT register_ifstub(wine_marshal_id *mid, REFIID riid, IUnknown *obj, IRpcStubBuffer *stub, BOOL tablemarshal) static HRESULT register_ifstub(wine_marshal_id *mid, REFIID riid, IUnknown *obj, IRpcStubBuffer *stub, MSHLFLAGS mshlflags)
{ {
struct stub_manager *manager = NULL; struct stub_manager *manager = NULL;
struct ifstub *ifstub; struct ifstub *ifstub;
APARTMENT *apt; APARTMENT *apt;
BOOL tablemarshal;
if (!(apt = COM_ApartmentFromOXID(mid->oxid, TRUE))) if (!(apt = COM_ApartmentFromOXID(mid->oxid, TRUE)))
{ {
...@@ -136,6 +137,8 @@ static HRESULT register_ifstub(wine_marshal_id *mid, REFIID riid, IUnknown *obj, ...@@ -136,6 +137,8 @@ static HRESULT register_ifstub(wine_marshal_id *mid, REFIID riid, IUnknown *obj,
mid->oid = manager->oid; mid->oid = manager->oid;
} }
tablemarshal = ((mshlflags & MSHLFLAGS_TABLESTRONG) || (mshlflags & MSHLFLAGS_TABLEWEAK));
ifstub = stub_manager_new_ifstub(manager, stub, obj, riid, tablemarshal); ifstub = stub_manager_new_ifstub(manager, stub, obj, riid, tablemarshal);
if (!ifstub) if (!ifstub)
{ {
...@@ -146,7 +149,10 @@ static HRESULT register_ifstub(wine_marshal_id *mid, REFIID riid, IUnknown *obj, ...@@ -146,7 +149,10 @@ static HRESULT register_ifstub(wine_marshal_id *mid, REFIID riid, IUnknown *obj,
return E_OUTOFMEMORY; return E_OUTOFMEMORY;
} }
if (!tablemarshal) stub_manager_ext_addref(manager, 1); if (!tablemarshal)
stub_manager_ext_addref(manager, 1);
else if (mshlflags & MSHLFLAGS_TABLESTRONG)
stub_manager_ext_addref(manager, 1);
mid->ipid = ifstub->ipid; mid->ipid = ifstub->ipid;
...@@ -225,13 +231,48 @@ static const IInternalUnknownVtbl ClientIdentity_Vtbl = ...@@ -225,13 +231,48 @@ static const IInternalUnknownVtbl ClientIdentity_Vtbl =
static HRESULT ifproxy_get_public_ref(struct ifproxy * This) static HRESULT ifproxy_get_public_ref(struct ifproxy * This)
{ {
EnterCriticalSection(&This->parent->cs);
if (This->refs == 0)
{
APARTMENT * apt;
TRACE("getting public ref for ifproxy %p\n", This);
/* FIXME: call IRemUnknown::RemAddRef if necessary */ /* FIXME: call IRemUnknown::RemAddRef if necessary */
/* FIXME: this is a hack around not yet implemented IRemUnknown */
if ((apt = COM_ApartmentFromOXID(This->parent->oxid, TRUE)))
{
struct stub_manager * stubmgr;
if ((stubmgr = get_stub_manager(apt, This->parent->oid)))
{
stub_manager_ext_addref(stubmgr, 1);
This->refs += 1;
stub_manager_int_release(stubmgr);
}
COM_ApartmentRelease(apt);
}
else
FIXME("Need to implement IRemUnknown for inter-process table marshaling\n");
}
LeaveCriticalSection(&This->parent->cs);
return S_OK; return S_OK;
} }
static HRESULT ifproxy_release_public_refs(struct ifproxy * This) static HRESULT ifproxy_release_public_refs(struct ifproxy * This)
{ {
/* FIXME: call IRemUnknown::RemRelease */ EnterCriticalSection(&This->parent->cs);
/*
if (This->refs > 0)
{
// FIXME: call IRemUnknown::RemRelease
This->refs = 0;
}
*/
LeaveCriticalSection(&This->parent->cs);
return S_OK; return S_OK;
} }
...@@ -292,6 +333,7 @@ static HRESULT proxy_manager_create_ifproxy(struct proxy_manager * This, IPID ip ...@@ -292,6 +333,7 @@ static HRESULT proxy_manager_create_ifproxy(struct proxy_manager * This, IPID ip
list_init(&ifproxy->entry); list_init(&ifproxy->entry);
ifproxy->parent = This;
ifproxy->ipid = ipid; ifproxy->ipid = ipid;
ifproxy->iid = *riid; ifproxy->iid = *riid;
ifproxy->refs = cPublicRefs; ifproxy->refs = cPublicRefs;
...@@ -513,7 +555,6 @@ StdMarshalImpl_MarshalInterface( ...@@ -513,7 +555,6 @@ StdMarshalImpl_MarshalInterface(
HRESULT hres; HRESULT hres;
IRpcStubBuffer *stubbuffer; IRpcStubBuffer *stubbuffer;
IPSFactoryBuffer *psfacbuf; IPSFactoryBuffer *psfacbuf;
BOOL tablemarshal;
struct stub_manager *manager; struct stub_manager *manager;
APARTMENT *apt = COM_CurrentApt(); APARTMENT *apt = COM_CurrentApt();
...@@ -537,9 +578,6 @@ StdMarshalImpl_MarshalInterface( ...@@ -537,9 +578,6 @@ StdMarshalImpl_MarshalInterface(
return hres; return hres;
} }
tablemarshal = ((mshlflags & MSHLFLAGS_TABLESTRONG) || (mshlflags & MSHLFLAGS_TABLEWEAK));
if (tablemarshal) FIXME("table marshalling unimplemented\n");
/* now fill out the MID */ /* now fill out the MID */
mid.oxid = apt->oxid; mid.oxid = apt->oxid;
...@@ -555,7 +593,7 @@ StdMarshalImpl_MarshalInterface( ...@@ -555,7 +593,7 @@ StdMarshalImpl_MarshalInterface(
mid.oid = 0; /* will be set by register_ifstub */ mid.oid = 0; /* will be set by register_ifstub */
} }
hres = register_ifstub(&mid, riid, pUnk, stubbuffer, tablemarshal); hres = register_ifstub(&mid, riid, pUnk, stubbuffer, mshlflags);
IUnknown_Release(pUnk); IUnknown_Release(pUnk);
...@@ -581,6 +619,8 @@ StdMarshalImpl_UnmarshalInterface(LPMARSHAL iface, IStream *pStm, REFIID riid, v ...@@ -581,6 +619,8 @@ StdMarshalImpl_UnmarshalInterface(LPMARSHAL iface, IStream *pStm, REFIID riid, v
IRpcChannelBuffer *chanbuf; IRpcChannelBuffer *chanbuf;
struct proxy_manager *proxy_manager; struct proxy_manager *proxy_manager;
APARTMENT *apt = COM_CurrentApt(); APARTMENT *apt = COM_CurrentApt();
APARTMENT *stub_apt;
ULONG cPublicRefs = 1;
TRACE("(...,%s,....)\n",debugstr_guid(riid)); TRACE("(...,%s,....)\n",debugstr_guid(riid));
...@@ -601,12 +641,46 @@ StdMarshalImpl_UnmarshalInterface(LPMARSHAL iface, IStream *pStm, REFIID riid, v ...@@ -601,12 +641,46 @@ StdMarshalImpl_UnmarshalInterface(LPMARSHAL iface, IStream *pStm, REFIID riid, v
hres = IUnknown_QueryInterface(stubmgr->object, riid, ppv); hres = IUnknown_QueryInterface(stubmgr->object, riid, ppv);
/* unref the ifstub. FIXME: only do this on success? */ /* unref the ifstub. FIXME: only do this on success? */
if (!stub_manager_is_table_marshaled(stubmgr, &mid.ipid))
stub_manager_ext_release(stubmgr, 1); stub_manager_ext_release(stubmgr, 1);
stub_manager_int_release(stubmgr); stub_manager_int_release(stubmgr);
return hres; 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 = COM_ApartmentFromOXID(mid.oxid, TRUE)))
{
if ((stubmgr = get_stub_manager(stub_apt, mid.oid)))
{
if (!stub_manager_notify_unmarshal(stubmgr, &mid.ipid))
hres = CO_E_OBJNOTCONNECTED;
/* FIXME: hack around not using STDOBJREF yet */
if (stub_manager_is_table_marshaled(stubmgr, &mid.ipid))
cPublicRefs = 0;
stub_manager_int_release(stubmgr);
}
else
{
WARN("Couldn't find object for OXID %s, OID %s, assuming disconnected\n",
wine_dbgstr_longlong(mid.oxid),
wine_dbgstr_longlong(mid.oid));
hres = CO_E_OBJNOTCONNECTED;
}
COM_ApartmentRelease(stub_apt);
}
else
TRACE("Treating unmarshal from OXID %s as inter-process\n", wine_dbgstr_longlong(mid.oxid));
if (hres) return hres;
if (!find_proxy_manager(apt, mid.oxid, mid.oid, &proxy_manager)) if (!find_proxy_manager(apt, mid.oxid, mid.oid, &proxy_manager))
{ {
hres = PIPE_GetNewPipeBuf(&mid,&chanbuf); hres = PIPE_GetNewPipeBuf(&mid,&chanbuf);
...@@ -621,7 +695,7 @@ StdMarshalImpl_UnmarshalInterface(LPMARSHAL iface, IStream *pStm, REFIID riid, v ...@@ -621,7 +695,7 @@ StdMarshalImpl_UnmarshalInterface(LPMARSHAL iface, IStream *pStm, REFIID riid, v
if (hres == S_OK) if (hres == S_OK)
IUnknown_AddRef((IUnknown *)ifproxy->iface); IUnknown_AddRef((IUnknown *)ifproxy->iface);
else if (hres == E_NOINTERFACE) else if (hres == E_NOINTERFACE)
hres = proxy_manager_create_ifproxy(proxy_manager, mid.ipid, riid, 1, &ifproxy); hres = proxy_manager_create_ifproxy(proxy_manager, mid.ipid, riid, cPublicRefs, &ifproxy);
if (hres == S_OK) if (hres == S_OK)
*ppv = ifproxy->iface; /* AddRef'd above */ *ppv = ifproxy->iface; /* AddRef'd above */
......
...@@ -266,7 +266,12 @@ struct ifstub *stub_manager_new_ifstub(struct stub_manager *m, IRpcStubBuffer *s ...@@ -266,7 +266,12 @@ struct ifstub *stub_manager_new_ifstub(struct stub_manager *m, IRpcStubBuffer *s
/* no need to ref this, same object as sb */ /* no need to ref this, same object as sb */
stub->iface = iptr; stub->iface = iptr;
stub->table = tablemarshal;
if (tablemarshal)
stub->state = IFSTUB_STATE_TABLE_MARSHALED;
else
stub->state = IFSTUB_STATE_NORMAL_MARSHALED;
stub->iid = *iid; stub->iid = *iid;
stub->ipid = *iid; /* FIXME: should be globally unique */ stub->ipid = *iid; /* FIXME: should be globally unique */
...@@ -288,3 +293,61 @@ static void stub_manager_delete_ifstub(struct stub_manager *m, struct ifstub *if ...@@ -288,3 +293,61 @@ static void stub_manager_delete_ifstub(struct stub_manager *m, struct ifstub *if
HeapFree(GetProcessHeap(), 0, ifstub); HeapFree(GetProcessHeap(), 0, ifstub);
} }
/* returns TRUE if it is possible to unmarshal, FALSE otherwise. */
BOOL stub_manager_notify_unmarshal(struct stub_manager *m, const IPID *ipid)
{
struct ifstub *ifstub;
BOOL ret;
ifstub = stub_manager_ipid_to_ifstub(m, ipid);
if (!ifstub)
{
WARN("Can't find ifstub for OID %s, IPID %s\n",
wine_dbgstr_longlong(m->oid), wine_dbgstr_guid(ipid));
return FALSE;
}
EnterCriticalSection(&m->lock);
switch (ifstub->state)
{
case IFSTUB_STATE_TABLE_MARSHALED:
ret = TRUE;
break;
case IFSTUB_STATE_NORMAL_MARSHALED:
ifstub->state = IFSTUB_STATE_NORMAL_UNMARSHALED;
ret = TRUE;
break;
default:
WARN("object OID %s, IPID %s already unmarshaled\n",
wine_dbgstr_longlong(m->oid), wine_dbgstr_guid(ipid));
ret = FALSE;
break;
}
LeaveCriticalSection(&m->lock);
return ret;
}
/* is an ifstub table marshaled? */
BOOL stub_manager_is_table_marshaled(struct stub_manager *m, const IPID *ipid)
{
struct ifstub *ifstub;
BOOL ret;
ifstub = stub_manager_ipid_to_ifstub(m, ipid);
if (!ifstub)
{
WARN("Can't find ifstub for OID %s, IPID %s\n",
wine_dbgstr_longlong(m->oid), wine_dbgstr_guid(ipid));
return FALSE;
}
EnterCriticalSection(&m->lock);
ret = (ifstub->state == IFSTUB_STATE_TABLE_MARSHALED);
LeaveCriticalSection(&m->lock);
return ret;
}
...@@ -279,7 +279,7 @@ static void test_interthread_marshal_and_unmarshal() ...@@ -279,7 +279,7 @@ static void test_interthread_marshal_and_unmarshal()
IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL); IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy); hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
ok_ole_success(hr, CoReleaseMarshalData); ok_ole_success(hr, CoUnmarshalInterface);
IStream_Release(pStream); IStream_Release(pStream);
ok_more_than_one_lock(); ok_more_than_one_lock();
...@@ -397,7 +397,7 @@ static void test_tableweak_marshal_and_unmarshal_twice() ...@@ -397,7 +397,7 @@ static void test_tableweak_marshal_and_unmarshal_twice()
/* this line is shows the difference between weak and strong table marshaling: /* this line is shows the difference between weak and strong table marshaling:
* weak has cLocks == 0 * weak has cLocks == 0
* strong has cLocks > 0 */ * strong has cLocks > 0 */
todo_wine { ok_no_locks(); } ok_no_locks();
end_host_object(tid, thread); end_host_object(tid, thread);
} }
...@@ -446,7 +446,7 @@ static void test_tablestrong_marshal_and_unmarshal_twice() ...@@ -446,7 +446,7 @@ static void test_tablestrong_marshal_and_unmarshal_twice()
release_host_object(tid); release_host_object(tid);
IStream_Release(pStream); IStream_Release(pStream);
todo_wine { ok_no_locks(); } ok_no_locks();
end_host_object(tid, thread); end_host_object(tid, thread);
} }
...@@ -534,10 +534,8 @@ static void test_normal_marshal_and_unmarshal_twice() ...@@ -534,10 +534,8 @@ static void test_normal_marshal_and_unmarshal_twice()
IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL); IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2); hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
todo_wine {
ok(hr == CO_E_OBJNOTCONNECTED, ok(hr == CO_E_OBJNOTCONNECTED,
"CoUnmarshalInterface should have failed with error CO_E_OBJNOTCONNECTED for double unmarshal, instead of 0x%08lx\n", hr); "CoUnmarshalInterface should have failed with error CO_E_OBJNOTCONNECTED for double unmarshal, instead of 0x%08lx\n", hr);
}
IStream_Release(pStream); IStream_Release(pStream);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment