From: Francis De Brabandere <francisdb@gmail.com> When declaring variables with Dim in a visible named item context, check the named item's IDispatch for each variable name via GetIDsOfNames. This matches Windows VBScript behavior where Dim probes the host object before creating the variable. --- dlls/vbscript/tests/vbscript.c | 25 +++++++++++++++++++++-- dlls/vbscript/vbscript.c | 37 +++++++++++++++++++++++++++++++--- 2 files changed, 57 insertions(+), 5 deletions(-) diff --git a/dlls/vbscript/tests/vbscript.c b/dlls/vbscript/tests/vbscript.c index adda087ce76..25584990a62 100644 --- a/dlls/vbscript/tests/vbscript.c +++ b/dlls/vbscript/tests/vbscript.c @@ -2088,8 +2088,8 @@ static void test_named_items(void) hres = IActiveScriptParse_ParseScriptText(parse, L"dim abc\n", L"visibleItem", NULL, NULL, 0, 0, 0, NULL, NULL); ok(hres == S_OK, "ParseScriptText failed: %08lx\n", hres); CHECK_CALLED(OnEnterScript); - todo_wine CHECK_CALLED(GetItemInfo_visible); - todo_wine CHECK_CALLED(GetIDsOfNames_visible); + CHECK_CALLED(GetItemInfo_visible); + CHECK_CALLED(GetIDsOfNames_visible); CHECK_CALLED(OnLeaveScript); SET_EXPECT(OnEnterScript); SET_EXPECT(OnLeaveScript); @@ -2106,6 +2106,27 @@ static void test_named_items(void) CHECK_CALLED(GetIDsOfNames_visible); CHECK_CALLED(OnLeaveScript); + /* dim testCall under visibleItem: testCall exists on the host's dispatch, + so the dim should not create a local variable that shadows it. */ + SET_EXPECT(OnEnterScript); + SET_EXPECT(GetItemInfo_visible); + SET_EXPECT(OnLeaveScript); + hres = IActiveScriptParse_ParseScriptText(parse, L"dim testCall\n", L"visibleItem", NULL, NULL, 0, 0, 0, NULL, NULL); + ok(hres == S_OK, "ParseScriptText failed: %08lx\n", hres); + CHECK_CALLED(OnEnterScript); + CHECK_CALLED(GetItemInfo_visible); + CHECK_CALLED(OnLeaveScript); + + /* Verify testCall still resolves to the host method, not a local variable. */ + SET_EXPECT(OnEnterScript); + SET_EXPECT(testCall); + SET_EXPECT(OnLeaveScript); + hres = IActiveScriptParse_ParseScriptText(parse, L"testCall\n", L"visibleItem", NULL, NULL, 0, 0, 0, NULL, NULL); + ok(hres == S_OK, "ParseScriptText failed: %08lx\n", hres); + CHECK_CALLED(OnEnterScript); + CHECK_CALLED(testCall); + CHECK_CALLED(OnLeaveScript); + SET_EXPECT(OnEnterScript); SET_EXPECT(OnLeaveScript); hres = IActiveScriptParse_ParseScriptText(parse, L"dim abc\ntestVar_global = 5\n", L"visibleCodeItem", NULL, NULL, 0, 0, 0, NULL, NULL); diff --git a/dlls/vbscript/vbscript.c b/dlls/vbscript/vbscript.c index 715c98d32bb..bc71f1d366f 100644 --- a/dlls/vbscript/vbscript.c +++ b/dlls/vbscript/vbscript.c @@ -91,6 +91,8 @@ static inline BOOL is_started(VBScript *This) || This->state == SCRIPTSTATE_DISCONNECTED; } +static HRESULT retrieve_named_item_disp(IActiveScriptSite *site, named_item_t *item); + static HRESULT exec_global_code(script_ctx_t *ctx, vbscode_t *code, VARIANT *res) { ScriptDisp *obj = ctx->script_obj; @@ -136,8 +138,39 @@ static HRESULT exec_global_code(script_ctx_t *ctx, vbscode_t *code, VARIANT *res obj->global_funcs_size = cnt; } + /* For visible named items with Dim declarations, re-fetch the dispatch + from the host to ensure it is current before probing variable names. + Windows does this even if the dispatch was previously cached. */ + if(code->main_code.var_cnt && code->named_item + && !(code->named_item->flags & SCRIPTITEM_CODEONLY)) + { + if(code->named_item->disp) + { + IDispatch_Release(code->named_item->disp); + code->named_item->disp = NULL; + } + retrieve_named_item_disp(ctx->site, code->named_item); + } + for (i = 0; i < code->main_code.var_cnt; i++) { + /* If the name already exists on a visible named item's dispatch, + skip creating a local variable so the name resolves to the host + object's property at runtime instead of shadowing it. */ + if(code->named_item && code->named_item->disp + && !(code->named_item->flags & SCRIPTITEM_CODEONLY)) + { + DISPID id; + + if(SUCCEEDED(disp_get_id(code->named_item->disp, code->main_code.vars[i].name, + VBDISP_CALLGET, TRUE, &id))) + { + TRACE("%s found on named item dispatch, skipping local variable\n", + debugstr_w(code->main_code.vars[i].name)); + continue; + } + } + if (!(var = heap_pool_alloc(&obj->heap, sizeof(*var)))) return E_OUTOFMEMORY; @@ -148,11 +181,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++) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10393