[PATCH 2/5] rpcrt4: Write parameter signatures into the procedure format string.

Zebediah Figura z.figura12 at gmail.com
Thu Nov 8 22:18:15 CST 2018


Signed-off-by: Zebediah Figura <z.figura12 at gmail.com>
---
 dlls/rpcrt4/ndr_typelib.c | 252 +++++++++++++++++++++++++++++++++++++-
 1 file changed, 251 insertions(+), 1 deletion(-)

diff --git a/dlls/rpcrt4/ndr_typelib.c b/dlls/rpcrt4/ndr_typelib.c
index 71d87919db..265f9be709 100644
--- a/dlls/rpcrt4/ndr_typelib.c
+++ b/dlls/rpcrt4/ndr_typelib.c
@@ -35,6 +35,30 @@ WINE_DEFAULT_DEBUG_CHANNEL(ole);
 #define WRITE_SHORT(str, len, val) \
     do { if ((str)) *((short *)((str) + (len))) = (val); (len) += 2; } while (0)
 
+static unsigned char get_base_type(VARTYPE vt)
+{
+    switch (vt)
+    {
+    case VT_I1:     return FC_SMALL;
+    case VT_BOOL:
+    case VT_I2:     return FC_SHORT;
+    case VT_INT:
+    case VT_ERROR:
+    case VT_HRESULT:
+    case VT_I4:     return FC_LONG;
+    case VT_I8:
+    case VT_UI8:    return FC_HYPER;
+    case VT_UI1:    return FC_USMALL;
+    case VT_UI2:    return FC_USHORT;
+    case VT_UINT:
+    case VT_UI4:    return FC_ULONG;
+    case VT_R4:     return FC_FLOAT;
+    case VT_DATE:
+    case VT_R8:     return FC_DOUBLE;
+    default:        return 0;
+    }
+}
+
 static unsigned int type_memsize(ITypeInfo *typeinfo, TYPEDESC *desc)
 {
     switch (desc->vt)
@@ -94,6 +118,12 @@ static unsigned int type_memsize(ITypeInfo *typeinfo, TYPEDESC *desc)
     }
 }
 
+static size_t write_type_tfs(ITypeInfo *typeinfo, unsigned char *str,
+        size_t *len, TYPEDESC *desc, BOOL toplevel, BOOL onstack)
+{
+    return E_NOTIMPL;
+}
+
 static unsigned short get_stack_size(ITypeInfo *typeinfo, TYPEDESC *desc)
 {
 #ifdef __i386__
@@ -107,11 +137,231 @@ static unsigned short get_stack_size(ITypeInfo *typeinfo, TYPEDESC *desc)
 #endif
 }
 
