mirror of
https://github.com/reactos/wine.git
synced 2024-11-25 04:39:45 +00:00
- Implement the COM stub manager, refactor the current stub code.
- Begin implementing interface stubs.
This commit is contained in:
parent
d900b5392d
commit
5475a2e617
@ -35,7 +35,8 @@ C_SRCS = \
|
||||
rpc.c \
|
||||
stg_bigblockfile.c \
|
||||
stg_stream.c \
|
||||
storage32.c
|
||||
storage32.c \
|
||||
stubmanager.c
|
||||
|
||||
C_SRCS16 = \
|
||||
memlockbytes16.c \
|
||||
|
@ -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) {
|
||||
/*
|
||||
|
@ -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))
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
269
dlls/ole32/stubmanager.c
Normal 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);
|
||||
}
|
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user