[PATCH 0/2] MR10856: oleaut32: Don't include IDispatch slots in stored cbSizeVft for TKIND_DISPATCH.
ICreateTypeInfo2_fnLayOut starts cbSizeVft at 7*ptr_size for TKIND_DISPATCH to position own funcs after the IDispatch vtbl, then increments per added func. The own funcs receive correct oVft offsets that way, but the resulting stored cbSizeVft is too large by exactly the IDispatch vtbl size: GetTypeAttr later derives cFuncs as cbSizeVft/ptr_size and so reports own_count + 7 instead of own_count. Subtract the prefix at the end of LayOut so cFuncs matches native, both in-memory and after SaveAllChanges + LoadTypeLibEx. Public cbSizeVft is unchanged: GetTypeAttr already overrides it to sizeof(IDispatchVtbl). -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10856
From: Francis De Brabandere <francisdb@gmail.com> A typeinfo built with ICreateTypeLib2 + AddImplType(IDispatch) reports cFuncs reflecting only the funcs added directly: the inherited IDispatch slots are not included, even though cImplTypes == 1. The same numbers hold after SaveAllChanges + LoadTypeLibEx. Mark these as todo_wine until LayOut is fixed to stop adding the IDispatch vtbl size to the stored cbSizeVft. --- dlls/oleaut32/tests/typelib.c | 100 ++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/dlls/oleaut32/tests/typelib.c b/dlls/oleaut32/tests/typelib.c index 153964e17d5..091defda68d 100644 --- a/dlls/oleaut32/tests/typelib.c +++ b/dlls/oleaut32/tests/typelib.c @@ -8763,6 +8763,105 @@ static void test_DeleteFuncDesc(void) DeleteFileW(filenameW); } +/* TKIND_DISPATCH built via ICreateTypeLib2 with an explicit + * AddImplType(IDispatch) - both in-memory and after Save+Reload. cFuncs + * should reflect only own funcs (the inherited IDispatch slots aren't + * counted), even though cImplTypes==1. */ +static void test_dispatch_with_implparent(void) +{ + OLECHAR ifaceW[] = L"iface"; + OLECHAR funcW[] = L"func"; + OLECHAR *funcnames[] = { funcW }; + WCHAR filenameW[MAX_PATH], temp_path[MAX_PATH]; + ICreateTypeInfo *createti; + ICreateTypeLib2 *createtl; + ITypeInfo *idispatch_ti, *parent_ti, *ti; + ITypeLib *stdole, *tl; + FUNCDESC funcdesc; + TYPEATTR *typeattr; + HREFTYPE href; + HRESULT hr; + + GetTempPathW(ARRAY_SIZE(temp_path), temp_path); + GetTempFileNameW(temp_path, L"tlb", 0, filenameW); + + hr = LoadTypeLib(wszStdOle2, &stdole); + ok(hr == S_OK, "got %#lx\n", hr); + hr = ITypeLib_GetTypeInfoOfGuid(stdole, &IID_IDispatch, &idispatch_ti); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = CreateTypeLib2(SYS_WIN64, filenameW, &createtl); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = ICreateTypeLib2_CreateTypeInfo(createtl, ifaceW, TKIND_DISPATCH, &createti); + ok(hr == S_OK, "got %#lx\n", hr); + hr = ICreateTypeInfo_SetTypeFlags(createti, TYPEFLAG_FDISPATCHABLE); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = ICreateTypeInfo_AddRefTypeInfo(createti, idispatch_ti, &href); + ok(hr == S_OK, "got %#lx\n", hr); + hr = ICreateTypeInfo_AddImplType(createti, 0, href); + ok(hr == S_OK, "got %#lx\n", hr); + + memset(&funcdesc, 0, sizeof(funcdesc)); + funcdesc.memid = 0x100; + funcdesc.funckind = FUNC_DISPATCH; + funcdesc.invkind = INVOKE_FUNC; + funcdesc.callconv = CC_STDCALL; + funcdesc.elemdescFunc.tdesc.vt = VT_VOID; + hr = ICreateTypeInfo_AddFuncDesc(createti, 0, &funcdesc); + ok(hr == S_OK, "got %#lx\n", hr); + hr = ICreateTypeInfo_SetFuncAndParamNames(createti, 0, funcnames, 1); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = ICreateTypeInfo_LayOut(createti); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = ICreateTypeInfo_QueryInterface(createti, &IID_ITypeInfo, (void **)&ti); + ok(hr == S_OK, "got %#lx\n", hr); + hr = ITypeInfo_GetTypeAttr(ti, &typeattr); + ok(hr == S_OK, "got %#lx\n", hr); + ok(typeattr->typekind == TKIND_DISPATCH, "typekind %d\n", typeattr->typekind); + todo_wine + ok(typeattr->cFuncs == 1, "in-memory cFuncs %u\n", typeattr->cFuncs); + ok(typeattr->cImplTypes == 1, "in-memory cImplTypes %u\n", typeattr->cImplTypes); + ok(typeattr->cbSizeVft == sizeof(IDispatchVtbl), "in-memory cbSizeVft %u\n", typeattr->cbSizeVft); + ITypeInfo_ReleaseTypeAttr(ti, typeattr); + ITypeInfo_Release(ti); + + hr = ICreateTypeLib2_SaveAllChanges(createtl); + ok(hr == S_OK, "got %#lx\n", hr); + ICreateTypeInfo_Release(createti); + ICreateTypeLib2_Release(createtl); + ITypeInfo_Release(idispatch_ti); + ITypeLib_Release(stdole); + + hr = LoadTypeLibEx(filenameW, REGKIND_NONE, &tl); + ok(hr == S_OK, "got %#lx\n", hr); + hr = ITypeLib_GetTypeInfo(tl, 0, &ti); + ok(hr == S_OK, "got %#lx\n", hr); + hr = ITypeInfo_GetTypeAttr(ti, &typeattr); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine + ok(typeattr->cFuncs == 1, "reloaded cFuncs %u\n", typeattr->cFuncs); + ok(typeattr->cImplTypes == 1, "reloaded cImplTypes %u\n", typeattr->cImplTypes); + ITypeInfo_ReleaseTypeAttr(ti, typeattr); + + hr = ITypeInfo_GetRefTypeOfImplType(ti, 0, &href); + ok(hr == S_OK, "got %#lx\n", hr); + hr = ITypeInfo_GetRefTypeInfo(ti, href, &parent_ti); + ok(hr == S_OK, "got %#lx\n", hr); + hr = ITypeInfo_GetTypeAttr(parent_ti, &typeattr); + ok(hr == S_OK, "got %#lx\n", hr); + ok(IsEqualGUID(&typeattr->guid, &IID_IDispatch), "parent guid %s\n", wine_dbgstr_guid(&typeattr->guid)); + ITypeInfo_ReleaseTypeAttr(parent_ti, typeattr); + ITypeInfo_Release(parent_ti); + + ITypeInfo_Release(ti); + ITypeLib_Release(tl); + DeleteFileW(filenameW); +} + START_TEST(typelib) { const WCHAR *filename; @@ -8806,4 +8905,5 @@ START_TEST(typelib) test_stub(); test_DeleteImplType(); test_DeleteFuncDesc(); + test_dispatch_with_implparent(); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10856
From: Francis De Brabandere <francisdb@gmail.com> ICreateTypeInfo2_fnLayOut starts cbSizeVft at 7*ptr_size for TKIND_DISPATCH to position own funcs after the IDispatch vtbl, then increments per added func. The own funcs receive correct oVft offsets that way, but the resulting stored cbSizeVft is too large by exactly the IDispatch vtbl size: GetTypeAttr later derives cFuncs as cbSizeVft/ptr_size and so reports own_count + 7 instead of own_count. Subtract the prefix at the end of LayOut so cFuncs matches native, both in-memory and after SaveAllChanges + LoadTypeLibEx. Public cbSizeVft is unchanged: GetTypeAttr already overrides it to sizeof(IDispatchVtbl). --- dlls/oleaut32/tests/typelib.c | 2 -- dlls/oleaut32/typelib.c | 9 +++++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/dlls/oleaut32/tests/typelib.c b/dlls/oleaut32/tests/typelib.c index 091defda68d..7010b879582 100644 --- a/dlls/oleaut32/tests/typelib.c +++ b/dlls/oleaut32/tests/typelib.c @@ -8822,7 +8822,6 @@ static void test_dispatch_with_implparent(void) hr = ITypeInfo_GetTypeAttr(ti, &typeattr); ok(hr == S_OK, "got %#lx\n", hr); ok(typeattr->typekind == TKIND_DISPATCH, "typekind %d\n", typeattr->typekind); - todo_wine ok(typeattr->cFuncs == 1, "in-memory cFuncs %u\n", typeattr->cFuncs); ok(typeattr->cImplTypes == 1, "in-memory cImplTypes %u\n", typeattr->cImplTypes); ok(typeattr->cbSizeVft == sizeof(IDispatchVtbl), "in-memory cbSizeVft %u\n", typeattr->cbSizeVft); @@ -8842,7 +8841,6 @@ static void test_dispatch_with_implparent(void) ok(hr == S_OK, "got %#lx\n", hr); hr = ITypeInfo_GetTypeAttr(ti, &typeattr); ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(typeattr->cFuncs == 1, "reloaded cFuncs %u\n", typeattr->cFuncs); ok(typeattr->cImplTypes == 1, "reloaded cImplTypes %u\n", typeattr->cImplTypes); ITypeInfo_ReleaseTypeAttr(ti, typeattr); diff --git a/dlls/oleaut32/typelib.c b/dlls/oleaut32/typelib.c index e9997a86d24..d604ccc0fd8 100644 --- a/dlls/oleaut32/typelib.c +++ b/dlls/oleaut32/typelib.c @@ -11193,6 +11193,15 @@ static HRESULT WINAPI ICreateTypeInfo2_fnLayOut(ICreateTypeInfo2 *iface) if (user_vft > This->typeattr.cbSizeVft) This->typeattr.cbSizeVft = user_vft + This->pTypeLib->ptr_size; + /* For TKIND_DISPATCH, the IDispatch vtbl slots are not part of the + * stored cbSizeVft on native ICreateTypeLib2 typelibs - GetTypeAttr + * later overrides cbSizeVft to sizeof(IDispatchVtbl) for the public + * API regardless. Subtract the prefix here so that GetTypeAttr's + * `cFuncs = cbSizeVft / ptr_size` derivation yields the own-func + * count (matching native), without changing oVft assignments. */ + if (This->typeattr.typekind == TKIND_DISPATCH) + This->typeattr.cbSizeVft -= 7 * This->pTypeLib->ptr_size; + for(i = 0; i < This->typeattr.cVars; ++i){ TLBVarDesc *var_desc = &This->vardescs[i]; if(var_desc->vardesc.memid == MEMBERID_NIL){ -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10856
This merge request was closed by Francis De Brabandere. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10856
Closed as requested by reviewer, no native-parity fixes without app evidence. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10856#note_139677
participants (2)
-
Francis De Brabandere -
Francis De Brabandere (@francisdb)