Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com ---
These patches correct the implementation so that it passes the tests at the end of the series. Some changes are done to simplify the next patch in the series.
I haven't sent the linked list->array conversion yet, because that is not a functional change, just an optimization, so it will come after this is corrected first.
dlls/vbscript/compile.c | 3 ++- dlls/vbscript/vbdisp.c | 5 +++++ dlls/vbscript/vbscript.c | 12 ++++++++++++ dlls/vbscript/vbscript.h | 1 + 4 files changed, 20 insertions(+), 1 deletion(-)
diff --git a/dlls/vbscript/compile.c b/dlls/vbscript/compile.c index 2023261..fc94998 100644 --- a/dlls/vbscript/compile.c +++ b/dlls/vbscript/compile.c @@ -1948,7 +1948,6 @@ HRESULT compile_script(script_ctx_t *script, const WCHAR *src, const WCHAR *deli ctx.code = NULL; release_compiler(&ctx);
- list_add_tail(&script->code_list, &code->entry); *ret = code; return S_OK; } @@ -1975,6 +1974,8 @@ HRESULT compile_procedure(script_ctx_t *script, const WCHAR *src, const WCHAR *d desc->next = script->procs; script->procs = desc;
+ list_add_tail(&script->script_obj->code_list, &code->entry); + *ret = desc; return S_OK; } diff --git a/dlls/vbscript/vbdisp.c b/dlls/vbscript/vbdisp.c index 1dd6d4e..7859abf 100644 --- a/dlls/vbscript/vbdisp.c +++ b/dlls/vbscript/vbdisp.c @@ -616,6 +616,10 @@ static ULONG WINAPI ScriptDisp_Release(IDispatchEx *iface)
if(!ref) { assert(!This->ctx); + + while (!list_empty(&This->code_list)) + release_vbscode(LIST_ENTRY(list_head(&This->code_list), vbscode_t, entry)); + heap_free(This->ident_map); heap_free(This); } @@ -827,6 +831,7 @@ HRESULT create_script_disp(script_ctx_t *ctx, ScriptDisp **ret) script_disp->IDispatchEx_iface.lpVtbl = &ScriptDispVtbl; script_disp->ref = 1; script_disp->ctx = ctx; + list_init(&script_disp->code_list);
*ret = script_disp; return S_OK; diff --git a/dlls/vbscript/vbscript.c b/dlls/vbscript/vbscript.c index 56c53b4..ca594f1 100644 --- a/dlls/vbscript/vbscript.c +++ b/dlls/vbscript/vbscript.c @@ -94,6 +94,10 @@ static void exec_queued_code(script_ctx_t *ctx) if(iter->pending_exec) exec_global_code(ctx, iter, NULL); } + LIST_FOR_EACH_ENTRY(iter, &ctx->script_obj->code_list, vbscode_t, entry) { + if(iter->pending_exec) + exec_global_code(ctx, iter, NULL); + } }
IDispatch *lookup_named_item(script_ctx_t *ctx, const WCHAR *name, unsigned flags) @@ -764,6 +768,7 @@ static HRESULT WINAPI VBScriptParse_ParseScriptText(IActiveScriptParse *iface, { VBScript *This = impl_from_IActiveScriptParse(iface); IDispatch *context = NULL; + struct list *list; vbscode_t *code; HRESULT hres;
@@ -786,6 +791,13 @@ static HRESULT WINAPI VBScriptParse_ParseScriptText(IActiveScriptParse *iface, if(FAILED(hres)) return hres;
+ if(dwFlags & SCRIPTTEXT_ISPERSISTENT) + list = &This->ctx->code_list; + else + list = &This->ctx->script_obj->code_list; + + list_add_tail(list, &code->entry); + if(context) IDispatch_AddRef(code->context = context);
diff --git a/dlls/vbscript/vbscript.h b/dlls/vbscript/vbscript.h index 33eb1e8..cfa7469 100644 --- a/dlls/vbscript/vbscript.h +++ b/dlls/vbscript/vbscript.h @@ -131,6 +131,7 @@ typedef struct { unsigned ident_map_size;
script_ctx_t *ctx; + struct list code_list; } ScriptDisp;
typedef struct _builtin_prop_t builtin_prop_t;
Get rid of the pending_exec field, which was not correct in the first place. Persistent code that is stored in the script context has to be re-executed every time the script is restarted (for the new dispatch object), and so we simply store it in a list that will always get executed when the state changes.
If the script is stopped, then all persistent code becomes pending again without any change. Meanwhile, the non-persistent code stored in the script dispatch gets released and removed along with the script dispatch, as it should.
For manually executed code regardless of state (expressions or procedure code), we only have to reference it in another list in the script dispatch object, since it shouldn't get queued for execution; it either gets executed instantly or manually.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/vbscript/compile.c | 2 +- dlls/vbscript/vbdisp.c | 3 +++ dlls/vbscript/vbscript.c | 20 ++++++++------------ dlls/vbscript/vbscript.h | 2 +- 4 files changed, 13 insertions(+), 14 deletions(-)
diff --git a/dlls/vbscript/compile.c b/dlls/vbscript/compile.c index fc94998..8852cd2 100644 --- a/dlls/vbscript/compile.c +++ b/dlls/vbscript/compile.c @@ -1974,7 +1974,7 @@ HRESULT compile_procedure(script_ctx_t *script, const WCHAR *src, const WCHAR *d desc->next = script->procs; script->procs = desc;
- list_add_tail(&script->script_obj->code_list, &code->entry); + list_add_tail(&script->script_obj->noexec_code_list, &code->entry);
*ret = desc; return S_OK; diff --git a/dlls/vbscript/vbdisp.c b/dlls/vbscript/vbdisp.c index 7859abf..e84f31b 100644 --- a/dlls/vbscript/vbdisp.c +++ b/dlls/vbscript/vbdisp.c @@ -619,6 +619,8 @@ static ULONG WINAPI ScriptDisp_Release(IDispatchEx *iface)
while (!list_empty(&This->code_list)) release_vbscode(LIST_ENTRY(list_head(&This->code_list), vbscode_t, entry)); + while (!list_empty(&This->noexec_code_list)) + release_vbscode(LIST_ENTRY(list_head(&This->noexec_code_list), vbscode_t, entry));
heap_free(This->ident_map); heap_free(This); @@ -832,6 +834,7 @@ HRESULT create_script_disp(script_ctx_t *ctx, ScriptDisp **ret) script_disp->ref = 1; script_disp->ctx = ctx; list_init(&script_disp->code_list); + list_init(&script_disp->noexec_code_list);
*ret = script_disp; return S_OK; diff --git a/dlls/vbscript/vbscript.c b/dlls/vbscript/vbscript.c index ca594f1..5e39f76 100644 --- a/dlls/vbscript/vbscript.c +++ b/dlls/vbscript/vbscript.c @@ -82,7 +82,6 @@ static inline BOOL is_started(VBScript *This)
static HRESULT exec_global_code(script_ctx_t *ctx, vbscode_t *code, VARIANT *res) { - code->pending_exec = FALSE; return exec_script(ctx, TRUE, &code->main_code, NULL, NULL, res); }
@@ -90,14 +89,11 @@ static void exec_queued_code(script_ctx_t *ctx) { vbscode_t *iter;
- LIST_FOR_EACH_ENTRY(iter, &ctx->code_list, vbscode_t, entry) { - if(iter->pending_exec) - exec_global_code(ctx, iter, NULL); - } - LIST_FOR_EACH_ENTRY(iter, &ctx->script_obj->code_list, vbscode_t, entry) { - if(iter->pending_exec) - exec_global_code(ctx, iter, NULL); - } + LIST_FOR_EACH_ENTRY(iter, &ctx->code_list, vbscode_t, entry) + exec_global_code(ctx, iter, NULL); + + LIST_FOR_EACH_ENTRY(iter, &ctx->script_obj->code_list, vbscode_t, entry) + exec_global_code(ctx, iter, NULL); }
IDispatch *lookup_named_item(script_ctx_t *ctx, const WCHAR *name, unsigned flags) @@ -793,6 +789,8 @@ static HRESULT WINAPI VBScriptParse_ParseScriptText(IActiveScriptParse *iface,
if(dwFlags & SCRIPTTEXT_ISPERSISTENT) list = &This->ctx->code_list; + else if(dwFlags & SCRIPTTEXT_ISEXPRESSION) + list = &This->ctx->script_obj->noexec_code_list; else list = &This->ctx->script_obj->code_list;
@@ -801,10 +799,8 @@ static HRESULT WINAPI VBScriptParse_ParseScriptText(IActiveScriptParse *iface, if(context) IDispatch_AddRef(code->context = context);
- if(!(dwFlags & SCRIPTTEXT_ISEXPRESSION) && !is_started(This)) { - code->pending_exec = TRUE; + if(!(dwFlags & SCRIPTTEXT_ISEXPRESSION) && !is_started(This)) return S_OK; - }
return exec_global_code(This->ctx, code, pvarResult); } diff --git a/dlls/vbscript/vbscript.h b/dlls/vbscript/vbscript.h index cfa7469..cada4e2 100644 --- a/dlls/vbscript/vbscript.h +++ b/dlls/vbscript/vbscript.h @@ -132,6 +132,7 @@ typedef struct {
script_ctx_t *ctx; struct list code_list; + struct list noexec_code_list; } ScriptDisp;
typedef struct _builtin_prop_t builtin_prop_t; @@ -338,7 +339,6 @@ struct _vbscode_t {
BOOL option_explicit;
- BOOL pending_exec; function_t main_code; IDispatch *context;
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com ---
Their lifespan must be limited to the script dispatch, and contained within the script dispatch's context (the pstrItemName argument when it will be implemented). When the script is stopped, they must be released since the persistent code will be re-add anyway to rebuild them.
dlls/vbscript/compile.c | 31 ++++++++++++++++--------------- dlls/vbscript/interp.c | 16 +++++++++------- dlls/vbscript/vbdisp.c | 13 +++++++++++-- dlls/vbscript/vbscript.c | 15 --------------- dlls/vbscript/vbscript.h | 28 ++++++++++++++-------------- 5 files changed, 50 insertions(+), 53 deletions(-)
diff --git a/dlls/vbscript/compile.c b/dlls/vbscript/compile.c index 8852cd2..6ab8352 100644 --- a/dlls/vbscript/compile.c +++ b/dlls/vbscript/compile.c @@ -1737,23 +1737,23 @@ 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(ScriptDisp *obj, const WCHAR *identifier) { class_desc_t *class; dynamic_var_t *var; function_t *func;
- for(var = script->global_vars; var; var = var->next) { + for(var = obj->global_vars; var; var = var->next) { if(!wcsicmp(var->name, identifier)) return TRUE; }
- for(func = script->global_funcs; func; func = func->next) { + for(func = obj->global_funcs; func; func = func->next) { if(!wcsicmp(func->name, identifier)) return TRUE; }
- for(class = script->classes; class; class = class->next) { + for(class = obj->classes; class; class = class->next) { if(!wcsicmp(class->name, identifier)) return TRUE; } @@ -1763,26 +1763,27 @@ static BOOL lookup_script_identifier(script_ctx_t *script, const WCHAR *identifi
static HRESULT check_script_collisions(compile_ctx_t *ctx, script_ctx_t *script) { + ScriptDisp *obj = script->script_obj; class_desc_t *class; dynamic_var_t *var; function_t *func;
for(var = ctx->global_vars; var; var = var->next) { - if(lookup_script_identifier(script, var->name)) { + if(lookup_script_identifier(obj, var->name)) { FIXME("%s: redefined\n", debugstr_w(var->name)); return E_FAIL; } }
for(func = ctx->funcs; func; func = func->next) { - if(lookup_script_identifier(script, func->name)) { + if(lookup_script_identifier(obj, func->name)) { FIXME("%s: redefined\n", debugstr_w(func->name)); return E_FAIL; } }
for(class = ctx->classes; class; class = class->next) { - if(lookup_script_identifier(script, class->name)) { + if(lookup_script_identifier(obj, class->name)) { FIXME("%s: redefined\n", debugstr_w(class->name)); return E_FAIL; } @@ -1917,15 +1918,15 @@ HRESULT compile_script(script_ctx_t *script, const WCHAR *src, const WCHAR *deli
for(var = ctx.global_vars; var->next; var = var->next);
- var->next = script->global_vars; - script->global_vars = ctx.global_vars; + var->next = script->script_obj->global_vars; + script->script_obj->global_vars = ctx.global_vars; }
if(ctx.funcs) { for(new_func = ctx.funcs; new_func->next; new_func = new_func->next);
- new_func->next = script->global_funcs; - script->global_funcs = ctx.funcs; + new_func->next = script->script_obj->global_funcs; + script->script_obj->global_funcs = ctx.funcs; }
if(ctx.classes) { @@ -1938,8 +1939,8 @@ HRESULT compile_script(script_ctx_t *script, const WCHAR *src, const WCHAR *deli class = class->next; }
- class->next = script->classes; - script->classes = ctx.classes; + class->next = script->script_obj->classes; + script->script_obj->classes = ctx.classes; }
if(TRACE_ON(vbscript_disas)) @@ -1971,8 +1972,8 @@ HRESULT compile_procedure(script_ctx_t *script, const WCHAR *src, const WCHAR *d desc->func_cnt = 1; desc->funcs->entries[VBDISP_CALLGET] = &code->main_code;
- desc->next = script->procs; - script->procs = desc; + desc->next = script->script_obj->procs; + script->script_obj->procs = desc;
list_add_tail(&script->script_obj->noexec_code_list, &code->entry);
diff --git a/dlls/vbscript/interp.c b/dlls/vbscript/interp.c index 60c4340..3c9595f 100644 --- a/dlls/vbscript/interp.c +++ b/dlls/vbscript/interp.c @@ -97,6 +97,7 @@ static BOOL lookup_dynamic_vars(dynamic_var_t *var, const WCHAR *name, ref_t *re
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; named_item_t *item; function_t *func; IDispatch *disp; @@ -128,7 +129,7 @@ static HRESULT lookup_identifier(exec_ctx_t *ctx, BSTR name, vbdisp_invoke_type_ } }
- if(lookup_dynamic_vars(ctx->func->type == FUNC_GLOBAL ? ctx->script->global_vars : ctx->dynamic_vars, name, ref)) + if(lookup_dynamic_vars(ctx->func->type == FUNC_GLOBAL ? script_obj->global_vars : ctx->dynamic_vars, name, ref)) return S_OK;
if(ctx->func->type != FUNC_GLOBAL) { @@ -162,10 +163,10 @@ static HRESULT lookup_identifier(exec_ctx_t *ctx, BSTR name, vbdisp_invoke_type_ } }
- if(ctx->func->type != FUNC_GLOBAL && lookup_dynamic_vars(ctx->script->global_vars, name, ref)) + if(ctx->func->type != FUNC_GLOBAL && lookup_dynamic_vars(script_obj->global_vars, name, ref)) return S_OK;
- for(func = ctx->script->global_funcs; func; func = func->next) { + for(func = script_obj->global_funcs; func; func = func->next) { if(!wcsicmp(func->name, name)) { ref->type = REF_FUNC; ref->u.f = func; @@ -207,12 +208,13 @@ 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; dynamic_var_t *new_var; heap_pool_t *heap; WCHAR *str; unsigned size;
- heap = ctx->func->type == FUNC_GLOBAL ? &ctx->script->heap : &ctx->heap; + heap = ctx->func->type == FUNC_GLOBAL ? &script_obj->heap : &ctx->heap;
new_var = heap_pool_alloc(heap, sizeof(*new_var)); if(!new_var) @@ -228,8 +230,8 @@ static HRESULT add_dynamic_var(exec_ctx_t *ctx, const WCHAR *name, V_VT(&new_var->v) = VT_EMPTY;
if(ctx->func->type == FUNC_GLOBAL) { - new_var->next = ctx->script->global_vars; - ctx->script->global_vars = new_var; + new_var->next = script_obj->global_vars; + script_obj->global_vars = new_var; }else { new_var->next = ctx->dynamic_vars; ctx->dynamic_vars = new_var; @@ -1066,7 +1068,7 @@ static HRESULT interp_new(exec_ctx_t *ctx) return stack_push(ctx, &v); }
- for(class_desc = ctx->script->classes; class_desc; class_desc = class_desc->next) { + for(class_desc = ctx->script->script_obj->classes; class_desc; class_desc = class_desc->next) { if(!wcsicmp(class_desc->name, arg)) break; } diff --git a/dlls/vbscript/vbdisp.c b/dlls/vbscript/vbdisp.c index e84f31b..3ea3feb 100644 --- a/dlls/vbscript/vbdisp.c +++ b/dlls/vbscript/vbdisp.c @@ -617,11 +617,19 @@ static ULONG WINAPI ScriptDisp_Release(IDispatchEx *iface) if(!ref) { assert(!This->ctx);
+ release_dynamic_vars(This->global_vars); + while (This->procs) + { + class_desc_t *class_desc = This->procs; + This->procs = class_desc->next; + heap_free(class_desc); + } while (!list_empty(&This->code_list)) release_vbscode(LIST_ENTRY(list_head(&This->code_list), vbscode_t, entry)); while (!list_empty(&This->noexec_code_list)) release_vbscode(LIST_ENTRY(list_head(&This->noexec_code_list), vbscode_t, entry));
+ heap_pool_free(&This->heap); heap_free(This->ident_map); heap_free(This); } @@ -697,7 +705,7 @@ static HRESULT WINAPI ScriptDisp_GetDispID(IDispatchEx *iface, BSTR bstrName, DW } }
- for(var = This->ctx->global_vars; var; var = var->next) { + for(var = This->global_vars; var; var = var->next) { if(!wcsicmp(var->name, bstrName)) { ident = add_ident(This, var->name); if(!ident) @@ -710,7 +718,7 @@ static HRESULT WINAPI ScriptDisp_GetDispID(IDispatchEx *iface, BSTR bstrName, DW } }
- for(func = This->ctx->global_funcs; func; func = func->next) { + for(func = This->global_funcs; func; func = func->next) { if(!wcsicmp(func->name, bstrName)) { ident = add_ident(This, func->name); if(!ident) @@ -835,6 +843,7 @@ HRESULT create_script_disp(script_ctx_t *ctx, ScriptDisp **ret) script_disp->ctx = ctx; list_init(&script_disp->code_list); list_init(&script_disp->noexec_code_list); + heap_pool_init(&script_disp->heap);
*ret = script_disp; return S_OK; diff --git a/dlls/vbscript/vbscript.c b/dlls/vbscript/vbscript.c index 5e39f76..f4ac249 100644 --- a/dlls/vbscript/vbscript.c +++ b/dlls/vbscript/vbscript.c @@ -130,14 +130,9 @@ IDispatch *lookup_named_item(script_ctx_t *ctx, const WCHAR *name, unsigned flag
static void release_script(script_ctx_t *ctx) { - class_desc_t *class_desc; - collect_objects(ctx); clear_ei(&ctx->ei);
- release_dynamic_vars(ctx->global_vars); - ctx->global_vars = NULL; - while(!list_empty(&ctx->named_items)) { named_item_t *iter = LIST_ENTRY(list_head(&ctx->named_items), named_item_t, entry);
@@ -148,13 +143,6 @@ static void release_script(script_ctx_t *ctx) heap_free(iter); }
- while(ctx->procs) { - class_desc = ctx->procs; - ctx->procs = class_desc->next; - - heap_free(class_desc); - } - if(ctx->host_global) { IDispatch_Release(ctx->host_global); ctx->host_global = NULL; @@ -179,8 +167,6 @@ static void release_script(script_ctx_t *ctx) }
detach_global_objects(ctx); - heap_pool_free(&ctx->heap); - heap_pool_init(&ctx->heap); }
static void destroy_script(script_ctx_t *ctx) @@ -963,7 +949,6 @@ HRESULT WINAPI VBScriptFactory_CreateInstance(IClassFactory *iface, IUnknown *pU }
ctx->safeopt = INTERFACE_USES_DISPEX; - heap_pool_init(&ctx->heap); list_init(&ctx->objects); list_init(&ctx->code_list); list_init(&ctx->named_items); diff --git a/dlls/vbscript/vbscript.h b/dlls/vbscript/vbscript.h index cada4e2..9ce309e 100644 --- a/dlls/vbscript/vbscript.h +++ b/dlls/vbscript/vbscript.h @@ -120,6 +120,13 @@ struct _vbdisp_t { VARIANT props[1]; };
+typedef struct _dynamic_var_t { + struct _dynamic_var_t *next; + VARIANT v; + const WCHAR *name; + BOOL is_const; +} dynamic_var_t; + typedef struct _ident_map_t ident_map_t;
typedef struct { @@ -133,6 +140,13 @@ typedef struct { script_ctx_t *ctx; struct list code_list; struct list noexec_code_list; + + dynamic_var_t *global_vars; + function_t *global_funcs; + class_desc_t *classes; + class_desc_t *procs; + + heap_pool_t heap; } ScriptDisp;
typedef struct _builtin_prop_t builtin_prop_t; @@ -166,13 +180,6 @@ static inline VARIANT *get_arg(DISPPARAMS *dp, DWORD i) return dp->rgvarg + dp->cArgs-i-1; }
-typedef struct _dynamic_var_t { - struct _dynamic_var_t *next; - VARIANT v; - const WCHAR *name; - BOOL is_const; -} dynamic_var_t; - struct _script_ctx_t { IActiveScriptSite *site; LCID lcid; @@ -189,13 +196,6 @@ struct _script_ctx_t {
EXCEPINFO ei;
- dynamic_var_t *global_vars; - function_t *global_funcs; - class_desc_t *classes; - class_desc_t *procs; - - heap_pool_t heap; - struct list objects; struct list code_list; struct list named_items;
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com ---
This is temporary (instead of using an array which will come later), to keep it simpler and with less changes.
dlls/vbscript/compile.c | 32 +++----------------------------- dlls/vbscript/vbscript.c | 38 ++++++++++++++++++++++++++++++++++++++ dlls/vbscript/vbscript.h | 4 ++++ 3 files changed, 45 insertions(+), 29 deletions(-)
diff --git a/dlls/vbscript/compile.c b/dlls/vbscript/compile.c index 6ab8352..0b49380 100644 --- a/dlls/vbscript/compile.c +++ b/dlls/vbscript/compile.c @@ -1913,35 +1913,9 @@ HRESULT compile_script(script_ctx_t *script, const WCHAR *src, const WCHAR *deli return compile_error(script, hres); }
- if(ctx.global_vars) { - dynamic_var_t *var; - - for(var = ctx.global_vars; var->next; var = var->next); - - var->next = script->script_obj->global_vars; - script->script_obj->global_vars = ctx.global_vars; - } - - if(ctx.funcs) { - for(new_func = ctx.funcs; new_func->next; new_func = new_func->next); - - new_func->next = script->script_obj->global_funcs; - script->script_obj->global_funcs = ctx.funcs; - } - - if(ctx.classes) { - class_desc_t *class = ctx.classes; - - while(1) { - class->ctx = script; - if(!class->next) - break; - class = class->next; - } - - class->next = script->script_obj->classes; - script->script_obj->classes = ctx.classes; - } + code->global_vars = ctx.global_vars; + code->funcs = ctx.funcs; + code->classes = ctx.classes;
if(TRACE_ON(vbscript_disas)) dump_code(&ctx); diff --git a/dlls/vbscript/vbscript.c b/dlls/vbscript/vbscript.c index f4ac249..79a27d1 100644 --- a/dlls/vbscript/vbscript.c +++ b/dlls/vbscript/vbscript.c @@ -82,6 +82,44 @@ 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; + + if (code->global_vars) + { + dynamic_var_t *var; + + for (var = code->global_vars; var->next; var = var->next); + + var->next = obj->global_vars; + obj->global_vars = code->global_vars; + } + + if (code->funcs) + { + function_t *func; + + for (func = code->funcs; func->next; func = func->next); + + func->next = obj->global_funcs; + obj->global_funcs = code->funcs; + } + + if (code->classes) + { + class_desc_t *class = code->classes; + + for (;;) + { + class->ctx = ctx; + if (!class->next) + break; + class = class->next; + } + + class->next = obj->classes; + obj->classes = code->classes; + } + return exec_script(ctx, TRUE, &code->main_code, NULL, NULL, res); }
diff --git a/dlls/vbscript/vbscript.h b/dlls/vbscript/vbscript.h index 9ce309e..568c1a5 100644 --- a/dlls/vbscript/vbscript.h +++ b/dlls/vbscript/vbscript.h @@ -347,6 +347,10 @@ struct _vbscode_t { unsigned bstr_cnt; heap_pool_t heap;
+ dynamic_var_t *global_vars; + function_t *funcs; + class_desc_t *classes; + struct list entry; };
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com ---
Needed for next patch.
dlls/vbscript/vbscript.c | 42 ++++++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 14 deletions(-)
diff --git a/dlls/vbscript/vbscript.c b/dlls/vbscript/vbscript.c index 79a27d1..d751c57 100644 --- a/dlls/vbscript/vbscript.c +++ b/dlls/vbscript/vbscript.c @@ -73,6 +73,32 @@ static void change_state(VBScript *This, SCRIPTSTATE state) IActiveScriptSite_OnStateChange(This->ctx->site, state); }
+static HRESULT init_ctx(VBScript *vbscript) +{ + script_ctx_t *ctx; + HRESULT hr; + + if (vbscript->ctx) return S_OK; + + ctx = heap_alloc_zero(sizeof(*ctx)); + if (!ctx) return E_OUTOFMEMORY; + + ctx->safeopt = INTERFACE_USES_DISPEX; + list_init(&ctx->objects); + list_init(&ctx->code_list); + list_init(&ctx->named_items); + + hr = init_global(ctx); + if (FAILED(hr)) + { + heap_free(ctx); + return hr; + } + + vbscript->ctx = ctx; + return S_OK; +} + static inline BOOL is_started(VBScript *This) { return This->state == SCRIPTSTATE_STARTED @@ -961,7 +987,6 @@ static const IObjectSafetyVtbl VBScriptSafetyVtbl = {
HRESULT WINAPI VBScriptFactory_CreateInstance(IClassFactory *iface, IUnknown *pUnkOuter, REFIID riid, void **ppv) { - script_ctx_t *ctx; VBScript *ret; HRESULT hres;
@@ -980,20 +1005,9 @@ HRESULT WINAPI VBScriptFactory_CreateInstance(IClassFactory *iface, IUnknown *pU ret->ref = 1; ret->state = SCRIPTSTATE_UNINITIALIZED;
- ctx = ret->ctx = heap_alloc_zero(sizeof(*ctx)); - if(!ctx) { + if(FAILED(hres = init_ctx(ret))) + { heap_free(ret); - return E_OUTOFMEMORY; - } - - ctx->safeopt = INTERFACE_USES_DISPEX; - list_init(&ctx->objects); - list_init(&ctx->code_list); - list_init(&ctx->named_items); - - hres = init_global(ctx); - if(FAILED(hres)) { - IActiveScript_Release(&ret->IActiveScript_iface); return hres; }
When the engine is closed, even the persistent code is removed.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/vbscript/vbscript.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-)
diff --git a/dlls/vbscript/vbscript.c b/dlls/vbscript/vbscript.c index d751c57..e0ac05e 100644 --- a/dlls/vbscript/vbscript.c +++ b/dlls/vbscript/vbscript.c @@ -238,7 +238,6 @@ static void destroy_script(script_ctx_t *ctx) while(!list_empty(&ctx->code_list)) release_vbscode(LIST_ENTRY(list_head(&ctx->code_list), vbscode_t, entry));
- release_script(ctx); heap_free(ctx); }
@@ -262,6 +261,11 @@ static void decrease_state(VBScript *This, SCRIPTSTATE state) change_state(This, state); release_script(This->ctx); This->thread_id = 0; + if(state == SCRIPTSTATE_CLOSED) + { + destroy_script(This->ctx); + This->ctx = NULL; + } break; case SCRIPTSTATE_CLOSED: break; @@ -437,7 +441,6 @@ static ULONG WINAPI VBScript_Release(IActiveScript *iface)
if(!ref) { decrease_state(This, SCRIPTSTATE_CLOSED); - destroy_script(This->ctx); heap_free(This); }
@@ -455,6 +458,9 @@ static HRESULT WINAPI VBScript_SetScriptSite(IActiveScript *iface, IActiveScript if(!pass) return E_POINTER;
+ if(FAILED(hres = init_ctx(This))) + return hres; + if(This->ctx->site) return E_UNEXPECTED;
@@ -781,9 +787,13 @@ static ULONG WINAPI VBScriptParse_Release(IActiveScriptParse *iface) static HRESULT WINAPI VBScriptParse_InitNew(IActiveScriptParse *iface) { VBScript *This = impl_from_IActiveScriptParse(iface); + HRESULT hr;
TRACE("(%p)\n", This);
+ if(FAILED(hr = init_ctx(This))) + return hr; + if(This->is_initialized) return E_UNEXPECTED; This->is_initialized = TRUE; @@ -952,12 +962,16 @@ static HRESULT WINAPI VBScriptSafety_GetInterfaceSafetyOptions(IObjectSafety *if DWORD *pdwSupportedOptions, DWORD *pdwEnabledOptions) { VBScript *This = impl_from_IObjectSafety(iface); + HRESULT hr;
TRACE("(%p)->(%s %p %p)\n", This, debugstr_guid(riid), pdwSupportedOptions, pdwEnabledOptions);
if(!pdwSupportedOptions || !pdwEnabledOptions) return E_POINTER;
+ if(FAILED(hr = init_ctx(This))) + return hr; + *pdwSupportedOptions = SUPPORTED_OPTIONS; *pdwEnabledOptions = This->ctx->safeopt; return S_OK; @@ -967,12 +981,16 @@ static HRESULT WINAPI VBScriptSafety_SetInterfaceSafetyOptions(IObjectSafety *if DWORD dwOptionSetMask, DWORD dwEnabledOptions) { VBScript *This = impl_from_IObjectSafety(iface); + HRESULT hr;
TRACE("(%p)->(%s %x %x)\n", This, debugstr_guid(riid), dwOptionSetMask, dwEnabledOptions);
if(dwOptionSetMask & ~SUPPORTED_OPTIONS) return E_FAIL;
+ if(FAILED(hr = init_ctx(This))) + return hr; + This->ctx->safeopt = (dwEnabledOptions & dwOptionSetMask) | (This->ctx->safeopt & ~dwOptionSetMask) | INTERFACE_USES_DISPEX; return S_OK; }
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/vbscript/tests/vbscript.c | 194 +++++++++++++++++++++++++++++++++ 1 file changed, 194 insertions(+)
diff --git a/dlls/vbscript/tests/vbscript.c b/dlls/vbscript/tests/vbscript.c index fdbfc44..a678710 100644 --- a/dlls/vbscript/tests/vbscript.c +++ b/dlls/vbscript/tests/vbscript.c @@ -624,6 +624,199 @@ static void test_scriptdisp(void) ok(!ref, "ref = %d\n", ref); }
+static void test_code_persistence(void) +{ + IActiveScriptParse *parser; + IDispatchEx *script_disp; + IActiveScript *vbscript; + HRESULT hr; + DISPID id; + ULONG ref; + BSTR str; + + vbscript = create_vbscript(); + + hr = IActiveScript_QueryInterface(vbscript, &IID_IActiveScriptParse, (void**)&parser); + ok(hr == S_OK, "Could not get IActiveScriptParse iface: %08x\n", hr); + test_state(vbscript, SCRIPTSTATE_UNINITIALIZED); + test_safety(vbscript); + + SET_EXPECT(GetLCID); + hr = IActiveScript_SetScriptSite(vbscript, &ActiveScriptSite); + ok(hr == S_OK, "SetScriptSite failed: %08x\n", hr); + CHECK_CALLED(GetLCID); + + SET_EXPECT(OnStateChange_INITIALIZED); + hr = IActiveScriptParse_InitNew(parser); + ok(hr == S_OK, "InitNew failed: %08x\n", hr); + CHECK_CALLED(OnStateChange_INITIALIZED); + test_state(vbscript, SCRIPTSTATE_INITIALIZED); + + str = a2bstr( + "x = 1\n" + "dim y\ny = 2\n"); + hr = IActiveScriptParse_ParseScriptText(parser, str, NULL, NULL, NULL, 0, 0, 0, NULL, NULL); + ok(hr == S_OK, "ParseScriptText failed: %08x\n", hr); + SysFreeString(str); + + str = a2bstr("dim z\nz = 3\n"); + hr = IActiveScriptParse_ParseScriptText(parser, str, NULL, NULL, NULL, 0, 0, SCRIPTTEXT_ISPERSISTENT, NULL, NULL); + ok(hr == S_OK, "ParseScriptText failed: %08x\n", hr); + SysFreeString(str); + + /* Pending code does not add identifiers to the global scope */ + script_disp = get_script_dispatch(vbscript); + id = 0; + get_disp_id(script_disp, "x", DISP_E_UNKNOWNNAME, &id); + ok(id == -1, "id = %d, expected -1\n", id); + id = 0; + get_disp_id(script_disp, "y", DISP_E_UNKNOWNNAME, &id); + ok(id == -1, "id = %d, expected -1\n", id); + id = 0; + get_disp_id(script_disp, "z", DISP_E_UNKNOWNNAME, &id); + ok(id == -1, "id = %d, expected -1\n", id); + IDispatchEx_Release(script_disp); + + /* Uninitialized state removes code without SCRIPTTEXT_ISPERSISTENT */ + SET_EXPECT(OnStateChange_UNINITIALIZED); + hr = IActiveScript_SetScriptState(vbscript, SCRIPTSTATE_UNINITIALIZED); + ok(hr == S_OK, "SetScriptState(SCRIPTSTATE_UNINITIALIZED) failed: %08x\n", hr); + CHECK_CALLED(OnStateChange_UNINITIALIZED); + test_no_script_dispatch(vbscript); + + SET_EXPECT(GetLCID); + SET_EXPECT(OnStateChange_INITIALIZED); + hr = IActiveScript_SetScriptSite(vbscript, &ActiveScriptSite); + ok(hr == S_OK, "SetScriptSite failed: %08x\n", hr); + CHECK_CALLED(GetLCID); + CHECK_CALLED(OnStateChange_INITIALIZED); + + SET_EXPECT(OnStateChange_CONNECTED); + SET_EXPECT(OnEnterScript); + SET_EXPECT(OnLeaveScript); + hr = IActiveScript_SetScriptState(vbscript, SCRIPTSTATE_CONNECTED); + ok(hr == S_OK, "SetScriptState(SCRIPTSTATE_CONNECTED) failed: %08x\n", hr); + CHECK_CALLED(OnStateChange_CONNECTED); + CHECK_CALLED(OnEnterScript); + CHECK_CALLED(OnLeaveScript); + test_state(vbscript, SCRIPTSTATE_CONNECTED); + + script_disp = get_script_dispatch(vbscript); + id = 0; + get_disp_id(script_disp, "x", DISP_E_UNKNOWNNAME, &id); + ok(id == -1, "id = %d, expected -1\n", id); + id = 0; + get_disp_id(script_disp, "y", DISP_E_UNKNOWNNAME, &id); + ok(id == -1, "id = %d, expected -1\n", id); + id = 0; + get_disp_id(script_disp, "z", S_OK, &id); + ok(id != -1, "id = -1\n"); + IDispatchEx_Release(script_disp); + + /* Uninitialized state does not remove persistent code, even if it was executed */ + SET_EXPECT(OnStateChange_DISCONNECTED); + SET_EXPECT(OnStateChange_INITIALIZED); + SET_EXPECT(OnStateChange_UNINITIALIZED); + hr = IActiveScript_SetScriptState(vbscript, SCRIPTSTATE_UNINITIALIZED); + ok(hr == S_OK, "SetScriptState(SCRIPTSTATE_UNINITIALIZED) failed: %08x\n", hr); + CHECK_CALLED(OnStateChange_DISCONNECTED); + CHECK_CALLED(OnStateChange_INITIALIZED); + CHECK_CALLED(OnStateChange_UNINITIALIZED); + test_no_script_dispatch(vbscript); + + SET_EXPECT(GetLCID); + SET_EXPECT(OnStateChange_INITIALIZED); + hr = IActiveScript_SetScriptSite(vbscript, &ActiveScriptSite); + ok(hr == S_OK, "SetScriptSite failed: %08x\n", hr); + CHECK_CALLED(GetLCID); + CHECK_CALLED(OnStateChange_INITIALIZED); + + script_disp = get_script_dispatch(vbscript); + id = 0; + get_disp_id(script_disp, "z", DISP_E_UNKNOWNNAME, &id); + ok(id == -1, "id = %d, expected -1\n", id); + IDispatchEx_Release(script_disp); + + SET_EXPECT(OnStateChange_CONNECTED); + SET_EXPECT(OnEnterScript); + SET_EXPECT(OnLeaveScript); + hr = IActiveScript_SetScriptState(vbscript, SCRIPTSTATE_CONNECTED); + ok(hr == S_OK, "SetScriptState(SCRIPTSTATE_CONNECTED) failed: %08x\n", hr); + CHECK_CALLED(OnStateChange_CONNECTED); + CHECK_CALLED(OnEnterScript); + CHECK_CALLED(OnLeaveScript); + test_state(vbscript, SCRIPTSTATE_CONNECTED); + + script_disp = get_script_dispatch(vbscript); + id = 0; + get_disp_id(script_disp, "z", S_OK, &id); + ok(id != -1, "id = -1\n"); + IDispatchEx_Release(script_disp); + + SET_EXPECT(OnStateChange_DISCONNECTED); + SET_EXPECT(OnStateChange_INITIALIZED); + SET_EXPECT(OnStateChange_UNINITIALIZED); + hr = IActiveScript_SetScriptState(vbscript, SCRIPTSTATE_UNINITIALIZED); + ok(hr == S_OK, "SetScriptState(SCRIPTSTATE_UNINITIALIZED) failed: %08x\n", hr); + CHECK_CALLED(OnStateChange_DISCONNECTED); + CHECK_CALLED(OnStateChange_INITIALIZED); + CHECK_CALLED(OnStateChange_UNINITIALIZED); + + SET_EXPECT(GetLCID); + SET_EXPECT(OnStateChange_INITIALIZED); + hr = IActiveScript_SetScriptSite(vbscript, &ActiveScriptSite); + ok(hr == S_OK, "SetScriptSite failed: %08x\n", hr); + CHECK_CALLED(GetLCID); + CHECK_CALLED(OnStateChange_INITIALIZED); + + str = a2bstr("dim y\ny = 2\n"); + hr = IActiveScriptParse_ParseScriptText(parser, str, NULL, NULL, NULL, 0, 0, SCRIPTTEXT_ISPERSISTENT, NULL, NULL); + ok(hr == S_OK, "ParseScriptText failed: %08x\n", hr); + SysFreeString(str); + + /* Closing the script engine removes all code (even if it's pending and persistent) */ + SET_EXPECT(OnStateChange_CLOSED); + hr = IActiveScript_Close(vbscript); + ok(hr == S_OK, "Close failed: %08x\n", hr); + CHECK_CALLED(OnStateChange_CLOSED); + test_state(vbscript, SCRIPTSTATE_CLOSED); + test_no_script_dispatch(vbscript); + + SET_EXPECT(OnStateChange_INITIALIZED); + SET_EXPECT(GetLCID); + hr = IActiveScript_SetScriptSite(vbscript, &ActiveScriptSite); + ok(hr == S_OK, "SetScriptSite failed: %08x\n", hr); + CHECK_CALLED(OnStateChange_INITIALIZED); + CHECK_CALLED(GetLCID); + test_state(vbscript, SCRIPTSTATE_INITIALIZED); + + SET_EXPECT(OnStateChange_CONNECTED); + hr = IActiveScript_SetScriptState(vbscript, SCRIPTSTATE_CONNECTED); + ok(hr == S_OK, "SetScriptState(SCRIPTSTATE_CONNECTED) failed: %08x\n", hr); + CHECK_CALLED(OnStateChange_CONNECTED); + test_state(vbscript, SCRIPTSTATE_CONNECTED); + + script_disp = get_script_dispatch(vbscript); + id = 0; + get_disp_id(script_disp, "y", DISP_E_UNKNOWNNAME, &id); + ok(id == -1, "id = %d, expected -1\n", id); + id = 0; + get_disp_id(script_disp, "z", DISP_E_UNKNOWNNAME, &id); + ok(id == -1, "id = %d, expected -1\n", id); + IDispatchEx_Release(script_disp); + + IActiveScriptParse_Release(parser); + + SET_EXPECT(OnStateChange_DISCONNECTED); + SET_EXPECT(OnStateChange_INITIALIZED); + SET_EXPECT(OnStateChange_CLOSED); + ref = IActiveScript_Release(vbscript); + ok(!ref, "ref = %d\n", ref); + CHECK_CALLED(OnStateChange_DISCONNECTED); + CHECK_CALLED(OnStateChange_INITIALIZED); + CHECK_CALLED(OnStateChange_CLOSED); +} + static void test_vbscript(void) { IActiveScriptParseProcedure2 *parse_proc; @@ -1215,6 +1408,7 @@ START_TEST(vbscript) test_vbscript_initializing(); test_named_items(); test_scriptdisp(); + test_code_persistence(); test_RegExp(); test_RegExp_Replace(); }else {
So, I realized there are some corner cases in which this series is wrong (mostly to do with persistent code). Hopefully I'll figure out a simple way to fix them tomorrow.
Please ignore for now.