[PATCH 12/14] rpcrt4: Delegate to the parent if it is not IUnknown.

Zebediah Figura z.figura12 at gmail.com
Sat Nov 3 18:07:24 CDT 2018


Signed-off-by: Zebediah Figura <z.figura12 at 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);
-- 
2.19.1




More information about the wine-devel mailing list