From bd9891ffed347bce23e864b5d5a017d7ba423a2b Mon Sep 17 00:00:00 2001 From: Huw Davies Date: Thu, 31 Aug 2006 15:40:05 +0100 Subject: [PATCH] rpcrt4: Add delegating stub support. --- dlls/rpcrt4/cpsf.c | 7 ++ dlls/rpcrt4/cpsf.h | 9 +++ dlls/rpcrt4/cstub.c | 135 ++++++++++++++++++++++++++++++++++---- dlls/rpcrt4/tests/cstub.c | 100 ++++++++++++++++++++++++---- 4 files changed, 225 insertions(+), 26 deletions(-) diff --git a/dlls/rpcrt4/cpsf.c b/dlls/rpcrt4/cpsf.c index a90dc2f9ac5..a10e231c35b 100644 --- a/dlls/rpcrt4/cpsf.c +++ b/dlls/rpcrt4/cpsf.c @@ -110,6 +110,12 @@ static HRESULT WINAPI CStdPSFactory_CreateStub(LPPSFACTORYBUFFER iface, pUnkServer,ppStub); if (!FindProxyInfo(This->pProxyFileList,riid,&ProxyInfo,&Index)) return E_NOINTERFACE; + + if(ProxyInfo->pDelegatedIIDs && ProxyInfo->pDelegatedIIDs[Index]) + return CStdStubBuffer_Delegating_Construct(riid, pUnkServer, ProxyInfo->pNamesArray[Index], + ProxyInfo->pStubVtblList[Index], ProxyInfo->pDelegatedIIDs[Index], + iface, ppStub); + return CStdStubBuffer_Construct(riid, pUnkServer, ProxyInfo->pNamesArray[Index], ProxyInfo->pStubVtblList[Index], iface, ppStub); } @@ -152,6 +158,7 @@ HRESULT WINAPI NdrDllGetClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv, int j; if ((*pProxyFileList2)->pDelegatedIIDs && (*pProxyFileList2)->pDelegatedIIDs[i]) { + pSrcRpcStubVtbl = (void * const *)&CStdStubBuffer_Delegating_Vtbl; if ((*pProxyFileList2)->pStubVtblList[i]->header.DispatchTableCount > max_delegating_vtbl_size) max_delegating_vtbl_size = (*pProxyFileList2)->pStubVtblList[i]->header.DispatchTableCount; } diff --git a/dlls/rpcrt4/cpsf.h b/dlls/rpcrt4/cpsf.h index 599dec175b0..5ce8fe6575e 100644 --- a/dlls/rpcrt4/cpsf.h +++ b/dlls/rpcrt4/cpsf.h @@ -36,9 +36,18 @@ HRESULT WINAPI CStdStubBuffer_Construct(REFIID riid, LPPSFACTORYBUFFER pPSFactory, LPRPCSTUBBUFFER *ppStub); +HRESULT WINAPI CStdStubBuffer_Delegating_Construct(REFIID riid, + LPUNKNOWN pUnkServer, + PCInterfaceName name, + CInterfaceStubVtbl *vtbl, + REFIID delegating_iid, + LPPSFACTORYBUFFER pPSFactory, + LPRPCSTUBBUFFER *ppStub); + const MIDL_SERVER_INFO *CStdStubBuffer_GetServerInfo(IRpcStubBuffer *iface); const IRpcStubBufferVtbl CStdStubBuffer_Vtbl; +const IRpcStubBufferVtbl CStdStubBuffer_Delegating_Vtbl; void create_delegating_vtbl(DWORD num_methods); diff --git a/dlls/rpcrt4/cstub.c b/dlls/rpcrt4/cstub.c index a61316434d4..67d56aa4d47 100644 --- a/dlls/rpcrt4/cstub.c +++ b/dlls/rpcrt4/cstub.c @@ -252,6 +252,58 @@ static void release_delegating_vtbl(IUnknownVtbl *vtbl) LeaveCriticalSection(&delegating_vtbl_section); } +HRESULT WINAPI CStdStubBuffer_Delegating_Construct(REFIID riid, + LPUNKNOWN pUnkServer, + PCInterfaceName name, + CInterfaceStubVtbl *vtbl, + REFIID delegating_iid, + LPPSFACTORYBUFFER pPSFactory, + LPRPCSTUBBUFFER *ppStub) +{ + cstdstubbuffer_delegating_t *This; + IUnknown *pvServer; + HRESULT r; + + TRACE("(%p,%p,%p,%p) %s\n", pUnkServer, vtbl, pPSFactory, ppStub, name); + TRACE("iid=%s delegating to %s\n", debugstr_guid(vtbl->header.piid), debugstr_guid(delegating_iid)); + TRACE("vtbl=%p\n", &vtbl->Vtbl); + + if (!IsEqualGUID(vtbl->header.piid, riid)) + { + ERR("IID mismatch during stub creation\n"); + return RPC_E_UNEXPECTED; + } + + r = IUnknown_QueryInterface(pUnkServer, riid, (void**)&pvServer); + if(FAILED(r)) return r; + + This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This)); + if (!This) + { + IUnknown_Release(pvServer); + return E_OUTOFMEMORY; + } + + This->base_obj = get_delegating_vtbl(); + r = create_stub(delegating_iid, (IUnknown*)&This->base_obj, &This->base_stub); + if(FAILED(r)) + { + release_delegating_vtbl(This->base_obj); + HeapFree(GetProcessHeap(), 0, This); + IUnknown_Release(pvServer); + return r; + } + + This->stub_buffer.lpVtbl = &vtbl->Vtbl; + This->stub_buffer.RefCount = 1; + This->stub_buffer.pvServerObject = pvServer; + This->stub_buffer.pPSFactory = pPSFactory; + *ppStub = (LPRPCSTUBBUFFER)&This->stub_buffer; + + IPSFactoryBuffer_AddRef(pPSFactory); + return S_OK; +} + HRESULT WINAPI CStdStubBuffer_QueryInterface(LPRPCSTUBBUFFER iface, REFIID riid, LPVOID *obj) @@ -301,8 +353,26 @@ ULONG WINAPI NdrCStdStubBuffer_Release(LPRPCSTUBBUFFER iface, ULONG WINAPI NdrCStdStubBuffer2_Release(LPRPCSTUBBUFFER iface, LPPSFACTORYBUFFER pPSF) { - FIXME("Not implemented\n"); - return 0; + cstdstubbuffer_delegating_t *This = impl_from_delegating( iface ); + ULONG refs; + + TRACE("(%p)->Release()\n", This); + + refs = InterlockedDecrement(&This->stub_buffer.RefCount); + if (!refs) + { + /* Just like NdrCStdStubBuffer_Release, we shouldn't call + Disconnect here */ + IRpcStubBuffer_Disconnect((IRpcStubBuffer *)&This->stub_buffer); + + IRpcStubBuffer_Release(This->base_stub); + release_delegating_vtbl(This->base_obj); + + IPSFactoryBuffer_Release(pPSF); + HeapFree(GetProcessHeap(), 0, This); + } + + return refs; } HRESULT WINAPI CStdStubBuffer_Connect(LPRPCSTUBBUFFER iface, @@ -408,6 +478,55 @@ const IRpcStubBufferVtbl CStdStubBuffer_Vtbl = CStdStubBuffer_DebugServerRelease }; +static HRESULT WINAPI CStdStubBuffer_Delegating_Connect(LPRPCSTUBBUFFER iface, + LPUNKNOWN lpUnkServer) +{ + cstdstubbuffer_delegating_t *This = impl_from_delegating(iface); + HRESULT r; + TRACE("(%p)->Connect(%p)\n", This, lpUnkServer); + + r = CStdStubBuffer_Connect(iface, lpUnkServer); + if(SUCCEEDED(r)) + r = IRpcStubBuffer_Connect(This->base_stub, (IUnknown*)&This->base_obj); + + return r; +} + +static void WINAPI CStdStubBuffer_Delegating_Disconnect(LPRPCSTUBBUFFER iface) +{ + cstdstubbuffer_delegating_t *This = impl_from_delegating(iface); + TRACE("(%p)->Disconnect()\n", This); + + IRpcStubBuffer_Disconnect(This->base_stub); + CStdStubBuffer_Disconnect(iface); +} + +static ULONG WINAPI CStdStubBuffer_Delegating_CountRefs(LPRPCSTUBBUFFER iface) +{ + cstdstubbuffer_delegating_t *This = impl_from_delegating(iface); + ULONG ret; + TRACE("(%p)->CountRefs()\n", This); + + ret = CStdStubBuffer_CountRefs(iface); + ret += IRpcStubBuffer_CountRefs(This->base_stub); + + return ret; +} + +const IRpcStubBufferVtbl CStdStubBuffer_Delegating_Vtbl = +{ + CStdStubBuffer_QueryInterface, + CStdStubBuffer_AddRef, + NULL, + CStdStubBuffer_Delegating_Connect, + CStdStubBuffer_Delegating_Disconnect, + CStdStubBuffer_Invoke, + CStdStubBuffer_IsIIDSupported, + CStdStubBuffer_Delegating_CountRefs, + CStdStubBuffer_DebugServerQueryInterface, + CStdStubBuffer_DebugServerRelease +}; + const MIDL_SERVER_INFO *CStdStubBuffer_GetServerInfo(IRpcStubBuffer *iface) { CStdStubBuffer *This = (CStdStubBuffer *)iface; @@ -420,22 +539,12 @@ const MIDL_SERVER_INFO *CStdStubBuffer_GetServerInfo(IRpcStubBuffer *iface) void __RPC_STUB NdrStubForwardingFunction( IRpcStubBuffer *iface, IRpcChannelBuffer *pChannel, PRPC_MESSAGE pMsg, DWORD *pdwStubPhase ) { - /* Once stub delegation is implemented, this should call - IRpcStubBuffer_Invoke on the stub's base interface. The - IRpcStubBuffer for this interface is stored at (void**)iface-1. - The pChannel and pMsg parameters are passed intact - (RPCOLEMESSAGE is basically a RPC_MESSAGE). If Invoke returns - with a failure then an exception is raised (to see this, change - the return value in the test). + /* Note pMsg is passed intact since RPCOLEMESSAGE is basically a RPC_MESSAGE. */ cstdstubbuffer_delegating_t *This = impl_from_delegating(iface); HRESULT r = IRpcStubBuffer_Invoke(This->base_stub, (RPCOLEMESSAGE*)pMsg, pChannel); if(FAILED(r)) RpcRaiseException(r); return; - */ - - FIXME("Not implemented\n"); - return; } /*********************************************************************** diff --git a/dlls/rpcrt4/tests/cstub.c b/dlls/rpcrt4/tests/cstub.c index 70399437f3d..88489905405 100644 --- a/dlls/rpcrt4/tests/cstub.c +++ b/dlls/rpcrt4/tests/cstub.c @@ -480,15 +480,11 @@ static IPSFactoryBuffer *test_NdrDllGetClassObject(void) VTBL_TEST_CHANGE_TO(QueryInterface, 1); VTBL_TEST_CHANGE_TO(AddRef, 1); VTBL_TEST_NOT_CHANGE_TO(Release, 1); -todo_wine { VTBL_TEST_NOT_CHANGE_TO(Connect, 1); VTBL_TEST_NOT_CHANGE_TO(Disconnect, 1); -} VTBL_TEST_CHANGE_TO(Invoke, 1); VTBL_TEST_CHANGE_TO(IsIIDSupported, 1); -todo_wine { VTBL_TEST_NOT_CHANGE_TO(CountRefs, 1); -} VTBL_TEST_CHANGE_TO(DebugServerQueryInterface, 1); VTBL_TEST_CHANGE_TO(DebugServerRelease, 1); @@ -506,15 +502,11 @@ todo_wine { VTBL_TEST_CHANGE_TO(QueryInterface, 3); VTBL_TEST_CHANGE_TO(AddRef, 3); VTBL_TEST_ZERO(Release, 3); -todo_wine { VTBL_TEST_NOT_CHANGE_TO(Connect, 3); VTBL_TEST_NOT_CHANGE_TO(Disconnect, 3); -} VTBL_TEST_CHANGE_TO(Invoke, 3); VTBL_TEST_CHANGE_TO(IsIIDSupported, 3); -todo_wine { VTBL_TEST_NOT_CHANGE_TO(CountRefs, 3); -} VTBL_TEST_CHANGE_TO(DebugServerQueryInterface, 3); VTBL_TEST_CHANGE_TO(DebugServerRelease, 3); @@ -565,10 +557,7 @@ static void test_NdrStubForwardingFunction(void) real_this = &This[1]; NdrStubForwardingFunction( real_this, channel, msg, phase ); - -todo_wine { ok(base_buffer_invoke_called == 1, "base_buffer_invoke called %d times\n", base_buffer_invoke_called); -} } @@ -743,10 +732,8 @@ static void test_Connect(IPSFactoryBuffer *ppsf) obj = (IUnknown*)&new_vtbl; r = IRpcStubBuffer_Connect(pstub, obj); -todo_wine { ok(connect_test_base_Connect_called == 1, "connect_test_bsae_Connect called %d times\n", connect_test_base_Connect_called); - } ok(connect_test_orig_release_called == 3, "release called %d\n", connect_test_orig_release_called); cstd_stub = (CStdStubBuffer*)pstub; ok(cstd_stub->pvServerObject == (void*)0xcafebabe, "pvServerObject %p\n", cstd_stub->pvServerObject); @@ -810,6 +797,92 @@ todo_wine { ok(PSFactoryBuffer.RefCount == facbuf_refs, "factory buffer refs %ld orig %ld\n", PSFactoryBuffer.RefCount, facbuf_refs); } +static HRESULT WINAPI delegating_invoke_test_QI(ITypeLib *pUnk, REFIID iid, void** ppv) +{ + + *ppv = pUnk; + return S_OK; +} + +static ULONG WINAPI delegating_invoke_test_addref(ITypeLib *pUnk) +{ + return 1; +} + +static ULONG WINAPI delegating_invoke_test_release(ITypeLib *pUnk) +{ + return 1; +} + +static UINT WINAPI delegating_invoke_test_get_type_info_count(ITypeLib *pUnk) +{ + return 0xabcdef; +} + +static ITypeLibVtbl delegating_invoke_test_obj_vtbl = +{ + delegating_invoke_test_QI, + delegating_invoke_test_addref, + delegating_invoke_test_release, + delegating_invoke_test_get_type_info_count, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +static HRESULT WINAPI delegating_invoke_test_get_buffer(IRpcChannelBuffer *pchan, + RPCOLEMESSAGE *msg, + REFIID iid) +{ + msg->Buffer = HeapAlloc(GetProcessHeap(), 0, msg->cbBuffer); + return S_OK; +} + +static IRpcChannelBufferVtbl delegating_invoke_test_rpc_chan_vtbl = +{ + NULL, + NULL, + NULL, + delegating_invoke_test_get_buffer, + NULL, + NULL, + NULL, + NULL +}; + +static void test_delegating_Invoke(IPSFactoryBuffer *ppsf) +{ + ITypeLibVtbl *obj_vtbl = &delegating_invoke_test_obj_vtbl; + IUnknown *obj = (IUnknown*)&obj_vtbl; + IRpcStubBuffer *pstub = create_stub(ppsf, &IID_if2, obj, S_OK); + IRpcChannelBufferVtbl *pchan_vtbl = &delegating_invoke_test_rpc_chan_vtbl; + IRpcChannelBuffer *pchan = (IRpcChannelBuffer *)&pchan_vtbl; + HRESULT r = E_FAIL; + RPCOLEMESSAGE msg; + + memset(&msg, 0, sizeof(msg)); + msg.dataRepresentation = NDR_LOCAL_DATA_REPRESENTATION; + msg.iMethod = 3; +#if 0 /* FIXME: Figure out why this fails in Windows */ + r = IRpcStubBuffer_Invoke(pstub, &msg, pchan); + ok(r == S_OK, "ret %08lx\n", r); +#else + pchan = NULL; /* stop compiler waring */ +#endif + if(r == S_OK) + { + ok(*(DWORD*)msg.Buffer == 0xabcdef, "buf[0] %08lx\n", *(DWORD*)msg.Buffer); + ok(*((DWORD*)msg.Buffer + 1) == S_OK, "buf[1] %08lx\n", *((DWORD*)msg.Buffer + 1)); + } + IRpcStubBuffer_Release(pstub); +} + START_TEST( cstub ) { IPSFactoryBuffer *ppsf; @@ -822,6 +895,7 @@ START_TEST( cstub ) test_Connect(ppsf); test_Disconnect(ppsf); test_Release(ppsf); + test_delegating_Invoke(ppsf); OleUninitialize(); }