diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index 298f7e1af89..e25378e866b 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -128,28 +128,24 @@ static DWORD get_flags(jsdisp_t *This, dispex_prop_t *prop) return prop->flags; } -static const builtin_prop_t *find_builtin_prop(jsdisp_t *This, const WCHAR *name) +static const builtin_prop_t *find_builtin_prop(jsdisp_t *This, const WCHAR *name, BOOL case_insens) { - int min = 0, max, i, r; + int min = 0, max = This->builtin_info->props_cnt-1, i, r; + unsigned version; + + if(case_insens) { + for(i = min; i <= max; i++) + if(!wcsicmp(name, This->builtin_info->props[i].name)) + goto found; + return NULL; + } - max = This->builtin_info->props_cnt-1; while(min <= max) { i = (min+max)/2; r = wcscmp(name, This->builtin_info->props[i].name); - if(!r) { - /* Skip prop if it's available only in higher compatibility mode. */ - unsigned version = (This->builtin_info->props[i].flags & PROPF_VERSION_MASK) - >> PROPF_VERSION_SHIFT; - if(version && version > This->ctx->version) - return NULL; - - /* Skip prop if it's available only in HTML mode and we're not running in HTML mode. */ - if((This->builtin_info->props[i].flags & PROPF_HTML) && !This->ctx->html_mode) - return NULL; - - return This->builtin_info->props + i; - } + if(!r) + goto found; if(r < 0) max = i-1; @@ -158,6 +154,18 @@ static const builtin_prop_t *find_builtin_prop(jsdisp_t *This, const WCHAR *name } return NULL; + +found: + /* Skip prop if it's available only in higher compatibility mode. */ + version = (This->builtin_info->props[i].flags & PROPF_VERSION_MASK) >> PROPF_VERSION_SHIFT; + if(version && version > This->ctx->version) + return NULL; + + /* Skip prop if it's available only in HTML mode and we're not running in HTML mode. */ + if((This->builtin_info->props[i].flags & PROPF_HTML) && !This->ctx->html_mode) + return NULL; + + return This->builtin_info->props + i; } static inline unsigned string_hash(const WCHAR *name) @@ -237,7 +245,7 @@ static dispex_prop_t *alloc_protref(jsdisp_t *This, const WCHAR *name, DWORD ref return ret; } -static HRESULT find_prop_name(jsdisp_t *This, unsigned hash, const WCHAR *name, dispex_prop_t **ret) +static HRESULT find_prop_name(jsdisp_t *This, unsigned hash, const WCHAR *name, BOOL case_insens, dispex_prop_t **ret) { const builtin_prop_t *builtin; unsigned bucket, pos, prev = ~0; @@ -247,7 +255,7 @@ static HRESULT find_prop_name(jsdisp_t *This, unsigned hash, const WCHAR *name, bucket = get_props_idx(This, hash); pos = This->props[bucket].bucket_head; while(pos != ~0) { - if(!wcscmp(name, This->props[pos].name)) { + if(case_insens ? !wcsicmp(name, This->props[pos].name) : !wcscmp(name, This->props[pos].name)) { if(prev != ~0) { This->props[prev].bucket_next = This->props[pos].bucket_next; This->props[pos].bucket_next = This->props[bucket].bucket_head; @@ -262,7 +270,7 @@ static HRESULT find_prop_name(jsdisp_t *This, unsigned hash, const WCHAR *name, pos = This->props[pos].bucket_next; } - builtin = find_builtin_prop(This, name); + builtin = find_builtin_prop(This, name, case_insens); if(builtin) { unsigned flags = builtin->flags; if(flags & PROPF_METHOD) { @@ -272,7 +280,7 @@ static HRESULT find_prop_name(jsdisp_t *This, unsigned hash, const WCHAR *name, if(FAILED(hres)) return hres; - prop = alloc_prop(This, name, PROP_JSVAL, (flags & PROPF_ALL) | PROPF_WRITABLE | PROPF_CONFIGURABLE); + prop = alloc_prop(This, builtin->name, PROP_JSVAL, (flags & PROPF_ALL) | PROPF_WRITABLE | PROPF_CONFIGURABLE); if(!prop) { jsdisp_release(obj); return E_OUTOFMEMORY; @@ -285,7 +293,7 @@ static HRESULT find_prop_name(jsdisp_t *This, unsigned hash, const WCHAR *name, }else if(builtin->setter) flags |= PROPF_WRITABLE; flags &= PROPF_ENUMERABLE | PROPF_WRITABLE | PROPF_CONFIGURABLE; - prop = alloc_prop(This, name, PROP_BUILTIN, flags); + prop = alloc_prop(This, builtin->name, PROP_BUILTIN, flags); if(!prop) return E_OUTOFMEMORY; @@ -318,12 +326,12 @@ static HRESULT find_prop_name(jsdisp_t *This, unsigned hash, const WCHAR *name, return S_OK; } -static HRESULT find_prop_name_prot(jsdisp_t *This, unsigned hash, const WCHAR *name, dispex_prop_t **ret) +static HRESULT find_prop_name_prot(jsdisp_t *This, unsigned hash, const WCHAR *name, BOOL case_insens, dispex_prop_t **ret) { dispex_prop_t *prop, *del=NULL; HRESULT hres; - hres = find_prop_name(This, hash, name, &prop); + hres = find_prop_name(This, hash, name, case_insens, &prop); if(FAILED(hres)) return hres; if(prop && prop->type==PROP_DELETED) { @@ -335,7 +343,7 @@ static HRESULT find_prop_name_prot(jsdisp_t *This, unsigned hash, const WCHAR *n } if(This->prototype) { - hres = find_prop_name_prot(This->prototype, hash, name, &prop); + hres = find_prop_name_prot(This->prototype, hash, name, case_insens, &prop); if(FAILED(hres)) return hres; if(prop && prop->type != PROP_DELETED) { @@ -358,12 +366,12 @@ static HRESULT find_prop_name_prot(jsdisp_t *This, unsigned hash, const WCHAR *n return S_OK; } -static HRESULT ensure_prop_name(jsdisp_t *This, const WCHAR *name, DWORD create_flags, dispex_prop_t **ret) +static HRESULT ensure_prop_name(jsdisp_t *This, const WCHAR *name, DWORD create_flags, BOOL case_insens, dispex_prop_t **ret) { dispex_prop_t *prop; HRESULT hres; - hres = find_prop_name_prot(This, string_hash(name), name, &prop); + hres = find_prop_name_prot(This, string_hash(name), name, case_insens, &prop); if(SUCCEEDED(hres) && (!prop || prop->type == PROP_DELETED)) { TRACE("creating prop %s flags %lx\n", debugstr_w(name), create_flags); @@ -613,7 +621,7 @@ static HRESULT fill_protrefs(jsdisp_t *This) fill_protrefs(This->prototype); for(iter = This->prototype->props; iter < This->prototype->props+This->prototype->prop_cnt; iter++) { - hres = find_prop_name(This, iter->hash, iter->name, &prop); + hres = find_prop_name(This, iter->hash, iter->name, FALSE, &prop); if(FAILED(hres)) return hres; if(!prop || prop->type==PROP_DELETED) { @@ -1532,7 +1540,7 @@ static HRESULT WINAPI DispatchEx_GetDispID(IDispatchEx *iface, BSTR bstrName, DW TRACE("(%p)->(%s %lx %p)\n", This, debugstr_w(bstrName), grfdex, pid); - if(grfdex & ~(fdexNameCaseSensitive|fdexNameEnsure|fdexNameImplicit|FDEX_VERSION_MASK)) { + if(grfdex & ~(fdexNameCaseSensitive|fdexNameCaseInsensitive|fdexNameEnsure|fdexNameImplicit|FDEX_VERSION_MASK)) { FIXME("Unsupported grfdex %lx\n", grfdex); return E_NOTIMPL; } @@ -1678,10 +1686,10 @@ static HRESULT WINAPI DispatchEx_DeleteMemberByName(IDispatchEx *iface, BSTR bst TRACE("(%p)->(%s %lx)\n", This, debugstr_w(bstrName), grfdex); - if(grfdex & ~(fdexNameCaseSensitive|fdexNameEnsure|fdexNameImplicit|FDEX_VERSION_MASK)) + if(grfdex & ~(fdexNameCaseSensitive|fdexNameCaseInsensitive|fdexNameEnsure|fdexNameImplicit|FDEX_VERSION_MASK)) FIXME("Unsupported grfdex %lx\n", grfdex); - hres = find_prop_name(This, string_hash(bstrName), bstrName, &prop); + hres = find_prop_name(This, string_hash(bstrName), bstrName, grfdex & fdexNameCaseInsensitive, &prop); if(FAILED(hres)) return hres; if(!prop) { @@ -1902,7 +1910,7 @@ HRESULT init_dispex_from_constr(jsdisp_t *dispex, script_ctx_t *ctx, const built dispex_prop_t *prop; HRESULT hres; - hres = find_prop_name_prot(constr, string_hash(L"prototype"), L"prototype", &prop); + hres = find_prop_name_prot(constr, string_hash(L"prototype"), L"prototype", FALSE, &prop); if(SUCCEEDED(hres) && prop && prop->type!=PROP_DELETED) { jsval_t val; @@ -1941,9 +1949,9 @@ HRESULT jsdisp_get_id(jsdisp_t *jsdisp, const WCHAR *name, DWORD flags, DISPID * if(jsdisp->extensible && (flags & fdexNameEnsure)) hres = ensure_prop_name(jsdisp, name, PROPF_ENUMERABLE | PROPF_CONFIGURABLE | PROPF_WRITABLE, - &prop); + flags & fdexNameCaseInsensitive, &prop); else - hres = find_prop_name_prot(jsdisp, string_hash(name), name, &prop); + hres = find_prop_name_prot(jsdisp, string_hash(name), name, flags & fdexNameCaseInsensitive, &prop); if(FAILED(hres)) return hres; @@ -1996,7 +2004,7 @@ HRESULT jsdisp_call_name(jsdisp_t *disp, const WCHAR *name, WORD flags, unsigned dispex_prop_t *prop; HRESULT hres; - hres = find_prop_name_prot(disp, string_hash(name), name, &prop); + hres = find_prop_name_prot(disp, string_hash(name), name, FALSE, &prop); if(FAILED(hres)) return hres; @@ -2227,9 +2235,9 @@ HRESULT jsdisp_propput(jsdisp_t *obj, const WCHAR *name, DWORD flags, BOOL throw HRESULT hres; if(obj->extensible) - hres = ensure_prop_name(obj, name, flags, &prop); + hres = ensure_prop_name(obj, name, flags, FALSE, &prop); else - hres = find_prop_name(obj, string_hash(name), name, &prop); + hres = find_prop_name(obj, string_hash(name), name, FALSE, &prop); if(FAILED(hres)) return hres; if(!prop || (prop->type == PROP_DELETED && !obj->extensible)) @@ -2330,7 +2338,7 @@ HRESULT jsdisp_propget_name(jsdisp_t *obj, const WCHAR *name, jsval_t *val) dispex_prop_t *prop; HRESULT hres; - hres = find_prop_name_prot(obj, string_hash(name), name, &prop); + hres = find_prop_name_prot(obj, string_hash(name), name, FALSE, &prop); if(FAILED(hres)) return hres; @@ -2350,7 +2358,7 @@ HRESULT jsdisp_get_idx(jsdisp_t *obj, DWORD idx, jsval_t *r) swprintf(name, ARRAY_SIZE(name), L"%d", idx); - hres = find_prop_name_prot(obj, string_hash(name), name, &prop); + hres = find_prop_name_prot(obj, string_hash(name), name, FALSE, &prop); if(FAILED(hres)) return hres; @@ -2407,7 +2415,7 @@ HRESULT jsdisp_delete_idx(jsdisp_t *obj, DWORD idx) swprintf(buf, ARRAY_SIZE(buf), L"%d", idx); - hres = find_prop_name(obj, string_hash(buf), buf, &prop); + hres = find_prop_name(obj, string_hash(buf), buf, FALSE, &prop); if(FAILED(hres) || !prop) return hres; @@ -2465,7 +2473,7 @@ HRESULT jsdisp_next_prop(jsdisp_t *obj, DISPID id, enum jsdisp_enum_type enum_ty for(i = 0; i < len; i++) { swprintf(name, ARRAY_SIZE(name), L"%d", i); - hres = find_prop_name(obj, string_hash(name), name, &iter); + hres = find_prop_name(obj, string_hash(name), name, FALSE, &iter); if(FAILED(hres)) return hres; } @@ -2514,7 +2522,7 @@ HRESULT disp_delete_name(script_ctx_t *ctx, IDispatch *disp, jsstr_t *name, BOOL return E_OUTOFMEMORY; } - hres = find_prop_name(jsdisp, string_hash(ptr), ptr, &prop); + hres = find_prop_name(jsdisp, string_hash(ptr), ptr, FALSE, &prop); if(prop) { hres = delete_prop(prop, ret); }else { @@ -2561,7 +2569,7 @@ HRESULT jsdisp_get_own_property(jsdisp_t *obj, const WCHAR *name, BOOL flags_onl dispex_prop_t *prop; HRESULT hres; - hres = find_prop_name(obj, string_hash(name), name, &prop); + hres = find_prop_name(obj, string_hash(name), name, FALSE, &prop); if(FAILED(hres)) return hres; @@ -2605,7 +2613,7 @@ HRESULT jsdisp_define_property(jsdisp_t *obj, const WCHAR *name, property_desc_t dispex_prop_t *prop; HRESULT hres; - hres = find_prop_name(obj, string_hash(name), name, &prop); + hres = find_prop_name(obj, string_hash(name), name, FALSE, &prop); if(FAILED(hres)) return hres; diff --git a/dlls/jscript/tests/jscript.c b/dlls/jscript/tests/jscript.c index 872354161fc..03774dac4f3 100644 --- a/dlls/jscript/tests/jscript.c +++ b/dlls/jscript/tests/jscript.c @@ -930,6 +930,124 @@ static void test_aggregation(void) ok(!unk || broken(unk != NULL), "unk = %p\n", unk); } +static void test_case_sens(void) +{ + static const WCHAR *const names[] = { L"abc", L"foo", L"bar", L"mAth", L"evaL" }; + DISPPARAMS dp = { NULL, NULL, 0, 0 }; + IActiveScriptParse *parser; + IActiveScript *script; + EXCEPINFO ei = { 0 }; + IDispatchEx *disp; + DISPID id, id2; + unsigned i; + HRESULT hr; + VARIANT v; + BSTR bstr; + + script = create_jscript(); + + hr = IActiveScript_QueryInterface(script, &IID_IActiveScriptParse, (void**)&parser); + ok(hr == S_OK, "Could not get IActiveScriptParse iface: %08lx\n", hr); + + SET_EXPECT(GetLCID); + hr = IActiveScript_SetScriptSite(script, &ActiveScriptSite); + ok(hr == S_OK, "SetScriptSite failed: %08lx\n", hr); + CHECK_CALLED(GetLCID); + + SET_EXPECT(OnStateChange_INITIALIZED); + hr = IActiveScriptParse_InitNew(parser); + ok(hr == S_OK, "InitNew failed: %08lx\n", hr); + CHECK_CALLED(OnStateChange_INITIALIZED); + + SET_EXPECT(OnStateChange_CONNECTED); + hr = IActiveScript_SetScriptState(script, SCRIPTSTATE_CONNECTED); + ok(hr == S_OK, "SetScriptState(SCRIPTSTATE_CONNECTED) failed: %08lx\n", hr); + CHECK_CALLED(OnStateChange_CONNECTED); + + parse_script(parser, L"var aBc; var abC; function Foo() { }\nFoo.prototype.foo = 13; var Bar = new Foo(); Bar.Foo = 42;"); + disp = get_script_dispatch(script, NULL); + + for(i = 0; i < ARRAY_SIZE(names); i++) { + bstr = SysAllocString(names[i]); + hr = IDispatchEx_GetIDsOfNames(disp, &IID_NULL, &bstr, 1, 0, &id); + ok(hr == DISP_E_UNKNOWNNAME, "GetIDsOfNames(%s) returned %08lx, expected %08lx\n", debugstr_w(bstr), hr, DISP_E_UNKNOWNNAME); + + hr = IDispatchEx_GetDispID(disp, bstr, 0, &id); + ok(hr == DISP_E_UNKNOWNNAME, "GetDispID(%s) returned %08lx, expected %08lx\n", debugstr_w(bstr), hr, DISP_E_UNKNOWNNAME); + + hr = IDispatchEx_GetDispID(disp, bstr, fdexNameCaseInsensitive, &id); + ok(hr == S_OK, "GetDispID(%s) with fdexNameCaseInsensitive failed: %08lx\n", debugstr_w(bstr), hr); + ok(id > 0, "Unexpected DISPID for %s: %ld\n", debugstr_w(bstr), id); + SysFreeString(bstr); + } + + get_disp_id(disp, L"Bar", S_OK, &id); + hr = IDispatchEx_InvokeEx(disp, id, 0, DISPATCH_PROPERTYGET, &dp, &v, &ei, NULL); + ok(hr == S_OK, "InvokeEx failed: %08lx\n", hr); + ok(V_VT(&v) == VT_DISPATCH, "V_VT(v) = %d\n", V_VT(&v)); + ok(V_DISPATCH(&v) != NULL, "V_DISPATCH(v) = NULL\n"); + IDispatchEx_Release(disp); + + hr = IDispatch_QueryInterface(V_DISPATCH(&v), &IID_IDispatchEx, (void**)&disp); + ok(hr == S_OK, "Could not get IDispatchEx iface: %08lx\n", hr); + VariantClear(&v); + + bstr = SysAllocString(L"foo"); + hr = IDispatchEx_GetDispID(disp, bstr, fdexNameCaseSensitive, &id); + ok(hr == S_OK, "GetDispID failed: %08lx\n", hr); + + /* Native picks one "arbitrarily" here, depending how it's laid out, so can't compare exact id */ + hr = IDispatchEx_GetDispID(disp, bstr, fdexNameCaseInsensitive, &id2); + ok(hr == S_OK, "GetDispID failed: %08lx\n", hr); + + hr = IDispatchEx_GetIDsOfNames(disp, &IID_NULL, &bstr, 1, 0, &id2); + ok(hr == S_OK, "GetIDsOfNames failed: %08lx\n", hr); + ok(id == id2, "id != id2\n"); + + hr = IDispatchEx_DeleteMemberByName(disp, bstr, fdexNameCaseInsensitive); + ok(hr == S_OK, "DeleteMemberByName failed: %08lx\n", hr); + + hr = IDispatchEx_GetDispID(disp, bstr, fdexNameCaseInsensitive, &id2); + ok(hr == S_OK, "GetDispID failed: %08lx\n", hr); + ok(id == id2, "id != id2\n"); + + hr = IDispatchEx_GetDispID(disp, bstr, fdexNameCaseInsensitive | fdexNameEnsure, &id2); + ok(hr == S_OK, "GetDispID failed: %08lx\n", hr); + ok(id == id2, "id != id2\n"); + SysFreeString(bstr); + + bstr = SysAllocString(L"fOo"); + hr = IDispatchEx_GetDispID(disp, bstr, fdexNameCaseInsensitive, &id2); + ok(hr == S_OK, "GetDispID failed: %08lx\n", hr); + ok(id == id2, "id != id2\n"); + + hr = IDispatchEx_GetDispID(disp, bstr, fdexNameCaseInsensitive | fdexNameEnsure, &id2); + ok(hr == S_OK, "GetDispID failed: %08lx\n", hr); + ok(id == id2, "id != id2\n"); + + hr = IDispatchEx_GetDispID(disp, bstr, fdexNameEnsure, &id2); + ok(hr == S_OK, "GetDispID failed: %08lx\n", hr); + ok(id != id2, "id == id2\n"); + + hr = IDispatchEx_GetDispID(disp, bstr, fdexNameCaseInsensitive | fdexNameEnsure, &id2); + ok(hr == S_OK, "GetDispID failed: %08lx\n", hr); + SysFreeString(bstr); + + 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: %08lx\n", hr); + CHECK_CALLED(OnStateChange_DISCONNECTED); + CHECK_CALLED(OnStateChange_INITIALIZED); + CHECK_CALLED(OnStateChange_CLOSED); + + IActiveScript_Release(script); +} + static void test_param_ids(void) { static const WCHAR *const names1[] = { L"test", L"c", L"foo", L"b", L"a" }; @@ -2324,6 +2442,7 @@ START_TEST(jscript) test_jscript2(); test_jscript_uninitializing(); test_aggregation(); + test_case_sens(); test_param_ids(); test_code_persistence(); test_named_items(); diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index c18639582d0..bfaacd1bd5b 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -33,6 +33,18 @@ var JS_E_WRONG_THIS = 0x800a13fc; var tests = []; +sync_test("script vars", function() { + function foo() { } + foo.prototype.foo = 13; + var obj = new foo(); + obj.Foo = 42; + obj.aBc = 1; + obj.abC = 2; + obj.Bar = 3; + document.body.foobar = 42; + external.testVars(document.body, obj); +}); + sync_test("date_now", function() { var now = Date.now(); var time = (new Date()).getTime(); diff --git a/dlls/mshtml/tests/script.c b/dlls/mshtml/tests/script.c index 660f62759c9..14e3a148239 100644 --- a/dlls/mshtml/tests/script.c +++ b/dlls/mshtml/tests/script.c @@ -155,6 +155,7 @@ DEFINE_EXPECT(GetTypeInfo); #define DISPID_EXTERNAL_NULL_DISP 0x300008 #define DISPID_EXTERNAL_IS_ENGLISH 0x300009 #define DISPID_EXTERNAL_LIST_SEP 0x30000A +#define DISPID_EXTERNAL_TEST_VARS 0x30000B static const GUID CLSID_TestScript = {0x178fc163,0xf585,0x4e24,{0x9c,0x13,0x4b,0xb7,0xfa,0xf8,0x07,0x46}}; @@ -198,6 +199,95 @@ static BOOL init_key(const char *key_name, const char *def_value, BOOL init) return res == ERROR_SUCCESS; } +static void test_script_vars(unsigned argc, VARIANTARG *argv) +{ + static const WCHAR *const jsobj_names[] = { L"abc", L"foO", L"bar", L"TostRing", L"hasownpropERty" }; + IHTMLBodyElement *body; + IDispatchEx *disp; + DISPID id, id2; + HRESULT hres; + unsigned i; + BSTR bstr; + + ok(argc == 2, "argc = %d\n", argc); + ok(V_VT(&argv[0]) == VT_DISPATCH, "VT = %d\n", V_VT(&argv[0])); + ok(V_VT(&argv[1]) == VT_DISPATCH, "VT = %d\n", V_VT(&argv[1])); + + /* JS object disp */ + hres = IDispatch_QueryInterface(V_DISPATCH(&argv[0]), &IID_IDispatchEx, (void**)&disp); + ok(hres == S_OK, "Could not get IDispatchEx iface: %08lx\n", hres); + + hres = IDispatchEx_QueryInterface(disp, &IID_IHTMLBodyElement, (void**)&body); + ok(hres == E_NOINTERFACE, "Got IHTMLBodyElement iface on JS object? %08lx\n", hres); + + for(i = 0; i < ARRAY_SIZE(jsobj_names); i++) { + bstr = SysAllocString(jsobj_names[i]); + hres = IDispatchEx_GetIDsOfNames(disp, &IID_NULL, &bstr, 1, 0, &id); + ok(hres == DISP_E_UNKNOWNNAME, "GetIDsOfNames(%s) returned %08lx, expected %08lx\n", debugstr_w(bstr), hres, DISP_E_UNKNOWNNAME); + + hres = IDispatchEx_GetDispID(disp, bstr, 0, &id); + ok(hres == DISP_E_UNKNOWNNAME, "GetDispID(%s) returned %08lx, expected %08lx\n", debugstr_w(bstr), hres, DISP_E_UNKNOWNNAME); + + hres = IDispatchEx_GetDispID(disp, bstr, fdexNameCaseInsensitive, &id); + ok(hres == S_OK, "GetDispID(%s) with fdexNameCaseInsensitive failed: %08lx\n", debugstr_w(bstr), hres); + ok(id > 0, "Unexpected DISPID for %s: %ld\n", debugstr_w(bstr), id); + SysFreeString(bstr); + } + + bstr = SysAllocString(L"foo"); + hres = IDispatchEx_GetDispID(disp, bstr, fdexNameCaseSensitive, &id); + ok(hres == S_OK, "GetDispID failed: %08lx\n", hres); + + /* Native picks one "arbitrarily" here, depending how it's laid out, so can't compare exact id */ + hres = IDispatchEx_GetDispID(disp, bstr, fdexNameCaseInsensitive, &id2); + ok(hres == S_OK, "GetDispID failed: %08lx\n", hres); + + hres = IDispatchEx_GetIDsOfNames(disp, &IID_NULL, &bstr, 1, 0, &id2); + ok(hres == S_OK, "GetIDsOfNames failed: %08lx\n", hres); + ok(id == id2, "id != id2\n"); + + hres = IDispatchEx_DeleteMemberByName(disp, bstr, fdexNameCaseInsensitive); + ok(hres == S_OK, "DeleteMemberByName failed: %08lx\n", hres); + + hres = IDispatchEx_GetDispID(disp, bstr, fdexNameCaseInsensitive, &id2); + ok(hres == S_OK, "GetDispID failed: %08lx\n", hres); + ok(id == id2, "id != id2\n"); + + hres = IDispatchEx_GetDispID(disp, bstr, fdexNameCaseInsensitive | fdexNameEnsure, &id2); + ok(hres == S_OK, "GetDispID failed: %08lx\n", hres); + ok(id == id2, "id != id2\n"); + SysFreeString(bstr); + + bstr = SysAllocString(L"fOo"); + hres = IDispatchEx_GetDispID(disp, bstr, fdexNameCaseInsensitive, &id2); + ok(hres == S_OK, "GetDispID failed: %08lx\n", hres); + ok(id == id2, "id != id2\n"); + + hres = IDispatchEx_GetDispID(disp, bstr, fdexNameCaseInsensitive | fdexNameEnsure, &id2); + ok(hres == S_OK, "GetDispID failed: %08lx\n", hres); + ok(id == id2, "id != id2\n"); + + hres = IDispatchEx_GetDispID(disp, bstr, fdexNameEnsure, &id2); + ok(hres == S_OK, "GetDispID failed: %08lx\n", hres); + ok(id != id2, "id == id2\n"); + + hres = IDispatchEx_GetDispID(disp, bstr, fdexNameCaseInsensitive | fdexNameEnsure, &id2); + ok(hres == S_OK, "GetDispID failed: %08lx\n", hres); + SysFreeString(bstr); + + IDispatchEx_Release(disp); + + /* Body element disp */ + hres = IDispatch_QueryInterface(V_DISPATCH(&argv[1]), &IID_IDispatchEx, (void**)&disp); + ok(hres == S_OK, "Could not get IDispatchEx iface: %08lx\n", hres); + + hres = IDispatchEx_QueryInterface(disp, &IID_IHTMLBodyElement, (void**)&body); + ok(hres == S_OK, "Could not get IHTMLBodyElement iface: %08lx\n", hres); + IHTMLBodyElement_Release(body); + + IDispatchEx_Release(disp); +} + static HRESULT WINAPI PropertyNotifySink_QueryInterface(IPropertyNotifySink *iface, REFIID riid, void**ppv) { @@ -609,6 +699,10 @@ static HRESULT WINAPI externalDisp_GetDispID(IDispatchEx *iface, BSTR bstrName, *pid = DISPID_EXTERNAL_LIST_SEP; return S_OK; } + if(!lstrcmpW(bstrName, L"testVars")) { + *pid = DISPID_EXTERNAL_TEST_VARS; + return S_OK; + } ok(0, "unexpected name %s\n", wine_dbgstr_w(bstrName)); return DISP_E_UNKNOWNNAME; @@ -833,6 +927,15 @@ static HRESULT WINAPI externalDisp_InvokeEx(IDispatchEx *iface, DISPID id, LCID return S_OK; } + case DISPID_EXTERNAL_TEST_VARS: + ok(pdp != NULL, "pdp == NULL\n"); + ok(pdp->rgvarg != NULL, "rgvarg == NULL\n"); + ok(!pdp->rgdispidNamedArgs, "rgdispidNamedArgs != NULL\n"); + ok(!pdp->cNamedArgs, "cNamedArgs = %d\n", pdp->cNamedArgs); + ok(pei != NULL, "pei == NULL\n"); + test_script_vars(pdp->cArgs, pdp->rgvarg); + return S_OK; + default: ok(0, "unexpected call\n"); return E_NOTIMPL;