diff --git a/dlls/ole32/compobj.c b/dlls/ole32/compobj.c index b0fecba2f74..575f04fd230 100644 --- a/dlls/ole32/compobj.c +++ b/dlls/ole32/compobj.c @@ -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; diff --git a/dlls/ole32/compobj_private.h b/dlls/ole32/compobj_private.h index 3aa9d6748b4..ee9ed9a3058 100644 --- a/dlls/ole32/compobj_private.h +++ b/dlls/ole32/compobj_private.h @@ -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); diff --git a/dlls/ole32/marshal.c b/dlls/ole32/marshal.c index 9fb76752a5d..84ea8fdf206 100644 --- a/dlls/ole32/marshal.c +++ b/dlls/ole32/marshal.c @@ -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; diff --git a/dlls/ole32/rpc.c b/dlls/ole32/rpc.c index 371632a8a0a..b70e74388aa 100644 --- a/dlls/ole32/rpc.c +++ b/dlls/ole32/rpc.c @@ -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;ioxid) && - (GetCurrentThreadId()==pipes[i].tid) - ) - return pipes+i; - } - return NULL; +PIPE_GetFromIPID(const IPID *ipid) { + int i; + for (i=0; iData2) && + (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) { diff --git a/dlls/ole32/stubmanager.c b/dlls/ole32/stubmanager.c index 29f495299f7..362edf5760f 100644 --- a/dlls/ole32/stubmanager.c +++ b/dlls/ole32/stubmanager.c @@ -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} };