jscript: Pass jsthis internally without using DISPPARAMS.
diff --git a/dlls/jscript/array.c b/dlls/jscript/array.c
index 91a7b82..139b04d 100644
--- a/dlls/jscript/array.c
+++ b/dlls/jscript/array.c
@@ -646,7 +646,7 @@
         args[0] = *v2;
         args[1] = *v1;
 
-        hres = jsdisp_call_value(cmp_func, DISPATCH_METHOD, &dp, &res, ei);
+        hres = jsdisp_call_value(cmp_func, NULL, DISPATCH_METHOD, &dp, &res, ei);
         if(FAILED(hres))
             return hres;
 
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c
index 7763512..86fcd85 100644
--- a/dlls/jscript/dispex.c
+++ b/dlls/jscript/dispex.c
@@ -291,7 +291,7 @@
     return hres;
 }
 
-static HRESULT set_this(DISPPARAMS *dp, DISPPARAMS *olddp, IDispatch *jsthis)
+static HRESULT set_this(DISPPARAMS *dp, const DISPPARAMS *olddp, IDispatch *jsthis)
 {
     VARIANTARG *oldargs;
     int i;
@@ -333,6 +333,24 @@
     return S_OK;
 }
 
+static IDispatch *get_this(DISPPARAMS *dp)
+{
+    DWORD i;
+
+    for(i=0; i < dp->cNamedArgs; i++) {
+        if(dp->rgdispidNamedArgs[i] == DISPID_THIS) {
+            if(V_VT(dp->rgvarg+i) == VT_DISPATCH)
+                return V_DISPATCH(dp->rgvarg+i);
+
+            WARN("This is not VT_DISPATCH\n");
+            return NULL;
+        }
+    }
+
+    TRACE("no this passed\n");
+    return NULL;
+}
+
 static HRESULT convert_params(const DISPPARAMS *dp, VARIANT *buf, DISPPARAMS *ret)
 {
     BOOL need_conversion = FALSE;
@@ -382,7 +400,7 @@
     return S_OK;
 }
 
