Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com ---
v2: Get rid of special case for global script dispatch. However, source functions are still treated specially, and native/builtin ones ignored (so that patch has been kept).
Tests added to verify both of these behaviors.
dlls/jscript/dispex.c | 264 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 262 insertions(+), 2 deletions(-)
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index 463fd2f..92e9b96 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -590,6 +590,254 @@ 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); @@ -649,8 +897,20 @@ 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); - return E_NOTIMPL; + ScriptTypeInfo *typeinfo; + + TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo); + + if (iTInfo != 0) return DISP_E_BADINDEX; + + if (!(typeinfo = heap_alloc(sizeof(*typeinfo)))) + return E_OUTOFMEMORY; + + typeinfo->ITypeInfo_iface.lpVtbl = &ScriptTypeInfoVtbl; + typeinfo->ref = 1; + + *ppTInfo = &typeinfo->ITypeInfo_iface; + return S_OK; }
static HRESULT WINAPI DispatchEx_GetIDsOfNames(IDispatchEx *iface, REFIID riid,
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 92e9b96..5710fdd 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; @@ -897,17 +929,94 @@ static HRESULT WINAPI DispatchEx_GetTypeInfo(IDispatchEx *iface, UINT iTInfo, LC ITypeInfo **ppTInfo) { jsdisp_t *This = impl_from_IDispatchEx(iface); + 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;
TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
if (iTInfo != 0) return DISP_E_BADINDEX;
+ for (prop = This->props, end = prop + This->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 = This->props[get_props_idx(This, prop->hash)].bucket_head; + while (pos) + { + cur = This->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++; + } + if (!(typeinfo = heap_alloc(sizeof(*typeinfo)))) return E_OUTOFMEMORY;
typeinfo->ITypeInfo_iface.lpVtbl = &ScriptTypeInfoVtbl; typeinfo->ref = 1; + typeinfo->num_vars = num_vars; + typeinfo->num_funcs = num_funcs; + typeinfo->jsdisp = This; + + 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 = This->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(&This->IDispatchEx_iface);
*ppTInfo = &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;
Hi Gabriel,
On 12/9/19 6:12 PM, Gabriel Ivăncescu wrote:
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;
+};
Storing the whole function object reference does not seem right here. Maybe we should store function_code_t instead? We could have a single getter that could replace both is_source_function() and get_source_function_params() from your patches. Such getter should probably use function_vtbl_t for that. Storing bytecode_t pointer inside function_code_t could also be handy for reference tracking.
- for (prop = This->props, end = prop + This->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 = This->props[get_props_idx(This, prop->hash)].bucket_head;
while (pos)
{
cur = This->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;
}
It would be good to limit dispex_prop_t usage inside ITypeInfo in general. IDispatchEx support in jscript deserves pretty deep changes and extending usage of its internal structure may not be helpful. I'm fine with trying to use them here for now, but I'd rather avoid depending on its internals and that's the kind of internal thing I'd rather not have here. We could call GetDispID(fdexNameCaseInsensitive) and compare returned id to current one, if we had support for that. However, is it really important in practice? I wouldn't mind leaving it as FIXME for now.
Thanks,
Jacek
Hi Jacek,
On 12/10/19 7:49 PM, Jacek Caban wrote:
Hi Gabriel,
On 12/9/19 6:12 PM, Gabriel Ivăncescu wrote:
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; +};
Storing the whole function object reference does not seem right here. Maybe we should store function_code_t instead? We could have a single getter that could replace both is_source_function() and get_source_function_params() from your patches. Such getter should probably use function_vtbl_t for that. Storing bytecode_t pointer inside function_code_t could also be handy for reference tracking.
Ah sure, storing the function object seemed the easiest for me. I think I got the hang how this works now after looking at it for a bit longer, so I'll do as you suggested :-)
+ for (prop = This->props, end = prop + This->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 = This->props[get_props_idx(This, prop->hash)].bucket_head; + while (pos) + { + cur = This->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; + }
It would be good to limit dispex_prop_t usage inside ITypeInfo in general. IDispatchEx support in jscript deserves pretty deep changes and extending usage of its internal structure may not be helpful. I'm fine with trying to use them here for now, but I'd rather avoid depending on its internals and that's the kind of internal thing I'd rather not have here. We could call GetDispID(fdexNameCaseInsensitive) and compare returned id to current one, if we had support for that. However, is it really important in practice? I wouldn't mind leaving it as FIXME for now.
Are you referring to the hash lookup? If so, I think this place could be an exception, since it's also part of the DispatchEx_* implementation, anyway, so it shouldn't be an issue using internals.
The main reason is that it simplifies the code. Leaving it as a FIXME would complicate the rest of the code that assumes there are no duplicated names, case insensitively.
I don't think GetDispID(fdexNameCaseInsensitive) would work in all cases: there's a chance that it returns the same DISPID, if it's the first one found. I'm also not sure if it even works on jscript (it might enforce case sensitivity due to language specs, depends on tests).
However, if you were referring to the other usage of prop (such as flags), that's actually quite needed else it will fail to pass the tests since it's not exclusive enough.
IMO, we should keep it this way, since it should be the only "new" place it's used, and it's implemented directly in DispatchEx_GetTypeInfo.
Thanks, Gabriel
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 5710fdd..8c1fc45 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 8c1fc45..e58b285 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 e58b285..5f252fb 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 5f252fb..f7a1a51 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 f7a1a51..3769874 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); @@ -1085,6 +1144,7 @@ static HRESULT WINAPI DispatchEx_GetTypeInfo(IDispatchEx *iface, UINT iTInfo, LC return E_OUTOFMEMORY;
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 3769874..6f0768e 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 6f0768e..3226fb8 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 | 362 +++++++++++++++++++++++++++++++++++ 1 file changed, 362 insertions(+)
diff --git a/dlls/jscript/tests/jscript.c b/dlls/jscript/tests/jscript.c index 0904374..5aaf7ef 100644 --- a/dlls/jscript/tests/jscript.c +++ b/dlls/jscript/tests/jscript.c @@ -33,6 +33,8 @@ #define IActiveScriptParse_Release IActiveScriptParse64_Release #define IActiveScriptParse_InitNew IActiveScriptParse64_InitNew #define IActiveScriptParse_ParseScriptText IActiveScriptParse64_ParseScriptText +#define IActiveScriptParseProcedure2_Release IActiveScriptParseProcedure2_64_Release +#define IActiveScriptParseProcedure2_ParseProcedureText IActiveScriptParseProcedure2_64_ParseProcedureText
#else
@@ -40,10 +42,13 @@ #define IActiveScriptParse_Release IActiveScriptParse32_Release #define IActiveScriptParse_InitNew IActiveScriptParse32_InitNew #define IActiveScriptParse_ParseScriptText IActiveScriptParse32_ParseScriptText +#define IActiveScriptParseProcedure2_Release IActiveScriptParseProcedure2_32_Release +#define IActiveScriptParseProcedure2_ParseProcedureText IActiveScriptParseProcedure2_32_ParseProcedureText
#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 +279,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 +926,347 @@ static void test_code_persistence(void) CHECK_CALLED(OnStateChange_CLOSED); }
+static void test_typeinfo(const WCHAR *parse_func_name) +{ + 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" } + }; + const WCHAR *source = 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" + "var native_func = decodeURI;\n" + + "(function() {\n" + " f1 = function infuncexpr(x) { return 1; }\n" + " f2 = function infuncexpr(x) { return 2; }\n" + "})();\n"; + UINT expected_funcs_cnt = parse_func_name ? 0 : ARRAY_SIZE(func); + UINT expected_vars_cnt = parse_func_name ? 0 : ARRAY_SIZE(var); + + ITypeInfo *typeinfo, *typeinfo2; + ITypeComp *typecomp, *typecomp2; + IActiveScriptParse *parser; + IActiveScript *script; + FUNCDESC *funcdesc; + VARDESC *vardesc; + IDispatchEx *disp; + DESCKIND desckind; + BINDPTR bindptr; + MEMBERID memid; + TYPEATTR *attr; + UINT index; + HRESULT hr; + WCHAR str[64], *names = str; + int i; + + if (parse_func_name) + trace("Testing TypeInfo for function %s...\n", wine_dbgstr_w(parse_func_name)); + else + trace("Testing TypeInfo for script dispatch...\n"); + + 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); + + if (parse_func_name) + { + IActiveScriptParseProcedure2 *parse_proc; + IDispatch *proc_disp; + + hr = IActiveScript_QueryInterface(script, &IID_IActiveScriptParseProcedure2, (void**)&parse_proc); + ok(hr == S_OK, "Could not get IActiveScriptParse: %08x\n", hr); + + hr = IActiveScriptParseProcedure2_ParseProcedureText(parse_proc, source, NULL, L"", NULL, + NULL, NULL, 0, 0, SCRIPTPROC_IMPLICIT_THIS | SCRIPTPROC_IMPLICIT_PARENTS, &proc_disp); + ok(hr == S_OK, "ParseProcedureText failed: %08x\n", hr); + IActiveScriptParseProcedure2_Release(parse_proc); + + hr = IDispatch_QueryInterface(proc_disp, &IID_IDispatchEx, (void**)&disp); + ok(hr == S_OK, "Could not get IDispatchEx: %08x\n", hr); + IDispatch_Release(proc_disp); + } + else + { + parse_script(parser, source); + disp = get_script_dispatch(script); + } + + hr = IDispatchEx_QueryInterface(disp, &IID_ITypeInfo, (void**)&typeinfo); + ok(hr == E_NOINTERFACE, "QueryInterface(IID_ITypeInfo) returned: %08x\n", hr); + hr = IDispatchEx_GetTypeInfo(disp, 1, LOCALE_USER_DEFAULT, &typeinfo); + ok(hr == DISP_E_BADINDEX, "GetTypeInfo returned: %08x\n", hr); + hr = IDispatchEx_GetTypeInfo(disp, 0, LOCALE_USER_DEFAULT, &typeinfo); + ok(hr == S_OK, "GetTypeInfo failed: %08x\n", hr); + hr = IDispatchEx_GetTypeInfo(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 == expected_funcs_cnt, "Unexpected cFuncs %u\n", attr->cFuncs); + ok(attr->cVars == expected_vars_cnt, "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)); + if (expected_funcs_cnt) + { + 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 < expected_vars_cnt; 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 < expected_funcs_cnt; 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"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 < expected_vars_cnt; 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 < expected_funcs_cnt; 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. */ + if (!parse_func_name) + { + parse_script(parser, L"" + "var new_var;\n" + "function new_func() { }\n"); + + hr = IDispatchEx_GetTypeInfo(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 == expected_funcs_cnt, "Unexpected cFuncs %u\n", attr->cFuncs); + ok(attr->cVars == expected_vars_cnt, "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 == expected_funcs_cnt + 1, "Unexpected cFuncs %u\n", attr->cFuncs); + ok(attr->cVars == expected_vars_cnt + 1, "Unexpected cVars %u\n", attr->cVars); + ITypeInfo_ReleaseTypeAttr(typeinfo2, attr); + ITypeInfo_Release(typeinfo2); + + /* 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(disp, 0, LOCALE_USER_DEFAULT, &typeinfo2); + ok(hr == TYPE_E_AMBIGUOUSNAME, "GetTypeInfo returned: %08x\n", hr); + } + + ITypeInfo_Release(typeinfo); + IDispatchEx_Release(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 +1291,8 @@ START_TEST(jscript) test_jscript_uninitializing(); test_aggregation(); test_code_persistence(); + test_typeinfo(NULL); + test_typeinfo(L"some_func_name");
trace("Testing JScriptEncode object...\n"); engine_clsid = &CLSID_JScriptEncode;