[PATCH v6 0/2] MR9660: jscript: Treat DISPATCH_PROPERTYGET | DISPATCH_METHOD as property getter in ES5+ modes.
-- v6: mshtml: Handle DISPATCH_PROPERTYGET | DISPATCH_METHOD in dispex_value as jscript: Treat DISPATCH_PROPERTYGET | DISPATCH_METHOD as property getter https://gitlab.winehq.org/wine/wine/-/merge_requests/9660
From: Gabriel Ivăncescu <gabrielopcode@gmail.com> Signed-off-by: Gabriel Ivăncescu <gabrielopcode@gmail.com> --- dlls/jscript/dispex.c | 8 +-- dlls/mshtml/tests/documentmode.js | 2 +- dlls/mshtml/tests/dom.c | 81 +++++++++++++++++++++++++++++++ dlls/mshtml/tests/es5.js | 12 +++-- dlls/mshtml/tests/script.c | 52 +++++++++++++++++++- 5 files changed, 143 insertions(+), 12 deletions(-) diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index f39a8cd4b12..dc2ff9f6a55 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -2136,10 +2136,10 @@ static HRESULT WINAPI DispatchEx_InvokeEx(IWineJSDispatch *iface, DISPID id, LCI if(pspCaller) IServiceProvider_AddRef(pspCaller); + if(wFlags == (DISPATCH_METHOD | DISPATCH_PROPERTYGET)) + wFlags = (This->ctx->version < SCRIPTLANGUAGEVERSION_ES5) ? DISPATCH_METHOD : DISPATCH_PROPERTYGET; + switch(wFlags) { - case DISPATCH_METHOD|DISPATCH_PROPERTYGET: - wFlags = DISPATCH_METHOD; - /* fall through */ case DISPATCH_METHOD: case DISPATCH_CONSTRUCT: { jsval_t *argv, buf[6], r; @@ -2712,7 +2712,7 @@ HRESULT disp_call(script_ctx_t *ctx, IDispatch *disp, DISPID id, WORD flags, uns jsdisp_release(jsdisp); flags &= ~DISPATCH_JSCRIPT_INTERNAL_MASK; - if(ret && argc) + if(ret && argc && (!jsdisp || ctx->version < SCRIPTLANGUAGEVERSION_ES5)) flags |= DISPATCH_PROPERTYGET; dp.cArgs = argc; diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 1c5f5dd4d25..4e1fa97f125 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -2455,7 +2455,7 @@ async_test("weakmap_obj", function() { ok(e.number === 0xa13fd - 0x80000000, "set('test') threw " + e.number); } try { - r = s.set(external.testHostContext(true), 1); + r = s.set(external.testHostContext(1), 1); ok(false, "set(host_obj) did not throw"); }catch(e) { ok(e.number === 0xa13fd - 0x80000000, "set(host_obj) threw " + e.number); diff --git a/dlls/mshtml/tests/dom.c b/dlls/mshtml/tests/dom.c index 3235cbbaca5..861042bc6eb 100644 --- a/dlls/mshtml/tests/dom.c +++ b/dlls/mshtml/tests/dom.c @@ -11731,6 +11731,85 @@ static void test_case_insens(IHTMLDocument2 *doc) IDispatchEx_Release(dispex); } +static void test_method_vs_getter(IHTMLDocument2 *doc) +{ + DISPPARAMS dp = { 0 }; + IDispatchEx *dispex; + DISPID dispid; + HRESULT hres; + VARIANT v; + BSTR bstr; + + hres = IHTMLDocument2_QueryInterface(doc, &IID_IDispatchEx, (void**)&dispex); + ok(hres == S_OK, "Could not get IDispatchEx: %08lx\n", hres); + + V_VT(&v) = VT_EMPTY; + hres = IDispatchEx_InvokeEx(dispex, DISPID_VALUE, LOCALE_NEUTRAL, DISPATCH_METHOD | DISPATCH_PROPERTYGET, &dp, &v, NULL, NULL); + todo_wine_if(compat_mode < COMPAT_IE9) + ok(hres == S_OK, "InvokeEx failed: %08lx\n", hres); + todo_wine_if(compat_mode < COMPAT_IE9) + ok(V_VT(&v) == VT_BSTR, "V_VT = %d\n", V_VT(&v)); + VariantClear(&v); + + bstr = SysAllocString(L"body"); + hres = IDispatchEx_GetDispID(dispex, bstr, 0, &dispid); + ok(hres == S_OK, "GetDispID returned: %08lx\n", hres); + SysFreeString(bstr); + + hres = IDispatchEx_InvokeEx(dispex, dispid, LOCALE_NEUTRAL, DISPATCH_METHOD | DISPATCH_PROPERTYGET, &dp, &v, NULL, NULL); + ok(hres == S_OK, "InvokeEx failed: %08lx\n", hres); + ok(V_VT(&v) == VT_DISPATCH, "V_VT = %d\n", V_VT(&v)); + ok(V_DISPATCH(&v) != NULL, "V_DISPATCH == NULL\n"); + VariantClear(&v); + + bstr = SysAllocString(L"title"); + hres = IDispatchEx_GetDispID(dispex, bstr, 0, &dispid); + ok(hres == S_OK, "GetDispID returned: %08lx\n", hres); + SysFreeString(bstr); + + hres = IDispatchEx_InvokeEx(dispex, dispid, LOCALE_NEUTRAL, DISPATCH_METHOD | DISPATCH_PROPERTYGET, &dp, &v, NULL, NULL); + ok(hres == S_OK, "InvokeEx failed: %08lx\n", hres); + ok(V_VT(&v) == VT_BSTR, "V_VT = %d\n", V_VT(&v)); + VariantClear(&v); + + bstr = SysAllocString(L"close"); + hres = IDispatchEx_GetDispID(dispex, bstr, 0, &dispid); + ok(hres == S_OK, "GetDispID returned: %08lx\n", hres); + SysFreeString(bstr); + + hres = IDispatchEx_InvokeEx(dispex, dispid, LOCALE_NEUTRAL, DISPATCH_METHOD | DISPATCH_PROPERTYGET, &dp, &v, NULL, NULL); + ok(hres == S_OK, "InvokeEx failed: %08lx\n", hres); + if(compat_mode < COMPAT_IE9) + ok(V_VT(&v) == VT_EMPTY, "V_VT = %d\n", V_VT(&v)); + else { + ok(V_VT(&v) == VT_DISPATCH, "V_VT = %d\n", V_VT(&v)); + ok(V_DISPATCH(&v) != NULL, "V_DISPATCH == NULL\n"); + } + VariantClear(&v); + + hres = IDispatchEx_InvokeEx(dispex, dispid, LOCALE_NEUTRAL, DISPATCH_PROPERTYGET, &dp, &v, NULL, NULL); + ok(hres == S_OK, "InvokeEx failed: %08lx\n", hres); + ok(V_VT(&v) == VT_DISPATCH, "V_VT = %d\n", V_VT(&v)); + ok(V_DISPATCH(&v) != NULL, "V_DISPATCH == NULL\n"); + IDispatchEx_Release(dispex); + + hres = IDispatch_QueryInterface(V_DISPATCH(&v), &IID_IDispatchEx, (void**)&dispex); + ok(hres == S_OK, "Could not get IDispatchEx: %08lx\n", hres); + VariantClear(&v); + + hres = IDispatchEx_InvokeEx(dispex, DISPID_VALUE, LOCALE_NEUTRAL, DISPATCH_METHOD | DISPATCH_PROPERTYGET, &dp, &v, NULL, NULL); + if(compat_mode < COMPAT_IE9) + todo_wine + ok(hres == E_ACCESSDENIED, "InvokeEx returned: %08lx\n", hres); + else { + ok(hres == S_OK, "InvokeEx failed: %08lx\n", hres); + ok(V_VT(&v) == VT_BSTR, "V_VT = %d\n", V_VT(&v)); + } + VariantClear(&v); + + IDispatchEx_Release(dispex); +} + static void test_null_write(IHTMLDocument2 *doc) { HRESULT hres; @@ -13842,9 +13921,11 @@ START_TEST(dom) run_domtest(doc_blank_ie8, test_quirks_mode_perf_toJSON); run_domtest(doctype_str, test_doctype); run_domtest(case_insens_str, test_case_insens); + run_domtest(doc_blank, test_method_vs_getter); if(is_ie9plus) { compat_mode = COMPAT_IE9; run_domtest(emptydiv_ie9_str, test_docfrag); + run_domtest(doc_blank_ie9, test_method_vs_getter); compat_mode = COMPAT_NONE; } diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index 150736dc438..ac133e6b7a4 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -2749,17 +2749,19 @@ sync_test("globals override", function() { }); sync_test("host this", function() { - var tests = [ undefined, null, external.nullDisp, function() {}, [0], "foobar", true, 42, new Number(42), external.testHostContext(true), window, document ]; + var tests = [ undefined, null, external.nullDisp, function() {}, [0], "foobar", true, 42, new Number(42), external.testHostContext(1), window, document ]; var i, obj = Object.create(Function.prototype); // only pure js objects are passed as 'this' (regardless of prototype) - [137].forEach(external.testHostContext(true), obj); - Function.prototype.apply.call(external.testHostContext(true), obj, [137, 0, {}]); + [137].forEach(external.testHostContext(1), obj); + Function.prototype.apply.call(external.testHostContext(1), obj, [137, 0, {}]); for(i = 0; i < tests.length; i++) { - [137].forEach(external.testHostContext(false), tests[i]); - Function.prototype.apply.call(external.testHostContext(false), tests[i], [137, 0, {}]); + [137].forEach(external.testHostContext(0), tests[i]); + Function.prototype.apply.call(external.testHostContext(0), tests[i], [137, 0, {}]); } + + i = external.testHostContext(2).prop(42); }); sync_test("head_setter", function() { diff --git a/dlls/mshtml/tests/script.c b/dlls/mshtml/tests/script.c index 2703ba68e4e..56c2848ab2d 100644 --- a/dlls/mshtml/tests/script.c +++ b/dlls/mshtml/tests/script.c @@ -160,6 +160,7 @@ DEFINE_EXPECT(GetTypeInfo); #define DISPID_SCRIPT_TESTPROP2 0x100001 #define DISPID_REFTEST_GET 0x100000 #define DISPID_REFTEST_REF 0x100001 +#define DISPID_TESTHOSTCTX_PROP 0x100000 #define DISPID_EXTERNAL_OK 0x300000 #define DISPID_EXTERNAL_TRACE 0x300001 @@ -971,6 +972,52 @@ static IDispatchExVtbl testHostContextDisp_no_this_vtbl = { static IDispatchEx testHostContextDisp_no_this = { &testHostContextDisp_no_this_vtbl }; +static HRESULT WINAPI testHostContextDisp_with_prop_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid) +{ + if(!lstrcmpW(bstrName, L"prop")) { + *pid = DISPID_TESTHOSTCTX_PROP; + return S_OK; + } + + ok(0, "unexpected call %s\n", wine_dbgstr_w(bstrName)); + return E_NOTIMPL; +} + +static HRESULT WINAPI testHostContextDisp_with_prop_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, + VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) +{ + ok(id == DISPID_TESTHOSTCTX_PROP, "id = %ld\n", id); + ok(wFlags == (DISPATCH_PROPERTYGET | DISPATCH_METHOD), "wFlags = %x\n", wFlags); + ok(pdp != NULL, "pdp == NULL\n"); + ok(pdp->cArgs == 1, "pdp->cArgs = %d\n", pdp->cArgs); + ok(pdp->cNamedArgs == 0, "pdp->cNamedArgs = %d\n", pdp->cNamedArgs); + ok(V_VT(&pdp->rgvarg[0]) == VT_I4, "V_VT(rgvarg[0]) = %d\n", V_VT(&pdp->rgvarg[0])); + ok(V_I4(&pdp->rgvarg[0]) == 42, "V_I4(rgvarg[0]) = %ld\n", V_I4(&pdp->rgvarg[0])); + ok(!pdp->rgdispidNamedArgs, "pdp->rgdispidNamedArgs != NULL\n"); + ok(pvarRes != NULL, "pvarRes = NULL\n"); + return S_OK; +} + +static IDispatchExVtbl testHostContextDisp_with_prop_vtbl = { + DispatchEx_QueryInterface, + DispatchEx_AddRef, + DispatchEx_Release, + DispatchEx_GetTypeInfoCount, + DispatchEx_GetTypeInfo, + DispatchEx_GetIDsOfNames, + DispatchEx_Invoke, + testHostContextDisp_with_prop_GetDispID, + testHostContextDisp_with_prop_InvokeEx, + DispatchEx_DeleteMemberByName, + DispatchEx_DeleteMemberByDispID, + DispatchEx_GetMemberProperties, + DispatchEx_GetMemberName, + DispatchEx_GetNextDispID, + DispatchEx_GetNameSpaceParent +}; + +static IDispatchEx testHostContextDisp_with_prop = { &testHostContextDisp_with_prop_vtbl }; + struct refTestObj { IDispatchEx IDispatchEx_iface; @@ -1455,9 +1502,10 @@ static HRESULT WINAPI externalDisp_InvokeEx(IDispatchEx *iface, DISPID id, LCID ok(pei != NULL, "pei == NULL\n"); ok(pdp->rgvarg != NULL, "rgvarg == NULL\n"); ok(pdp->cArgs == 1, "cArgs = %d\n", pdp->cArgs); - ok(V_VT(pdp->rgvarg) == VT_BOOL, "V_VT(rgvarg) = %d\n", V_VT(pdp->rgvarg)); + ok(V_VT(pdp->rgvarg) == VT_I4, "V_VT(rgvarg) = %d\n", V_VT(pdp->rgvarg)); V_VT(pvarRes) = VT_DISPATCH; - V_DISPATCH(pvarRes) = (IDispatch*)(V_BOOL(pdp->rgvarg) ? &testHostContextDisp : &testHostContextDisp_no_this); + V_DISPATCH(pvarRes) = (IDispatch*)(V_I4(pdp->rgvarg) == 0 ? &testHostContextDisp_no_this : + V_I4(pdp->rgvarg) == 1 ? &testHostContextDisp : &testHostContextDisp_with_prop); return S_OK; case DISPID_EXTERNAL_GETMIMETYPE: -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9660
From: Gabriel Ivăncescu <gabrielopcode@gmail.com> Signed-off-by: Gabriel Ivăncescu <gabrielopcode@gmail.com> --- dlls/mshtml/dispex.c | 1 + dlls/mshtml/tests/dom.c | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index 0af89aca630..a6b8afb0543 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -868,6 +868,7 @@ static HRESULT dispex_value(DispatchEx *This, LCID lcid, WORD flags, DISPPARAMS return This->info->vtbl->value(This, lcid, flags, params, res, ei, caller); switch(flags) { + case DISPATCH_PROPERTYGET | DISPATCH_METHOD: case DISPATCH_PROPERTYGET: V_VT(res) = VT_BSTR; hres = dispex_to_string(This, &V_BSTR(res)); diff --git a/dlls/mshtml/tests/dom.c b/dlls/mshtml/tests/dom.c index 861042bc6eb..58a409a7a77 100644 --- a/dlls/mshtml/tests/dom.c +++ b/dlls/mshtml/tests/dom.c @@ -11745,9 +11745,7 @@ static void test_method_vs_getter(IHTMLDocument2 *doc) V_VT(&v) = VT_EMPTY; hres = IDispatchEx_InvokeEx(dispex, DISPID_VALUE, LOCALE_NEUTRAL, DISPATCH_METHOD | DISPATCH_PROPERTYGET, &dp, &v, NULL, NULL); - todo_wine_if(compat_mode < COMPAT_IE9) ok(hres == S_OK, "InvokeEx failed: %08lx\n", hres); - todo_wine_if(compat_mode < COMPAT_IE9) ok(V_VT(&v) == VT_BSTR, "V_VT = %d\n", V_VT(&v)); VariantClear(&v); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9660
On Tue Dec 9 21:12:19 2025 +0000, Gabriel Ivăncescu wrote:
After wasting time on a dead end solution, actually I realized it's easier than I thought, since the issue was just cross-context script objects. For those we can still just not add PROPERTYGET, as long as they're still a jsdisp. I pushed it but it will be deferred to after code freeze.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/9660#note_125315
Jacek Caban (@jacek) commented about dlls/mshtml/tests/script.c:
ok(pei != NULL, "pei == NULL\n"); ok(pdp->rgvarg != NULL, "rgvarg == NULL\n"); ok(pdp->cArgs == 1, "cArgs = %d\n", pdp->cArgs); - ok(V_VT(pdp->rgvarg) == VT_BOOL, "V_VT(rgvarg) = %d\n", V_VT(pdp->rgvarg)); + ok(V_VT(pdp->rgvarg) == VT_I4, "V_VT(rgvarg) = %d\n", V_VT(pdp->rgvarg)); V_VT(pvarRes) = VT_DISPATCH; - V_DISPATCH(pvarRes) = (IDispatch*)(V_BOOL(pdp->rgvarg) ? &testHostContextDisp : &testHostContextDisp_no_this); + V_DISPATCH(pvarRes) = (IDispatch*)(V_I4(pdp->rgvarg) == 0 ? &testHostContextDisp_no_this : + V_I4(pdp->rgvarg) == 1 ? &testHostContextDisp : &testHostContextDisp_with_prop);
This is getting a bit cryptic. Could we just have separate properties for all of these objects, with names that clearly correspond to their meaning? FWIW, while the implementation itself will likely have to wait until the end of the code freeze, we can still merge tests, so feel free to repurpose this MR to contain tests only. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/9660#note_125801
participants (3)
-
Gabriel Ivăncescu -
Gabriel Ivăncescu (@insn) -
Jacek Caban (@jacek)