[PATCH v2 0/1] MR11128: Draft: vbscript: Look up named items before builtin functions.
A named item shadows a builtin function of the same name in native VBScript, so a host item named like a builtin, e.g. Trim, resolves to the item. Global members of host objects do not shadow builtins. -- v2: vbscript: Look up named items before builtin functions. https://gitlab.winehq.org/wine/wine/-/merge_requests/11128
From: Francis De Brabandere <francisdb@gmail.com> A named item shadows a builtin function of the same name in native VBScript, so a host item named like a builtin, e.g. Trim, resolves to the item. Global members of host objects do not shadow builtins. Builtins are still checked first; a per-script count of visible named items whose names collide with builtins keeps the named item walk off the builtin lookup path for hosts with many named items. --- dlls/vbscript/interp.c | 9 ++++++++ dlls/vbscript/tests/run.c | 44 +++++++++++++++++++++++++++++++++++++++ dlls/vbscript/vbscript.c | 9 ++++++++ dlls/vbscript/vbscript.h | 2 ++ 4 files changed, 64 insertions(+) diff --git a/dlls/vbscript/interp.c b/dlls/vbscript/interp.c index 1b071d6f077..c352f15c4f7 100644 --- a/dlls/vbscript/interp.c +++ b/dlls/vbscript/interp.c @@ -227,6 +227,15 @@ static HRESULT lookup_identifier(exec_ctx_t *ctx, BSTR name, vbdisp_invoke_type_ hres = get_builtin_id(ctx->script->global_obj, name, &id); if(SUCCEEDED(hres)) { + /* A named item shadows a builtin function of the same name, while + global members of host objects do not. The counter avoids walking + the named item list on every builtin lookup. */ + if(ctx->script->builtin_shadow_cnt + && (item = lookup_named_item(ctx->script, name, SCRIPTITEM_ISVISIBLE)) && item->disp) { + ref->type = REF_OBJ; + ref->u.obj = item->disp; + return S_OK; + } ref->type = REF_DISP; ref->u.d.disp = &ctx->script->global_obj->IDispatch_iface; ref->u.d.id = id; diff --git a/dlls/vbscript/tests/run.c b/dlls/vbscript/tests/run.c index bee738d236c..20a835f7702 100644 --- a/dlls/vbscript/tests/run.c +++ b/dlls/vbscript/tests/run.c @@ -1242,6 +1242,8 @@ static HRESULT WINAPI Global_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD { L"invokeDisp", DISPID_GLOBAL_INVOKEDISP }, { L"invokeMethod", DISPID_GLOBAL_INVOKEMETHOD }, { L"testObj", DISPID_GLOBAL_TESTOBJ }, + /* host property sharing its name with a builtin function */ + { L"InputBox", DISPID_GLOBAL_TESTOBJ }, { L"collectionObj" , DISPID_GLOBAL_COLLOBJ }, { L"vbvar", DISPID_GLOBAL_VBVAR, REF_EXPECT(global_vbvar_d) }, { L"letobj", DISPID_GLOBAL_LETOBJ }, @@ -2079,6 +2081,8 @@ static HRESULT WINAPI ActiveScriptSite_GetItemInfo(IActiveScriptSite *iface, LPC *ppiunkItem = (IUnknown*)&Global; }else if(!lstrcmpW(pstrName, L"indexedObj")) { *ppiunkItem = (IUnknown*)&indexedObj; + }else if(!lstrcmpW(pstrName, L"Trim")) { + *ppiunkItem = (IUnknown*)&testObj; }else { ok(0, "unexpected pstrName %s\n", wine_dbgstr_w(pstrName)); *ppiunkItem = NULL; @@ -3745,6 +3749,39 @@ static void test_sub_decl_scope(void) } } +static void test_named_item_builtin_shadowing(void) +{ + IActiveScriptParse *parser; + IActiveScript *engine; + BSTR str; + HRESULT hres; + + strict_dispid_check = FALSE; + + engine = create_and_init_script(SCRIPTITEM_GLOBALMEMBERS, TRUE); + if(!engine) + return; + + hres = IActiveScript_QueryInterface(engine, &IID_IActiveScriptParse, (void**)&parser); + ok(hres == S_OK, "Could not get IActiveScriptParse: %08lx\n", hres); + + hres = IActiveScript_AddNamedItem(engine, L"Trim", SCRIPTITEM_ISVISIBLE); + ok(hres == S_OK, "AddNamedItem failed: %08lx\n", hres); + + str = SysAllocString(L"Call ok(getVT(Trim) = \"VT_DISPATCH\", \"getVT(Trim) = \" & getVT(Trim))\n" + L"Trim.propput = 1\n"); + SET_EXPECT(testobj_propput_d); + SET_EXPECT(testobj_propput_i); + hres = IActiveScriptParse_ParseScriptText(parser, str, NULL, NULL, NULL, 0, 0, 0, NULL, NULL); + ok(hres == S_OK, "ParseScriptText failed: %08lx\n", hres); + CHECK_CALLED(testobj_propput_d); + CHECK_CALLED(testobj_propput_i); + SysFreeString(str); + + IActiveScriptParse_Release(parser); + close_script(engine); +} + static void test_msgbox(void) { HRESULT hres; @@ -4240,6 +4277,12 @@ static void run_tests(void) CHECK_CALLED(testobj_propput_d); CHECK_CALLED(testobj_propput_i); + /* the builtin function wins over a global-members host property of the same name */ + SET_EXPECT(OnScriptError); + hres = parse_script_wr(L"InputBox.propput = 1"); + ok(hres == MAKE_VBSERROR(450), "InputBox.propput = 1 returned: %08lx\n", hres); + CHECK_CALLED(OnScriptError); + SET_EXPECT(global_propargput_d); SET_EXPECT(global_propargput_i); parse_script_w(L"propargput(counter(), counter()) = counter()"); @@ -4438,6 +4481,7 @@ static void run_tests(void) test_procedures(); test_gc(); test_msgbox(); + test_named_item_builtin_shadowing(); test_isexpression(); test_option_explicit_errors(); test_parse_errors(); diff --git a/dlls/vbscript/vbscript.c b/dlls/vbscript/vbscript.c index ff28b3b17ef..2a10e6e2ec0 100644 --- a/dlls/vbscript/vbscript.c +++ b/dlls/vbscript/vbscript.c @@ -311,6 +311,8 @@ static void release_script(script_ctx_t *ctx) release_named_item_script_obj(item); if(!(item->flags & SCRIPTITEM_ISPERSISTENT)) { + if(item->shadows_builtin) + ctx->builtin_shadow_cnt--; list_remove(&item->entry); release_named_item(item); } @@ -352,6 +354,7 @@ static void release_named_item_list(script_ctx_t *ctx) list_remove(&iter->entry); release_named_item(iter); } + ctx->builtin_shadow_cnt = 0; } static void decrease_state(VBScript *This, SCRIPTSTATE state) @@ -835,6 +838,7 @@ static HRESULT WINAPI VBScript_AddNamedItem(IActiveScript *iface, LPCOLESTR pstr named_item_t *item; IDispatch *disp = NULL; HRESULT hres; + DISPID id; TRACE("(%p)->(%s %lx)\n", This, debugstr_w(pstrName), dwFlags); @@ -877,6 +881,11 @@ static HRESULT WINAPI VBScript_AddNamedItem(IActiveScript *iface, LPCOLESTR pstr return E_OUTOFMEMORY; } + item->shadows_builtin = (dwFlags & SCRIPTITEM_ISVISIBLE) + && get_builtin_id(This->ctx->global_obj, item->name, &id) == S_OK; + if(item->shadows_builtin) + This->ctx->builtin_shadow_cnt++; + list_add_tail(&This->ctx->named_items, &item->entry); return S_OK; } diff --git a/dlls/vbscript/vbscript.h b/dlls/vbscript/vbscript.h index e3c57b0f8e5..4cbfd6a93a0 100644 --- a/dlls/vbscript/vbscript.h +++ b/dlls/vbscript/vbscript.h @@ -162,6 +162,7 @@ typedef struct named_item_t { IDispatch *disp; unsigned ref; DWORD flags; + BOOL shadows_builtin; LPWSTR name; struct list entry; @@ -216,6 +217,7 @@ struct _script_ctx_t { ScriptDisp *script_obj; named_item_t *current_named_item; + unsigned builtin_shadow_cnt; BuiltinDisp *global_obj; BuiltinDisp *err_obj; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11128
participants (2)
-
Francis De Brabandere -
Francis De Brabandere (@francisdb)