-- v2: mshtml: Forward deletion for GLOBAL_SCRIPTVAR to the script's object. mshtml: Check if window global prop still exists before returning its id. mshtml: Override window's element prop directly rather than using mshtml: Use BSTR to store global prop's name. jscript: Add basic semi-stub implementation of GetMemberProperties. mshtml: Throw invalid action for IE8 window prop deletion. mshtml: Reset builtin function props to their default values when deleted.
From: Gabriel Ivăncescu gabrielopcode@gmail.com
The previous tests bailed out too early on IE8, and did not test builtin props. Also added todos for tests that we did not even test because of returning early.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/dispex.c | 62 ++++++++++++++++++++----------- dlls/mshtml/tests/documentmode.js | 47 +++++++++++++++++++---- 2 files changed, 80 insertions(+), 29 deletions(-)
diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index e194024607d..65c54ed8aec 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -1764,6 +1764,26 @@ HRESULT dispex_call_builtin(DispatchEx *dispex, DISPID id, DISPPARAMS *dp, return call_builtin_function(dispex, func, dp, res, ei, caller); }
+static VARIANT_BOOL reset_builtin_func(DispatchEx *dispex, func_info_t *func) +{ + func_obj_entry_t *entry; + + if(!dispex->dynamic_data || !dispex->dynamic_data->func_disps || + !dispex->dynamic_data->func_disps[func->func_disp_idx].func_obj) + return VARIANT_FALSE; + + entry = dispex->dynamic_data->func_disps + func->func_disp_idx; + if(V_VT(&entry->val) == VT_DISPATCH && + V_DISPATCH(&entry->val) == (IDispatch*)&entry->func_obj->dispex.IWineJSDispatchHost_iface) + return VARIANT_FALSE; + + VariantClear(&entry->val); + V_VT(&entry->val) = VT_DISPATCH; + V_DISPATCH(&entry->val) = (IDispatch*)&entry->func_obj->dispex.IWineJSDispatchHost_iface; + IDispatch_AddRef(V_DISPATCH(&entry->val)); + return VARIANT_TRUE; +} + HRESULT remove_attribute(DispatchEx *This, DISPID id, VARIANT_BOOL *success) { switch(get_dispid_type(id)) { @@ -1793,26 +1813,7 @@ HRESULT remove_attribute(DispatchEx *This, DISPID id, VARIANT_BOOL *success)
/* For builtin functions, we set their value to the original function. */ if(func->func_disp_idx >= 0) { - func_obj_entry_t *entry; - - if(!This->dynamic_data || !This->dynamic_data->func_disps - || !This->dynamic_data->func_disps[func->func_disp_idx].func_obj) { - *success = VARIANT_FALSE; - return S_OK; - } - - entry = This->dynamic_data->func_disps + func->func_disp_idx; - if(V_VT(&entry->val) == VT_DISPATCH - && V_DISPATCH(&entry->val) == (IDispatch*)&entry->func_obj->dispex.IWineJSDispatchHost_iface) { - *success = VARIANT_FALSE; - return S_OK; - } - - VariantClear(&entry->val); - V_VT(&entry->val) = VT_DISPATCH; - V_DISPATCH(&entry->val) = (IDispatch*)&entry->func_obj->dispex.IWineJSDispatchHost_iface; - IDispatch_AddRef(V_DISPATCH(&entry->val)); - *success = VARIANT_TRUE; + *success = reset_builtin_func(This, func); return S_OK; } *success = VARIANT_TRUE; @@ -2304,7 +2305,8 @@ static HRESULT dispex_prop_delete(DispatchEx *dispex, DISPID id) return E_NOTIMPL; }
- if(is_dynamic_dispid(id)) { + switch(get_dispid_type(id)) { + case DISPEXPROP_DYNAMIC: { DWORD idx = id - DISPID_DYNPROP_0; dynamic_prop_t *prop;
@@ -2316,6 +2318,24 @@ static HRESULT dispex_prop_delete(DispatchEx *dispex, DISPID id) prop->flags |= DYNPROP_DELETED; return S_OK; } + case DISPEXPROP_BUILTIN: { + func_info_t *func; + HRESULT hres; + + if(!ensure_real_info(dispex)) + return E_OUTOFMEMORY; + + hres = get_builtin_func(dispex->info, id, &func); + if(FAILED(hres)) + return hres; + + if(func->func_disp_idx >= 0) + reset_builtin_func(dispex, func); + return S_OK; + } + default: + break; + }
return S_OK; } diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 306d65e5768..ae5e68126dd 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -1301,7 +1301,7 @@ sync_test("navigator", function() {
sync_test("delete_prop", function() { var v = document.documentMode; - var obj = document.createElement("div"), r, obj2; + var obj = document.createElement("div"), r, obj2, func, prop;
obj.prop1 = true; r = false; @@ -1317,6 +1317,40 @@ sync_test("delete_prop", function() { ok(!r, "got an unexpected exception"); ok(!("prop1" in obj), "prop1 is still in obj");
+ /* builtin properties don't throw any exception, but are not really deleted */ + r = (delete obj.tagName); + ok(r, "delete returned " + r); + ok("tagName" in obj, "tagName deleted from obj"); + ok(obj.tagName === "DIV", "tagName = " + obj.tagName); + + prop = obj.id; + r = (delete obj.id); + ok(r, "delete returned " + r); + ok("id" in obj, "id deleted from obj"); + ok(obj.id === prop, "id = " + obj.id); + + obj.id = "1234"; + ok(obj.id === "1234", "id after set to 1234 = " + obj.id); + r = (delete obj.id); + ok(r, "delete returned " + r); + ok("id" in obj, "id deleted from obj"); + ok(obj.id === "1234", "id = " + obj.id); + + /* builtin functions get reset to their original values */ + func = function() { } + prop = obj.setAttribute; + r = (delete obj.setAttribute); + ok(r, "delete returned " + r); + ok("setAttribute" in obj, "setAttribute deleted from obj"); + ok(obj.setAttribute === prop, "setAttribute = " + obj.setAttribute); + + obj.setAttribute = func; + ok(obj.setAttribute === func, "setAttribute after set to func = " + obj.setAttribute); + r = (delete obj.setAttribute); + ok(r, "delete returned " + r); + ok("setAttribute" in obj, "setAttribute deleted from obj"); + ok(obj.setAttribute === prop, "setAttribute = " + obj.setAttribute); + /* again, this time prop1 does not exist */ r = false; try { @@ -1326,7 +1360,6 @@ sync_test("delete_prop", function() { } if(v < 9) { ok(r, "did not get an expected exception"); - return; }else { ok(!r, "got an unexpected exception"); ok(!("prop1" in obj), "prop1 is still in obj"); @@ -1337,12 +1370,6 @@ sync_test("delete_prop", function() { ok("className" in obj, "className deleted from obj"); ok(obj.className === "", "className = " + obj.className);
- /* builtin propertiles don't throw any exception, but are not really deleted */ - r = (delete obj.tagName); - ok(r, "delete returned " + r); - ok("tagName" in obj, "tagName deleted from obj"); - ok(obj.tagName === "DIV", "tagName = " + obj.tagName); - obj = document.querySelectorAll("*"); ok("0" in obj, "0 is not in obj"); obj2 = obj[0]; @@ -1362,6 +1389,7 @@ sync_test("delete_prop", function() { r = true; } if(v < 9) { + todo_wine. ok(r, "did not get an expected exception"); }else { ok(!r, "got an unexpected globalprop1 exception"); @@ -1377,6 +1405,7 @@ sync_test("delete_prop", function() { r = true; } if(v < 9) { + todo_wine. ok(r, "did not get an expected globalprop2 exception"); }else { ok(!r, "got an unexpected exception"); @@ -1393,7 +1422,9 @@ sync_test("delete_prop", function() { r = true; } if(v < 9) { + todo_wine. ok(r, "did not get an expected exception"); + todo_wine. ok("globalprop3" in obj, "globalprop3 is not in obj"); }else { ok(!r, "got an unexpected globalprop3 exception");
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Instead of E_NOTIMPL.
We can't use the dispex's delete because it also applies to dynamic and builtin props and it also happens too late when deleting by name (after looking it up), where existing tests show it doesn't look up the dispid at all.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmlwindow.c | 16 ++++++++++++++++ dlls/mshtml/tests/documentmode.js | 22 ++++++++++++++++++---- 2 files changed, 34 insertions(+), 4 deletions(-)
diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index a4039ce08bc..731acd61cd7 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -3364,18 +3364,34 @@ static HRESULT WINAPI WindowDispEx_InvokeEx(IWineJSDispatchHost *iface, DISPID i static HRESULT WINAPI WindowDispEx_DeleteMemberByName(IWineJSDispatchHost *iface, BSTR bstrName, DWORD grfdex) { HTMLOuterWindow *This = impl_from_IWineJSDispatchHost(iface); + compat_mode_t compat_mode = dispex_compat_mode(&This->base.inner_window->event_target.dispex);
TRACE("(%p)->(%s %lx)\n", This, debugstr_w(bstrName), grfdex);
+ if(compat_mode < COMPAT_MODE_IE8) { + /* Not implemented by IE */ + return E_NOTIMPL; + } + if(compat_mode == COMPAT_MODE_IE8) + return MSHTML_E_INVALID_ACTION; + return IWineJSDispatchHost_DeleteMemberByName(&This->base.inner_window->event_target.dispex.IWineJSDispatchHost_iface, bstrName, grfdex); }
static HRESULT WINAPI WindowDispEx_DeleteMemberByDispID(IWineJSDispatchHost *iface, DISPID id) { HTMLOuterWindow *This = impl_from_IWineJSDispatchHost(iface); + compat_mode_t compat_mode = dispex_compat_mode(&This->base.inner_window->event_target.dispex);
TRACE("(%p)->(%lx)\n", This, id);
+ if(compat_mode < COMPAT_MODE_IE8) { + /* Not implemented by IE */ + return E_NOTIMPL; + } + if(compat_mode == COMPAT_MODE_IE8) + return MSHTML_E_INVALID_ACTION; + return IWineJSDispatchHost_DeleteMemberByDispID(&This->base.inner_window->event_target.dispex.IWineJSDispatchHost_iface, id); }
diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index ae5e68126dd..53372ac7752 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -1380,16 +1380,31 @@ sync_test("delete_prop", function() { /* test window object and its global scope handling */ obj = window;
+ ok("encodeURIComponent" in obj, "encodeURIComponent not in obj"); + try { + prop = window.encodeURIComponent; + r = (delete window.encodeURIComponent); + ok(v >= 9, "did not get an expect exception deleting encodeURIComponent"); + ok(r, "delete returned " + r); + todo_wine. + ok(!("encodeURIComponent" in obj), "encodeURIComponent is still in obj"); + window.encodeURIComponent = prop; + }catch(ex) { + ok(v < 9, "expected exception deleting encodeURIComponent"); + ok(ex.number === 0xa01bd - 0x80000000, "deleting encodeURIComponent threw " + ex.number); + ok("encodeURIComponent" in obj, "encodeURIComponent is not in obj"); + } + obj.globalprop1 = true; ok(globalprop1, "globalprop1 = " + globalprop1); r = false; try { delete obj.globalprop1; }catch(ex) { + ok(ex.number === 0xa01bd - 0x80000000, "deleting globalprop1 threw " + ex.number); r = true; } if(v < 9) { - todo_wine. ok(r, "did not get an expected exception"); }else { ok(!r, "got an unexpected globalprop1 exception"); @@ -1402,10 +1417,10 @@ sync_test("delete_prop", function() { try { delete obj.globalprop2; }catch(ex) { + ok(ex.number === 0xa01bd - 0x80000000, "deleting globalprop2 threw " + ex.number); r = true; } if(v < 9) { - todo_wine. ok(r, "did not get an expected globalprop2 exception"); }else { ok(!r, "got an unexpected exception"); @@ -1419,12 +1434,11 @@ sync_test("delete_prop", function() { try { delete globalprop3; }catch(ex) { + ok(ex.number === 0xa01bd - 0x80000000, "deleting globalprop3 threw " + ex.number); r = true; } if(v < 9) { - todo_wine. ok(r, "did not get an expected exception"); - todo_wine. ok("globalprop3" in obj, "globalprop3 is not in obj"); }else { ok(!r, "got an unexpected globalprop3 exception");
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Also add tests for GetMemberName and DeleteMemberBy* which we did not have.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/dispex.c | 17 ++++++++- dlls/jscript/tests/run.c | 80 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+), 2 deletions(-)
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index 91fa2c00cf4..7d5ebe2c863 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -2322,8 +2322,21 @@ static HRESULT WINAPI DispatchEx_DeleteMemberByDispID(IWineJSDispatch *iface, DI static HRESULT WINAPI DispatchEx_GetMemberProperties(IWineJSDispatch *iface, DISPID id, DWORD grfdexFetch, DWORD *pgrfdex) { jsdisp_t *This = impl_from_IWineJSDispatch(iface); - FIXME("(%p)->(%lx %lx %p)\n", This, id, grfdexFetch, pgrfdex); - return E_NOTIMPL; + dispex_prop_t *prop; + + TRACE("(%p)->(%lx %lx %p)\n", This, id, grfdexFetch, pgrfdex); + + prop = get_prop(This, id); + if(!prop) + return DISP_E_MEMBERNOTFOUND; + *pgrfdex = 0; + + if(grfdexFetch) { + FIXME("unimplemented flags %08lx\n", grfdexFetch); + return E_NOTIMPL; + } + + return S_OK; }
static HRESULT WINAPI DispatchEx_GetMemberName(IWineJSDispatch *iface, DISPID id, BSTR *pbstrName) diff --git a/dlls/jscript/tests/run.c b/dlls/jscript/tests/run.c index 1a92dca6dbb..106fd8c99d4 100644 --- a/dlls/jscript/tests/run.c +++ b/dlls/jscript/tests/run.c @@ -3641,6 +3641,85 @@ static void test_invokeex(void) IActiveScript_Release(script); }
+static void test_members(void) +{ + DISPID func_id, prop_id; + IActiveScript *script; + IDispatchEx *dispex; + DWORD propflags; + HRESULT hres; + VARIANT v; + BSTR str; + + hres = parse_script_expr(L"var o = { func: function() {}, prop: 1 }; o", &v, &script); + ok(hres == S_OK, "parse_script_expr failed: %08lx\n", hres); + ok(V_VT(&v) == VT_DISPATCH, "V_VT(v) = %d\n", V_VT(&v)); + + hres = IDispatch_QueryInterface(V_DISPATCH(&v), &IID_IDispatchEx, (void**)&dispex); + ok(hres == S_OK, "Could not get IDispatchEx iface: %08lx\n", hres); + VariantClear(&v); + + str = SysAllocString(L"func"); + hres = IDispatchEx_GetDispID(dispex, str, 0, &func_id); + SysFreeString(str); + ok(hres == S_OK, "GetDispID failed: %08lx\n", hres); + + str = SysAllocString(L"prop"); + hres = IDispatchEx_GetDispID(dispex, str, 0, &prop_id); + SysFreeString(str); + ok(hres == S_OK, "GetDispID failed: %08lx\n", hres); + + hres = IDispatchEx_GetMemberName(dispex, func_id, &str); + ok(hres == S_OK, "GetMemberName failed: %08lx\n", hres); + ok(!wcscmp(str, L"func"), "GetMemberName returned %s\n", wine_dbgstr_w(str)); + SysFreeString(str); + + hres = IDispatchEx_GetMemberName(dispex, prop_id, &str); + ok(hres == S_OK, "GetMemberName failed: %08lx\n", hres); + ok(!wcscmp(str, L"prop"), "GetMemberName returned %s\n", wine_dbgstr_w(str)); + SysFreeString(str); + + propflags = 0xdeadbeef; + hres = IDispatchEx_GetMemberProperties(dispex, func_id, 0, &propflags); + ok(hres == S_OK, "GetMemberProperties failed: %08lx\n", hres); + ok(propflags == 0, "propflags = %08lx", propflags); + + propflags = 0xdeadbeef; + hres = IDispatchEx_GetMemberProperties(dispex, prop_id, 0, &propflags); + ok(hres == S_OK, "GetMemberProperties failed: %08lx\n", hres); + ok(propflags == 0, "propflags = %08lx", propflags); + + hres = IDispatchEx_DeleteMemberByDispID(dispex, func_id); + ok(hres == S_OK, "DeleteMemberByDispID failed: %08lx\n", hres); + + hres = IDispatchEx_GetMemberName(dispex, func_id, &str); + ok(hres == DISP_E_MEMBERNOTFOUND, "GetMemberName failed: %08lx\n", hres); + hres = IDispatchEx_GetMemberProperties(dispex, func_id, 0, &propflags); + ok(hres == DISP_E_MEMBERNOTFOUND, "GetMemberProperties failed: %08lx\n", hres); + + hres = IDispatchEx_GetMemberName(dispex, prop_id, &str); + ok(hres == S_OK, "GetMemberName failed: %08lx\n", hres); + ok(!wcscmp(str, L"prop"), "GetMemberName returned %s\n", wine_dbgstr_w(str)); + SysFreeString(str); + propflags = 0xdeadbeef; + hres = IDispatchEx_GetMemberProperties(dispex, prop_id, 0, &propflags); + ok(hres == S_OK, "GetMemberProperties failed: %08lx\n", hres); + ok(propflags == 0, "propflags = %08lx", propflags); + + str = SysAllocString(L"prop"); + hres = IDispatchEx_DeleteMemberByName(dispex, str, 0); + ok(hres == S_OK, "DeleteMemberByName failed: %08lx\n", hres); + SysFreeString(str); + + hres = IDispatchEx_GetMemberName(dispex, prop_id, &str); + ok(hres == DISP_E_MEMBERNOTFOUND, "GetMemberName failed: %08lx\n", hres); + hres = IDispatchEx_GetMemberProperties(dispex, prop_id, 0, &propflags); + ok(hres == DISP_E_MEMBERNOTFOUND, "GetMemberProperties failed: %08lx\n", hres); + + IDispatchEx_Release(dispex); + IActiveScript_Release(script); +} + static void test_destructors(void) { static const WCHAR cyclic_refs[] = L"(function() {\n" @@ -4299,6 +4378,7 @@ static BOOL run_tests(void)
test_script_exprs(); test_invokeex(); + test_members(); test_destructors(); test_eval(); test_error_reports();
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmlwindow.c | 4 ++-- dlls/mshtml/mshtml_private.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index 731acd61cd7..8a7119c5451 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -3302,7 +3302,7 @@ static global_prop_t *alloc_global_prop(HTMLInnerWindow *This, global_prop_type_ This->global_prop_size = new_size; }
- This->global_props[This->global_prop_cnt].name = wcsdup(name); + This->global_props[This->global_prop_cnt].name = SysAllocString(name); if(!This->global_props[This->global_prop_cnt].name) return NULL;
@@ -3779,7 +3779,7 @@ static void HTMLWindow_destructor(DispatchEx *dispex) VariantClear(&This->performance);
for(i = 0; i < This->global_prop_cnt; i++) - free(This->global_props[i].name); + SysFreeString(This->global_props[i].name); free(This->global_props);
if(This->mon) diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index b006202befd..591bb3eddd1 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -656,7 +656,7 @@ typedef enum {
typedef struct { global_prop_type_t type; - WCHAR *name; + BSTR name; ScriptHost *script_host; DISPID id; } global_prop_t;
From: Gabriel Ivăncescu gabrielopcode@gmail.com
When GLOBAL_DISPEXVAR is used, we store the id of the dynamic prop and invoke it using the same id. But this is not the case if we have a jsdisp, which is redirected from InvokeEx and results in an invalid id.
The actual way this works on native (in IE9+) is that element/frame props are special and not part of the window object at all. They're actually looked up after the prototype is, in a special way, but that requires a revamp. Storing over it just creates an actual prop on the window (which is what we are doing here).
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com ---
This is necessary in next patch (and tested). --- dlls/jscript/dispex.c | 8 +++++++- dlls/mshtml/htmlwindow.c | 3 +++ 2 files changed, 10 insertions(+), 1 deletion(-)
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index 7d5ebe2c863..aa81de7ad75 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -656,7 +656,13 @@ static HRESULT prop_put(jsdisp_t *This, dispex_prop_t *prop, jsval_t val) TRACE("no prop_put\n"); return S_OK; } - return This->builtin_info->prop_put(This, prop->u.id, val); + hres = This->builtin_info->prop_put(This, prop->u.id, val); + if(hres != S_FALSE) + return hres; + prop->type = PROP_JSVAL; + prop->flags = PROPF_ENUMERABLE | PROPF_CONFIGURABLE | PROPF_WRITABLE; + prop->u.val = jsval_undefined(); + break; default: ERR("type %d\n", prop->type); return E_FAIL; diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index 8a7119c5451..1343c75ba34 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -3926,6 +3926,9 @@ HRESULT HTMLWindow_invoke(DispatchEx *dispex, DISPID id, LCID lcid, WORD flags, case DISPATCH_PROPERTYPUT: { DISPID dispex_id;
+ if(This->event_target.dispex.jsdisp) + return S_FALSE; + hres = dispex_get_dynid(&This->event_target.dispex, prop->name, TRUE, &dispex_id); if(FAILED(hres)) return hres;
From: Gabriel Ivăncescu gabrielopcode@gmail.com
We have to introduce special handling for jscript, as it's probably integrated on native mshtml.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmlscript.h | 1 + dlls/mshtml/htmlwindow.c | 6 ++- dlls/mshtml/script.c | 57 +++++++++++++++++++++ dlls/mshtml/tests/documentmode.js | 83 ++++++++++++++++++++++++++++++- 4 files changed, 144 insertions(+), 3 deletions(-)
diff --git a/dlls/mshtml/htmlscript.h b/dlls/mshtml/htmlscript.h index 6d608d525a1..30b46677395 100644 --- a/dlls/mshtml/htmlscript.h +++ b/dlls/mshtml/htmlscript.h @@ -48,6 +48,7 @@ IDispatch *script_parse_event(HTMLInnerWindow*,LPCWSTR); HRESULT exec_script(HTMLInnerWindow*,const WCHAR*,const WCHAR*,VARIANT*); void update_browser_script_mode(GeckoBrowser*,IUri*); BOOL find_global_prop(HTMLInnerWindow*,const WCHAR*,DWORD,ScriptHost**,DISPID*); +HRESULT global_prop_still_exists(HTMLInnerWindow*,global_prop_t*); IDispatch *get_script_disp(ScriptHost*); IActiveScriptSite *get_first_script_site(HTMLInnerWindow*); void initialize_script_global(HTMLInnerWindow*); diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index 1343c75ba34..d9ecf9d3d29 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -3324,8 +3324,10 @@ HRESULT search_window_props(HTMLInnerWindow *This, const WCHAR *name, DWORD grfd for(i=0; i < This->global_prop_cnt; i++) { /* FIXME: case sensitivity */ if(!wcscmp(This->global_props[i].name, name)) { - *pid = MSHTML_DISPID_CUSTOM_MIN+i; - return S_OK; + HRESULT hres = global_prop_still_exists(This, &This->global_props[i]); + if(hres == S_OK) + *pid = MSHTML_DISPID_CUSTOM_MIN + i; + return (hres == DISP_E_MEMBERNOTFOUND) ? DISP_E_UNKNOWNNAME : hres; } }
diff --git a/dlls/mshtml/script.c b/dlls/mshtml/script.c index 7ac26e63a3b..73bb8e1d5c6 100644 --- a/dlls/mshtml/script.c +++ b/dlls/mshtml/script.c @@ -85,6 +85,7 @@ struct ScriptHost { SCRIPTSTATE script_state;
HTMLInnerWindow *window; + IDispatchEx *script_dispex;
GUID guid; struct list entry; @@ -255,6 +256,18 @@ static BOOL init_script_engine(ScriptHost *script_host, IActiveScript *script) if(is_second_init) set_script_prop(first_host->script, SCRIPTPROP_ABBREVIATE_GLOBALNAME_RESOLUTION, &var); } + + if(IsEqualGUID(&script_host->guid, &CLSID_JScript)) { + IDispatch *script_disp; + + hres = IActiveScript_GetScriptDispatch(script, NULL, &script_disp); + if(FAILED(hres)) + WARN("GetScriptDispatch failed: %08lx\n", hres); + else { + IDispatch_QueryInterface(script_disp, &IID_IDispatchEx, (void**)&script_host->script_dispex); + IDispatch_Release(script_disp); + } + } }else { WARN("AddNamedItem failed: %08lx\n", hres); } @@ -288,6 +301,8 @@ static void release_script_engine(ScriptHost *This) unlink_ref(&This->parse); }
+ if(This->script_dispex) + IDispatchEx_Release(This->script_dispex); IActiveScript_Release(This->script); This->script = NULL; This->script_state = SCRIPTSTATE_UNINITIALIZED; @@ -1825,6 +1840,48 @@ BOOL find_global_prop(HTMLInnerWindow *window, const WCHAR *name, DWORD flags, S return FALSE; }
+HRESULT global_prop_still_exists(HTMLInnerWindow *window, global_prop_t *prop) +{ + HRESULT hres; + + switch(prop->type) { + case GLOBAL_SCRIPTVAR: { + DWORD properties; + + if(!prop->script_host->script) + return E_UNEXPECTED; + if(!prop->script_host->script_dispex) + return S_OK; + return IDispatchEx_GetMemberProperties(prop->script_host->script_dispex, prop->id, 0, &properties); + } + case GLOBAL_ELEMENTVAR: { + IHTMLElement *elem; + + hres = IHTMLDocument3_getElementById(&window->doc->IHTMLDocument3_iface, prop->name, &elem); + if(FAILED(hres)) + return hres; + + if(!elem) + return DISP_E_MEMBERNOTFOUND; + IHTMLElement_Release(elem); + return S_OK; + } + case GLOBAL_FRAMEVAR: { + HTMLOuterWindow *frame; + + hres = get_frame_by_name(window->base.outer_window, prop->name, FALSE, &frame); + if(FAILED(hres)) + return hres; + + return frame ? S_OK : DISP_E_MEMBERNOTFOUND; + } + default: + break; + } + + return S_OK; +} + static BOOL is_jscript_available(void) { static BOOL available, checked; diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 53372ac7752..ca89fdadbdb 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -1449,8 +1449,89 @@ sync_test("delete_prop", function() { ok(obj.globalprop4, "globalprop4 = " + globalprop4); r = (delete globalprop4); ok(r, "delete returned " + r); - todo_wine. ok(!("globalprop4" in obj), "globalprop4 is still in obj"); + + globalprop5 = true; + ok(obj.globalprop5, "globalprop5 = " + globalprop5); + try { + r = (delete window.globalprop5); + ok(v >= 9, "did not get an expected exception deleting globalprop5"); + ok(r, "delete returned " + r); + todo_wine. + ok(!("globalprop5" in obj), "globalprop5 is still in obj"); + }catch(ex) { + ok(v < 9, "expected exception deleting globalprop5"); + ok(ex.number === 0xa01bd - 0x80000000, "deleting globalprop5 threw " + ex.number); + ok("globalprop5" in obj, "globalprop5 is not in obj"); + } + + document.body.innerHTML = '<div id="winetest"/>'; + ok("winetest" in obj, "winetest not in obj"); + try { + r = (delete window.winetest); + ok(v >= 9, "did not get an expected exception deleting winetest"); + ok(r, "delete returned " + r); + }catch(ex) { + ok(v < 9, "expected exception deleting winetest"); + ok(ex.number === 0xa01bd - 0x80000000, "deleting winetest threw " + ex.number); + } + ok("winetest" in obj, "winetest is not in obj"); + document.body.innerHTML = ""; + ok(!("winetest" in obj), "winetest is still in obj"); + + document.body.innerHTML = '<div id="foobar"/>'; + ok("foobar" in obj, "foobar not in obj"); + window.foobar = "1234"; + ok(obj.foobar === "1234", "foobar = " + obj.foobar); + document.body.innerHTML = ""; + ok("foobar" in obj, "foobar is not in obj"); + ok(obj.foobar === "1234", "foobar = " + obj.foobar); + try { + r = (delete window.foobar); + ok(v >= 9, "did not get an expected exception deleting foobar"); + ok(r, "delete returned " + r); + ok(!("foobar" in obj), "foobar is still in obj"); + }catch(ex) { + ok(v < 9, "expected exception deleting foobar"); + ok(ex.number === 0xa01bd - 0x80000000, "deleting foobar threw " + ex.number); + ok("foobar" in obj, "foobar is not in obj"); + } + + document.body.innerHTML = '<div id="barfoo"/>'; + ok("barfoo" in obj, "barfoo not in obj"); + window.barfoo = "5678"; + ok(obj.barfoo === "5678", "barfoo = " + obj.barfoo); + try { + r = (delete window.barfoo); + ok(v >= 9, "did not get an expected exception deleting barfoo"); + ok(r, "delete returned " + r); + ok(obj.barfoo !== "5678", "barfoo is still 5678"); + }catch(ex) { + ok(v < 9, "expected exception deleting barfoo"); + ok(ex.number === 0xa01bd - 0x80000000, "deleting barfoo threw " + ex.number); + ok(obj.barfoo === "5678", "barfoo = " + obj.barfoo); + } + ok("barfoo" in obj, "barfoo is not in obj"); + document.body.innerHTML = ""; + if(v < 9) + ok("barfoo" in obj, "barfoo is not in obj"); + else + ok(!("barfoo" in obj), "barfoo is still in obj"); + + document.body.innerHTML = '<iframe id="testwine"/>'; + ok("testwine" in obj, "testwine not in obj"); + try { + r = (delete window.testwine); + ok(v >= 9, "did not get an expected exception deleting testwine"); + ok(r, "delete returned " + r); + }catch(ex) { + ok(v < 9, "expected exception deleting testwine"); + ok(ex.number === 0xa01bd - 0x80000000, "deleting testwine threw " + ex.number); + } + ok("testwine" in obj, "testwine is not in obj"); + + document.body.innerHTML = ""; + ok(!("testwine" in obj), "testwine is still in obj"); });
sync_test("detached arguments", function() {
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmlwindow.c | 39 +++++++++++++++++++++++++++++++ dlls/mshtml/tests/documentmode.js | 3 --- 2 files changed, 39 insertions(+), 3 deletions(-)
diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index d9ecf9d3d29..b6f66627dd9 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -3974,6 +3974,44 @@ HRESULT HTMLWindow_invoke(DispatchEx *dispex, DISPID id, LCID lcid, WORD flags, return hres; }
+static HRESULT HTMLWindow_delete(DispatchEx *dispex, DISPID id) +{ + HTMLInnerWindow *This = impl_from_DispatchEx(dispex); + DWORD idx = id - MSHTML_DISPID_CUSTOM_MIN; + global_prop_t *prop; + HRESULT hres = S_OK; + + if(idx >= This->global_prop_cnt) + return DISP_E_MEMBERNOTFOUND; + + prop = This->global_props + idx; + switch(prop->type) { + case GLOBAL_SCRIPTVAR: { + IDispatchEx *iface; + IDispatch *disp; + + disp = get_script_disp(prop->script_host); + if(!disp) + return E_UNEXPECTED; + + hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&iface); + if(SUCCEEDED(hres)) { + hres = IDispatchEx_DeleteMemberByDispID(iface, prop->id); + IDispatchEx_Release(iface); + }else { + WARN("No IDispatchEx, so can't delete\n"); + hres = S_OK; + } + IDispatch_Release(disp); + break; + } + default: + break; + } + + return hres; +} + static HRESULT HTMLWindow_next_dispid(DispatchEx *dispex, DISPID id, DISPID *pid) { DWORD idx = (id == DISPID_STARTENUM) ? 0 : id - MSHTML_DISPID_CUSTOM_MIN + 1; @@ -4200,6 +4238,7 @@ static const event_target_vtbl_t HTMLWindow_event_target_vtbl = { .lookup_dispid = HTMLWindow_lookup_dispid, .find_dispid = HTMLWindow_find_dispid, .invoke = HTMLWindow_invoke, + .delete = HTMLWindow_delete, .next_dispid = HTMLWindow_next_dispid, .get_prop_desc = HTMLWindow_get_prop_desc, .get_script_global = HTMLWindow_get_script_global, diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index ca89fdadbdb..0ee20de7a90 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -1386,7 +1386,6 @@ sync_test("delete_prop", function() { r = (delete window.encodeURIComponent); ok(v >= 9, "did not get an expect exception deleting encodeURIComponent"); ok(r, "delete returned " + r); - todo_wine. ok(!("encodeURIComponent" in obj), "encodeURIComponent is still in obj"); window.encodeURIComponent = prop; }catch(ex) { @@ -1424,7 +1423,6 @@ sync_test("delete_prop", function() { ok(r, "did not get an expected globalprop2 exception"); }else { ok(!r, "got an unexpected exception"); - todo_wine. ok(!("globalprop2" in obj), "globalprop2 is still in obj"); }
@@ -1457,7 +1455,6 @@ sync_test("delete_prop", function() { r = (delete window.globalprop5); ok(v >= 9, "did not get an expected exception deleting globalprop5"); ok(r, "delete returned " + r); - todo_wine. ok(!("globalprop5" in obj), "globalprop5 is still in obj"); }catch(ex) { ok(v < 9, "expected exception deleting globalprop5");
This merge request was approved by Jacek Caban.