From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/dispex.c | 9 ++ dlls/jscript/jscript.c | 17 ++- dlls/jscript/jscript.h | 3 + dlls/jscript/jsutils.c | 9 ++ dlls/jscript/tests/caller.c | 212 +++++++++++++++++++++++++++++++++++- 5 files changed, 241 insertions(+), 9 deletions(-)
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index 2c35f2ae9cc..4b56ec9fc70 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -1900,6 +1900,7 @@ static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lc VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) { jsdisp_t *This = impl_from_IDispatchEx(iface); + IServiceProvider *prev_caller; dispex_prop_t *prop; jsexcept_t ei; HRESULT hres; @@ -1917,6 +1918,11 @@ static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lc
enter_script(This->ctx, &ei);
+ prev_caller = This->ctx->jscaller->caller; + This->ctx->jscaller->caller = pspCaller; + if(pspCaller) + IServiceProvider_AddRef(pspCaller); + switch(wFlags) { case DISPATCH_METHOD|DISPATCH_PROPERTYGET: wFlags = DISPATCH_METHOD; @@ -2000,6 +2006,9 @@ static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lc break; }
+ This->ctx->jscaller->caller = prev_caller; + if(pspCaller) + IServiceProvider_Release(pspCaller); return leave_script(This->ctx, hres); }
diff --git a/dlls/jscript/jscript.c b/dlls/jscript/jscript.c index f5331a13b96..401f6ca85b0 100644 --- a/dlls/jscript/jscript.c +++ b/dlls/jscript/jscript.c @@ -428,6 +428,17 @@ static void release_named_item_list(JScript *This) } }
+static HRESULT exec_global_code(script_ctx_t *ctx, bytecode_t *code, jsval_t *r) +{ + IServiceProvider *prev_caller = ctx->jscaller->caller; + HRESULT hres; + + ctx->jscaller->caller = SP_CALLER_UNINITIALIZED; + hres = exec_source(ctx, EXEC_GLOBAL, code, &code->global_code, NULL, NULL, NULL, 0, NULL, r); + ctx->jscaller->caller = prev_caller; + return hres; +} + static void exec_queued_code(JScript *This) { bytecode_t *iter; @@ -436,7 +447,7 @@ static void exec_queued_code(JScript *This)
LIST_FOR_EACH_ENTRY(iter, &This->queued_code, bytecode_t, entry) { enter_script(This->ctx, &ei); - hres = exec_source(This->ctx, EXEC_GLOBAL, iter, &iter->global_code, NULL, NULL, NULL, 0, NULL, NULL); + hres = exec_global_code(This->ctx, iter, NULL); leave_script(This->ctx, hres); if(FAILED(hres)) break; @@ -1103,7 +1114,7 @@ static HRESULT WINAPI JScriptParse_ParseScriptText(IActiveScriptParse *iface, if(dwFlags & SCRIPTTEXT_ISEXPRESSION) { jsval_t r;
- hres = exec_source(This->ctx, EXEC_GLOBAL, code, &code->global_code, NULL, NULL, NULL, 0, NULL, &r); + hres = exec_global_code(This->ctx, code, &r); if(SUCCEEDED(hres)) { if(pvarResult) hres = jsval_to_variant(r, pvarResult); @@ -1122,7 +1133,7 @@ static HRESULT WINAPI JScriptParse_ParseScriptText(IActiveScriptParse *iface, if(!pvarResult && !is_started(This->ctx)) { list_add_tail(&This->queued_code, &code->entry); }else { - hres = exec_source(This->ctx, EXEC_GLOBAL, code, &code->global_code, NULL, NULL, NULL, 0, NULL, NULL); + hres = exec_global_code(This->ctx, code, NULL); if(code->is_persistent) list_add_tail(&This->persistent_code, &code->entry); else diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index b633f390508..36a6d23c917 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -331,12 +331,15 @@ typedef struct {
void release_cc(cc_ctx_t*) DECLSPEC_HIDDEN;
+#define SP_CALLER_UNINITIALIZED ((IServiceProvider*)IntToPtr(-1)) + typedef struct { IServiceProvider IServiceProvider_iface;
LONG ref;
script_ctx_t *ctx; + IServiceProvider *caller; } JSCaller;
#include "jsval.h" diff --git a/dlls/jscript/jsutils.c b/dlls/jscript/jsutils.c index 3dfcd08f14c..a26b63833ee 100644 --- a/dlls/jscript/jsutils.c +++ b/dlls/jscript/jsutils.c @@ -1034,6 +1034,14 @@ static HRESULT WINAPI JSCaller_QueryService(IServiceProvider *iface, REFGUID gui { JSCaller *This = impl_from_IServiceProvider(iface);
+ if(IsEqualGUID(guidService, &SID_GetCaller)) { + TRACE("(%p)->(SID_GetCaller)\n", This); + *ppv = NULL; + if(!This->caller) + return S_OK; + return (This->caller == SP_CALLER_UNINITIALIZED) ? E_NOINTERFACE : IServiceProvider_QueryInterface(This->caller, riid, ppv); + } + if(IsEqualGUID(guidService, &SID_VariantConversion) && This->ctx && This->ctx->active_script) { TRACE("(%p)->(SID_VariantConversion)\n", This); return IActiveScript_QueryInterface(This->ctx->active_script, riid, ppv); @@ -1063,6 +1071,7 @@ HRESULT create_jscaller(script_ctx_t *ctx) ret->IServiceProvider_iface.lpVtbl = &ServiceProviderVtbl; ret->ref = 1; ret->ctx = ctx; + ret->caller = SP_CALLER_UNINITIALIZED;
ctx->jscaller = ret; return S_OK; diff --git a/dlls/jscript/tests/caller.c b/dlls/jscript/tests/caller.c index 836f5a820a1..8a1ebb83a33 100644 --- a/dlls/jscript/tests/caller.c +++ b/dlls/jscript/tests/caller.c @@ -74,14 +74,23 @@ static const CLSID CLSID_JScript = #define CLEAR_CALLED(func) \ expect_ ## func = called_ ## func = FALSE
+DEFINE_EXPECT(sp_caller_QI_NULL); DEFINE_EXPECT(testArgConv); +DEFINE_EXPECT(testGetCaller); +DEFINE_EXPECT(testGetCallerJS); +DEFINE_EXPECT(testGetCallerNested); DEFINE_EXPECT(OnEnterScript); DEFINE_EXPECT(OnLeaveScript);
+static IActiveScriptParse *active_script_parser; static IVariantChangeType *script_change_type; static IDispatch *stored_obj; +static IServiceProvider *test_get_caller_sp;
#define DISPID_TEST_TESTARGCONV 0x1000 +#define DISPID_TEST_TESTGETCALLER 0x1001 +#define DISPID_TEST_TESTGETCALLERJS 0x1002 +#define DISPID_TEST_TESTGETCALLERNESTED 0x1003
typedef struct { int int_result; @@ -254,6 +263,55 @@ static void test_caller(IServiceProvider *caller, IDispatch *arg_obj) IVariantChangeType_Release(change_type); }
+static IServiceProvider sp_caller_obj; + +static HRESULT WINAPI sp_caller_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv) +{ + if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IServiceProvider, riid)) + *ppv = &sp_caller_obj; + else { + ok(IsEqualGUID(&IID_NULL, riid), "unexpected riid %s\n", wine_dbgstr_guid(riid)); + CHECK_EXPECT(sp_caller_QI_NULL); + *ppv = NULL; + return E_NOINTERFACE; + } + + return S_OK; +} + +static ULONG WINAPI sp_caller_AddRef(IServiceProvider *iface) +{ + return 2; +} + +static ULONG WINAPI sp_caller_Release(IServiceProvider *iface) +{ + return 1; +} + +static HRESULT WINAPI sp_caller_QueryService(IServiceProvider *iface, REFGUID guidService, + REFIID riid, void **ppv) +{ + if(IsEqualGUID(guidService, &SID_GetCaller)) { + ok(IsEqualGUID(riid, &IID_IServiceProvider), "unexpected riid %s\n", wine_dbgstr_guid(riid)); + *ppv = NULL; + return S_OK; + } + + ok(0, "unexpected guidService %s with riid %s\n", wine_dbgstr_guid(guidService), wine_dbgstr_guid(riid)); + *ppv = NULL; + return E_NOINTERFACE; +} + +static const IServiceProviderVtbl sp_caller_vtbl = { + sp_caller_QueryInterface, + sp_caller_AddRef, + sp_caller_Release, + sp_caller_QueryService +}; + +static IServiceProvider sp_caller_obj = { &sp_caller_vtbl }; + static HRESULT WINAPI DispatchEx_QueryInterface(IDispatchEx *iface, REFIID riid, void **ppv) { if(IsEqualGUID(riid, &IID_IUnknown)) { @@ -350,6 +408,21 @@ static HRESULT WINAPI Test_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD gr *pid = DISPID_TEST_TESTARGCONV; return S_OK; } + if(!lstrcmpW(bstrName, L"testGetCaller")) { + ok(grfdex == fdexNameCaseSensitive, "grfdex = %lx\n", grfdex); + *pid = DISPID_TEST_TESTGETCALLER; + return S_OK; + } + if(!lstrcmpW(bstrName, L"testGetCallerJS")) { + ok(grfdex == fdexNameCaseSensitive, "grfdex = %lx\n", grfdex); + *pid = DISPID_TEST_TESTGETCALLERJS; + return S_OK; + } + if(!lstrcmpW(bstrName, L"testGetCallerNested")) { + ok(grfdex == fdexNameCaseSensitive, "grfdex = %lx\n", grfdex); + *pid = DISPID_TEST_TESTGETCALLERNESTED; + return S_OK; + }
return E_NOTIMPL; } @@ -357,6 +430,9 @@ static HRESULT WINAPI Test_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD gr static HRESULT WINAPI Test_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) { + IServiceProvider *caller = (void*)0xdeadbeef; + HRESULT hres; + ok(pspCaller != NULL, "pspCaller == NULL\n");
switch(id) { @@ -380,6 +456,80 @@ static HRESULT WINAPI Test_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WO IDispatch_AddRef(stored_obj); break;
+ case DISPID_TEST_TESTGETCALLER: { + void *iface = (void*)0xdeadbeef; + + CHECK_EXPECT(testGetCaller); + CHECK_CALLED(OnEnterScript); + + ok(wFlags == DISPATCH_METHOD, "wFlags = %x\n", wFlags); + ok(pdp != NULL, "pdp == NULL\n"); + ok(!pdp->rgdispidNamedArgs, "rgdispidNamedArgs != NULL\n"); + ok(!pvarRes, "pvarRes != NULL\n"); + ok(pei != NULL, "pei == NULL\n"); + + SET_EXPECT(OnEnterScript); + SET_EXPECT(OnLeaveScript); + SET_EXPECT(testGetCallerNested); + hres = IActiveScriptParse_ParseScriptText(active_script_parser, L"testGetCallerNested(1,2)", + NULL, NULL, NULL, 0, 0, 0, NULL, NULL); + ok(hres == S_OK, "ParseScriptText failed: %08lx\n", hres); + CHECK_CALLED(testGetCallerNested); + CHECK_CALLED(OnLeaveScript); + CHECK_CALLED(OnEnterScript); + SET_EXPECT(OnLeaveScript); + + hres = IServiceProvider_QueryService(pspCaller, &SID_GetCaller, &IID_IServiceProvider, (void**)&caller); + ok(hres == S_OK, "Could not get SID_GetCaller service: %08lx\n", hres); + ok(caller == test_get_caller_sp, "caller != test_get_caller_sp\n"); + if(caller) IServiceProvider_Release(caller); + + if(test_get_caller_sp) + SET_EXPECT(sp_caller_QI_NULL); + hres = IServiceProvider_QueryService(pspCaller, &SID_GetCaller, &IID_NULL, &iface); + ok(hres == (test_get_caller_sp ? E_NOINTERFACE : S_OK), "Could not query SID_GetCaller with IID_NULL: %08lx\n", hres); + ok(iface == NULL, "iface != NULL\n"); + if(test_get_caller_sp) + CHECK_CALLED(sp_caller_QI_NULL); + break; + } + + case DISPID_TEST_TESTGETCALLERJS: + CHECK_EXPECT(testGetCallerJS); + + ok(wFlags == DISPATCH_METHOD, "wFlags = %x\n", wFlags); + ok(pdp != NULL, "pdp == NULL\n"); + ok(pdp->cArgs == 1, "cArgs = %d\n", pdp->cArgs); + ok(!pdp->rgdispidNamedArgs, "rgdispidNamedArgs != NULL\n"); + ok(!pvarRes, "pvarRes != NULL\n"); + ok(pei != NULL, "pei == NULL\n"); + ok(V_VT(pdp->rgvarg) == VT_I4, "V_VT(rgvarg) = %d\n", V_VT(pdp->rgvarg)); + ok(V_I4(pdp->rgvarg) == 42, "V_I4(rgvarg) = %ld\n", V_I4(pdp->rgvarg)); + + hres = IServiceProvider_QueryService(pspCaller, &SID_GetCaller, &IID_IServiceProvider, (void**)&caller); + ok(hres == E_NOINTERFACE, "QueryService(SID_GetCaller) returned: %08lx\n", hres); + ok(caller == NULL, "caller != NULL\n"); + break; + + case DISPID_TEST_TESTGETCALLERNESTED: + CHECK_EXPECT(testGetCallerNested); + + ok(wFlags == DISPATCH_METHOD, "wFlags = %x\n", wFlags); + ok(pdp != NULL, "pdp == NULL\n"); + ok(pdp->cArgs == 2, "cArgs = %d\n", pdp->cArgs); + ok(!pdp->rgdispidNamedArgs, "rgdispidNamedArgs != NULL\n"); + ok(!pvarRes, "pvarRes != NULL\n"); + ok(pei != NULL, "pei == NULL\n"); + ok(V_VT(&pdp->rgvarg[0]) == VT_I4, "V_VT(rgvarg[0]) = %d\n", V_VT(&pdp->rgvarg[0])); + ok(V_VT(&pdp->rgvarg[1]) == VT_I4, "V_VT(rgvarg[1]) = %d\n", V_VT(&pdp->rgvarg[1])); + ok(V_I4(&pdp->rgvarg[0]) == 2, "V_I4(rgvarg[0]) = %ld\n", V_I4(&pdp->rgvarg[0])); + ok(V_I4(&pdp->rgvarg[1]) == 1, "V_I4(rgvarg[1]) = %ld\n", V_I4(&pdp->rgvarg[1])); + + hres = IServiceProvider_QueryService(pspCaller, &SID_GetCaller, &IID_IServiceProvider, (void**)&caller); + ok(hres == E_NOINTERFACE, "QueryService(SID_GetCaller) returned: %08lx\n", hres); + ok(caller == NULL, "caller != NULL\n"); + break; + default: ok(0, "unexpected call\n"); return E_NOTIMPL; @@ -542,22 +692,32 @@ static IActiveScriptParse *create_script(void)
static void run_scripts(void) { - IActiveScriptParse *parser; + IActiveScript *active_script; + DISPPARAMS dp = { 0 }; + IDispatchEx *dispex; + IDispatch *disp; + DISPID dispid; HRESULT hres; + VARIANT var; + BSTR bstr;
- parser = create_script(); + active_script_parser = create_script();
- hres = IActiveScriptParse_QueryInterface(parser, &IID_IVariantChangeType, (void**)&script_change_type); + hres = IActiveScriptParse_QueryInterface(active_script_parser, &IID_IVariantChangeType, (void**)&script_change_type); ok(hres == S_OK, "Could not get IVariantChangeType iface: %08lx\n", hres);
SET_EXPECT(OnEnterScript); /* checked in callback */ SET_EXPECT(testArgConv); - parse_script(parser, + SET_EXPECT(testGetCallerJS); + parse_script(active_script_parser, L"var obj = {" L" toString: function() { return 'strval'; }," L" valueOf: function() { return 10; }" L"};" - L"testArgConv(obj);"); + L"testArgConv(obj);" + L"function testGetCallerFunc() { testGetCaller(); };" + L"testGetCallerJS(42);"); + CHECK_CALLED(testGetCallerJS); CHECK_CALLED(testArgConv); CHECK_CALLED(OnLeaveScript); /* set in callback */
@@ -565,7 +725,47 @@ static void run_scripts(void) IDispatch_Release(stored_obj); IVariantChangeType_Release(script_change_type);
- IActiveScriptParse_Release(parser); + hres = IActiveScriptParse_QueryInterface(active_script_parser, &IID_IActiveScript, (void**)&active_script); + ok(hres == S_OK, "Could not get IActiveScript: %08lx\n", hres); + hres = IActiveScript_GetScriptDispatch(active_script, NULL, &disp); + ok(hres == S_OK, "GetScriptDispatch failed: %08lx\n", hres); + IActiveScript_Release(active_script); + hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex); + ok(hres == S_OK, "Could not get IDispatchEx: %08lx\n", hres); + IDispatch_Release(disp); + bstr = SysAllocString(L"testGetCallerFunc"); + hres = IDispatchEx_GetDispID(dispex, bstr, 0, &dispid); + ok(hres == S_OK, "GetDispID failed: %08lx\n", hres); + SysFreeString(bstr); + + hres = IDispatchEx_InvokeEx(dispex, dispid, 0, DISPATCH_PROPERTYGET, &dp, &var, NULL, NULL); + ok(hres == S_OK, "InvokeEx failed: %08lx\n", hres); + ok(V_VT(&var) == VT_DISPATCH, "V_VT(testGetCallerFunc) = %d\n", V_VT(&var)); + ok(V_DISPATCH(&var) != NULL, "V_DISPATCH(testGetCallerFunc) = NULL\n"); + IDispatchEx_Release(dispex); + hres = IDispatch_QueryInterface(V_DISPATCH(&var), &IID_IDispatchEx, (void**)&dispex); + ok(hres == S_OK, "Could not get IDispatchEx: %08lx\n", hres); + IDispatch_Release(V_DISPATCH(&var)); + + SET_EXPECT(OnEnterScript); + SET_EXPECT(OnLeaveScript); + SET_EXPECT(testGetCaller); + hres = IDispatchEx_InvokeEx(dispex, DISPID_VALUE, 0, DISPATCH_METHOD, &dp, NULL, NULL, NULL); + ok(hres == S_OK, "InvokeEx failed: %08lx\n", hres); + CHECK_CALLED(testGetCaller); + CHECK_CALLED(OnLeaveScript); + test_get_caller_sp = &sp_caller_obj; + SET_EXPECT(OnEnterScript); + SET_EXPECT(OnLeaveScript); + SET_EXPECT(testGetCaller); + hres = IDispatchEx_InvokeEx(dispex, DISPID_VALUE, 0, DISPATCH_METHOD, &dp, NULL, NULL, test_get_caller_sp); + ok(hres == S_OK, "InvokeEx failed: %08lx\n", hres); + CHECK_CALLED(testGetCaller); + CHECK_CALLED(OnLeaveScript); + IDispatchEx_Release(dispex); + + IActiveScriptParse_Release(active_script_parser); + active_script_parser = NULL; }
static BOOL check_jscript(void)