The current code can't cope with it, so do the same thing as in GetDispID, to prevent a possible crash.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com ---
v4: Added a lot more tests. Store a ref to the named item in vbscode_t. Implement SCRIPTITEM_CODEONLY properly.
dlls/vbscript/vbdisp.c | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/dlls/vbscript/vbdisp.c b/dlls/vbscript/vbdisp.c index c14cd7b..36eba21 100644 --- a/dlls/vbscript/vbdisp.c +++ b/dlls/vbscript/vbdisp.c @@ -1388,6 +1388,9 @@ static HRESULT WINAPI ScriptDisp_InvokeEx(IDispatchEx *iface, DISPID id, LCID lc
TRACE("(%p)->(%x %x %x %p %p %p %p)\n", This, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller);
+ if (!This->ctx) + return E_UNEXPECTED; + if (id & DISPID_FUNCTION_MASK) { id &= ~DISPID_FUNCTION_MASK;
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com ---
Simplifies the 5th patch.
dlls/vbscript/interp.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-)
diff --git a/dlls/vbscript/interp.c b/dlls/vbscript/interp.c index b328674..f0820be 100644 --- a/dlls/vbscript/interp.c +++ b/dlls/vbscript/interp.c @@ -110,6 +110,22 @@ static BOOL lookup_global_vars(ScriptDisp *script, const WCHAR *name, ref_t *ref return FALSE; }
+static BOOL lookup_global_funcs(ScriptDisp *script, const WCHAR *name, ref_t *ref) +{ + function_t **funcs = script->global_funcs; + size_t i, cnt = script->global_funcs_cnt; + + for(i = 0; i < cnt; i++) { + if(!wcsicmp(funcs[i]->name, name)) { + ref->type = REF_FUNC; + ref->u.f = funcs[i]; + return TRUE; + } + } + + return FALSE; +} + static HRESULT lookup_identifier(exec_ctx_t *ctx, BSTR name, vbdisp_invoke_type_t invoke_type, ref_t *ref) { ScriptDisp *script_obj = ctx->script->script_obj; @@ -177,15 +193,8 @@ static HRESULT lookup_identifier(exec_ctx_t *ctx, BSTR name, vbdisp_invoke_type_
if(lookup_global_vars(script_obj, name, ref)) return S_OK; - - for(i = 0; i < script_obj->global_funcs_cnt; i++) { - function_t *func = script_obj->global_funcs[i]; - if(!wcsicmp(func->name, name)) { - ref->type = REF_FUNC; - ref->u.f = func; - return S_OK; - } - } + if(lookup_global_funcs(script_obj, name, ref)) + return S_OK;
hres = get_builtin_id(ctx->script->global_obj, name, &id); if(SUCCEEDED(hres)) {
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com ---
This is needed for 5th patch to avoid forward declaring ScriptDisp.
dlls/vbscript/vbscript.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/dlls/vbscript/vbscript.h b/dlls/vbscript/vbscript.h index f37b0ce..589abc3 100644 --- a/dlls/vbscript/vbscript.h +++ b/dlls/vbscript/vbscript.h @@ -55,14 +55,6 @@ typedef struct _vbscode_t vbscode_t; typedef struct _script_ctx_t script_ctx_t; typedef struct _vbdisp_t vbdisp_t;
-typedef struct named_item_t { - IDispatch *disp; - DWORD flags; - LPWSTR name; - - struct list entry; -} named_item_t; - typedef enum { VBDISP_CALLGET, VBDISP_LET, @@ -156,6 +148,14 @@ typedef struct { script_ctx_t *ctx; } BuiltinDisp;
+typedef struct named_item_t { + IDispatch *disp; + DWORD flags; + LPWSTR name; + + struct list entry; +} named_item_t; + HRESULT create_vbdisp(const class_desc_t*,vbdisp_t**) DECLSPEC_HIDDEN; HRESULT disp_get_id(IDispatch*,BSTR,vbdisp_invoke_type_t,BOOL,DISPID*) DECLSPEC_HIDDEN; HRESULT vbdisp_get_id(vbdisp_t*,BSTR,vbdisp_invoke_type_t,BOOL,DISPID*) DECLSPEC_HIDDEN;
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com ---
The tests that are added as part of testing the named item script dispatches are sufficient to cover the remaining cases, otherwise many calls fail both on Windows and Wine (we already have ok(0, ...) tests for those, it's not really necessary to add more tests for the same thing, in my opinion).
dlls/vbscript/compile.c | 2 +- dlls/vbscript/interp.c | 2 +- dlls/vbscript/tests/vbscript.c | 56 +++++++++++++++++++++++++++++++++- dlls/vbscript/vbscript.c | 4 +-- dlls/vbscript/vbscript.h | 2 +- 5 files changed, 60 insertions(+), 6 deletions(-)
diff --git a/dlls/vbscript/compile.c b/dlls/vbscript/compile.c index 9888109..cd33641 100644 --- a/dlls/vbscript/compile.c +++ b/dlls/vbscript/compile.c @@ -1933,7 +1933,7 @@ HRESULT compile_script(script_ctx_t *script, const WCHAR *src, const WCHAR *item HRESULT hres;
if(item_name) { - item = lookup_named_item(script, item_name, 0); + item = lookup_named_item(script, item_name, 0, SCRIPTITEM_CODEONLY); if(!item) { WARN("Unknown context %s\n", debugstr_w(item_name)); return E_INVALIDARG; diff --git a/dlls/vbscript/interp.c b/dlls/vbscript/interp.c index f0820be..adffc25 100644 --- a/dlls/vbscript/interp.c +++ b/dlls/vbscript/interp.c @@ -204,7 +204,7 @@ static HRESULT lookup_identifier(exec_ctx_t *ctx, BSTR name, vbdisp_invoke_type_ return S_OK; }
- item = lookup_named_item(ctx->script, name, SCRIPTITEM_ISVISIBLE); + item = lookup_named_item(ctx->script, name, SCRIPTITEM_ISVISIBLE, 0); if(item && item->disp) { ref->type = REF_OBJ; ref->u.obj = item->disp; diff --git a/dlls/vbscript/tests/vbscript.c b/dlls/vbscript/tests/vbscript.c index 10af993..4e44758 100644 --- a/dlls/vbscript/tests/vbscript.c +++ b/dlls/vbscript/tests/vbscript.c @@ -97,6 +97,7 @@ DEFINE_EXPECT(OnEnterScript); DEFINE_EXPECT(OnLeaveScript); DEFINE_EXPECT(GetItemInfo_global); DEFINE_EXPECT(GetItemInfo_visible); +DEFINE_EXPECT(GetItemInfo_visible_code); DEFINE_EXPECT(testCall);
DEFINE_GUID(CLSID_VBScript, 0xb54f3741, 0x5b07, 0x11cf, 0xa4,0xb0, 0x00,0xaa,0x00,0x4a,0x55,0xe8); @@ -137,7 +138,7 @@ static HRESULT WINAPI Dispatch_QueryInterface(IDispatch *iface, REFIID riid, voi return E_NOINTERFACE; }
-static ULONG global_named_item_ref, visible_named_item_ref; +static ULONG global_named_item_ref, visible_named_item_ref, visible_code_named_item_ref;
static ULONG WINAPI global_AddRef(IDispatch *iface) { @@ -159,6 +160,16 @@ static ULONG WINAPI visible_Release(IDispatch *iface) return --visible_named_item_ref; }
+static ULONG WINAPI visible_code_AddRef(IDispatch *iface) +{ + return ++visible_code_named_item_ref; +} + +static ULONG WINAPI visible_code_Release(IDispatch *iface) +{ + return --visible_code_named_item_ref; +} + static HRESULT WINAPI Dispatch_GetTypeInfoCount(IDispatch *iface, UINT *pctinfo) { ok(0, "unexpected call\n"); @@ -214,6 +225,18 @@ static const IDispatchVtbl visible_named_item_vtbl = {
static IDispatch visible_named_item = { &visible_named_item_vtbl };
+static const IDispatchVtbl visible_code_named_item_vtbl = { + Dispatch_QueryInterface, + visible_code_AddRef, + visible_code_Release, + Dispatch_GetTypeInfoCount, + Dispatch_GetTypeInfo, + Dispatch_GetIDsOfNames, + Dispatch_Invoke +}; + +static IDispatch visible_code_named_item = { &visible_code_named_item_vtbl }; + static HRESULT WINAPI ActiveScriptSite_QueryInterface(IActiveScriptSite *iface, REFIID riid, void **ppv) { *ppv = NULL; @@ -261,6 +284,12 @@ static HRESULT WINAPI ActiveScriptSite_GetItemInfo(IActiveScriptSite *iface, LPC *item_unk = (IUnknown*)&visible_named_item; return S_OK; } + if(!wcscmp(name, L"visibleCodeItem")) { + CHECK_EXPECT(GetItemInfo_visible_code); + IDispatch_AddRef(&visible_code_named_item); + *item_unk = (IUnknown*)&visible_code_named_item; + return S_OK; + } ok(0, "unexpected call %s\n", wine_dbgstr_w(name)); return E_NOTIMPL; } @@ -1704,6 +1733,7 @@ static void test_named_items(void) { IActiveScriptParse *parse; IActiveScript *script; + IDispatch *disp; ULONG ref; HRESULT hres;
@@ -1731,9 +1761,12 @@ static void test_named_items(void)
hres = IActiveScript_AddNamedItem(script, L"visibleItem", SCRIPTITEM_ISVISIBLE); ok(hres == S_OK, "AddNamedItem failed: %08x\n", hres); + hres = IActiveScript_AddNamedItem(script, L"visibleCodeItem", SCRIPTITEM_ISVISIBLE | SCRIPTITEM_CODEONLY); + ok(hres == S_OK, "AddNamedItem failed: %08x\n", hres);
ok(global_named_item_ref > 0, "global_named_item_ref = %u\n", global_named_item_ref); ok(visible_named_item_ref == 0, "visible_named_item_ref = %u\n", visible_named_item_ref); + ok(visible_code_named_item_ref == 0, "visible_code_named_item_ref = %u\n", visible_code_named_item_ref);
SET_EXPECT(OnStateChange_INITIALIZED); hres = IActiveScriptParse_InitNew(parse); @@ -1755,8 +1788,28 @@ static void test_named_items(void) CHECK_CALLED(GetItemInfo_visible); CHECK_CALLED(testCall);
+ SET_EXPECT(OnEnterScript); + SET_EXPECT(OnLeaveScript); + SET_EXPECT(testCall); + hres = IActiveScriptParse_ParseScriptText(parse, L"testCall\n", L"visibleCodeItem", NULL, NULL, 0, 0, 0, NULL, NULL); + ok(hres == S_OK, "ParseScriptText failed: %08x\n", hres); + CHECK_CALLED(OnEnterScript); + CHECK_CALLED(OnLeaveScript); + CHECK_CALLED(testCall); + + hres = IActiveScript_GetScriptDispatch(script, L"visibleCodeItem", &disp); + ok(hres == S_OK, "GetScriptDispatch returned: %08x\n", hres); + IDispatch_Release(disp); + + SET_EXPECT(GetItemInfo_visible_code); + SET_EXPECT(testCall); + parse_script(parse, "visibleCodeItem.testCall\n"); + CHECK_CALLED(GetItemInfo_visible_code); + CHECK_CALLED(testCall); + ok(global_named_item_ref > 0, "global_named_item_ref = %u\n", global_named_item_ref); ok(visible_named_item_ref == 1, "visible_named_item_ref = %u\n", visible_named_item_ref); + ok(visible_code_named_item_ref == 1, "visible_code_named_item_ref = %u\n", visible_code_named_item_ref);
SET_EXPECT(testCall); parse_script(parse, "visibleItem.testCall\n"); @@ -1773,6 +1826,7 @@ static void test_named_items(void)
ok(global_named_item_ref == 0, "global_named_item_ref = %u\n", global_named_item_ref); ok(visible_named_item_ref == 0, "visible_named_item_ref = %u\n", visible_named_item_ref); + ok(visible_code_named_item_ref == 0, "visible_code_named_item_ref = %u\n", visible_code_named_item_ref);
test_state(script, SCRIPTSTATE_CLOSED);
diff --git a/dlls/vbscript/vbscript.c b/dlls/vbscript/vbscript.c index 88574fe..3b80fe8 100644 --- a/dlls/vbscript/vbscript.c +++ b/dlls/vbscript/vbscript.c @@ -189,14 +189,14 @@ static void exec_queued_code(script_ctx_t *ctx) } }
-named_item_t *lookup_named_item(script_ctx_t *ctx, const WCHAR *name, unsigned flags) +named_item_t *lookup_named_item(script_ctx_t *ctx, const WCHAR *name, unsigned flags, unsigned no_disp_flags) { named_item_t *item; HRESULT hres;
LIST_FOR_EACH_ENTRY(item, &ctx->named_items, named_item_t, entry) { if((item->flags & flags) == flags && !wcsicmp(item->name, name)) { - if(!item->disp) { + if(!item->disp && !(item->flags & no_disp_flags)) { IUnknown *unk;
hres = IActiveScriptSite_GetItemInfo(ctx->site, item->name, diff --git a/dlls/vbscript/vbscript.h b/dlls/vbscript/vbscript.h index 589abc3..941834c 100644 --- a/dlls/vbscript/vbscript.h +++ b/dlls/vbscript/vbscript.h @@ -372,7 +372,7 @@ HRESULT compile_script(script_ctx_t*,const WCHAR*,const WCHAR*,const WCHAR*,DWOR HRESULT compile_procedure(script_ctx_t*,const WCHAR*,const WCHAR*,const WCHAR*,DWORD_PTR,unsigned,DWORD,class_desc_t**) DECLSPEC_HIDDEN; HRESULT exec_script(script_ctx_t*,BOOL,function_t*,vbdisp_t*,DISPPARAMS*,VARIANT*) DECLSPEC_HIDDEN; void release_dynamic_var(dynamic_var_t*) DECLSPEC_HIDDEN; -named_item_t *lookup_named_item(script_ctx_t*,const WCHAR*,unsigned) DECLSPEC_HIDDEN; +named_item_t *lookup_named_item(script_ctx_t*,const WCHAR*,unsigned,unsigned) DECLSPEC_HIDDEN; void clear_ei(EXCEPINFO*) DECLSPEC_HIDDEN; HRESULT report_script_error(script_ctx_t*,const vbscode_t*,unsigned) DECLSPEC_HIDDEN; void detach_global_objects(script_ctx_t*) DECLSPEC_HIDDEN;
Hi Gabriel,
On 07.02.2020 14:55, Gabriel Ivăncescu wrote:
-named_item_t *lookup_named_item(script_ctx_t *ctx, const WCHAR *name, unsigned flags) +named_item_t *lookup_named_item(script_ctx_t *ctx, const WCHAR *name, unsigned flags, unsigned no_disp_flags) { named_item_t *item; HRESULT hres;
LIST_FOR_EACH_ENTRY(item, &ctx->named_items, named_item_t, entry) { if((item->flags & flags) == flags && !wcsicmp(item->name, name)) {
if(!item->disp) {
if(!item->disp && !(item->flags & no_disp_flags)) {
Can you just always check for SCRIPTITEM_CODEONLY before trying to fetch IDispatch instead of introducing an additional argument?
Thanks,
Jacek
On 11/02/2020 15:33, Jacek Caban wrote:
Hi Gabriel,
On 07.02.2020 14:55, Gabriel Ivăncescu wrote:
-named_item_t *lookup_named_item(script_ctx_t *ctx, const WCHAR *name, unsigned flags) +named_item_t *lookup_named_item(script_ctx_t *ctx, const WCHAR *name, unsigned flags, unsigned no_disp_flags) { named_item_t *item; HRESULT hres; LIST_FOR_EACH_ENTRY(item, &ctx->named_items, named_item_t, entry) { if((item->flags & flags) == flags && !wcsicmp(item->name, name)) { - if(!item->disp) { + if(!item->disp && !(item->flags & no_disp_flags)) {
Can you just always check for SCRIPTITEM_CODEONLY before trying to fetch IDispatch instead of introducing an additional argument?
Thanks,
Jacek
Hi Jacek,
That's what I originally had and it's wrong in some corner cases (see the tests). Specifically, items with SCRIPTITEM_ISVISIBLE will fetch the IDispatch in the interpreter, even if they have the SCRIPTITEM_CODEONLY flag (i.e. they have both).
The SCRIPTITEM_CODEONLY flag stops fetching it only from:
* GetScriptDispatch * ParseScriptText * ParseProcedureText
Without the SCRIPTITEM_CODEONLY flag, the IDispatch will be fetched in the above functions. (you can check this in the tests I wrote, by removing the flag from the test, it should give exact same test failures as on Windows)
With the flag, it's not fetched. However, items with SCRIPTITEM_ISVISIBLE will *still* fetch it in the interpreter, when they're found in code. This is where my previous attempt was wrong, and why we need the new argument. In the tests, "visibleCodeItem" should test this. Unless I am missing something here.
Thanks, Gabriel
Each named item should have its own associated script dispatch object. Identifiers are added to this object, but code does look into the global script object as well.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/vbscript/compile.c | 47 ++++++++++++++++++++++++-------------- dlls/vbscript/interp.c | 27 ++++++++++++++++------ dlls/vbscript/vbscript.c | 49 +++++++++++++++++++++++++++++++++++++--- dlls/vbscript/vbscript.h | 3 +++ 4 files changed, 99 insertions(+), 27 deletions(-)
diff --git a/dlls/vbscript/compile.c b/dlls/vbscript/compile.c index cd33641..07d27a8 100644 --- a/dlls/vbscript/compile.c +++ b/dlls/vbscript/compile.c @@ -1778,26 +1778,33 @@ static HRESULT compile_class(compile_ctx_t *ctx, class_decl_t *class_decl) return S_OK; }
-static BOOL lookup_script_identifier(script_ctx_t *script, const WCHAR *identifier) +static BOOL lookup_script_identifier(compile_ctx_t *ctx, script_ctx_t *script, const WCHAR *identifier) { - ScriptDisp *obj = script->script_obj; + ScriptDisp *contexts[] = { + ctx->code->named_item ? ctx->code->named_item->script_obj : NULL, + script->script_obj + }; class_desc_t *class; vbscode_t *code; - unsigned i; + unsigned c, i;
- for(i = 0; i < obj->global_vars_cnt; i++) { - if(!wcsicmp(obj->global_vars[i]->name, identifier)) - return TRUE; - } + for(c = 0; c < ARRAY_SIZE(contexts); c++) { + if(!contexts[c]) continue;
- for(i = 0; i < obj->global_funcs_cnt; i++) { - if(!wcsicmp(obj->global_funcs[i]->name, identifier)) - return TRUE; - } + for(i = 0; i < contexts[c]->global_vars_cnt; i++) { + if(!wcsicmp(contexts[c]->global_vars[i]->name, identifier)) + return TRUE; + }
- for(class = obj->classes; class; class = class->next) { - if(!wcsicmp(class->name, identifier)) - return TRUE; + for(i = 0; i < contexts[c]->global_funcs_cnt; i++) { + if(!wcsicmp(contexts[c]->global_funcs[i]->name, identifier)) + return TRUE; + } + + for(class = contexts[c]->classes; class; class = class->next) { + if(!wcsicmp(class->name, identifier)) + return TRUE; + } }
LIST_FOR_EACH_ENTRY(code, &script->code_list, vbscode_t, entry) { @@ -1805,7 +1812,7 @@ static BOOL lookup_script_identifier(script_ctx_t *script, const WCHAR *identifi var_desc_t *vars = code->main_code.vars; function_t *func;
- if(!code->pending_exec) + if(!code->pending_exec || (code->named_item && code->named_item != ctx->code->named_item)) continue;
for(i = 0; i < var_cnt; i++) { @@ -1834,14 +1841,14 @@ static HRESULT check_script_collisions(compile_ctx_t *ctx, script_ctx_t *script) class_desc_t *class;
for(i = 0; i < var_cnt; i++) { - if(lookup_script_identifier(script, vars[i].name)) { + if(lookup_script_identifier(ctx, script, vars[i].name)) { FIXME("%s: redefined\n", debugstr_w(vars[i].name)); return E_FAIL; } }
for(class = ctx->code->classes; class; class = class->next) { - if(lookup_script_identifier(script, class->name)) { + if(lookup_script_identifier(ctx, script, class->name)) { FIXME("%s: redefined\n", debugstr_w(class->name)); return E_FAIL; } @@ -1862,6 +1869,8 @@ void release_vbscode(vbscode_t *code)
if(code->context) IDispatch_Release(code->context); + if(code->named_item && !--code->named_item->ref) + heap_free(code->named_item); heap_pool_free(&code->heap);
heap_free(code->bstr_pool); @@ -1944,6 +1953,10 @@ HRESULT compile_script(script_ctx_t *script, const WCHAR *src, const WCHAR *item code = ctx.code = alloc_vbscode(&ctx, src, cookie, start_line); if(!ctx.code) return E_OUTOFMEMORY; + if(item) { + code->named_item = item; + item->ref++; + }
hres = parse_script(&ctx.parser, code->source, delimiter, flags); if(FAILED(hres)) { diff --git a/dlls/vbscript/interp.c b/dlls/vbscript/interp.c index adffc25..ff8949f 100644 --- a/dlls/vbscript/interp.c +++ b/dlls/vbscript/interp.c @@ -191,6 +191,13 @@ static HRESULT lookup_identifier(exec_ctx_t *ctx, BSTR name, vbdisp_invoke_type_ } }
+ if(ctx->code->named_item) { + if(lookup_global_vars(ctx->code->named_item->script_obj, name, ref)) + return S_OK; + if(lookup_global_funcs(ctx->code->named_item->script_obj, name, ref)) + return S_OK; + } + if(lookup_global_vars(script_obj, name, ref)) return S_OK; if(lookup_global_funcs(script_obj, name, ref)) @@ -230,7 +237,7 @@ static HRESULT lookup_identifier(exec_ctx_t *ctx, BSTR name, vbdisp_invoke_type_ static HRESULT add_dynamic_var(exec_ctx_t *ctx, const WCHAR *name, BOOL is_const, VARIANT **out_var) { - ScriptDisp *script_obj = ctx->script->script_obj; + ScriptDisp *script_obj = ctx->code->named_item ? ctx->code->named_item->script_obj : ctx->script->script_obj; dynamic_var_t *new_var; heap_pool_t *heap; WCHAR *str; @@ -1113,7 +1120,7 @@ static HRESULT interp_deref(exec_ctx_t *ctx) static HRESULT interp_new(exec_ctx_t *ctx) { const WCHAR *arg = ctx->instr->arg1.bstr; - class_desc_t *class_desc; + class_desc_t *class_desc = NULL; vbdisp_t *obj; VARIANT v; HRESULT hres; @@ -1131,10 +1138,14 @@ static HRESULT interp_new(exec_ctx_t *ctx) return stack_push(ctx, &v); }
- for(class_desc = ctx->script->script_obj->classes; class_desc; class_desc = class_desc->next) { - if(!wcsicmp(class_desc->name, arg)) - break; - } + if(ctx->code->named_item) + for(class_desc = ctx->code->named_item->script_obj->classes; class_desc; class_desc = class_desc->next) + if(!wcsicmp(class_desc->name, arg)) + break; + if(!class_desc) + for(class_desc = ctx->script->script_obj->classes; class_desc; class_desc = class_desc->next) + if(!wcsicmp(class_desc->name, arg)) + break; if(!class_desc) { FIXME("Class %s not found\n", debugstr_w(arg)); return E_FAIL; @@ -1151,7 +1162,7 @@ static HRESULT interp_new(exec_ctx_t *ctx)
static HRESULT interp_dim(exec_ctx_t *ctx) { - ScriptDisp *script_obj = ctx->script->script_obj; + ScriptDisp *script_obj = ctx->code->named_item ? ctx->code->named_item->script_obj : ctx->script->script_obj; const BSTR ident = ctx->instr->arg1.bstr; const unsigned array_id = ctx->instr->arg2.uint; const array_desc_t *array_desc; @@ -1517,6 +1528,8 @@ static HRESULT interp_me(exec_ctx_t *ctx)
if(ctx->vbthis) disp = (IDispatch*)&ctx->vbthis->IDispatchEx_iface; + else if(ctx->code->named_item) + disp = (IDispatch*)&ctx->code->named_item->script_obj->IDispatchEx_iface; else if(ctx->script->host_global) disp = ctx->script->host_global; else diff --git a/dlls/vbscript/vbscript.c b/dlls/vbscript/vbscript.c index 3b80fe8..1bba826 100644 --- a/dlls/vbscript/vbscript.c +++ b/dlls/vbscript/vbscript.c @@ -93,7 +93,7 @@ static inline BOOL is_started(VBScript *This)
static HRESULT exec_global_code(script_ctx_t *ctx, vbscode_t *code, VARIANT *res) { - ScriptDisp *obj = ctx->script_obj; + ScriptDisp *obj = code->named_item ? code->named_item->script_obj : ctx->script_obj; function_t *func_iter, **new_funcs; dynamic_var_t *var, **new_vars; size_t cnt, i; @@ -221,6 +221,15 @@ named_item_t *lookup_named_item(script_ctx_t *ctx, const WCHAR *name, unsigned f return NULL; }
+static void release_named_item_script_obj(named_item_t *item) +{ + if(!item->script_obj) return; + + item->script_obj->ctx = NULL; + IDispatchEx_Release(&item->script_obj->IDispatchEx_iface); + item->script_obj = NULL; +} + static void release_script(script_ctx_t *ctx) { vbscode_t *code, *code_next; @@ -234,6 +243,7 @@ static void release_script(script_ctx_t *ctx) { code->pending_exec = TRUE; if(code->last_class) code->last_class->next = NULL; + if(code->named_item) release_named_item_script_obj(code->named_item); } else { @@ -248,8 +258,10 @@ static void release_script(script_ctx_t *ctx) list_remove(&iter->entry); if(iter->disp) IDispatch_Release(iter->disp); + release_named_item_script_obj(iter); heap_free(iter->name); - heap_free(iter); + if(!--iter->ref) + heap_free(iter); }
if(ctx->host_global) { @@ -504,6 +516,7 @@ static ULONG WINAPI VBScript_Release(IActiveScript *iface) static HRESULT WINAPI VBScript_SetScriptSite(IActiveScript *iface, IActiveScriptSite *pass) { VBScript *This = impl_from_IActiveScript(iface); + vbscode_t *code; LCID lcid; HRESULT hres;
@@ -522,6 +535,21 @@ static HRESULT WINAPI VBScript_SetScriptSite(IActiveScript *iface, IActiveScript if(FAILED(hres)) return hres;
+ /* Create new script dispatches for persistent code with named items */ + LIST_FOR_EACH_ENTRY(code, &This->ctx->code_list, vbscode_t, entry) + { + if(code->named_item && !code->named_item->script_obj) + { + hres = create_script_disp(This->ctx, &code->named_item->script_obj); + if(FAILED(hres)) + { + This->ctx->script_obj->ctx = NULL; + IDispatchEx_Release(&This->ctx->script_obj->IDispatchEx_iface); + return hres; + } + } + } + This->ctx->site = pass; IActiveScriptSite_AddRef(This->ctx->site);
@@ -659,8 +687,14 @@ static HRESULT WINAPI VBScript_AddNamedItem(IActiveScript *iface, LPCOLESTR pstr }
item->disp = disp; + item->ref = 1; item->flags = dwFlags; item->name = heap_strdupW(pstrName); + hres = create_script_disp(This->ctx, &item->script_obj); + if(FAILED(hres)) { + heap_free(item->name); + item->name = NULL; + } if(!item->name) { if(disp) IDispatch_Release(disp); @@ -683,6 +717,7 @@ static HRESULT WINAPI VBScript_AddTypeLib(IActiveScript *iface, REFGUID rguidTyp static HRESULT WINAPI VBScript_GetScriptDispatch(IActiveScript *iface, LPCOLESTR pstrItemName, IDispatch **ppdisp) { VBScript *This = impl_from_IActiveScript(iface); + ScriptDisp *script_obj;
TRACE("(%p)->(%s %p)\n", This, debugstr_w(pstrItemName), ppdisp);
@@ -694,7 +729,15 @@ static HRESULT WINAPI VBScript_GetScriptDispatch(IActiveScript *iface, LPCOLESTR return E_UNEXPECTED; }
- *ppdisp = (IDispatch*)&This->ctx->script_obj->IDispatchEx_iface; + if(pstrItemName) { + named_item_t *item = lookup_named_item(This->ctx, pstrItemName, 0, SCRIPTITEM_CODEONLY); + if(!item) return E_INVALIDARG; + script_obj = item->script_obj; + } + else + script_obj = This->ctx->script_obj; + + *ppdisp = (IDispatch*)&script_obj->IDispatchEx_iface; IDispatch_AddRef(*ppdisp); return S_OK; } diff --git a/dlls/vbscript/vbscript.h b/dlls/vbscript/vbscript.h index 941834c..2f58807 100644 --- a/dlls/vbscript/vbscript.h +++ b/dlls/vbscript/vbscript.h @@ -149,7 +149,9 @@ typedef struct { } BuiltinDisp;
typedef struct named_item_t { + ScriptDisp *script_obj; IDispatch *disp; + unsigned ref; DWORD flags; LPWSTR name;
@@ -349,6 +351,7 @@ struct _vbscode_t { BOOL is_persistent; function_t main_code; IDispatch *context; + named_item_t *named_item;
BSTR *bstr_pool; unsigned bstr_pool_size;
On 07.02.2020 14:55, Gabriel Ivăncescu wrote:
@@ -248,8 +258,10 @@ static void release_script(script_ctx_t *ctx) list_remove(&iter->entry); if(iter->disp) IDispatch_Release(iter->disp);
release_named_item_script_obj(iter); heap_free(iter->name);
heap_free(iter);
if(!--iter->ref)
heap_free(iter); } if(ctx->host_global) {
A separated release_vbscode() would be cleaner IMO. It would decrease the counter and free the struct if it's the last reference. You could also move freeing the name there.
There is a bigger problem with the patch: script dispatch objects created for persistent scripts on reinitialization will never be released.
@@ -504,6 +516,7 @@ static ULONG WINAPI VBScript_Release(IActiveScript *iface) static HRESULT WINAPI VBScript_SetScriptSite(IActiveScript *iface, IActiveScriptSite *pass) { VBScript *This = impl_from_IActiveScript(iface);
- vbscode_t *code; LCID lcid; HRESULT hres;
@@ -522,6 +535,21 @@ static HRESULT WINAPI VBScript_SetScriptSite(IActiveScript *iface, IActiveScript if(FAILED(hres)) return hres;
- /* Create new script dispatches for persistent code with named items */
- LIST_FOR_EACH_ENTRY(code, &This->ctx->code_list, vbscode_t, entry)
- {
if(code->named_item && !code->named_item->script_obj)
{
hres = create_script_disp(This->ctx, &code->named_item->script_obj);
if(FAILED(hres))
{
This->ctx->script_obj->ctx = NULL;
IDispatchEx_Release(&This->ctx->script_obj->IDispatchEx_iface);
return hres;
}
}
- }
This->ctx->site = pass; IActiveScriptSite_AddRef(This->ctx->site);
@@ -659,8 +687,14 @@ static HRESULT WINAPI VBScript_AddNamedItem(IActiveScript *iface, LPCOLESTR pstr }
item->disp = disp;
- item->ref = 1; item->flags = dwFlags; item->name = heap_strdupW(pstrName);
- hres = create_script_disp(This->ctx, &item->script_obj);
- if(FAILED(hres)) {
heap_free(item->name);
item->name = NULL;
- } if(!item->name) { if(disp) IDispatch_Release(disp);
How about creating it on demand in exec_script instead?
Thanks,
Jacek
On 11/02/2020 18:27, Jacek Caban wrote:
On 07.02.2020 14:55, Gabriel Ivăncescu wrote:
@@ -248,8 +258,10 @@ static void release_script(script_ctx_t *ctx) list_remove(&iter->entry); if(iter->disp) IDispatch_Release(iter->disp); + release_named_item_script_obj(iter); heap_free(iter->name); - heap_free(iter); + if(!--iter->ref) + heap_free(iter); } if(ctx->host_global) {
A separated release_vbscode() would be cleaner IMO. It would decrease the counter and free the struct if it's the last reference. You could also move freeing the name there.
Did you mean release_named_item() here?
And sure I can move the name freeing there, but it's not really needed to be held until last ref. It's needed only for persistent items (not persistent code referring to normal items), which is a different thing wine doesn't implement yet, so I didn't think of it.
There is a bigger problem with the patch: script dispatch objects created for persistent scripts on reinitialization will never be released.
I think they will still be released when the engine is closed (release_script loops through persistent code and does release_named_item_script_obj(code->named_item)).
However, creating them on-demand in exec_script as you suggested might be better and also avoid creating them in SetScriptSite, I'll look into that, thanks.
@@ -504,6 +516,7 @@ static ULONG WINAPI VBScript_Release(IActiveScript *iface) static HRESULT WINAPI VBScript_SetScriptSite(IActiveScript *iface, IActiveScriptSite *pass) { VBScript *This = impl_from_IActiveScript(iface); + vbscode_t *code; LCID lcid; HRESULT hres; @@ -522,6 +535,21 @@ static HRESULT WINAPI VBScript_SetScriptSite(IActiveScript *iface, IActiveScript if(FAILED(hres)) return hres; + /* Create new script dispatches for persistent code with named items */ + LIST_FOR_EACH_ENTRY(code, &This->ctx->code_list, vbscode_t, entry) + { + if(code->named_item && !code->named_item->script_obj) + { + hres = create_script_disp(This->ctx, &code->named_item->script_obj); + if(FAILED(hres)) + { + This->ctx->script_obj->ctx = NULL;
IDispatchEx_Release(&This->ctx->script_obj->IDispatchEx_iface); + return hres; + } + } + }
This->ctx->site = pass; IActiveScriptSite_AddRef(This->ctx->site); @@ -659,8 +687,14 @@ static HRESULT WINAPI VBScript_AddNamedItem(IActiveScript *iface, LPCOLESTR pstr } item->disp = disp; + item->ref = 1; item->flags = dwFlags; item->name = heap_strdupW(pstrName); + hres = create_script_disp(This->ctx, &item->script_obj); + if(FAILED(hres)) { + heap_free(item->name); + item->name = NULL; + } if(!item->name) { if(disp) IDispatch_Release(disp);
How about creating it on demand in exec_script instead?
Thanks,
Jacek
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com ---
Tests with 'me' are added in next patch because that requires a separate (unrelated) fix.
dlls/vbscript/tests/vbscript.c | 302 +++++++++++++++++++++++++++++++-- 1 file changed, 288 insertions(+), 14 deletions(-)
diff --git a/dlls/vbscript/tests/vbscript.c b/dlls/vbscript/tests/vbscript.c index 4e44758..038ce47 100644 --- a/dlls/vbscript/tests/vbscript.c +++ b/dlls/vbscript/tests/vbscript.c @@ -93,6 +93,7 @@ DEFINE_EXPECT(OnStateChange_CONNECTED); DEFINE_EXPECT(OnStateChange_DISCONNECTED); DEFINE_EXPECT(OnStateChange_CLOSED); DEFINE_EXPECT(OnStateChange_INITIALIZED); +DEFINE_EXPECT(OnScriptError); DEFINE_EXPECT(OnEnterScript); DEFINE_EXPECT(OnLeaveScript); DEFINE_EXPECT(GetItemInfo_global); @@ -126,6 +127,19 @@ static void _test_state(unsigned line, IActiveScript *script, SCRIPTSTATE exstat ok_(__FILE__,line) (state == exstate, "state=%d, expected %d\n", state, exstate); }
+static const WCHAR *named_item_global_idents[] = +{ + L"testSub_global", + L"testExplicitVar_global", + L"testVar_global" +}; +static const WCHAR *named_item_context_idents[] = +{ + L"testSub", + L"testExplicitVar", + L"testVar" +}; + static HRESULT WINAPI Dispatch_QueryInterface(IDispatch *iface, REFIID riid, void **ppv) { if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IDispatch, riid)) { @@ -184,10 +198,23 @@ static HRESULT WINAPI Dispatch_GetTypeInfo(IDispatch *iface, UINT iTInfo, LCID l static HRESULT WINAPI Dispatch_GetIDsOfNames(IDispatch *iface, REFIID riid, LPOLESTR *names, UINT name_cnt, LCID lcid, DISPID *ids) { + unsigned i; + ok(name_cnt == 1, "name_cnt = %u\n", name_cnt); - ok(!wcscmp(names[0], L"testCall"), "names[0] = %s\n", wine_dbgstr_w(names[0])); *ids = 1; - return S_OK; + if (!wcscmp(names[0], L"testCall")) + return S_OK; + + for (i = 0; i < ARRAY_SIZE(named_item_global_idents); i++) + if (!wcscmp(names[0], named_item_global_idents[i])) + return DISP_E_UNKNOWNNAME; + for (i = 0; i < ARRAY_SIZE(named_item_context_idents); i++) + if (!wcscmp(names[0], named_item_context_idents[i])) + return DISP_E_UNKNOWNNAME; + + ok(!wcscmp(names[0], L"testClass_global") || !wcscmp(names[0], L"testClass") || !wcscmp(names[0], L"x"), + "names[0] = %s\n", wine_dbgstr_w(names[0])); + return DISP_E_UNKNOWNNAME; }
static HRESULT WINAPI Dispatch_Invoke(IDispatch *iface, DISPID id, REFIID riid, LCID lcid, WORD flags, @@ -337,7 +364,7 @@ static HRESULT WINAPI ActiveScriptSite_OnStateChange(IActiveScriptSite *iface, S
static HRESULT WINAPI ActiveScriptSite_OnScriptError(IActiveScriptSite *iface, IActiveScriptError *pscripterror) { - ok(0, "unexpected call\n"); + CHECK_EXPECT(OnScriptError); return E_NOTIMPL; }
@@ -460,14 +487,14 @@ static void test_safety(IActiveScript *script) IObjectSafety_Release(safety); }
-static IDispatchEx *get_script_dispatch(IActiveScript *script) +static IDispatchEx *get_script_dispatch(IActiveScript *script, const WCHAR *item_name) { IDispatchEx *dispex; IDispatch *disp; HRESULT hres;
disp = (void*)0xdeadbeef; - hres = IActiveScript_GetScriptDispatch(script, NULL, &disp); + hres = IActiveScript_GetScriptDispatch(script, item_name, &disp); ok(hres == S_OK, "GetScriptDispatch failed: %08x\n", hres); if(FAILED(hres)) return NULL; @@ -560,7 +587,7 @@ static void test_scriptdisp(void) ok(hres == S_OK, "SetScriptSite failed: %08x\n", hres); CHECK_CALLED(GetLCID);
- script_disp2 = get_script_dispatch(vbscript); + script_disp2 = get_script_dispatch(vbscript, NULL);
test_state(vbscript, SCRIPTSTATE_UNINITIALIZED);
@@ -578,7 +605,7 @@ static void test_scriptdisp(void)
test_state(vbscript, SCRIPTSTATE_CONNECTED);
- script_disp = get_script_dispatch(vbscript); + script_disp = get_script_dispatch(vbscript, NULL); ok(script_disp == script_disp2, "script_disp != script_disp2\n"); IDispatchEx_Release(script_disp2);
@@ -705,7 +732,7 @@ static void test_code_persistence(void) ok(hr == S_OK, "ParseScriptText failed: %08x\n", hr);
/* Pending code does not add identifiers to the global scope */ - script_disp = get_script_dispatch(vbscript); + script_disp = get_script_dispatch(vbscript, NULL); id = 0; get_disp_id(script_disp, "x", DISP_E_UNKNOWNNAME, &id); ok(id == -1, "id = %d, expected -1\n", id); @@ -744,7 +771,7 @@ static void test_code_persistence(void) CHECK_CALLED_MULTI(OnLeaveScript, 2); test_state(vbscript, SCRIPTSTATE_CONNECTED);
- script_disp = get_script_dispatch(vbscript); + script_disp = get_script_dispatch(vbscript, NULL); id = 0; get_disp_id(script_disp, "x", DISP_E_UNKNOWNNAME, &id); ok(id == -1, "id = %d, expected -1\n", id); @@ -790,7 +817,7 @@ static void test_code_persistence(void) CHECK_CALLED(GetLCID); CHECK_CALLED(OnStateChange_INITIALIZED);
- script_disp = get_script_dispatch(vbscript); + script_disp = get_script_dispatch(vbscript, NULL); id = 0; get_disp_id(script_disp, "z", DISP_E_UNKNOWNNAME, &id); ok(id == -1, "id = %d, expected -1\n", id); @@ -806,7 +833,7 @@ static void test_code_persistence(void) CHECK_CALLED(OnLeaveScript); test_state(vbscript, SCRIPTSTATE_CONNECTED);
- script_disp = get_script_dispatch(vbscript); + script_disp = get_script_dispatch(vbscript, NULL); id = 0; get_disp_id(script_disp, "z", S_OK, &id); ok(id != -1, "id = -1\n"); @@ -869,7 +896,7 @@ static void test_code_persistence(void) CHECK_CALLED(OnStateChange_CONNECTED); test_state(vbscript, SCRIPTSTATE_CONNECTED);
- script_disp = get_script_dispatch(vbscript); + script_disp = get_script_dispatch(vbscript, NULL); id = 0; get_disp_id(script_disp, "y", DISP_E_UNKNOWNNAME, &id); ok(id == -1, "id = %d, expected -1\n", id); @@ -982,7 +1009,7 @@ static void test_script_typeinfo(void) "implicit = 10\n" "dim obj\nset obj = new C\n");
- script_disp = get_script_dispatch(vbscript); + script_disp = get_script_dispatch(vbscript, NULL); hr = IDispatchEx_QueryInterface(script_disp, &IID_ITypeInfo, (void**)&typeinfo); ok(hr == E_NOINTERFACE, "QueryInterface(IID_ITypeInfo) returned: %08x\n", hr); hr = IDispatchEx_GetTypeInfo(script_disp, 1, LOCALE_USER_DEFAULT, &typeinfo); @@ -1475,7 +1502,7 @@ static void test_vbscript_uninitializing(void)
test_state(script, SCRIPTSTATE_CONNECTED);
- dispex = get_script_dispatch(script); + dispex = get_script_dispatch(script, NULL); ok(dispex != NULL, "dispex == NULL\n"); if(dispex) IDispatchEx_Release(dispex); @@ -1731,10 +1758,28 @@ static void test_vbscript_initializing(void)
static void test_named_items(void) { + static const WCHAR *global_code_test[] = + { + L"testSub_global\n", + L"if testExplicitVar_global <> 10 then err.raise 500\n", + L"if testVar_global <> 5 then err.raise 500\n", + L"set x = new testClass_global\n" + }; + static const WCHAR *context_code_test[] = + { + L"testSub\n", + L"if testExplicitVar <> 42 then err.raise 500\n", + L"if testVar <> 99 then err.raise 500\n", + L"set x = new testClass\n" + }; + IDispatchEx *script_disp, *script_disp2; IActiveScriptParse *parse; IActiveScript *script; IDispatch *disp; + unsigned i; + DISPID id; ULONG ref; + BSTR bstr; HRESULT hres;
script = create_vbscript(); @@ -1748,6 +1793,8 @@ static void test_named_items(void) ok(hres == E_UNEXPECTED, "AddNamedItem returned: %08x\n", hres); hres = IActiveScript_AddNamedItem(script, L"globalItem", SCRIPTITEM_GLOBALMEMBERS); ok(hres == E_UNEXPECTED, "AddNamedItem returned: %08x\n", hres); + hres = IActiveScript_AddNamedItem(script, L"code context", SCRIPTITEM_CODEONLY); + ok(hres == E_UNEXPECTED, "AddNamedItem returned: %08x\n", hres);
SET_EXPECT(GetLCID); hres = IActiveScript_SetScriptSite(script, &ActiveScriptSite); @@ -1763,11 +1810,20 @@ static void test_named_items(void) ok(hres == S_OK, "AddNamedItem failed: %08x\n", hres); hres = IActiveScript_AddNamedItem(script, L"visibleCodeItem", SCRIPTITEM_ISVISIBLE | SCRIPTITEM_CODEONLY); ok(hres == S_OK, "AddNamedItem failed: %08x\n", hres); + hres = IActiveScript_AddNamedItem(script, L"code context", SCRIPTITEM_CODEONLY); + ok(hres == S_OK, "AddNamedItem failed: %08x\n", hres);
ok(global_named_item_ref > 0, "global_named_item_ref = %u\n", global_named_item_ref); ok(visible_named_item_ref == 0, "visible_named_item_ref = %u\n", visible_named_item_ref); ok(visible_code_named_item_ref == 0, "visible_code_named_item_ref = %u\n", visible_code_named_item_ref);
+ hres = IActiveScript_GetScriptDispatch(script, L"no context", &disp); + ok(hres == E_INVALIDARG, "GetScriptDispatch returned: %08x\n", hres); + + script_disp = get_script_dispatch(script, NULL); + script_disp2 = get_script_dispatch(script, L"code CONTEXT"); + ok(script_disp != script_disp2, "get_script_dispatch returned same dispatch objects.\n"); + SET_EXPECT(OnStateChange_INITIALIZED); hres = IActiveScriptParse_InitNew(parse); ok(hres == S_OK, "InitNew failed: %08x\n", hres); @@ -1815,6 +1871,224 @@ static void test_named_items(void) parse_script(parse, "visibleItem.testCall\n"); CHECK_CALLED(testCall);
+ hres = IActiveScriptParse_ParseScriptText(parse, L"sub testSub\nend sub\n", L"no context", NULL, NULL, 0, 0, 0, NULL, NULL); + ok(hres == E_INVALIDARG, "ParseScriptText returned: %08x\n", hres); + SET_EXPECT(OnEnterScript); + SET_EXPECT(OnLeaveScript); + hres = IActiveScriptParse_ParseScriptText(parse, L"" + "sub testSub_global\nend sub\n" + "dim testExplicitVar_global\ntestExplicitVar_global = 10\n" + "testVar_global = 10\n" + "class testClass_global\nend class\n", + NULL, NULL, NULL, 0, 0, SCRIPTTEXT_ISPERSISTENT, NULL, NULL); + ok(hres == S_OK, "ParseScriptText failed: %08x\n", hres); + CHECK_CALLED(OnEnterScript); + CHECK_CALLED(OnLeaveScript); + SET_EXPECT(OnEnterScript); + SET_EXPECT(OnLeaveScript); + hres = IActiveScriptParse_ParseScriptText(parse, L"" + "sub testSub\nend sub\n" + "dim testExplicitVar\ntestExplicitVar = 42\n" + "class testClass\nend class\n", + L"code context", NULL, NULL, 0, 0, 0, NULL, NULL); + ok(hres == S_OK, "ParseScriptText failed: %08x\n", hres); + CHECK_CALLED(OnEnterScript); + CHECK_CALLED(OnLeaveScript); + SET_EXPECT(OnEnterScript); + SET_EXPECT(OnLeaveScript); + hres = IActiveScriptParse_ParseScriptText(parse, L"" + "testVar = 99\n" + "testVar_global = 5\n", + L"Code Context", NULL, NULL, 0, 0, SCRIPTTEXT_ISPERSISTENT, NULL, NULL); + ok(hres == S_OK, "ParseScriptText failed: %08x\n", hres); + CHECK_CALLED(OnEnterScript); + CHECK_CALLED(OnLeaveScript); + + for (i = 0; i < ARRAY_SIZE(named_item_global_idents); i++) + { + bstr = SysAllocString(named_item_global_idents[i]); + id = 0; + hres = IDispatchEx_GetDispID(script_disp, bstr, 0, &id); + ok(hres == S_OK, "GetDispID(%s) returned %08x\n", wine_dbgstr_w(named_item_global_idents[i]), hres); + ok(id != -1, "[%s] id = -1\n", wine_dbgstr_w(named_item_global_idents[i])); + id = 0; + hres = IDispatchEx_GetDispID(script_disp2, bstr, 0, &id); + ok(hres == DISP_E_UNKNOWNNAME, "GetDispID(%s) returned %08x\n", wine_dbgstr_w(named_item_global_idents[i]), hres); + ok(id == -1, "[%s] id = %d, expected -1\n", wine_dbgstr_w(named_item_global_idents[i]), id); + SysFreeString(bstr); + } + for (i = 0; i < ARRAY_SIZE(named_item_context_idents); i++) + { + bstr = SysAllocString(named_item_context_idents[i]); + id = 0; + hres = IDispatchEx_GetDispID(script_disp, bstr, 0, &id); + ok(hres == DISP_E_UNKNOWNNAME, "GetDispID(%s) returned %08x\n", wine_dbgstr_w(named_item_context_idents[i]), hres); + ok(id == -1, "[%s] id = %d, expected -1\n", wine_dbgstr_w(named_item_context_idents[i]), id); + id = 0; + hres = IDispatchEx_GetDispID(script_disp2, bstr, 0, &id); + ok(hres == S_OK, "GetDispID(%s) returned %08x\n", wine_dbgstr_w(named_item_context_idents[i]), hres); + ok(id != -1, "[%s] id = -1\n", wine_dbgstr_w(named_item_context_idents[i])); + SysFreeString(bstr); + } + + for (i = 0; i < ARRAY_SIZE(global_code_test); i++) + { + SET_EXPECT(OnEnterScript); + SET_EXPECT(OnLeaveScript); + hres = IActiveScriptParse_ParseScriptText(parse, global_code_test[i], NULL, NULL, NULL, 0, 0, 0, NULL, NULL); + ok(hres == S_OK, "ParseScriptText(%s) failed: %08x\n", wine_dbgstr_w(global_code_test[i]), hres); + CHECK_CALLED(OnEnterScript); + CHECK_CALLED(OnLeaveScript); + SET_EXPECT(OnEnterScript); + SET_EXPECT(OnLeaveScript); + hres = IActiveScriptParse_ParseScriptText(parse, global_code_test[i], L"code context", NULL, NULL, 0, 0, 0, NULL, NULL); + ok(hres == S_OK, "ParseScriptText(%s) failed: %08x\n", wine_dbgstr_w(global_code_test[i]), hres); + CHECK_CALLED(OnEnterScript); + CHECK_CALLED(OnLeaveScript); + } + for (i = 0; i < ARRAY_SIZE(context_code_test); i++) + { + SET_EXPECT(OnScriptError); + SET_EXPECT(OnEnterScript); + SET_EXPECT(OnLeaveScript); + hres = IActiveScriptParse_ParseScriptText(parse, context_code_test[i], NULL, NULL, NULL, 0, 0, 0, NULL, NULL); + ok(FAILED(hres), "ParseScriptText(%s) returned: %08x\n", wine_dbgstr_w(context_code_test[i]), hres); + CHECK_CALLED(OnScriptError); + CHECK_CALLED(OnEnterScript); + CHECK_CALLED(OnLeaveScript); + SET_EXPECT(OnEnterScript); + SET_EXPECT(OnLeaveScript); + hres = IActiveScriptParse_ParseScriptText(parse, context_code_test[i], L"code context", NULL, NULL, 0, 0, 0, NULL, NULL); + ok(hres == S_OK, "ParseScriptText(%s) failed: %08x\n", wine_dbgstr_w(context_code_test[i]), hres); + CHECK_CALLED(OnEnterScript); + CHECK_CALLED(OnLeaveScript); + } + SET_EXPECT(OnScriptError); + SET_EXPECT(OnEnterScript); + SET_EXPECT(OnLeaveScript); + hres = IActiveScriptParse_ParseScriptText(parse, L"testSub_global = 10\n", L"code context", NULL, NULL, 0, 0, 0, NULL, NULL); + ok(FAILED(hres), "ParseScriptText returned: %08x\n", hres); + CHECK_CALLED(OnScriptError); + CHECK_CALLED(OnEnterScript); + CHECK_CALLED(OnLeaveScript); + + IDispatchEx_Release(script_disp2); + IDispatchEx_Release(script_disp); + + SET_EXPECT(OnStateChange_DISCONNECTED); + SET_EXPECT(OnStateChange_INITIALIZED); + SET_EXPECT(OnStateChange_UNINITIALIZED); + hres = IActiveScript_SetScriptState(script, SCRIPTSTATE_UNINITIALIZED); + ok(hres == S_OK, "SetScriptState(SCRIPTSTATE_UNINITIALIZED) failed: %08x\n", hres); + CHECK_CALLED(OnStateChange_DISCONNECTED); + CHECK_CALLED(OnStateChange_INITIALIZED); + CHECK_CALLED(OnStateChange_UNINITIALIZED); + test_no_script_dispatch(script); + + ok(global_named_item_ref == 0, "global_named_item_ref = %u\n", global_named_item_ref); + ok(visible_named_item_ref == 0, "visible_named_item_ref = %u\n", visible_named_item_ref); + ok(visible_code_named_item_ref == 0, "visible_code_named_item_ref = %u\n", visible_code_named_item_ref); + + hres = IActiveScript_GetScriptDispatch(script, L"code context", &disp); + ok(hres == E_UNEXPECTED, "hres = %08x, expected E_UNEXPECTED\n", hres); + + SET_EXPECT(GetLCID); + SET_EXPECT(OnStateChange_INITIALIZED); + hres = IActiveScript_SetScriptSite(script, &ActiveScriptSite); + ok(hres == S_OK, "SetScriptSite failed: %08x\n", hres); + CHECK_CALLED(GetLCID); + CHECK_CALLED(OnStateChange_INITIALIZED); + + hres = IActiveScript_AddNamedItem(script, L"code context", SCRIPTITEM_CODEONLY); + ok(hres == S_OK, "AddNamedItem failed: %08x\n", hres); + + SET_EXPECT(OnStateChange_CONNECTED); + SET_EXPECT_MULTI(OnEnterScript, 2); + SET_EXPECT_MULTI(OnLeaveScript, 2); + hres = IActiveScript_SetScriptState(script, SCRIPTSTATE_CONNECTED); + ok(hres == S_OK, "SetScriptState(SCRIPTSTATE_CONNECTED) failed: %08x\n", hres); + CHECK_CALLED(OnStateChange_CONNECTED); + CHECK_CALLED_MULTI(OnEnterScript, 2); + CHECK_CALLED_MULTI(OnLeaveScript, 2); + test_state(script, SCRIPTSTATE_CONNECTED); + + script_disp = get_script_dispatch(script, NULL); + for (i = 0; i < ARRAY_SIZE(named_item_global_idents); i++) + { + bstr = SysAllocString(named_item_global_idents[i]); + id = 0; + hres = IDispatchEx_GetDispID(script_disp, bstr, 0, &id); + ok(hres == S_OK, "GetDispID(%s) returned %08x\n", wine_dbgstr_w(named_item_global_idents[i]), hres); + ok(id != -1, "[%s] id = -1\n", wine_dbgstr_w(named_item_global_idents[i])); + SysFreeString(bstr); + } + for (i = 0; i < ARRAY_SIZE(named_item_context_idents); i++) + { + bstr = SysAllocString(named_item_context_idents[i]); + id = 0; + hres = IDispatchEx_GetDispID(script_disp, bstr, 0, &id); + ok(hres == DISP_E_UNKNOWNNAME, "GetDispID(%s) returned %08x\n", wine_dbgstr_w(named_item_context_idents[i]), hres); + ok(id == -1, "[%s] id = %d, expected -1\n", wine_dbgstr_w(named_item_context_idents[i]), id); + SysFreeString(bstr); + } + IDispatchEx_Release(script_disp); + + script_disp = get_script_dispatch(script, L"code context"); + for (i = 0; i < ARRAY_SIZE(named_item_global_idents); i++) + { + bstr = SysAllocString(named_item_global_idents[i]); + id = 0; + hres = IDispatchEx_GetDispID(script_disp, bstr, 0, &id); + ok(hres == DISP_E_UNKNOWNNAME, "GetDispID(%s) returned %08x\n", wine_dbgstr_w(named_item_global_idents[i]), hres); + ok(id == -1, "[%s] id = %d, expected -1\n", wine_dbgstr_w(named_item_global_idents[i]), id); + SysFreeString(bstr); + } + for (i = 0; i < ARRAY_SIZE(named_item_context_idents); i++) + { + bstr = SysAllocString(named_item_context_idents[i]); + id = 0; + hres = IDispatchEx_GetDispID(script_disp, bstr, 0, &id); + ok(hres == DISP_E_UNKNOWNNAME, "GetDispID(%s) returned %08x\n", wine_dbgstr_w(named_item_context_idents[i]), hres); + ok(id == -1, "[%s] id = %d, expected -1\n", wine_dbgstr_w(named_item_context_idents[i]), id); + SysFreeString(bstr); + } + IDispatchEx_Release(script_disp); + + for (i = 0; i < ARRAY_SIZE(global_code_test); i++) + { + SET_EXPECT(OnEnterScript); + SET_EXPECT(OnLeaveScript); + hres = IActiveScriptParse_ParseScriptText(parse, global_code_test[i], NULL, NULL, NULL, 0, 0, 0, NULL, NULL); + ok(hres == S_OK, "ParseScriptText(%s) failed: %08x\n", wine_dbgstr_w(global_code_test[i]), hres); + CHECK_CALLED(OnEnterScript); + CHECK_CALLED(OnLeaveScript); + SET_EXPECT(OnEnterScript); + SET_EXPECT(OnLeaveScript); + hres = IActiveScriptParse_ParseScriptText(parse, global_code_test[i], L"code context", NULL, NULL, 0, 0, 0, NULL, NULL); + ok(hres == S_OK, "ParseScriptText(%s) failed: %08x\n", wine_dbgstr_w(global_code_test[i]), hres); + CHECK_CALLED(OnEnterScript); + CHECK_CALLED(OnLeaveScript); + } + for (i = 0; i < ARRAY_SIZE(context_code_test); i++) + { + SET_EXPECT(OnScriptError); + SET_EXPECT(OnEnterScript); + SET_EXPECT(OnLeaveScript); + hres = IActiveScriptParse_ParseScriptText(parse, context_code_test[i], NULL, NULL, NULL, 0, 0, 0, NULL, NULL); + ok(FAILED(hres), "ParseScriptText(%s) returned: %08x\n", wine_dbgstr_w(context_code_test[i]), hres); + CHECK_CALLED(OnScriptError); + CHECK_CALLED(OnEnterScript); + CHECK_CALLED(OnLeaveScript); + SET_EXPECT(OnScriptError); + SET_EXPECT(OnEnterScript); + SET_EXPECT(OnLeaveScript); + hres = IActiveScriptParse_ParseScriptText(parse, context_code_test[i], L"code context", NULL, NULL, 0, 0, 0, NULL, NULL); + ok(FAILED(hres), "ParseScriptText(%s) returned: %08x\n", wine_dbgstr_w(context_code_test[i]), hres); + CHECK_CALLED(OnScriptError); + CHECK_CALLED(OnEnterScript); + CHECK_CALLED(OnLeaveScript); + } + SET_EXPECT(OnStateChange_DISCONNECTED); SET_EXPECT(OnStateChange_INITIALIZED); SET_EXPECT(OnStateChange_CLOSED);
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com ---
This matches Windows behavior and allows us to test 'me' with named item script dispatches too.
dlls/vbscript/interp.c | 4 +--- dlls/vbscript/tests/run.c | 13 +++++++++++++ dlls/vbscript/tests/vbscript.c | 20 ++++++++++++++++++++ 3 files changed, 34 insertions(+), 3 deletions(-)
diff --git a/dlls/vbscript/interp.c b/dlls/vbscript/interp.c index ff8949f..a30aab2 100644 --- a/dlls/vbscript/interp.c +++ b/dlls/vbscript/interp.c @@ -1494,9 +1494,7 @@ static HRESULT interp_retval(exec_ctx_t *ctx)
TRACE("\n");
- hres = stack_pop_val(ctx, &val); - if(FAILED(hres)) - return hres; + stack_pop_deref(ctx, &val);
if(val.owned) { VariantClear(&ctx->ret_val); diff --git a/dlls/vbscript/tests/run.c b/dlls/vbscript/tests/run.c index 8acf220..474fe1d 100644 --- a/dlls/vbscript/tests/run.c +++ b/dlls/vbscript/tests/run.c @@ -2685,6 +2685,7 @@ static void test_isexpression(void) { IActiveScriptParse *parser; IActiveScript *engine; + IDispatch *disp; SCRIPTSTATE ss; HRESULT hres; VARIANT var; @@ -2747,6 +2748,18 @@ static void test_isexpression(void) VariantClear(&var); SysFreeString(str);
+ /* Without a global host or named item context, "me" returns the script dispatch */ + hres = IActiveScript_GetScriptDispatch(engine, NULL, &disp); + ok(hres == S_OK, "GetScriptDispatch failed: %08x\n", hres); + str = a2bstr("me"); + hres = IActiveScriptParse_ParseScriptText(parser, str, NULL, NULL, NULL, 0, 0, SCRIPTTEXT_ISEXPRESSION, &var, NULL); + ok(hres == S_OK, "ParseScriptText failed: %08x\n", hres); + ok(V_VT(&var) == VT_DISPATCH, "Expected VT_DISPATCH, got %s\n", vt2a(&var)); + ok(V_DISPATCH(&var) == disp, "Wrong dispatch returned for 'me'\n"); + IDispatch_Release(disp); + VariantClear(&var); + SysFreeString(str); + /* An expression can also refer to a variable, function, class, etc previously set */ V_VT(&var) = VT_I2; str = a2bstr("If True Then foo = 42 Else foo = 0\n"); diff --git a/dlls/vbscript/tests/vbscript.c b/dlls/vbscript/tests/vbscript.c index 038ce47..4850c8e 100644 --- a/dlls/vbscript/tests/vbscript.c +++ b/dlls/vbscript/tests/vbscript.c @@ -1776,6 +1776,7 @@ static void test_named_items(void) IActiveScriptParse *parse; IActiveScript *script; IDispatch *disp; + VARIANT var; unsigned i; DISPID id; ULONG ref; @@ -1972,6 +1973,25 @@ static void test_named_items(void) CHECK_CALLED(OnEnterScript); CHECK_CALLED(OnLeaveScript);
+ SET_EXPECT(OnEnterScript); + SET_EXPECT(OnLeaveScript); + hres = IActiveScriptParse_ParseScriptText(parse, L"me", NULL, NULL, NULL, 0, 0, SCRIPTTEXT_ISEXPRESSION, &var, NULL); + ok(hres == S_OK, "ParseScriptText failed: %08x\n", hres); + ok(V_VT(&var) == VT_DISPATCH && V_DISPATCH(&var) == &global_named_item, + "Unexpected 'me': V_VT = %d, V_DISPATCH = %p\n", V_VT(&var), V_DISPATCH(&var)); + VariantClear(&var); + CHECK_CALLED(OnEnterScript); + CHECK_CALLED(OnLeaveScript); + SET_EXPECT(OnEnterScript); + SET_EXPECT(OnLeaveScript); + hres = IActiveScriptParse_ParseScriptText(parse, L"me", L"code context", NULL, NULL, 0, 0, SCRIPTTEXT_ISEXPRESSION, &var, NULL); + ok(hres == S_OK, "ParseScriptText failed: %08x\n", hres); + ok(V_VT(&var) == VT_DISPATCH && V_DISPATCH(&var) == (IDispatch*)script_disp2, + "Unexpected 'me': V_VT = %d, V_DISPATCH = %p\n", V_VT(&var), V_DISPATCH(&var)); + VariantClear(&var); + CHECK_CALLED(OnEnterScript); + CHECK_CALLED(OnLeaveScript); + IDispatchEx_Release(script_disp2); IDispatchEx_Release(script_disp);