From: Zebediah Figura z.figura12@gmail.com
Signed-off-by: Zebediah Figura z.figura12@gmail.com Signed-off-by: Huw Davies huw@codeweavers.com --- dlls/rpcrt4/ndr_typelib.c | 254 +++++++++++++++++++++++++++++++++++++- 1 file changed, 253 insertions(+), 1 deletion(-)
diff --git a/dlls/rpcrt4/ndr_typelib.c b/dlls/rpcrt4/ndr_typelib.c index 71d87919db..a462524c79 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,233 @@ 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); + hr = E_NOTIMPL; + break; + } + + 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); + hr = E_NOTIMPL; + break; + } + + 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,