From: Francis De Brabandere <francisdb@gmail.com> When parsing top-level declarations (Dim variables, Subs, Functions, Classes) in a visible named item context, the first such parse release-and-refetches the host IDispatch and probes each declared name on it via GetIDsOfNames. This matches Windows VBScript behavior; the variable/sub/function/class is always created regardless of whether the name exists on the host dispatch. Subsequent parses on the same named item reuse the cached dispatch and only probe newly declared names. --- dlls/vbscript/vbscript.c | 58 ++++++++++++++++++++++++++++++++++++++++ dlls/vbscript/vbscript.h | 1 + 2 files changed, 59 insertions(+) diff --git a/dlls/vbscript/vbscript.c b/dlls/vbscript/vbscript.c index ff28b3b17ef..a758caa9d40 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,6 +140,61 @@ 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 top-level + declarations release-and-refetches the host dispatch, then probes + each declared name (Dim variables, Subs, Functions, Classes) via + GetIDsOfNames. Subsequent parses reuse the cache. Names are always + declared regardless of whether they exist on the host dispatch. + TODO: It is unclear why Windows refetches the host dispatch on the + first declaration when the result is not used to skip name + creation. Perhaps it is used for some side effect or diagnostic + purpose that we have not yet identified. */ + if(code->named_item && !(code->named_item->flags & SCRIPTITEM_CODEONLY) + && (code->main_code.var_cnt || code->funcs || code->classes)) + { + if(!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; + } + } + + if(code->named_item && code->named_item->disp + && !(code->named_item->flags & SCRIPTITEM_CODEONLY)) + { + class_desc_t *class_iter; + + /* Probe top-level declared names (Dim vars, Subs/Functions, + Classes) on the host dispatch. */ + for (i = 0; i < code->main_code.var_cnt; i++) { + 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); + } + } + for (func_iter = code->funcs; func_iter; func_iter = func_iter->next) { + BSTR name = SysAllocString(func_iter->name); + if(name) { + DISPID id; + disp_get_id(code->named_item->disp, name, VBDISP_CALLGET, TRUE, &id); + SysFreeString(name); + } + } + for (class_iter = code->classes; class_iter; class_iter = class_iter->next) { + BSTR name = SysAllocString(class_iter->name); + if(name) { + DISPID id; + disp_get_id(code->named_item->disp, name, VBDISP_CALLGET, TRUE, &id); + SysFreeString(name); + } + } + } + for (i = 0; i < code->main_code.var_cnt; i++) { if (script_disp_find_var(obj, code->main_code.vars[i].name)) @@ -869,6 +926,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