From e8a7c71d6ad9c839b5f93c44e98650d191edfc2c Mon Sep 17 00:00:00 2001 From: Mikolaj Zalewski Date: Fri, 5 Oct 2007 15:55:56 -0700 Subject: [PATCH] oleaut32: function kind for dispatch interfaces should be FUNC_DISPATCH (with test, fixes bug #9057) --- dlls/oleaut32/tests/Makefile.in | 2 dlls/oleaut32/tests/test_tlb.idl | 39 +++ dlls/oleaut32/tests/typelib.c | 447 ++++++++++++++++++++++++++++++++++++++ dlls/oleaut32/typelib.c | 2 4 files changed, 489 insertions(+), 1 deletions(-) diff --git a/dlls/oleaut32/tests/Makefile.in b/dlls/oleaut32/tests/Makefile.in index 7e0b307..6152eb3 100644 --- a/dlls/oleaut32/tests/Makefile.in +++ b/dlls/oleaut32/tests/Makefile.in @@ -20,7 +20,7 @@ CTESTS = \ RC_SRCS = tmarshal.rc IDL_I_SRCS = tmarshal.idl -IDL_TLB_SRCS = tmarshal.idl +IDL_TLB_SRCS = test_tlb.idl tmarshal.idl @MAKE_TEST_RULES@ diff --git a/dlls/oleaut32/tests/test_tlb.idl b/dlls/oleaut32/tests/test_tlb.idl new file mode 100644 index 0000000..d69d05b --- /dev/null +++ b/dlls/oleaut32/tests/test_tlb.idl @@ -0,0 +1,39 @@ +/* + * ITypeLib test IDL - we dump it and compare results in typelib.c + * + * Copyright 2007 Google (Mikolaj Zalewski) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +import "oaidl.idl"; /* needed by widl */ + +[uuid(8b05fe77-4a6c-4133-b9cd-8f81747af784)] +library Test +{ + importlib("../../stdole2.tlb/std_ole_v2.tlb"); + + [dual,uuid(b14b6bb5-904e-4ff9-b247-bd361f7aaedd)] + interface IDualIface : IDispatch + { + HRESULT test(); + } + + [uuid(ec5dfcd6-eeb0-4cd6-b51e-8030e1dac009)] + interface ISimpleIface : IDispatch + { + HRESULT test(); + } +} diff --git a/dlls/oleaut32/tests/typelib.c b/dlls/oleaut32/tests/typelib.c index d19afd3..89b3cb5 100644 --- a/dlls/oleaut32/tests/typelib.c +++ b/dlls/oleaut32/tests/typelib.c @@ -31,6 +31,25 @@ #include "ocidl.h" #include "shlwapi.h" #include "tmarshal.h" +#define expect_eq(expr, value, type, format) { type _ret = (expr); ok((value) == _ret, #expr " expected " format " got " format "\n", value, _ret); } +#define expect_int(expr, value) expect_eq(expr, (LONGLONG)value, LONGLONG, "%lld") +#define expect_hex(expr, value) expect_eq(expr, (LONGLONG)value, LONGLONG, "0x%llx") +#define expect_null(expr) expect_eq(expr, NULL, void *, "%p") + +#define expect_wstr_utf8val(expr, value) \ + { \ + CHAR buf[260]; \ + expect_eq(!WideCharToMultiByte(CP_UTF8, 0, (expr), -1, buf, 260, NULL, NULL), 0, int, "%d"); \ + ok(lstrcmp(value, buf) == 0, #expr " expected \"%s\" got \"%s\"\n", value, buf); \ + } + +#define ole_expect(expr, expect) { \ + HRESULT r = expr; \ + ok(r == (expect), #expr " returned %x, expected %s (%x)\n", r, #expect, expect); \ +} + +#define ole_check(expr) ole_expect(expr, S_OK); + #define ok_ole_success(hr, func) ok(hr == S_OK, #func " failed with error 0x%08x\n", hr) static const WCHAR wszStdOle2[] = {'s','t','d','o','l','e','2','.','t','l','b',0}; @@ -826,6 +845,433 @@ if(use_midl_tlb) { return; } +#if 0 /* use this to generate more tests */ + +#define OLE_CHECK(x) { HRESULT hr = x; if (FAILED(hr)) { printf(#x "failed - %x\n", hr); return; } } + +char *dump_string(LPWSTR wstr) +{ + int size = lstrlenW(wstr)+3; + char *out = CoTaskMemAlloc(size); + WideCharToMultiByte(20127, 0, wstr, -1, out+1, size, NULL, NULL); + out[0] = '\"'; + strcat(out, "\""); + return out; +} + +struct map_entry +{ + DWORD value; + const char *name; +}; + +#define MAP_ENTRY(x) { x, #x } +struct map_entry tkind_map[] = { + MAP_ENTRY(TKIND_ENUM), + MAP_ENTRY(TKIND_RECORD), + MAP_ENTRY(TKIND_MODULE), + MAP_ENTRY(TKIND_INTERFACE), + MAP_ENTRY(TKIND_DISPATCH), + MAP_ENTRY(TKIND_COCLASS), + MAP_ENTRY(TKIND_ALIAS), + MAP_ENTRY(TKIND_UNION), + MAP_ENTRY(TKIND_MAX), + {0, NULL} +}; + +struct map_entry funckind_map[] = { + MAP_ENTRY(FUNC_VIRTUAL), + MAP_ENTRY(FUNC_PUREVIRTUAL), + MAP_ENTRY(FUNC_NONVIRTUAL), + MAP_ENTRY(FUNC_STATIC), + MAP_ENTRY(FUNC_DISPATCH), + {0, NULL} +}; + +struct map_entry invkind_map[] = { + MAP_ENTRY(INVOKE_FUNC), + MAP_ENTRY(INVOKE_PROPERTYGET), + MAP_ENTRY(INVOKE_PROPERTYPUT), + MAP_ENTRY(INVOKE_PROPERTYPUTREF), + {0, NULL} +}; + +#undef MAP_ENTRY + +const char *map_value(DWORD val, struct map_entry *map) +{ + static int map_id; + static char bufs[16][256]; + char *buf; + + while (map->name) + { + if (map->value == val) + return map->name; + map++; + } + + buf = bufs[(map_id++)%16]; + sprintf(buf, "0x%x", val); + return buf; +} + +void test_dump_typelib(const char *name) +{ + WCHAR wszString[260]; + ITypeInfo *info; + ITypeLib *lib; + int count; + int i; + + MultiByteToWideChar(CP_ACP, 0, name, -1, wszString, 260); + OLE_CHECK(LoadTypeLib(wszString, &lib)); + count = ITypeLib_GetTypeInfoCount(lib); + printf("/* interfaces count: %d */\n", count); + for (i = 0; i < count; i++) + { + TYPEATTR *attr; + BSTR name; + int f = 0; + + OLE_CHECK(ITypeLib_GetDocumentation(lib, i, &name, NULL, NULL, NULL)); + printf("{\n" + " %s,\n", dump_string(name)); + SysFreeString(name); + + OLE_CHECK(ITypeLib_GetTypeInfo(lib, i, &info)); + ITypeInfo_GetTypeAttr(info, &attr); + printf(" /*kind*/ %s, /*flags*/ 0x%x, /*align*/ %d, /*size*/ %d,\n" + " /*#vtbl*/ %d, /*#func*/ %d,\n" + " {\n", + map_value(attr->typekind, tkind_map), attr->wTypeFlags, attr->cbAlignment, attr->cbSizeInstance, attr->cbSizeVft, + attr->cFuncs); + ITypeInfo_ReleaseTypeAttr(info, attr); + while (1) + { + FUNCDESC *desc; + BSTR tab[256]; + UINT cNames; + int p; + + if (FAILED(ITypeInfo_GetFuncDesc(info, f, &desc))) + break; + printf(" {\n" + " 0x%x, /*func*/ %s, /*inv*/ %s, /*call*/ 0x%x,\n", + desc->memid, map_value(desc->funckind, funckind_map), map_value(desc->invkind, invkind_map), + desc->callconv); + printf(" /*#param*/ %d, /*#opt*/ %d, /*vtbl*/ %d, /*#scodes*/ %d, /*flags*/ 0x%x,\n", + desc->cParams, desc->cParamsOpt, desc->oVft, desc->cScodes, desc->wFuncFlags); + printf(" {%d, %x}, /* ret */\n", desc->elemdescFunc.tdesc.vt, desc->elemdescFunc.paramdesc.wParamFlags); + printf(" { /* params */\n"); + for (p = 0; p < desc->cParams; p++) + { + ELEMDESC e = desc->lprgelemdescParam[p]; + printf(" {%d, %x},\n", e.tdesc.vt, e.paramdesc.wParamFlags); + } + printf(" {-1, -1}\n"); + printf(" },\n"); + printf(" { /* names */\n"); + OLE_CHECK(ITypeInfo_GetNames(info, desc->memid, tab, 256, &cNames)); + for (p = 0; p < cNames; p++) + { + printf(" %s,\n", dump_string(tab[p])); + SysFreeString(tab[p]); + } + printf(" NULL,\n"); + printf(" },\n"); + printf(" },\n"); + ITypeInfo_ReleaseFuncDesc(info, desc); + f++; + } + printf(" }\n"); + printf("},\n"); + ITypeInfo_Release(info); + } + ITypeLib_Release(lib); +} + +#else + +typedef struct _element_info +{ + VARTYPE vt; + USHORT wParamFlags; +} element_info; + +typedef struct _function_info +{ + MEMBERID memid; + FUNCKIND funckind; + INVOKEKIND invkind; + CALLCONV callconv; + short cParams; + short cParamsOpt; + short oVft; + short cScodes; + WORD wFuncFlags; + element_info ret_type; + element_info params[15]; + LPCSTR names[15]; +} function_info; + +typedef struct _interface_info +{ + LPCSTR name; + TYPEKIND type; + WORD wTypeFlags; + USHORT cbAlignment; + USHORT cbSizeInstance; + USHORT cbSizeVft; + USHORT cFuncs; + function_info funcs[20]; +} interface_info; + +interface_info info[] = { +/* interfaces count: 2 */ +{ + "IDualIface", + /*kind*/ TKIND_DISPATCH, /*flags*/ 0x1040, /*align*/ 4, /*size*/ 4, + /*#vtbl*/ 28, /*#func*/ 8, + { + { + 0x60000000, /*func*/ FUNC_DISPATCH, /*inv*/ INVOKE_FUNC, /*call*/ 0x4, + /*#param*/ 2, /*#opt*/ 0, /*vtbl*/ 0, /*#scodes*/ 0, /*flags*/ 0x1, + {24, 0}, /* ret */ + { /* params */ + {26, 1}, + {26, 2}, + {-1, -1} + }, + { /* names */ + "QueryInterface", + "riid", + "ppvObj", + NULL, + }, + }, + { + 0x60000001, /*func*/ FUNC_DISPATCH, /*inv*/ INVOKE_FUNC, /*call*/ 0x4, + /*#param*/ 0, /*#opt*/ 0, /*vtbl*/ 4, /*#scodes*/ 0, /*flags*/ 0x1, + {19, 0}, /* ret */ + { /* params */ + {-1, -1} + }, + { /* names */ + "AddRef", + NULL, + }, + }, + { + 0x60000002, /*func*/ FUNC_DISPATCH, /*inv*/ INVOKE_FUNC, /*call*/ 0x4, + /*#param*/ 0, /*#opt*/ 0, /*vtbl*/ 8, /*#scodes*/ 0, /*flags*/ 0x1, + {19, 0}, /* ret */ + { /* params */ + {-1, -1} + }, + { /* names */ + "Release", + NULL, + }, + }, + { + 0x60010000, /*func*/ FUNC_DISPATCH, /*inv*/ INVOKE_FUNC, /*call*/ 0x4, + /*#param*/ 1, /*#opt*/ 0, /*vtbl*/ 12, /*#scodes*/ 0, /*flags*/ 0x1, + {24, 0}, /* ret */ + { /* params */ + {26, 2}, + {-1, -1} + }, + { /* names */ + "GetTypeInfoCount", + "pctinfo", + NULL, + }, + }, + { + 0x60010001, /*func*/ FUNC_DISPATCH, /*inv*/ INVOKE_FUNC, /*call*/ 0x4, + /*#param*/ 3, /*#opt*/ 0, /*vtbl*/ 16, /*#scodes*/ 0, /*flags*/ 0x1, + {24, 0}, /* ret */ + { /* params */ + {23, 1}, + {19, 1}, + {26, 2}, + {-1, -1} + }, + { /* names */ + "GetTypeInfo", + "itinfo", + "lcid", + "pptinfo", + NULL, + }, + }, + { + 0x60010002, /*func*/ FUNC_DISPATCH, /*inv*/ INVOKE_FUNC, /*call*/ 0x4, + /*#param*/ 5, /*#opt*/ 0, /*vtbl*/ 20, /*#scodes*/ 0, /*flags*/ 0x1, + {24, 0}, /* ret */ + { /* params */ + {26, 1}, + {26, 1}, + {23, 1}, + {19, 1}, + {26, 2}, + {-1, -1} + }, + { /* names */ + "GetIDsOfNames", + "riid", + "rgszNames", + "cNames", + "lcid", + "rgdispid", + NULL, + }, + }, + { + 0x60010003, /*func*/ FUNC_DISPATCH, /*inv*/ INVOKE_FUNC, /*call*/ 0x4, + /*#param*/ 8, /*#opt*/ 0, /*vtbl*/ 24, /*#scodes*/ 0, /*flags*/ 0x1, + {24, 0}, /* ret */ + { /* params */ + {3, 1}, + {26, 1}, + {19, 1}, + {18, 1}, + {26, 1}, + {26, 2}, + {26, 2}, + {26, 2}, + {-1, -1} + }, + { /* names */ + "Invoke", + "dispidMember", + "riid", + "lcid", + "wFlags", + "pdispparams", + "pvarResult", + "pexcepinfo", + "puArgErr", + NULL, + }, + }, + { + 0x60020000, /*func*/ FUNC_DISPATCH, /*inv*/ INVOKE_FUNC, /*call*/ 0x4, + /*#param*/ 0, /*#opt*/ 0, /*vtbl*/ 28, /*#scodes*/ 0, /*flags*/ 0x0, + {24, 0}, /* ret */ + { /* params */ + {-1, -1} + }, + { /* names */ + "Test", + NULL, + }, + }, + } +}, +{ + "ISimpleIface", + /*kind*/ TKIND_INTERFACE, /*flags*/ 0x1000, /*align*/ 4, /*size*/ 4, + /*#vtbl*/ 32, /*#func*/ 1, + { + { + 0x60020000, /*func*/ FUNC_PUREVIRTUAL, /*inv*/ INVOKE_FUNC, /*call*/ 0x4, + /*#param*/ 0, /*#opt*/ 0, /*vtbl*/ 28, /*#scodes*/ 0, /*flags*/ 0x0, + {25, 0}, /* ret */ + { /* params */ + {-1, -1} + }, + { /* names */ + "Test", + NULL, + }, + }, + } +}, +}; + +#define check_type(elem, info) { \ + expect_int((elem)->tdesc.vt, (info)->vt); \ + expect_hex((elem)->paramdesc.wParamFlags, (info)->wParamFlags); \ + } + +void test_dump_typelib(const char *name) +{ + WCHAR wszName[MAX_PATH]; + ITypeLib *typelib; + int ifcount = sizeof(info)/sizeof(info[0]); + int iface, func; + + MultiByteToWideChar(CP_UTF8, 0, name, -1, wszName, MAX_PATH); + ole_check(LoadTypeLibEx(wszName, REGKIND_NONE, &typelib)); + expect_eq(ITypeLib_GetTypeInfoCount(typelib), ifcount, UINT, "%d"); + for (iface = 0; iface < ifcount; iface++) + { + interface_info *if_info = &info[iface]; + ITypeInfo *typeinfo; + TYPEATTR *typeattr; + BSTR bstrIfName; + + trace("Interface %s\n", if_info->name); + ole_check(ITypeLib_GetTypeInfo(typelib, iface, &typeinfo)); + ole_check(ITypeLib_GetDocumentation(typelib, iface, &bstrIfName, NULL, NULL, NULL)); + expect_wstr_utf8val(bstrIfName, if_info->name); + SysFreeString(bstrIfName); + + ole_check(ITypeInfo_GetTypeAttr(typeinfo, &typeattr)); + expect_int(typeattr->typekind, if_info->type); + expect_hex(typeattr->wTypeFlags, if_info->wTypeFlags); + expect_int(typeattr->cbAlignment, if_info->cbAlignment); + expect_int(typeattr->cbSizeInstance, if_info->cbSizeInstance); + expect_int(typeattr->cbSizeVft, if_info->cbSizeVft); + expect_int(typeattr->cFuncs, if_info->cFuncs); + + for (func = 0; func < typeattr->cFuncs; func++) + { + function_info *fn_info = (function_info *)&if_info->funcs[func]; + FUNCDESC *desc; + BSTR namesTab[256]; + UINT cNames; + int i; + + trace("Function %s\n", fn_info->names[0]); + ole_check(ITypeInfo_GetFuncDesc(typeinfo, func, &desc)); + expect_int(desc->memid, fn_info->memid); + expect_int(desc->funckind, fn_info->funckind); + expect_int(desc->invkind, fn_info->invkind); + expect_int(desc->callconv, fn_info->callconv); + expect_int(desc->cParams, fn_info->cParams); + expect_int(desc->cParamsOpt, fn_info->cParamsOpt); + expect_int(desc->oVft, fn_info->oVft); + expect_int(desc->cScodes, fn_info->cScodes); + expect_int(desc->wFuncFlags, fn_info->wFuncFlags); + ole_check(ITypeInfo_GetNames(typeinfo, desc->memid, namesTab, 256, &cNames)); + for (i = 0; i < cNames; i++) + { + expect_wstr_utf8val(namesTab[i], fn_info->names[i]); + SysFreeString(namesTab[i]); + } + expect_null(fn_info->names[cNames]); + + check_type(&desc->elemdescFunc, &fn_info->ret_type); + for (i = 0 ; i < desc->cParams; i++) + { + check_type(&desc->lprgelemdescParam[i], &fn_info->params[i]); + } + expect_int(fn_info->params[desc->cParams].vt, (VARTYPE)-1); + + ITypeInfo_ReleaseFuncDesc(typeinfo, desc); + } + + ITypeInfo_ReleaseTypeAttr(typeinfo, typeattr); + ITypeInfo_Release(typeinfo); + } + ITypeLib_Release(typelib); +} + +#endif + START_TEST(typelib) { ref_count_test(wszStdOle2); @@ -834,4 +1280,5 @@ START_TEST(typelib) test_TypeInfo(); test_QueryPathOfRegTypeLib(); test_inheritance(); + test_dump_typelib("test_tlb.tlb"); } diff --git a/dlls/oleaut32/typelib.c b/dlls/oleaut32/typelib.c index bf8673d..16e5a6f 100644 --- a/dlls/oleaut32/typelib.c +++ b/dlls/oleaut32/typelib.c @@ -4674,6 +4674,8 @@ static HRESULT TLB_AllocAndInitFuncDesc( if (!dest) return E_OUTOFMEMORY; memcpy(dest, src, sizeof(FUNCDESC)); + if (dispinterface) /* overwrite funckind */ + dest->funckind = FUNC_DISPATCH; buffer = (char *)(dest + 1); dest->lprgscode = (SCODE *)buffer; -- 1.4.1