rpcrt4: Fix the PSFactoryBuffer proxy refcounting, with tests.

This commit is contained in:
Alexandre Julliard 2009-05-27 21:25:10 +02:00
parent 36965f5726
commit 7571c1fd53
2 changed files with 74 additions and 8 deletions

View File

@ -147,11 +147,11 @@ HRESULT StdProxy_Construct(REFIID riid,
if (stubless) { if (stubless) {
CInterfaceStubVtbl *svtbl = ProxyInfo->pStubVtblList[Index]; CInterfaceStubVtbl *svtbl = ProxyInfo->pStubVtblList[Index];
unsigned long i, count = svtbl->header.DispatchTableCount; ULONG i, count = svtbl->header.DispatchTableCount;
/* Maybe the original vtbl is just modified directly to point at /* Maybe the original vtbl is just modified directly to point at
* ObjectStublessClientXXX thunks in real Windows, but I don't like it * ObjectStublessClientXXX thunks in real Windows, but I don't like it
*/ */
TRACE("stubless thunks: count=%ld\n", count); TRACE("stubless thunks: count=%d\n", count);
This->thunks = HeapAlloc(GetProcessHeap(),0,sizeof(struct StublessThunk)*count); This->thunks = HeapAlloc(GetProcessHeap(),0,sizeof(struct StublessThunk)*count);
This->PVtbl = HeapAlloc(GetProcessHeap(),0,sizeof(LPVOID)*count); This->PVtbl = HeapAlloc(GetProcessHeap(),0,sizeof(LPVOID)*count);
for (i=0; i<count; i++) { for (i=0; i<count; i++) {
@ -159,7 +159,7 @@ HRESULT StdProxy_Construct(REFIID riid,
if (vtbl->Vtbl[i] == (LPVOID)-1) { if (vtbl->Vtbl[i] == (LPVOID)-1) {
PFORMAT_STRING fs = stubless->ProcFormatString + stubless->FormatStringOffset[i]; PFORMAT_STRING fs = stubless->ProcFormatString + stubless->FormatStringOffset[i];
unsigned bytes = *(const WORD*)(fs+8) - STACK_ADJUST; unsigned bytes = *(const WORD*)(fs+8) - STACK_ADJUST;
TRACE("method %ld: stacksize=%d\n", i, bytes); TRACE("method %d: stacksize=%d\n", i, bytes);
FILL_STUBLESS(thunk, i, bytes) FILL_STUBLESS(thunk, i, bytes)
This->PVtbl[i] = thunk; This->PVtbl[i] = thunk;
} }
@ -172,6 +172,7 @@ HRESULT StdProxy_Construct(REFIID riid,
else else
This->PVtbl = vtbl->Vtbl; This->PVtbl = vtbl->Vtbl;
if (!pUnkOuter) pUnkOuter = (IUnknown *)This;
This->lpVtbl = &StdProxy_Vtbl; This->lpVtbl = &StdProxy_Vtbl;
/* one reference for the proxy */ /* one reference for the proxy */
This->RefCount = 1; This->RefCount = 1;
@ -183,11 +184,7 @@ HRESULT StdProxy_Construct(REFIID riid,
This->pChannel = NULL; This->pChannel = NULL;
*ppProxy = (LPRPCPROXYBUFFER)&This->lpVtbl; *ppProxy = (LPRPCPROXYBUFFER)&This->lpVtbl;
*ppvObj = &This->PVtbl; *ppvObj = &This->PVtbl;
/* if there is no outer unknown then the caller will control the lifetime IUnknown_AddRef((IUnknown *)*ppvObj);
* of the proxy object through the proxy buffer, so no need to increment the
* ref count of the proxy object */
if (pUnkOuter)
IUnknown_AddRef((IUnknown *)*ppvObj);
IPSFactoryBuffer_AddRef(pPSFactory); IPSFactoryBuffer_AddRef(pPSFactory);
return S_OK; return S_OK;

View File

@ -613,6 +613,74 @@ static IUnknownVtbl create_stub_test_fail_vtbl =
NULL NULL
}; };
struct dummy_unknown
{
const IUnknownVtbl *vtbl;
LONG ref;
};
static HRESULT WINAPI dummy_QueryInterface(IUnknown *This, REFIID iid, void **ppv)
{
*ppv = NULL;
return E_NOINTERFACE;
}
static ULONG WINAPI dummy_AddRef(LPUNKNOWN iface)
{
struct dummy_unknown *this = (struct dummy_unknown *)iface;
return InterlockedIncrement( &this->ref );
}
ULONG WINAPI dummy_Release(LPUNKNOWN iface)
{
struct dummy_unknown *this = (struct dummy_unknown *)iface;
return InterlockedDecrement( &this->ref );
}
static IUnknownVtbl dummy_unknown_vtbl =
{
dummy_QueryInterface,
dummy_AddRef,
dummy_Release
};
static struct dummy_unknown dummy_unknown = { &dummy_unknown_vtbl, 0 };
static void create_proxy_test( IPSFactoryBuffer *ppsf, REFIID iid, const void *expected_vtbl )
{
IRpcProxyBuffer *proxy = NULL;
IUnknown *iface = NULL;
HRESULT r;
ULONG count;
r = IPSFactoryBuffer_CreateProxy(ppsf, NULL, iid, &proxy, (void **)&iface);
ok( r == S_OK, "IPSFactoryBuffer_CreateProxy failed %x\n", r );
ok( *(void **)iface == expected_vtbl, "wrong iface pointer %p/%p\n", *(void **)iface, expected_vtbl );
count = IUnknown_Release( iface );
ok( count == 1, "wrong refcount %u\n", count );
count = IRpcProxyBuffer_Release( proxy );
ok( count == 0, "wrong refcount %u\n", count );
dummy_unknown.ref = 4;
r = IPSFactoryBuffer_CreateProxy(ppsf, (IUnknown *)&dummy_unknown, iid, &proxy, (void **)&iface);
ok( r == S_OK, "IPSFactoryBuffer_CreateProxy failed %x\n", r );
ok( dummy_unknown.ref == 5, "wrong refcount %u\n", dummy_unknown.ref );
ok( *(void **)iface == expected_vtbl, "wrong iface pointer %p/%p\n", *(void **)iface, expected_vtbl );
count = IUnknown_Release( iface );
ok( count == 4, "wrong refcount %u\n", count );
ok( dummy_unknown.ref == 4, "wrong refcount %u\n", dummy_unknown.ref );
count = IRpcProxyBuffer_Release( proxy );
ok( count == 0, "wrong refcount %u\n", count );
ok( dummy_unknown.ref == 4, "wrong refcount %u\n", dummy_unknown.ref );
}
static void test_CreateProxy( IPSFactoryBuffer *ppsf )
{
create_proxy_test( ppsf, &IID_if1, if1_proxy_vtbl.Vtbl );
create_proxy_test( ppsf, &IID_if2, if2_proxy_vtbl.Vtbl );
create_proxy_test( ppsf, &IID_if3, if3_proxy_vtbl.Vtbl );
create_proxy_test( ppsf, &IID_if4, if4_proxy_vtbl.Vtbl );
}
static void test_CreateStub(IPSFactoryBuffer *ppsf) static void test_CreateStub(IPSFactoryBuffer *ppsf)
{ {
IUnknownVtbl *vtbl = &create_stub_test_vtbl; IUnknownVtbl *vtbl = &create_stub_test_vtbl;
@ -951,6 +1019,7 @@ START_TEST( cstub )
ppsf = test_NdrDllGetClassObject(); ppsf = test_NdrDllGetClassObject();
test_NdrStubForwardingFunction(); test_NdrStubForwardingFunction();
test_CreateProxy(ppsf);
test_CreateStub(ppsf); test_CreateStub(ppsf);
test_Connect(ppsf); test_Connect(ppsf);
test_Disconnect(ppsf); test_Disconnect(ppsf);