Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/dispex.c | 272 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 271 insertions(+), 1 deletion(-)
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index 463fd2f..68e4e1c 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -590,11 +590,273 @@ static HRESULT fill_protrefs(jsdisp_t *This) return S_OK; }
+typedef struct { + ITypeInfo ITypeInfo_iface; + LONG ref; +} ScriptTypeInfo; + +static inline ScriptTypeInfo *ScriptTypeInfo_from_ITypeInfo(ITypeInfo *iface) +{ + return CONTAINING_RECORD(iface, ScriptTypeInfo, ITypeInfo_iface); +} + +static HRESULT WINAPI ScriptTypeInfo_QueryInterface(ITypeInfo *iface, REFIID riid, void **ppv) +{ + ScriptTypeInfo *This = ScriptTypeInfo_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; + } + + TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv); + IUnknown_AddRef((IUnknown*)*ppv); + return S_OK; +} + +static ULONG WINAPI ScriptTypeInfo_AddRef(ITypeInfo *iface) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + LONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p) ref=%d\n", This, ref); + + return ref; +} + +static ULONG WINAPI ScriptTypeInfo_Release(ITypeInfo *iface) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + LONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p) ref=%d\n", This, ref); + + if (!ref) + { + heap_free(This); + } + return ref; +} + +static HRESULT WINAPI ScriptTypeInfo_GetTypeAttr(ITypeInfo *iface, TYPEATTR **ppTypeAttr) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + + FIXME("(%p)->(%p)\n", This, ppTypeAttr); + + return E_NOTIMPL; +} + +static HRESULT WINAPI ScriptTypeInfo_GetTypeComp(ITypeInfo *iface, ITypeComp **ppTComp) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + + FIXME("(%p)->(%p)\n", This, ppTComp); + + return E_NOTIMPL; +} + +static HRESULT WINAPI ScriptTypeInfo_GetFuncDesc(ITypeInfo *iface, UINT index, FUNCDESC **ppFuncDesc) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + + FIXME("(%p)->(%u %p)\n", This, index, ppFuncDesc); + + return E_NOTIMPL; +} + +static HRESULT WINAPI ScriptTypeInfo_GetVarDesc(ITypeInfo *iface, UINT index, VARDESC **ppVarDesc) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + + FIXME("(%p)->(%u %p)\n", This, index, ppVarDesc); + + return E_NOTIMPL; +} + +static HRESULT WINAPI ScriptTypeInfo_GetNames(ITypeInfo *iface, MEMBERID memid, BSTR *rgBstrNames, + UINT cMaxNames, UINT *pcNames) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + + FIXME("(%p)->(%d %p %u %p)\n", This, memid, rgBstrNames, cMaxNames, pcNames); + + return E_NOTIMPL; +} + +static HRESULT WINAPI ScriptTypeInfo_GetRefTypeOfImplType(ITypeInfo *iface, UINT index, HREFTYPE *pRefType) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + + FIXME("(%p)->(%u %p)\n", This, index, pRefType); + + return E_NOTIMPL; +} + +static HRESULT WINAPI ScriptTypeInfo_GetImplTypeFlags(ITypeInfo *iface, UINT index, INT *pImplTypeFlags) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + + FIXME("(%p)->(%u %p)\n", This, index, pImplTypeFlags); + + return E_NOTIMPL; +} + +static HRESULT WINAPI ScriptTypeInfo_GetIDsOfNames(ITypeInfo *iface, LPOLESTR *rgszNames, UINT cNames, + MEMBERID *pMemId) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + + FIXME("(%p)->(%p %u %p)\n", This, rgszNames, cNames, pMemId); + + return E_NOTIMPL; +} + +static HRESULT WINAPI ScriptTypeInfo_Invoke(ITypeInfo *iface, PVOID pvInstance, MEMBERID memid, WORD wFlags, + DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + + FIXME("(%p)->(%p %d %d %p %p %p %p)\n", This, pvInstance, memid, wFlags, + pDispParams, pVarResult, pExcepInfo, puArgErr); + + return E_NOTIMPL; +} + +static HRESULT WINAPI ScriptTypeInfo_GetDocumentation(ITypeInfo *iface, MEMBERID memid, BSTR *pBstrName, + BSTR *pBstrDocString, DWORD *pdwHelpContext, BSTR *pBstrHelpFile) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + + FIXME("(%p)->(%d %p %p %p %p)\n", This, memid, pBstrName, pBstrDocString, pdwHelpContext, pBstrHelpFile); + + return E_NOTIMPL; +} + +static HRESULT WINAPI ScriptTypeInfo_GetDllEntry(ITypeInfo *iface, MEMBERID memid, INVOKEKIND invKind, + BSTR *pBstrDllName, BSTR *pBstrName, WORD *pwOrdinal) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + + FIXME("(%p)->(%d %d %p %p %p)\n", This, memid, invKind, pBstrDllName, pBstrName, pwOrdinal); + + return E_NOTIMPL; +} + +static HRESULT WINAPI ScriptTypeInfo_GetRefTypeInfo(ITypeInfo *iface, HREFTYPE hRefType, ITypeInfo **ppTInfo) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + + FIXME("(%p)->(%x %p)\n", This, hRefType, ppTInfo); + + return E_NOTIMPL; +} + +static HRESULT WINAPI ScriptTypeInfo_AddressOfMember(ITypeInfo *iface, MEMBERID memid, INVOKEKIND invKind, PVOID *ppv) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + + FIXME("(%p)->(%d %d %p)\n", This, memid, invKind, ppv); + + return E_NOTIMPL; +} + +static HRESULT WINAPI ScriptTypeInfo_CreateInstance(ITypeInfo *iface, IUnknown *pUnkOuter, REFIID riid, PVOID *ppvObj) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + + FIXME("(%p)->(%p %s %p)\n", This, pUnkOuter, debugstr_guid(riid), ppvObj); + + return E_NOTIMPL; +} + +static HRESULT WINAPI ScriptTypeInfo_GetMops(ITypeInfo *iface, MEMBERID memid, BSTR *pBstrMops) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + + FIXME("(%p)->(%d %p)\n", This, memid, pBstrMops); + + return E_NOTIMPL; +} + +static HRESULT WINAPI ScriptTypeInfo_GetContainingTypeLib(ITypeInfo *iface, ITypeLib **ppTLib, UINT *pIndex) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + + FIXME("(%p)->(%p %p)\n", This, ppTLib, pIndex); + + return E_NOTIMPL; +} + +static void WINAPI ScriptTypeInfo_ReleaseTypeAttr(ITypeInfo *iface, TYPEATTR *pTypeAttr) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + + FIXME("(%p)->(%p)\n", This, pTypeAttr); +} + +static void WINAPI ScriptTypeInfo_ReleaseFuncDesc(ITypeInfo *iface, FUNCDESC *pFuncDesc) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + + FIXME("(%p)->(%p)\n", This, pFuncDesc); +} + +static void WINAPI ScriptTypeInfo_ReleaseVarDesc(ITypeInfo *iface, VARDESC *pVarDesc) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + + FIXME("(%p)->(%p)\n", This, pVarDesc); +} + +static const ITypeInfoVtbl ScriptTypeInfoVtbl = { + ScriptTypeInfo_QueryInterface, + ScriptTypeInfo_AddRef, + ScriptTypeInfo_Release, + ScriptTypeInfo_GetTypeAttr, + ScriptTypeInfo_GetTypeComp, + ScriptTypeInfo_GetFuncDesc, + ScriptTypeInfo_GetVarDesc, + ScriptTypeInfo_GetNames, + ScriptTypeInfo_GetRefTypeOfImplType, + ScriptTypeInfo_GetImplTypeFlags, + ScriptTypeInfo_GetIDsOfNames, + ScriptTypeInfo_Invoke, + ScriptTypeInfo_GetDocumentation, + ScriptTypeInfo_GetDllEntry, + ScriptTypeInfo_GetRefTypeInfo, + ScriptTypeInfo_AddressOfMember, + ScriptTypeInfo_CreateInstance, + ScriptTypeInfo_GetMops, + ScriptTypeInfo_GetContainingTypeLib, + ScriptTypeInfo_ReleaseTypeAttr, + ScriptTypeInfo_ReleaseFuncDesc, + ScriptTypeInfo_ReleaseVarDesc +}; + static inline jsdisp_t *impl_from_IDispatchEx(IDispatchEx *iface) { return CONTAINING_RECORD(iface, jsdisp_t, IDispatchEx_iface); }
+static HRESULT create_script_typeinfo(jsdisp_t *jsdisp, ITypeInfo **out) +{ + ScriptTypeInfo *typeinfo; + + if (!(typeinfo = heap_alloc(sizeof(*typeinfo)))) + return E_OUTOFMEMORY; + + typeinfo->ITypeInfo_iface.lpVtbl = &ScriptTypeInfoVtbl; + typeinfo->ref = 1; + + *out = &typeinfo->ITypeInfo_iface; + return S_OK; +} + static HRESULT WINAPI DispatchEx_QueryInterface(IDispatchEx *iface, REFIID riid, void **ppv) { jsdisp_t *This = impl_from_IDispatchEx(iface); @@ -649,7 +911,15 @@ static HRESULT WINAPI DispatchEx_GetTypeInfo(IDispatchEx *iface, UINT iTInfo, LC ITypeInfo **ppTInfo) { jsdisp_t *This = impl_from_IDispatchEx(iface); - FIXME("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo); + + TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo); + + if (iTInfo != 0) return DISP_E_BADINDEX; + + if (This == This->ctx->global) + return create_script_typeinfo(This, ppTInfo); + + FIXME("non-global not implemented\n"); return E_NOTIMPL; }
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/dispex.c | 109 ++++++++++++++++++++++++++++++++++++++++ dlls/jscript/function.c | 5 ++ dlls/jscript/jscript.h | 1 + 3 files changed, 115 insertions(+)
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index 68e4e1c..2c309cd 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -70,6 +70,20 @@ static inline dispex_prop_t *get_prop(jsdisp_t *This, DISPID id) return This->props+id; }
+static inline BOOL is_function_prop(dispex_prop_t *prop) +{ + BOOL ret = FALSE; + + if (is_object_instance(prop->u.val)) + { + jsdisp_t *jsdisp = iface_to_jsdisp(get_object(prop->u.val)); + + if (jsdisp) ret = is_class(jsdisp, JSCLASS_FUNCTION); + jsdisp_release(jsdisp); + } + return ret; +} + static DWORD get_flags(jsdisp_t *This, dispex_prop_t *prop) { if(prop->type == PROP_PROTREF) { @@ -590,9 +604,21 @@ static HRESULT fill_protrefs(jsdisp_t *This) return S_OK; }
+struct typeinfo_func { + dispex_prop_t *prop; + jsdisp_t *disp; +}; + typedef struct { ITypeInfo ITypeInfo_iface; LONG ref; + + UINT num_funcs; + UINT num_vars; + struct typeinfo_func *funcs; + dispex_prop_t **vars; + + jsdisp_t *jsdisp; } ScriptTypeInfo;
static inline ScriptTypeInfo *ScriptTypeInfo_from_ITypeInfo(ITypeInfo *iface) @@ -632,11 +658,17 @@ static ULONG WINAPI ScriptTypeInfo_Release(ITypeInfo *iface) { ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); LONG ref = InterlockedDecrement(&This->ref); + UINT i;
TRACE("(%p) ref=%d\n", This, ref);
if (!ref) { + for (i = This->num_funcs; i--;) + IDispatchEx_Release(&This->funcs[i].disp->IDispatchEx_iface); + IDispatchEx_Release(&This->jsdisp->IDispatchEx_iface); + heap_free(This->funcs); + heap_free(This->vars); heap_free(This); } return ref; @@ -845,13 +877,90 @@ static inline jsdisp_t *impl_from_IDispatchEx(IDispatchEx *iface)
static HRESULT create_script_typeinfo(jsdisp_t *jsdisp, ITypeInfo **out) { + dispex_prop_t *prop, *cur, *end, **typevar; + UINT num_funcs = 0, num_vars = 0; + struct typeinfo_func *typefunc; ScriptTypeInfo *typeinfo; + jsdisp_t *fn; + unsigned pos;
if (!(typeinfo = heap_alloc(sizeof(*typeinfo)))) return E_OUTOFMEMORY;
+ for (prop = jsdisp->props, end = prop + jsdisp->prop_cnt; prop != end; prop++) + { + if (!prop->name || prop->type != PROP_JSVAL || !(prop->flags & PROPF_ENUMERABLE)) + continue; + + /* If two identifiers differ only by case, the TypeInfo fails */ + pos = jsdisp->props[get_props_idx(jsdisp, prop->hash)].bucket_head; + while (pos) + { + cur = jsdisp->props + pos; + + if (prop->hash == cur->hash && prop != cur && + cur->type == PROP_JSVAL && (cur->flags & PROPF_ENUMERABLE) && + !wcsicmp(prop->name, cur->name)) + { + return TYPE_E_AMBIGUOUSNAME; + } + pos = cur->bucket_next; + } + + if (is_function_prop(prop)) + { + fn = impl_from_IDispatchEx((IDispatchEx*)get_object(prop->u.val)); + if (is_source_function(fn)) num_funcs++; + } + else num_vars++; + } + typeinfo->ITypeInfo_iface.lpVtbl = &ScriptTypeInfoVtbl; typeinfo->ref = 1; + typeinfo->num_vars = num_vars; + typeinfo->num_funcs = num_funcs; + typeinfo->jsdisp = jsdisp; + + typeinfo->funcs = heap_alloc(sizeof(*typeinfo->funcs) * num_funcs); + if (!typeinfo->funcs) + { + heap_free(typeinfo); + return E_OUTOFMEMORY; + } + + typeinfo->vars = heap_alloc(sizeof(*typeinfo->vars) * num_vars); + if (!typeinfo->vars) + { + heap_free(typeinfo->funcs); + heap_free(typeinfo); + return E_OUTOFMEMORY; + } + + typefunc = typeinfo->funcs; + typevar = typeinfo->vars; + for (prop = jsdisp->props; prop != end; prop++) + { + if (!prop->name || prop->type != PROP_JSVAL || !(prop->flags & PROPF_ENUMERABLE)) + continue; + + if (is_function_prop(prop)) + { + fn = impl_from_IDispatchEx((IDispatchEx*)get_object(prop->u.val)); + if (!is_source_function(fn)) continue; + + typefunc->prop = prop; + typefunc->disp = fn; + typefunc++; + + /* The function's object may be deleted, so keep it alive */ + IDispatchEx_AddRef(&fn->IDispatchEx_iface); + } + else + *typevar++ = prop; + } + + /* Keep a ref to the props and their names */ + IDispatchEx_AddRef(&jsdisp->IDispatchEx_iface);
*out = &typeinfo->ITypeInfo_iface; return S_OK; diff --git a/dlls/jscript/function.c b/dlls/jscript/function.c index 7a44f50..98d1259 100644 --- a/dlls/jscript/function.c +++ b/dlls/jscript/function.c @@ -803,6 +803,11 @@ HRESULT create_source_function(script_ctx_t *ctx, bytecode_t *code, function_cod return S_OK; }
+BOOL is_source_function(jsdisp_t *jsdisp) +{ + return function_from_jsdisp(jsdisp)->vtbl == &InterpretedFunctionVtbl; +} + static HRESULT BindFunction_call(script_ctx_t *ctx, FunctionInstance *func, IDispatch *this_obj, unsigned flags, unsigned argc, jsval_t *argv, jsval_t *r) { diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index 5d635b7..91923f8 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -303,6 +303,7 @@ HRESULT create_builtin_function(script_ctx_t*,builtin_invoke_t,const WCHAR*,cons jsdisp_t*,jsdisp_t**) DECLSPEC_HIDDEN; HRESULT create_builtin_constructor(script_ctx_t*,builtin_invoke_t,const WCHAR*,const builtin_info_t*,DWORD, jsdisp_t*,jsdisp_t**) DECLSPEC_HIDDEN; +BOOL is_source_function(jsdisp_t*) DECLSPEC_HIDDEN; HRESULT Function_invoke(jsdisp_t*,IDispatch*,WORD,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN;
HRESULT Function_value(script_ctx_t*,vdisp_t*,WORD,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN;
On 12/9/19 3:01 PM, Gabriel Ivăncescu wrote:
+BOOL is_source_function(jsdisp_t *jsdisp) +{
- return function_from_jsdisp(jsdisp)->vtbl == &InterpretedFunctionVtbl;
+}
I'm not sure about that, are native functions really not treated as functions? It should be easy to test with something like:
var native_func = decodeURI;
Thanks,
Jacek
On 12/9/19 4:56 PM, Jacek Caban wrote:
On 12/9/19 3:01 PM, Gabriel Ivăncescu wrote:
+BOOL is_source_function(jsdisp_t *jsdisp) +{ + return function_from_jsdisp(jsdisp)->vtbl == &InterpretedFunctionVtbl; +}
I'm not sure about that, are native functions really not treated as functions? It should be easy to test with something like:
var native_func = decodeURI;
Thanks,
Jacek
Ok, I'll see about the tests, but I was actually more worried about how to get the args and their names for native functions (didn't know how).
On 12/9/19 5:24 PM, Gabriel Ivăncescu wrote:
On 12/9/19 4:56 PM, Jacek Caban wrote:
On 12/9/19 3:01 PM, Gabriel Ivăncescu wrote:
+BOOL is_source_function(jsdisp_t *jsdisp) +{ + return function_from_jsdisp(jsdisp)->vtbl == &InterpretedFunctionVtbl; +}
I'm not sure about that, are native functions really not treated as functions? It should be easy to test with something like:
var native_func = decodeURI;
Thanks,
Jacek
Ok, I'll see about the tests, but I was actually more worried about how to get the args and their names for native functions (didn't know how).
Looks like indeed native functions are completely ignored: they don't show up as variables, either.
So do I keep this patch it as-is?
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/dispex.c | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-)
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index 2c309cd..1f28538 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -24,6 +24,8 @@
WINE_DEFAULT_DEBUG_CHANNEL(jscript);
+static const GUID GUID_JScriptTypeInfo = {0xc59c6b12,0xf6c1,0x11cf,{0x88,0x35,0x00,0xa0,0xc9,0x11,0xe8,0xb2}}; + #define FDEX_VERSION_MASK 0xf0000000 #define GOLDEN_RATIO 0x9E3779B9U
@@ -677,10 +679,32 @@ static ULONG WINAPI ScriptTypeInfo_Release(ITypeInfo *iface) static HRESULT WINAPI ScriptTypeInfo_GetTypeAttr(ITypeInfo *iface, TYPEATTR **ppTypeAttr) { ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); - - FIXME("(%p)->(%p)\n", This, ppTypeAttr); - - return E_NOTIMPL; + TYPEATTR *attr; + + TRACE("(%p)->(%p)\n", This, ppTypeAttr); + + if (!ppTypeAttr) return E_INVALIDARG; + + attr = heap_alloc_zero(sizeof(*attr)); + if (!attr) return E_OUTOFMEMORY; + + attr->guid = GUID_JScriptTypeInfo; + 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 = JSCRIPT_MAJOR_VERSION; + attr->wMinorVerNum = JSCRIPT_MINOR_VERSION; + + *ppTypeAttr = attr; + return S_OK; }
static HRESULT WINAPI ScriptTypeInfo_GetTypeComp(ITypeInfo *iface, ITypeComp **ppTComp) @@ -828,7 +852,9 @@ static void WINAPI ScriptTypeInfo_ReleaseTypeAttr(ITypeInfo *iface, TYPEATTR *pT { ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
- FIXME("(%p)->(%p)\n", This, pTypeAttr); + TRACE("(%p)->(%p)\n", This, pTypeAttr); + + heap_free(pTypeAttr); }
static void WINAPI ScriptTypeInfo_ReleaseFuncDesc(ITypeInfo *iface, FUNCDESC *pFuncDesc)
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/dispex.c | 32 +++++++++++++++++++++++++++++--- dlls/jscript/function.c | 8 ++++++++ dlls/jscript/jscript.h | 1 + 3 files changed, 38 insertions(+), 3 deletions(-)
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index 1f28538..5db7da6 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -719,10 +719,34 @@ static HRESULT WINAPI ScriptTypeInfo_GetTypeComp(ITypeInfo *iface, ITypeComp **p static HRESULT WINAPI ScriptTypeInfo_GetFuncDesc(ITypeInfo *iface, UINT index, FUNCDESC **ppFuncDesc) { ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + struct typeinfo_func *func; + unsigned num_args, i; + FUNCDESC *desc;
- FIXME("(%p)->(%u %p)\n", This, index, ppFuncDesc); + TRACE("(%p)->(%u %p)\n", This, index, ppFuncDesc);
- return E_NOTIMPL; + if (!ppFuncDesc) return E_INVALIDARG; + if (index >= This->num_funcs) return TYPE_E_ELEMENTNOTFOUND; + func = &This->funcs[index]; + get_source_function_params(func->disp, &num_args); + + /* Store the parameter array after the FUNCDESC structure */ + desc = heap_alloc_zero(sizeof(*desc) + sizeof(ELEMDESC) * num_args); + if (!desc) return E_OUTOFMEMORY; + + desc->memid = prop_to_id(This->jsdisp, func->prop); + desc->funckind = FUNC_DISPATCH; + desc->invkind = INVOKE_FUNC; + desc->callconv = CC_STDCALL; + desc->cParams = num_args; + desc->elemdescFunc.tdesc.vt = VT_VARIANT; + + if (num_args) desc->lprgelemdescParam = (ELEMDESC*)(desc + 1); + for (i = 0; i < num_args; i++) + desc->lprgelemdescParam[i].tdesc.vt = VT_VARIANT; + + *ppFuncDesc = desc; + return S_OK; }
static HRESULT WINAPI ScriptTypeInfo_GetVarDesc(ITypeInfo *iface, UINT index, VARDESC **ppVarDesc) @@ -861,7 +885,9 @@ static void WINAPI ScriptTypeInfo_ReleaseFuncDesc(ITypeInfo *iface, FUNCDESC *pF { ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
- FIXME("(%p)->(%p)\n", This, pFuncDesc); + TRACE("(%p)->(%p)\n", This, pFuncDesc); + + heap_free(pFuncDesc); }
static void WINAPI ScriptTypeInfo_ReleaseVarDesc(ITypeInfo *iface, VARDESC *pVarDesc) diff --git a/dlls/jscript/function.c b/dlls/jscript/function.c index 98d1259..c2d058b 100644 --- a/dlls/jscript/function.c +++ b/dlls/jscript/function.c @@ -808,6 +808,14 @@ BOOL is_source_function(jsdisp_t *jsdisp) return function_from_jsdisp(jsdisp)->vtbl == &InterpretedFunctionVtbl; }
+BSTR *get_source_function_params(jsdisp_t *jsdisp, unsigned *param_cnt) +{ + InterpretedFunction *func = (InterpretedFunction*)function_from_jsdisp(jsdisp); + + *param_cnt = func->func_code->param_cnt; + return func->func_code->params; +} + static HRESULT BindFunction_call(script_ctx_t *ctx, FunctionInstance *func, IDispatch *this_obj, unsigned flags, unsigned argc, jsval_t *argv, jsval_t *r) { diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index 91923f8..09ecfb4 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -304,6 +304,7 @@ HRESULT create_builtin_function(script_ctx_t*,builtin_invoke_t,const WCHAR*,cons HRESULT create_builtin_constructor(script_ctx_t*,builtin_invoke_t,const WCHAR*,const builtin_info_t*,DWORD, jsdisp_t*,jsdisp_t**) DECLSPEC_HIDDEN; BOOL is_source_function(jsdisp_t*) DECLSPEC_HIDDEN; +BSTR *get_source_function_params(jsdisp_t*,unsigned*) DECLSPEC_HIDDEN; HRESULT Function_invoke(jsdisp_t*,IDispatch*,WORD,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN;
HRESULT Function_value(script_ctx_t*,vdisp_t*,WORD,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN;
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/dispex.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-)
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index 5db7da6..7847ad6 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -752,10 +752,22 @@ static HRESULT WINAPI ScriptTypeInfo_GetFuncDesc(ITypeInfo *iface, UINT index, F static HRESULT WINAPI ScriptTypeInfo_GetVarDesc(ITypeInfo *iface, UINT index, VARDESC **ppVarDesc) { ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + VARDESC *desc;
- FIXME("(%p)->(%u %p)\n", This, index, ppVarDesc); + TRACE("(%p)->(%u %p)\n", This, index, ppVarDesc);
- return E_NOTIMPL; + if (!ppVarDesc) return E_INVALIDARG; + if (index >= This->num_vars) return TYPE_E_ELEMENTNOTFOUND; + + desc = heap_alloc_zero(sizeof(*desc)); + if (!desc) return E_OUTOFMEMORY; + + desc->memid = prop_to_id(This->jsdisp, This->vars[index]); + desc->varkind = VAR_DISPATCH; + desc->elemdescVar.tdesc.vt = VT_VARIANT; + + *ppVarDesc = desc; + return S_OK; }
static HRESULT WINAPI ScriptTypeInfo_GetNames(ITypeInfo *iface, MEMBERID memid, BSTR *rgBstrNames, @@ -894,7 +906,9 @@ static void WINAPI ScriptTypeInfo_ReleaseVarDesc(ITypeInfo *iface, VARDESC *pVar { ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
- FIXME("(%p)->(%p)\n", This, pVarDesc); + TRACE("(%p)->(%p)\n", This, pVarDesc); + + heap_free(pVarDesc); }
static const ITypeInfoVtbl ScriptTypeInfoVtbl = {
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/dispex.c | 51 +++++++++++++++++++++++++++++++++++-- dlls/jscript/jscript.h | 1 + dlls/jscript/jscript_main.c | 25 ++++++++++++++++++ 3 files changed, 75 insertions(+), 2 deletions(-)
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index 7847ad6..ddea563 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -802,10 +802,57 @@ static HRESULT WINAPI ScriptTypeInfo_GetIDsOfNames(ITypeInfo *iface, LPOLESTR *r MEMBERID *pMemId) { ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + ITypeInfo *disp_typeinfo; + const WCHAR *name; + HRESULT hr = S_OK; + int i, j, arg;
- FIXME("(%p)->(%p %u %p)\n", This, rgszNames, cNames, pMemId); + TRACE("(%p)->(%p %u %p)\n", This, rgszNames, cNames, pMemId);
- return E_NOTIMPL; + if (!rgszNames || !cNames || !pMemId) return E_INVALIDARG; + + for (i = 0; i < cNames; i++) pMemId[i] = MEMBERID_NIL; + name = rgszNames[0]; + + for (i = 0; i < This->num_funcs; i++) + { + struct typeinfo_func *func = &This->funcs[i]; + unsigned num_args; + BSTR *args; + + if (wcsicmp(name, func->prop->name)) continue; + pMemId[0] = prop_to_id(This->jsdisp, func->prop); + + args = get_source_function_params(func->disp, &num_args); + + for (j = 1; j < cNames; j++) + { + name = rgszNames[j]; + for (arg = num_args; --arg >= 0;) + if (!wcsicmp(name, args[arg])) + break; + if (arg >= 0) + pMemId[j] = arg; + else + hr = DISP_E_UNKNOWNNAME; + } + return hr; + } + + for (i = 0; i < This->num_vars; i++) + { + dispex_prop_t *var = This->vars[i]; + + if (wcsicmp(name, var->name)) continue; + pMemId[0] = prop_to_id(This->jsdisp, var); + return S_OK; + } + + /* Look into the inherited IDispatch */ + hr = get_dispatch_typeinfo(&disp_typeinfo); + if (FAILED(hr)) return hr; + + return ITypeInfo_GetIDsOfNames(disp_typeinfo, rgszNames, cNames, pMemId); }
static HRESULT WINAPI ScriptTypeInfo_Invoke(ITypeInfo *iface, PVOID pvInstance, MEMBERID memid, WORD wFlags, diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index 09ecfb4..6066772 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -87,6 +87,7 @@ static inline LPWSTR heap_strdupW(LPCWSTR str) typedef struct jsdisp_t jsdisp_t;
extern HINSTANCE jscript_hinstance DECLSPEC_HIDDEN; +HRESULT get_dispatch_typeinfo(ITypeInfo**) DECLSPEC_HIDDEN;
#define PROPF_ARGMASK 0x00ff #define PROPF_METHOD 0x0100 diff --git a/dlls/jscript/jscript_main.c b/dlls/jscript/jscript_main.c index 9f9f412..532cdf9 100644 --- a/dlls/jscript/jscript_main.c +++ b/dlls/jscript/jscript_main.c @@ -37,6 +37,30 @@ LONG module_ref = 0; DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
HINSTANCE jscript_hinstance; +static ITypeInfo *dispatch_typeinfo; + +HRESULT get_dispatch_typeinfo(ITypeInfo **out) +{ + ITypeInfo *typeinfo; + ITypeLib *typelib; + HRESULT hr; + + if (!dispatch_typeinfo) + { + hr = LoadRegTypeLib(&IID_StdOle, STDOLE_MAJORVERNUM, STDOLE_MINORVERNUM, STDOLE_LCID, &typelib); + if (FAILED(hr)) return hr; + + hr = ITypeLib_GetTypeInfoOfGuid(typelib, &IID_IDispatch, &typeinfo); + ITypeLib_Release(typelib); + if (FAILED(hr)) return hr; + + if (InterlockedCompareExchangePointer((void**)&dispatch_typeinfo, typeinfo, NULL)) + ITypeInfo_Release(typeinfo); + } + + *out = dispatch_typeinfo; + return S_OK; +}
static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID riid, void **ppv) { @@ -145,6 +169,7 @@ BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv) break; case DLL_PROCESS_DETACH: if (lpv) break; + if (dispatch_typeinfo) ITypeInfo_Release(dispatch_typeinfo); free_strings(); }
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/dispex.c | 64 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 62 insertions(+), 2 deletions(-)
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index ddea563..f7ad023 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -613,6 +613,7 @@ struct typeinfo_func {
typedef struct { ITypeInfo ITypeInfo_iface; + ITypeComp ITypeComp_iface; LONG ref;
UINT num_funcs; @@ -628,12 +629,19 @@ static inline ScriptTypeInfo *ScriptTypeInfo_from_ITypeInfo(ITypeInfo *iface) return CONTAINING_RECORD(iface, ScriptTypeInfo, ITypeInfo_iface); }
+static inline ScriptTypeInfo *ScriptTypeInfo_from_ITypeComp(ITypeComp *iface) +{ + return CONTAINING_RECORD(iface, ScriptTypeInfo, ITypeComp_iface); +} + static HRESULT WINAPI ScriptTypeInfo_QueryInterface(ITypeInfo *iface, REFIID riid, void **ppv) { ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
if (IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_ITypeInfo, riid)) *ppv = &This->ITypeInfo_iface; + else if (IsEqualGUID(&IID_ITypeComp, riid)) + *ppv = &This->ITypeComp_iface; else { WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv); @@ -711,9 +719,13 @@ static HRESULT WINAPI ScriptTypeInfo_GetTypeComp(ITypeInfo *iface, ITypeComp **p { ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
- FIXME("(%p)->(%p)\n", This, ppTComp); + TRACE("(%p)->(%p)\n", This, ppTComp);
- return E_NOTIMPL; + if (!ppTComp) return E_INVALIDARG; + + *ppTComp = &This->ITypeComp_iface; + ITypeInfo_AddRef(iface); + return S_OK; }
static HRESULT WINAPI ScriptTypeInfo_GetFuncDesc(ITypeInfo *iface, UINT index, FUNCDESC **ppFuncDesc) @@ -983,6 +995,53 @@ static const ITypeInfoVtbl ScriptTypeInfoVtbl = { ScriptTypeInfo_ReleaseVarDesc };
+static HRESULT WINAPI ScriptTypeComp_QueryInterface(ITypeComp *iface, REFIID riid, void **ppv) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeComp(iface); + return ITypeInfo_QueryInterface(&This->ITypeInfo_iface, riid, ppv); +} + +static ULONG WINAPI ScriptTypeComp_AddRef(ITypeComp *iface) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeComp(iface); + return ITypeInfo_AddRef(&This->ITypeInfo_iface); +} + +static ULONG WINAPI ScriptTypeComp_Release(ITypeComp *iface) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeComp(iface); + return ITypeInfo_Release(&This->ITypeInfo_iface); +} + +static HRESULT WINAPI ScriptTypeComp_Bind(ITypeComp *iface, LPOLESTR szName, ULONG lHashVal, WORD wFlags, + ITypeInfo **ppTInfo, DESCKIND *pDescKind, BINDPTR *pBindPtr) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeComp(iface); + + FIXME("(%p)->(%s %08x %d %p %p %p)\n", This, debugstr_w(szName), lHashVal, + wFlags, ppTInfo, pDescKind, pBindPtr); + + return E_NOTIMPL; +} + +static HRESULT WINAPI ScriptTypeComp_BindType(ITypeComp *iface, LPOLESTR szName, ULONG lHashVal, + ITypeInfo **ppTInfo, ITypeComp **ppTComp) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeComp(iface); + + FIXME("(%p)->(%s %08x %p %p)\n", This, debugstr_w(szName), lHashVal, ppTInfo, ppTComp); + + return E_NOTIMPL; +} + +static const ITypeCompVtbl ScriptTypeCompVtbl = { + ScriptTypeComp_QueryInterface, + ScriptTypeComp_AddRef, + ScriptTypeComp_Release, + ScriptTypeComp_Bind, + ScriptTypeComp_BindType +}; + static inline jsdisp_t *impl_from_IDispatchEx(IDispatchEx *iface) { return CONTAINING_RECORD(iface, jsdisp_t, IDispatchEx_iface); @@ -1029,6 +1088,7 @@ static HRESULT create_script_typeinfo(jsdisp_t *jsdisp, ITypeInfo **out) }
typeinfo->ITypeInfo_iface.lpVtbl = &ScriptTypeInfoVtbl; + typeinfo->ITypeComp_iface.lpVtbl = &ScriptTypeCompVtbl; typeinfo->ref = 1; typeinfo->num_vars = num_vars; typeinfo->num_funcs = num_funcs;
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/dispex.c | 49 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-)
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index f7ad023..37e851e 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -1017,11 +1017,56 @@ static HRESULT WINAPI ScriptTypeComp_Bind(ITypeComp *iface, LPOLESTR szName, ULO ITypeInfo **ppTInfo, DESCKIND *pDescKind, BINDPTR *pBindPtr) { ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeComp(iface); + UINT flags = wFlags ? wFlags : ~0; + ITypeInfo *disp_typeinfo; + ITypeComp *disp_typecomp; + HRESULT hr; + UINT i;
- FIXME("(%p)->(%s %08x %d %p %p %p)\n", This, debugstr_w(szName), lHashVal, + TRACE("(%p)->(%s %08x %d %p %p %p)\n", This, debugstr_w(szName), lHashVal, wFlags, ppTInfo, pDescKind, pBindPtr);
- return E_NOTIMPL; + if (!szName || !ppTInfo || !pDescKind || !pBindPtr) + return E_INVALIDARG; + + for (i = 0; i < This->num_funcs; i++) + { + if (wcsicmp(szName, This->funcs[i].prop->name)) continue; + if (!(flags & INVOKE_FUNC)) return TYPE_E_TYPEMISMATCH; + + hr = ITypeInfo_GetFuncDesc(&This->ITypeInfo_iface, i, &pBindPtr->lpfuncdesc); + if (FAILED(hr)) return hr; + + *pDescKind = DESCKIND_FUNCDESC; + *ppTInfo = &This->ITypeInfo_iface; + ITypeInfo_AddRef(*ppTInfo); + return S_OK; + } + + for (i = 0; i < This->num_vars; i++) + { + if (wcsicmp(szName, This->vars[i]->name)) continue; + if (!(flags & INVOKE_PROPERTYGET)) return TYPE_E_TYPEMISMATCH; + + hr = ITypeInfo_GetVarDesc(&This->ITypeInfo_iface, i, &pBindPtr->lpvardesc); + if (FAILED(hr)) return hr; + + *pDescKind = DESCKIND_VARDESC; + *ppTInfo = &This->ITypeInfo_iface; + ITypeInfo_AddRef(*ppTInfo); + return S_OK; + } + + /* Look into the inherited IDispatch */ + hr = get_dispatch_typeinfo(&disp_typeinfo); + if (FAILED(hr)) return hr; + + hr = ITypeInfo_GetTypeComp(disp_typeinfo, &disp_typecomp); + if (FAILED(hr)) return hr; + + hr = ITypeComp_Bind(disp_typecomp, szName, lHashVal, wFlags, ppTInfo, pDescKind, pBindPtr); + ITypeComp_Release(disp_typecomp); + return hr; }
static HRESULT WINAPI ScriptTypeComp_BindType(ITypeComp *iface, LPOLESTR szName, ULONG lHashVal,
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/dispex.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-)
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index 37e851e..999ea56 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -1073,10 +1073,25 @@ static HRESULT WINAPI ScriptTypeComp_BindType(ITypeComp *iface, LPOLESTR szName, ITypeInfo **ppTInfo, ITypeComp **ppTComp) { ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeComp(iface); + ITypeInfo *disp_typeinfo; + ITypeComp *disp_typecomp; + HRESULT hr;
- FIXME("(%p)->(%s %08x %p %p)\n", This, debugstr_w(szName), lHashVal, ppTInfo, ppTComp); + TRACE("(%p)->(%s %08x %p %p)\n", This, debugstr_w(szName), lHashVal, ppTInfo, ppTComp);
- return E_NOTIMPL; + if (!szName || !ppTInfo || !ppTComp) + return E_INVALIDARG; + + /* Look into the inherited IDispatch */ + hr = get_dispatch_typeinfo(&disp_typeinfo); + if (FAILED(hr)) return hr; + + hr = ITypeInfo_GetTypeComp(disp_typeinfo, &disp_typecomp); + if (FAILED(hr)) return hr; + + hr = ITypeComp_BindType(disp_typecomp, szName, lHashVal, ppTInfo, ppTComp); + ITypeComp_Release(disp_typecomp); + return hr; }
static const ITypeCompVtbl ScriptTypeCompVtbl = {
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/tests/jscript.c | 325 +++++++++++++++++++++++++++++++++++ 1 file changed, 325 insertions(+)
diff --git a/dlls/jscript/tests/jscript.c b/dlls/jscript/tests/jscript.c index 0904374..fa03ee3 100644 --- a/dlls/jscript/tests/jscript.c +++ b/dlls/jscript/tests/jscript.c @@ -44,6 +44,7 @@ #endif
DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0); +DEFINE_GUID(IID_IScriptTypeInfo, 0xc59c6b12, 0xf6c1, 0x11cf, 0x88,0x35, 0x00,0xa0,0xc9,0x11,0xe8,0xb2);
static const CLSID CLSID_JScript = {0xf414c260,0x6ac0,0x11cf,{0xb6,0xd1,0x00,0xaa,0x00,0xbb,0xbb,0x58}}; @@ -274,6 +275,20 @@ static IDispatchEx *get_script_dispatch(IActiveScript *script) return dispex; }
+static void parse_script(IActiveScriptParse *parser, const WCHAR *src) +{ + HRESULT hres; + + SET_EXPECT(OnEnterScript); + SET_EXPECT(OnLeaveScript); + + hres = IActiveScriptParse_ParseScriptText(parser, src, NULL, NULL, NULL, 0, 0, 0, NULL, NULL); + ok(hres == S_OK, "ParseScriptText failed: %08x\n", hres); + + CHECK_CALLED(OnEnterScript); + CHECK_CALLED(OnLeaveScript); +} + #define get_disp_id(a,b,c,d) _get_disp_id(__LINE__,a,b,c,d) static void _get_disp_id(unsigned line, IDispatchEx *dispex, const WCHAR *name, HRESULT exhr, DISPID *id) { @@ -907,6 +922,315 @@ static void test_code_persistence(void) CHECK_CALLED(OnStateChange_CLOSED); }
+static void test_script_typeinfo(void) +{ + static struct + { + const WCHAR *name; + UINT num_args; + } func[] = + { + { L"emptyfn", 0 }, + { L"voidfn", 0 }, + { L"math", 2 }, + { L"foobar", 1 }, + { L"C", 0 }, + { L"funcvar", 2 }, + { L"f1", 1 }, + { L"f2", 1 } + }; + static struct + { + const WCHAR *name; + } var[] = + { + { L"global_var" }, + { L"uninit" }, + { L"obj" } + }; + ITypeInfo *typeinfo, *typeinfo2; + ITypeComp *typecomp, *typecomp2; + IActiveScriptParse *parser; + IDispatchEx *script_disp; + IActiveScript *script; + FUNCDESC *funcdesc; + VARDESC *vardesc; + DESCKIND desckind; + BINDPTR bindptr; + MEMBERID memid; + TYPEATTR *attr; + UINT index; + HRESULT hr; + WCHAR str[64], *names = str; + int i; + + script = create_jscript(); + + hr = IActiveScript_QueryInterface(script, &IID_IActiveScriptParse, (void**)&parser); + ok(hr == S_OK, "Could not get IActiveScriptParse iface: %08x\n", hr); + + SET_EXPECT(GetLCID); + hr = IActiveScript_SetScriptSite(script, &ActiveScriptSite); + ok(hr == S_OK, "SetScriptSite failed: %08x\n", hr); + CHECK_CALLED(GetLCID); + + SET_EXPECT(OnStateChange_INITIALIZED); + hr = IActiveScriptParse_InitNew(parser); + ok(hr == S_OK, "InitNew failed: %08x\n", hr); + CHECK_CALLED(OnStateChange_INITIALIZED); + + SET_EXPECT(OnStateChange_CONNECTED); + hr = IActiveScript_SetScriptState(script, SCRIPTSTATE_CONNECTED); + ok(hr == S_OK, "SetScriptState(SCRIPTSTATE_CONNECTED) failed: %08x\n", hr); + CHECK_CALLED(OnStateChange_CONNECTED); + + parse_script(parser, L"" + "var global_var = 42;\n" + + "function emptyfn() { }\n" + "function voidfn() { return void(0); }\n" + "function math(x, y) { return x - y; }\n" + "function foobar(x) { return "foobar"; }\n" + + "function C() {\n" + " this.x;\n" + " this.strret = function() { return "ret"; }\n" + "}\n" + + "var uninit;\n" + "var obj = new C();\n" + + "var funcvar = function(x, y) { return x * y; };\n" + + "(function() {\n" + " f1 = function infuncexpr(x) { return 1; }\n" + " f2 = function infuncexpr(x) { return 2; }\n" + "})();\n"); + + script_disp = get_script_dispatch(script); + hr = IDispatchEx_QueryInterface(script_disp, &IID_ITypeInfo, (void**)&typeinfo); + ok(hr == E_NOINTERFACE, "QueryInterface(IID_ITypeInfo) returned: %08x\n", hr); + hr = IDispatchEx_GetTypeInfo(script_disp, 1, LOCALE_USER_DEFAULT, &typeinfo); + ok(hr == DISP_E_BADINDEX, "GetTypeInfo returned: %08x\n", hr); + hr = IDispatchEx_GetTypeInfo(script_disp, 0, LOCALE_USER_DEFAULT, &typeinfo); + ok(hr == S_OK, "GetTypeInfo failed: %08x\n", hr); + hr = IDispatchEx_GetTypeInfo(script_disp, 0, LOCALE_USER_DEFAULT, &typeinfo2); + ok(hr == S_OK, "GetTypeInfo failed: %08x\n", hr); + ok(typeinfo != typeinfo2, "TypeInfo was not supposed to be shared.\n"); + ITypeInfo_Release(typeinfo2); + + hr = ITypeInfo_GetTypeAttr(typeinfo, &attr); + ok(hr == S_OK, "GetTypeAttr failed: %08x\n", hr); + ok(IsEqualGUID(&attr->guid, &IID_IScriptTypeInfo), "Unexpected GUID %s\n", wine_dbgstr_guid(&attr->guid)); + ok(attr->lcid == LOCALE_USER_DEFAULT, "Unexpected LCID %u\n", attr->lcid); + ok(attr->memidConstructor == MEMBERID_NIL, "Unexpected constructor memid %u\n", attr->memidConstructor); + ok(attr->memidDestructor == MEMBERID_NIL, "Unexpected destructor memid %u\n", attr->memidDestructor); + ok(attr->cbSizeInstance == 4, "Unexpected cbSizeInstance %u\n", attr->cbSizeInstance); + ok(attr->typekind == TKIND_DISPATCH, "Unexpected typekind %u\n", attr->typekind); + ok(attr->cFuncs == ARRAY_SIZE(func), "Unexpected cFuncs %u\n", attr->cFuncs); + ok(attr->cVars == ARRAY_SIZE(var), "Unexpected cVars %u\n", attr->cVars); + ok(attr->cImplTypes == 1, "Unexpected cImplTypes %u\n", attr->cImplTypes); + ok(attr->cbSizeVft == sizeof(IDispatchVtbl), "Unexpected cbSizeVft %u\n", attr->cbSizeVft); + ok(attr->cbAlignment == 4, "Unexpected cbAlignment %u\n", attr->cbAlignment); + ok(attr->wTypeFlags == TYPEFLAG_FDISPATCHABLE, "Unexpected wTypeFlags 0x%x\n", attr->wTypeFlags); + ok(attr->tdescAlias.vt == VT_EMPTY, "Unexpected tdescAlias.vt %d\n", attr->tdescAlias.vt); + ok(attr->idldescType.wIDLFlags == IDLFLAG_NONE, "Unexpected idldescType.wIDLFlags 0x%x\n", attr->idldescType.wIDLFlags); + ITypeInfo_ReleaseTypeAttr(typeinfo, attr); + + /* GetIDsOfNames looks into the inherited types as well */ + wcscpy(str, L"queryinterface"); + hr = ITypeInfo_GetIDsOfNames(typeinfo, NULL, 1, &memid); + ok(hr == E_INVALIDARG, "GetIDsOfNames returned: %08x\n", hr); + hr = ITypeInfo_GetIDsOfNames(typeinfo, &names, 1, NULL); + ok(hr == E_INVALIDARG, "GetIDsOfNames returned: %08x\n", hr); + hr = ITypeInfo_GetIDsOfNames(typeinfo, &names, 0, &memid); + ok(hr == E_INVALIDARG, "GetIDsOfNames returned: %08x\n", hr); + hr = ITypeInfo_GetIDsOfNames(typeinfo, &names, 1, &memid); + ok(hr == S_OK, "GetIDsOfNames failed: %08x\n", hr); + ok(!lstrcmpW(str, L"queryinterface"), "Unexpected string %s\n", wine_dbgstr_w(str)); + wcscpy(str, L"Math"); + hr = ITypeInfo_GetIDsOfNames(typeinfo, &names, 1, &memid); + ok(hr == S_OK, "GetIDsOfNames failed: %08x\n", hr); + ok(!lstrcmpW(str, L"Math"), "Unexpected string %s\n", wine_dbgstr_w(str)); + + /* Check variable descriptions */ + hr = ITypeInfo_GetVarDesc(typeinfo, 0, NULL); + ok(hr == E_INVALIDARG, "GetVarDesc returned: %08x\n", hr); + hr = ITypeInfo_GetVarDesc(typeinfo, 1337, &vardesc); + ok(hr == TYPE_E_ELEMENTNOTFOUND, "GetVarDesc returned: %08x\n", hr); + for (i = 0; i < ARRAY_SIZE(var); i++) + { + hr = ITypeInfo_GetVarDesc(typeinfo, i, &vardesc); + ok(hr == S_OK, "GetVarDesc(%u) failed: %08x\n", i, hr); + ok(vardesc->memid <= 0xFFFF, "[%u] Unexpected memid 0x%x\n", i, vardesc->memid); + ok(vardesc->lpstrSchema == NULL, "[%u] Unexpected lpstrSchema %p\n", i, vardesc->lpstrSchema); + ok(vardesc->oInst == 0, "[%u] Unexpected oInst %u\n", i, vardesc->oInst); + ok(vardesc->varkind == VAR_DISPATCH, "[%u] Unexpected varkind %d\n", i, vardesc->varkind); + ok(vardesc->wVarFlags == 0, "[%u] Unexpected wVarFlags 0x%x\n", i, vardesc->wVarFlags); + ok(vardesc->elemdescVar.tdesc.vt == VT_VARIANT, + "[%u] Unexpected variable type vt %d (expected %d)\n", i, vardesc->elemdescVar.tdesc.vt, 0); + ok(vardesc->elemdescVar.paramdesc.pparamdescex == NULL, + "[%u] Unexpected variable type pparamdescex %p\n", i, vardesc->elemdescVar.paramdesc.pparamdescex); + ok(vardesc->elemdescVar.paramdesc.wParamFlags == PARAMFLAG_NONE, + "[%u] Unexpected variable type wParamFlags 0x%x\n", i, vardesc->elemdescVar.paramdesc.wParamFlags); + ITypeInfo_ReleaseVarDesc(typeinfo, vardesc); + } + + /* Check function descriptions */ + hr = ITypeInfo_GetFuncDesc(typeinfo, 0, NULL); + ok(hr == E_INVALIDARG, "GetFuncDesc returned: %08x\n", hr); + hr = ITypeInfo_GetFuncDesc(typeinfo, 1337, &funcdesc); + ok(hr == TYPE_E_ELEMENTNOTFOUND, "GetFuncDesc returned: %08x\n", hr); + for (i = 0; i < ARRAY_SIZE(func); i++) + { + hr = ITypeInfo_GetFuncDesc(typeinfo, i, &funcdesc); + ok(hr == S_OK, "GetFuncDesc(%u) failed: %08x\n", i, hr); + ok(funcdesc->memid <= 0xFFFF, "[%u] Unexpected memid 0x%x\n", i, funcdesc->memid); + ok(funcdesc->lprgscode == NULL, "[%u] Unexpected lprgscode %p\n", i, funcdesc->lprgscode); + ok(func[i].num_args ? (funcdesc->lprgelemdescParam != NULL) : (funcdesc->lprgelemdescParam == NULL), + "[%u] Unexpected lprgelemdescParam %p\n", i, funcdesc->lprgelemdescParam); + ok(funcdesc->funckind == FUNC_DISPATCH, "[%u] Unexpected funckind %u\n", i, funcdesc->funckind); + ok(funcdesc->invkind == INVOKE_FUNC, "[%u] Unexpected invkind %u\n", i, funcdesc->invkind); + ok(funcdesc->callconv == CC_STDCALL, "[%u] Unexpected callconv %u\n", i, funcdesc->callconv); + ok(funcdesc->cParams == func[i].num_args, "[%u] Unexpected cParams %d (expected %d)\n", + i, funcdesc->cParams, func[i].num_args); + ok(funcdesc->cParamsOpt == 0, "[%u] Unexpected cParamsOpt %d\n", i, funcdesc->cParamsOpt); + ok(funcdesc->cScodes == 0, "[%u] Unexpected cScodes %d\n", i, funcdesc->cScodes); + ok(funcdesc->wFuncFlags == 0, "[%u] Unexpected wFuncFlags 0x%x\n", i, funcdesc->wFuncFlags); + ok(funcdesc->elemdescFunc.tdesc.vt == VT_VARIANT, + "[%u] Unexpected return type vt %d\n", i, funcdesc->elemdescFunc.tdesc.vt); + ok(funcdesc->elemdescFunc.paramdesc.pparamdescex == NULL, + "[%u] Unexpected return type pparamdescex %p\n", i, funcdesc->elemdescFunc.paramdesc.pparamdescex); + ok(funcdesc->elemdescFunc.paramdesc.wParamFlags == PARAMFLAG_NONE, + "[%u] Unexpected return type wParamFlags 0x%x\n", i, funcdesc->elemdescFunc.paramdesc.wParamFlags); + if (funcdesc->lprgelemdescParam) + for (index = 0; index < funcdesc->cParams; index++) + { + ok(funcdesc->lprgelemdescParam[index].tdesc.vt == VT_VARIANT, + "[%u] Unexpected parameter %u vt %d\n", i, index, funcdesc->lprgelemdescParam[index].tdesc.vt); + ok(funcdesc->lprgelemdescParam[index].paramdesc.pparamdescex == NULL, + "[%u] Unexpected parameter %u pparamdescex %p\n", i, index, funcdesc->lprgelemdescParam[index].paramdesc.pparamdescex); + ok(funcdesc->lprgelemdescParam[index].paramdesc.wParamFlags == PARAMFLAG_NONE, + "[%u] Unexpected parameter %u wParamFlags 0x%x\n", i, index, funcdesc->lprgelemdescParam[index].paramdesc.wParamFlags); + } + ITypeInfo_ReleaseFuncDesc(typeinfo, funcdesc); + } + + /* Test TypeComp Binds */ + hr = ITypeInfo_QueryInterface(typeinfo, &IID_ITypeComp, (void**)&typecomp); + ok(hr == S_OK, "QueryInterface(IID_ITypeComp) failed: %08x\n", hr); + hr = ITypeInfo_GetTypeComp(typeinfo, NULL); + ok(hr == E_INVALIDARG, "GetTypeComp returned: %08x\n", hr); + hr = ITypeInfo_GetTypeComp(typeinfo, &typecomp2); + ok(hr == S_OK, "GetTypeComp failed: %08x\n", hr); + ok(typecomp == typecomp2, "QueryInterface(IID_ITypeComp) and GetTypeComp returned different TypeComps\n"); + ITypeComp_Release(typecomp2); + wcscpy(str, L"not_found"); + hr = ITypeComp_Bind(typecomp, NULL, 0, 0, &typeinfo2, &desckind, &bindptr); + ok(hr == E_INVALIDARG, "Bind returned: %08x\n", hr); + hr = ITypeComp_Bind(typecomp, str, 0, 0, NULL, &desckind, &bindptr); + ok(hr == E_INVALIDARG, "Bind returned: %08x\n", hr); + hr = ITypeComp_Bind(typecomp, str, 0, 0, &typeinfo2, NULL, &bindptr); + ok(hr == E_INVALIDARG, "Bind returned: %08x\n", hr); + hr = ITypeComp_Bind(typecomp, str, 0, 0, &typeinfo2, &desckind, NULL); + ok(hr == E_INVALIDARG, "Bind returned: %08x\n", hr); + hr = ITypeComp_Bind(typecomp, str, 0, 0, &typeinfo2, &desckind, &bindptr); + ok(hr == S_OK, "Bind failed: %08x\n", hr); + ok(desckind == DESCKIND_NONE, "Unexpected desckind %u\n", desckind); + wcscpy(str, L"GLOBAL_VAR"); + hr = ITypeComp_Bind(typecomp, str, 0, INVOKE_FUNC, &typeinfo2, &desckind, &bindptr); + ok(hr == TYPE_E_TYPEMISMATCH, "Bind returned: %08x\n", hr); + ok(!lstrcmpW(str, L"GLOBAL_VAR"), "Unexpected string %s\n", wine_dbgstr_w(str)); + wcscpy(str, L"addRef"); + hr = ITypeComp_Bind(typecomp, str, 0, 0, &typeinfo2, &desckind, &bindptr); + ok(hr == S_OK, "Bind failed: %08x\n", hr); + ok(desckind == DESCKIND_FUNCDESC, "Unexpected desckind %u\n", desckind); + ok(!lstrcmpW(str, L"addRef"), "Unexpected string %s\n", wine_dbgstr_w(str)); + ITypeInfo_ReleaseFuncDesc(typeinfo2, bindptr.lpfuncdesc); + ITypeInfo_Release(typeinfo2); + for (i = 0; i < ARRAY_SIZE(var); i++) + { + wcscpy(str, var[i].name); + hr = ITypeComp_Bind(typecomp, str, 0, INVOKE_PROPERTYGET, &typeinfo2, &desckind, &bindptr); + ok(hr == S_OK, "Bind failed: %08x\n", hr); + ok(desckind == DESCKIND_VARDESC, "Unexpected desckind %u\n", desckind); + ITypeInfo_ReleaseVarDesc(typeinfo2, bindptr.lpvardesc); + ITypeInfo_Release(typeinfo2); + } + for (i = 0; i < ARRAY_SIZE(func); i++) + { + wcscpy(str, func[i].name); + hr = ITypeComp_Bind(typecomp, str, 0, INVOKE_FUNC, &typeinfo2, &desckind, &bindptr); + ok(hr == S_OK, "Bind failed: %08x\n", hr); + ok(desckind == DESCKIND_FUNCDESC, "Unexpected desckind %u\n", desckind); + ITypeInfo_ReleaseFuncDesc(typeinfo2, bindptr.lpfuncdesc); + ITypeInfo_Release(typeinfo2); + } + wcscpy(str, L"JScriptTypeInfo"); + hr = ITypeComp_BindType(typecomp, NULL, 0, &typeinfo2, &typecomp2); + ok(hr == E_INVALIDARG, "BindType returned: %08x\n", hr); + hr = ITypeComp_BindType(typecomp, str, 0, NULL, &typecomp2); + ok(hr == E_INVALIDARG, "BindType returned: %08x\n", hr); + hr = ITypeComp_BindType(typecomp, str, 0, &typeinfo2, NULL); + ok(hr == E_INVALIDARG, "BindType returned: %08x\n", hr); + hr = ITypeComp_BindType(typecomp, str, 0, &typeinfo2, &typecomp2); + ok(hr == S_OK, "BindType failed: %08x\n", hr); + ok(!typeinfo2, "Unexpected TypeInfo %p (expected null)\n", typeinfo2); + ok(!typecomp2, "Unexpected TypeComp %p (expected null)\n", typecomp2); + wcscpy(str, L"C"); + hr = ITypeComp_BindType(typecomp, str, 0, &typeinfo2, &typecomp2); + ok(hr == S_OK, "BindType failed: %08x\n", hr); + ok(!typeinfo2, "Unexpected TypeInfo %p (expected null)\n", typeinfo2); + ok(!typecomp2, "Unexpected TypeComp %p (expected null)\n", typecomp2); + wcscpy(str, L"IDispatch"); + hr = ITypeComp_BindType(typecomp, str, 0, &typeinfo2, &typecomp2); + ok(hr == S_OK, "BindType failed: %08x\n", hr); + ok(!typeinfo2, "Unexpected TypeInfo %p (expected null)\n", typeinfo2); + ok(!typecomp2, "Unexpected TypeComp %p (expected null)\n", typecomp2); + ITypeComp_Release(typecomp); + + /* Updating the script won't update the typeinfo obtained before, + but it will be reflected in any typeinfo obtained afterwards. */ + parse_script(parser, L"" + "var new_var;\n" + "function new_func() { }\n"); + + hr = IDispatchEx_GetTypeInfo(script_disp, 0, LOCALE_USER_DEFAULT, &typeinfo2); + ok(hr == S_OK, "GetTypeInfo failed: %08x\n", hr); + hr = ITypeInfo_GetTypeAttr(typeinfo, &attr); + ok(hr == S_OK, "GetTypeAttr failed: %08x\n", hr); + ok(attr->cFuncs == ARRAY_SIZE(func), "Unexpected cFuncs %u\n", attr->cFuncs); + ok(attr->cVars == ARRAY_SIZE(var), "Unexpected cVars %u\n", attr->cVars); + ITypeInfo_ReleaseTypeAttr(typeinfo, attr); + hr = ITypeInfo_GetTypeAttr(typeinfo2, &attr); + ok(hr == S_OK, "GetTypeAttr failed: %08x\n", hr); + ok(attr->cFuncs == ARRAY_SIZE(func) + 1, "Unexpected cFuncs %u\n", attr->cFuncs); + ok(attr->cVars == ARRAY_SIZE(var) + 1, "Unexpected cVars %u\n", attr->cVars); + ITypeInfo_ReleaseTypeAttr(typeinfo2, attr); + ITypeInfo_Release(typeinfo2); + ITypeInfo_Release(typeinfo); + + /* Adding an identifier that differs only in case gives an error + when retrieving the TypeInfo, even though it is valid jscript. */ + parse_script(parser, L"var NEW_FUNC;\n"); + hr = IDispatchEx_GetTypeInfo(script_disp, 0, LOCALE_USER_DEFAULT, &typeinfo); + ok(hr == TYPE_E_AMBIGUOUSNAME, "GetTypeInfo returned: %08x\n", hr); + + IDispatchEx_Release(script_disp); + IActiveScriptParse_Release(parser); + + SET_EXPECT(OnStateChange_DISCONNECTED); + SET_EXPECT(OnStateChange_INITIALIZED); + SET_EXPECT(OnStateChange_CLOSED); + hr = IActiveScript_Close(script); + ok(hr == S_OK, "Close failed: %08x\n", hr); + CHECK_CALLED(OnStateChange_DISCONNECTED); + CHECK_CALLED(OnStateChange_INITIALIZED); + CHECK_CALLED(OnStateChange_CLOSED); + + IActiveScript_Release(script); +} + static BOOL check_jscript(void) { IActiveScriptProperty *script_prop; @@ -931,6 +1255,7 @@ START_TEST(jscript) test_jscript_uninitializing(); test_aggregation(); test_code_persistence(); + test_script_typeinfo();
trace("Testing JScriptEncode object...\n"); engine_clsid = &CLSID_JScriptEncode;
Hi Gabriel,
On 12/9/19 3:01 PM, Gabriel Ivăncescu wrote:
- if (This == This->ctx->global)
return create_script_typeinfo(This, ppTInfo);
That's not pretty. However, do you depend on jsdisp_t being a script dispatch anywhere? It seems to me that this could be just a generic implementation (although that would need some tests).
Thanks,
Jacek
On 12/9/19 4:54 PM, Jacek Caban wrote:
Hi Gabriel,
On 12/9/19 3:01 PM, Gabriel Ivăncescu wrote:
+ if (This == This->ctx->global) + return create_script_typeinfo(This, ppTInfo);
That's not pretty. However, do you depend on jsdisp_t being a script dispatch anywhere? It seems to me that this could be just a generic implementation (although that would need some tests).
Thanks,
Jacek
Right, I wanted to keep it similar to vbscript. I'll look into adding some tests for it.
But just in case tests show that it applies only to script dispatch, would this current approach work? (i.e. should I resend it?)