diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index 9e2ba5bffa2..721ad16eb88 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -1205,6 +1205,12 @@ HRESULT disp_call_value(script_ctx_t *ctx, IDispatch *disp, IDispatch *jsthis, W if(r && argc) flags |= DISPATCH_PROPERTYGET; + hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex); + if(FAILED(hres)) { + TRACE("using IDispatch\n"); + dispex = NULL; + jsthis = NULL; + } if(jsthis) { static DISPID this_id = DISPID_THIS; @@ -1220,8 +1226,11 @@ HRESULT disp_call_value(script_ctx_t *ctx, IDispatch *disp, IDispatch *jsthis, W if(dp.cArgs > sizeof(buf)/sizeof(*buf)) { dp.rgvarg = heap_alloc(dp.cArgs*sizeof(VARIANT)); - if(!dp.rgvarg) + if(!dp.rgvarg) { + if(dispex) + IDispatchEx_Release(dispex); return E_OUTOFMEMORY; + } }else { dp.rgvarg = buf; } @@ -1233,6 +1242,8 @@ HRESULT disp_call_value(script_ctx_t *ctx, IDispatch *disp, IDispatch *jsthis, W VariantClear(dp.rgvarg+dp.cArgs-i-1); if(dp.rgvarg != buf) heap_free(dp.rgvarg); + if(dispex) + IDispatchEx_Release(dispex); return hres; } } @@ -1243,8 +1254,7 @@ HRESULT disp_call_value(script_ctx_t *ctx, IDispatch *disp, IDispatch *jsthis, W V_VT(&retv) = VT_EMPTY; clear_ei(ctx); - hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex); - if(SUCCEEDED(hres)) { + if(dispex) { hres = IDispatchEx_InvokeEx(dispex, DISPID_VALUE, ctx->lcid, flags, &dp, r ? &retv : NULL, &ctx->ei.ei, &ctx->jscaller->IServiceProvider_iface); IDispatchEx_Release(dispex); @@ -1256,7 +1266,6 @@ HRESULT disp_call_value(script_ctx_t *ctx, IDispatch *disp, IDispatch *jsthis, W return DISP_E_MEMBERNOTFOUND; } - TRACE("using IDispatch\n"); hres = IDispatch_Invoke(disp, DISPID_VALUE, &IID_NULL, ctx->lcid, flags, &dp, r ? &retv : NULL, &ctx->ei.ei, &err); } diff --git a/dlls/jscript/tests/run.c b/dlls/jscript/tests/run.c index 0b0215c4fb5..f6538df3b92 100644 --- a/dlls/jscript/tests/run.c +++ b/dlls/jscript/tests/run.c @@ -90,6 +90,8 @@ DEFINE_EXPECT(global_propargput_i); DEFINE_EXPECT(global_testargtypes_i); DEFINE_EXPECT(puredisp_prop_d); DEFINE_EXPECT(puredisp_noprop_d); +DEFINE_EXPECT(puredisp_value); +DEFINE_EXPECT(dispexfunc_value); DEFINE_EXPECT(testobj_delete_test); DEFINE_EXPECT(testobj_delete_nodelete); DEFINE_EXPECT(testobj_value); @@ -131,6 +133,7 @@ DEFINE_EXPECT(DeleteMemberByDispID_false); #define DISPID_GLOBAL_DISPUNK 0x1017 #define DISPID_GLOBAL_TESTRES 0x1018 #define DISPID_GLOBAL_TESTNORES 0x1019 +#define DISPID_GLOBAL_DISPEXFUNC 0x101a #define DISPID_GLOBAL_TESTPROPDELETE 0x2000 #define DISPID_GLOBAL_TESTNOPROPDELETE 0x2001 @@ -244,18 +247,6 @@ static HRESULT WINAPI DispatchEx_GetIDsOfNames(IDispatchEx *iface, REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId) { - ok(IsEqualGUID(riid, &IID_NULL), "Expected IID_NULL\n"); - ok(cNames==1, "cNames = %d\n", cNames); - - if(!strcmp_wa(*rgszNames, "prop")) { - CHECK_EXPECT(puredisp_prop_d); - *rgDispId = DISPID_TESTOBJ_PROP; - return S_OK; - } else if(!strcmp_wa(*rgszNames, "noprop")) { - CHECK_EXPECT(puredisp_noprop_d); - return DISP_E_UNKNOWNNAME; - } - ok(0, "unexpected call\n"); return E_NOTIMPL; } @@ -268,6 +259,12 @@ static HRESULT WINAPI DispatchEx_Invoke(IDispatchEx *iface, DISPID dispIdMember, return E_NOTIMPL; } +static HRESULT WINAPI DispatchEx_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + static HRESULT WINAPI DispatchEx_DeleteMemberByName(IDispatchEx *iface, BSTR bstrName, DWORD grfdex) { ok(0, "unexpected call %s %x\n", wine_dbgstr_w(bstrName), grfdex); @@ -441,6 +438,60 @@ static IDispatchExVtbl testObjVtbl = { static IDispatchEx testObj = { &testObjVtbl }; +static HRESULT WINAPI dispexFunc_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, + VARIANT *res, EXCEPINFO *pei, IServiceProvider *pspCaller) +{ + ok(pspCaller != NULL, "pspCaller = NULL\n"); + + switch(id) { + case DISPID_VALUE: + CHECK_EXPECT(dispexfunc_value); + + ok(pdp != NULL, "pdp == NULL\n"); + ok(pdp->rgvarg != NULL, "rgvarg == NULL\n"); + ok(pdp->rgdispidNamedArgs != NULL, "rgdispidNamedArgs != NULL\n"); + ok(*pdp->rgdispidNamedArgs == DISPID_THIS, "*rgdispidNamedArgs = %d\n", *pdp->rgdispidNamedArgs); + ok(pdp->cArgs == 2, "cArgs = %d\n", pdp->cArgs); + ok(pdp->cNamedArgs == 1, "cNamedArgs = %d\n", pdp->cNamedArgs); + ok(res != NULL, "res == NULL\n"); + ok(wFlags == (DISPATCH_PROPERTYGET|DISPATCH_METHOD), "wFlags = %x\n", wFlags); + ok(pei != NULL, "pei == NULL\n"); + + ok(V_VT(pdp->rgvarg+1) == VT_BOOL, "V_VT(pdp->rgvarg+1) = %d\n", V_VT(pdp->rgvarg+1)); + ok(!V_BOOL(pdp->rgvarg+1), "V_BOOL(pdp->rgvarg+1) = %x\n", V_BOOL(pdp->rgvarg+1)); + + ok(V_VT(pdp->rgvarg) == VT_DISPATCH, "V_VT(pdp->rgvarg) = %d\n", V_VT(pdp->rgvarg)); + ok(V_DISPATCH(pdp->rgvarg) != NULL, "V_DISPATCH(pdp->rgvarg) == NULL\n"); + + if(res) + V_VT(res) = VT_NULL; + return S_OK; + default: + ok(0, "unexpected call %x\n", id); + return DISP_E_MEMBERNOTFOUND; + } +} + +static IDispatchExVtbl dispexFuncVtbl = { + DispatchEx_QueryInterface, + DispatchEx_AddRef, + DispatchEx_Release, + DispatchEx_GetTypeInfoCount, + DispatchEx_GetTypeInfo, + DispatchEx_GetIDsOfNames, + DispatchEx_Invoke, + DispatchEx_GetDispID, + dispexFunc_InvokeEx, + DispatchEx_DeleteMemberByName, + DispatchEx_DeleteMemberByDispID, + DispatchEx_GetMemberProperties, + DispatchEx_GetMemberName, + DispatchEx_GetNextDispID, + DispatchEx_GetNameSpaceParent +}; + +static IDispatchEx dispexFunc = { &dispexFuncVtbl }; + static HRESULT WINAPI pureDisp_QueryInterface(IDispatchEx *iface, REFIID riid, void **ppv) { if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IDispatch)) { @@ -452,14 +503,65 @@ static HRESULT WINAPI pureDisp_QueryInterface(IDispatchEx *iface, REFIID riid, v return E_NOINTERFACE; } +static HRESULT WINAPI pureDisp_GetIDsOfNames(IDispatchEx *iface, REFIID riid, + LPOLESTR *rgszNames, UINT cNames, + LCID lcid, DISPID *rgDispId) +{ + ok(IsEqualGUID(riid, &IID_NULL), "Expected IID_NULL\n"); + ok(cNames==1, "cNames = %d\n", cNames); + + if(!strcmp_wa(*rgszNames, "prop")) { + CHECK_EXPECT(puredisp_prop_d); + *rgDispId = DISPID_TESTOBJ_PROP; + return S_OK; + } else if(!strcmp_wa(*rgszNames, "noprop")) { + CHECK_EXPECT(puredisp_noprop_d); + return DISP_E_UNKNOWNNAME; + } + + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI pureDisp_Invoke(IDispatchEx *iface, DISPID dispIdMember, REFIID riid, LCID lcid, + WORD wFlags, DISPPARAMS *pdp, VARIANT *res, EXCEPINFO *ei, UINT *puArgErr) +{ + ok(IsEqualGUID(&IID_NULL, riid), "unexpected riid\n"); + + switch(dispIdMember) { + case DISPID_VALUE: + CHECK_EXPECT(puredisp_value); + + ok(pdp != NULL, "pdp == NULL\n"); + ok(pdp->rgvarg != NULL, "rgvarg == NULL\n"); + ok(!pdp->rgdispidNamedArgs, "rgdispidNamedArgs != NULL\n"); + ok(pdp->cArgs == 1, "cArgs = %d\n", pdp->cArgs); + ok(!pdp->cNamedArgs, "cNamedArgs = %d\n", pdp->cNamedArgs); + ok(res != NULL, "res == NULL\n"); + ok(wFlags == (DISPATCH_PROPERTYGET|DISPATCH_METHOD), "wFlags = %x\n", wFlags); + ok(ei != NULL, "ei == NULL\n"); + ok(puArgErr != NULL, "puArgErr == NULL\n"); + + ok(V_VT(pdp->rgvarg) == VT_BOOL, "V_VT(pdp->rgvarg) = %d\n", V_VT(pdp->rgvarg)); + ok(!V_BOOL(pdp->rgvarg), "V_BOOL(pdp->rgvarg) = %x\n", V_BOOL(pdp->rgvarg)); + + if(res) + V_VT(res) = VT_NULL; + return S_OK; + default: + ok(0, "unexpected call\n"); + return E_NOTIMPL; + } +} + static IDispatchExVtbl pureDispVtbl = { pureDisp_QueryInterface, DispatchEx_AddRef, DispatchEx_Release, DispatchEx_GetTypeInfoCount, DispatchEx_GetTypeInfo, - DispatchEx_GetIDsOfNames, - DispatchEx_Invoke + pureDisp_GetIDsOfNames, + pureDisp_Invoke }; static IDispatchEx pureDisp = { &pureDispVtbl }; @@ -628,6 +730,11 @@ static HRESULT WINAPI Global_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD return S_OK; } + if(!strcmp_wa(bstrName, "dispexFunc")) { + *pid = DISPID_GLOBAL_DISPEXFUNC; + return S_OK; + } + if(strict_dispid_check && strcmp_wa(bstrName, "t")) ok(0, "unexpected call %s\n", wine_dbgstr_w(bstrName)); return DISP_E_UNKNOWNNAME; @@ -809,6 +916,11 @@ static HRESULT WINAPI Global_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, V_DISPATCH(pvarRes) = (IDispatch*)&pureDisp; return S_OK; + case DISPID_GLOBAL_DISPEXFUNC: + V_VT(pvarRes) = VT_DISPATCH; + V_DISPATCH(pvarRes) = (IDispatch*)&dispexFunc; + return S_OK; + case DISPID_GLOBAL_GETNULLBSTR: if(pvarRes) { V_VT(pvarRes) = VT_BSTR; @@ -1891,6 +2003,22 @@ static BOOL run_tests(void) parse_script_a("ok((delete pureDisp.noprop) === true, 'delete pureDisp.noprop did not return false');"); CHECK_CALLED(puredisp_noprop_d); + SET_EXPECT(puredisp_value); + parse_script_a("var t=pureDisp; t=t(false);"); + CHECK_CALLED(puredisp_value); + + SET_EXPECT(puredisp_value); + parse_script_a("var t = {func: pureDisp}; t = t.func(false);"); + CHECK_CALLED(puredisp_value); + + SET_EXPECT(dispexfunc_value); + parse_script_a("var t = dispexFunc; t = t(false);"); + CHECK_CALLED(dispexfunc_value); + + SET_EXPECT(dispexfunc_value); + parse_script_a("var t = {func: dispexFunc}; t = t.func(false);"); + CHECK_CALLED(dispexfunc_value); + parse_script_a("(function reportSuccess() {})()"); parse_script_a("ok(typeof(test) === 'object', \"typeof(test) != 'object'\");");