+static const unsigned short MustSize    = 0x0001;
+static const unsigned short MustFree    = 0x0002;
+static const unsigned short IsIn        = 0x0008;
+static const unsigned short IsOut       = 0x0010;
+static const unsigned short IsReturn    = 0x0020;
+static const unsigned short IsBasetype  = 0x0040;
+static const unsigned short IsByValue   = 0x0080;
+static const unsigned short IsSimpleRef = 0x0100;
+
+static HRESULT get_param_pointer_info(ITypeInfo *typeinfo, TYPEDESC *tdesc, int is_in,
+        int is_out, unsigned short *server_size, unsigned short *flags,
+        unsigned char *basetype, TYPEDESC **tfs_tdesc)
+{
+    ITypeInfo *refinfo;
+    HRESULT hr = S_OK;
+    TYPEATTR *attr;
+
+    switch (tdesc->vt)
+    {
+    case VT_UNKNOWN:
+    case VT_DISPATCH:
+        *flags |= MustFree;
+        if (is_in && is_out)
+            *server_size = sizeof(void *);
+        break;
+    case VT_PTR:
+        *flags |= MustFree;
+
+        if (tdesc->lptdesc->vt == VT_USERDEFINED)
+        {
+            ITypeInfo_GetRefTypeInfo(typeinfo, tdesc->lptdesc->hreftype, &refinfo);
+            ITypeInfo_GetTypeAttr(refinfo, &attr);
+
+            switch (attr->typekind)
+            {
+            case TKIND_INTERFACE:
+            case TKIND_DISPATCH:
+            case TKIND_COCLASS:
+                if (is_in && is_out)
+                    *server_size = sizeof(void *);
+                break;
+            default:
+                *server_size = sizeof(void *);
+            }
+
+            ITypeInfo_ReleaseTypeAttr(refinfo, attr);
+            ITypeInfo_Release(refinfo);
+        }
+        else
+            *server_size = sizeof(void *);
+        break;
+    case VT_CARRAY:
+        *flags |= IsSimpleRef | MustFree;
+        *server_size = type_memsize(typeinfo, tdesc);
+        *tfs_tdesc = tdesc;
+        break;
+    case VT_USERDEFINED:
+        ITypeInfo_GetRefTypeInfo(typeinfo, tdesc->hreftype, &refinfo);
+        ITypeInfo_GetTypeAttr(refinfo, &attr);
+
+        switch (attr->typekind)
+        {
+        case TKIND_ENUM:
+            *flags |= IsSimpleRef | IsBasetype;
+            if (!is_in && is_out)
+                *server_size = sizeof(void *);
+            *basetype = FC_ENUM32;
+            break;
+        case TKIND_RECORD:
+            *flags |= IsSimpleRef | MustFree;
+            if (!is_in && is_out)
+                *server_size = attr->cbSizeInstance;
+            *tfs_tdesc = tdesc;
+            break;
+        case TKIND_INTERFACE:
+        case TKIND_DISPATCH:
+        case TKIND_COCLASS:
+            *flags |= MustFree;
+            break;
+        case TKIND_ALIAS:
+            hr = get_param_pointer_info(refinfo, &attr->tdescAlias, is_in,
+                    is_out, server_size, flags, basetype, tfs_tdesc);
+            break;
+        default:
+            FIXME("unhandled kind %#x\n", attr->typekind);
+            return E_NOTIMPL;
+        }
+
+        ITypeInfo_ReleaseTypeAttr(refinfo, attr);
+        ITypeInfo_Release(refinfo);
+        break;
+    default:
+        *flags |= IsSimpleRef;
+        *tfs_tdesc = tdesc;
+        if (!is_in && is_out)
+            *server_size = type_memsize(typeinfo, tdesc);
+        if ((*basetype = get_base_type(tdesc->vt)))
+            *flags |= IsBasetype;
+        break;
+    }
+
+    return hr;
+}
+
+static HRESULT get_param_info(ITypeInfo *typeinfo, TYPEDESC *tdesc, int is_in,
+        int is_out, unsigned short *server_size, unsigned short *flags,
+        unsigned char *basetype, TYPEDESC **tfs_tdesc)
+{
+    ITypeInfo *refinfo;
+    HRESULT hr = S_OK;
+    TYPEATTR *attr;
+
+    *server_size = 0;
+    *flags = MustSize;
+    *basetype = 0;
+    *tfs_tdesc = tdesc;
+
+    TRACE("vt %u\n", tdesc->vt);
+
+    switch (tdesc->vt)
+    {
+    case VT_VARIANT:
+#ifndef __i386__
+        *flags |= IsSimpleRef | MustFree;
+        break;
+#endif
+        /* otherwise fall through */
+    case VT_BSTR:
+    case VT_SAFEARRAY:
+    case VT_CY:
+        *flags |= IsByValue | MustFree;
+        break;
+    case VT_UNKNOWN:
+    case VT_DISPATCH:
+    case VT_CARRAY:
+        *flags |= MustFree;
+        break;
+    case VT_PTR:
+        return get_param_pointer_info(typeinfo, tdesc->lptdesc, is_in, is_out,
+                server_size, flags, basetype, tfs_tdesc);
+    case VT_USERDEFINED:
+        ITypeInfo_GetRefTypeInfo(typeinfo, tdesc->hreftype, &refinfo);
+        ITypeInfo_GetTypeAttr(refinfo, &attr);
+
+        switch (attr->typekind)
+        {
+        case TKIND_ENUM:
+            *flags |= IsBasetype;
+            *basetype = FC_ENUM32;
+            break;
+        case TKIND_RECORD:
+#ifdef __i386__
+            *flags |= IsByValue | MustFree;
+#elif defined(__x86_64__)
+            if (attr->cbSizeInstance <= 8)
+                *flags |= IsByValue | MustFree;
+            else
+                *flags |= IsSimpleRef | MustFree;
+#endif
+            break;
+        case TKIND_ALIAS:
+            hr = get_param_info(refinfo, &attr->tdescAlias, is_in, is_out,
+                    server_size, flags, basetype, tfs_tdesc);
+            break;
+        default:
+            FIXME("unhandled kind %#x\n", attr->typekind);
+            return E_NOTIMPL;
+        }
+
+        ITypeInfo_ReleaseTypeAttr(refinfo, attr);
+        ITypeInfo_Release(refinfo);
+        break;
+    default:
+        if ((*basetype = get_base_type(tdesc->vt)))
+            *flags |= IsBasetype;
+        else
+        {
+            FIXME("unhandled type %u\n", tdesc->vt);
+            return E_NOTIMPL;
+        }
+        break;
+    }
+
+    return hr;
+}
+
 static HRESULT write_param_fs(ITypeInfo *typeinfo, unsigned char *type,
         size_t *typelen, unsigned char *proc, size_t *proclen, ELEMDESC *desc,
         BOOL is_return, unsigned short *stack_offset)
 {
-    return E_NOTIMPL;
+    USHORT param_flags = desc->paramdesc.wParamFlags;
+    int is_in  = param_flags & PARAMFLAG_FIN;
+    int is_out = param_flags & PARAMFLAG_FOUT;
+    TYPEDESC *tdesc = &desc->tdesc, *tfs_tdesc;
+    unsigned short server_size;
+    unsigned short stack_size = get_stack_size(typeinfo, tdesc);
+    unsigned char basetype;
+    unsigned short flags;
+    size_t off = 0;
+    HRESULT hr;
+
+    hr = get_param_info(typeinfo, tdesc, is_in, is_out, &server_size, &flags,
+            &basetype, &tfs_tdesc);
+
+    if (is_in)      flags |= IsIn;
+    if (is_out)     flags |= IsOut;
+    if (is_return)  flags |= IsOut | IsReturn;
+
+    server_size = (server_size + 7) / 8;
+    if (server_size >= 8) server_size = 0;
+    flags |= server_size << 13;
+
+    if (!basetype)
+        off = write_type_tfs(typeinfo, type, typelen, tfs_tdesc, TRUE, server_size != 0);
+
+    if (SUCCEEDED(hr))
+    {
+        WRITE_SHORT(proc, *proclen, flags);
+        WRITE_SHORT(proc, *proclen, *stack_offset);
+        WRITE_SHORT(proc, *proclen, basetype ? basetype : off);
+
+        *stack_offset += stack_size;
+    }
+
+    return hr;
 }
 
 static void write_proc_func_header(ITypeInfo *typeinfo, FUNCDESC *desc,
-- 
2.19.1




More information about the wine-devel mailing list