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 | 4 ++-- dlls/vbscript/vbscript.c | 38 ++++++++++++++++++++++++++++++++++ dlls/vbscript/vbscript.h | 1 + 3 files changed, 41 insertions(+), 2 deletions(-) diff --git a/dlls/vbscript/tests/vbscript.c b/dlls/vbscript/tests/vbscript.c index 7500ec30a8d..2eb366fe1c0 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); diff --git a/dlls/vbscript/vbscript.c b/dlls/vbscript/vbscript.c index ff28b3b17ef..6bdc692d82d 100644 --- a/dlls/vbscript/vbscript.c +++ b/dlls/vbscript/vbscript.c @@ -93,6 +93,8 @@ static inline BOOL is_started(VBScript *This) || This->state == SCRIPTSTATE_DISCONNECTED; } +static HRESULT retrieve_named_item_disp(IActiveScriptSite *site, named_item_t *item); + HRESULT exec_global_code(script_ctx_t *ctx, vbscode_t *code, VARIANT *res, BOOL extern_caller) { ScriptDisp *obj = ctx->script_obj; @@ -138,8 +140,43 @@ HRESULT exec_global_code(script_ctx_t *ctx, vbscode_t *code, VARIANT *res, BOOL obj->global_funcs_size = cnt; } + /* For visible named items, the first exec_global_code with Dim + declarations release-and-refetches the host dispatch, then probes + each variable name via GetIDsOfNames. Subsequent parses reuse the + cache; the variable is always created regardless of whether the + name exists on the host dispatch. + TODO: It is unclear why Windows refetches the host dispatch on the + first Dim when the result is not used to skip variable creation. + Perhaps it is used for some side effect or diagnostic purpose that + we have not yet identified. */ + if(code->main_code.var_cnt && code->named_item + && !(code->named_item->flags & SCRIPTITEM_CODEONLY) + && !code->named_item->dim_disp_probed) + { + 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); + code->named_item->dim_disp_probed = TRUE; + } + for (i = 0; i < code->main_code.var_cnt; i++) { + /* Probe the named item's dispatch for each variable name, matching + Windows behavior. The variable is always created regardless. */ + if(code->named_item && code->named_item->disp + && !(code->named_item->flags & SCRIPTITEM_CODEONLY)) + { + BSTR name = SysAllocString(code->main_code.vars[i].name); + if(name) + { + DISPID id; + disp_get_id(code->named_item->disp, name, VBDISP_CALLGET, TRUE, &id); + SysFreeString(name); + } + } + if (script_disp_find_var(obj, code->main_code.vars[i].name)) continue; @@ -869,6 +906,7 @@ static HRESULT WINAPI VBScript_AddNamedItem(IActiveScript *iface, LPCOLESTR pstr item->disp = disp; item->flags = dwFlags; item->script_obj = NULL; + item->dim_disp_probed = FALSE; item->name = wcsdup(pstrName); if(!item->name) { if(disp) diff --git a/dlls/vbscript/vbscript.h b/dlls/vbscript/vbscript.h index 1420e2da0d1..b0a674cc67f 100644 --- a/dlls/vbscript/vbscript.h +++ b/dlls/vbscript/vbscript.h @@ -163,6 +163,7 @@ typedef struct named_item_t { unsigned ref; DWORD flags; LPWSTR name; + BOOL dim_disp_probed; struct list entry; } named_item_t; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10393