Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com ---
Note that we have to move the non-persistent vbscode from the context's list, so it can be freed by the dispatch object only when it is released.
This is needed for the TypeInfo (and named contexts).
dlls/vbscript/compile.c | 15 ++++---- dlls/vbscript/interp.c | 39 +++++++++++---------- dlls/vbscript/vbdisp.c | 38 +++++++++++++++----- dlls/vbscript/vbscript.c | 75 +++++++++++++++------------------------- dlls/vbscript/vbscript.h | 43 ++++++++++++----------- 5 files changed, 107 insertions(+), 103 deletions(-)
diff --git a/dlls/vbscript/compile.c b/dlls/vbscript/compile.c index bc00209..9ddfacf 100644 --- a/dlls/vbscript/compile.c +++ b/dlls/vbscript/compile.c @@ -1758,21 +1758,22 @@ static HRESULT compile_class(compile_ctx_t *ctx, class_decl_t *class_decl)
static BOOL lookup_script_identifier(script_ctx_t *script, const WCHAR *identifier) { + ScriptDisp *obj = script->script_obj; class_desc_t *class; vbscode_t *code; unsigned i;
- for(i = 0; i < script->global_vars_cnt; i++) { - if(!wcsicmp(script->global_vars[i]->name, identifier)) + for(i = 0; i < obj->global_vars_cnt; i++) { + if(!wcsicmp(obj->global_vars[i]->name, identifier)) return TRUE; }
- for(i = 0; i < script->global_funcs_cnt; i++) { - if(!wcsicmp(script->global_funcs[i]->name, identifier)) + for(i = 0; i < obj->global_funcs_cnt; i++) { + if(!wcsicmp(obj->global_funcs[i]->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; } @@ -1977,8 +1978,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;
*ret = desc; return S_OK; diff --git a/dlls/vbscript/interp.c b/dlls/vbscript/interp.c index d15a1b5..66ad206 100644 --- a/dlls/vbscript/interp.c +++ b/dlls/vbscript/interp.c @@ -94,7 +94,7 @@ static BOOL lookup_dynamic_vars(dynamic_var_t *var, const WCHAR *name, ref_t *re return FALSE; }
-static BOOL lookup_global_vars(script_ctx_t *script, const WCHAR *name, ref_t *ref) +static BOOL lookup_global_vars(ScriptDisp *script, const WCHAR *name, ref_t *ref) { dynamic_var_t **vars = script->global_vars; size_t i, cnt = script->global_vars_cnt; @@ -112,6 +112,7 @@ static BOOL lookup_global_vars(script_ctx_t *script, const WCHAR *name, ref_t *r
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; IDispatch *disp; unsigned i; @@ -175,11 +176,11 @@ static HRESULT lookup_identifier(exec_ctx_t *ctx, BSTR name, vbdisp_invoke_type_ } }
- if(lookup_global_vars(ctx->script, name, ref)) + if(lookup_global_vars(script_obj, name, ref)) return S_OK;
- for(i = 0; i < ctx->script->global_funcs_cnt; i++) { - function_t *func = ctx->script->global_funcs[i]; + 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; @@ -221,12 +222,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) @@ -243,19 +245,19 @@ 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) { - size_t cnt = ctx->script->global_vars_cnt + 1; - if(cnt > ctx->script->global_vars_size) { + size_t cnt = script_obj->global_vars_cnt + 1; + if(cnt > script_obj->global_vars_size) { dynamic_var_t **new_vars; - if(ctx->script->global_vars) - new_vars = heap_realloc(ctx->script->global_vars, cnt * 2 * sizeof(*new_vars)); + if(script_obj->global_vars) + new_vars = heap_realloc(script_obj->global_vars, cnt * 2 * sizeof(*new_vars)); else new_vars = heap_alloc(cnt * 2 * sizeof(*new_vars)); if(!new_vars) return E_OUTOFMEMORY; - ctx->script->global_vars = new_vars; - ctx->script->global_vars_size = cnt * 2; + script_obj->global_vars = new_vars; + script_obj->global_vars_size = cnt * 2; } - ctx->script->global_vars[ctx->script->global_vars_cnt++] = new_var; + script_obj->global_vars[script_obj->global_vars_cnt++] = new_var; }else { new_var->next = ctx->dynamic_vars; ctx->dynamic_vars = new_var; @@ -1113,7 +1115,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; } @@ -1133,6 +1135,7 @@ static HRESULT interp_new(exec_ctx_t *ctx)
static HRESULT interp_dim(exec_ctx_t *ctx) { + ScriptDisp *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; @@ -1146,13 +1149,13 @@ static HRESULT interp_dim(exec_ctx_t *ctx)
if(ctx->func->type == FUNC_GLOBAL) { unsigned i; - for(i = 0; i < ctx->script->global_vars_cnt; i++) { - if(!wcsicmp(ctx->script->global_vars[i]->name, ident)) + for(i = 0; i < script_obj->global_vars_cnt; i++) { + if(!wcsicmp(script_obj->global_vars[i]->name, ident)) break; } - assert(i < ctx->script->global_vars_cnt); - v = &ctx->script->global_vars[i]->v; - array_ref = &ctx->script->global_vars[i]->array; + assert(i < script_obj->global_vars_cnt); + v = &script_obj->global_vars[i]->v; + array_ref = &script_obj->global_vars[i]->array; }else { ref_t ref;
diff --git a/dlls/vbscript/vbdisp.c b/dlls/vbscript/vbdisp.c index 12626e0..8bb2b68 100644 --- a/dlls/vbscript/vbdisp.c +++ b/dlls/vbscript/vbdisp.c @@ -569,11 +569,29 @@ static ULONG WINAPI ScriptDisp_Release(IDispatchEx *iface) { ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface); LONG ref = InterlockedDecrement(&This->ref); + unsigned i;
TRACE("(%p) ref=%d\n", This, ref);
if(!ref) { assert(!This->ctx); + + while (This->procs) + { + class_desc_t *class_desc = This->procs; + This->procs = class_desc->next; + heap_free(class_desc); + } + + for (i = 0; i < This->global_vars_cnt; i++) + release_dynamic_var(This->global_vars[i]); + + while (!list_empty(&This->code_list)) + release_vbscode(LIST_ENTRY(list_head(&This->code_list), vbscode_t, entry)); + + heap_pool_free(&This->heap); + heap_free(This->global_vars); + heap_free(This->global_funcs); heap_free(This); }
@@ -639,15 +657,15 @@ static HRESULT WINAPI ScriptDisp_GetDispID(IDispatchEx *iface, BSTR bstrName, DW if(!This->ctx) return E_UNEXPECTED;
- for(i = 0; i < This->ctx->global_vars_cnt; i++) { - if(!wcsicmp(This->ctx->global_vars[i]->name, bstrName)) { + for(i = 0; i < This->global_vars_cnt; i++) { + if(!wcsicmp(This->global_vars[i]->name, bstrName)) { *pid = i + 1; return S_OK; } }
- for(i = 0; i < This->ctx->global_funcs_cnt; i++) { - if(!wcsicmp(This->ctx->global_funcs[i]->name, bstrName)) { + for(i = 0; i < This->global_funcs_cnt; i++) { + if(!wcsicmp(This->global_funcs[i]->name, bstrName)) { *pid = i + 1 + DISPID_FUNCTION_MASK; return S_OK; } @@ -668,14 +686,14 @@ static HRESULT WINAPI ScriptDisp_InvokeEx(IDispatchEx *iface, DISPID id, LCID lc if (id & DISPID_FUNCTION_MASK) { id &= ~DISPID_FUNCTION_MASK; - if (id > This->ctx->global_funcs_cnt) + if (id > This->global_funcs_cnt) return DISP_E_MEMBERNOTFOUND;
switch (wFlags) { case DISPATCH_METHOD: case DISPATCH_METHOD | DISPATCH_PROPERTYGET: - hres = exec_script(This->ctx, TRUE, This->ctx->global_funcs[id - 1], NULL, pdp, pvarRes); + hres = exec_script(This->ctx, TRUE, This->global_funcs[id - 1], NULL, pdp, pvarRes); break; default: FIXME("Unsupported flags %x\n", wFlags); @@ -685,16 +703,16 @@ static HRESULT WINAPI ScriptDisp_InvokeEx(IDispatchEx *iface, DISPID id, LCID lc return hres; }
- if (id > This->ctx->global_vars_cnt) + if (id > This->global_vars_cnt) return DISP_E_MEMBERNOTFOUND;
- if (This->ctx->global_vars[id - 1]->is_const) + if (This->global_vars[id - 1]->is_const) { FIXME("const not supported\n"); return E_NOTIMPL; }
- return invoke_variant_prop(This->ctx, &This->ctx->global_vars[id - 1]->v, wFlags, pdp, pvarRes); + return invoke_variant_prop(This->ctx, &This->global_vars[id - 1]->v, wFlags, pdp, pvarRes); }
static HRESULT WINAPI ScriptDisp_DeleteMemberByName(IDispatchEx *iface, BSTR bstrName, DWORD grfdex) @@ -768,6 +786,8 @@ HRESULT create_script_disp(script_ctx_t *ctx, ScriptDisp **ret) script_disp->IDispatchEx_iface.lpVtbl = &ScriptDispVtbl; script_disp->ref = 1; script_disp->ctx = ctx; + heap_pool_init(&script_disp->heap); + 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 fdade9f..9d20433 100644 --- a/dlls/vbscript/vbscript.c +++ b/dlls/vbscript/vbscript.c @@ -82,41 +82,42 @@ 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; function_t *func_iter, **new_funcs; dynamic_var_t *var, **new_vars; size_t cnt, i;
- cnt = ctx->global_vars_cnt + code->main_code.var_cnt; - if (cnt > ctx->global_vars_size) + cnt = obj->global_vars_cnt + code->main_code.var_cnt; + if (cnt > obj->global_vars_size) { - if (ctx->global_vars) - new_vars = heap_realloc(ctx->global_vars, cnt * sizeof(*new_vars)); + if (obj->global_vars) + new_vars = heap_realloc(obj->global_vars, cnt * sizeof(*new_vars)); else new_vars = heap_alloc(cnt * sizeof(*new_vars)); if (!new_vars) return E_OUTOFMEMORY; - ctx->global_vars = new_vars; - ctx->global_vars_size = cnt; + obj->global_vars = new_vars; + obj->global_vars_size = cnt; }
- cnt = ctx->global_funcs_cnt; + cnt = obj->global_funcs_cnt; for (func_iter = code->funcs; func_iter; func_iter = func_iter->next) cnt++; - if (cnt > ctx->global_funcs_size) + if (cnt > obj->global_funcs_size) { - if (ctx->global_funcs) - new_funcs = heap_realloc(ctx->global_funcs, cnt * sizeof(*new_funcs)); + if (obj->global_funcs) + new_funcs = heap_realloc(obj->global_funcs, cnt * sizeof(*new_funcs)); else new_funcs = heap_alloc(cnt * sizeof(*new_funcs)); if (!new_funcs) return E_OUTOFMEMORY; - ctx->global_funcs = new_funcs; - ctx->global_funcs_size = cnt; + obj->global_funcs = new_funcs; + obj->global_funcs_size = cnt; }
for (i = 0; i < code->main_code.var_cnt; i++) { - if (!(var = heap_pool_alloc(&ctx->heap, sizeof(*var)))) + if (!(var = heap_pool_alloc(&obj->heap, sizeof(*var)))) return E_OUTOFMEMORY;
var->name = code->main_code.vars[i].name; @@ -124,24 +125,24 @@ static HRESULT exec_global_code(script_ctx_t *ctx, vbscode_t *code, VARIANT *res var->is_const = FALSE; var->array = NULL;
- ctx->global_vars[ctx->global_vars_cnt + i] = var; + obj->global_vars[obj->global_vars_cnt + i] = var; }
- ctx->global_vars_cnt += code->main_code.var_cnt; + obj->global_vars_cnt += code->main_code.var_cnt;
for (func_iter = code->funcs; func_iter; func_iter = func_iter->next) { - for (i = 0; i < ctx->global_funcs_cnt; i++) + for (i = 0; i < obj->global_funcs_cnt; i++) { - if (!wcsicmp(ctx->global_funcs[i]->name, func_iter->name)) + if (!wcsicmp(obj->global_funcs[i]->name, func_iter->name)) { /* global function already exists, replace it */ - ctx->global_funcs[i] = func_iter; + obj->global_funcs[i] = func_iter; break; } } - if (i == ctx->global_funcs_cnt) - ctx->global_funcs[ctx->global_funcs_cnt++] = func_iter; + if (i == obj->global_funcs_cnt) + obj->global_funcs[obj->global_funcs_cnt++] = func_iter; }
if (code->classes) @@ -156,8 +157,8 @@ static HRESULT exec_global_code(script_ctx_t *ctx, vbscode_t *code, VARIANT *res class = class->next; }
- class->next = ctx->classes; - ctx->classes = code->classes; + class->next = obj->classes; + obj->classes = code->classes; code->last_class = class; }
@@ -210,24 +211,10 @@ IDispatch *lookup_named_item(script_ctx_t *ctx, const WCHAR *name, unsigned flag static void release_script(script_ctx_t *ctx) { vbscode_t *code, *code_next; - class_desc_t *class_desc; - unsigned i;
collect_objects(ctx); clear_ei(&ctx->ei);
- for(i = 0; i < ctx->global_vars_cnt; i++) - release_dynamic_var(ctx->global_vars[i]); - - heap_free(ctx->global_vars); - heap_free(ctx->global_funcs); - ctx->global_vars = NULL; - ctx->global_vars_cnt = 0; - ctx->global_vars_size = 0; - ctx->global_funcs = NULL; - ctx->global_funcs_cnt = 0; - ctx->global_funcs_size = 0; - LIST_FOR_EACH_ENTRY_SAFE(code, code_next, &ctx->code_list, vbscode_t, entry) { if(code->is_persistent) @@ -236,7 +223,10 @@ static void release_script(script_ctx_t *ctx) if(code->last_class) code->last_class->next = NULL; } else - release_vbscode(code); + { + list_remove(&code->entry); + list_add_tail(&ctx->script_obj->code_list, &code->entry); + } }
while(!list_empty(&ctx->named_items)) { @@ -249,13 +239,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; @@ -278,9 +261,6 @@ static void release_script(script_ctx_t *ctx) script_obj->ctx = NULL; IDispatchEx_Release(&script_obj->IDispatchEx_iface); } - - heap_pool_free(&ctx->heap); - heap_pool_init(&ctx->heap); }
static void release_code_list(script_ctx_t *ctx) @@ -1054,7 +1034,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 1cc36fd..58db0b5 100644 --- a/dlls/vbscript/vbscript.h +++ b/dlls/vbscript/vbscript.h @@ -120,11 +120,33 @@ struct _vbdisp_t { VARIANT props[1]; };
+typedef struct _dynamic_var_t { + struct _dynamic_var_t *next; + VARIANT v; + const WCHAR *name; + BOOL is_const; + SAFEARRAY *array; +} dynamic_var_t; + typedef struct { IDispatchEx IDispatchEx_iface; LONG ref;
+ dynamic_var_t **global_vars; + size_t global_vars_cnt; + size_t global_vars_size; + + function_t **global_funcs; + size_t global_funcs_cnt; + size_t global_funcs_size; + + class_desc_t *classes; + class_desc_t *procs; + script_ctx_t *ctx; + heap_pool_t heap; + + struct list code_list; } ScriptDisp;
typedef struct _builtin_prop_t builtin_prop_t; @@ -158,14 +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; - SAFEARRAY *array; -} dynamic_var_t; - struct _script_ctx_t { IActiveScriptSite *site; LCID lcid; @@ -182,19 +196,6 @@ struct _script_ctx_t {
EXCEPINFO ei;
- dynamic_var_t **global_vars; - size_t global_vars_cnt; - size_t global_vars_size; - - function_t **global_funcs; - size_t global_funcs_cnt; - size_t global_funcs_size; - - 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 needed for the TypeInfo since it needs to hold a ref to the persistent code, too. Though we keep the ref in the script dispatch since it's more correct this way (even though we bail out when there's no context, we still technically reference the persistent code funcs/classes in the dispatch object).
I couldn't refcount the script context itself since it is re-used after being closed, and was not deemed a good approach to free it (my previous attempts).
dlls/vbscript/compile.c | 4 +-- dlls/vbscript/vbdisp.c | 4 +++ dlls/vbscript/vbscript.c | 54 ++++++++++++++++++++++++++++------------ dlls/vbscript/vbscript.h | 9 ++++++- 4 files changed, 52 insertions(+), 19 deletions(-)
diff --git a/dlls/vbscript/compile.c b/dlls/vbscript/compile.c index 9ddfacf..6305fe2 100644 --- a/dlls/vbscript/compile.c +++ b/dlls/vbscript/compile.c @@ -1778,7 +1778,7 @@ static BOOL lookup_script_identifier(script_ctx_t *script, const WCHAR *identifi return TRUE; }
- LIST_FOR_EACH_ENTRY(code, &script->code_list, vbscode_t, entry) { + LIST_FOR_EACH_ENTRY(code, &script->code_list->list, vbscode_t, entry) { unsigned var_cnt = code->main_code.var_cnt; var_desc_t *vars = code->main_code.vars; function_t *func; @@ -1954,7 +1954,7 @@ 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); + list_add_tail(&script->code_list->list, &code->entry); *ret = code; return S_OK; } diff --git a/dlls/vbscript/vbdisp.c b/dlls/vbscript/vbdisp.c index 8bb2b68..e6a2552 100644 --- a/dlls/vbscript/vbdisp.c +++ b/dlls/vbscript/vbdisp.c @@ -589,6 +589,7 @@ 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));
+ release_code_list(This->persistent_code_list); heap_pool_free(&This->heap); heap_free(This->global_vars); heap_free(This->global_funcs); @@ -789,6 +790,9 @@ HRESULT create_script_disp(script_ctx_t *ctx, ScriptDisp **ret) heap_pool_init(&script_disp->heap); list_init(&script_disp->code_list);
+ script_disp->persistent_code_list = ctx->code_list; + script_disp->persistent_code_list->ref++; + *ret = script_disp; return S_OK; } diff --git a/dlls/vbscript/vbscript.c b/dlls/vbscript/vbscript.c index 9d20433..6c04781 100644 --- a/dlls/vbscript/vbscript.c +++ b/dlls/vbscript/vbscript.c @@ -170,7 +170,7 @@ static void exec_queued_code(script_ctx_t *ctx) { vbscode_t *iter;
- LIST_FOR_EACH_ENTRY(iter, &ctx->code_list, vbscode_t, entry) { + LIST_FOR_EACH_ENTRY(iter, &ctx->code_list->list, vbscode_t, entry) { if(iter->pending_exec) exec_global_code(ctx, iter, NULL); } @@ -215,17 +215,20 @@ static void release_script(script_ctx_t *ctx) collect_objects(ctx); clear_ei(&ctx->ei);
- LIST_FOR_EACH_ENTRY_SAFE(code, code_next, &ctx->code_list, vbscode_t, entry) + if(ctx->code_list) { - if(code->is_persistent) + LIST_FOR_EACH_ENTRY_SAFE(code, code_next, &ctx->code_list->list, vbscode_t, entry) { - code->pending_exec = TRUE; - if(code->last_class) code->last_class->next = NULL; - } - else - { - list_remove(&code->entry); - list_add_tail(&ctx->script_obj->code_list, &code->entry); + if(code->is_persistent) + { + code->pending_exec = TRUE; + if(code->last_class) code->last_class->next = NULL; + } + else + { + list_remove(&code->entry); + list_add_tail(&ctx->script_obj->code_list, &code->entry); + } } }
@@ -263,10 +266,25 @@ static void release_script(script_ctx_t *ctx) } }
-static void release_code_list(script_ctx_t *ctx) +static struct ref_list *alloc_code_list(void) { - while(!list_empty(&ctx->code_list)) - release_vbscode(LIST_ENTRY(list_head(&ctx->code_list), vbscode_t, entry)); + struct ref_list *ret = heap_alloc(sizeof(*ret)); + + if(ret) { + ret->ref = 1; + list_init(&ret->list); + } + return ret; +} + +void release_code_list(struct ref_list *code_list) +{ + if(!code_list || --code_list->ref) + return; + + while(!list_empty(&code_list->list)) + release_vbscode(LIST_ENTRY(list_head(&code_list->list), vbscode_t, entry)); + heap_free(code_list); }
static void decrease_state(VBScript *This, SCRIPTSTATE state) @@ -288,8 +306,10 @@ static void decrease_state(VBScript *This, SCRIPTSTATE state) break; release_script(This->ctx); This->thread_id = 0; - if(state == SCRIPTSTATE_CLOSED) - release_code_list(This->ctx); + if(state == SCRIPTSTATE_CLOSED) { + release_code_list(This->ctx->code_list); + This->ctx->code_list = NULL; + } break; case SCRIPTSTATE_CLOSED: break; @@ -490,6 +510,9 @@ static HRESULT WINAPI VBScript_SetScriptSite(IActiveScript *iface, IActiveScript if(InterlockedCompareExchange(&This->thread_id, GetCurrentThreadId(), 0)) return E_UNEXPECTED;
+ if(!This->ctx->code_list && !(This->ctx->code_list = alloc_code_list())) + return E_OUTOFMEMORY; + hres = create_script_disp(This->ctx, &This->ctx->script_obj); if(FAILED(hres)) return hres; @@ -1035,7 +1058,6 @@ HRESULT WINAPI VBScriptFactory_CreateInstance(IClassFactory *iface, IUnknown *pU
ctx->safeopt = INTERFACE_USES_DISPEX; list_init(&ctx->objects); - list_init(&ctx->code_list); list_init(&ctx->named_items);
hres = init_global(ctx); diff --git a/dlls/vbscript/vbscript.h b/dlls/vbscript/vbscript.h index 58db0b5..ceca069 100644 --- a/dlls/vbscript/vbscript.h +++ b/dlls/vbscript/vbscript.h @@ -128,6 +128,11 @@ typedef struct _dynamic_var_t { SAFEARRAY *array; } dynamic_var_t;
+struct ref_list { + struct list list; + LONG ref; +}; + typedef struct { IDispatchEx IDispatchEx_iface; LONG ref; @@ -147,6 +152,7 @@ typedef struct { heap_pool_t heap;
struct list code_list; + struct ref_list *persistent_code_list; } ScriptDisp;
typedef struct _builtin_prop_t builtin_prop_t; @@ -197,8 +203,8 @@ struct _script_ctx_t { EXCEPINFO ei;
struct list objects; - struct list code_list; struct list named_items; + struct ref_list *code_list; };
HRESULT init_global(script_ctx_t*) DECLSPEC_HIDDEN; @@ -358,6 +364,7 @@ struct _vbscode_t { struct list entry; };
+void release_code_list(struct ref_list*) DECLSPEC_HIDDEN; void release_vbscode(vbscode_t*) DECLSPEC_HIDDEN; HRESULT compile_script(script_ctx_t*,const WCHAR*,const WCHAR*,DWORD,vbscode_t**) DECLSPEC_HIDDEN; HRESULT compile_procedure(script_ctx_t*,const WCHAR*,const WCHAR*,DWORD,class_desc_t**) DECLSPEC_HIDDEN;
Hi Gabriel,
On 11/13/19 4:24 PM, Gabriel Ivăncescu wrote:
Signed-off-by: Gabriel Ivăncescugabrielopcode@gmail.com
This is needed for the TypeInfo since it needs to hold a ref to the persistent code, too. Though we keep the ref in the script dispatch since it's more correct this way (even though we bail out when there's no context, we still technically reference the persistent code funcs/classes in the dispatch object).
I couldn't refcount the script context itself since it is re-used after being closed, and was not deemed a good approach to free it (my previous attempts).
It doesn't look pretty, but also I think it's not enough for what you need. What about non-persistent code? Unless I'm missing something, this will be exposed from ITypeInfo as well, but freed when script is uninitialized, so we will crash on an attempt to access it. An alternative idea would be to add a reference count to vbscode_t itself. It could be referenced by each entry in global variables and functions arrays as well as from ITypeInfo implementation. How does that sound?
Thanks,
Jacek
On 11/13/19 11:53 PM, Jacek Caban wrote:
Hi Gabriel,
On 11/13/19 4:24 PM, Gabriel Ivăncescu wrote:
Signed-off-by: Gabriel Ivăncescugabrielopcode@gmail.com
This is needed for the TypeInfo since it needs to hold a ref to the persistent code, too. Though we keep the ref in the script dispatch since it's more correct this way (even though we bail out when there's no context, we still technically reference the persistent code funcs/classes in the dispatch object).
I couldn't refcount the script context itself since it is re-used after being closed, and was not deemed a good approach to free it (my previous attempts).
It doesn't look pretty, but also I think it's not enough for what you need. What about non-persistent code? Unless I'm missing something, this will be exposed from ITypeInfo as well, but freed when script is uninitialized, so we will crash on an attempt to access it. An alternative idea would be to add a reference count to vbscode_t itself. It could be referenced by each entry in global variables and functions arrays as well as from ITypeInfo implementation. How does that sound?
Thanks,
Jacek
The non-persistent code gets moved to the script dispatch when it is released, so it shouldn't be an issue, because the TypeInfo keeps a reference to it, so the script dispatch itself won't be freed when the script gets released in this particular case.
Refcounting the vbscode itself is possible but I think it will be more complicated though. We'll also have to loop through all variables/functions to add a ref to them when creating the TypeInfo (currently we don't even store the vars list at all since we read it directly from the script dispatch).
I think this is the simplest approach, still. (ref counting the persistent code list)
Thanks, Gabriel
I had some time to look at this in more depth. I believe that we can simplify it down to just add a ref to the code for each var and function during exec_global_code. Meaning, the script dispatch itself will hold the refs, not the typeinfo.
Then during the release of the script dispatch, we release the references, since we already go through the variables anyway to release their contents.
We'll have to add a loop to go through each function to release the code it references, though, but it shouldn't be much of a problem.
Do you think I should pursue this approach instead?
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com ---
This initial patch series will implement some of the dynamic TypeInfo for the script's dispatch, that inherits from IDispatch. Implementing the TypeInfo is necessary even for Wine's own msscript.ocx (for example, to implement the Procedures property with tests) or to have native msscript work properly.
dlls/vbscript/vbdisp.c | 270 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 268 insertions(+), 2 deletions(-)
diff --git a/dlls/vbscript/vbdisp.c b/dlls/vbscript/vbdisp.c index e6a2552..644665a 100644 --- a/dlls/vbscript/vbdisp.c +++ b/dlls/vbscript/vbdisp.c @@ -527,6 +527,268 @@ HRESULT create_vbdisp(const class_desc_t *desc, vbdisp_t **ret) return S_OK; }
+typedef struct { + ITypeInfo ITypeInfo_iface; + LONG ref; +} ScriptTypeInfo; + +static inline ScriptTypeInfo *ScriptTypeInfo_from_ITypeInfo(ITypeInfo *iface) +{ + return CONTAINING_RECORD(iface, ScriptTypeInfo, ITypeInfo_iface); +} + +static HRESULT WINAPI ScriptTypeInfo_QueryInterface(ITypeInfo *iface, REFIID riid, void **ppv) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + + if (IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_ITypeInfo, riid)) + *ppv = &This->ITypeInfo_iface; + else + { + WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv); + *ppv = NULL; + return E_NOINTERFACE; + } + + TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv); + IUnknown_AddRef((IUnknown*)*ppv); + return S_OK; +} + +static ULONG WINAPI ScriptTypeInfo_AddRef(ITypeInfo *iface) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + LONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p) ref=%d\n", This, ref); + + return ref; +} + +static ULONG WINAPI ScriptTypeInfo_Release(ITypeInfo *iface) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + LONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p) ref=%d\n", This, ref); + + if (!ref) + { + heap_free(This); + } + return ref; +} + +static HRESULT WINAPI ScriptTypeInfo_GetTypeAttr(ITypeInfo *iface, TYPEATTR **ppTypeAttr) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + + FIXME("(%p)->(%p)\n", This, ppTypeAttr); + + return E_NOTIMPL; +} + +static HRESULT WINAPI ScriptTypeInfo_GetTypeComp(ITypeInfo *iface, ITypeComp **ppTComp) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + + FIXME("(%p)->(%p)\n", This, ppTComp); + + return E_NOTIMPL; +} + +static HRESULT WINAPI ScriptTypeInfo_GetFuncDesc(ITypeInfo *iface, UINT index, FUNCDESC **ppFuncDesc) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + + FIXME("(%p)->(%u %p)\n", This, index, ppFuncDesc); + + return E_NOTIMPL; +} + +static HRESULT WINAPI ScriptTypeInfo_GetVarDesc(ITypeInfo *iface, UINT index, VARDESC **ppVarDesc) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + + FIXME("(%p)->(%u %p)\n", This, index, ppVarDesc); + + return E_NOTIMPL; +} + +static HRESULT WINAPI ScriptTypeInfo_GetNames(ITypeInfo *iface, MEMBERID memid, BSTR *rgBstrNames, + UINT cMaxNames, UINT *pcNames) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + + FIXME("(%p)->(%d %p %u %p)\n", This, memid, rgBstrNames, cMaxNames, pcNames); + + return E_NOTIMPL; +} + +static HRESULT WINAPI ScriptTypeInfo_GetRefTypeOfImplType(ITypeInfo *iface, UINT index, HREFTYPE *pRefType) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + + FIXME("(%p)->(%u %p)\n", This, index, pRefType); + + return E_NOTIMPL; +} + +static HRESULT WINAPI ScriptTypeInfo_GetImplTypeFlags(ITypeInfo *iface, UINT index, INT *pImplTypeFlags) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + + FIXME("(%p)->(%u %p)\n", This, index, pImplTypeFlags); + + return E_NOTIMPL; +} + +static HRESULT WINAPI ScriptTypeInfo_GetIDsOfNames(ITypeInfo *iface, LPOLESTR *rgszNames, UINT cNames, + MEMBERID *pMemId) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + + FIXME("(%p)->(%p %u %p)\n", This, rgszNames, cNames, pMemId); + + return E_NOTIMPL; +} + +static HRESULT WINAPI ScriptTypeInfo_Invoke(ITypeInfo *iface, PVOID pvInstance, MEMBERID memid, WORD wFlags, + DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + + FIXME("(%p)->(%p %d %d %p %p %p %p)\n", This, pvInstance, memid, wFlags, + pDispParams, pVarResult, pExcepInfo, puArgErr); + + return E_NOTIMPL; +} + +static HRESULT WINAPI ScriptTypeInfo_GetDocumentation(ITypeInfo *iface, MEMBERID memid, BSTR *pBstrName, + BSTR *pBstrDocString, DWORD *pdwHelpContext, BSTR *pBstrHelpFile) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + + FIXME("(%p)->(%d %p %p %p %p)\n", This, memid, pBstrName, pBstrDocString, pdwHelpContext, pBstrHelpFile); + + return E_NOTIMPL; +} + +static HRESULT WINAPI ScriptTypeInfo_GetDllEntry(ITypeInfo *iface, MEMBERID memid, INVOKEKIND invKind, + BSTR *pBstrDllName, BSTR *pBstrName, WORD *pwOrdinal) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + + FIXME("(%p)->(%d %d %p %p %p)\n", This, memid, invKind, pBstrDllName, pBstrName, pwOrdinal); + + return E_NOTIMPL; +} + +static HRESULT WINAPI ScriptTypeInfo_GetRefTypeInfo(ITypeInfo *iface, HREFTYPE hRefType, ITypeInfo **ppTInfo) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + + FIXME("(%p)->(%x %p)\n", This, hRefType, ppTInfo); + + return E_NOTIMPL; +} + +static HRESULT WINAPI ScriptTypeInfo_AddressOfMember(ITypeInfo *iface, MEMBERID memid, INVOKEKIND invKind, PVOID *ppv) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + + FIXME("(%p)->(%d %d %p)\n", This, memid, invKind, ppv); + + return E_NOTIMPL; +} + +static HRESULT WINAPI ScriptTypeInfo_CreateInstance(ITypeInfo *iface, IUnknown *pUnkOuter, REFIID riid, PVOID *ppvObj) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + + FIXME("(%p)->(%p %s %p)\n", This, pUnkOuter, debugstr_guid(riid), ppvObj); + + return E_NOTIMPL; +} + +static HRESULT WINAPI ScriptTypeInfo_GetMops(ITypeInfo *iface, MEMBERID memid, BSTR *pBstrMops) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + + FIXME("(%p)->(%d %p)\n", This, memid, pBstrMops); + + return E_NOTIMPL; +} + +static HRESULT WINAPI ScriptTypeInfo_GetContainingTypeLib(ITypeInfo *iface, ITypeLib **ppTLib, UINT *pIndex) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + + FIXME("(%p)->(%p %p)\n", This, ppTLib, pIndex); + + return E_NOTIMPL; +} + +static void WINAPI ScriptTypeInfo_ReleaseTypeAttr(ITypeInfo *iface, TYPEATTR *pTypeAttr) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + + FIXME("(%p)->(%p)\n", This, pTypeAttr); +} + +static void WINAPI ScriptTypeInfo_ReleaseFuncDesc(ITypeInfo *iface, FUNCDESC *pFuncDesc) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + + FIXME("(%p)->(%p)\n", This, pFuncDesc); +} + +static void WINAPI ScriptTypeInfo_ReleaseVarDesc(ITypeInfo *iface, VARDESC *pVarDesc) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + + FIXME("(%p)->(%p)\n", This, pVarDesc); +} + +static const ITypeInfoVtbl ScriptTypeInfoVtbl = { + ScriptTypeInfo_QueryInterface, + ScriptTypeInfo_AddRef, + ScriptTypeInfo_Release, + ScriptTypeInfo_GetTypeAttr, + ScriptTypeInfo_GetTypeComp, + ScriptTypeInfo_GetFuncDesc, + ScriptTypeInfo_GetVarDesc, + ScriptTypeInfo_GetNames, + ScriptTypeInfo_GetRefTypeOfImplType, + ScriptTypeInfo_GetImplTypeFlags, + ScriptTypeInfo_GetIDsOfNames, + ScriptTypeInfo_Invoke, + ScriptTypeInfo_GetDocumentation, + ScriptTypeInfo_GetDllEntry, + ScriptTypeInfo_GetRefTypeInfo, + ScriptTypeInfo_AddressOfMember, + ScriptTypeInfo_CreateInstance, + ScriptTypeInfo_GetMops, + ScriptTypeInfo_GetContainingTypeLib, + ScriptTypeInfo_ReleaseTypeAttr, + ScriptTypeInfo_ReleaseFuncDesc, + ScriptTypeInfo_ReleaseVarDesc +}; + +static HRESULT create_script_typeinfo(ScriptDisp *disp, ITypeInfo **typeinfo) +{ + ScriptTypeInfo *p; + + if (!(p = heap_alloc(sizeof(*p)))) + return E_OUTOFMEMORY; + + p->ITypeInfo_iface.lpVtbl = &ScriptTypeInfoVtbl; + p->ref = 1; + + *typeinfo = &p->ITypeInfo_iface; + return S_OK; +} + static inline ScriptDisp *ScriptDisp_from_IDispatchEx(IDispatchEx *iface) { return CONTAINING_RECORD(iface, ScriptDisp, IDispatchEx_iface); @@ -613,8 +875,12 @@ static HRESULT WINAPI ScriptDisp_GetTypeInfo(IDispatchEx *iface, UINT iTInfo, LC ITypeInfo **ppTInfo) { ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface); - FIXME("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo); - return E_NOTIMPL; + + TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo); + + if (iTInfo != 0) return DISP_E_BADINDEX; + + return create_script_typeinfo(This, ppTInfo); }
static HRESULT WINAPI ScriptDisp_GetIDsOfNames(IDispatchEx *iface, REFIID riid,
The TypeInfo is built when it is retrieved and frozen at that moment, even if the script changes after that and more identifiers are added to it.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com ---
This builds most of the necessary information for subsequent patches.
dlls/vbscript/vbdisp.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+)
diff --git a/dlls/vbscript/vbdisp.c b/dlls/vbscript/vbdisp.c index 644665a..09dda25 100644 --- a/dlls/vbscript/vbdisp.c +++ b/dlls/vbscript/vbdisp.c @@ -530,6 +530,12 @@ HRESULT create_vbdisp(const class_desc_t *desc, vbdisp_t **ret) typedef struct { ITypeInfo ITypeInfo_iface; LONG ref; + + UINT num_vars; + UINT num_funcs; + UINT *func_ids; + + ScriptDisp *disp; } ScriptTypeInfo;
static inline ScriptTypeInfo *ScriptTypeInfo_from_ITypeInfo(ITypeInfo *iface) @@ -574,6 +580,8 @@ static ULONG WINAPI ScriptTypeInfo_Release(ITypeInfo *iface)
if (!ref) { + IDispatchEx_Release(&This->disp->IDispatchEx_iface); + heap_free(This->func_ids); heap_free(This); } return ref; @@ -777,13 +785,35 @@ static const ITypeInfoVtbl ScriptTypeInfoVtbl = {
static HRESULT create_script_typeinfo(ScriptDisp *disp, ITypeInfo **typeinfo) { + UINT num_funcs = 0; ScriptTypeInfo *p; + unsigned i, j;
if (!(p = heap_alloc(sizeof(*p)))) return E_OUTOFMEMORY;
+ for (i = 0; i < disp->global_funcs_cnt; i++) + if (disp->global_funcs[i]->is_public) + num_funcs++; + p->ITypeInfo_iface.lpVtbl = &ScriptTypeInfoVtbl; p->ref = 1; + p->num_funcs = num_funcs; + p->num_vars = disp->global_vars_cnt; + p->disp = disp; + + p->func_ids = heap_alloc(sizeof(*p->func_ids) * num_funcs); + if (!p->func_ids) + { + heap_free(p); + return E_OUTOFMEMORY; + } + + for (j = 0, i = 0; i < disp->global_funcs_cnt; i++) + if (disp->global_funcs[i]->is_public) + p->func_ids[j++] = i; + + IDispatchEx_AddRef(&disp->IDispatchEx_iface);
*typeinfo = &p->ITypeInfo_iface; return S_OK;
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/vbscript/vbdisp.c | 37 ++++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-)
diff --git a/dlls/vbscript/vbdisp.c b/dlls/vbscript/vbdisp.c index 09dda25..40d2c12 100644 --- a/dlls/vbscript/vbdisp.c +++ b/dlls/vbscript/vbdisp.c @@ -19,11 +19,14 @@ #include <assert.h>
#include "vbscript.h" +#include "initguid.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(vbscript);
+DEFINE_GUID(IID_IScriptTypeInfo, 0xc59c6b12, 0xf6c1, 0x11cf, 0x88,0x35, 0x00,0xa0,0xc9,0x11,0xe8,0xb2); + #define DISPID_FUNCTION_MASK 0x20000000 #define FDEX_VERSION_MASK 0xf0000000
@@ -590,10 +593,32 @@ static ULONG WINAPI ScriptTypeInfo_Release(ITypeInfo *iface) static HRESULT WINAPI ScriptTypeInfo_GetTypeAttr(ITypeInfo *iface, TYPEATTR **ppTypeAttr) { ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); - - FIXME("(%p)->(%p)\n", This, ppTypeAttr); - - return E_NOTIMPL; + TYPEATTR *p; + + TRACE("(%p)->(%p)\n", This, ppTypeAttr); + + if (!ppTypeAttr) return E_INVALIDARG; + + p = heap_alloc_zero(sizeof(*p)); + if (!p) return E_OUTOFMEMORY; + + p->guid = IID_IScriptTypeInfo; + p->lcid = LOCALE_USER_DEFAULT; + p->memidConstructor = MEMBERID_NIL; + p->memidDestructor = MEMBERID_NIL; + p->cbSizeInstance = 4; + p->typekind = TKIND_DISPATCH; + p->cFuncs = This->num_funcs; + p->cVars = This->num_vars; + p->cImplTypes = 1; + p->cbSizeVft = 7 * sizeof(void*); + p->cbAlignment = 4; + p->wTypeFlags = TYPEFLAG_FDISPATCHABLE; + p->wMajorVerNum = VBSCRIPT_MAJOR_VERSION; + p->wMinorVerNum = VBSCRIPT_MINOR_VERSION; + + *ppTypeAttr = p; + return S_OK; }
static HRESULT WINAPI ScriptTypeInfo_GetTypeComp(ITypeInfo *iface, ITypeComp **ppTComp) @@ -741,7 +766,9 @@ static void WINAPI ScriptTypeInfo_ReleaseTypeAttr(ITypeInfo *iface, TYPEATTR *pT { ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
- FIXME("(%p)->(%p)\n", This, pTypeAttr); + TRACE("(%p)->(%p)\n", This, pTypeAttr); + + heap_free(pTypeAttr); }
static void WINAPI ScriptTypeInfo_ReleaseFuncDesc(ITypeInfo *iface, FUNCDESC *pFuncDesc)
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/vbscript/vbdisp.c | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-)
diff --git a/dlls/vbscript/vbdisp.c b/dlls/vbscript/vbdisp.c index 40d2c12..bfe70d6 100644 --- a/dlls/vbscript/vbdisp.c +++ b/dlls/vbscript/vbdisp.c @@ -633,10 +633,33 @@ static HRESULT WINAPI ScriptTypeInfo_GetTypeComp(ITypeInfo *iface, ITypeComp **p static HRESULT WINAPI ScriptTypeInfo_GetFuncDesc(ITypeInfo *iface, UINT index, FUNCDESC **ppFuncDesc) { ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + function_t *func; + FUNCDESC *p; + UINT i;
- FIXME("(%p)->(%u %p)\n", This, index, ppFuncDesc); + TRACE("(%p)->(%u %p)\n", This, index, ppFuncDesc);
- return E_NOTIMPL; + if (!ppFuncDesc) return E_INVALIDARG; + if (index >= This->num_funcs) return TYPE_E_ELEMENTNOTFOUND; + func = This->disp->global_funcs[This->func_ids[index]]; + + /* Store the parameter array after the FUNCDESC structure */ + p = heap_alloc_zero(sizeof(*p) + sizeof(ELEMDESC) * func->arg_cnt); + if (!p) return E_OUTOFMEMORY; + + p->memid = This->func_ids[index] + 1 + DISPID_FUNCTION_MASK; + p->funckind = FUNC_DISPATCH; + p->invkind = INVOKE_FUNC; + p->callconv = CC_STDCALL; + p->cParams = func->arg_cnt; + p->elemdescFunc.tdesc.vt = (func->type == FUNC_SUB) ? VT_VOID : VT_VARIANT; + + if (func->arg_cnt) p->lprgelemdescParam = (ELEMDESC*)(p + 1); + for (i = 0; i < func->arg_cnt; i++) + p->lprgelemdescParam[i].tdesc.vt = VT_VARIANT; + + *ppFuncDesc = p; + return S_OK; }
static HRESULT WINAPI ScriptTypeInfo_GetVarDesc(ITypeInfo *iface, UINT index, VARDESC **ppVarDesc) @@ -775,7 +798,9 @@ static void WINAPI ScriptTypeInfo_ReleaseFuncDesc(ITypeInfo *iface, FUNCDESC *pF { ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
- FIXME("(%p)->(%p)\n", This, pFuncDesc); + TRACE("(%p)->(%p)\n", This, pFuncDesc); + + heap_free(pFuncDesc); }
static void WINAPI ScriptTypeInfo_ReleaseVarDesc(ITypeInfo *iface, VARDESC *pVarDesc)
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/vbscript/vbdisp.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-)
diff --git a/dlls/vbscript/vbdisp.c b/dlls/vbscript/vbdisp.c index bfe70d6..d14ce5b 100644 --- a/dlls/vbscript/vbdisp.c +++ b/dlls/vbscript/vbdisp.c @@ -665,10 +665,22 @@ static HRESULT WINAPI ScriptTypeInfo_GetFuncDesc(ITypeInfo *iface, UINT index, F static HRESULT WINAPI ScriptTypeInfo_GetVarDesc(ITypeInfo *iface, UINT index, VARDESC **ppVarDesc) { ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + VARDESC *p;
- FIXME("(%p)->(%u %p)\n", This, index, ppVarDesc); + TRACE("(%p)->(%u %p)\n", This, index, ppVarDesc);
- return E_NOTIMPL; + if (!ppVarDesc) return E_INVALIDARG; + if (index >= This->num_vars) return TYPE_E_ELEMENTNOTFOUND; + + p = heap_alloc_zero(sizeof(*p)); + if (!p) return E_OUTOFMEMORY; + + p->memid = index + 1; + p->varkind = VAR_DISPATCH; + p->elemdescVar.tdesc.vt = VT_VARIANT; + + *ppVarDesc = p; + return S_OK; }
static HRESULT WINAPI ScriptTypeInfo_GetNames(ITypeInfo *iface, MEMBERID memid, BSTR *rgBstrNames, @@ -807,7 +819,9 @@ static void WINAPI ScriptTypeInfo_ReleaseVarDesc(ITypeInfo *iface, VARDESC *pVar { ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
- FIXME("(%p)->(%p)\n", This, pVarDesc); + TRACE("(%p)->(%p)\n", This, pVarDesc); + + heap_free(pVarDesc); }
static const ITypeInfoVtbl ScriptTypeInfoVtbl = {
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com ---
It's not really feasible to use the script dispatch's GetIDsOfNames since the TypeInfo can have a limited amount of variables/functions compared to the script dispatch (and also inherits from IDispatch, which has to look into as well).
The logic of this has been taken from the generic TypeLib implementation. Tests at the end of the series are added to verify its behavior, anyway.
dlls/vbscript/vbdisp.c | 44 +++++++++++++++++++++++++++++++++-- dlls/vbscript/vbscript.h | 1 + dlls/vbscript/vbscript_main.c | 25 ++++++++++++++++++++ 3 files changed, 68 insertions(+), 2 deletions(-)
diff --git a/dlls/vbscript/vbdisp.c b/dlls/vbscript/vbdisp.c index d14ce5b..6f94dca 100644 --- a/dlls/vbscript/vbdisp.c +++ b/dlls/vbscript/vbdisp.c @@ -715,10 +715,50 @@ static HRESULT WINAPI ScriptTypeInfo_GetIDsOfNames(ITypeInfo *iface, LPOLESTR *r MEMBERID *pMemId) { ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + const WCHAR *name; + HRESULT hr = S_OK; + int i, j, arg;
- FIXME("(%p)->(%p %u %p)\n", This, rgszNames, cNames, pMemId); + TRACE("(%p)->(%p %u %p)\n", This, rgszNames, cNames, pMemId);
- return E_NOTIMPL; + if (!rgszNames || !cNames || !pMemId) return E_INVALIDARG; + + for (i = 0; i < cNames; i++) pMemId[i] = MEMBERID_NIL; + name = rgszNames[0]; + + for (i = 0; i < This->num_funcs; i++) + { + function_t *func = This->disp->global_funcs[This->func_ids[i]]; + + if (wcsicmp(name, func->name)) continue; + pMemId[0] = This->func_ids[i] + 1 + DISPID_FUNCTION_MASK; + + for (j = 1; j < cNames; j++) + { + name = rgszNames[j]; + for (arg = func->arg_cnt; --arg >= 0;) + if (!wcsicmp(name, func->args[arg].name)) + break; + if (arg >= 0) + pMemId[j] = arg; + else + hr = DISP_E_UNKNOWNNAME; + } + return hr; + } + + for (i = 0; i < This->num_vars; i++) + { + if (wcsicmp(name, This->disp->global_vars[i]->name)) continue; + pMemId[0] = i + 1; + return S_OK; + } + + /* Look into the inherited IDispatch */ + hr = get_IDispatch_typeinfo(&iface); + if (FAILED(hr)) return hr; + + return ITypeInfo_GetIDsOfNames(iface, rgszNames, cNames, pMemId); }
static HRESULT WINAPI ScriptTypeInfo_Invoke(ITypeInfo *iface, PVOID pvInstance, MEMBERID memid, WORD wFlags, diff --git a/dlls/vbscript/vbscript.h b/dlls/vbscript/vbscript.h index ceca069..5b4156b 100644 --- a/dlls/vbscript/vbscript.h +++ b/dlls/vbscript/vbscript.h @@ -377,6 +377,7 @@ void detach_global_objects(script_ctx_t*) DECLSPEC_HIDDEN; HRESULT get_builtin_id(BuiltinDisp*,const WCHAR*,DISPID*) DECLSPEC_HIDDEN;
void release_regexp_typelib(void) DECLSPEC_HIDDEN; +HRESULT get_IDispatch_typeinfo(ITypeInfo**) DECLSPEC_HIDDEN;
static inline BOOL is_int32(double d) { diff --git a/dlls/vbscript/vbscript_main.c b/dlls/vbscript/vbscript_main.c index 6e6f386..8c05d53 100644 --- a/dlls/vbscript/vbscript_main.c +++ b/dlls/vbscript/vbscript_main.c @@ -34,6 +34,7 @@ WINE_DECLARE_DEBUG_CHANNEL(heap); DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
static HINSTANCE vbscript_hinstance; +static ITypeInfo *IDispatch_typeinfo;
BSTR get_vbscript_string(int id) { @@ -180,6 +181,29 @@ heap_pool_t *heap_pool_mark(heap_pool_t *heap) return heap; }
+HRESULT get_IDispatch_typeinfo(ITypeInfo **out) +{ + ITypeInfo *typeinfo; + ITypeLib *typelib; + HRESULT hr; + + if (!IDispatch_typeinfo) + { + hr = LoadRegTypeLib(&IID_StdOle, STDOLE_MAJORVERNUM, STDOLE_MINORVERNUM, STDOLE_LCID, &typelib); + if (FAILED(hr)) return hr; + + hr = ITypeLib_GetTypeInfoOfGuid(typelib, &IID_IDispatch, &typeinfo); + ITypeLib_Release(typelib); + if (FAILED(hr)) return hr; + + if (InterlockedCompareExchangePointer((void**)(&IDispatch_typeinfo), typeinfo, NULL)) + ITypeInfo_Release(typeinfo); + } + + *out = IDispatch_typeinfo; + return S_OK; +} + static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID riid, void **ppv) { *ppv = NULL; @@ -256,6 +280,7 @@ BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv) break; case DLL_PROCESS_DETACH: if (lpv) break; + if (IDispatch_typeinfo) ITypeInfo_Release(IDispatch_typeinfo); release_regexp_typelib(); }
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/vbscript/vbdisp.c | 124 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 122 insertions(+), 2 deletions(-)
diff --git a/dlls/vbscript/vbdisp.c b/dlls/vbscript/vbdisp.c index 6f94dca..1b61c33 100644 --- a/dlls/vbscript/vbdisp.c +++ b/dlls/vbscript/vbdisp.c @@ -532,6 +532,7 @@ HRESULT create_vbdisp(const class_desc_t *desc, vbdisp_t **ret)
typedef struct { ITypeInfo ITypeInfo_iface; + ITypeComp ITypeComp_iface; LONG ref;
UINT num_vars; @@ -546,12 +547,19 @@ static inline ScriptTypeInfo *ScriptTypeInfo_from_ITypeInfo(ITypeInfo *iface) return CONTAINING_RECORD(iface, ScriptTypeInfo, ITypeInfo_iface); }
+static inline ScriptTypeInfo *ScriptTypeInfo_from_ITypeComp(ITypeComp *iface) +{ + return CONTAINING_RECORD(iface, ScriptTypeInfo, ITypeComp_iface); +} + static HRESULT WINAPI ScriptTypeInfo_QueryInterface(ITypeInfo *iface, REFIID riid, void **ppv) { ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
if (IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_ITypeInfo, riid)) *ppv = &This->ITypeInfo_iface; + else if (IsEqualGUID(&IID_ITypeComp, riid)) + *ppv = &This->ITypeComp_iface; else { WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv); @@ -625,9 +633,13 @@ static HRESULT WINAPI ScriptTypeInfo_GetTypeComp(ITypeInfo *iface, ITypeComp **p { ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
- FIXME("(%p)->(%p)\n", This, ppTComp); + TRACE("(%p)->(%p)\n", This, ppTComp);
- return E_NOTIMPL; + if (!ppTComp) return E_INVALIDARG; + + *ppTComp = &This->ITypeComp_iface; + ITypeInfo_AddRef(iface); + return S_OK; }
static HRESULT WINAPI ScriptTypeInfo_GetFuncDesc(ITypeInfo *iface, UINT index, FUNCDESC **ppFuncDesc) @@ -889,6 +901,113 @@ static const ITypeInfoVtbl ScriptTypeInfoVtbl = { ScriptTypeInfo_ReleaseVarDesc };
+static HRESULT WINAPI ScriptTypeComp_QueryInterface(ITypeComp *iface, REFIID riid, void **ppv) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeComp(iface); + return ITypeInfo_QueryInterface(&This->ITypeInfo_iface, riid, ppv); +} + +static ULONG WINAPI ScriptTypeComp_AddRef(ITypeComp *iface) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeComp(iface); + return ITypeInfo_AddRef(&This->ITypeInfo_iface); +} + +static ULONG WINAPI ScriptTypeComp_Release(ITypeComp *iface) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeComp(iface); + return ITypeInfo_Release(&This->ITypeInfo_iface); +} + +static HRESULT WINAPI ScriptTypeComp_Bind(ITypeComp *iface, LPOLESTR szName, ULONG lHashVal, WORD wFlags, + ITypeInfo **ppTInfo, DESCKIND *pDescKind, BINDPTR *pBindPtr) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeComp(iface); + UINT flags = wFlags ? wFlags : ~0; + ITypeInfo *typeinfo; + ITypeComp *typecomp; + HRESULT hr; + UINT i; + + TRACE("(%p)->(%s %08x %d %p %p %p)\n", This, debugstr_w(szName), lHashVal, + wFlags, ppTInfo, pDescKind, pBindPtr); + + if (!szName || !ppTInfo || !pDescKind || !pBindPtr) + return E_INVALIDARG; + + for (i = 0; i < This->num_funcs; i++) + { + if (wcsicmp(szName, This->disp->global_funcs[This->func_ids[i]]->name)) continue; + if (!(flags & INVOKE_FUNC)) return TYPE_E_TYPEMISMATCH; + + hr = ITypeInfo_GetFuncDesc(&This->ITypeInfo_iface, i, &pBindPtr->lpfuncdesc); + if (FAILED(hr)) return hr; + + *pDescKind = DESCKIND_FUNCDESC; + *ppTInfo = &This->ITypeInfo_iface; + ITypeInfo_AddRef(*ppTInfo); + return S_OK; + } + + for (i = 0; i < This->num_vars; i++) + { + if (wcsicmp(szName, This->disp->global_vars[i]->name)) continue; + if (!(flags & INVOKE_PROPERTYGET)) return TYPE_E_TYPEMISMATCH; + + hr = ITypeInfo_GetVarDesc(&This->ITypeInfo_iface, i, &pBindPtr->lpvardesc); + if (FAILED(hr)) return hr; + + *pDescKind = DESCKIND_VARDESC; + *ppTInfo = &This->ITypeInfo_iface; + ITypeInfo_AddRef(*ppTInfo); + return S_OK; + } + + /* Look into the inherited IDispatch */ + hr = get_IDispatch_typeinfo(&typeinfo); + if (FAILED(hr)) return hr; + + hr = ITypeInfo_GetTypeComp(typeinfo, &typecomp); + if (FAILED(hr)) return hr; + + hr = ITypeComp_Bind(typecomp, szName, lHashVal, wFlags, ppTInfo, pDescKind, pBindPtr); + ITypeComp_Release(typecomp); + return hr; +} + +static HRESULT WINAPI ScriptTypeComp_BindType(ITypeComp *iface, LPOLESTR szName, ULONG lHashVal, + ITypeInfo **ppTInfo, ITypeComp **ppTComp) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeComp(iface); + ITypeInfo *typeinfo; + ITypeComp *typecomp; + HRESULT hr; + + TRACE("(%p)->(%s %08x %p %p)\n", This, debugstr_w(szName), lHashVal, ppTInfo, ppTComp); + + if (!szName || !ppTInfo || !ppTComp) + return E_INVALIDARG; + + /* Look into the inherited IDispatch */ + hr = get_IDispatch_typeinfo(&typeinfo); + if (FAILED(hr)) return hr; + + hr = ITypeInfo_GetTypeComp(typeinfo, &typecomp); + if (FAILED(hr)) return hr; + + hr = ITypeComp_BindType(typecomp, szName, lHashVal, ppTInfo, ppTComp); + ITypeComp_Release(typecomp); + return hr; +} + +static const ITypeCompVtbl ScriptTypeCompVtbl = { + ScriptTypeComp_QueryInterface, + ScriptTypeComp_AddRef, + ScriptTypeComp_Release, + ScriptTypeComp_Bind, + ScriptTypeComp_BindType +}; + static HRESULT create_script_typeinfo(ScriptDisp *disp, ITypeInfo **typeinfo) { UINT num_funcs = 0; @@ -903,6 +1022,7 @@ static HRESULT create_script_typeinfo(ScriptDisp *disp, ITypeInfo **typeinfo) num_funcs++;
p->ITypeInfo_iface.lpVtbl = &ScriptTypeInfoVtbl; + p->ITypeComp_iface.lpVtbl = &ScriptTypeCompVtbl; p->ref = 1; p->num_funcs = num_funcs; p->num_vars = disp->global_vars_cnt;
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/vbscript/tests/vbscript.c | 326 +++++++++++++++++++++++++++++++++ 1 file changed, 326 insertions(+)
diff --git a/dlls/vbscript/tests/vbscript.c b/dlls/vbscript/tests/vbscript.c index b41d677..a19721d 100644 --- a/dlls/vbscript/tests/vbscript.c +++ b/dlls/vbscript/tests/vbscript.c @@ -51,6 +51,7 @@ #endif
DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0); +DEFINE_GUID(IID_IScriptTypeInfo, 0xc59c6b12, 0xf6c1, 0x11cf, 0x88,0x35, 0x00,0xa0,0xc9,0x11,0xe8,0xb2);
#define DEFINE_EXPECT(func) \ static int expect_ ## func = 0, called_ ## func = 0 @@ -860,6 +861,330 @@ static void test_code_persistence(void) CHECK_CALLED(OnStateChange_CLOSED); }
+static void test_script_typeinfo(void) +{ + static struct + { + const WCHAR *name; + VARTYPE ret_type; + UINT num_args; + } func[] = + { + { L"test", VT_VOID, 0 }, + { L"subtract", VT_VARIANT, 2 }, + { L"emptyfn", VT_VARIANT, 0 }, + { L"foobar", VT_VARIANT, 0 } + }; + static struct + { + const WCHAR *name; + } var[] = + { + { L"global_var" }, + { L"obj" }, + { L"const_var" }, + { L"implicit" } + }; + ITypeInfo *typeinfo, *typeinfo2; + ITypeComp *typecomp, *typecomp2; + IActiveScriptParse *parser; + IDispatchEx *script_disp; + IActiveScript *vbscript; + FUNCDESC *funcdesc; + VARDESC *vardesc; + DESCKIND desckind; + BINDPTR bindptr; + MEMBERID memid; + TYPEATTR *attr; + UINT index; + HRESULT hr; + BSTR str; + int i; + + vbscript = create_vbscript(); + + hr = IActiveScript_QueryInterface(vbscript, &IID_IActiveScriptParse, (void**)&parser); + ok(hr == S_OK, "Could not get IActiveScriptParse iface: %08x\n", hr); + + 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); + + 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); + + parse_script(parser, + "dim global_var\n" + "const const_var = 1337\n" + + "sub test\nend sub\n" + "private sub private_sub\nend sub\n" + + "function subtract(byref x, byval y)\n" + " subtract = x - y\n" + "end function\n" + + "function emptyfn\nend function\n" + + "function foobar\n" + " foobar = "foobar"\n" + "end function\n" + + "class C\n" + " dim x\n" + " public sub method\nend sub\n" + " private function strret\n" + " strret = "ret"\n" + " end function\n" + "end class\n" + + "implicit = 10\n" + "dim obj\nset obj = new C\n"); + + script_disp = get_script_dispatch(vbscript); + 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); + ok(hr == DISP_E_BADINDEX, "GetTypeInfo returned: %08x\n", hr); + hr = IDispatchEx_GetTypeInfo(script_disp, 0, LOCALE_USER_DEFAULT, &typeinfo); + ok(hr == S_OK, "GetTypeInfo failed: %08x\n", hr); + hr = IDispatchEx_GetTypeInfo(script_disp, 0, LOCALE_USER_DEFAULT, &typeinfo2); + ok(hr == S_OK, "GetTypeInfo failed: %08x\n", hr); + ok(typeinfo != typeinfo2, "TypeInfo was not supposed to be shared.\n"); + ITypeInfo_Release(typeinfo2); + + hr = ITypeInfo_GetTypeAttr(typeinfo, &attr); + ok(hr == S_OK, "GetTypeAttr failed: %08x\n", hr); + ok(IsEqualGUID(&attr->guid, &IID_IScriptTypeInfo), "Unexpected GUID %s\n", wine_dbgstr_guid(&attr->guid)); + ok(attr->lcid == LOCALE_USER_DEFAULT, "Unexpected LCID %u\n", attr->lcid); + ok(attr->memidConstructor == MEMBERID_NIL, "Unexpected constructor memid %u\n", attr->memidConstructor); + ok(attr->memidDestructor == MEMBERID_NIL, "Unexpected destructor memid %u\n", attr->memidDestructor); + ok(attr->cbSizeInstance == 4, "Unexpected cbSizeInstance %u\n", attr->cbSizeInstance); + ok(attr->typekind == TKIND_DISPATCH, "Unexpected typekind %u\n", attr->typekind); + ok(attr->cFuncs == ARRAY_SIZE(func), "Unexpected cFuncs %u\n", attr->cFuncs); + ok(attr->cVars == ARRAY_SIZE(var), "Unexpected cVars %u\n", attr->cVars); + ok(attr->cImplTypes == 1, "Unexpected cImplTypes %u\n", attr->cImplTypes); + ok(attr->cbSizeVft == 7 * sizeof(void*), "Unexpected cbSizeVft %u\n", attr->cbSizeVft); + ok(attr->cbAlignment == 4, "Unexpected cbAlignment %u\n", attr->cbAlignment); + ok(attr->wTypeFlags == TYPEFLAG_FDISPATCHABLE, "Unexpected wTypeFlags 0x%x\n", attr->wTypeFlags); + ok(attr->tdescAlias.vt == VT_EMPTY, "Unexpected tdescAlias.vt %d\n", attr->tdescAlias.vt); + ok(attr->idldescType.wIDLFlags == IDLFLAG_NONE, "Unexpected idldescType.wIDLFlags 0x%x\n", attr->idldescType.wIDLFlags); + ITypeInfo_ReleaseTypeAttr(typeinfo, attr); + + /* GetIDsOfNames looks into the inherited types as well */ + str = SysAllocString(L"queryinterface"); + hr = ITypeInfo_GetIDsOfNames(typeinfo, NULL, 1, &memid); + ok(hr == E_INVALIDARG, "GetIDsOfNames returned: %08x\n", hr); + hr = ITypeInfo_GetIDsOfNames(typeinfo, &str, 1, NULL); + ok(hr == E_INVALIDARG, "GetIDsOfNames returned: %08x\n", hr); + hr = ITypeInfo_GetIDsOfNames(typeinfo, &str, 0, &memid); + ok(hr == E_INVALIDARG, "GetIDsOfNames returned: %08x\n", hr); + hr = ITypeInfo_GetIDsOfNames(typeinfo, &str, 1, &memid); + ok(hr == S_OK, "GetIDsOfNames failed: %08x\n", hr); + ok(!lstrcmpW(str, L"queryinterface"), "Unexpected string %s\n", wine_dbgstr_w(str)); + SysFreeString(str); + str = SysAllocString(L"C"); + hr = ITypeInfo_GetIDsOfNames(typeinfo, &str, 1, &memid); + ok(hr == DISP_E_UNKNOWNNAME, "GetIDsOfNames returned: %08x\n", hr); + SysFreeString(str); + str = SysAllocString(L"SUBtract"); + hr = ITypeInfo_GetIDsOfNames(typeinfo, &str, 1, &memid); + ok(hr == S_OK, "GetIDsOfNames failed: %08x\n", hr); + ok(!lstrcmpW(str, L"SUBtract"), "Unexpected string %s\n", wine_dbgstr_w(str)); + SysFreeString(str); + + /* Check variable descriptions */ + hr = ITypeInfo_GetVarDesc(typeinfo, 0, NULL); + ok(hr == E_INVALIDARG, "GetVarDesc returned: %08x\n", hr); + hr = ITypeInfo_GetVarDesc(typeinfo, 1337, &vardesc); + ok(hr == TYPE_E_ELEMENTNOTFOUND, "GetVarDesc returned: %08x\n", hr); + for (i = 0; i < ARRAY_SIZE(var); i++) + { + hr = ITypeInfo_GetVarDesc(typeinfo, i, &vardesc); + ok(hr == S_OK, "GetVarDesc(%u) failed: %08x\n", i, hr); + ok(vardesc->lpstrSchema == NULL, "[%u] Unexpected lpstrSchema %p\n", i, vardesc->lpstrSchema); + ok(vardesc->oInst == 0, "[%u] Unexpected oInst %u\n", i, vardesc->oInst); + ok(vardesc->varkind == VAR_DISPATCH, "[%u] Unexpected varkind %d\n", i, vardesc->varkind); + ok(vardesc->wVarFlags == 0, "[%u] Unexpected wVarFlags 0x%x\n", i, vardesc->wVarFlags); + ok(vardesc->elemdescVar.tdesc.vt == VT_VARIANT, + "[%u] Unexpected variable type vt %d (expected %d)\n", i, vardesc->elemdescVar.tdesc.vt, 0); + ok(vardesc->elemdescVar.paramdesc.pparamdescex == NULL, + "[%u] Unexpected variable type pparamdescex %p\n", i, vardesc->elemdescVar.paramdesc.pparamdescex); + ok(vardesc->elemdescVar.paramdesc.wParamFlags == PARAMFLAG_NONE, + "[%u] Unexpected variable type wParamFlags 0x%x\n", i, vardesc->elemdescVar.paramdesc.wParamFlags); + ITypeInfo_ReleaseVarDesc(typeinfo, vardesc); + } + + /* Check function descriptions */ + hr = ITypeInfo_GetFuncDesc(typeinfo, 0, NULL); + ok(hr == E_INVALIDARG, "GetFuncDesc returned: %08x\n", hr); + hr = ITypeInfo_GetFuncDesc(typeinfo, 1337, &funcdesc); + ok(hr == TYPE_E_ELEMENTNOTFOUND, "GetFuncDesc returned: %08x\n", hr); + for (i = 0; i < ARRAY_SIZE(func); i++) + { + hr = ITypeInfo_GetFuncDesc(typeinfo, i, &funcdesc); + ok(hr == S_OK, "GetFuncDesc(%u) failed: %08x\n", i, hr); + ok(funcdesc->lprgscode == NULL, "[%u] Unexpected lprgscode %p\n", i, funcdesc->lprgscode); + ok(func[i].num_args ? (funcdesc->lprgelemdescParam != NULL) : (funcdesc->lprgelemdescParam == NULL), + "[%u] Unexpected lprgelemdescParam %p\n", i, funcdesc->lprgelemdescParam); + ok(funcdesc->funckind == FUNC_DISPATCH, "[%u] Unexpected funckind %u\n", i, funcdesc->funckind); + ok(funcdesc->invkind == INVOKE_FUNC, "[%u] Unexpected invkind %u\n", i, funcdesc->invkind); + ok(funcdesc->callconv == CC_STDCALL, "[%u] Unexpected callconv %u\n", i, funcdesc->callconv); + ok(funcdesc->cParams == func[i].num_args, "[%u] Unexpected cParams %d (expected %d)\n", + i, funcdesc->cParams, func[i].num_args); + ok(funcdesc->cParamsOpt == 0, "[%u] Unexpected cParamsOpt %d\n", i, funcdesc->cParamsOpt); + ok(funcdesc->cScodes == 0, "[%u] Unexpected cScodes %d\n", i, funcdesc->cScodes); + ok(funcdesc->wFuncFlags == 0, "[%u] Unexpected wFuncFlags 0x%x\n", i, funcdesc->wFuncFlags); + ok(funcdesc->elemdescFunc.tdesc.vt == func[i].ret_type, + "[%u] Unexpected return type vt %d (expected %d)\n", i, funcdesc->elemdescFunc.tdesc.vt, func[i].ret_type); + ok(funcdesc->elemdescFunc.paramdesc.pparamdescex == NULL, + "[%u] Unexpected return type pparamdescex %p\n", i, funcdesc->elemdescFunc.paramdesc.pparamdescex); + ok(funcdesc->elemdescFunc.paramdesc.wParamFlags == PARAMFLAG_NONE, + "[%u] Unexpected return type wParamFlags 0x%x\n", i, funcdesc->elemdescFunc.paramdesc.wParamFlags); + if (funcdesc->lprgelemdescParam) + for (index = 0; index < funcdesc->cParams; index++) + { + ok(funcdesc->lprgelemdescParam[index].tdesc.vt == VT_VARIANT, + "[%u] Unexpected parameter %u vt %d\n", i, index, funcdesc->lprgelemdescParam[index].tdesc.vt); + ok(funcdesc->lprgelemdescParam[index].paramdesc.pparamdescex == NULL, + "[%u] Unexpected parameter %u pparamdescex %p\n", i, index, funcdesc->lprgelemdescParam[index].paramdesc.pparamdescex); + ok(funcdesc->lprgelemdescParam[index].paramdesc.wParamFlags == PARAMFLAG_NONE, + "[%u] Unexpected parameter %u wParamFlags 0x%x\n", i, index, funcdesc->lprgelemdescParam[index].paramdesc.wParamFlags); + } + ITypeInfo_ReleaseFuncDesc(typeinfo, funcdesc); + } + + /* Test TypeComp Binds */ + hr = ITypeInfo_QueryInterface(typeinfo, &IID_ITypeComp, (void**)&typecomp); + ok(hr == S_OK, "QueryInterface(IID_ITypeComp) failed: %08x\n", hr); + hr = ITypeInfo_GetTypeComp(typeinfo, NULL); + ok(hr == E_INVALIDARG, "GetTypeComp returned: %08x\n", hr); + hr = ITypeInfo_GetTypeComp(typeinfo, &typecomp2); + ok(hr == S_OK, "GetTypeComp failed: %08x\n", hr); + ok(typecomp == typecomp2, "QueryInterface(IID_ITypeComp) and GetTypeComp returned different TypeComps\n"); + ITypeComp_Release(typecomp2); + str = SysAllocString(L"not_found"); + hr = ITypeComp_Bind(typecomp, NULL, 0, 0, &typeinfo2, &desckind, &bindptr); + ok(hr == E_INVALIDARG, "Bind returned: %08x\n", hr); + hr = ITypeComp_Bind(typecomp, str, 0, 0, NULL, &desckind, &bindptr); + ok(hr == E_INVALIDARG, "Bind returned: %08x\n", hr); + hr = ITypeComp_Bind(typecomp, str, 0, 0, &typeinfo2, NULL, &bindptr); + ok(hr == E_INVALIDARG, "Bind returned: %08x\n", hr); + hr = ITypeComp_Bind(typecomp, str, 0, 0, &typeinfo2, &desckind, NULL); + ok(hr == E_INVALIDARG, "Bind returned: %08x\n", hr); + hr = ITypeComp_Bind(typecomp, str, 0, 0, &typeinfo2, &desckind, &bindptr); + ok(hr == S_OK, "Bind failed: %08x\n", hr); + ok(desckind == DESCKIND_NONE, "Unexpected desckind %u\n", desckind); + SysFreeString(str); + str = SysAllocString(L"GLOBAL_VAR"); + hr = ITypeComp_Bind(typecomp, str, 0, INVOKE_FUNC, &typeinfo2, &desckind, &bindptr); + ok(hr == TYPE_E_TYPEMISMATCH, "Bind returned: %08x\n", hr); + ok(!lstrcmpW(str, L"GLOBAL_VAR"), "Unexpected string %s\n", wine_dbgstr_w(str)); + SysFreeString(str); + str = SysAllocString(L"C"); + hr = ITypeComp_Bind(typecomp, str, 0, 0, &typeinfo2, &desckind, &bindptr); + ok(hr == S_OK, "Bind failed: %08x\n", hr); + ok(desckind == DESCKIND_NONE, "Unexpected desckind %u\n", desckind); + SysFreeString(str); + str = SysAllocString(L"addRef"); + hr = ITypeComp_Bind(typecomp, str, 0, 0, &typeinfo2, &desckind, &bindptr); + ok(hr == S_OK, "Bind failed: %08x\n", hr); + ok(desckind == DESCKIND_FUNCDESC, "Unexpected desckind %u\n", desckind); + ok(!lstrcmpW(str, L"addRef"), "Unexpected string %s\n", wine_dbgstr_w(str)); + ITypeInfo_ReleaseFuncDesc(typeinfo2, bindptr.lpfuncdesc); + ITypeInfo_Release(typeinfo2); + SysFreeString(str); + for (i = 0; i < ARRAY_SIZE(var); i++) + { + str = SysAllocString(var[i].name); + hr = ITypeComp_Bind(typecomp, str, 0, INVOKE_PROPERTYGET, &typeinfo2, &desckind, &bindptr); + ok(hr == S_OK, "Bind failed: %08x\n", hr); + ok(desckind == DESCKIND_VARDESC, "Unexpected desckind %u\n", desckind); + ITypeInfo_ReleaseVarDesc(typeinfo2, bindptr.lpvardesc); + ITypeInfo_Release(typeinfo2); + SysFreeString(str); + } + for (i = 0; i < ARRAY_SIZE(func); i++) + { + str = SysAllocString(func[i].name); + hr = ITypeComp_Bind(typecomp, str, 0, INVOKE_FUNC, &typeinfo2, &desckind, &bindptr); + ok(hr == S_OK, "Bind failed: %08x\n", hr); + ok(desckind == DESCKIND_FUNCDESC, "Unexpected desckind %u\n", desckind); + ITypeInfo_ReleaseFuncDesc(typeinfo2, bindptr.lpfuncdesc); + ITypeInfo_Release(typeinfo2); + SysFreeString(str); + } + str = SysAllocString(L"VBScriptTypeInfo"); + hr = ITypeComp_BindType(typecomp, NULL, 0, &typeinfo2, &typecomp2); + ok(hr == E_INVALIDARG, "BindType returned: %08x\n", hr); + hr = ITypeComp_BindType(typecomp, str, 0, NULL, &typecomp2); + ok(hr == E_INVALIDARG, "BindType returned: %08x\n", hr); + hr = ITypeComp_BindType(typecomp, str, 0, &typeinfo2, NULL); + ok(hr == E_INVALIDARG, "BindType returned: %08x\n", hr); + hr = ITypeComp_BindType(typecomp, str, 0, &typeinfo2, &typecomp2); + ok(hr == S_OK, "BindType failed: %08x\n", hr); + ok(!typeinfo2, "Unexpected TypeInfo %p (expected null)\n", typeinfo2); + ok(!typecomp2, "Unexpected TypeComp %p (expected null)\n", typecomp2); + SysFreeString(str); + str = SysAllocString(L"C"); + hr = ITypeComp_BindType(typecomp, str, 0, &typeinfo2, &typecomp2); + ok(hr == S_OK, "BindType failed: %08x\n", hr); + ok(!typeinfo2, "Unexpected TypeInfo %p (expected null)\n", typeinfo2); + ok(!typecomp2, "Unexpected TypeComp %p (expected null)\n", typecomp2); + SysFreeString(str); + str = SysAllocString(L"IDispatch"); + hr = ITypeComp_BindType(typecomp, str, 0, &typeinfo2, &typecomp2); + ok(hr == S_OK, "BindType failed: %08x\n", hr); + ok(!typeinfo2, "Unexpected TypeInfo %p (expected null)\n", typeinfo2); + ok(!typecomp2, "Unexpected TypeComp %p (expected null)\n", typecomp2); + SysFreeString(str); + ITypeComp_Release(typecomp); + + /* Updating the script won't update the typeinfo obtained before, + but it will be reflected in any typeinfo obtained afterwards. */ + parse_script(parser, + "dim new_var\nnew_var = 10\n" + "sub new_sub\nend sub\n" + "function new_fn\nend function\n"); + + hr = IDispatchEx_GetTypeInfo(script_disp, 0, LOCALE_USER_DEFAULT, &typeinfo2); + ok(hr == S_OK, "GetTypeInfo failed: %08x\n", hr); + hr = ITypeInfo_GetTypeAttr(typeinfo, &attr); + ok(hr == S_OK, "GetTypeAttr failed: %08x\n", hr); + ok(attr->cFuncs == ARRAY_SIZE(func), "Unexpected cFuncs %u\n", attr->cFuncs); + ok(attr->cVars == ARRAY_SIZE(var), "Unexpected cVars %u\n", attr->cVars); + ITypeInfo_ReleaseTypeAttr(typeinfo, attr); + hr = ITypeInfo_GetTypeAttr(typeinfo2, &attr); + ok(hr == S_OK, "GetTypeAttr failed: %08x\n", hr); + ok(attr->cFuncs == ARRAY_SIZE(func) + 2, "Unexpected cFuncs %u\n", attr->cFuncs); + ok(attr->cVars == ARRAY_SIZE(var) + 1, "Unexpected cVars %u\n", attr->cVars); + ITypeInfo_ReleaseTypeAttr(typeinfo2, attr); + ITypeInfo_Release(typeinfo2); + + ITypeInfo_Release(typeinfo); + IDispatchEx_Release(script_disp); + IActiveScriptParse_Release(parser); + + SET_EXPECT(OnStateChange_DISCONNECTED); + SET_EXPECT(OnStateChange_INITIALIZED); + SET_EXPECT(OnStateChange_CLOSED); + hr = IActiveScript_Close(vbscript); + ok(hr == S_OK, "Close failed: %08x\n", hr); + CHECK_CALLED(OnStateChange_DISCONNECTED); + CHECK_CALLED(OnStateChange_INITIALIZED); + CHECK_CALLED(OnStateChange_CLOSED); + + IActiveScript_Release(vbscript); +} + static void test_vbscript(void) { IActiveScriptParseProcedure2 *parse_proc; @@ -1486,6 +1811,7 @@ START_TEST(vbscript) test_named_items(); test_scriptdisp(); test_code_persistence(); + test_script_typeinfo(); test_RegExp(); test_RegExp_Replace(); }else {