Signed-off-by: Zebediah Figura z.figura12@gmail.com ---
This differs from the old typelib marshaller's approach of using the parent interface's methods directly; I find this approach to be simpler given the architecture of stubless proxies.
dlls/rpcrt4/cpsf.h | 9 +++ dlls/rpcrt4/cstub.c | 11 +--- dlls/rpcrt4/ndr_typelib.c | 126 +++++++++++++++++++++++++++++--------- 3 files changed, 107 insertions(+), 39 deletions(-)
diff --git a/dlls/rpcrt4/cpsf.h b/dlls/rpcrt4/cpsf.h index c8980e526d..3cfbf77ff6 100644 --- a/dlls/rpcrt4/cpsf.h +++ b/dlls/rpcrt4/cpsf.h @@ -37,6 +37,13 @@ typedef struct IRpcChannelBuffer *pChannel; } StdProxyImpl;
+typedef struct +{ + IUnknownVtbl *base_obj; + IRpcStubBuffer *base_stub; + CStdStubBuffer stub_buffer; +} cstdstubbuffer_delegating_t; + HRESULT StdProxy_Construct(REFIID riid, LPUNKNOWN pUnkOuter, const ProxyFileInfo *ProxyInfo, int Index, LPPSFACTORYBUFFER pPSFactory, LPRPCPROXYBUFFER *ppProxy, LPVOID *ppvObj) DECLSPEC_HIDDEN; @@ -62,5 +69,7 @@ BOOL fill_delegated_proxy_table(IUnknownVtbl *vtbl, DWORD num) DECLSPEC_HIDDEN; HRESULT create_proxy(REFIID iid, IUnknown *pUnkOuter, IRpcProxyBuffer **pproxy, void **ppv) DECLSPEC_HIDDEN; HRESULT create_stub(REFIID iid, IUnknown *pUnk, IRpcStubBuffer **ppstub) DECLSPEC_HIDDEN; BOOL fill_stubless_table(IUnknownVtbl *vtbl, DWORD num) DECLSPEC_HIDDEN; +IUnknownVtbl *get_delegating_vtbl(DWORD num_methods) DECLSPEC_HIDDEN; +void release_delegating_vtbl(IUnknownVtbl *vtbl) DECLSPEC_HIDDEN;
#endif /* __WINE_CPSF_H */ diff --git a/dlls/rpcrt4/cstub.c b/dlls/rpcrt4/cstub.c index 838ed03653..77b0faf430 100644 --- a/dlls/rpcrt4/cstub.c +++ b/dlls/rpcrt4/cstub.c @@ -50,13 +50,6 @@ static LONG WINAPI stub_filter(EXCEPTION_POINTERS *eptr) return EXCEPTION_EXECUTE_HANDLER; }
-typedef struct -{ - IUnknownVtbl *base_obj; - IRpcStubBuffer *base_stub; - CStdStubBuffer stub_buffer; -} cstdstubbuffer_delegating_t; - static inline cstdstubbuffer_delegating_t *impl_from_delegating( IRpcStubBuffer *iface ) { return CONTAINING_RECORD(iface, cstdstubbuffer_delegating_t, stub_buffer); @@ -260,7 +253,7 @@ BOOL fill_delegated_proxy_table(IUnknownVtbl *vtbl, DWORD num) return TRUE; }
-static IUnknownVtbl *get_delegating_vtbl(DWORD num_methods) +IUnknownVtbl *get_delegating_vtbl(DWORD num_methods) { IUnknownVtbl *ret;
@@ -296,7 +289,7 @@ static IUnknownVtbl *get_delegating_vtbl(DWORD num_methods) return ret; }
-static void release_delegating_vtbl(IUnknownVtbl *vtbl) +void release_delegating_vtbl(IUnknownVtbl *vtbl) { ref_counted_vtbl *table = (ref_counted_vtbl*)((DWORD *)vtbl - 1);
diff --git a/dlls/rpcrt4/ndr_typelib.c b/dlls/rpcrt4/ndr_typelib.c index 5eb72af8c7..b06139eae0 100644 --- a/dlls/rpcrt4/ndr_typelib.c +++ b/dlls/rpcrt4/ndr_typelib.c @@ -663,7 +663,7 @@ static void write_proc_func_header(ITypeInfo *typeinfo, FUNCDESC *desc, WRITE_CHAR (proc, *proclen, desc->cParams + 1); /* incl. return value */ }
-static HRESULT write_iface_fs(ITypeInfo *typeinfo, WORD funcs, +static HRESULT write_iface_fs(ITypeInfo *typeinfo, WORD funcs, WORD parentfuncs, unsigned char *type, size_t *typelen, unsigned char *proc, size_t *proclen, unsigned short *offset) { @@ -672,6 +672,12 @@ static HRESULT write_iface_fs(ITypeInfo *typeinfo, WORD funcs, FUNCDESC *desc; HRESULT hr;
+ for (proc_idx = 3; proc_idx < parentfuncs; proc_idx++) + { + if (offset) + offset[proc_idx - 3] = -1; + } + for (proc_idx = 0; proc_idx < funcs; proc_idx++) { TRACE("proc %d\n", proc_idx); @@ -680,9 +686,9 @@ static HRESULT write_iface_fs(ITypeInfo *typeinfo, WORD funcs, if (FAILED(hr)) return hr;
if (offset) - offset[proc_idx] = *proclen; + offset[proc_idx + parentfuncs - 3] = *proclen;
- write_proc_func_header(typeinfo, desc, proc_idx + 3, proc, proclen); + write_proc_func_header(typeinfo, desc, proc_idx + parentfuncs, proc, proclen);
stack_offset = sizeof(void *); /* This */ for (param_idx = 0; param_idx < desc->cParams; param_idx++) @@ -704,20 +710,20 @@ static HRESULT write_iface_fs(ITypeInfo *typeinfo, WORD funcs, }
static HRESULT build_format_strings(ITypeInfo *typeinfo, WORD funcs, - const unsigned char **type_ret, const unsigned char **proc_ret, - unsigned short **offset_ret) + WORD parentfuncs, const unsigned char **type_ret, + const unsigned char **proc_ret, unsigned short **offset_ret) { size_t typelen = oleaut_tfs_size, proclen = 0; unsigned char *type, *proc; unsigned short *offset; HRESULT hr;
- hr = write_iface_fs(typeinfo, funcs, NULL, &typelen, NULL, &proclen, NULL); + hr = write_iface_fs(typeinfo, funcs, parentfuncs, NULL, &typelen, NULL, &proclen, NULL); if (FAILED(hr)) return hr;
type = heap_alloc(typelen); proc = heap_alloc(proclen); - offset = heap_alloc(funcs * sizeof(*offset)); + offset = heap_alloc((parentfuncs + funcs - 3) * sizeof(*offset)); if (!type || !proc || !offset) { ERR("Failed to allocate format strings.\n"); @@ -729,7 +735,7 @@ static HRESULT build_format_strings(ITypeInfo *typeinfo, WORD funcs, typelen = oleaut_tfs_size; proclen = 0;
- hr = write_iface_fs(typeinfo, funcs, type, &typelen, proc, &proclen, offset); + hr = write_iface_fs(typeinfo, funcs, parentfuncs, type, &typelen, proc, &proclen, offset); if (SUCCEEDED(hr)) { *type_ret = type; @@ -746,9 +752,10 @@ err: }
/* Common helper for Create{Proxy,Stub}FromTypeInfo(). */ -static HRESULT get_iface_info(ITypeInfo **typeinfo, WORD *funcs, WORD *parentfuncs) +static HRESULT get_iface_info(ITypeInfo **typeinfo, WORD *funcs, WORD *parentfuncs, + GUID *parentiid) { - ITypeInfo *real_typeinfo; + ITypeInfo *real_typeinfo, *parentinfo; TYPEATTR *typeattr; ITypeLib *typelib; TLIBATTR *libattr; @@ -800,7 +807,20 @@ static HRESULT get_iface_info(ITypeInfo **typeinfo, WORD *funcs, WORD *parentfun *parentfuncs = typeattr->cbSizeVft / (syskind == SYS_WIN64 ? 8 : 4) - *funcs; ITypeInfo_ReleaseTypeAttr(*typeinfo, typeattr);
- return S_OK; + hr = ITypeInfo_GetRefTypeOfImplType(*typeinfo, 0, &reftype); + if (FAILED(hr)) + return hr; + hr = ITypeInfo_GetRefTypeInfo(*typeinfo, reftype, &parentinfo); + if (FAILED(hr)) + return hr; + hr = ITypeInfo_GetTypeAttr(parentinfo, &typeattr); + if (FAILED(hr)) + return hr; + *parentiid = typeattr->guid; + ITypeInfo_ReleaseTypeAttr(parentinfo, typeattr); + ITypeInfo_Release(parentinfo); + + return hr; }
static void init_stub_desc(MIDL_STUB_DESC *desc) @@ -833,6 +853,10 @@ static ULONG WINAPI typelib_proxy_Release(IRpcProxyBuffer *iface) { if (proxy->proxy.pChannel) IRpcProxyBuffer_Disconnect(&proxy->proxy.IRpcProxyBuffer_iface); + if (proxy->proxy.base_object) + IUnknown_Release(proxy->proxy.base_object); + if (proxy->proxy.base_proxy) + IRpcProxyBuffer_Release(proxy->proxy.base_proxy); heap_free((void *)proxy->stub_desc.pFormatTypes); heap_free((void *)proxy->proxy_info.ProcFormatString); heap_free(proxy->offset_table); @@ -852,7 +876,7 @@ static const IRpcProxyBufferVtbl typelib_proxy_vtbl = };
static HRESULT typelib_proxy_init(struct typelib_proxy *proxy, IUnknown *outer, - ULONG count, IRpcProxyBuffer **proxy_buffer, void **out) + ULONG count, const GUID *parentiid, IRpcProxyBuffer **proxy_buffer, void **out) { if (!fill_stubless_table((IUnknownVtbl *)proxy->proxy_vtbl->Vtbl, count)) return E_OUTOFMEMORY; @@ -865,6 +889,13 @@ static HRESULT typelib_proxy_init(struct typelib_proxy *proxy, IUnknown *outer, proxy->proxy.piid = proxy->proxy_vtbl->header.piid; proxy->proxy.pUnkOuter = outer;
+ if (!IsEqualGUID(parentiid, &IID_IUnknown)) + { + HRESULT hr = create_proxy(parentiid, NULL, &proxy->proxy.base_proxy, + (void **)&proxy->proxy.base_object); + if (FAILED(hr)) return hr; + } + *proxy_buffer = &proxy->proxy.IRpcProxyBuffer_iface; *out = &proxy->proxy.PVtbl; IUnknown_AddRef((IUnknown *)*out); @@ -877,12 +908,13 @@ HRESULT WINAPI CreateProxyFromTypeInfo(ITypeInfo *typeinfo, IUnknown *outer, { struct typelib_proxy *proxy; WORD funcs, parentfuncs, i; + GUID parentiid; HRESULT hr;
TRACE("typeinfo %p, outer %p, iid %s, proxy_buffer %p, out %p.\n", typeinfo, outer, debugstr_guid(iid), proxy_buffer, out);
- hr = get_iface_info(&typeinfo, &funcs, &parentfuncs); + hr = get_iface_info(&typeinfo, &funcs, &parentfuncs, &parentiid); if (FAILED(hr)) return hr;
@@ -905,10 +937,11 @@ HRESULT WINAPI CreateProxyFromTypeInfo(ITypeInfo *typeinfo, IUnknown *outer, proxy->proxy_vtbl->header.pStublessProxyInfo = &proxy->proxy_info; proxy->iid = *iid; proxy->proxy_vtbl->header.piid = &proxy->iid; + fill_delegated_proxy_table((IUnknownVtbl *)proxy->proxy_vtbl->Vtbl, parentfuncs); for (i = 0; i < funcs; i++) - proxy->proxy_vtbl->Vtbl[3 + i] = (void *)-1; + proxy->proxy_vtbl->Vtbl[parentfuncs + i] = (void *)-1;
- hr = build_format_strings(typeinfo, funcs, &proxy->stub_desc.pFormatTypes, + hr = build_format_strings(typeinfo, funcs, parentfuncs, &proxy->stub_desc.pFormatTypes, &proxy->proxy_info.ProcFormatString, &proxy->offset_table); if (FAILED(hr)) { @@ -918,7 +951,7 @@ HRESULT WINAPI CreateProxyFromTypeInfo(ITypeInfo *typeinfo, IUnknown *outer, } proxy->proxy_info.FormatStringOffset = &proxy->offset_table[-3];
- hr = typelib_proxy_init(proxy, outer, funcs + parentfuncs, proxy_buffer, out); + hr = typelib_proxy_init(proxy, outer, funcs + parentfuncs, &parentiid, proxy_buffer, out); if (FAILED(hr)) { heap_free((void *)proxy->stub_desc.pFormatTypes); @@ -933,18 +966,19 @@ HRESULT WINAPI CreateProxyFromTypeInfo(ITypeInfo *typeinfo, IUnknown *outer,
struct typelib_stub { - CStdStubBuffer stub; + cstdstubbuffer_delegating_t stub; IID iid; MIDL_STUB_DESC stub_desc; MIDL_SERVER_INFO server_info; CInterfaceStubVtbl stub_vtbl; unsigned short *offset_table; + PRPC_STUB_FUNCTION *dispatch_table; };
static ULONG WINAPI typelib_stub_Release(IRpcStubBuffer *iface) { - struct typelib_stub *stub = CONTAINING_RECORD(iface, struct typelib_stub, stub); - ULONG refcount = InterlockedDecrement(&stub->stub.RefCount); + struct typelib_stub *stub = CONTAINING_RECORD(iface, struct typelib_stub, stub.stub_buffer); + ULONG refcount = InterlockedDecrement(&stub->stub.stub_buffer.RefCount);
TRACE("(%p) decreasing refs to %d\n", stub, refcount);
@@ -954,6 +988,13 @@ static ULONG WINAPI typelib_stub_Release(IRpcStubBuffer *iface) We'll leave it in for the time being. */ IRpcStubBuffer_Disconnect(iface);
+ if (stub->stub.base_stub) + { + IRpcStubBuffer_Release(stub->stub.base_stub); + release_delegating_vtbl(stub->stub.base_obj); + heap_free(stub->dispatch_table); + } + heap_free((void *)stub->stub_desc.pFormatTypes); heap_free((void *)stub->server_info.ProcString); heap_free(stub->offset_table); @@ -964,38 +1005,51 @@ static ULONG WINAPI typelib_stub_Release(IRpcStubBuffer *iface) }
static HRESULT typelib_stub_init(struct typelib_stub *stub, IUnknown *server, - IRpcStubBuffer **stub_buffer) + const GUID *parentiid, IRpcStubBuffer **stub_buffer) { HRESULT hr;
hr = IUnknown_QueryInterface(server, stub->stub_vtbl.header.piid, - (void **)&stub->stub.pvServerObject); + (void **)&stub->stub.stub_buffer.pvServerObject); if (FAILED(hr)) { WARN("Failed to get interface %s, hr %#x.\n", debugstr_guid(stub->stub_vtbl.header.piid), hr); - stub->stub.pvServerObject = server; + stub->stub.stub_buffer.pvServerObject = server; IUnknown_AddRef(server); }
- stub->stub.lpVtbl = &stub->stub_vtbl.Vtbl; - stub->stub.RefCount = 1; + if (!IsEqualGUID(parentiid, &IID_IUnknown)) + { + stub->stub.base_obj = get_delegating_vtbl(stub->stub_vtbl.header.DispatchTableCount); + hr = create_stub(parentiid, (IUnknown *)&stub->stub.base_obj, &stub->stub.base_stub); + if (FAILED(hr)) + { + release_delegating_vtbl(stub->stub.base_obj); + IUnknown_Release(stub->stub.stub_buffer.pvServerObject); + return hr; + } + } + + stub->stub.stub_buffer.lpVtbl = &stub->stub_vtbl.Vtbl; + stub->stub.stub_buffer.RefCount = 1;
- *stub_buffer = (IRpcStubBuffer *)&stub->stub; + *stub_buffer = (IRpcStubBuffer *)&stub->stub.stub_buffer; return S_OK; }
HRESULT WINAPI CreateStubFromTypeInfo(ITypeInfo *typeinfo, REFIID iid, IUnknown *server, IRpcStubBuffer **stub_buffer) { + WORD funcs, parentfuncs, i; struct typelib_stub *stub; - WORD funcs, parentfuncs; + GUID parentiid; HRESULT hr;
TRACE("typeinfo %p, iid %s, server %p, stub_buffer %p.\n", typeinfo, debugstr_guid(iid), server, stub_buffer);
- hr = get_iface_info(&typeinfo, &funcs, &parentfuncs); + hr = get_iface_info(&typeinfo, &funcs, &parentfuncs, &parentiid); if (FAILED(hr)) return hr;
@@ -1008,7 +1062,7 @@ HRESULT WINAPI CreateStubFromTypeInfo(ITypeInfo *typeinfo, REFIID iid, init_stub_desc(&stub->stub_desc); stub->server_info.pStubDesc = &stub->stub_desc;
- hr = build_format_strings(typeinfo, funcs, &stub->stub_desc.pFormatTypes, + hr = build_format_strings(typeinfo, funcs, parentfuncs, &stub->stub_desc.pFormatTypes, &stub->server_info.ProcString, &stub->offset_table); if (FAILED(hr)) { @@ -1021,10 +1075,22 @@ HRESULT WINAPI CreateStubFromTypeInfo(ITypeInfo *typeinfo, REFIID iid, stub->stub_vtbl.header.piid = &stub->iid; stub->stub_vtbl.header.pServerInfo = &stub->server_info; stub->stub_vtbl.header.DispatchTableCount = funcs + parentfuncs; - stub->stub_vtbl.Vtbl = CStdStubBuffer_Vtbl; + + if (!IsEqualGUID(&parentiid, &IID_IUnknown)) + { + stub->dispatch_table = heap_alloc((funcs + parentfuncs) * sizeof(void *)); + for (i = 3; i < parentfuncs; i++) + stub->dispatch_table[i - 3] = NdrStubForwardingFunction; + for (; i < funcs + parentfuncs; i++) + stub->dispatch_table[i - 3] = (PRPC_STUB_FUNCTION)NdrStubCall2; + stub->stub_vtbl.header.pDispatchTable = &stub->dispatch_table[-3]; + stub->stub_vtbl.Vtbl = CStdStubBuffer_Delegating_Vtbl; + } + else + stub->stub_vtbl.Vtbl = CStdStubBuffer_Vtbl; stub->stub_vtbl.Vtbl.Release = typelib_stub_Release;
- hr = typelib_stub_init(stub, server, stub_buffer); + hr = typelib_stub_init(stub, server, &parentiid, stub_buffer); if (FAILED(hr)) { heap_free((void *)stub->stub_desc.pFormatTypes);