diff --git a/dlls/rpcrt4/cproxy.c b/dlls/rpcrt4/cproxy.c index 887de870b07..64616123657 100644 --- a/dlls/rpcrt4/cproxy.c +++ b/dlls/rpcrt4/cproxy.c @@ -2,6 +2,7 @@ * COM proxy implementation * * Copyright 2001 Ove Kåven, TransGaming Technologies + * Copyright 2009 Alexandre Julliard * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -48,6 +49,8 @@ typedef struct { LONG RefCount; const IID* piid; LPUNKNOWN pUnkOuter; + IUnknown *base_object; /* must be at offset 0x10 from PVtbl */ + IRpcProxyBuffer *base_proxy; PCInterfaceName name; LPPSFACTORYBUFFER pPSFactory; LPRPCCHANNELBUFFER pChannel; @@ -172,8 +175,6 @@ HRESULT StdProxy_Construct(REFIID riid, fill_stubless_table( (IUnknownVtbl *)vtbl->Vtbl, count ); } - TRACE("iid=%s vtbl=%p\n", debugstr_guid(vtbl->header.piid), vtbl->Vtbl); - if (!IsEqualGUID(vtbl->header.piid, riid)) { ERR("IID mismatch during proxy creation\n"); return RPC_E_UNEXPECTED; @@ -188,15 +189,31 @@ HRESULT StdProxy_Construct(REFIID riid, /* one reference for the proxy */ This->RefCount = 1; This->piid = vtbl->header.piid; + This->base_object = NULL; + This->base_proxy = NULL; This->pUnkOuter = pUnkOuter; This->name = name; This->pPSFactory = pPSFactory; This->pChannel = NULL; + + if(ProxyInfo->pDelegatedIIDs && ProxyInfo->pDelegatedIIDs[Index]) + { + HRESULT r = create_proxy( ProxyInfo->pDelegatedIIDs[Index], NULL, + &This->base_proxy, (void **)&This->base_object ); + if (FAILED(r)) + { + HeapFree( GetProcessHeap(), 0, This ); + return r; + } + } + *ppProxy = (LPRPCPROXYBUFFER)&This->lpVtbl; *ppvObj = &This->PVtbl; IUnknown_AddRef((IUnknown *)*ppvObj); IPSFactoryBuffer_AddRef(pPSFactory); + TRACE( "iid=%s this %p proxy %p obj %p vtbl %p base proxy %p base obj %p\n", + debugstr_guid(riid), This, *ppProxy, *ppvObj, This->PVtbl, This->base_proxy, This->base_object ); return S_OK; } @@ -207,6 +224,9 @@ static void StdProxy_Destruct(LPRPCPROXYBUFFER iface) if (This->pChannel) IRpcProxyBuffer_Disconnect(iface); + if (This->base_object) IUnknown_Release( This->base_object ); + if (This->base_proxy) IRpcProxyBuffer_Release( This->base_proxy ); + IPSFactoryBuffer_Release(This->pPSFactory); HeapFree(GetProcessHeap(),0,This); } @@ -262,6 +282,7 @@ static HRESULT WINAPI StdProxy_Connect(LPRPCPROXYBUFFER iface, This->pChannel = pChannel; IRpcChannelBuffer_AddRef(pChannel); + if (This->base_proxy) IRpcProxyBuffer_Connect( This->base_proxy, pChannel ); return S_OK; } @@ -270,6 +291,8 @@ static VOID WINAPI StdProxy_Disconnect(LPRPCPROXYBUFFER iface) ICOM_THIS_MULTI(StdProxyImpl,lpVtbl,iface); TRACE("(%p)->Disconnect()\n",This); + if (This->base_proxy) IRpcProxyBuffer_Disconnect( This->base_proxy ); + IRpcChannelBuffer_Release(This->pChannel); This->pChannel = NULL; } diff --git a/dlls/rpcrt4/cpsf.c b/dlls/rpcrt4/cpsf.c index 6d945808738..fe551857472 100644 --- a/dlls/rpcrt4/cpsf.c +++ b/dlls/rpcrt4/cpsf.c @@ -155,6 +155,7 @@ static void init_psfactory( CStdPSFactoryBuffer *psfac, const ProxyFileInfo **fi psfac->pProxyFileList = file_list; for (i = 0; file_list[i]; i++) { + const PCInterfaceProxyVtblList *proxies = file_list[i]->pProxyVtblList; const PCInterfaceStubVtblList *stubs = file_list[i]->pStubVtblList; for (j = 0; j < file_list[i]->TableSize; j++) @@ -165,7 +166,11 @@ static void init_psfactory( CStdPSFactoryBuffer *psfac, const ProxyFileInfo **fi void **pRpcStubVtbl = (void **)&stubs[j]->Vtbl; if (file_list[i]->pDelegatedIIDs && file_list[i]->pDelegatedIIDs[j]) + { + fill_delegated_proxy_table( (IUnknownVtbl *)proxies[j]->Vtbl, + stubs[j]->header.DispatchTableCount ); pSrcRpcStubVtbl = (void * const *)&CStdStubBuffer_Delegating_Vtbl; + } for (k = 0; k < sizeof(IRpcStubBufferVtbl)/sizeof(void *); k++) if (!pRpcStubVtbl[k]) pRpcStubVtbl[k] = pSrcRpcStubVtbl[k]; diff --git a/dlls/rpcrt4/cpsf.h b/dlls/rpcrt4/cpsf.h index 58645fb06c1..9cc046ff7ca 100644 --- a/dlls/rpcrt4/cpsf.h +++ b/dlls/rpcrt4/cpsf.h @@ -38,6 +38,8 @@ const MIDL_SERVER_INFO *CStdStubBuffer_GetServerInfo(IRpcStubBuffer *iface); const IRpcStubBufferVtbl CStdStubBuffer_Vtbl; const IRpcStubBufferVtbl CStdStubBuffer_Delegating_Vtbl; +BOOL fill_delegated_proxy_table(IUnknownVtbl *vtbl, DWORD num); +HRESULT create_proxy(REFIID iid, IUnknown *pUnkOuter, IRpcProxyBuffer **pproxy, void **ppv); HRESULT create_stub(REFIID iid, IUnknown *pUnk, IRpcStubBuffer **ppstub); #endif /* __WINE_CPSF_H */ diff --git a/dlls/rpcrt4/cstub.c b/dlls/rpcrt4/cstub.c index 8e947f2f37a..3e1ae8fb631 100644 --- a/dlls/rpcrt4/cstub.c +++ b/dlls/rpcrt4/cstub.c @@ -2,6 +2,7 @@ * COM stub (CStdStubBuffer) implementation * * Copyright 2001 Ove Kåven, TransGaming Technologies + * Copyright 2009 Alexandre Julliard * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -212,6 +213,24 @@ static BOOL fill_delegated_stub_table(IUnknownVtbl *vtbl, DWORD num) return TRUE; } +BOOL fill_delegated_proxy_table(IUnknownVtbl *vtbl, DWORD num) +{ + const void **entry = (const void **)(vtbl + 1); + DWORD i, j; + + vtbl->QueryInterface = IUnknown_QueryInterface_Proxy; + vtbl->AddRef = IUnknown_AddRef_Proxy; + vtbl->Release = IUnknown_Release_Proxy; + for (i = 0; i < (num - 3 + BLOCK_SIZE - 1) / BLOCK_SIZE; i++) + { + const vtbl_method_t *block = method_blocks[i]; + if (!block && !(block = allocate_block( i ))) return FALSE; + for (j = 0; j < BLOCK_SIZE && j < num - 3 - i * BLOCK_SIZE; j++, entry++) + if (!*entry) *entry = &block[j]; + } + return TRUE; +} + #else /* __i386__ */ static BOOL fill_delegated_stub_table(IUnknownVtbl *vtbl, DWORD num) @@ -220,6 +239,12 @@ static BOOL fill_delegated_stub_table(IUnknownVtbl *vtbl, DWORD num) return FALSE; } +BOOL fill_delegated_proxy_table(IUnknownVtbl *vtbl, DWORD num) +{ + ERR("delegated proxies are not supported on this architecture\n"); + return FALSE; +} + #endif /* __i386__ */ static IUnknownVtbl *get_delegating_vtbl(DWORD num_methods) diff --git a/dlls/rpcrt4/ndr_ole.c b/dlls/rpcrt4/ndr_ole.c index a3264e70122..a4c23c2c5c2 100644 --- a/dlls/rpcrt4/ndr_ole.c +++ b/dlls/rpcrt4/ndr_ole.c @@ -369,6 +369,30 @@ void WINAPI NdrOleFree(void *NodeToFree) COM_MemFree(NodeToFree); } +/*********************************************************************** + * Helper function to create a proxy. + * Probably similar to NdrpCreateProxy. + */ +HRESULT create_proxy(REFIID iid, IUnknown *pUnkOuter, IRpcProxyBuffer **pproxy, void **ppv) +{ + CLSID clsid; + IPSFactoryBuffer *psfac; + HRESULT r; + + if(!LoadCOM()) return E_FAIL; + + r = COM_GetPSClsid( iid, &clsid ); + if(FAILED(r)) return r; + + r = COM_GetClassObject( &clsid, CLSCTX_INPROC_SERVER, NULL, &IID_IPSFactoryBuffer, (void**)&psfac ); + if(FAILED(r)) return r; + + r = IPSFactoryBuffer_CreateProxy(psfac, pUnkOuter, iid, pproxy, ppv); + + IPSFactoryBuffer_Release(psfac); + return r; +} + /*********************************************************************** * Helper function to create a stub. * This probably looks very much like NdrpCreateStub.