-static HRESULT invoke_prop_func(jsdisp_t *This, jsdisp_t *jsthis, dispex_prop_t *prop, WORD flags,
+static HRESULT invoke_prop_func(jsdisp_t *This, IDispatch *jsthis, dispex_prop_t *prop, WORD flags,
         DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
 {
     HRESULT hres;
@@ -401,15 +419,18 @@
         if(FAILED(hres))
             return hres;
 
-        if(prop->name || jsthis->builtin_info->class != JSCLASS_FUNCTION) {
+        if(prop->name || This->builtin_info->class != JSCLASS_FUNCTION) {
             vdisp_t vthis;
 
-            set_jsdisp(&vthis, jsthis);
+            if(jsthis)
+                set_disp(&vthis, jsthis);
+            else
+                set_jsdisp(&vthis, This);
             hres = prop->u.p->invoke(This->ctx, &vthis, flags, &params, retv, ei);
             vdisp_release(&vthis);
         }else {
             /* Function object calls are special case */
-            hres = Function_invoke(This, flags, &params, retv, ei);
+            hres = Function_invoke(This, jsthis, flags, &params, retv, ei);
         }
         if(params.rgvarg != buf && params.rgvarg != dp->rgvarg)
             heap_free(params.rgvarg);
@@ -418,8 +439,6 @@
     case PROP_PROTREF:
         return invoke_prop_func(This->prototype, jsthis, This->prototype->props+prop->u.ref, flags, dp, retv, ei, caller);
     case PROP_VARIANT: {
-        DISPPARAMS new_dp;
-
         if(V_VT(&prop->u.var) != VT_DISPATCH) {
             FIXME("invoke vt %d\n", V_VT(&prop->u.var));
             return E_FAIL;
@@ -427,19 +446,7 @@
 
         TRACE("call %s %p\n", debugstr_w(prop->name), V_DISPATCH(&prop->u.var));
 
-        hres = set_this(&new_dp, dp, to_disp(jsthis));
-        if(FAILED(hres))
-            return hres;
-
-        hres = disp_call(This->ctx, V_DISPATCH(&prop->u.var), DISPID_VALUE, flags, &new_dp, retv, ei);
-
-        if(new_dp.rgvarg != dp->rgvarg) {
-            heap_free(new_dp.rgvarg);
-            if(new_dp.cNamedArgs > 1)
-                heap_free(new_dp.rgdispidNamedArgs);
-        }
-
-        return hres;
+        return disp_call_value(This->ctx, V_DISPATCH(&prop->u.var), jsthis, flags, dp, retv, ei);
     }
     default:
         ERR("type %d\n", prop->type);
@@ -732,7 +739,7 @@
         /* fall through */
     case DISPATCH_METHOD:
     case DISPATCH_CONSTRUCT:
-        hres = invoke_prop_func(This, This, prop, wFlags, pdp, pvarRes, &jsexcept, pspCaller);
+        hres = invoke_prop_func(This, get_this(pdp), prop, wFlags, pdp, pvarRes, &jsexcept, pspCaller);
         break;
     case DISPATCH_PROPERTYGET:
         hres = prop_get(This, prop, pdp, pvarRes, &jsexcept, pspCaller);
@@ -1055,14 +1062,21 @@
     return DISP_E_UNKNOWNNAME;
 }
 
-HRESULT jsdisp_call_value(jsdisp_t *jsthis, WORD flags, DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei)
+HRESULT jsdisp_call_value(jsdisp_t *jsfunc, IDispatch *jsthis, WORD flags, DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei)
 {
-    vdisp_t vdisp;
     HRESULT hres;
 
-    set_jsdisp(&vdisp, jsthis);
-    hres = jsthis->builtin_info->value_prop.invoke(jsthis->ctx, &vdisp, flags, dp, retv, ei);
-    vdisp_release(&vdisp);
+    TRACE("args %p\n", dp->rgvarg);
+
+    if(is_class(jsfunc, JSCLASS_FUNCTION)) {
+        hres = Function_invoke(jsfunc, jsthis, flags, dp, retv, ei);
+    }else {
+        vdisp_t vdisp;
+
+        set_disp(&vdisp, jsthis);
+        hres = jsfunc->builtin_info->value_prop.invoke(jsfunc->ctx, &vdisp, flags, dp, retv, ei);
+        vdisp_release(&vdisp);
+    }
     return hres;
 }
 
@@ -1078,7 +1092,7 @@
     if(!prop)
         return DISP_E_MEMBERNOTFOUND;
 
-    return invoke_prop_func(disp, disp, prop, flags, dp, retv, ei, NULL);
+    return invoke_prop_func(disp, to_disp(disp), prop, flags, dp, retv, ei, NULL);
 }
 
 HRESULT jsdisp_call_name(jsdisp_t *disp, const WCHAR *name, WORD flags, DISPPARAMS *dp, VARIANT *retv,
@@ -1095,7 +1109,7 @@
     if(retv)
         V_VT(retv) = VT_EMPTY;
 
-    return invoke_prop_func(disp, disp, prop, flags, dp, retv, ei, NULL);
+    return invoke_prop_func(disp, to_disp(disp), prop, flags, dp, retv, ei, NULL);
 }
 
 HRESULT disp_call(script_ctx_t *ctx, IDispatch *disp, DISPID id, WORD flags, DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei)
@@ -1146,6 +1160,71 @@
     return S_OK;
 }
 
+HRESULT disp_call_value(script_ctx_t *ctx, IDispatch *disp, IDispatch *jsthis, WORD flags, DISPPARAMS *dp,
+        VARIANT *retv, jsexcept_t *ei)
+{
+    DISPPARAMS params;
+    jsdisp_t *jsdisp;
+    IDispatchEx *dispex;
+    HRESULT hres;
+
+    jsdisp = iface_to_jsdisp((IUnknown*)disp);
+    if(jsdisp) {
+        if(flags & DISPATCH_PROPERTYPUT) {
+            FIXME("disp_call(propput) on builtin object\n");
+            return E_FAIL;
+        }
+
+        hres = jsdisp_call_value(jsdisp, jsthis, flags, dp, retv, ei);
+        jsdisp_release(jsdisp);
+        return hres;
+    }
+
+    memset(ei, 0, sizeof(*ei));
+    if(retv && arg_cnt(dp))
+        flags |= DISPATCH_PROPERTYGET;
+
+    if(jsthis) {
+        hres = set_this(&params, dp, jsthis);
+        if(FAILED(hres))
+            return hres;
+    }else {
+        params = *dp;
+    }
+
+    if(retv)
+        V_VT(retv) = VT_EMPTY;
+    hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
+    if(SUCCEEDED(hres)) {
+        hres = IDispatchEx_InvokeEx(dispex, DISPID_VALUE, ctx->lcid, flags, &params, retv, &ei->ei,
+                &ctx->jscaller->IServiceProvider_iface);
+        IDispatchEx_Release(dispex);
+    }else {
+        UINT err = 0;
+
+        if(flags == DISPATCH_CONSTRUCT) {
+            WARN("IDispatch cannot be constructor\n");
+            return DISP_E_MEMBERNOTFOUND;
+        }
+
+        TRACE("using IDispatch\n");
+        hres = IDispatch_Invoke(disp, DISPID_VALUE, &IID_NULL, ctx->lcid, flags, &params, retv, &ei->ei, &err);
+    }
+
+    if(params.rgvarg != dp->rgvarg) {
+        heap_free(params.rgvarg);
+        if(params.cNamedArgs > 1)
+            heap_free(params.rgdispidNamedArgs);
+    }
+
+    if(FAILED(hres))
+        return hres;
+
+    if(retv)
+        ensure_retval_type(retv);
+    return S_OK;
+}
+
 HRESULT jsdisp_propput_name(jsdisp_t *obj, const WCHAR *name, VARIANT *val, jsexcept_t *ei)
 {
     dispex_prop_t *prop;
diff --git a/dlls/jscript/engine.c b/dlls/jscript/engine.c
index 8117cb5..3b20e6a 100644
--- a/dlls/jscript/engine.c
+++ b/dlls/jscript/engine.c
@@ -1014,8 +1014,7 @@
         return throw_type_error(ctx->script, ctx->ei, JS_E_INVALID_PROPERTY, NULL);
 
     jsstack_to_dp(ctx, arg, &dp);
-    hres = disp_call(ctx->script, V_DISPATCH(constr), DISPID_VALUE,
-            DISPATCH_CONSTRUCT, &dp, &v, ctx->ei);
+    hres = disp_call_value(ctx->script, V_DISPATCH(constr), NULL, DISPATCH_CONSTRUCT, &dp, &v, ctx->ei);
     if(FAILED(hres))
         return hres;
 
@@ -1039,7 +1038,7 @@
         return throw_type_error(ctx->script, ctx->ei, JS_E_INVALID_PROPERTY, NULL);
 
     jsstack_to_dp(ctx, argn, &dp);
-    hres = disp_call(ctx->script, V_DISPATCH(objv), DISPID_VALUE, DISPATCH_METHOD, &dp,
+    hres = disp_call_value(ctx->script, V_DISPATCH(objv), NULL, DISPATCH_METHOD, &dp,
             do_ret ? &v : NULL, ctx->ei);
     if(FAILED(hres))
         return hres;
diff --git a/dlls/jscript/function.c b/dlls/jscript/function.c
index 9643195..5cde8657 100644
--- a/dlls/jscript/function.c
+++ b/dlls/jscript/function.c
@@ -307,23 +307,23 @@
     return S_OK;
 }
 
-HRESULT Function_invoke(jsdisp_t *func_this, WORD flags, DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei)
+HRESULT Function_invoke(jsdisp_t *func_this, IDispatch *jsthis, WORD flags, DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei)
 {
     FunctionInstance *function;
 
-    TRACE("\n");
+    TRACE("func %p this %p\n", func_this, jsthis);
 
     assert(is_class(func_this, JSCLASS_FUNCTION));
     function = (FunctionInstance*)func_this;
 
     if(function->value_proc)
-        return invoke_value_proc(function->dispex.ctx, function, get_this(dp), flags, dp, retv, ei);
+        return invoke_value_proc(function->dispex.ctx, function, jsthis, flags, dp, retv, ei);
 
     if(flags == DISPATCH_CONSTRUCT)
         return invoke_constructor(function->dispex.ctx, function, dp, retv, ei);
 
     assert(flags == DISPATCH_METHOD);
-    return invoke_source(function->dispex.ctx, function, get_this(dp), dp, retv, ei);
+    return invoke_source(function->dispex.ctx, function, jsthis, dp, retv, ei);
 }
 
 static HRESULT Function_length(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
diff --git a/dlls/jscript/global.c b/dlls/jscript/global.c
index ae43285..ce1c541 100644
--- a/dlls/jscript/global.c
+++ b/dlls/jscript/global.c
@@ -117,7 +117,7 @@
         VARIANT *retv, jsexcept_t *ei)
 {
     if(flags != DISPATCH_PROPERTYGET)
-        return jsdisp_call_value(constr, flags, dp, retv, ei);
+        return jsdisp_call_value(constr, NULL, flags, dp, retv, ei);
 
     jsdisp_addref(constr);
     var_set_jsdisp(retv, constr);
diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h
index f278b6a..b136651 100644
--- a/dlls/jscript/jscript.h
+++ b/dlls/jscript/jscript.h
@@ -207,7 +207,8 @@
 HRESULT init_dispex_from_constr(jsdisp_t*,script_ctx_t*,const builtin_info_t*,jsdisp_t*) DECLSPEC_HIDDEN;
 
 HRESULT disp_call(script_ctx_t*,IDispatch*,DISPID,WORD,DISPPARAMS*,VARIANT*,jsexcept_t*) DECLSPEC_HIDDEN;
-HRESULT jsdisp_call_value(jsdisp_t*,WORD,DISPPARAMS*,VARIANT*,jsexcept_t*) DECLSPEC_HIDDEN;
+HRESULT disp_call_value(script_ctx_t*,IDispatch*,IDispatch*,WORD,DISPPARAMS*,VARIANT*,jsexcept_t*) DECLSPEC_HIDDEN;
+HRESULT jsdisp_call_value(jsdisp_t*,IDispatch*,WORD,DISPPARAMS*,VARIANT*,jsexcept_t*) DECLSPEC_HIDDEN;
 HRESULT jsdisp_call(jsdisp_t*,DISPID,WORD,DISPPARAMS*,VARIANT*,jsexcept_t*) DECLSPEC_HIDDEN;
 HRESULT jsdisp_call_name(jsdisp_t*,const WCHAR*,WORD,DISPPARAMS*,VARIANT*,jsexcept_t*) DECLSPEC_HIDDEN;
 HRESULT disp_propget(script_ctx_t*,IDispatch*,DISPID,VARIANT*,jsexcept_t*) DECLSPEC_HIDDEN;
@@ -225,7 +226,7 @@
 HRESULT create_builtin_function(script_ctx_t*,builtin_invoke_t,const WCHAR*,const builtin_info_t*,DWORD,
         jsdisp_t*,jsdisp_t**) DECLSPEC_HIDDEN;
 HRESULT Function_value(script_ctx_t*,vdisp_t*,WORD,DISPPARAMS*,VARIANT*,jsexcept_t*) DECLSPEC_HIDDEN;
-HRESULT Function_invoke(jsdisp_t*,WORD,DISPPARAMS*,VARIANT*,jsexcept_t*);
+HRESULT Function_invoke(jsdisp_t*,IDispatch*,WORD,DISPPARAMS*,VARIANT*,jsexcept_t*);
 
 HRESULT throw_eval_error(script_ctx_t*,jsexcept_t*,HRESULT,const WCHAR*) DECLSPEC_HIDDEN;
 HRESULT throw_generic_error(script_ctx_t*,jsexcept_t*,HRESULT,const WCHAR*) DECLSPEC_HIDDEN;
diff --git a/dlls/jscript/string.c b/dlls/jscript/string.c
index 2adc605..1cc2048 100644
--- a/dlls/jscript/string.c
+++ b/dlls/jscript/string.c
@@ -728,7 +728,7 @@
     }
 
     if(SUCCEEDED(hres))
-        hres = jsdisp_call_value(func, DISPATCH_METHOD, &dp, &var, ei);
+        hres = jsdisp_call_value(func, NULL, DISPATCH_METHOD, &dp, &var, ei);
 
     for(i=0; i < parens_cnt+3; i++) {
         if(i != parens_cnt+1)