jscript: Use host global object as default 'this' if available and global object otherwise.

oldstable
Jacek Caban 2009-09-27 20:59:28 +02:00 committed by Alexandre Julliard
parent aa347e0721
commit d833314c70
7 changed files with 136 additions and 69 deletions

View File

@ -178,7 +178,8 @@ void scope_release(scope_chain_t *scope)
heap_free(scope);
}
HRESULT create_exec_ctx(IDispatch *this_obj, DispatchEx *var_disp, scope_chain_t *scope, exec_ctx_t **ret)
HRESULT create_exec_ctx(script_ctx_t *script_ctx, IDispatch *this_obj, DispatchEx *var_disp,
scope_chain_t *scope, exec_ctx_t **ret)
{
exec_ctx_t *ctx;
@ -188,8 +189,13 @@ HRESULT create_exec_ctx(IDispatch *this_obj, DispatchEx *var_disp, scope_chain_t
ctx->ref = 1;
IDispatch_AddRef(this_obj);
ctx->this_obj = this_obj;
if(this_obj)
ctx->this_obj = this_obj;
else if(script_ctx->host_global)
ctx->this_obj = script_ctx->host_global;
else
ctx->this_obj = (IDispatch*)_IDispatchEx_(script_ctx->global);
IDispatch_AddRef(ctx->this_obj);
IDispatchEx_AddRef(_IDispatchEx_(var_disp));
ctx->var_disp = var_disp;
@ -537,21 +543,15 @@ static HRESULT identifier_eval(exec_ctx_t *ctx, BSTR identifier, DWORD flags, js
}
}
hres = jsdisp_get_id(ctx->parser->script->script_disp, identifier, 0, &id);
if(SUCCEEDED(hres)) {
exprval_set_idref(ret, (IDispatch*)_IDispatchEx_(ctx->parser->script->script_disp), id);
return S_OK;
}
if(lookup_global_members(ctx->parser->script, identifier, ret))
return S_OK;
if(flags & EXPR_NEWREF) {
hres = jsdisp_get_id(ctx->parser->script->script_disp, identifier, fdexNameEnsure, &id);
hres = jsdisp_get_id(ctx->parser->script->global, identifier, fdexNameEnsure, &id);
if(FAILED(hres))
return hres;
exprval_set_idref(ret, (IDispatch*)_IDispatchEx_(ctx->parser->script->script_disp), id);
exprval_set_idref(ret, (IDispatch*)_IDispatchEx_(ctx->parser->script->global), id);
return S_OK;
}

View File

@ -116,7 +116,7 @@ static inline void exec_addref(exec_ctx_t *ctx)
}
void exec_release(exec_ctx_t*);
HRESULT create_exec_ctx(IDispatch*,DispatchEx*,scope_chain_t*,exec_ctx_t**);
HRESULT create_exec_ctx(script_ctx_t*,IDispatch*,DispatchEx*,scope_chain_t*,exec_ctx_t**);
HRESULT exec_source(exec_ctx_t*,parser_ctx_t*,source_elements_t*,jsexcept_t*,VARIANT*);
typedef struct _statement_t statement_t;

View File

