- Implement the COM stub manager, refactor the current stub code.

- Begin implementing interface stubs.
This commit is contained in:
Mike Hearn 2004-12-27 19:21:47 +00:00 committed by Alexandre Julliard
parent d900b5392d
commit 5475a2e617
7 changed files with 506 additions and 184 deletions

View File

@ -35,7 +35,8 @@ C_SRCS = \
rpc.c \
stg_bigblockfile.c \
stg_stream.c \
storage32.c
storage32.c \
stubmanager.c
C_SRCS16 = \
memlockbytes16.c \

View File

@ -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 model)
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(APARTMENT *apt)
/* 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) {
/*

View File

@ -5,6 +5,7 @@
* Copyright 1999 Sylvain St-Germain
* Copyright 2002 Marcus Meissner
* Copyright 2003 Ove Kåven, 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* StdGlobalInterfaceTableInstance;
/* 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_marshal_id *mid1, wine_marshal_id *mid2) {
;
}
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(void)
}
/* 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))

View File

@ -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 stub_manager_iid_to_stubbuffer(m, &mid->iid);
}
/* 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;
/* mid->oid of zero means create a new stub manager */
return;
}
HRESULT
MARSHAL_Find_Stub_Buffer(wine_marshal_id *mid,IRpcStubBuffer **stub) {
int i;
for (i=0;i<nrofstubs;i++) {
if (!stubs[i].valid) continue;
if (MARSHAL_Compare_Mids(mid,&(stubs[i].mid))) {
*stub = stubs[i].stub;
IUnknown_AddRef((*stub));
return S_OK;
}
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;
for (i=0;i<nrofstubs;i++) {
if (!stubs[i].valid) continue;
if (MARSHAL_Compare_Mids(mid,&(stubs[i].mid))) {
*pUnk = stubs[i].pUnkServer;
IUnknown_AddRef((*pUnk));
return S_OK;
}
}
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;
{
TRACE("constructing new stub manager\n");
manager = new_stub_manager(COM_ApartmentFromOXID(mid->oxid), obj);
if (!manager) return E_OUTOFMEMORY;
if (!tablemarshal) stub_manager_ref(manager, 1);
mid->oid = manager->oid;
}
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;
wine_marshal_id mid;
ULONG res;
HRESULT hres;
struct stub_manager *stubmgr;
hres = IStream_Read(pStm,&mid,sizeof(mid),&res);
if (hres) return hres;
TRACE("iface=%p, pStm=%p\n", iface, pStm);
hres = IStream_Read(pStm,&mid,sizeof(mid),&res);
if (hres) return hres;
for (i=0; i < nrofstubs; i++)
{
if (!stubs[i].valid) continue;
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);
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);
return S_OK;
}
}
FIXME("Could not map MID to stub??\n");
return E_FAIL;
return S_OK;
}
static HRESULT WINAPI

View File

@ -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;

269
dlls/ole32/stubmanager.c Normal file
View File

@ -0,0 +1,269 @@
/*
* 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 <stdarg.h>
#include "windef.h"
#include "winbase.h"
#include "winuser.h"
#include "objbase.h"
#include "ole2.h"
#include "ole2ver.h"
#include "rpc.h"
#include "wine/debug.h"
#include "compobj_private.h"
WINE_DEFAULT_DEBUG_CHANNEL(ole);
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);
}

View File

@ -145,6 +145,7 @@ static DWORD CALLBACK host_object_proc(LPVOID p)
{
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_release()
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_unmarshal_twice()
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_unmarshal_twice()
/* 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_unmarshal_twice()
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_unmarshal_twice()
/* 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_unmarshal_twice()
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 */