[PATCH v2 0/1] MR10461: Draft: vbscript: Implement IDispatch::GetTypeInfo for class instances.
Implement GetTypeInfo on vbdisp_t (VBScript class instances) by returning a lightweight ITypeInfo that reports the class name via GetDocumentation(MEMBERID_NIL). This makes TypeName() return the actual class name (e.g. "MyClass") instead of falling back to "Object". This is partially based on previous work by @jsm174 at https://github.com/jsm174/libwinevbs/blob/fbc4d2a17a2da8196d50805f7ae289406c... -- v2: vbscript: Implement IDispatch::GetTypeInfo for class instances. https://gitlab.winehq.org/wine/wine/-/merge_requests/10461
From: Francis De Brabandere <francisdb@gmail.com> Implement GetTypeInfo on vbdisp_t (VBScript class instances) by returning a lightweight ITypeInfo that reports the class name via GetDocumentation(MEMBERID_NIL). This makes TypeName() return the actual class name (e.g. "MyClass") instead of falling back to "Object". --- dlls/vbscript/tests/api.vbs | 11 + dlls/vbscript/tests/vbscript.c | 155 ++++++++++ dlls/vbscript/vbdisp.c | 524 ++++++++++++++++++++++++++++++++- 3 files changed, 688 insertions(+), 2 deletions(-) diff --git a/dlls/vbscript/tests/api.vbs b/dlls/vbscript/tests/api.vbs index e18d887306b..d989ba8a332 100644 --- a/dlls/vbscript/tests/api.vbs +++ b/dlls/vbscript/tests/api.vbs @@ -1711,6 +1711,17 @@ Dim regex set regex = new RegExp Call ok(TypeName(regex) = "IRegExp2", "TypeName(regex) = " & TypeName(regex)) +' TypeName for VBScript class instances +Dim emptyClsObj +Set emptyClsObj = New EmptyClass +Call ok(TypeName(emptyClsObj) = "EmptyClass", "TypeName(EmptyClass) = " & TypeName(emptyClsObj)) +Call ok(getVT(TypeName(emptyClsObj)) = "VT_BSTR", "getVT(TypeName(EmptyClass)) = " & getVT(TypeName(emptyClsObj))) +Dim valClsObj +Set valClsObj = New ValClass +Call ok(TypeName(valClsObj) = "ValClass", "TypeName(ValClass) = " & TypeName(valClsObj)) +Set emptyClsObj = Nothing +Call ok(TypeName(emptyClsObj) = "Nothing", "TypeName after Set Nothing = " & TypeName(emptyClsObj)) + Call ok(VarType(Empty) = vbEmpty, "VarType(Empty) = " & VarType(Empty)) Call ok(getVT(VarType(Empty)) = "VT_I2", "getVT(VarType(Empty)) = " & getVT(VarType(Empty))) Call ok(VarType(Null) = vbNull, "VarType(Null) = " & VarType(Null)) diff --git a/dlls/vbscript/tests/vbscript.c b/dlls/vbscript/tests/vbscript.c index adda087ce76..7bbb49eb86a 100644 --- a/dlls/vbscript/tests/vbscript.c +++ b/dlls/vbscript/tests/vbscript.c @@ -1468,6 +1468,161 @@ static void test_script_typeinfo(void) ITypeInfo_ReleaseFuncDesc(typeinfo2, funcdesc); ITypeInfo_Release(typeinfo2); + /* Tests for vbdisp (class instance) ITypeInfo, using 'obj' which is 'new C' with: + dim x (public), public sub method, private function strret */ + { + IDispatchEx *obj_disp; + ITypeInfo *obj_typeinfo, *obj_typeinfo2; + DISPPARAMS dp = { 0 }; + VARIANT var_result; + DISPID dispid; + + wcscpy(str, L"obj"); + hr = IDispatchEx_GetDispID(script_disp, str, 0, &dispid); + ok(hr == S_OK, "GetDispID(obj) failed: %08lx\n", hr); + V_VT(&var_result) = VT_EMPTY; + hr = IDispatchEx_InvokeEx(script_disp, dispid, LOCALE_USER_DEFAULT, + DISPATCH_PROPERTYGET, &dp, &var_result, NULL, NULL); + ok(hr == S_OK, "InvokeEx(obj) failed: %08lx\n", hr); + ok(V_VT(&var_result) == VT_DISPATCH, "Unexpected vt %d\n", V_VT(&var_result)); + hr = IDispatch_QueryInterface(V_DISPATCH(&var_result), &IID_IDispatchEx, (void**)&obj_disp); + ok(hr == S_OK, "QI(IDispatchEx) failed: %08lx\n", hr); + VariantClear(&var_result); + + /* GetTypeInfoCount */ + hr = IDispatchEx_GetTypeInfoCount(obj_disp, &count); + ok(hr == S_OK, "GetTypeInfoCount failed: %08lx\n", hr); + ok(count == 1, "Unexpected count %u\n", count); + + /* GetTypeInfo with bad index */ + hr = IDispatchEx_GetTypeInfo(obj_disp, 1, LOCALE_USER_DEFAULT, &obj_typeinfo); + ok(hr == DISP_E_BADINDEX, "GetTypeInfo(1) returned: %08lx\n", hr); + + /* GetTypeInfo returns a new instance each time */ + hr = IDispatchEx_GetTypeInfo(obj_disp, 0, LOCALE_USER_DEFAULT, &obj_typeinfo); + ok(hr == S_OK, "GetTypeInfo failed: %08lx\n", hr); + hr = IDispatchEx_GetTypeInfo(obj_disp, 0, LOCALE_USER_DEFAULT, &obj_typeinfo2); + ok(hr == S_OK, "GetTypeInfo failed: %08lx\n", hr); + ok(obj_typeinfo != obj_typeinfo2, "TypeInfo was not supposed to be shared.\n"); + ITypeInfo_Release(obj_typeinfo2); + + /* GetDocumentation(MEMBERID_NIL) returns the class name */ + hr = ITypeInfo_GetDocumentation(obj_typeinfo, MEMBERID_NIL, &bstr, NULL, NULL, NULL); + ok(hr == S_OK, "GetDocumentation(MEMBERID_NIL) failed: %08lx\n", hr); + ok(!lstrcmpW(bstr, L"C"), "Unexpected class name %s\n", wine_dbgstr_w(bstr)); + SysFreeString(bstr); + + /* GetTypeAttr: class C has 1 public func (method) and 1 public var (x) */ + hr = ITypeInfo_GetTypeAttr(obj_typeinfo, &attr); + ok(hr == S_OK, "GetTypeAttr failed: %08lx\n", hr); + ok(attr->typekind == TKIND_DISPATCH, "Unexpected typekind %u\n", attr->typekind); + ok(attr->cFuncs == 1, "Unexpected cFuncs %u\n", attr->cFuncs); + ok(attr->cVars == 1, "Unexpected cVars %u\n", attr->cVars); + ok(attr->cImplTypes == 1, "Unexpected cImplTypes %u\n", attr->cImplTypes); + ok(attr->wTypeFlags == TYPEFLAG_FDISPATCHABLE, "Unexpected wTypeFlags 0x%x\n", attr->wTypeFlags); + ITypeInfo_ReleaseTypeAttr(obj_typeinfo, attr); + + /* GetFuncDesc for the public sub 'method' (index 0) */ + hr = ITypeInfo_GetFuncDesc(obj_typeinfo, 0, &funcdesc); + ok(hr == S_OK, "GetFuncDesc(0) failed: %08lx\n", hr); + ok(funcdesc->funckind == FUNC_DISPATCH, "Unexpected funckind %u\n", funcdesc->funckind); + ok(funcdesc->invkind == INVOKE_FUNC, "Unexpected invkind %u\n", funcdesc->invkind); + ok(funcdesc->cParams == 0, "Unexpected cParams %d\n", funcdesc->cParams); + ok(funcdesc->elemdescFunc.tdesc.vt == VT_VOID, "Unexpected ret vt %d\n", funcdesc->elemdescFunc.tdesc.vt); + hr = ITypeInfo_GetDocumentation(obj_typeinfo, funcdesc->memid, &bstr, NULL, NULL, NULL); + ok(hr == S_OK, "GetDocumentation failed: %08lx\n", hr); + ok(!lstrcmpW(bstr, L"method"), "Unexpected func name %s\n", wine_dbgstr_w(bstr)); + SysFreeString(bstr); + ITypeInfo_ReleaseFuncDesc(obj_typeinfo, funcdesc); + + /* Out of range func */ + hr = ITypeInfo_GetFuncDesc(obj_typeinfo, 1, &funcdesc); + ok(hr == TYPE_E_ELEMENTNOTFOUND, "GetFuncDesc(1) returned: %08lx\n", hr); + + /* GetVarDesc for the public dim 'x' (index 0) */ + hr = ITypeInfo_GetVarDesc(obj_typeinfo, 0, &vardesc); + ok(hr == S_OK, "GetVarDesc(0) failed: %08lx\n", hr); + ok(vardesc->varkind == VAR_DISPATCH, "Unexpected varkind %u\n", vardesc->varkind); + ok(vardesc->elemdescVar.tdesc.vt == VT_VARIANT, "Unexpected var vt %d\n", vardesc->elemdescVar.tdesc.vt); + hr = ITypeInfo_GetDocumentation(obj_typeinfo, vardesc->memid, &bstr, NULL, NULL, NULL); + ok(hr == S_OK, "GetDocumentation failed: %08lx\n", hr); + ok(!lstrcmpW(bstr, L"x"), "Unexpected var name %s\n", wine_dbgstr_w(bstr)); + SysFreeString(bstr); + ITypeInfo_ReleaseVarDesc(obj_typeinfo, vardesc); + + /* Out of range var */ + hr = ITypeInfo_GetVarDesc(obj_typeinfo, 1, &vardesc); + ok(hr == TYPE_E_ELEMENTNOTFOUND, "GetVarDesc(1) returned: %08lx\n", hr); + + /* GetIDsOfNames */ + wcscpy(str, L"method"); + hr = ITypeInfo_GetIDsOfNames(obj_typeinfo, &names, 1, &memid); + ok(hr == S_OK, "GetIDsOfNames(method) failed: %08lx\n", hr); + wcscpy(str, L"x"); + hr = ITypeInfo_GetIDsOfNames(obj_typeinfo, &names, 1, &memid); + ok(hr == S_OK, "GetIDsOfNames(x) failed: %08lx\n", hr); + wcscpy(str, L"strret"); + hr = ITypeInfo_GetIDsOfNames(obj_typeinfo, &names, 1, &memid); + ok(hr == DISP_E_UNKNOWNNAME, "GetIDsOfNames(strret) returned: %08lx\n", hr); + wcscpy(str, L"nonexistent"); + hr = ITypeInfo_GetIDsOfNames(obj_typeinfo, &names, 1, &memid); + ok(hr == DISP_E_UNKNOWNNAME, "GetIDsOfNames(nonexistent) returned: %08lx\n", hr); + + /* GetNames for 'method' */ + wcscpy(str, L"method"); + hr = ITypeInfo_GetIDsOfNames(obj_typeinfo, &names, 1, &memid); + ok(hr == S_OK, "GetIDsOfNames(method) failed: %08lx\n", hr); + hr = ITypeInfo_GetNames(obj_typeinfo, memid, bstrs, ARRAY_SIZE(bstrs), &count); + ok(hr == S_OK, "GetNames failed: %08lx\n", hr); + ok(count == 1, "Unexpected count %u\n", count); + ok(!lstrcmpW(bstrs[0], L"method"), "Unexpected name %s\n", wine_dbgstr_w(bstrs[0])); + SysFreeString(bstrs[0]); + + /* GetImplTypeFlags */ + hr = ITypeInfo_GetImplTypeFlags(obj_typeinfo, 0, &implTypeFlags); + ok(hr == S_OK, "GetImplTypeFlags failed: %08lx\n", hr); + ok(implTypeFlags == 0, "Unexpected implTypeFlags 0x%x\n", implTypeFlags); + hr = ITypeInfo_GetImplTypeFlags(obj_typeinfo, 1, &implTypeFlags); + ok(hr == TYPE_E_ELEMENTNOTFOUND, "GetImplTypeFlags(1) returned: %08lx\n", hr); + + /* GetRefTypeOfImplType */ + hr = ITypeInfo_GetRefTypeOfImplType(obj_typeinfo, 0, &reftype); + ok(hr == S_OK, "GetRefTypeOfImplType failed: %08lx\n", hr); + ok(reftype == 1, "Unexpected reftype %ld\n", reftype); + hr = ITypeInfo_GetRefTypeInfo(obj_typeinfo, reftype, &obj_typeinfo2); + ok(hr == S_OK, "GetRefTypeInfo failed: %08lx\n", hr); + hr = ITypeInfo_GetDocumentation(obj_typeinfo2, MEMBERID_NIL, &bstr, NULL, NULL, NULL); + ok(hr == S_OK, "GetDocumentation failed: %08lx\n", hr); + ok(!lstrcmpW(bstr, L"IDispatch"), "Unexpected TypeInfo name %s\n", wine_dbgstr_w(bstr)); + SysFreeString(bstr); + ITypeInfo_Release(obj_typeinfo2); + + /* GetMops */ + hr = ITypeInfo_GetMops(obj_typeinfo, MEMBERID_NIL, &bstr); + ok(hr == S_OK, "GetMops failed: %08lx\n", hr); + ok(!bstr, "Unexpected non-null string %s\n", wine_dbgstr_w(bstr)); + + /* CreateInstance / AddressOfMember / GetDllEntry always fail */ + obj = (void*)0xdeadbeef; + hr = ITypeInfo_CreateInstance(obj_typeinfo, NULL, NULL, &obj); + ok(hr == TYPE_E_BADMODULEKIND, "CreateInstance returned: %08lx\n", hr); + ok(!obj, "Unexpected non-null obj %p.\n", obj); + obj = (void*)0xdeadbeef; + wcscpy(str, L"method"); + hr = ITypeInfo_GetIDsOfNames(obj_typeinfo, &names, 1, &memid); + ok(hr == S_OK, "GetIDsOfNames failed: %08lx\n", hr); + hr = ITypeInfo_AddressOfMember(obj_typeinfo, memid, INVOKE_FUNC, &obj); + ok(hr == TYPE_E_BADMODULEKIND, "AddressOfMember returned: %08lx\n", hr); + ok(!obj, "Unexpected non-null obj %p.\n", obj); + bstr = (BSTR)0xdeadbeef; + hr = ITypeInfo_GetDllEntry(obj_typeinfo, memid, INVOKE_FUNC, &bstr, NULL, NULL); + ok(hr == TYPE_E_BADMODULEKIND, "GetDllEntry returned: %08lx\n", hr); + ok(!bstr, "Unexpected non-null str %p.\n", bstr); + + ITypeInfo_Release(obj_typeinfo); + IDispatchEx_Release(obj_disp); + } + ITypeInfo_Release(typeinfo); IDispatchEx_Release(script_disp); IActiveScriptParse_Release(parser); diff --git a/dlls/vbscript/vbdisp.c b/dlls/vbscript/vbdisp.c index db3059c7fca..33814a932a1 100644 --- a/dlls/vbscript/vbdisp.c +++ b/dlls/vbscript/vbdisp.c @@ -358,12 +358,532 @@ static HRESULT WINAPI DispatchEx_GetTypeInfoCount(IDispatchEx *iface, UINT *pcti return S_OK; } +typedef struct { + ITypeInfo ITypeInfo_iface; + LONG ref; + const class_desc_t *desc; + UINT num_funcs; + UINT num_vars; +} VBDispTypeInfo; + +static inline VBDispTypeInfo *VBDispTypeInfo_from_ITypeInfo(ITypeInfo *iface) +{ + return CONTAINING_RECORD(iface, VBDispTypeInfo, ITypeInfo_iface); +} + +static HRESULT WINAPI VBDispTypeInfo_QueryInterface(ITypeInfo *iface, REFIID riid, void **ppv) +{ + VBDispTypeInfo *This = VBDispTypeInfo_from_ITypeInfo(iface); + + if (IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_ITypeInfo, riid)) + *ppv = &This->ITypeInfo_iface; + else + { + WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv); + *ppv = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown *)*ppv); + return S_OK; +} + +static ULONG WINAPI VBDispTypeInfo_AddRef(ITypeInfo *iface) +{ + VBDispTypeInfo *This = VBDispTypeInfo_from_ITypeInfo(iface); + LONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p) ref=%ld\n", This, ref); + + return ref; +} + +static ULONG WINAPI VBDispTypeInfo_Release(ITypeInfo *iface) +{ + VBDispTypeInfo *This = VBDispTypeInfo_from_ITypeInfo(iface); + LONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p) ref=%ld\n", This, ref); + + if (!ref) + free(This); + + return ref; +} + +static HRESULT WINAPI VBDispTypeInfo_GetTypeAttr(ITypeInfo *iface, TYPEATTR **ppTypeAttr) +{ + VBDispTypeInfo *This = VBDispTypeInfo_from_ITypeInfo(iface); + TYPEATTR *attr; + + TRACE("(%p)->(%p)\n", This, ppTypeAttr); + + if (!ppTypeAttr) return E_INVALIDARG; + + attr = calloc(1, sizeof(*attr)); + if (!attr) return E_OUTOFMEMORY; + + attr->guid = GUID_VBScriptTypeInfo; + attr->lcid = LOCALE_USER_DEFAULT; + attr->memidConstructor = MEMBERID_NIL; + attr->memidDestructor = MEMBERID_NIL; + attr->cbSizeInstance = 4; + attr->typekind = TKIND_DISPATCH; + attr->cFuncs = This->num_funcs; + attr->cVars = This->num_vars; + attr->cImplTypes = 1; + attr->cbSizeVft = sizeof(IDispatchVtbl); + attr->cbAlignment = 4; + attr->wTypeFlags = TYPEFLAG_FDISPATCHABLE; + attr->wMajorVerNum = VBSCRIPT_MAJOR_VERSION; + attr->wMinorVerNum = VBSCRIPT_MINOR_VERSION; + + *ppTypeAttr = attr; + return S_OK; +} + +static HRESULT WINAPI VBDispTypeInfo_GetTypeComp(ITypeInfo *iface, ITypeComp **ppTComp) +{ + VBDispTypeInfo *This = VBDispTypeInfo_from_ITypeInfo(iface); + + FIXME("(%p)->(%p)\n", This, ppTComp); + + return E_NOTIMPL; +} + +static HRESULT WINAPI VBDispTypeInfo_GetFuncDesc(ITypeInfo *iface, UINT index, FUNCDESC **ppFuncDesc) +{ + VBDispTypeInfo *This = VBDispTypeInfo_from_ITypeInfo(iface); + const class_desc_t *desc = This->desc; + FUNCDESC *funcdesc; + function_t *func; + UINT i, n = 0; + + TRACE("(%p)->(%u %p)\n", This, index, ppFuncDesc); + + if (!ppFuncDesc) return E_INVALIDARG; + if (index >= This->num_funcs) return TYPE_E_ELEMENTNOTFOUND; + + /* Map index to the n-th public function */ + for (i = 0; i < desc->func_cnt; i++) + { + if (!desc->funcs[i].is_public || !desc->funcs[i].name) + continue; + if (n == index) + break; + n++; + } + + func = desc->funcs[i].entries[VBDISP_CALLGET]; + if (!func) + func = desc->funcs[i].entries[VBDISP_LET]; + if (!func) + func = desc->funcs[i].entries[VBDISP_SET]; + + funcdesc = calloc(1, sizeof(*funcdesc) + sizeof(ELEMDESC) * (func ? func->arg_cnt : 0)); + if (!funcdesc) return E_OUTOFMEMORY; + + funcdesc->memid = i; + funcdesc->funckind = FUNC_DISPATCH; + funcdesc->invkind = INVOKE_FUNC; + funcdesc->callconv = CC_STDCALL; + + if (func) + { + UINT j; + funcdesc->cParams = func->arg_cnt; + funcdesc->elemdescFunc.tdesc.vt = (func->type == FUNC_SUB) ? VT_VOID : VT_VARIANT; + if (func->arg_cnt) funcdesc->lprgelemdescParam = (ELEMDESC *)(funcdesc + 1); + for (j = 0; j < func->arg_cnt; j++) + funcdesc->lprgelemdescParam[j].tdesc.vt = VT_VARIANT; + } + else + { + funcdesc->elemdescFunc.tdesc.vt = VT_VARIANT; + } + + *ppFuncDesc = funcdesc; + return S_OK; +} + +static HRESULT WINAPI VBDispTypeInfo_GetVarDesc(ITypeInfo *iface, UINT index, VARDESC **ppVarDesc) +{ + VBDispTypeInfo *This = VBDispTypeInfo_from_ITypeInfo(iface); + const class_desc_t *desc = This->desc; + VARDESC *vardesc; + UINT i, n = 0; + + TRACE("(%p)->(%u %p)\n", This, index, ppVarDesc); + + if (!ppVarDesc) return E_INVALIDARG; + if (index >= This->num_vars) return TYPE_E_ELEMENTNOTFOUND; + + /* Map index to the n-th public property */ + for (i = 0; i < desc->prop_cnt; i++) + { + if (!desc->props[i].is_public) + continue; + if (n == index) + break; + n++; + } + + vardesc = calloc(1, sizeof(*vardesc)); + if (!vardesc) return E_OUTOFMEMORY; + + vardesc->memid = i + desc->func_cnt; + vardesc->varkind = VAR_DISPATCH; + vardesc->elemdescVar.tdesc.vt = VT_VARIANT; + + *ppVarDesc = vardesc; + return S_OK; +} + +static HRESULT WINAPI VBDispTypeInfo_GetNames(ITypeInfo *iface, MEMBERID memid, BSTR *rgBstrNames, + UINT cMaxNames, UINT *pcNames) +{ + VBDispTypeInfo *This = VBDispTypeInfo_from_ITypeInfo(iface); + const class_desc_t *desc = This->desc; + + TRACE("(%p)->(%ld %p %u %p)\n", This, memid, rgBstrNames, cMaxNames, pcNames); + + if (!rgBstrNames || !pcNames) return E_INVALIDARG; + + *pcNames = 0; + if (!cMaxNames) return S_OK; + + if (memid < 0) return TYPE_E_ELEMENTNOTFOUND; + + if ((UINT)memid < desc->func_cnt) + { + function_t *func; + UINT i; + + if (!desc->funcs[memid].name) + return TYPE_E_ELEMENTNOTFOUND; + + rgBstrNames[0] = SysAllocString(desc->funcs[memid].name); + if (!rgBstrNames[0]) return E_OUTOFMEMORY; + + func = desc->funcs[memid].entries[VBDISP_CALLGET]; + if (!func) func = desc->funcs[memid].entries[VBDISP_LET]; + if (!func) func = desc->funcs[memid].entries[VBDISP_SET]; + + *pcNames = 1; + if (func) + { + UINT num = min(cMaxNames, func->arg_cnt + 1); + for (i = 1; i < num; i++) + { + if (!(rgBstrNames[i] = SysAllocString(func->args[i - 1].name))) + { + do SysFreeString(rgBstrNames[--i]); while (i); + *pcNames = 0; + return E_OUTOFMEMORY; + } + } + *pcNames = num; + } + return S_OK; + } + + if ((UINT)memid < desc->func_cnt + desc->prop_cnt) + { + UINT prop_idx = memid - desc->func_cnt; + rgBstrNames[0] = SysAllocString(desc->props[prop_idx].name); + if (!rgBstrNames[0]) return E_OUTOFMEMORY; + *pcNames = 1; + return S_OK; + } + + return TYPE_E_ELEMENTNOTFOUND; +} + +static HRESULT WINAPI VBDispTypeInfo_GetRefTypeOfImplType(ITypeInfo *iface, UINT index, HREFTYPE *pRefType) +{ + VBDispTypeInfo *This = VBDispTypeInfo_from_ITypeInfo(iface); + + TRACE("(%p)->(%u %p)\n", This, index, pRefType); + + if (!pRefType) return E_INVALIDARG; + if (index != 0) return TYPE_E_ELEMENTNOTFOUND; + + *pRefType = 1; + return S_OK; +} + +static HRESULT WINAPI VBDispTypeInfo_GetImplTypeFlags(ITypeInfo *iface, UINT index, INT *pImplTypeFlags) +{ + VBDispTypeInfo *This = VBDispTypeInfo_from_ITypeInfo(iface); + + TRACE("(%p)->(%u %p)\n", This, index, pImplTypeFlags); + + if (!pImplTypeFlags) return E_INVALIDARG; + if (index != 0) return TYPE_E_ELEMENTNOTFOUND; + + *pImplTypeFlags = 0; + return S_OK; +} + +static HRESULT WINAPI VBDispTypeInfo_GetIDsOfNames(ITypeInfo *iface, LPOLESTR *rgszNames, + UINT cNames, MEMBERID *pMemId) +{ + VBDispTypeInfo *This = VBDispTypeInfo_from_ITypeInfo(iface); + const class_desc_t *desc = This->desc; + const WCHAR *name; + UINT i; + + TRACE("(%p)->(%p %u %p)\n", This, rgszNames, cNames, pMemId); + + if (!rgszNames || !cNames || !pMemId) return E_INVALIDARG; + + for (i = 0; i < cNames; i++) pMemId[i] = MEMBERID_NIL; + name = rgszNames[0]; + + for (i = 0; i < desc->func_cnt; i++) + { + if (!desc->funcs[i].is_public || !desc->funcs[i].name) + continue; + if (!wcsicmp(name, desc->funcs[i].name)) + { + pMemId[0] = i; + return S_OK; + } + } + + for (i = 0; i < desc->prop_cnt; i++) + { + if (!desc->props[i].is_public) + continue; + if (!wcsicmp(name, desc->props[i].name)) + { + pMemId[0] = i + desc->func_cnt; + return S_OK; + } + } + + return DISP_E_UNKNOWNNAME; +} + +static HRESULT WINAPI VBDispTypeInfo_Invoke(ITypeInfo *iface, PVOID pvInstance, MEMBERID memid, + WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + VBDispTypeInfo *This = VBDispTypeInfo_from_ITypeInfo(iface); + IDispatch *disp; + HRESULT hr; + + TRACE("(%p)->(%p %ld %d %p %p %p %p)\n", This, pvInstance, memid, wFlags, + pDispParams, pVarResult, pExcepInfo, puArgErr); + + if (!pvInstance) return E_INVALIDARG; + + hr = IUnknown_QueryInterface((IUnknown *)pvInstance, &IID_IDispatch, (void **)&disp); + if (FAILED(hr)) return hr; + + hr = IDispatch_Invoke(disp, memid, &IID_NULL, LOCALE_USER_DEFAULT, wFlags, + pDispParams, pVarResult, pExcepInfo, puArgErr); + IDispatch_Release(disp); + return hr; +} + +static HRESULT WINAPI VBDispTypeInfo_GetDocumentation(ITypeInfo *iface, MEMBERID memid, BSTR *pBstrName, + BSTR *pBstrDocString, DWORD *pdwHelpContext, BSTR *pBstrHelpFile) +{ + VBDispTypeInfo *This = VBDispTypeInfo_from_ITypeInfo(iface); + const class_desc_t *desc = This->desc; + + TRACE("(%p)->(%ld %p %p %p %p)\n", This, memid, pBstrName, pBstrDocString, pdwHelpContext, pBstrHelpFile); + + if (pBstrDocString) *pBstrDocString = NULL; + if (pdwHelpContext) *pdwHelpContext = 0; + if (pBstrHelpFile) *pBstrHelpFile = NULL; + + if (memid == MEMBERID_NIL) + { + if (pBstrName && !(*pBstrName = SysAllocString(desc->name))) + return E_OUTOFMEMORY; + return S_OK; + } + + if (memid < 0) return TYPE_E_ELEMENTNOTFOUND; + + if ((UINT)memid < desc->func_cnt) + { + if (!desc->funcs[memid].name) return TYPE_E_ELEMENTNOTFOUND; + if (pBstrName && !(*pBstrName = SysAllocString(desc->funcs[memid].name))) + return E_OUTOFMEMORY; + return S_OK; + } + + if ((UINT)memid < desc->func_cnt + desc->prop_cnt) + { + UINT prop_idx = memid - desc->func_cnt; + if (pBstrName && !(*pBstrName = SysAllocString(desc->props[prop_idx].name))) + return E_OUTOFMEMORY; + return S_OK; + } + + return TYPE_E_ELEMENTNOTFOUND; +} + +static HRESULT WINAPI VBDispTypeInfo_GetDllEntry(ITypeInfo *iface, MEMBERID memid, INVOKEKIND invKind, + BSTR *pBstrDllName, BSTR *pBstrName, WORD *pwOrdinal) +{ + VBDispTypeInfo *This = VBDispTypeInfo_from_ITypeInfo(iface); + + TRACE("(%p)->(%ld %d %p %p %p)\n", This, memid, invKind, pBstrDllName, pBstrName, pwOrdinal); + + if (pBstrDllName) *pBstrDllName = NULL; + if (pBstrName) *pBstrName = NULL; + if (pwOrdinal) *pwOrdinal = 0; + + return TYPE_E_BADMODULEKIND; +} + +static HRESULT WINAPI VBDispTypeInfo_GetRefTypeInfo(ITypeInfo *iface, HREFTYPE hRefType, ITypeInfo **ppTInfo) +{ + VBDispTypeInfo *This = VBDispTypeInfo_from_ITypeInfo(iface); + HRESULT hr; + + TRACE("(%p)->(%lx %p)\n", This, hRefType, ppTInfo); + + if (!ppTInfo || (INT)hRefType < 0) return E_INVALIDARG; + + if (hRefType & ~3) return E_FAIL; + if (hRefType & 1) + { + hr = get_dispatch_typeinfo(ppTInfo); + if (FAILED(hr)) return hr; + } + else + *ppTInfo = iface; + + ITypeInfo_AddRef(*ppTInfo); + return S_OK; +} + +static HRESULT WINAPI VBDispTypeInfo_AddressOfMember(ITypeInfo *iface, MEMBERID memid, INVOKEKIND invKind, PVOID *ppv) +{ + VBDispTypeInfo *This = VBDispTypeInfo_from_ITypeInfo(iface); + + TRACE("(%p)->(%ld %d %p)\n", This, memid, invKind, ppv); + + if (!ppv) return E_INVALIDARG; + *ppv = NULL; + + return TYPE_E_BADMODULEKIND; +} + +static HRESULT WINAPI VBDispTypeInfo_CreateInstance(ITypeInfo *iface, IUnknown *pUnkOuter, REFIID riid, PVOID *ppvObj) +{ + VBDispTypeInfo *This = VBDispTypeInfo_from_ITypeInfo(iface); + + TRACE("(%p)->(%p %s %p)\n", This, pUnkOuter, debugstr_guid(riid), ppvObj); + + if (!ppvObj) return E_INVALIDARG; + *ppvObj = NULL; + + return TYPE_E_BADMODULEKIND; +} + +static HRESULT WINAPI VBDispTypeInfo_GetMops(ITypeInfo *iface, MEMBERID memid, BSTR *pBstrMops) +{ + VBDispTypeInfo *This = VBDispTypeInfo_from_ITypeInfo(iface); + + TRACE("(%p)->(%ld %p)\n", This, memid, pBstrMops); + + if (!pBstrMops) return E_INVALIDARG; + + *pBstrMops = NULL; + return S_OK; +} + +static HRESULT WINAPI VBDispTypeInfo_GetContainingTypeLib(ITypeInfo *iface, ITypeLib **ppTLib, UINT *pIndex) +{ + VBDispTypeInfo *This = VBDispTypeInfo_from_ITypeInfo(iface); + + FIXME("(%p)->(%p %p)\n", This, ppTLib, pIndex); + + return E_NOTIMPL; +} + +static void WINAPI VBDispTypeInfo_ReleaseTypeAttr(ITypeInfo *iface, TYPEATTR *pTypeAttr) +{ + TRACE("(%p)->(%p)\n", iface, pTypeAttr); + free(pTypeAttr); +} + +static void WINAPI VBDispTypeInfo_ReleaseFuncDesc(ITypeInfo *iface, FUNCDESC *pFuncDesc) +{ + TRACE("(%p)->(%p)\n", iface, pFuncDesc); + free(pFuncDesc); +} + +static void WINAPI VBDispTypeInfo_ReleaseVarDesc(ITypeInfo *iface, VARDESC *pVarDesc) +{ + TRACE("(%p)->(%p)\n", iface, pVarDesc); + free(pVarDesc); +} + +static const ITypeInfoVtbl VBDispTypeInfoVtbl = { + VBDispTypeInfo_QueryInterface, + VBDispTypeInfo_AddRef, + VBDispTypeInfo_Release, + VBDispTypeInfo_GetTypeAttr, + VBDispTypeInfo_GetTypeComp, + VBDispTypeInfo_GetFuncDesc, + VBDispTypeInfo_GetVarDesc, + VBDispTypeInfo_GetNames, + VBDispTypeInfo_GetRefTypeOfImplType, + VBDispTypeInfo_GetImplTypeFlags, + VBDispTypeInfo_GetIDsOfNames, + VBDispTypeInfo_Invoke, + VBDispTypeInfo_GetDocumentation, + VBDispTypeInfo_GetDllEntry, + VBDispTypeInfo_GetRefTypeInfo, + VBDispTypeInfo_AddressOfMember, + VBDispTypeInfo_CreateInstance, + VBDispTypeInfo_GetMops, + VBDispTypeInfo_GetContainingTypeLib, + VBDispTypeInfo_ReleaseTypeAttr, + VBDispTypeInfo_ReleaseFuncDesc, + VBDispTypeInfo_ReleaseVarDesc +}; + static HRESULT WINAPI DispatchEx_GetTypeInfo(IDispatchEx *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) { vbdisp_t *This = impl_from_IDispatchEx(iface); - FIXME("(%p)->(%u %lu %p)\n", This, iTInfo, lcid, ppTInfo); - return E_NOTIMPL; + VBDispTypeInfo *type_info; + unsigned i; + + TRACE("(%p)->(%u %lu %p)\n", This, iTInfo, lcid, ppTInfo); + + if (iTInfo) + return DISP_E_BADINDEX; + + if (!This->desc) + return E_UNEXPECTED; + + if (!(type_info = malloc(sizeof(*type_info)))) + return E_OUTOFMEMORY; + + type_info->ITypeInfo_iface.lpVtbl = &VBDispTypeInfoVtbl; + type_info->ref = 1; + type_info->desc = This->desc; + type_info->num_funcs = 0; + type_info->num_vars = 0; + + for (i = 0; i < This->desc->func_cnt; i++) + if (This->desc->funcs[i].is_public && This->desc->funcs[i].name) + type_info->num_funcs++; + + for (i = 0; i < This->desc->prop_cnt; i++) + if (This->desc->props[i].is_public) + type_info->num_vars++; + + *ppTInfo = &type_info->ITypeInfo_iface; + return S_OK; } static HRESULT WINAPI DispatchEx_GetIDsOfNames(IDispatchEx *iface, REFIID riid, -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10461
participants (2)
-
Francis De Brabandere -
Francis De Brabandere (@francisdb)