@ -210,7 +210,7 @@ static HRESULT invoke_source(script_ctx_t *ctx, FunctionInstance *function, IDis
hres = scope_push(function->scope_chain, var_disp, &scope);
if(SUCCEEDED(hres)) {
hres = create_exec_ctx(this_obj, var_disp, scope, &exec_ctx);
hres = create_exec_ctx(ctx, this_obj, var_disp, scope, &exec_ctx);
scope_release(scope);
}
if(FAILED(hres))
@ -222,17 +222,6 @@ static HRESULT invoke_source(script_ctx_t *ctx, FunctionInstance *function, IDis
return hres;
}
static HRESULT invoke_function(script_ctx_t *ctx, FunctionInstance *function, DISPPARAMS *dp,
VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
{
IDispatch *this_obj;
if(!(this_obj = get_this(dp)))
this_obj = (IDispatch*)_IDispatchEx_(ctx->script_disp);
return invoke_source(ctx, function, this_obj, dp, retv, ei, caller);
}
static HRESULT invoke_constructor(script_ctx_t *ctx, FunctionInstance *function, DISPPARAMS *dp,
VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
{
@ -254,18 +243,18 @@ static HRESULT invoke_constructor(script_ctx_t *ctx, FunctionInstance *function,
return S_OK;
}
static HRESULT invoke_value_proc(script_ctx_t *ctx, FunctionInstance *function, WORD flags, DISPPARAMS *dp,
static HRESULT invoke_value_proc(script_ctx_t *ctx, FunctionInstance *function, IDispatch *this_disp, WORD flags, DISPPARAMS *dp,
VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
{
IDispatch *this_disp;
vdisp_t vthis;
HRESULT hres;
this_disp = get_this(dp);
if(this_disp)
set_disp(&vthis, this_disp);
else if(ctx->host_global)
set_disp(&vthis, ctx->host_global);
else
set_jsdisp(&vthis, ctx->script_disp);
set_jsdisp(&vthis, ctx->global);
hres = function->value_proc(ctx, &vthis, flags, dp, retv, ei, caller);
@ -276,24 +265,10 @@ static HRESULT invoke_value_proc(script_ctx_t *ctx, FunctionInstance *function,
static HRESULT call_function(script_ctx_t *ctx, FunctionInstance *function, IDispatch *this_obj, DISPPARAMS *args,
VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
{
HRESULT hres;
if(function->value_proc)
return invoke_value_proc(ctx, function, this_obj, DISPATCH_METHOD, args, retv, ei, caller);
if(function->value_proc) {
vdisp_t vthis;
if(this_obj)
set_disp(&vthis, this_obj);
else
set_jsdisp(&vthis, ctx->script_disp);
hres = function->value_proc(ctx, &vthis, DISPATCH_METHOD, args, retv, ei, caller);
vdisp_release(&vthis);
}else {
hres = invoke_source(ctx, function, this_obj ? this_obj : (IDispatch*)_IDispatchEx_(ctx->script_disp),
args, retv, ei, caller);
}
return hres;
return invoke_source(ctx, function, this_obj, args, retv, ei, caller);
}
static HRESULT function_to_string(FunctionInstance *function, BSTR *ret)
@ -506,9 +481,9 @@ HRESULT Function_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAM
switch(flags) {
case DISPATCH_METHOD:
if(function->value_proc)
return invoke_value_proc(ctx, function, flags, dp, retv, ei, caller);
return invoke_value_proc(ctx, function, get_this(dp), flags, dp, retv, ei, caller);
return invoke_function(ctx, function, dp, retv, ei, caller);
return invoke_source(ctx, function, get_this(dp), dp, retv, ei, caller);
case DISPATCH_PROPERTYGET: {
HRESULT hres;
@ -525,7 +500,7 @@ HRESULT Function_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAM
case DISPATCH_CONSTRUCT:
if(function->value_proc)
return invoke_value_proc(ctx, function, flags, dp, retv, ei, caller);
return invoke_value_proc(ctx, function, get_this(dp), flags, dp, retv, ei, caller);
return invoke_constructor(ctx, function, dp, retv, ei, caller);

View File

@ -96,7 +96,7 @@ static HRESULT exec_global_code(JScript *This, parser_ctx_t *parser_ctx)
VARIANT var;
HRESULT hres;
hres = create_exec_ctx((IDispatch*)_IDispatchEx_(This->ctx->script_disp), This->ctx->script_disp, NULL, &exec_ctx);
hres = create_exec_ctx(This->ctx, NULL, This->ctx->global, NULL, &exec_ctx);
if(FAILED(hres))
return hres;
@ -148,12 +148,6 @@ static HRESULT set_ctx_site(JScript *This)
This->ctx->lcid = This->lcid;
if(!This->ctx->script_disp) {
hres = create_dispex(This->ctx, NULL, NULL, &This->ctx->script_disp);
if(FAILED(hres))
return hres;
}
hres = init_global(This->ctx);
if(FAILED(hres))
return hres;
@ -335,6 +329,11 @@ static HRESULT WINAPI JScript_Close(IActiveScript *iface)
if(This->ctx->state == SCRIPTSTATE_DISCONNECTED)
change_state(This, SCRIPTSTATE_INITIALIZED);
if(This->ctx->host_global) {
IDispatch_Release(This->ctx->host_global);
This->ctx->host_global = NULL;
}
if(This->ctx->named_items) {
named_item_t *iter, *iter2;
@ -360,11 +359,6 @@ static HRESULT WINAPI JScript_Close(IActiveScript *iface)
if (This->site)
change_state(This, SCRIPTSTATE_CLOSED);
if(This->ctx->script_disp) {
jsdisp_release(This->ctx->script_disp);
This->ctx->script_disp = NULL;
}
if(This->ctx->global) {
jsdisp_release(This->ctx->global);
This->ctx->global = NULL;
@ -407,6 +401,11 @@ static HRESULT WINAPI JScript_AddNamedItem(IActiveScript *iface,
WARN("object does not implement IDispatch\n");
return hres;
}
if(This->ctx->host_global)
IDispatch_Release(This->ctx->host_global);
IDispatch_AddRef(disp);
This->ctx->host_global = disp;
}
item = heap_alloc(sizeof(*item));
@ -449,12 +448,12 @@ static HRESULT WINAPI JScript_GetScriptDispatch(IActiveScript *iface, LPCOLESTR
if(!ppdisp)
return E_POINTER;
if(This->thread_id != GetCurrentThreadId() || !This->ctx->script_disp) {
if(This->thread_id != GetCurrentThreadId() || !This->ctx->global) {
*ppdisp = NULL;
return E_UNEXPECTED;
}
*ppdisp = (IDispatch*)_IDispatchEx_(This->ctx->script_disp);
*ppdisp = (IDispatch*)_IDispatchEx_(This->ctx->global);
IDispatch_AddRef(*ppdisp);
return S_OK;
}

View File

@ -264,7 +264,8 @@ struct _script_ctx_t {
jsheap_t tmp_heap;
DispatchEx *script_disp;
IDispatch *host_global;
DispatchEx *global;
DispatchEx *function_constr;
DispatchEx *array_constr;

View File

@ -68,6 +68,18 @@ DEFINE_EXPECT(OnStateChange_INITIALIZED);
DEFINE_EXPECT(OnEnterScript);
DEFINE_EXPECT(OnLeaveScript);
static BSTR a2bstr(const char *str)
{
BSTR ret;
int len;
len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
ret = SysAllocStringLen(NULL, len-1);
MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
return ret;
}
#define test_state(s,ss) _test_state(__LINE__,s,ss)
static void _test_state(unsigned line, IActiveScript *script, SCRIPTSTATE exstate)
{
@ -195,6 +207,8 @@ static void test_script_dispatch(IActiveScript *script, BOOL initialized)
{
IDispatchEx *dispex;
IDispatch *disp;
BSTR str;
DISPID id;
HRESULT hres;
disp = (void*)0xdeadbeef;
@ -214,6 +228,11 @@ static void test_script_dispatch(IActiveScript *script, BOOL initialized)
IDispatch_Release(disp);
ok(hres == S_OK, "Could not get IDispatchEx interface: %08x\n", hres);
str = a2bstr("ActiveXObject");
hres = IDispatchEx_GetDispID(dispex, str, fdexNameCaseSensitive, &id);
SysFreeString(str);
ok(hres == S_OK, "GetDispID failed: %08x\n", hres);
IDispatchEx_Release(dispex);
}

View File

@ -79,6 +79,8 @@ DEFINE_EXPECT(GetItemInfo_testVal);
#define DISPID_GLOBAL_TESTOBJ 0x1006
#define DISPID_GLOBAL_NULL_BSTR 0x1007
#define DISPID_GLOBAL_NULL_DISP 0x1008
#define DISPID_GLOBAL_TESTTHIS 0x1009
#define DISPID_GLOBAL_TESTTHIS2 0x100a
#define DISPID_TESTOBJ_PROP 0x2000
@ -89,6 +91,7 @@ static const CHAR test_valA[] = "testVal";
static BOOL strict_dispid_check;
static const char *test_name = "(null)";
static IDispatch *script_disp;
static BSTR a2bstr(const char *str)
{
@ -325,6 +328,18 @@ static HRESULT WINAPI Global_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD
return DISP_E_UNKNOWNNAME;
}
if(!strcmp_wa(bstrName, "testThis")) {
ok(grfdex == fdexNameCaseSensitive, "grfdex = %x\n", grfdex);
*pid = DISPID_GLOBAL_TESTTHIS;
return S_OK;
}
if(!strcmp_wa(bstrName, "testThis2")) {
ok(grfdex == fdexNameCaseSensitive, "grfdex = %x\n", grfdex);
*pid = DISPID_GLOBAL_TESTTHIS2;
return S_OK;
}
if(strict_dispid_check)
ok(0, "unexpected call %s\n", wine_dbgstr_w(bstrName));
return DISP_E_UNKNOWNNAME;
@ -492,6 +507,35 @@ static HRESULT WINAPI Global_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid,
V_VT(pvarRes) = VT_DISPATCH;
V_DISPATCH(pvarRes) = NULL;
return S_OK;
case DISPID_GLOBAL_TESTTHIS:
ok(pdp != NULL, "pdp == NULL\n");
ok(pdp->rgvarg != NULL, "rgvarg == NULL\n");
ok(!pdp->rgdispidNamedArgs, "rgdispidNamedArgs != NULL\n");
ok(pdp->cArgs == 1, "cArgs = %d\n", pdp->cArgs);
ok(!pdp->cNamedArgs, "cNamedArgs = %d\n", pdp->cNamedArgs);
ok(pvarRes == NULL, "pvarRes != NULL\n");
ok(pei != NULL, "pei == NULL\n");
ok(V_VT(pdp->rgvarg) == VT_DISPATCH, "V_VT(arg) = %d\n", V_VT(pdp->rgvarg));
ok(V_DISPATCH(pdp->rgvarg) == (IDispatch*)iface, "disp != iface\n");
return S_OK;
case DISPID_GLOBAL_TESTTHIS2:
ok(pdp != NULL, "pdp == NULL\n");
ok(pdp->rgvarg != NULL, "rgvarg == NULL\n");
ok(!pdp->rgdispidNamedArgs, "rgdispidNamedArgs != NULL\n");
ok(pdp->cArgs == 1, "cArgs = %d\n", pdp->cArgs);
ok(!pdp->cNamedArgs, "cNamedArgs = %d\n", pdp->cNamedArgs);
ok(pvarRes == NULL, "pvarRes != NULL\n");
ok(pei != NULL, "pei == NULL\n");
ok(V_VT(pdp->rgvarg) == VT_DISPATCH, "V_VT(arg) = %d\n", V_VT(pdp->rgvarg));
ok(V_DISPATCH(pdp->rgvarg) != (IDispatch*)iface, "disp == iface\n");
ok(V_DISPATCH(pdp->rgvarg) == script_disp, "disp != script_disp\n");
return S_OK;
}
ok(0, "unexpected call %x\n", id);
@ -625,7 +669,7 @@ static IActiveScript *create_script(void)
return script;
}
static void parse_script(BSTR script_str)
static void parse_script(DWORD flags, BSTR script_str)
{
IActiveScriptParse *parser;
IActiveScript *engine;
@ -650,15 +694,21 @@ static void parse_script(BSTR script_str)
ok(hres == S_OK, "SetScriptSite failed: %08x\n", hres);
hres = IActiveScript_AddNamedItem(engine, testW,
SCRIPTITEM_ISVISIBLE|SCRIPTITEM_ISSOURCE|SCRIPTITEM_GLOBALMEMBERS);
SCRIPTITEM_ISVISIBLE|SCRIPTITEM_ISSOURCE|flags);
ok(hres == S_OK, "AddNamedItem failed: %08x\n", hres);
hres = IActiveScript_SetScriptState(engine, SCRIPTSTATE_STARTED);
ok(hres == S_OK, "SetScriptState(SCRIPTSTATE_STARTED) failed: %08x\n", hres);
hres = IActiveScript_GetScriptDispatch(engine, NULL, &script_disp);
ok(hres == S_OK, "GetScriptDispatch failed: %08x\n", hres);
ok(script_disp != NULL, "script_disp == NULL\n");
ok(script_disp != (IDispatch*)&Global, "script_disp == Global\n");
hres = IActiveScriptParse64_ParseScriptText(parser, script_str, NULL, NULL, NULL, 0, 0, 0, NULL, NULL);
ok(hres == S_OK, "ParseScriptText failed: %08x\n", hres);
IDispatch_Release(script_disp);
IActiveScript_Release(engine);
IUnknown_Release(parser);
}
@ -704,13 +754,18 @@ static HRESULT parse_htmlscript(BSTR script_str)
return hres;
}
static void parse_script_a(const char *src)
static void parse_script_af(DWORD flags, const char *src)
{
BSTR tmp = a2bstr(src);
parse_script(tmp);
parse_script(flags, tmp);
SysFreeString(tmp);
}
static void parse_script_a(const char *src)
{
parse_script_af(SCRIPTITEM_GLOBALMEMBERS, src);
}
static HRESULT parse_htmlscript_a(const char *src)
{
HRESULT hres;
@ -766,7 +821,7 @@ static void run_from_file(const char *filename)
strict_dispid_check = FALSE;
if(script_str)
parse_script(script_str);
parse_script(SCRIPTITEM_GLOBALMEMBERS, script_str);
SysFreeString(script_str);
}
@ -793,7 +848,7 @@ static void run_from_res(const char *name)
SET_EXPECT(global_success_d);
SET_EXPECT(global_success_i);
parse_script(str);
parse_script(SCRIPTITEM_GLOBALMEMBERS, str);
CHECK_CALLED(global_success_d);
CHECK_CALLED(global_success_i);
@ -916,6 +971,21 @@ static void run_tests(void)
parse_script_a("ok(String.prototype.concat.call(testObj, ' OK') === '1 OK', 'wrong concat result');");
CHECK_CALLED(testobj_value);
SET_EXPECT(global_propget_d);
SET_EXPECT(global_propget_i);
parse_script_a("this.testPropGet;");
CHECK_CALLED(global_propget_d);
CHECK_CALLED(global_propget_i);
SET_EXPECT(global_propget_d);
SET_EXPECT(global_propget_i);
parse_script_a("(function () { this.testPropGet; })();");
CHECK_CALLED(global_propget_d);
CHECK_CALLED(global_propget_i);
parse_script_a("testThis(this);");
parse_script_a("(function () { testThis(this); })();");
run_from_res("lang.js");
run_from_res("api.js");
run_from_res("regexp.js");
@ -923,6 +993,9 @@ static void run_tests(void)
test_isvisible(FALSE);
test_isvisible(TRUE);
parse_script_af(0, "test.testThis2(this);");
parse_script_af(0, "(function () { test.testThis2(this); })();");
hres = parse_htmlscript_a("<!--");
ok(hres == S_OK, "ParseScriptText failed: %08x\n", hres);
hres = parse_htmlscript_a("-->");