[OLE #12] Implement the stub manager
Mike Hearn
mh at codeweavers.com
Thu Dec 23 08:42:22 CST 2004
This makes quite a few tests pass, and has been tested against
InstallShield.
- Implement the COM stub manager, refactor the current stub code
- Begin implementing interface stubs
-------------- next part --------------
--- dlls/ole32/Makefile.in (revision 7)
+++ dlls/ole32/Makefile.in (local)
@@ -35,7 +35,9 @@ C_SRCS = \
rpc.c \
stg_bigblockfile.c \
stg_stream.c \
- storage32.c
+ storage32.c \
+ stubmanager.c
+
C_SRCS16 = \
memlockbytes16.c \
--- dlls/ole32/compobj.c (revision 7)
+++ dlls/ole32/compobj.c (local)
@@ -102,6 +102,7 @@ typedef struct tagRegisteredClass
DWORD connectFlags;
DWORD dwCookie;
HANDLE hThread; /* only for localserver */
+ APARTMENT *apt; /* owning apartment */
struct tagRegisteredClass* nextClass;
} RegisteredClass;
@@ -226,6 +227,9 @@ APARTMENT* COM_CreateApartment(DWORD mod
else
apt = NtCurrentTeb()->ReservedForOle;
+ list_init(&apt->stubmgrs);
+ apt->oidc = 1;
+
apt->model = model;
if (model & COINIT_APARTMENTTHREADED) {
/* FIXME: how does windoze create OXIDs? */
@@ -269,17 +273,24 @@ static void COM_DestroyApartment(APARTME
/* The given OXID must be local to this process: you cannot use apartment
windows to send RPCs to other processes. This all needs to move to rpcrt4 */
-HWND COM_GetApartmentWin(OXID oxid)
+
+APARTMENT *COM_ApartmentFromOXID(OXID oxid)
{
- APARTMENT *apt;
- HWND win = 0;
+ APARTMENT *apt = NULL;
EnterCriticalSection(&csApartment);
apt = apts;
while (apt && apt->oxid != oxid) apt = apt->next;
- if (apt) win = apt->win;
LeaveCriticalSection(&csApartment);
- return win;
+
+ return apt;
+}
+
+HWND COM_GetApartmentWin(OXID oxid)
+{
+ APARTMENT *apt = COM_ApartmentFromOXID(oxid);
+
+ return apt ? apt->win : NULL;
}
/* Currently inter-thread marshalling is not fully implemented, so this does nothing */
@@ -1107,6 +1118,13 @@ _LocalServerThread(LPVOID param) {
TRACE("Starting classfactory server thread for %s.\n",debugstr_guid(&newClass->classIdentifier));
+ /* we need to enter the apartment of the thread which registered
+ * the class object to perform the next stage
+ */
+
+ assert( newClass->apt );
+ NtCurrentTeb()->ReservedForOle = newClass->apt;
+
strcpy(pipefn,PIPEPREF);
WINE_StringFromCLSID(&newClass->classIdentifier,pipefn+strlen(PIPEPREF));
@@ -1219,6 +1237,12 @@ HRESULT WINAPI CoRegisterClassObject(
if ( (lpdwRegister==0) || (pUnk==0) )
return E_INVALIDARG;
+ if (!COM_CurrentApt())
+ {
+ ERR("COM was not initialized\n");
+ return CO_E_NOTINITIALIZED;
+ }
+
*lpdwRegister = 0;
/*
@@ -1240,6 +1264,7 @@ HRESULT WINAPI CoRegisterClassObject(
newClass->classIdentifier = *rclsid;
newClass->runContext = dwClsContext;
newClass->connectFlags = flags;
+ newClass->apt = COM_CurrentApt();
/*
* Use the address of the chain node as the cookie since we are sure it's
* unique.
@@ -1981,6 +2006,8 @@ HRESULT WINAPI CoLockObjectExternal(
BOOL fLock, /* [in] do lock */
BOOL fLastUnlockReleases) /* [in] unlock all */
{
+ TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
+ pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
if (fLock) {
/*
--- dlls/ole32/compobj_private.h (revision 7)
+++ dlls/ole32/compobj_private.h (local)
@@ -5,6 +5,7 @@
* Copyright 1999 Sylvain St-Germain
* Copyright 2002 Marcus Meissner
* Copyright 2003 Ove K?n, TransGaming Technologies
+ * Copyright 2004 Mike Hearn, CodeWeavers Inc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -28,6 +29,8 @@
#include <stdarg.h>
+#include <wine/list.h>
+
#include "windef.h"
#include "winbase.h"
#include "wtypes.h"
@@ -97,15 +100,16 @@ typedef struct tagAPARTMENT {
DWORD tid; /* thread id */
HANDLE thread; /* thread handle */
OXID oxid; /* object exporter ID */
- OID oidc; /* object ID counter */
+ OID oidc; /* object ID counter, starts at 1, zero is invalid OID */
HWND win; /* message window */
CRITICAL_SECTION cs; /* thread safety */
LPMESSAGEFILTER filter; /* message filter */
XOBJECT *objs; /* exported objects */
- IOBJECT *proxies; /* imported objects */
+ IOBJECT *proxies; /* imported objects */
LPUNKNOWN state; /* state object (see Co[Get,Set]State) */
LPVOID ErrorInfo; /* thread error info */
DWORD listenertid; /* id of apartment_listener_thread */
+ struct list stubmgrs; /* stub managers for exported objects */
} APARTMENT;
extern APARTMENT MTA, *apts;
@@ -124,9 +128,9 @@ extern void* StdGlobalInterfaceTableInst
/* Standard Marshalling definitions */
typedef struct _wine_marshal_id {
- OXID oxid;
- OID oid; /* unique value corresp. IUnknown of object */
- IID iid;
+ OXID oxid; /* id of apartment */
+ OID oid; /* id of stub manager */
+ IID iid; /* id of interface (NOT ifptr) */
} wine_marshal_id;
inline static BOOL
@@ -147,12 +151,46 @@ MARSHAL_Compare_Mids_NoInterface(wine_ma
;
}
-HRESULT MARSHAL_Find_Stub_Buffer(wine_marshal_id *mid,IRpcStubBuffer **stub);
-void MARSHAL_Invalidate_Stub_From_MID(wine_marshal_id *mid);
HRESULT MARSHAL_Disconnect_Proxies(void);
-
HRESULT MARSHAL_GetStandardMarshalCF(LPVOID *ppv);
+/* an interface stub */
+struct ifstub
+{
+ struct list entry;
+ IRpcStubBuffer *stubbuffer;
+ IID iid; /* fixme: this should be an IPID not an IID */
+ IUnknown *iface;
+
+ BOOL table;
+};
+
+
+/* stub managers hold refs on the object and each interface stub */
+struct stub_manager
+{
+ struct list entry;
+ struct list ifstubs;
+ CRITICAL_SECTION lock;
+ APARTMENT *apt; /* owning apt */
+
+ DWORD refcount; /* count of 'external' references */
+ OID oid; /* apartment-scoped unique identifier */
+ IUnknown *object; /* the object we are managing the stub for */
+ DWORD next_ipid; /* currently unused */
+};
+
+struct stub_manager *new_stub_manager(APARTMENT *apt, IUnknown *object);
+int stub_manager_ref(struct stub_manager *m, int refs);
+int stub_manager_unref(struct stub_manager *m, int refs);
+IRpcStubBuffer *stub_manager_iid_to_stubbuffer(struct stub_manager *m, IID *iid);
+struct ifstub *stub_manager_new_ifstub(struct stub_manager *m, IRpcStubBuffer *sb, IUnknown *iptr, IID *iid, BOOL tablemarshal);
+struct stub_manager *get_stub_manager(OXID oxid, OID oid);
+struct stub_manager *get_stub_manager_from_object(OXID oxid, void *object);
+void stub_manager_delete_ifstub(struct stub_manager *m, IID *iid); /* fixme: should be ipid */
+
+IRpcStubBuffer *mid_to_stubbuffer(wine_marshal_id *mid);
+
void start_apartment_listener_thread(void);
extern HRESULT PIPE_GetNewPipeBuf(wine_marshal_id *mid, IRpcChannelBuffer **pipebuf);
@@ -185,8 +223,9 @@ static inline APARTMENT* COM_CurrentApt(
}
/* compobj.c */
-APARTMENT* COM_CreateApartment(DWORD model);
+APARTMENT *COM_CreateApartment(DWORD model);
HWND COM_GetApartmentWin(OXID oxid);
+APARTMENT *COM_ApartmentFromOXID(OXID oxid);
#define ICOM_THIS_MULTI(impl,field,iface) impl* const This=(impl*)((char*)(iface) - offsetof(impl,field))
--- dlls/ole32/marshal.c (revision 7)
+++ dlls/ole32/marshal.c (local)
@@ -1,7 +1,9 @@
/*
* Marshalling library
*
- * Copyright 2002 Marcus Meissner
+ * Copyright 2002 Marcus Meissner
+ * Copyright 2004 Mike Hearn, for CodeWeavers
+ * Copyright 2004 Rob Shearman, for CodeWeavers
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -55,6 +57,13 @@ extern const CLSID CLSID_DfMarshal;
* Process Identifier, Object IUnknown ptr, IID
*
* Note that the IUnknown_QI(ob,xiid,&ppv) always returns the SAME ppv value!
+ *
+ * In Windows, a different triple is used: OXID (apt id), OID (stub
+ * manager id), IPID (interface ptr/stub id).
+ *
+ * OXIDs identify an apartment and are network scoped
+ * OIDs identify a stub manager and are apartment scoped
+ * IPIDs identify an interface stub and are apartment scoped
*/
inline static HRESULT
@@ -77,85 +86,50 @@ typedef struct _mid2unknown {
LPUNKNOWN pUnk;
} mid2unknown;
-typedef struct _mid2stub {
- wine_marshal_id mid;
- IRpcStubBuffer *stub;
- LPUNKNOWN pUnkServer;
- BOOL valid;
-} mid2stub;
-
-static mid2stub *stubs = NULL;
-static int nrofstubs = 0;
-
static mid2unknown *proxies = NULL;
static int nrofproxies = 0;
-void MARSHAL_Invalidate_Stub_From_MID(wine_marshal_id *mid) {
- int i;
+IRpcStubBuffer *mid_to_stubbuffer(wine_marshal_id *mid)
+{
+ struct stub_manager *m;
- for (i=0;i<nrofstubs;i++) {
- if (!stubs[i].valid) continue;
-
- if (MARSHAL_Compare_Mids(mid,&(stubs[i].mid))) {
- stubs[i].valid = FALSE;
- IUnknown_Release(stubs[i].pUnkServer);
- return;
- }
+ if (!(m = get_stub_manager(mid->oxid, mid->oid)))
+ {
+ WARN("unknown OID %s\n", wine_dbgstr_longlong(mid->oid));
+ return NULL;
}
-
- return;
-}
-HRESULT
-MARSHAL_Find_Stub_Buffer(wine_marshal_id *mid,IRpcStubBuffer **stub) {
- int i;
+ return stub_manager_iid_to_stubbuffer(m, &mid->iid);
+}
- for (i=0;i<nrofstubs;i++) {
- if (!stubs[i].valid) continue;
+/* fixme: this should return an IPID */
+/* creates a new stub manager and sets mid->oid when mid->oid == 0 */
+static HRESULT register_ifstub(wine_marshal_id *mid, IUnknown *obj, IRpcStubBuffer *stub, BOOL tablemarshal)
+{
+ struct stub_manager *manager = NULL;
+ struct ifstub *ifstub;
- if (MARSHAL_Compare_Mids(mid,&(stubs[i].mid))) {
- *stub = stubs[i].stub;
- IUnknown_AddRef((*stub));
- return S_OK;
- }
+ /* mid->oid of zero means create a new stub manager */
+
+ if (mid->oid && (manager = get_stub_manager(mid->oxid, mid->oid)))
+ {
+ TRACE("registering new ifstub on pre-existing manager\n");
}
- return E_FAIL;
-}
-
-static HRESULT
-MARSHAL_Find_Stub(wine_marshal_id *mid,LPUNKNOWN *pUnk) {
- int i;
+ else
+ {
+ TRACE("constructing new stub manager\n");
+
+ manager = new_stub_manager(COM_ApartmentFromOXID(mid->oxid), obj);
+ if (!manager) return E_OUTOFMEMORY;
- for (i=0;i<nrofstubs;i++) {
- if (!stubs[i].valid) continue;
+ if (!tablemarshal) stub_manager_ref(manager, 1);
- if (MARSHAL_Compare_Mids(mid,&(stubs[i].mid))) {
- *pUnk = stubs[i].pUnkServer;
- IUnknown_AddRef((*pUnk));
- return S_OK;
- }
+ mid->oid = manager->oid;
}
- return E_FAIL;
-}
-static HRESULT
-MARSHAL_Register_Stub(wine_marshal_id *mid,LPUNKNOWN pUnk,IRpcStubBuffer *stub) {
- LPUNKNOWN xPunk;
- if (!MARSHAL_Find_Stub(mid,&xPunk)) {
- FIXME("Already have entry for (%s/%s)!\n",wine_dbgstr_longlong(mid->oid),debugstr_guid(&(mid->iid)));
- return S_OK;
- }
- if (nrofstubs)
- stubs=HeapReAlloc(GetProcessHeap(),0,stubs,sizeof(stubs[0])*(nrofstubs+1));
- else
- stubs=HeapAlloc(GetProcessHeap(),0,sizeof(stubs[0]));
- if (!stubs) return E_OUTOFMEMORY;
- stubs[nrofstubs].stub = stub;
- stubs[nrofstubs].pUnkServer = pUnk;
- memcpy(&(stubs[nrofstubs].mid),mid,sizeof(*mid));
- stubs[nrofstubs].valid = TRUE; /* set to false when released by ReleaseMarshalData */
- nrofstubs++;
- return S_OK;
+ ifstub = stub_manager_new_ifstub(manager, stub, obj, &mid->iid, tablemarshal);
+
+ return ifstub ? S_OK : E_OUTOFMEMORY;
}
HRESULT
@@ -256,54 +230,74 @@ StdMarshalImpl_MarshalInterface(
LPMARSHAL iface, IStream *pStm,REFIID riid, void* pv, DWORD dwDestContext,
void* pvDestContext, DWORD mshlflags
) {
- wine_marshal_id mid;
- wine_marshal_data md;
- IUnknown *pUnk;
- ULONG res;
- HRESULT hres;
- IRpcStubBuffer *stub;
- IPSFactoryBuffer *psfacbuf;
-
+ wine_marshal_id mid;
+ wine_marshal_data md;
+ IUnknown *pUnk;
+ ULONG res;
+ HRESULT hres;
+ IRpcStubBuffer *stubbuffer;
+ IPSFactoryBuffer *psfacbuf;
+ BOOL tablemarshal;
+ struct stub_manager *manager;
+
TRACE("(...,%s,...)\n",debugstr_guid(riid));
start_apartment_listener_thread(); /* just to be sure we have one running. */
- IUnknown_QueryInterface((LPUNKNOWN)pv,&IID_IUnknown,(LPVOID*)&pUnk);
- mid.oxid = COM_CurrentApt()->oxid;
- mid.oid = (DWORD)pUnk; /* FIXME */
- IUnknown_Release(pUnk);
- memcpy(&mid.iid,riid,sizeof(mid.iid));
- md.dwDestContext = dwDestContext;
- md.mshlflags = mshlflags;
- hres = IStream_Write(pStm,&mid,sizeof(mid),&res);
- if (hres) return hres;
- hres = IStream_Write(pStm,&md,sizeof(md),&res);
- if (hres) return hres;
-
- if (SUCCEEDED(MARSHAL_Find_Stub_Buffer(&mid,&stub))) {
- /* Find_Stub_Buffer gives us a ref but we want to keep it, as if we'd created a new one */
- TRACE("Found RpcStubBuffer %p\n", stub);
- return S_OK;
- }
hres = get_facbuf_for_iid(riid,&psfacbuf);
if (hres) return hres;
- hres = IPSFactoryBuffer_CreateStub(psfacbuf,riid,pv,&stub);
+ hres = IPSFactoryBuffer_CreateStub(psfacbuf,riid,pv,&stubbuffer);
IPSFactoryBuffer_Release(psfacbuf);
if (hres) {
- FIXME("Failed to create a stub for %s\n",debugstr_guid(riid));
+ FIXME("Failed to create an RpcStubBuffer from PSFactory for %s\n",debugstr_guid(riid));
return hres;
}
- IUnknown_QueryInterface((LPUNKNOWN)pv,riid,(LPVOID*)&pUnk);
- MARSHAL_Register_Stub(&mid,pUnk,stub);
+
+ tablemarshal = ((mshlflags & MSHLFLAGS_TABLESTRONG) || (mshlflags & MSHLFLAGS_TABLEWEAK));
+ if (tablemarshal) FIXME("table marshalling unimplemented\n");
+
+ /* now fill out the MID */
+ mid.oxid = COM_CurrentApt()->oxid;
+ memcpy(&mid.iid,riid,sizeof(mid.iid));
+
+ IUnknown_QueryInterface((LPUNKNOWN)pv, riid, (LPVOID*)&pUnk);
+
+ if ((manager = get_stub_manager_from_object(mid.oxid, pUnk)))
+ {
+ mid.oid = manager->oid;
+ }
+ else
+ {
+ mid.oid = 0; /* will be set by register_ifstub */
+ }
+
+ hres = register_ifstub(&mid, pUnk, stubbuffer, tablemarshal);
+
IUnknown_Release(pUnk);
+
+ if (hres)
+ {
+ FIXME("Failed to create ifstub, hres=0x%lx\n", hres);
+ return hres;
+ }
+
+ hres = IStream_Write(pStm,&mid,sizeof(mid),&res);
+ if (hres) return hres;
+
+ /* and then the marshal data */
+ md.dwDestContext = dwDestContext;
+ md.mshlflags = mshlflags;
+ hres = IStream_Write(pStm,&md,sizeof(md),&res);
+ if (hres) return hres;
+
return S_OK;
}
static HRESULT WINAPI
-StdMarshalImpl_UnmarshalInterface(
- LPMARSHAL iface, IStream *pStm, REFIID riid, void **ppv
-) {
+StdMarshalImpl_UnmarshalInterface(LPMARSHAL iface, IStream *pStm, REFIID riid, void **ppv)
+{
+ struct stub_manager *stubmgr;
wine_marshal_id mid;
wine_marshal_data md;
ULONG res;
@@ -311,31 +305,28 @@ StdMarshalImpl_UnmarshalInterface(
IPSFactoryBuffer *psfacbuf;
IRpcProxyBuffer *rpcproxy;
IRpcChannelBuffer *chanbuf;
- int i;
TRACE("(...,%s,....)\n",debugstr_guid(riid));
hres = IStream_Read(pStm,&mid,sizeof(mid),&res);
if (hres) return hres;
hres = IStream_Read(pStm,&md,sizeof(md),&res);
if (hres) return hres;
- for (i=0; i < nrofstubs; i++)
+
+ /* check if we're marshalling back to ourselves */
+ if ((stubmgr = get_stub_manager(mid.oxid, mid.oid)))
{
- if (!stubs[i].valid) continue;
-
- if (MARSHAL_Compare_Mids(&mid, &(stubs[i].mid)))
- {
- IRpcStubBuffer *stub = NULL;
- stub = stubs[i].stub;
- res = IRpcStubBuffer_Release(stub);
- TRACE("Same apartment marshal for %s, returning original object\n",
- debugstr_guid(riid));
-
- stubs[i].valid = FALSE;
- IUnknown_QueryInterface(stubs[i].pUnkServer, riid, ppv);
- IUnknown_Release(stubs[i].pUnkServer); /* no longer need our reference */
- return S_OK;
- }
+ 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);
+ if ((md.mshlflags & MSHLFLAGS_TABLESTRONG) || (md.mshlflags & MSHLFLAGS_TABLEWEAK))
+ FIXME("table marshalling unimplemented\n");
+
+ /* clean up the stubs */
+ stub_manager_delete_ifstub(stubmgr, &mid.iid);
+ stub_manager_unref(stubmgr, 1);
+ return hres;
}
+
if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_NULL)) {
/* should return proxy manager IUnknown object */
FIXME("Special treatment required for IID of %s\n", debugstr_guid(riid));
@@ -370,32 +361,31 @@ StdMarshalImpl_UnmarshalInterface(
static HRESULT WINAPI
StdMarshalImpl_ReleaseMarshalData(LPMARSHAL iface, IStream *pStm) {
- wine_marshal_id mid;
- ULONG res;
- HRESULT hres;
- int i;
-
- hres = IStream_Read(pStm,&mid,sizeof(mid),&res);
- if (hres) return hres;
-
- for (i=0; i < nrofstubs; i++)
- {
- if (!stubs[i].valid) continue;
+ wine_marshal_id mid;
+ ULONG res;
+ HRESULT hres;
+ struct stub_manager *stubmgr;
- if (MARSHAL_Compare_Mids(&mid, &(stubs[i].mid)))
- {
- IRpcStubBuffer *stub = NULL;
- stub = stubs[i].stub;
- res = IRpcStubBuffer_Release(stub);
- stubs[i].valid = FALSE;
- TRACE("stub refcount of %p is %ld\n", stub, res);
+ TRACE("iface=%p, pStm=%p\n", iface, pStm);
+
+ hres = IStream_Read(pStm,&mid,sizeof(mid),&res);
+ if (hres) return hres;
- return S_OK;
- }
- }
+ if (!(stubmgr = get_stub_manager(mid.oxid, mid.oid)))
+ {
+ ERR("could not map MID to stub manager, oxid=%s, oid=%s\n",
+ wine_dbgstr_longlong(mid.oxid), wine_dbgstr_longlong(mid.oid));
+ return RPC_E_INVALID_OBJREF;
+ }
+
+ /* currently, each marshal has its own interface stub. this might
+ * not be correct. but, it means we don't need to refcount anything
+ * here. */
+ stub_manager_delete_ifstub(stubmgr, &mid.iid);
+
+ stub_manager_unref(stubmgr, 1);
- FIXME("Could not map MID to stub??\n");
- return E_FAIL;
+ return S_OK;
}
static HRESULT WINAPI
--- dlls/ole32/rpc.c (revision 7)
+++ dlls/ole32/rpc.c (local)
@@ -1,5 +1,5 @@
/*
- * (Local) RPC Stuff aklsdfjaksldfj
+ * (Local) RPC Stuff
*
* Copyright 2002 Marcus Meissner
*
@@ -334,16 +334,18 @@ PipeBuf_GetBuffer(
static HRESULT
COM_InvokeAndRpcSend(wine_rpc_request *req) {
- IRpcStubBuffer *stub;
+ IRpcStubBuffer *stub;
RPCOLEMESSAGE msg;
HRESULT hres;
DWORD reqtype;
- hres = MARSHAL_Find_Stub_Buffer(&(req->reqh.mid),&stub);
- if (hres) {
+ if (!(stub = mid_to_stubbuffer(&(req->reqh.mid))))
+ {
ERR("Stub not found?\n");
- return hres;
+ return E_FAIL;
}
+
+ IUnknown_AddRef(stub);
msg.Buffer = req->Buffer;
msg.iMethod = req->reqh.iMethod;
msg.cbBuffer = req->reqh.cbBuffer;
@@ -661,8 +663,7 @@ COM_RpcReceive(wine_pipe *xpipe) {
if (reqtype == REQTYPE_DISCONNECT) { /* only received by servers */
wine_rpc_disconnect_header header;
- IRpcStubBuffer *stub;
- ULONG ret;
+ struct stub_manager *stubmgr;
hres = read_pipe(xhPipe, &header, sizeof(header));
if (hres) {
@@ -672,21 +673,15 @@ COM_RpcReceive(wine_pipe *xpipe) {
TRACE("read disconnect header\n");
- hres = MARSHAL_Find_Stub_Buffer(&header.mid, &stub);
- if (hres) {
- ERR("could not locate stub to disconnect, mid.oid=%s\n",
- wine_dbgstr_longlong(header.mid.oid));
+ if (!(stubmgr = get_stub_manager(header.mid.oxid, header.mid.oid)))
+ {
+ ERR("could not locate stub to disconnect, mid.oid=%s\n", wine_dbgstr_longlong(header.mid.oid));
goto end;
}
-
- /* release reference added by MARSHAL_Find_Stub_Buffer call */
- IRpcStubBuffer_Release(stub);
- /* release it for real */
- ret = IRpcStubBuffer_Release(stub);
- /* FIXME: race */
- if (ret == 0)
- MARSHAL_Invalidate_Stub_From_MID(&header.mid);
+ /* this should destroy the stub manager in the case of only one connection to it */
+ stub_manager_unref(stubmgr, 1);
+
goto end;
} else if (reqtype == REQTYPE_REQUEST) {
wine_rpc_request *xreq;
--- dlls/ole32/tests/marshal.c (revision 7)
+++ dlls/ole32/tests/marshal.c (local)
@@ -145,6 +145,7 @@ static DWORD CALLBACK host_object_proc(L
{
if (msg.hwnd == NULL && msg.message == RELEASEMARSHALDATA)
{
+ trace("releasing marshal data\n");
CoReleaseMarshalData(data->stream);
SetEvent((HANDLE)msg.lParam);
}
@@ -224,7 +225,7 @@ static void test_normal_marshal_and_rele
ok_ole_success(hr, CoReleaseMarshalData);
IStream_Release(pStream);
- todo_wine { ok_no_locks(); }
+ ok_no_locks();
}
/* tests success case of a same-thread marshal and unmarshal */
@@ -385,7 +386,7 @@ static void test_tableweak_marshal_and_u
IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
- todo_wine { ok_ole_success(hr, CoUnmarshalInterface); }
+ ok_ole_success(hr, CoUnmarshalInterface);
ok_more_than_one_lock();
@@ -395,7 +396,7 @@ static void test_tableweak_marshal_and_u
/* this line is shows the difference between weak and strong table marshaling:
* weak has cLocks == 0
* strong has cLocks > 0 */
- ok_no_locks();
+ todo_wine { ok_no_locks(); }
end_host_object(tid, thread);
}
@@ -426,7 +427,7 @@ static void test_tablestrong_marshal_and
IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
- todo_wine { ok_ole_success(hr, CoUnmarshalInterface); }
+ ok_ole_success(hr, CoUnmarshalInterface);
ok_more_than_one_lock();
@@ -436,7 +437,7 @@ static void test_tablestrong_marshal_and
/* this line is shows the difference between weak and strong table marshaling:
* weak has cLocks == 0
* strong has cLocks > 0 */
- todo_wine { ok_more_than_one_lock(); }
+ ok_more_than_one_lock();
/* release the remaining reference on the object by calling
* CoReleaseMarshalData in the hosting thread */
@@ -444,7 +445,7 @@ static void test_tablestrong_marshal_and
release_host_object(tid);
IStream_Release(pStream);
- ok_no_locks();
+ todo_wine { ok_no_locks(); }
end_host_object(tid, thread);
}
@@ -475,7 +476,7 @@ static void test_lock_object_external()
CoLockObjectExternal((IUnknown*)&Test_ClassFactory, FALSE, TRUE);
- todo_wine { ok_no_locks(); }
+ ok_no_locks();
}
/* tests disconnecting stubs */
--- dlls/ole32/stubmanager.c (revision 7)
+++ dlls/ole32/stubmanager.c (local)
@@ -0,0 +1,271 @@
+/*
+ * A stub manager is an object that controls interface stubs. It is
+ * identified by an OID (object identifier) and acts as the network
+ * identity of the object. There can be many stub managers in a
+ * process or apartment.
+ *
+ * Copyright 2002 Marcus Meissner
+ * Copyright 2004 Mike Hearn for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define COBJMACROS
+#define NONAMELESSUNION
+#define NONAMELESSSTRUCT
+
+#include <assert.h>
+
+#include <wine/debug.h>
+#include <wine/list.h>
+
+WINE_DEFAULT_DEBUG_CHANNEL(ole);
+
+#include "windef.h"
+#include "winbase.h"
+#include "winuser.h"
+#include "objbase.h"
+#include "ole2.h"
+#include "ole2ver.h"
+#include "rpc.h"
+
+#include "compobj_private.h"
+
+struct stub_manager *new_stub_manager(APARTMENT *apt, IUnknown *object)
+{
+ struct stub_manager *sm;
+
+ assert( apt );
+
+ sm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct stub_manager));
+ if (!sm) return NULL;
+
+ list_init(&sm->ifstubs);
+ InitializeCriticalSection(&sm->lock);
+ IUnknown_AddRef(object);
+ sm->object = object;
+ sm->apt = apt;
+ EnterCriticalSection(&apt->cs);
+ sm->oid = apt->oidc++;
+ LeaveCriticalSection(&apt->cs);
+
+ /* yes, that's right, this starts at zero. that's zero EXTERNAL
+ * refs, ie nobody has unmarshalled anything yet. we can't have
+ * negative refs because the stub manager cannot be explicitly
+ * killed, it has to die by somebody unmarshalling then releasing
+ * the marshalled ifptr.
+ */
+ sm->refcount = 0;
+
+ EnterCriticalSection(&apt->cs);
+ list_add_head(&apt->stubmgrs, &sm->entry);
+ LeaveCriticalSection(&apt->cs);
+
+ TRACE("Created new stub manager (oid=%s) at %p for object with IUnknown %p\n", wine_dbgstr_longlong(sm->oid), sm, object);
+
+ return sm;
+}
+
+struct stub_manager *get_stub_manager_from_object(OXID oxid, void *object)
+{
+ struct stub_manager *result = NULL;
+ struct list *cursor;
+ APARTMENT *apt;
+
+ if (!(apt = COM_ApartmentFromOXID(oxid)))
+ {
+ WARN("Could not map OXID %s to apartment object\n", wine_dbgstr_longlong(oxid));
+ return NULL;
+ }
+
+ EnterCriticalSection(&apt->cs);
+ LIST_FOR_EACH( cursor, &apt->stubmgrs )
+ {
+ struct stub_manager *m = LIST_ENTRY( cursor, struct stub_manager, entry );
+
+ if (m->object == object)
+ {
+ result = m;
+ break;
+ }
+ }
+ LeaveCriticalSection(&apt->cs);
+
+ TRACE("found %p from object %p\n", result, object);
+
+ return result;
+}
+
+struct stub_manager *get_stub_manager(OXID oxid, OID oid)
+{
+ struct stub_manager *result = NULL;
+ struct list *cursor;
+ APARTMENT *apt;
+
+ if (!(apt = COM_ApartmentFromOXID(oxid)))
+ {
+ WARN("Could not map OXID %s to apartment object\n", wine_dbgstr_longlong(oxid));
+ return NULL;
+ }
+
+ EnterCriticalSection(&apt->cs);
+
+ LIST_FOR_EACH( cursor, &apt->stubmgrs )
+ {
+ struct stub_manager *m = LIST_ENTRY( cursor, struct stub_manager, entry );
+
+ if (m->oid == oid)
+ {
+ result = m;
+ break;
+ }
+ }
+
+ LeaveCriticalSection(&apt->cs);
+
+ TRACE("found %p from oid %s\n", result, wine_dbgstr_longlong(oid));
+
+ return result;
+}
+
+/* add some external references (ie from a client that demarshalled an ifptr) */
+int stub_manager_ref(struct stub_manager *m, int refs)
+{
+ int rc = InterlockedExchangeAdd(&m->refcount, refs) + refs;
+ TRACE("added %d refs to %p (oid %s), rc is now %d\n", refs, m, wine_dbgstr_longlong(m->oid), rc);
+ return rc;
+}
+
+/* remove some external references */
+int stub_manager_unref(struct stub_manager *m, int refs)
+{
+ int rc = InterlockedExchangeAdd(&m->refcount, -refs) - refs;
+
+ TRACE("removed %d refs from %p (oid %s), rc is now %d\n", refs, m, wine_dbgstr_longlong(m->oid), rc);
+
+ if (rc == 0)
+ {
+ TRACE("destroying %p (oid=%s)\n", m, wine_dbgstr_longlong(m->oid));
+
+ EnterCriticalSection(&m->apt->cs);
+ list_remove(&m->entry);
+ LeaveCriticalSection(&m->apt->cs);
+
+ /* table strong and normal marshals have a ref on us, so we
+ * can't die while they are outstanding unless the app does
+ * something weird like explicitly killing us (how?)
+ */
+
+ EnterCriticalSection(&m->lock);
+ if (!list_empty(&m->ifstubs))
+ {
+ ERR("PANIC: Stub manager is being destroyed with outstanding interface stubs\n");
+ assert( FALSE );
+ }
+
+ /* fixme: the lifecycle of table-weak marshals is not
+ * currently understood. results of testing against dcom98
+ * appear to contradict Essential COM -m
+ */
+
+ LeaveCriticalSection(&m->lock);
+
+ IUnknown_Release(m->object);
+
+ HeapFree(GetProcessHeap(), 0, m);
+ }
+
+ return refs;
+}
+
+static struct ifstub *stub_manager_iid_to_ifstub(struct stub_manager *m, IID *iid)
+{
+ struct list *cursor;
+ struct ifstub *result = NULL;
+
+ EnterCriticalSection(&m->lock);
+ LIST_FOR_EACH( cursor, &m->ifstubs )
+ {
+ struct ifstub *ifstub = LIST_ENTRY( cursor, struct ifstub, entry );
+
+ if (IsEqualIID(iid, &ifstub->iid))
+ {
+ result = ifstub;
+ break;
+ }
+ }
+ LeaveCriticalSection(&m->lock);
+
+ return result;
+}
+
+IRpcStubBuffer *stub_manager_iid_to_stubbuffer(struct stub_manager *m, IID *iid)
+{
+ struct ifstub *ifstub = stub_manager_iid_to_ifstub(m, iid);
+
+ return ifstub ? ifstub->stubbuffer : NULL;
+}
+
+/* registers a new interface stub COM object with the stub manager and returns registration record */
+struct ifstub *stub_manager_new_ifstub(struct stub_manager *m, IRpcStubBuffer *sb, IUnknown *iptr, IID *iid, BOOL tablemarshal)
+{
+ struct ifstub *stub;
+
+ TRACE("oid=%s, stubbuffer=%p, iptr=%p, iid=%s, tablemarshal=%s\n",
+ wine_dbgstr_longlong(m->oid), sb, iptr, debugstr_guid(iid), tablemarshal ? "TRUE" : "FALSE");
+
+ stub = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct ifstub));
+ if (!stub) return NULL;
+
+ stub->stubbuffer = sb;
+ IUnknown_AddRef(sb);
+
+ /* no need to ref this, same object as sb */
+ stub->iface = iptr;
+ stub->table = tablemarshal;
+ stub->iid = *iid;
+
+ EnterCriticalSection(&m->lock);
+ list_add_head(&m->ifstubs, &stub->entry);
+ LeaveCriticalSection(&m->lock);
+
+ return stub;
+}
+
+/* fixme: should ifstubs be refcounted? iid should be ipid */
+void stub_manager_delete_ifstub(struct stub_manager *m, IID *iid)
+{
+ struct ifstub *ifstub;
+
+ TRACE("m=%p, m->oid=%s, iid=%s\n", m, wine_dbgstr_longlong(m->oid), debugstr_guid(iid));
+
+ EnterCriticalSection(&m->lock);
+
+ if ((ifstub = stub_manager_iid_to_ifstub(m, iid)))
+ {
+ list_remove(&ifstub->entry);
+
+ IUnknown_Release(ifstub->stubbuffer);
+ IUnknown_Release(ifstub->iface);
+
+ HeapFree(GetProcessHeap(), 0, ifstub);
+ }
+ else
+ {
+ WARN("could not map iid %s to ifstub\n", debugstr_guid(iid));
+ }
+
+ LeaveCriticalSection(&m->lock);
+}
More information about the wine-patches
mailing list