[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
participants (2)
-
Gabriel Ivăncescu -
Gabriel Ivăncescu (@insn)