[PATCH v15 0/1] MR10368: vbscript: Implement Eval, Execute, and ExecuteGlobal.
Eval compiles the string as an expression and returns the result. ExecuteGlobal compiles and executes the string at global scope. Execute compiles and executes the string in the calling scope. When called from within a Sub or Function, Eval and Execute use the calling scope for variable resolution, accessing local variables and arguments. When called from global scope, they fall back to exec_global_code. ExecuteGlobal always executes in global scope. The calling scope is passed through script_ctx_t.caller_exec, which exec_script picks up and stores on exec_ctx_t.caller. The interpreter's lookup_identifier checks the caller's locals, arguments, and dynamic vars when running FUNC_GLOBAL code with a caller context set. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49908 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=53962 -- v15: vbscript: Implement Eval, Execute, and ExecuteGlobal. https://gitlab.winehq.org/wine/wine/-/merge_requests/10368
From: Francis De Brabandere <francisdb@gmail.com> Eval compiles the string as an expression and returns the result. ExecuteGlobal compiles and executes the string at global scope. Execute compiles and executes the string in the calling scope. When called from within a Sub or Function, Eval and Execute use the calling scope for variable resolution, accessing local variables and arguments. When called from global scope, they fall back to exec_global_code. ExecuteGlobal always executes in global scope. The calling scope is passed through script_ctx_t.caller_exec, which exec_script picks up and stores on exec_ctx_t.caller. The interpreter's lookup_identifier checks the caller's locals, arguments, and dynamic vars when running FUNC_GLOBAL code with a caller context set. Dim inside Execute adds variables to the caller's dynamic_vars when in local scope (Sub/Function), so they persist in the calling scope. Dim inside ExecuteGlobal creates global variables, with duplicate names silently skipped. check_script_collisions is bypassed for code compiled via Execute/ExecuteGlobal to allow re-declaration. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49908 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=53962 --- dlls/vbscript/compile.c | 11 +- dlls/vbscript/global.c | 77 ++++++++++- dlls/vbscript/interp.c | 87 ++++++++++++- dlls/vbscript/parser.y | 4 +- dlls/vbscript/tests/lang.vbs | 244 +++++++++++++++++++++++++++++++++++ dlls/vbscript/vbscript.c | 42 ++++-- dlls/vbscript/vbscript.h | 9 ++ 7 files changed, 454 insertions(+), 20 deletions(-) diff --git a/dlls/vbscript/compile.c b/dlls/vbscript/compile.c index 8c82d849a1b..73405349856 100644 --- a/dlls/vbscript/compile.c +++ b/dlls/vbscript/compile.c @@ -402,7 +402,14 @@ static HRESULT compile_error(script_ctx_t *ctx, compile_ctx_t *compiler, HRESULT ctx->ei.scode = error; ctx->ei.bstrSource = get_vbscript_string(VBS_COMPILE_ERROR); map_vbs_exception(&ctx->ei); - return report_script_error(ctx, compiler->code, compiler->loc, TRUE); + + if(!ctx->error_loc_code) { + grab_vbscode(compiler->code); + ctx->error_loc_code = compiler->code; + ctx->error_loc_offset = compiler->loc; + } + + return SCRIPT_E_RECORDED; } static expression_t *lookup_const_decls(compile_ctx_t *ctx, const WCHAR *name, BOOL lookup_global) @@ -2155,7 +2162,7 @@ HRESULT compile_script(script_ctx_t *script, const WCHAR *src, const WCHAR *item } hres = check_script_collisions(&ctx, script); - if(FAILED(hres)) { + if(FAILED(hres) && !(flags & SCRIPTTEXT_ISEXECUTE)) { hres = compile_error(script, &ctx, hres); release_compiler(&ctx); return hres; diff --git a/dlls/vbscript/global.c b/dlls/vbscript/global.c index 1d244b8207f..9387e7ecfcc 100644 --- a/dlls/vbscript/global.c +++ b/dlls/vbscript/global.c @@ -3333,20 +3333,85 @@ static HRESULT Global_Unescape(BuiltinDisp *This, VARIANT *arg, unsigned args_cn static HRESULT Global_Eval(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res) { - FIXME("\n"); - return E_NOTIMPL; + vbscode_t *code; + HRESULT hres; + + TRACE("%s\n", debugstr_variant(arg)); + + if(V_VT(arg) != VT_BSTR) { + if(res) + return VariantCopy(res, arg); + return S_OK; + } + + hres = compile_script(This->ctx, V_BSTR(arg), NULL, NULL, 0, 0, + SCRIPTTEXT_ISEXPRESSION, &code); + if(FAILED(hres)) { + clear_error_loc(This->ctx); + return hres; + } + + if(is_exec_local_scope(This->ctx->current_exec)) { + This->ctx->caller_exec = This->ctx->current_exec; + return exec_script(This->ctx, FALSE, &code->main_code, NULL, NULL, res); + } + + return exec_global_code(This->ctx, code, res, FALSE); } static HRESULT Global_Execute(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res) { - FIXME("\n"); - return E_NOTIMPL; + vbscode_t *code; + HRESULT hres; + + TRACE("%s\n", debugstr_variant(arg)); + + if(V_VT(arg) != VT_BSTR) + return MAKE_VBSERROR(VBSE_TYPE_MISMATCH); + + hres = compile_script(This->ctx, V_BSTR(arg), NULL, NULL, 0, 0, + SCRIPTTEXT_ISEXECUTE, &code); + if(FAILED(hres)) { + clear_error_loc(This->ctx); + return hres; + } + + if(is_exec_local_scope(This->ctx->current_exec)) { + unsigned i; + + /* Pre-register Dim variables in the caller's scope */ + for(i = 0; i < code->main_code.var_cnt; i++) { + hres = exec_add_caller_dynamic_var(This->ctx, This->ctx->current_exec, + code->main_code.vars[i].name); + if(FAILED(hres)) + return hres; + } + + This->ctx->caller_exec = This->ctx->current_exec; + return exec_script(This->ctx, FALSE, &code->main_code, NULL, NULL, res); + } + + return exec_global_code(This->ctx, code, res, FALSE); } static HRESULT Global_ExecuteGlobal(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res) { - FIXME("\n"); - return E_NOTIMPL; + vbscode_t *code; + HRESULT hres; + + TRACE("%s\n", debugstr_variant(arg)); + + if(V_VT(arg) != VT_BSTR) + return MAKE_VBSERROR(VBSE_TYPE_MISMATCH); + + hres = compile_script(This->ctx, V_BSTR(arg), NULL, NULL, 0, 0, + SCRIPTTEXT_ISEXECUTE, &code); + if(FAILED(hres)) { + clear_error_loc(This->ctx); + return hres; + } + + return exec_global_code(This->ctx, code, res, FALSE); } static HRESULT Global_GetRef(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res) diff --git a/dlls/vbscript/interp.c b/dlls/vbscript/interp.c index d8f0f80dfaa..bff6f49a869 100644 --- a/dlls/vbscript/interp.c +++ b/dlls/vbscript/interp.c @@ -47,6 +47,8 @@ typedef struct { VARIANT *stack; VARIANT ret_val; + + void *caller; } exec_ctx_t; typedef HRESULT (*instr_func_t)(exec_ctx_t*); @@ -182,6 +184,29 @@ static HRESULT lookup_identifier(exec_ctx_t *ctx, BSTR name, vbdisp_invoke_type_ } } + if(ctx->func->type == FUNC_GLOBAL && ctx->caller) { + exec_ctx_t *caller = ctx->caller; + + for(i=0; i < caller->func->var_cnt; i++) { + if(!wcsicmp(caller->func->vars[i].name, name)) { + ref->type = REF_VAR; + ref->u.v = caller->vars+i; + return S_OK; + } + } + + for(i=0; i < caller->func->arg_cnt; i++) { + if(!wcsicmp(caller->func->args[i].name, name)) { + ref->type = REF_VAR; + ref->u.v = caller->args+i; + return S_OK; + } + } + + if(lookup_dynamic_vars(caller->dynamic_vars, name, ref)) + return S_OK; + } + if(ctx->code->named_item) { if(lookup_global_vars(ctx->code->named_item->script_obj, name, ref)) return S_OK; @@ -293,7 +318,7 @@ void clear_ei(EXCEPINFO *ei) memset(ei, 0, sizeof(*ei)); } -static void clear_error_loc(script_ctx_t *ctx) +void clear_error_loc(script_ctx_t *ctx) { if(ctx->error_loc_code) { release_vbscode(ctx->error_loc_code); @@ -2488,14 +2513,69 @@ static void release_exec(exec_ctx_t *ctx) free(ctx->stack); } +BOOL is_exec_local_scope(void *exec) +{ + exec_ctx_t *ctx = exec; + return ctx && ctx->func->type != FUNC_GLOBAL; +} + +HRESULT exec_add_caller_dynamic_var(script_ctx_t *script, void *exec, const WCHAR *name) +{ + exec_ctx_t *ctx = exec; + dynamic_var_t *new_var; + heap_pool_t *heap; + WCHAR *str; + unsigned size, i; + + /* Skip if name already exists in caller's locals, args, or dynamic vars */ + for(i = 0; i < ctx->func->var_cnt; i++) { + if(!wcsicmp(ctx->func->vars[i].name, name)) + return S_OK; + } + for(i = 0; i < ctx->func->arg_cnt; i++) { + if(!wcsicmp(ctx->func->args[i].name, name)) + return S_OK; + } + { + dynamic_var_t *var; + for(var = ctx->dynamic_vars; var; var = var->next) { + if(!wcsicmp(var->name, name)) + return S_OK; + } + } + + heap = &ctx->heap; + + new_var = heap_pool_alloc(heap, sizeof(*new_var)); + if(!new_var) + return E_OUTOFMEMORY; + + size = (lstrlenW(name) + 1) * sizeof(WCHAR); + str = heap_pool_alloc(heap, size); + if(!str) + return E_OUTOFMEMORY; + memcpy(str, name, size); + new_var->name = str; + new_var->is_const = FALSE; + new_var->array = NULL; + V_VT(&new_var->v) = VT_EMPTY; + + new_var->next = ctx->dynamic_vars; + ctx->dynamic_vars = new_var; + return S_OK; +} + HRESULT exec_script(script_ctx_t *ctx, BOOL extern_caller, function_t *func, vbdisp_t *vbthis, DISPPARAMS *dp, VARIANT *res) { exec_ctx_t exec = {func->code_ctx}; named_item_t *prev_named_item; + void *prev_exec; vbsop_t op; HRESULT hres = S_OK; exec.code = func->code_ctx; + exec.caller = ctx->caller_exec; + ctx->caller_exec = NULL; if(dp ? func->arg_cnt != arg_cnt(dp) : func->arg_cnt) { FIXME("wrong arg_cnt %d, expected %d\n", dp ? arg_cnt(dp) : 0, func->arg_cnt); @@ -2568,6 +2648,9 @@ HRESULT exec_script(script_ctx_t *ctx, BOOL extern_caller, function_t *func, vbd prev_named_item = ctx->current_named_item; ctx->current_named_item = exec.code->named_item; + prev_exec = ctx->current_exec; + ctx->current_exec = &exec; + while(exec.instr) { op = exec.instr->op; hres = op_funcs[op](&exec); @@ -2628,6 +2711,8 @@ HRESULT exec_script(script_ctx_t *ctx, BOOL extern_caller, function_t *func, vbd exec.instr += op_move[op]; } + ctx->current_exec = prev_exec; + assert(!exec.top); if(extern_caller) { diff --git a/dlls/vbscript/parser.y b/dlls/vbscript/parser.y index c1a5b944268..976767e72aa 100644 --- a/dlls/vbscript/parser.y +++ b/dlls/vbscript/parser.y @@ -572,8 +572,8 @@ static int parser_error(unsigned *loc, parser_ctx_t *ctx, const char *str) if(ctx->error_loc == -1) ctx->error_loc = *loc; if(ctx->hres == S_OK) { - FIXME("%s: %s\n", debugstr_w(ctx->code + *loc), debugstr_a(str)); - ctx->hres = E_FAIL; + WARN("%s: %s\n", debugstr_w(ctx->code + *loc), debugstr_a(str)); + ctx->hres = MAKE_VBSERROR(VBSE_SYNTAX_ERROR); }else { WARN("%s: %08lx\n", debugstr_w(ctx->code + *loc), ctx->hres); } diff --git a/dlls/vbscript/tests/lang.vbs b/dlls/vbscript/tests/lang.vbs index c0d22606ba6..6eb44c55911 100644 --- a/dlls/vbscript/tests/lang.vbs +++ b/dlls/vbscript/tests/lang.vbs @@ -2616,6 +2616,250 @@ Err.Clear Set getRefRef = GetRef(vbNullString) Call ok(Err.Number = 5, "GetRef vbNullString error is " & Err.Number) +' Eval tests +Call ok(Eval("1 + 2") = 3, "Eval(""1 + 2"") = " & Eval("1 + 2")) +Call ok(Eval("""test""") = "test", "Eval(""""""test"""""") = " & Eval("""test""")) +Call ok(Eval("true") = true, "Eval(""true"") = " & Eval("true")) + +x = 5 +Call ok(Eval("x + 1") = 6, "Eval(""x + 1"") = " & Eval("x + 1")) +Call ok(Eval("x * x") = 25, "Eval(""x * x"") = " & Eval("x * x")) + +Sub TestEvalLocalScope + Dim a + a = 10 + Call ok(Eval("a") = 10, "Eval(""a"") in local scope = " & Eval("a")) + Call ok(Eval("a + 5") = 15, "Eval(""a + 5"") in local scope = " & Eval("a + 5")) +End Sub +Call TestEvalLocalScope + +Function TestEvalLocalArgs(x) + TestEvalLocalArgs = Eval("x * 2") +End Function +Call ok(TestEvalLocalArgs(7) = 14, "TestEvalLocalArgs(7) = " & TestEvalLocalArgs(7)) + +Dim evalLocal +Sub TestEvalNoLeak + Dim evalLocal + evalLocal = 77 + Call ok(Eval("evalLocal") = 77, "Eval evalLocal = " & Eval("evalLocal")) +End Sub +Call TestEvalNoLeak +Call ok(getVT(evalLocal) = "VT_EMPTY*", "evalLocal leaked from Eval scope: " & getVT(evalLocal)) + +' ExecuteGlobal tests +x = 0 +ExecuteGlobal "x = 42" +Call ok(x = 42, "ExecuteGlobal x = " & x) + +ExecuteGlobal "Function evalTestFunc : evalTestFunc = 7 : End Function" +Call ok(evalTestFunc() = 7, "evalTestFunc() = " & evalTestFunc()) + +' ExecuteGlobal: Dim creates a new global variable +ExecuteGlobal "Dim egVar1 : egVar1 = 42" +Call ok(egVar1 = 42, "ExecuteGlobal Dim egVar1 = " & egVar1) + +' ExecuteGlobal: Dim variable persists across calls +ExecuteGlobal "Dim egVar2" +ExecuteGlobal "egVar2 = 99" +Call ok(egVar2 = 99, "ExecuteGlobal Dim egVar2 (set later) = " & egVar2) + +' ExecuteGlobal inside Sub: Dim creates a GLOBAL variable +Sub TestExecGlobalDimInSub + ExecuteGlobal "Dim egFromSub : egFromSub = 123" +End Sub +Call TestExecGlobalDimInSub +Call ok(egFromSub = 123, "ExecuteGlobal Dim in Sub - egFromSub = " & egFromSub) + +' ExecuteGlobal: Dim + Function in same call +ExecuteGlobal "Dim egFuncVar : Function egGetVar() : egGetVar = egFuncVar : End Function" +egFuncVar = 777 +Call ok(egGetVar() = 777, "ExecuteGlobal Dim+Function: egGetVar() = " & egGetVar()) + +' ExecuteGlobal: ReDim creates global dynamic array +ExecuteGlobal "ReDim egDynArr(1) : egDynArr(0) = ""a"" : egDynArr(1) = ""b""" +Call ok(egDynArr(0) = "a", "ExecuteGlobal ReDim egDynArr(0) = " & egDynArr(0)) +Call ok(egDynArr(1) = "b", "ExecuteGlobal ReDim egDynArr(1) = " & egDynArr(1)) + +' Execute tests +x = 0 +Execute "x = 99" +Call ok(x = 99, "Execute x = " & x) + +Sub TestExecuteLocalScope + Dim a + a = 10 + Execute "a = 20" + Call ok(a = 20, "Execute local assign: a = " & a) +End Sub +Call TestExecuteLocalScope + +Dim executeLocal +Sub TestExecuteNoLeak + Dim executeLocal + executeLocal = 10 + Execute "executeLocal = 55" + Call ok(executeLocal = 55, "executeLocal = " & executeLocal) +End Sub +Call TestExecuteNoLeak +Call ok(getVT(executeLocal) = "VT_EMPTY*", "executeLocal leaked from Execute scope: " & getVT(executeLocal)) + +' Execute at global scope: Dim creates a new global variable +Execute "Dim exVar1 : exVar1 = 77" +Call ok(exVar1 = 77, "Execute (global) Dim exVar1 = " & exVar1) + +' Execute inside Sub: Dim creates variable visible in caller's scope +Sub TestExecuteDimInSub + Dim localA + localA = 10 + Execute "Dim localB : localB = 20" + Call ok(localB = 20, "Execute Dim in Sub - localB = " & localB) + Call ok(localA = 10, "Execute Dim in Sub - localA still = " & localA) +End Sub +Call TestExecuteDimInSub + +' Execute inside Function: Dim creates variable visible in function scope +Function TestExecuteDimInFunc + Execute "Dim funcVar : funcVar = 55" + TestExecuteDimInFunc = funcVar +End Function +Call ok(TestExecuteDimInFunc() = 55, "Execute Dim in Function = " & TestExecuteDimInFunc()) + +' Execute: Dim same name as existing local has no effect, value preserved +Sub TestExecuteDimShadow + Dim x + x = 100 + Execute "Dim x" + Call ok(x = 100, "x after Execute Dim x = " & x) + Execute "x = 200" + Call ok(x = 200, "x after Execute x=200 = " & x) +End Sub +Call TestExecuteDimShadow + +' Execute: Dim then use in same string, visible in caller +Sub TestExecuteDimAndUse + Execute "Dim euVar : euVar = 999" + Call ok(euVar = 999, "Execute Dim+use euVar = " & euVar) +End Sub +Call TestExecuteDimAndUse + +' Execute: ReDim creates dynamic array visible in caller +Sub TestExecuteReDim + Execute "ReDim dynArr(2) : dynArr(0) = 10 : dynArr(1) = 20 : dynArr(2) = 30" + Call ok(dynArr(1) = 20, "Execute ReDim dynArr(1) = " & dynArr(1)) +End Sub +Call TestExecuteReDim + +' Option Explicit is per-compilation-unit in Execute/ExecuteGlobal +On Error Resume Next + +' Option Explicit inside same Execute string enforces Dim requirement +Err.Clear +Execute "Option Explicit : noDimExec = 101" +Call ok(Err.Number <> 0, "Execute Option Explicit undeclared should error: err=" & Err.Number) +todo_wine_ok Err.Number = 500, "Execute Option Explicit undeclared: err=" & Err.Number & " expected 500" + +' Option Explicit inside same ExecuteGlobal string enforces Dim requirement +Err.Clear +ExecuteGlobal "Option Explicit : noDimExecGlobal = 102" +Call ok(Err.Number <> 0, "ExecuteGlobal Option Explicit undeclared should error: err=" & Err.Number) +todo_wine_ok Err.Number = 500, "ExecuteGlobal Option Explicit undeclared: err=" & Err.Number & " expected 500" + +' Option Explicit with Dim in same string works +Err.Clear +ExecuteGlobal "Option Explicit : Dim oeDimVar : oeDimVar = 555" +Call ok(Err.Number = 0, "ExecuteGlobal Option Explicit + Dim: err=" & Err.Number) +Call ok(oeDimVar = 555, "ExecuteGlobal Option Explicit + Dim: oeDimVar = " & oeDimVar) + +' Option Explicit does not propagate to subsequent calls +Err.Clear +ExecuteGlobal "Option Explicit" +Call ok(Err.Number = 0, "ExecuteGlobal Option Explicit alone: err=" & Err.Number) +Err.Clear +ExecuteGlobal "noDimAfterOE = 123" +Call ok(Err.Number = 0, "ExecuteGlobal after separate OE: err=" & Err.Number) + +On Error Goto 0 + + +' Eval/Execute/ExecuteGlobal error handling tests +On Error Resume Next + +' Test Eval with syntax error +Err.Clear +Call Eval("1 + ") +Call ok(Err.Number = 1002, "Eval syntax error: Err.Number = " & Err.Number & " expected 1002") +Call ok(Err.Description = "Syntax error", "Eval syntax error: Err.Description = """ & Err.Description & """ expected ""Syntax error""") +Call ok(Err.Source = "Microsoft VBScript compilation error", "Eval syntax error: Err.Source = """ & Err.Source & """") + +' Test Execute with syntax error +Err.Clear +Execute "x = " +Call ok(Err.Number = 1002, "Execute syntax error: Err.Number = " & Err.Number & " expected 1002") +Call ok(Err.Description = "Syntax error", "Execute syntax error: Err.Description = """ & Err.Description & """ expected ""Syntax error""") +Call ok(Err.Source = "Microsoft VBScript compilation error", "Execute syntax error: Err.Source = """ & Err.Source & """") + +' Test ExecuteGlobal with syntax error +Err.Clear +ExecuteGlobal "y = " +Call ok(Err.Number = 1002, "ExecuteGlobal syntax error: Err.Number = " & Err.Number & " expected 1002") +Call ok(Err.Description = "Syntax error", "ExecuteGlobal syntax error: Err.Description = """ & Err.Description & """ expected ""Syntax error""") +Call ok(Err.Source = "Microsoft VBScript compilation error", "ExecuteGlobal syntax error: Err.Source = """ & Err.Source & """") + +' Eval with non-string arguments returns the value directly +Err.Clear +Call ok(Eval(123) = 123, "Eval(123) = " & Eval(123)) +Call ok(Err.Number = 0, "Eval(123) Err.Number = " & Err.Number) + +Err.Clear +Call ok(Eval(True) = True, "Eval(True) = " & Eval(True)) +Call ok(Err.Number = 0, "Eval(True) Err.Number = " & Err.Number) + +Err.Clear +Call ok(IsNull(Eval(Null)), "Eval(Null) should be Null") +Call ok(Err.Number = 0, "Eval(Null) Err.Number = " & Err.Number) + +Err.Clear +Call ok(IsEmpty(Eval(Empty)), "Eval(Empty) should be Empty") +Call ok(Err.Number = 0, "Eval(Empty) Err.Number = " & Err.Number) + +' Execute with non-string arguments returns type mismatch +Err.Clear +Execute 123 +Call ok(Err.Number = 13, "Execute 123 Err.Number = " & Err.Number) + +Err.Clear +Execute Null +Call ok(Err.Number = 13, "Execute Null Err.Number = " & Err.Number) + +Err.Clear +Execute Empty +Call ok(Err.Number = 13, "Execute Empty Err.Number = " & Err.Number) + +' ExecuteGlobal with non-string arguments returns type mismatch +Err.Clear +ExecuteGlobal 123 +Call ok(Err.Number = 13, "ExecuteGlobal 123 Err.Number = " & Err.Number) + +Err.Clear +ExecuteGlobal Null +Call ok(Err.Number = 13, "ExecuteGlobal Null Err.Number = " & Err.Number) + +Err.Clear +ExecuteGlobal Empty +Call ok(Err.Number = 13, "ExecuteGlobal Empty Err.Number = " & Err.Number) + +' Eval with Dim is a syntax error (Eval expects an expression, not a statement) +Err.Clear +Eval "Dim evalDimVar" +Call ok(Err.Number = 1002, "Eval Dim: Err.Number = " & Err.Number & " expected 1002") + +' Test runtime error in Eval is caught by On Error Resume Next +Err.Clear +Call Eval("CBool(""notabool"")") +Call ok(Err.Number = 13, "Eval type mismatch: Err.Number = " & Err.Number & " expected 13") +Call ok(Err.Source = "Microsoft VBScript runtime error", "Eval type mismatch: Err.Source = """ & Err.Source & """") + On Error Goto 0 ' Test calling a dispatch variable as statement (invokes default property) diff --git a/dlls/vbscript/vbscript.c b/dlls/vbscript/vbscript.c index bc5a4ea416c..10f3a92f872 100644 --- a/dlls/vbscript/vbscript.c +++ b/dlls/vbscript/vbscript.c @@ -93,7 +93,7 @@ static inline BOOL is_started(VBScript *This) || This->state == SCRIPTSTATE_DISCONNECTED; } -static HRESULT exec_global_code(script_ctx_t *ctx, vbscode_t *code, VARIANT *res) +HRESULT exec_global_code(script_ctx_t *ctx, vbscode_t *code, VARIANT *res, BOOL extern_caller) { ScriptDisp *obj = ctx->script_obj; function_t *func_iter, **new_funcs; @@ -140,6 +140,20 @@ static HRESULT exec_global_code(script_ctx_t *ctx, vbscode_t *code, VARIANT *res for (i = 0; i < code->main_code.var_cnt; i++) { + size_t j; + BOOL found = FALSE; + + for (j = 0; j < obj->global_vars_cnt; j++) + { + if (!wcsicmp(obj->global_vars[j]->name, code->main_code.vars[i].name)) + { + found = TRUE; + break; + } + } + if (found) + continue; + if (!(var = heap_pool_alloc(&obj->heap, sizeof(*var)))) return E_OUTOFMEMORY; @@ -150,11 +164,9 @@ static HRESULT exec_global_code(script_ctx_t *ctx, vbscode_t *code, VARIANT *res var->is_const = FALSE; var->array = NULL; - obj->global_vars[obj->global_vars_cnt + i] = var; + obj->global_vars[obj->global_vars_cnt++] = var; } - obj->global_vars_cnt += code->main_code.var_cnt; - for (func_iter = code->funcs; func_iter; func_iter = func_iter->next) { for (i = 0; i < obj->global_funcs_cnt; i++) @@ -191,7 +203,7 @@ static HRESULT exec_global_code(script_ctx_t *ctx, vbscode_t *code, VARIANT *res prev_caller = ctx->vbcaller->caller; ctx->vbcaller->caller = SP_CALLER_UNINITIALIZED; - hres = exec_script(ctx, TRUE, &code->main_code, NULL, NULL, res); + hres = exec_script(ctx, extern_caller, &code->main_code, NULL, NULL, res); ctx->vbcaller->caller = prev_caller; return hres; } @@ -202,7 +214,7 @@ static void exec_queued_code(script_ctx_t *ctx) LIST_FOR_EACH_ENTRY(iter, &ctx->code_list, vbscode_t, entry) { if(iter->pending_exec) - exec_global_code(ctx, iter, NULL); + exec_global_code(ctx, iter, NULL, TRUE); } } @@ -1091,15 +1103,21 @@ static HRESULT WINAPI VBScriptParse_ParseScriptText(IActiveScriptParse *iface, hres = compile_script(This->ctx, pstrCode, pstrItemName, pstrDelimiter, dwSourceContextCookie, ulStartingLine, dwFlags, &code); - if(FAILED(hres)) + if(FAILED(hres)) { + if(hres == SCRIPT_E_RECORDED) { + hres = report_script_error(This->ctx, This->ctx->error_loc_code, + This->ctx->error_loc_offset, TRUE); + clear_error_loc(This->ctx); + } return hres; + } if(!(dwFlags & SCRIPTTEXT_ISEXPRESSION) && !is_started(This)) { code->pending_exec = TRUE; return S_OK; } - return exec_global_code(This->ctx, code, pvarResult); + return exec_global_code(This->ctx, code, pvarResult, TRUE); } static const IActiveScriptParseVtbl VBScriptParseVtbl = { @@ -1153,8 +1171,14 @@ static HRESULT WINAPI VBScriptParseProcedure_ParseProcedureText(IActiveScriptPar hres = compile_procedure(This->ctx, pstrCode, pstrItemName, pstrDelimiter, dwSourceContextCookie, ulStartingLineNumber, dwFlags, &desc); - if(FAILED(hres)) + if(FAILED(hres)) { + if(hres == SCRIPT_E_RECORDED) { + hres = report_script_error(This->ctx, This->ctx->error_loc_code, + This->ctx->error_loc_offset, TRUE); + clear_error_loc(This->ctx); + } return hres; + } hres = create_vbdisp(desc, &vbdisp); if(FAILED(hres)) diff --git a/dlls/vbscript/vbscript.h b/dlls/vbscript/vbscript.h index ced19f86bbc..f1a5d3271b8 100644 --- a/dlls/vbscript/vbscript.h +++ b/dlls/vbscript/vbscript.h @@ -208,6 +208,9 @@ struct _script_ctx_t { BuiltinDisp *global_obj; BuiltinDisp *err_obj; + void *current_exec; + void *caller_exec; + EXCEPINFO ei; vbscode_t *error_loc_code; unsigned error_loc_offset; @@ -391,12 +394,18 @@ static inline void grab_vbscode(vbscode_t *code) } void release_vbscode(vbscode_t*); +/* Internal flag to skip check_script_collisions - used by Execute/ExecuteGlobal */ +#define SCRIPTTEXT_ISEXECUTE 0x40000000 HRESULT compile_script(script_ctx_t*,const WCHAR*,const WCHAR*,const WCHAR*,DWORD_PTR,unsigned,DWORD,vbscode_t**); HRESULT compile_procedure(script_ctx_t*,const WCHAR*,const WCHAR*,const WCHAR*,DWORD_PTR,unsigned,DWORD,class_desc_t**); HRESULT exec_script(script_ctx_t*,BOOL,function_t*,vbdisp_t*,DISPPARAMS*,VARIANT*); +HRESULT exec_global_code(script_ctx_t*,vbscode_t*,VARIANT*,BOOL); +BOOL is_exec_local_scope(void*); +HRESULT exec_add_caller_dynamic_var(script_ctx_t*,void*,const WCHAR*); void release_dynamic_var(dynamic_var_t*); named_item_t *lookup_named_item(script_ctx_t*,const WCHAR*,unsigned); void release_named_item(named_item_t*); +void clear_error_loc(script_ctx_t*); void clear_ei(EXCEPINFO*); HRESULT report_script_error(script_ctx_t*,vbscode_t*,unsigned,BOOL); void detach_global_objects(script_ctx_t*); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10368
participants (2)
-
Francis De Brabandere -
Francis De Brabandere (@francisdb)