Commit ad34f3dc authored by Robert Shearman's avatar Robert Shearman Committed by Alexandre Julliard

- Generate machine-local IPIDs.

- Make pipes be uniquely identified only by their IPID.
parent c1db191d
......@@ -246,8 +246,10 @@ APARTMENT* COM_CreateApartment(DWORD model)
list_init(&apt->proxies);
list_init(&apt->stubmgrs);
apt->oidc = 1;
apt->ipidc = 1;
apt->refs = 1;
apt->remunk_exported = FALSE;
apt->oidc = 1;
InitializeCriticalSection(&apt->cs);
apt->model = model;
......@@ -363,6 +365,30 @@ APARTMENT *COM_ApartmentFromOXID(OXID oxid, BOOL ref)
return result;
}
/* gets the apartment which has a given creator thread ID. The caller must
* release the reference from the apartment as soon as the apartment pointer
* is no longer required. */
APARTMENT *COM_ApartmentFromTID(DWORD tid)
{
APARTMENT *result = NULL;
struct list *cursor;
EnterCriticalSection(&csApartment);
LIST_FOR_EACH( cursor, &apts )
{
struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
if (apt->tid == tid)
{
result = apt;
COM_ApartmentAddRef(result);
break;
}
}
LeaveCriticalSection(&csApartment);
return result;
}
HWND COM_GetApartmentWin(OXID oxid, BOOL ref)
{
APARTMENT *apt;
......
......@@ -110,6 +110,7 @@ struct proxy_manager
DWORD refs; /* proxy reference count (LOCK) */
CRITICAL_SECTION cs; /* thread safety for this object and children */
ULONG sorflags; /* STDOBJREF flags (RO) */
IRemUnknown *remunk; /* proxy to IRemUnknown used for lifecycle management (CS cs) */
};
/* this needs to become a COM object that implements IRemUnknown */
......@@ -122,13 +123,15 @@ struct apartment
DWORD tid; /* thread id (RO) */
HANDLE thread; /* thread handle (RO) */
OXID oxid; /* object exporter ID (RO) */
OID oidc; /* object ID counter, starts at 1, zero is invalid OID (CS cs) */
DWORD ipidc; /* interface pointer ID counter, starts at 1 (CS cs) */
HWND win; /* message window (RO) */
CRITICAL_SECTION cs; /* thread safety */
LPMESSAGEFILTER filter; /* message filter (CS cs) */
struct list proxies; /* imported objects (CS cs) */
struct list stubmgrs; /* stub managers for exported objects (CS cs) */
BOOL remunk_exported; /* has the IRemUnknown interface for this apartment been created yet? (CS cs) */
OID oidc; /* object ID counter, starts at 1, zero is invalid OID (CS cs). FIXME: remove me */
DWORD listenertid; /* id of apartment_listener_thread. FIXME: remove me */
};
......@@ -177,12 +180,15 @@ ULONG stub_manager_int_release(struct stub_manager *This);
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_release(struct stub_manager *m, ULONG refs);
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 stub_manager *get_stub_manager(APARTMENT *apt, OID oid);
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);
HRESULT register_ifstub(APARTMENT *apt, STDOBJREF *stdobjref, REFIID riid, IUnknown *obj, MSHLFLAGS mshlflags);
HRESULT ipid_to_stub_manager(const IPID *ipid, APARTMENT **stub_apt, struct stub_manager **stubmgr_ret);
IRpcStubBuffer *ipid_to_stubbuffer(const IPID *ipid);
HRESULT start_apartment_remote_unknown(void);
IRpcStubBuffer *mid_to_stubbuffer(wine_marshal_id *mid);
......@@ -203,6 +209,7 @@ int WINAPI FileMonikerImpl_DecomposePath(LPCOLESTR str, LPOLESTR** stringTable);
/* compobj.c */
APARTMENT *COM_CreateApartment(DWORD model);
APARTMENT *COM_ApartmentFromOXID(OXID oxid, BOOL ref);
APARTMENT *COM_ApartmentFromTID(DWORD tid);
DWORD COM_ApartmentAddRef(struct apartment *apt);
DWORD COM_ApartmentRelease(struct apartment *apt);
......
......@@ -56,6 +56,8 @@ extern const CLSID CLSID_DfMarshal;
* when the proxy disconnects or is destroyed */
#define SORFP_NOLIFETIMEMGMT SORF_OXRES1
static HRESULT unmarshal_object(const STDOBJREF *stdobjref, APARTMENT *apt, REFIID riid, void **object);
/* Marshalling just passes a unique identifier to the remote client,
* that makes it possible to find the passed interface again.
*
......@@ -83,35 +85,8 @@ get_facbuf_for_iid(REFIID riid,IPSFactoryBuffer **facbuf) {
return CoGetClassObject(&pxclsid,CLSCTX_INPROC_SERVER,NULL,&IID_IPSFactoryBuffer,(LPVOID*)facbuf);
}
IRpcStubBuffer *mid_to_stubbuffer(wine_marshal_id *mid)
{
IRpcStubBuffer *ret;
APARTMENT *apt;
struct stub_manager *m;
if (!(apt = COM_ApartmentFromOXID(mid->oxid, TRUE)))
{
WARN("Could not map OXID %s to apartment object\n", wine_dbgstr_longlong(mid->oxid));
return NULL;
}
if (!(m = get_stub_manager(apt, mid->oid)))
{
WARN("unknown OID %s\n", wine_dbgstr_longlong(mid->oid));
return NULL;
}
ret = stub_manager_ipid_to_stubbuffer(m, &mid->ipid);
stub_manager_int_release(m);
COM_ApartmentRelease(apt);
return ret;
}
/* creates a new stub manager and sets stdobjref->oid when stdobjref->oid == 0 */
static HRESULT register_ifstub(APARTMENT *apt, STDOBJREF *stdobjref, REFIID riid, IUnknown *obj, MSHLFLAGS mshlflags)
HRESULT register_ifstub(APARTMENT *apt, STDOBJREF *stdobjref, REFIID riid, IUnknown *obj, MSHLFLAGS mshlflags)
{
struct stub_manager *manager = NULL;
struct ifstub *ifstub;
......
......@@ -59,7 +59,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(ole);
struct request_header
{
DWORD reqid;
wine_marshal_id mid;
IPID ipid;
DWORD iMethod;
DWORD cbBuffer;
};
......@@ -162,7 +162,6 @@ static DWORD WINAPI stub_dispatch_thread(LPVOID);
static HRESULT
PIPE_RegisterPipe(wine_marshal_id *mid, HANDLE hPipe, BOOL startreader)
{
/* FIXME: this pipe caching code is commented out because it is breaks the
* tests, causing them hang due to writing to or reading from the wrong pipe.
*/
......@@ -205,15 +204,21 @@ PIPE_FindByMID(wine_marshal_id *mid) {
}
static struct pipe*
PIPE_GetFromMID(wine_marshal_id *mid) {
int i;
for (i=0;i<nrofpipes;i++) {
if ((pipes[i].mid.oxid==mid->oxid) &&
(GetCurrentThreadId()==pipes[i].tid)
)
return pipes+i;
}
return NULL;
PIPE_GetFromIPID(const IPID *ipid) {
int i;
for (i=0; i<nrofpipes; i++)
{
/* compare TID and PID fields */
if ((pipes[i].mid.ipid.Data2 == ipid->Data2) &&
(pipes[i].mid.ipid.Data3 == ipid->Data3) &&
(GetCurrentThreadId() == pipes[i].tid))
return pipes+i;
/* special case for IRemUnknown IPID */
else if ((pipes[i].mid.oxid == *(OXID *)ipid->Data4) &&
(GetCurrentThreadId() == pipes[i].tid))
return pipes+i;
}
return NULL;
}
static HRESULT
......@@ -331,7 +336,7 @@ COM_InvokeAndRpcSend(struct rpc *req) {
HRESULT hres;
DWORD reqtype;
if (!(stub = mid_to_stubbuffer(&(req->reqh.mid))))
if (!(stub = ipid_to_stubbuffer(&(req->reqh.ipid))))
{
ERR("Stub not found?\n");
return E_FAIL;
......@@ -366,7 +371,7 @@ RPC_QueueRequestAndWait(struct rpc *req) {
struct rpc *xreq;
HRESULT hres;
DWORD reqtype;
struct pipe *xpipe = PIPE_GetFromMID(&(req->reqh.mid));
struct pipe *xpipe = PIPE_GetFromIPID(&(req->reqh.ipid));
if (!xpipe) {
FIXME("no pipe found.\n");
......@@ -421,7 +426,7 @@ PipeBuf_SendReceive(LPRPCCHANNELBUFFER iface,RPCOLEMESSAGE* msg,ULONG *status)
if (hres) return hres;
req->reqh.iMethod = msg->iMethod;
req->reqh.cbBuffer = msg->cbBuffer;
memcpy(&(req->reqh.mid),&(This->mid),sizeof(This->mid));
req->reqh.ipid = This->mid.ipid;
req->Buffer = msg->Buffer;
hres = RPC_QueueRequestAndWait(req);
if (hres) {
......
......@@ -243,11 +243,103 @@ static struct ifstub *stub_manager_ipid_to_ifstub(struct stub_manager *m, const
return result;
}
IRpcStubBuffer *stub_manager_ipid_to_stubbuffer(struct stub_manager *m, const IPID *ipid)
/* gets the stub manager associated with an ipid - caller must have
* a reference to the apartment while a reference to the stub manager is held.
* it must also call release on the stub manager when it is no longer needed */
static struct stub_manager *get_stub_manager_from_ipid(APARTMENT *apt, const IPID *ipid)
{
struct ifstub *ifstub = stub_manager_ipid_to_ifstub(m, ipid);
return ifstub ? ifstub->stubbuffer : NULL;
struct stub_manager *result = NULL;
struct list *cursor;
EnterCriticalSection(&apt->cs);
LIST_FOR_EACH( cursor, &apt->stubmgrs )
{
struct stub_manager *m = LIST_ENTRY( cursor, struct stub_manager, entry );
if (stub_manager_ipid_to_ifstub(m, ipid))
{
result = m;
stub_manager_int_addref(result);
break;
}
}
LeaveCriticalSection(&apt->cs);
if (result)
TRACE("found %p for ipid %s\n", result, debugstr_guid(ipid));
else
ERR("not found for ipid %s\n", debugstr_guid(ipid));
return result;
}
HRESULT ipid_to_stub_manager(const IPID *ipid, APARTMENT **stub_apt, struct stub_manager **stubmgr_ret)
{
/* FIXME: hack for IRemUnknown */
if (ipid->Data2 == 0xffff)
*stub_apt = COM_ApartmentFromOXID(*(OXID *)ipid->Data4, TRUE);
else
*stub_apt = COM_ApartmentFromTID(ipid->Data2);
if (!*stub_apt)
{
ERR("Couldn't find apartment corresponding to TID 0x%04x\n", ipid->Data2);
return RPC_E_INVALID_OBJECT;
}
*stubmgr_ret = get_stub_manager_from_ipid(*stub_apt, ipid);
if (!*stubmgr_ret)
{
COM_ApartmentRelease(*stub_apt);
*stub_apt = NULL;
return RPC_E_INVALID_OBJECT;
}
return S_OK;
}
IRpcStubBuffer *ipid_to_stubbuffer(const IPID *ipid)
{
IRpcStubBuffer *ret = NULL;
APARTMENT *apt;
struct stub_manager *stubmgr;
struct ifstub *ifstub;
HRESULT hr;
hr = ipid_to_stub_manager(ipid, &apt, &stubmgr);
if (hr != S_OK) return NULL;
ifstub = stub_manager_ipid_to_ifstub(stubmgr, ipid);
if (ifstub)
ret = ifstub->stubbuffer;
stub_manager_int_release(stubmgr);
COM_ApartmentRelease(apt);
return ret;
}
/* generates an ipid in the following format (similar to native version):
* Data1 = apartment-local ipid counter
* Data2 = apartment creator thread ID
* Data3 = process ID
* Data4 = random value
*/
static inline HRESULT generate_ipid(struct stub_manager *m, IPID *ipid)
{
HRESULT hr;
hr = UuidCreate(ipid);
if (FAILED(hr))
{
ERR("couldn't create IPID for stub manager %p\n", m);
UuidCreateNil(ipid);
return hr;
}
EnterCriticalSection(&m->apt->cs);
ipid->Data1 = m->apt->ipidc++;
LeaveCriticalSection(&m->apt->cs);
ipid->Data2 = (USHORT)m->apt->tid;
ipid->Data3 = (USHORT)GetCurrentProcessId();
return S_OK;
}
/* registers a new interface stub COM object with the stub manager and returns registration record */
......@@ -273,12 +365,26 @@ struct ifstub *stub_manager_new_ifstub(struct stub_manager *m, IRpcStubBuffer *s
stub->state = IFSTUB_STATE_NORMAL_MARSHALED;
stub->iid = *iid;
stub->ipid = *iid; /* FIXME: should be globally unique */
/* FIXME: hack for IRemUnknown because we don't notify SCM of our IPID
* yet, so we need to use a well-known one */
if (IsEqualIID(iid, &IID_IRemUnknown))
{
stub->ipid.Data1 = 0xffffffff;
stub->ipid.Data2 = 0xffff;
stub->ipid.Data3 = 0xffff;
assert(sizeof(stub->ipid.Data4) == sizeof(m->apt->oxid));
memcpy(&stub->ipid.Data4, &m->apt->oxid, sizeof(OXID));
}
else
generate_ipid(m, &stub->ipid);
EnterCriticalSection(&m->lock);
list_add_head(&m->ifstubs, &stub->entry);
LeaveCriticalSection(&m->lock);
TRACE("ifstub %p created with ipid %s\n", stub, debugstr_guid(&stub->ipid));
return stub;
}
......@@ -351,3 +457,5 @@ BOOL stub_manager_is_table_marshaled(struct stub_manager *m, const IPID *ipid)
return ret;
}
const IID IID_IRemUnknown = { 0x00000131, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46} };
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