jscript: Allow 'this' to be host object in builtin functions.
diff --git a/dlls/jscript/array.c b/dlls/jscript/array.c
index 71b526d..b3dc780 100644
--- a/dlls/jscript/array.c
+++ b/dlls/jscript/array.c
@@ -46,24 +46,56 @@
 
 static const WCHAR default_separatorW[] = {',',0};
 
-static HRESULT get_jsdisp_length(script_ctx_t *ctx, DispatchEx *obj, jsexcept_t *ei, DWORD *ret)
+static inline ArrayInstance *array_from_vdisp(vdisp_t *vdisp)
 {
+    return (ArrayInstance*)vdisp->u.jsdisp;
+}
+
+static inline ArrayInstance *array_this(vdisp_t *jsthis)
+{
+    return is_vclass(jsthis, JSCLASS_ARRAY) ? array_from_vdisp(jsthis) : NULL;
+}
+
+static HRESULT get_length(script_ctx_t *ctx, vdisp_t *vdisp, jsexcept_t *ei, DispatchEx **jsthis, DWORD *ret)
+{
+    ArrayInstance *array;
     VARIANT var;
     HRESULT hres;
 
-    hres = jsdisp_propget_name(obj, lengthW, &var, ei, NULL/*FIXME*/);
+    array = array_this(vdisp);
+    if(array) {
+        *jsthis = &array->dispex;
+        *ret = array->length;
+        return S_OK;
+    }
+
+    if(!is_jsdisp(vdisp)) {
+        FIXME("Not JScript object\n");
+        return E_FAIL;
+    }
+
+    hres = jsdisp_propget_name(vdisp->u.jsdisp, lengthW, &var, ei, NULL/*FIXME*/);
     if(FAILED(hres))
         return hres;
 
     hres = to_uint32(ctx, &var, ei, ret);
     VariantClear(&var);
-    return hres;
+    if(FAILED(hres))
+        return hres;
+
+    *jsthis = vdisp->u.jsdisp;
+    return S_OK;
 }
 
-static HRESULT set_jsdisp_length(DispatchEx *obj, jsexcept_t *ei, DWORD length)
+static HRESULT set_length(DispatchEx *obj, jsexcept_t *ei, DWORD length)
 {
     VARIANT var;
 
+    if(is_class(obj, JSCLASS_ARRAY)) {
+        ((ArrayInstance*)obj)->length = length;
+        return S_OK;
+    }
+
     V_VT(&var) = VT_I4;
     V_I4(&var) = length;
     return jsdisp_propput_name(obj, lengthW, &var, ei, NULL/*FIXME*/);
@@ -84,10 +116,10 @@
     return ptr+1;
 }
 
-static HRESULT Array_length(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Array_length(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
-    ArrayInstance *This = (ArrayInstance*)dispex;
+    ArrayInstance *This = array_from_vdisp(jsthis);
 
     TRACE("%p %d\n", This, This->length);
 
@@ -112,7 +144,7 @@
             return throw_range_error(ctx, ei, IDS_INVALID_LENGTH, NULL);
 
         for(i=len; i<This->length; i++) {
-            hres = jsdisp_delete_idx(dispex, i);
+            hres = jsdisp_delete_idx(&This->dispex, i);
             if(FAILED(hres))
                 return hres;
         }
@@ -173,7 +205,7 @@
     return jsdisp_propput_idx(array, (*len)++, &var, ei, caller);
 }
 
-static HRESULT Array_concat(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Array_concat(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
 {
     DispatchEx *ret;
@@ -186,7 +218,7 @@
     if(FAILED(hres))
         return hres;
 
-    hres = concat_obj(ret, (IDispatch*)_IDispatchEx_(dispex), &len, ei, caller);
+    hres = concat_obj(ret, jsthis->u.disp, &len, ei, caller);
     if(SUCCEEDED(hres)) {
         VARIANT *arg;
         DWORD i;
@@ -312,7 +344,7 @@
 }
 
 /* ECMA-262 3rd Edition    15.4.4.5 */
-static HRESULT Array_join(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Array_join(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
 {
     DWORD length;
@@ -320,8 +352,8 @@
 
     TRACE("\n");
 
-    if(is_class(dispex, JSCLASS_ARRAY)) {
-        length = ((ArrayInstance*)dispex)->length;
+    if(is_vclass(jsthis, JSCLASS_ARRAY)) {
+        length = array_from_vdisp(jsthis)->length;
     }else {
         FIXME("dispid is not Array\n");
         return E_NOTIMPL;
@@ -334,17 +366,17 @@
         if(FAILED(hres))
             return hres;
 
-        hres = array_join(ctx, dispex, length, sep, retv, ei, caller);
+        hres = array_join(ctx, jsthis->u.jsdisp, length, sep, retv, ei, caller);
 
         SysFreeString(sep);
     }else {
-        hres = array_join(ctx, dispex, length, default_separatorW, retv, ei, caller);
+        hres = array_join(ctx, jsthis->u.jsdisp, length, default_separatorW, retv, ei, caller);
     }
 
     return hres;
 }
 
-static HRESULT Array_pop(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Array_pop(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
 {
     VARIANT val;
@@ -357,8 +389,8 @@
 
     TRACE("\n");
 
-    if(is_class(dispex, JSCLASS_ARRAY)) {
-        ArrayInstance *array = (ArrayInstance*)dispex;
+    if(is_vclass(jsthis, JSCLASS_ARRAY)) {
+        ArrayInstance *array = array_from_vdisp(jsthis);
         length = array->length;
     }else {
         FIXME("not Array this\n");
@@ -372,13 +404,13 @@
     }
 
     sprintfW(buf, formatW, --length);
-    hres = jsdisp_get_id(dispex, buf, 0, &id);
+    hres = jsdisp_get_id(jsthis->u.jsdisp, buf, 0, &id);
     if(SUCCEEDED(hres)) {
-        hres = jsdisp_propget(dispex, id, &val, ei, caller);
+        hres = jsdisp_propget(jsthis->u.jsdisp, id, &val, ei, caller);
         if(FAILED(hres))
             return hres;
 
-        hres = IDispatchEx_DeleteMemberByDispID(_IDispatchEx_(dispex), id);
+        hres = IDispatchEx_DeleteMemberByDispID(jsthis->u.dispex, id);
     }else if(hres == DISP_E_UNKNOWNNAME) {
         V_VT(&val) = VT_EMPTY;
         hres = S_OK;
@@ -387,10 +419,8 @@
     }
 
     if(SUCCEEDED(hres)) {
-        if(is_class(dispex, JSCLASS_ARRAY)) {
-            ArrayInstance *array = (ArrayInstance*)dispex;
-            array->length = length;
-        }
+        ArrayInstance *array = array_from_vdisp(jsthis);
+        array->length = length;
     }
 
     if(FAILED(hres)) {
@@ -406,35 +436,30 @@
 }
 
 /* ECMA-262 3rd Edition    15.4.4.7 */
-static HRESULT Array_push(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Array_push(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
+    DispatchEx *jsthis;
     DWORD length = 0;
     int i, n;
     HRESULT hres;
 
     TRACE("\n");
 
-    if(dispex->builtin_info->class == JSCLASS_ARRAY) {
-        length = ((ArrayInstance*)dispex)->length;
-    }else {
-        hres = get_jsdisp_length(ctx, dispex, ei, &length);
-        if(FAILED(hres))
-            return hres;
-    }
+    hres = get_length(ctx, vthis, ei, &jsthis, &length);
+    if(FAILED(hres))
+        return hres;
 
     n = arg_cnt(dp);
     for(i=0; i < n; i++) {
-        hres = jsdisp_propput_idx(dispex, length+i, get_arg(dp, i), ei, sp);
+        hres = jsdisp_propput_idx(jsthis, length+i, get_arg(dp, i), ei, sp);
         if(FAILED(hres))
             return hres;
     }
 
-    if(!is_class(dispex, JSCLASS_ARRAY)) {
-        hres = set_jsdisp_length(dispex, ei, length+n);
-        if(FAILED(hres))
-            return hres;
-    }
+    hres = set_length(jsthis, ei, length+n);
+    if(FAILED(hres))
+        return hres;
 
     if(retv) {
         V_VT(retv) = VT_I4;
@@ -443,7 +468,7 @@
     return S_OK;
 }
 
-static HRESULT Array_reverse(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Array_reverse(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     FIXME("\n");
@@ -451,21 +476,22 @@
 }
 
 /* ECMA-262 3rd Edition    15.4.4.9 */
-static HRESULT Array_shift(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Array_shift(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
 {
+    DispatchEx *jsthis;
     DWORD length = 0, i;
     VARIANT v, ret;
     HRESULT hres;
 
     TRACE("\n");
 
-    if(is_class(dispex, JSCLASS_ARRAY)) {
-        length = ((ArrayInstance*)dispex)->length;
-    }else {
-        hres = get_jsdisp_length(ctx, dispex, ei, &length);
-        if(SUCCEEDED(hres) && !length)
-            hres = set_jsdisp_length(dispex, ei, 0);
+    hres = get_length(ctx, vthis, ei, &jsthis, &length);
+    if(FAILED(hres))
+        return hres;
+
+    if(!length) {
+        hres = set_length(jsthis, ei, 0);
         if(FAILED(hres))
             return hres;
     }
@@ -476,24 +502,24 @@
         return S_OK;
     }
 
-    hres = jsdisp_propget_idx(dispex, 0, &ret, ei, caller);
+    hres = jsdisp_propget_idx(jsthis, 0, &ret, ei, caller);
     if(hres == DISP_E_UNKNOWNNAME) {
         V_VT(&ret) = VT_EMPTY;
         hres = S_OK;
     }
 
     for(i=1; SUCCEEDED(hres) && i<length; i++) {
-        hres = jsdisp_propget_idx(dispex, i, &v, ei, caller);
+        hres = jsdisp_propget_idx(jsthis, i, &v, ei, caller);
         if(hres == DISP_E_UNKNOWNNAME)
-            hres = jsdisp_delete_idx(dispex, i-1);
+            hres = jsdisp_delete_idx(jsthis, i-1);
         else if(SUCCEEDED(hres))
-            hres = jsdisp_propput_idx(dispex, i-1, &v, ei, caller);
+            hres = jsdisp_propput_idx(jsthis, i-1, &v, ei, caller);
     }
 
     if(SUCCEEDED(hres)) {
-        hres = jsdisp_delete_idx(dispex, length-1);
+        hres = jsdisp_delete_idx(jsthis, length-1);
         if(SUCCEEDED(hres))
-            hres = set_jsdisp_length(dispex, ei, length-1);
+            hres = set_length(jsthis, ei, length-1);
     }
 
     if(SUCCEEDED(hres) && retv)
@@ -504,10 +530,10 @@
 }
 
 /* ECMA-262 3rd Edition    15.4.4.10 */
-static HRESULT Array_slice(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Array_slice(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
-    DispatchEx *arr;
+    DispatchEx *arr, *jsthis;
     VARIANT v;
     DOUBLE range;
     DWORD length, start, end, idx;
@@ -515,13 +541,9 @@
 
     TRACE("\n");
 
-    if(is_class(dispex, JSCLASS_ARRAY)) {
-        length = ((ArrayInstance*)dispex)->length;
-    }else {
-        hres = get_jsdisp_length(ctx, dispex, ei, &length);
-        if(FAILED(hres))
-            return hres;
-    }
+    hres = get_length(ctx, vthis, ei, &jsthis, &length);
+    if(FAILED(hres))
+        return hres;
 
     if(arg_cnt(dp)) {
         hres = to_number(ctx, get_arg(dp, 0), ei, &v);
@@ -562,7 +584,7 @@
         return hres;
 
     for(idx=start; idx<end; idx++) {
-        hres = jsdisp_propget_idx(dispex, idx, &v, ei, sp);
+        hres = jsdisp_propget_idx(jsthis, idx, &v, ei, sp);
         if(hres == DISP_E_UNKNOWNNAME)
             continue;
 
@@ -641,7 +663,7 @@
 }
 
 /* ECMA-262 3rd Edition    15.4.4.11 */
-static HRESULT Array_sort(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Array_sort(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
 {
     DispatchEx *cmp_func = NULL;
@@ -652,8 +674,8 @@
 
     TRACE("\n");
 
-    if(is_class(dispex, JSCLASS_ARRAY)) {
-        length = ((ArrayInstance*)dispex)->length;
+    if(is_vclass(jsthis, JSCLASS_ARRAY)) {
+        length = array_from_vdisp(jsthis)->length;
     }else {
         FIXME("unsupported this not array\n");
         return E_NOTIMPL;
@@ -687,8 +709,8 @@
             jsdisp_release(cmp_func);
         if(retv) {
             V_VT(retv) = VT_DISPATCH;
-            V_DISPATCH(retv) = (IDispatch*)_IDispatchEx_(dispex);
-	    IDispatchEx_AddRef(_IDispatchEx_(dispex));
+            V_DISPATCH(retv) = jsthis->u.disp;
+	    IDispatch_AddRef(jsthis->u.disp);
         }
         return S_OK;
     }
@@ -696,7 +718,7 @@
     vtab = heap_alloc_zero(length * sizeof(VARIANT));
     if(vtab) {
         for(i=0; i<length; i++) {
-            hres = jsdisp_propget_idx(dispex, i, vtab+i, ei, caller);
+            hres = jsdisp_propget_idx(jsthis->u.jsdisp, i, vtab+i, ei, caller);
             if(FAILED(hres) && hres != DISP_E_UNKNOWNNAME) {
                 WARN("Could not get elem %d: %08x\n", i, hres);
                 break;
@@ -773,7 +795,7 @@
         }
 
         for(i=0; SUCCEEDED(hres) && i < length; i++)
-            hres = jsdisp_propput_idx(dispex, i, sorttab[i], ei, caller);
+            hres = jsdisp_propput_idx(jsthis->u.jsdisp, i, sorttab[i], ei, caller);
     }
 
     if(vtab) {
@@ -790,31 +812,27 @@
 
     if(retv) {
         V_VT(retv) = VT_DISPATCH;
-        V_DISPATCH(retv) = (IDispatch*)_IDispatchEx_(dispex);
-        IDispatch_AddRef(_IDispatchEx_(dispex));
+        V_DISPATCH(retv) = jsthis->u.disp;
+        IDispatch_AddRef(jsthis->u.disp);
     }
 
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.4.4.12 */
-static HRESULT Array_splice(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Array_splice(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
 {
     DWORD length, start=0, delete_cnt=0, argc, i, add_args = 0;
-    DispatchEx *ret_array = NULL;
+    DispatchEx *ret_array = NULL, *jsthis;
     VARIANT v;
     HRESULT hres = S_OK;
 
     TRACE("\n");
 
-    if(is_class(dispex, JSCLASS_ARRAY)) {
-        length = ((ArrayInstance*)dispex)->length;
-    }else {
-        hres = get_jsdisp_length(ctx, dispex, ei, &length);
-        if(FAILED(hres))
-            return hres;
-    }
+    hres = get_length(ctx, vthis, ei, &jsthis, &length);
+    if(FAILED(hres))
+        return hres;
 
     argc = arg_cnt(dp);
     if(argc >= 1) {
@@ -853,7 +871,7 @@
             return hres;
 
         for(i=0; SUCCEEDED(hres) && i < delete_cnt; i++) {
-            hres = jsdisp_propget_idx(dispex, start+i, &v, ei, caller);
+            hres = jsdisp_propget_idx(jsthis, start+i, &v, ei, caller);
             if(hres == DISP_E_UNKNOWNNAME)
                 hres = S_OK;
             else if(SUCCEEDED(hres))
@@ -870,32 +888,32 @@
 
     if(add_args < delete_cnt) {
         for(i = start; SUCCEEDED(hres) && i < length-delete_cnt; i++) {
-            hres = jsdisp_propget_idx(dispex, i+delete_cnt, &v, ei, caller);
+            hres = jsdisp_propget_idx(jsthis, i+delete_cnt, &v, ei, caller);
             if(hres == DISP_E_UNKNOWNNAME)
-                hres = jsdisp_delete_idx(dispex, i+add_args);
+                hres = jsdisp_delete_idx(jsthis, i+add_args);
             else if(SUCCEEDED(hres))
-                hres = jsdisp_propput_idx(dispex, i+add_args, &v, ei, caller);
+                hres = jsdisp_propput_idx(jsthis, i+add_args, &v, ei, caller);
         }
 
         for(i=length; SUCCEEDED(hres) && i != length-delete_cnt+add_args; i--)
-            hres = jsdisp_delete_idx(dispex, i-1);
+            hres = jsdisp_delete_idx(jsthis, i-1);
     }else if(add_args > delete_cnt) {
         for(i=length-delete_cnt; SUCCEEDED(hres) && i != start; i--) {
-            hres = jsdisp_propget_idx(dispex, i+delete_cnt-1, &v, ei, caller);
+            hres = jsdisp_propget_idx(jsthis, i+delete_cnt-1, &v, ei, caller);
             if(hres == DISP_E_UNKNOWNNAME)
-                hres = jsdisp_delete_idx(dispex, i+add_args-1);
+                hres = jsdisp_delete_idx(jsthis, i+add_args-1);
             else if(SUCCEEDED(hres))
-                hres = jsdisp_propput_idx(dispex, i+add_args-1, &v, ei, caller);
+                hres = jsdisp_propput_idx(jsthis, i+add_args-1, &v, ei, caller);
         }
     }
 
     for(i=0; SUCCEEDED(hres) && i < add_args; i++)
-        hres = jsdisp_propput_idx(dispex, start+i, get_arg(dp,i+2), ei, caller);
+        hres = jsdisp_propput_idx(jsthis, start+i, get_arg(dp,i+2), ei, caller);
 
     if(SUCCEEDED(hres)) {
         V_VT(&v) = VT_I4;
         V_I4(&v) = length-delete_cnt+add_args;
-        hres = jsdisp_propput_name(dispex, lengthW, &v, ei, caller);
+        hres = jsdisp_propput_name(jsthis, lengthW, &v, ei, caller);
     }
 
     if(FAILED(hres)) {
@@ -912,20 +930,23 @@
 }
 
 /* ECMA-262 3rd Edition    15.4.4.2 */
-static HRESULT Array_toString(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Array_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
+    ArrayInstance *array;
+
     TRACE("\n");
 
-    if(!is_class(dispex, JSCLASS_ARRAY)) {
-        WARN("not Array object\n");
+    array = array_this(jsthis);
+    if(!array) {
+        FIXME("not Array object\n");
         return E_FAIL;
     }
 
-    return array_join(ctx, dispex, ((ArrayInstance*)dispex)->length, default_separatorW, retv, ei, sp);
+    return array_join(ctx, &array->dispex, array->length, default_separatorW, retv, ei, sp);
 }
 
-static HRESULT Array_toLocaleString(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Array_toLocaleString(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     FIXME("\n");
@@ -933,9 +954,10 @@
 }
 
 /* ECMA-262 3rd Edition    15.4.4.13 */
-static HRESULT Array_unshift(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Array_unshift(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
 {
+    DispatchEx *jsthis;
     WCHAR buf[14], *buf_end, *str;
     DWORD argc, i, length;
     VARIANT var;
@@ -944,13 +966,9 @@
 
     TRACE("\n");
 
-    if(is_class(dispex, JSCLASS_ARRAY)) {
-        length = ((ArrayInstance*)dispex)->length;
-    }else {
-        hres = get_jsdisp_length(ctx, dispex, ei, &length);
-        if(FAILED(hres))
-            return hres;
-    }
+    hres = get_length(ctx, vthis, ei, &jsthis, &length);
+    if(FAILED(hres))
+        return hres;
 
     argc = arg_cnt(dp);
     if(!argc) {
@@ -966,16 +984,16 @@
     while(i--) {
         str = idx_to_str(i, buf_end);
 
-        hres = jsdisp_get_id(dispex, str, 0, &id);
+        hres = jsdisp_get_id(jsthis, str, 0, &id);
         if(SUCCEEDED(hres)) {
-            hres = jsdisp_propget(dispex, id, &var, ei, caller);
+            hres = jsdisp_propget(jsthis, id, &var, ei, caller);
             if(FAILED(hres))
                 return hres;
 
-            hres = jsdisp_propput_idx(dispex, i+argc, &var, ei, caller);
+            hres = jsdisp_propput_idx(jsthis, i+argc, &var, ei, caller);
             VariantClear(&var);
         }else if(hres == DISP_E_UNKNOWNNAME) {
-            hres = IDispatchEx_DeleteMemberByDispID(_IDispatchEx_(dispex), id);
+            hres = IDispatchEx_DeleteMemberByDispID(vthis->u.dispex, id);
         }
 
         if(FAILED(hres))
@@ -983,23 +1001,21 @@
     }
 
     for(i=0; i<argc; i++) {
-        hres = jsdisp_propput_idx(dispex, i, get_arg(dp,i), ei, caller);
+        hres = jsdisp_propput_idx(jsthis, i, get_arg(dp,i), ei, caller);
         if(FAILED(hres))
             return hres;
     }
 
-    if(!is_class(dispex, JSCLASS_ARRAY)) {
-        hres = set_jsdisp_length(dispex, ei, length+argc);
-        if(FAILED(hres))
-            return hres;
-    }
+    hres = set_length(jsthis, ei, length+argc);
+    if(FAILED(hres))
+        return hres;
 
     if(retv)
         V_VT(retv) = VT_EMPTY;
     return S_OK;
 }
 
-static HRESULT Array_value(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Array_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     TRACE("\n");
@@ -1008,7 +1024,7 @@
     case INVOKE_FUNC:
         return throw_type_error(ctx, ei, IDS_NOT_FUNC, NULL);
     case INVOKE_PROPERTYGET:
-        return array_join(ctx, dispex, ((ArrayInstance*)dispex)->length, default_separatorW, retv, ei, sp);
+        return array_join(ctx, jsthis->u.jsdisp, array_from_vdisp(jsthis)->length, default_separatorW, retv, ei, sp);
     default:
         FIXME("unimplemented flags %x\n", flags);
         return E_NOTIMPL;
@@ -1068,7 +1084,7 @@
     Array_on_put
 };
 
-static HRESULT ArrayConstr_value(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT ArrayConstr_value(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
 {
     DispatchEx *obj;
diff --git a/dlls/jscript/bool.c b/dlls/jscript/bool.c
index 998c5d2..1fca406 100644
--- a/dlls/jscript/bool.c
+++ b/dlls/jscript/bool.c
@@ -32,20 +32,26 @@
 static const WCHAR toStringW[] = {'t','o','S','t','r','i','n','g',0};
 static const WCHAR valueOfW[] = {'v','a','l','u','e','O','f',0};
 
+static inline BoolInstance *bool_this(vdisp_t *jsthis)
+{
+    return is_vclass(jsthis, JSCLASS_BOOLEAN) ? (BoolInstance*)jsthis->u.jsdisp : NULL;
+}
+
 /* ECMA-262 3rd Edition    15.6.4.2 */
-static HRESULT Bool_toString(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Bool_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
+    BoolInstance *bool;
+
     static const WCHAR trueW[] = {'t','r','u','e',0};
     static const WCHAR falseW[] = {'f','a','l','s','e',0};
 
     TRACE("\n");
 
-    if(!is_class(dispex, JSCLASS_BOOLEAN))
+    if(!(bool = bool_this(jsthis)))
         return throw_type_error(ctx, ei, IDS_NOT_BOOL, NULL);
 
     if(retv) {
-        BoolInstance *bool = (BoolInstance*)dispex;
         BSTR val;
 
         if(bool->val) val = SysAllocString(trueW);
@@ -62,17 +68,17 @@
 }
 
 /* ECMA-262 3rd Edition    15.6.4.3 */
-static HRESULT Bool_valueOf(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Bool_valueOf(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
+    BoolInstance *bool;
+
     TRACE("\n");
 
-    if(!is_class(dispex, JSCLASS_BOOLEAN))
+    if(!(bool = bool_this(jsthis)))
         return throw_type_error(ctx, ei, IDS_NOT_BOOL, NULL);
 
     if(retv) {
-        BoolInstance *bool = (BoolInstance*)dispex;
-
         V_VT(retv) = VT_BOOL;
         V_BOOL(retv) = bool->val;
     }
@@ -80,7 +86,7 @@
     return S_OK;
 }
 
-static HRESULT Bool_value(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Bool_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     TRACE("\n");
@@ -111,7 +117,7 @@
     NULL
 };
 
-static HRESULT BoolConstr_value(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT BoolConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     HRESULT hres;
diff --git a/dlls/jscript/date.c b/dlls/jscript/date.c
index 7da320b..213d994 100644
--- a/dlls/jscript/date.c
+++ b/dlls/jscript/date.c
@@ -94,6 +94,11 @@
 static const WCHAR UTCW[] = {'U','T','C',0};
 static const WCHAR parseW[] = {'p','a','r','s','e',0};
 
+static inline DateInstance *date_this(vdisp_t *jsthis)
+{
+    return is_vclass(jsthis, JSCLASS_DATE) ? (DateInstance*)jsthis->u.jsdisp : NULL;
+}
+
 /*ECMA-262 3rd Edition    15.9.1.2 */
 #define MS_PER_DAY 86400000
 #define MS_PER_HOUR 3600000
@@ -595,19 +600,21 @@
     return date_to_string(time, TRUE, offset, retv);
 }
 
-static HRESULT Date_toString(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Date_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
 {
+    DateInstance *date;
+
     TRACE("\n");
 
-    if(!is_class(dispex, JSCLASS_DATE))
+    if(!(date = date_this(jsthis)))
         return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
 
-    return dateobj_to_string((DateInstance*)dispex, retv);
+    return dateobj_to_string(date, retv);
 }
 
 /* ECMA-262 3rd Edition    15.9.1.5 */
-static HRESULT Date_toLocaleString(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Date_toLocaleString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
 {
     static const WCHAR NaNW[] = { 'N','a','N',0 };
@@ -618,11 +625,9 @@
 
     TRACE("\n");
 
-    if(!is_class(dispex, JSCLASS_DATE))
+    if(!(date = date_this(jsthis)))
         return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
 
-    date = (DateInstance*)dispex;
-
     if(isnan(date->time)) {
         if(retv) {
             V_VT(retv) = VT_BSTR;
@@ -654,23 +659,23 @@
     return S_OK;
 }
 
-static HRESULT Date_valueOf(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Date_valueOf(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
 {
+    DateInstance *date;
+
     TRACE("\n");
 
-    if(!is_class(dispex, JSCLASS_DATE))
+    if(!(date = date_this(jsthis)))
         return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
 
-    if(retv) {
-        DateInstance *date = (DateInstance*)dispex;
+    if(retv)
         num_set_val(retv, date->time);
-    }
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.9.5.42 */
-static HRESULT Date_toUTCString(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Date_toUTCString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
 {
     static const WCHAR NaNW[] = { 'N','a','N',0 };
@@ -698,11 +703,9 @@
 
     TRACE("\n");
 
-    if(!is_class(dispex, JSCLASS_DATE))
+    if(!(date = date_this(jsthis)))
         return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
 
-    date = (DateInstance*)dispex;
-
     if(isnan(date->time)) {
         if(retv) {
             V_VT(retv) = VT_BSTR;
@@ -875,17 +878,19 @@
     return S_OK;
 }
 
-static HRESULT Date_toDateString(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Date_toDateString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
 {
-    if(!is_class(dispex, JSCLASS_DATE))
+    DateInstance *date;
+
+    if(!(date = date_this(jsthis)))
         return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
 
-    return dateobj_to_date_string((DateInstance*)dispex, retv);
+    return dateobj_to_date_string(date, retv);
 }
 
 /* ECMA-262 3rd Edition    15.9.5.4 */
-static HRESULT Date_toTimeString(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Date_toTimeString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
 {
     static const WCHAR NaNW[] = { 'N','a','N',0 };
@@ -901,11 +906,9 @@
 
     TRACE("\n");
 
-    if(!is_class(dispex, JSCLASS_DATE))
+    if(!(date = date_this(jsthis)))
         return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
 
-    date = (DateInstance*)dispex;
-
     if(isnan(date->time)) {
         if(retv) {
             V_VT(retv) = VT_BSTR;
@@ -947,7 +950,7 @@
 }
 
 /* ECMA-262 3rd Edition    15.9.5.6 */
-static HRESULT Date_toLocaleDateString(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Date_toLocaleDateString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
 {
     static const WCHAR NaNW[] = { 'N','a','N',0 };
@@ -958,11 +961,9 @@
 
     TRACE("\n");
 
-    if(!is_class(dispex, JSCLASS_DATE))
+    if(!(date = date_this(jsthis)))
         return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
 
-    date = (DateInstance*)dispex;
-
     if(isnan(date->time)) {
         if(retv) {
             V_VT(retv) = VT_BSTR;
@@ -992,7 +993,7 @@
 }
 
 /* ECMA-262 3rd Edition    15.9.5.7 */
-static HRESULT Date_toLocaleTimeString(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Date_toLocaleTimeString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
 {
     static const WCHAR NaNW[] = { 'N','a','N',0 };
@@ -1003,11 +1004,9 @@
 
     TRACE("\n");
 
-    if(!is_class(dispex, JSCLASS_DATE))
+    if(!(date = date_this(jsthis)))
         return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
 
-    date = (DateInstance*)dispex;
-
     if(isnan(date->time)) {
         if(retv) {
             V_VT(retv) = VT_BSTR;
@@ -1021,7 +1020,7 @@
     st = create_systemtime(local_time(date->time, date));
 
     if(st.wYear<1601 || st.wYear>9999)
-        return Date_toTimeString(ctx, dispex, flags, dp, retv, ei, caller);
+        return Date_toTimeString(ctx, jsthis, flags, dp, retv, ei, caller);
 
     if(retv) {
         len = GetTimeFormatW(ctx->lcid, 0, &st, NULL, NULL, 0);
@@ -1037,32 +1036,33 @@
 }
 
 /* ECMA-262 3rd Edition    15.9.5.9 */
-static HRESULT Date_getTime(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Date_getTime(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
 {
+    DateInstance *date;
+
     TRACE("\n");
 
-    if(!is_class(dispex, JSCLASS_DATE))
+    if(!(date = date_this(jsthis)))
         return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
 
-    if(retv) {
-        DateInstance *date = (DateInstance*)dispex;
+    if(retv)
         num_set_val(retv, date->time);
-    }
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.9.5.10 */
-static HRESULT Date_getFullYear(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Date_getFullYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
 {
+    DateInstance *date;
+
     TRACE("\n");
 
-    if(!is_class(dispex, JSCLASS_DATE))
+    if(!(date = date_this(jsthis)))
         return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
 
     if(retv) {
-        DateInstance *date = (DateInstance*)dispex;
         DOUBLE time = local_time(date->time, date);
 
         num_set_val(retv, year_from_time(time));
@@ -1071,32 +1071,33 @@
 }
 
 /* ECMA-262 3rd Edition    15.9.5.11 */
-static HRESULT Date_getUTCFullYear(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Date_getUTCFullYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
 {
+    DateInstance *date;
+
     TRACE("\n");
 
-    if(!is_class(dispex, JSCLASS_DATE))
+    if(!(date = date_this(jsthis)))
         return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
 
-    if(retv) {
-        DateInstance *date = (DateInstance*)dispex;
+    if(retv)
         num_set_val(retv, year_from_time(date->time));
-    }
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.9.5.12 */
-static HRESULT Date_getMonth(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Date_getMonth(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
 {
+    DateInstance *date;
+
     TRACE("\n");
 
-    if(!is_class(dispex, JSCLASS_DATE))
+    if(!(date = date_this(jsthis)))
         return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
 
     if(retv) {
-        DateInstance *date = (DateInstance*)dispex;
         DOUBLE time = local_time(date->time, date);
 
         num_set_val(retv, month_from_time(time));
@@ -1105,32 +1106,33 @@
 }
 
 /* ECMA-262 3rd Edition    15.9.5.13 */
-static HRESULT Date_getUTCMonth(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Date_getUTCMonth(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
 {
+    DateInstance *date;
+
     TRACE("\n");
 
-    if(!is_class(dispex, JSCLASS_DATE))
+    if(!(date = date_this(jsthis)))
         return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
 
-    if(retv) {
-        DateInstance *date = (DateInstance*)dispex;
+    if(retv)
         num_set_val(retv, month_from_time(date->time));
-    }
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.9.5.14 */
-static HRESULT Date_getDate(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Date_getDate(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
 {
+    DateInstance *date;
+
     TRACE("\n");
 
-    if(!is_class(dispex, JSCLASS_DATE))
+    if(!(date = date_this(jsthis)))
         return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
 
     if(retv) {
-        DateInstance *date = (DateInstance*)dispex;
         DOUBLE time = local_time(date->time, date);
 
         num_set_val(retv, date_from_time(time));
@@ -1139,32 +1141,33 @@
 }
 
 /* ECMA-262 3rd Edition    15.9.5.15 */
-static HRESULT Date_getUTCDate(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Date_getUTCDate(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
 {
+    DateInstance *date;
+
     TRACE("\n");
 
-    if(!is_class(dispex, JSCLASS_DATE))
+    if(!(date = date_this(jsthis)))
         return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
 
-    if(retv) {
-        DateInstance *date = (DateInstance*)dispex;
+    if(retv)
         num_set_val(retv, date_from_time(date->time));
-    }
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.9.5.16 */
-static HRESULT Date_getDay(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Date_getDay(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
 {
+    DateInstance *date;
+
     TRACE("\n");
 
-    if(!is_class(dispex, JSCLASS_DATE))
+    if(!(date = date_this(jsthis)))
         return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
 
     if(retv) {
-        DateInstance *date = (DateInstance*)dispex;
         DOUBLE time = local_time(date->time, date);
 
         num_set_val(retv, week_day(time));
@@ -1173,32 +1176,33 @@
 }
 
 /* ECMA-262 3rd Edition    15.9.5.17 */
-static HRESULT Date_getUTCDay(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Date_getUTCDay(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
 {
+    DateInstance *date;
+
     TRACE("\n");
 
-    if(!is_class(dispex, JSCLASS_DATE))
+    if(!(date = date_this(jsthis)))
         return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
 
-    if(retv) {
-        DateInstance *date = (DateInstance*)dispex;
+    if(retv)
         num_set_val(retv, week_day(date->time));
-    }
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.9.5.18 */
-static HRESULT Date_getHours(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Date_getHours(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
 {
+    DateInstance *date;
+
     TRACE("\n");
 
-    if(!is_class(dispex, JSCLASS_DATE))
+    if(!(date = date_this(jsthis)))
         return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
 
     if(retv) {
-        DateInstance *date = (DateInstance*)dispex;
         DOUBLE time = local_time(date->time, date);
 
         num_set_val(retv, hour_from_time(time));
@@ -1207,32 +1211,33 @@
 }
 
 /* ECMA-262 3rd Edition    15.9.5.19 */
-static HRESULT Date_getUTCHours(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Date_getUTCHours(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
 {
+    DateInstance *date;
+
     TRACE("\n");
 
-    if(!is_class(dispex, JSCLASS_DATE))
+    if(!(date = date_this(jsthis)))
         return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
 
-    if(retv) {
-        DateInstance *date = (DateInstance*)dispex;
+    if(retv)
         num_set_val(retv, hour_from_time(date->time));
-    }
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.9.5.20 */
-static HRESULT Date_getMinutes(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Date_getMinutes(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
 {
+    DateInstance *date;
+
     TRACE("\n");
 
-    if(!is_class(dispex, JSCLASS_DATE))
+    if(!(date = date_this(jsthis)))
         return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
 
     if(retv) {
-        DateInstance *date = (DateInstance*)dispex;
         DOUBLE time = local_time(date->time, date);
 
         num_set_val(retv, min_from_time(time));
@@ -1241,32 +1246,33 @@
 }
 
 /* ECMA-262 3rd Edition    15.9.5.21 */
-static HRESULT Date_getUTCMinutes(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Date_getUTCMinutes(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
 {
+    DateInstance *date;
+
     TRACE("\n");
 
-    if(!is_class(dispex, JSCLASS_DATE))
+    if(!(date = date_this(jsthis)))
         return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
 
-    if(retv) {
-        DateInstance *date = (DateInstance*)dispex;
+    if(retv)
         num_set_val(retv, min_from_time(date->time));
-    }
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.9.5.22 */
-static HRESULT Date_getSeconds(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Date_getSeconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
 {
+    DateInstance *date;
+
     TRACE("\n");
 
-    if(!is_class(dispex, JSCLASS_DATE))
+    if(!(date = date_this(jsthis)))
         return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
 
     if(retv) {
-        DateInstance *date = (DateInstance*)dispex;
         DOUBLE time = local_time(date->time, date);
 
         num_set_val(retv, sec_from_time(time));
@@ -1275,32 +1281,33 @@
 }
 
 /* ECMA-262 3rd Edition    15.9.5.23 */
-static HRESULT Date_getUTCSeconds(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Date_getUTCSeconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
 {
+    DateInstance *date;
+
     TRACE("\n");
 
-    if(!is_class(dispex, JSCLASS_DATE))
+    if(!(date = date_this(jsthis)))
         return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
 
-    if(retv) {
-        DateInstance *date = (DateInstance*)dispex;
+    if(retv)
         num_set_val(retv, sec_from_time(date->time));
-    }
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.9.5.24 */
-static HRESULT Date_getMilliseconds(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Date_getMilliseconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
 {
+    DateInstance *date;
+
     TRACE("\n");
 
-    if(!is_class(dispex, JSCLASS_DATE))
+    if(!(date = date_this(jsthis)))
         return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
 
     if(retv) {
-        DateInstance *date = (DateInstance*)dispex;
         DOUBLE time = local_time(date->time, date);
 
         num_set_val(retv, ms_from_time(time));
@@ -1309,40 +1316,40 @@
 }
 
 /* ECMA-262 3rd Edition    15.9.5.25 */
-static HRESULT Date_getUTCMilliseconds(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Date_getUTCMilliseconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
 {
+    DateInstance *date;
+
     TRACE("\n");
 
-    if(!is_class(dispex, JSCLASS_DATE))
+    if(!(date = date_this(jsthis)))
         return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
 
-    if(retv) {
-        DateInstance *date = (DateInstance*)dispex;
+    if(retv)
         num_set_val(retv, ms_from_time(date->time));
-    }
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.9.5.26 */
-static HRESULT Date_getTimezoneOffset(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Date_getTimezoneOffset(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
 {
+    DateInstance *date;
+
     TRACE("\n");
 
-    if(!is_class(dispex, JSCLASS_DATE))
+    if(!(date = date_this(jsthis)))
         return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
 
-    if(retv) {
-        DateInstance *date = (DateInstance*)dispex;
+    if(retv)
         num_set_val(retv, floor(
                     (date->time-local_time(date->time, date))/MS_PER_MINUTE));
-    }
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.9.5.27 */
-static HRESULT Date_setTime(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Date_setTime(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
 {
     VARIANT v;
@@ -1351,7 +1358,7 @@
 
     TRACE("\n");
 
-    if(!is_class(dispex, JSCLASS_DATE))
+    if(!(date = date_this(jsthis)))
         return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
 
     if(!arg_cnt(dp))
@@ -1361,7 +1368,6 @@
     if(FAILED(hres))
         return hres;
 
-    date = (DateInstance*)dispex;
     date->time = time_clip(num_val(&v));
 
     if(retv)
@@ -1371,7 +1377,7 @@
 }
 
 /* ECMA-262 3rd Edition    15.9.5.28 */
-static HRESULT Date_setMilliseconds(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Date_setMilliseconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
 {
     VARIANT v;
@@ -1381,7 +1387,7 @@
 
     TRACE("\n");
 
-    if(!is_class(dispex, JSCLASS_DATE))
+    if(!(date = date_this(jsthis)))
         return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
 
     if(!arg_cnt(dp))
@@ -1391,7 +1397,6 @@
     if(FAILED(hres))
         return hres;
 
-    date = (DateInstance*)dispex;
     t = local_time(date->time, date);
     t = make_date(day(t), make_time(hour_from_time(t), min_from_time(t),
                 sec_from_time(t), num_val(&v)));
@@ -1404,7 +1409,7 @@
 }
 
 /* ECMA-262 3rd Edition    15.9.5.29 */
-static HRESULT Date_setUTCMilliseconds(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Date_setUTCMilliseconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
 {
     VARIANT v;
@@ -1414,7 +1419,7 @@
 
     TRACE("\n");
 
-    if(!is_class(dispex, JSCLASS_DATE))
+    if(!(date = date_this(jsthis)))
         return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
 
     if(!arg_cnt(dp))
@@ -1424,7 +1429,6 @@
     if(FAILED(hres))
         return hres;
 
-    date = (DateInstance*)dispex;
     t = date->time;
     t = make_date(day(t), make_time(hour_from_time(t), min_from_time(t),
                 sec_from_time(t), num_val(&v)));
@@ -1437,7 +1441,7 @@
 }
 
 /* ECMA-262 3rd Edition    15.9.5.30 */
-static HRESULT Date_setSeconds(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Date_setSeconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
 {
     VARIANT v;
@@ -1447,13 +1451,12 @@
 
     TRACE("\n");
 
-    if(!is_class(dispex, JSCLASS_DATE))
+    if(!(date = date_this(jsthis)))
         return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
 
     if(!arg_cnt(dp))
         return throw_type_error(ctx, ei, IDS_ARG_NOT_OPT, NULL);
 
-    date = (DateInstance*)dispex;
     t = local_time(date->time, date);
 
     hres = to_number(ctx, get_arg(dp, 0), ei, &v);
@@ -1480,7 +1483,7 @@
 }
 
 /* ECMA-262 3rd Edition    15.9.5.31 */
-static HRESULT Date_setUTCSeconds(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Date_setUTCSeconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
 {
     VARIANT v;
@@ -1490,13 +1493,12 @@
 
     TRACE("\n");
 
-    if(!is_class(dispex, JSCLASS_DATE))
+    if(!(date = date_this(jsthis)))
         return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
 
     if(!arg_cnt(dp))
         return throw_type_error(ctx, ei, IDS_ARG_NOT_OPT, NULL);
 
-    date = (DateInstance*)dispex;
     t = date->time;
 
     hres = to_number(ctx, get_arg(dp, 0), ei, &v);
@@ -1523,7 +1525,7 @@
 }
 
 /* ECMA-262 3rd Edition    15.9.5.33 */
-static HRESULT Date_setMinutes(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Date_setMinutes(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
 {
     VARIANT v;
@@ -1533,13 +1535,12 @@
 
     TRACE("\n");
 
-    if(!is_class(dispex, JSCLASS_DATE))
+    if(!(date = date_this(jsthis)))
         return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
 
     if(!arg_cnt(dp))
         return throw_type_error(ctx, ei, IDS_ARG_NOT_OPT, NULL);
 
-    date = (DateInstance*)dispex;
     t = local_time(date->time, date);
 
     hres = to_number(ctx, get_arg(dp, 0), ei, &v);
@@ -1574,7 +1575,7 @@
 }
 
 /* ECMA-262 3rd Edition    15.9.5.34 */
-static HRESULT Date_setUTCMinutes(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Date_setUTCMinutes(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
 {
     VARIANT v;
@@ -1584,13 +1585,12 @@
 
     TRACE("\n");
 
-    if(!is_class(dispex, JSCLASS_DATE))
+    if(!(date = date_this(jsthis)))
         return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
 
     if(!arg_cnt(dp))
         return throw_type_error(ctx, ei, IDS_ARG_NOT_OPT, NULL);
 
-    date = (DateInstance*)dispex;
     t = date->time;
 
     hres = to_number(ctx, get_arg(dp, 0), ei, &v);
@@ -1625,7 +1625,7 @@
 }
 
 /* ECMA-262 3rd Edition    15.9.5.35 */
-static HRESULT Date_setHours(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Date_setHours(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
 {
     VARIANT v;
@@ -1635,13 +1635,12 @@
 
     TRACE("\n");
 
-    if(!is_class(dispex, JSCLASS_DATE))
+    if(!(date = date_this(jsthis)))
         return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
 
     if(!arg_cnt(dp))
         return throw_type_error(ctx, ei, IDS_ARG_NOT_OPT, NULL);
 
-    date = (DateInstance*)dispex;
     t = local_time(date->time, date);
 
     hres = to_number(ctx, get_arg(dp, 0), ei, &v);
@@ -1683,23 +1682,22 @@
 }
 
 /* ECMA-262 3rd Edition    15.9.5.36 */
-static HRESULT Date_setUTCHours(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Date_setUTCHours(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
 {
+    DateInstance *date;
     VARIANT v;
     HRESULT hres;
-    DateInstance *date;
     DOUBLE t, hour, min, sec, ms;
 
     TRACE("\n");
 
-    if(!is_class(dispex, JSCLASS_DATE))
+    if(!(date = date_this(jsthis)))
         return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
 
     if(!arg_cnt(dp))
         return throw_type_error(ctx, ei, IDS_ARG_NOT_OPT, NULL);
 
-    date = (DateInstance*)dispex;
     t = date->time;
 
     hres = to_number(ctx, get_arg(dp, 0), ei, &v);
@@ -1741,7 +1739,7 @@
 }
 
 /* ECMA-262 3rd Edition    15.9.5.36 */
-static HRESULT Date_setDate(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Date_setDate(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
 {
     VARIANT v;
@@ -1751,7 +1749,7 @@
 
     TRACE("\n");
 
-    if(!is_class(dispex, JSCLASS_DATE))
+    if(!(date = date_this(jsthis)))
         return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
 
     if(!arg_cnt(dp))
@@ -1761,7 +1759,6 @@
     if(FAILED(hres))
         return hres;
 
-    date = (DateInstance*)dispex;
     t = local_time(date->time, date);
     t = make_date(make_day(year_from_time(t), month_from_time(t),
                 num_val(&v)), time_within_day(t));
@@ -1774,7 +1771,7 @@
 }
 
 /* ECMA-262 3rd Edition    15.9.5.37 */
-static HRESULT Date_setUTCDate(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Date_setUTCDate(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
 {
     VARIANT v;
@@ -1784,7 +1781,7 @@
 
     TRACE("\n");
 
-    if(!is_class(dispex, JSCLASS_DATE))
+    if(!(date = date_this(jsthis)))
         return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
 
     if(!arg_cnt(dp))
@@ -1794,7 +1791,6 @@
     if(FAILED(hres))
         return hres;
 
-    date = (DateInstance*)dispex;
     t = date->time;
     t = make_date(make_day(year_from_time(t), month_from_time(t),
                 num_val(&v)), time_within_day(t));
@@ -1807,7 +1803,7 @@
 }
 
 /* ECMA-262 3rd Edition    15.9.5.38 */
-static HRESULT Date_setMonth(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Date_setMonth(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
 {
     VARIANT v;
@@ -1817,13 +1813,12 @@
 
     TRACE("\n");
 
-    if(!is_class(dispex, JSCLASS_DATE))
+    if(!(date = date_this(jsthis)))
         return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
 
     if(!arg_cnt(dp))
         return throw_type_error(ctx, ei, IDS_ARG_NOT_OPT, NULL);
 
-    date = (DateInstance*)dispex;
     t = local_time(date->time, date);
 
     hres = to_number(ctx, get_arg(dp, 0), ei, &v);
@@ -1850,7 +1845,7 @@
 }
 
 /* ECMA-262 3rd Edition    15.9.5.39 */
-static HRESULT Date_setUTCMonth(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Date_setUTCMonth(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
 {
     VARIANT v;
@@ -1860,13 +1855,12 @@
 
     TRACE("\n");
 
-    if(!is_class(dispex, JSCLASS_DATE))
+    if(!(date = date_this(jsthis)))
         return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
 
     if(!arg_cnt(dp))
         return throw_type_error(ctx, ei, IDS_ARG_NOT_OPT, NULL);
 
-    date = (DateInstance*)dispex;
     t = date->time;
 
     hres = to_number(ctx, get_arg(dp, 0), ei, &v);
@@ -1893,7 +1887,7 @@
 }
 
 /* ECMA-262 3rd Edition    15.9.5.40 */
-static HRESULT Date_setFullYear(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Date_setFullYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
 {
     VARIANT v;
@@ -1903,13 +1897,12 @@
 
     TRACE("\n");
 
-    if(!is_class(dispex, JSCLASS_DATE))
+    if(!(date = date_this(jsthis)))
         return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
 
     if(!arg_cnt(dp))
         return throw_type_error(ctx, ei, IDS_ARG_NOT_OPT, NULL);
 
-    date = (DateInstance*)dispex;
     t = local_time(date->time, date);
 
     hres = to_number(ctx, get_arg(dp, 0), ei, &v);
@@ -1943,7 +1936,7 @@
 }
 
 /* ECMA-262 3rd Edition    15.9.5.41 */
-static HRESULT Date_setUTCFullYear(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Date_setUTCFullYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
 {
     VARIANT v;
@@ -1953,13 +1946,12 @@
 
     TRACE("\n");
 
-    if(!is_class(dispex, JSCLASS_DATE))
+    if(!(date = date_this(jsthis)))
         return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
 
     if(!arg_cnt(dp))
         return throw_type_error(ctx, ei, IDS_ARG_NOT_OPT, NULL);
 
-    date = (DateInstance*)dispex;
     t = date->time;
 
     hres = to_number(ctx, get_arg(dp, 0), ei, &v);
@@ -1993,7 +1985,7 @@
 }
 
 /* ECMA-262 3rd Edition    B2.4 */
-static HRESULT Date_getYear(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Date_getYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
 {
     DateInstance *date;
@@ -2001,13 +1993,10 @@
 
     TRACE("\n");
 
-    if(!is_class(dispex, JSCLASS_DATE))
+    if(!(date = date_this(jsthis)))
         return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
 
-    date = (DateInstance*)dispex;
     t = local_time(date->time, date);
-
-
     if(isnan(t)) {
         if(retv)
             num_set_nan(retv);
@@ -2021,7 +2010,7 @@
     return S_OK;
 }
 
-static HRESULT Date_value(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Date_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
 {
     TRACE("\n");
@@ -2383,7 +2372,7 @@
     return S_OK;
 }
 
-static HRESULT DateConstr_parse(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT DateConstr_parse(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     BSTR parse_str;
@@ -2497,7 +2486,7 @@
     return S_OK;
 }
 
-static HRESULT DateConstr_UTC(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT DateConstr_UTC(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     TRACE("\n");
@@ -2505,7 +2494,7 @@
     return date_utc(ctx, dp, retv, ei);
 }
 
-static HRESULT DateConstr_value(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT DateConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     DispatchEx *date;
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c
index 921b4ad..307efd9 100644
--- a/dlls/jscript/dispex.c
+++ b/dlls/jscript/dispex.c
@@ -245,12 +245,19 @@
     HRESULT hres;
 
     switch(prop->type) {
-    case PROP_BUILTIN:
+    case PROP_BUILTIN: {
+        vdisp_t vthis;
+
         if(flags == DISPATCH_CONSTRUCT && (prop->flags & DISPATCH_METHOD)) {
             WARN("%s is not a constructor\n", debugstr_w(prop->name));
             return E_INVALIDARG;
         }
-        return prop->u.p->invoke(This->ctx, jsthis, flags, dp, retv, ei, caller);
+
+        set_jsdisp(&vthis, jsthis);
+        hres = prop->u.p->invoke(This->ctx, &vthis, flags, dp, retv, ei, caller);
+        vdisp_release(&vthis);
+        return hres;
+    }
     case PROP_PROTREF:
         return invoke_prop_func(This->prototype, jsthis, This->prototype->props+prop->u.ref, flags, dp, retv, ei, caller);
     case PROP_VARIANT: {
@@ -304,7 +311,11 @@
 
             hres = VariantCopy(retv, &prop->u.var);
         }else {
-            hres = prop->u.p->invoke(This->ctx, This, DISPATCH_PROPERTYGET, dp, retv, ei, caller);
+            vdisp_t vthis;
+
+            set_jsdisp(&vthis, This);
+            hres = prop->u.p->invoke(This->ctx, &vthis, DISPATCH_PROPERTYGET, dp, retv, ei, caller);
+            vdisp_release(&vthis);
         }
         break;
     case PROP_PROTREF:
@@ -335,8 +346,14 @@
 
     switch(prop->type) {
     case PROP_BUILTIN:
-        if(!(prop->flags & PROPF_METHOD))
-            return prop->u.p->invoke(This->ctx, This, DISPATCH_PROPERTYPUT, dp, NULL, ei, caller);
+        if(!(prop->flags & PROPF_METHOD)) {
+            vdisp_t vthis;
+
+            set_jsdisp(&vthis, This);
+            hres = prop->u.p->invoke(This->ctx, &vthis, DISPATCH_PROPERTYPUT, dp, NULL, ei, caller);
+            vdisp_release(&vthis);
+            return hres;
+        }
     case PROP_PROTREF:
         prop->type = PROP_VARIANT;
         prop->flags = PROPF_ENUM;
@@ -823,10 +840,16 @@
     return DISP_E_UNKNOWNNAME;
 }
 
-HRESULT jsdisp_call_value(DispatchEx *disp, WORD flags, DISPPARAMS *dp, VARIANT *retv,
+HRESULT jsdisp_call_value(DispatchEx *jsthis, WORD flags, DISPPARAMS *dp, VARIANT *retv,
         jsexcept_t *ei, IServiceProvider *caller)
 {
-    return disp->builtin_info->value_prop.invoke(disp->ctx, disp, flags, dp, retv, ei, caller);
+    vdisp_t vdisp;
+    HRESULT hres;
+
+    set_jsdisp(&vdisp, jsthis);
+    hres = jsthis->builtin_info->value_prop.invoke(jsthis->ctx, &vdisp, flags, dp, retv, ei, caller);
+    vdisp_release(&vdisp);
+    return hres;
 }
 
 HRESULT jsdisp_call(DispatchEx *disp, DISPID id, WORD flags, DISPPARAMS *dp, VARIANT *retv,
diff --git a/dlls/jscript/error.c b/dlls/jscript/error.c
index 5932611..91bc95a 100644
--- a/dlls/jscript/error.c
+++ b/dlls/jscript/error.c
@@ -39,10 +39,15 @@
 static const WCHAR numberW[] = {'n','u','m','b','e','r',0};
 static const WCHAR toStringW[] = {'t','o','S','t','r','i','n','g',0};
 
-static HRESULT Error_number(script_ctx_t *ctx, DispatchEx *dispex, WORD flags,
+static inline ErrorInstance *error_from_vdisp(vdisp_t *vdisp)
+{
+    return (ErrorInstance*)vdisp->u.jsdisp;
+}
+
+static HRESULT Error_number(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
         DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
-    ErrorInstance *This = (ErrorInstance*)dispex;
+    ErrorInstance *This = error_from_vdisp(jsthis);
 
     TRACE("\n");
 
@@ -57,10 +62,10 @@
     }
 }
 
-static HRESULT Error_description(script_ctx_t *ctx, DispatchEx *dispex, WORD flags,
+static HRESULT Error_description(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
         DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
-    ErrorInstance *This = (ErrorInstance*)dispex;
+    ErrorInstance *This = error_from_vdisp(jsthis);
 
     TRACE("\n");
 
@@ -76,10 +81,10 @@
 }
 
 /* ECMA-262 3rd Edition    15.11.4.3 */
-static HRESULT Error_message(script_ctx_t *ctx, DispatchEx *dispex, WORD flags,
+static HRESULT Error_message(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
         DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
-    ErrorInstance *This = (ErrorInstance*)dispex;
+    ErrorInstance *This = error_from_vdisp(jsthis);
 
     TRACE("\n");
 
@@ -95,7 +100,7 @@
 }
 
 /* ECMA-262 3rd Edition    15.11.4.4 */
-static HRESULT Error_toString(script_ctx_t *ctx, DispatchEx *dispex, WORD flags,
+static HRESULT Error_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
         DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     static const WCHAR str[] = {'[','o','b','j','e','c','t',' ','E','r','r','o','r',']',0};
@@ -112,7 +117,7 @@
     return S_OK;
 }
 
-static HRESULT Error_value(script_ctx_t *ctx, DispatchEx *dispex, WORD flags,
+static HRESULT Error_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
         DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     TRACE("\n");
@@ -278,56 +283,56 @@
     }
 }
 
-static HRESULT ErrorConstr_value(script_ctx_t *ctx, DispatchEx *dispex, WORD flags,
+static HRESULT ErrorConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
         DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     TRACE("\n");
     return error_constr(ctx, flags, dp, retv, ei, ctx->error_constr);
 }
 
-static HRESULT EvalErrorConstr_value(script_ctx_t *ctx, DispatchEx *dispex, WORD flags,
+static HRESULT EvalErrorConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
         DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     TRACE("\n");
     return error_constr(ctx, flags, dp, retv, ei, ctx->eval_error_constr);
 }
 
-static HRESULT RangeErrorConstr_value(script_ctx_t *ctx, DispatchEx *dispex, WORD flags,
+static HRESULT RangeErrorConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
         DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     TRACE("\n");
     return error_constr(ctx, flags, dp, retv, ei, ctx->range_error_constr);
 }
 
-static HRESULT ReferenceErrorConstr_value(script_ctx_t *ctx, DispatchEx *dispex, WORD flags,
+static HRESULT ReferenceErrorConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
         DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     TRACE("\n");
     return error_constr(ctx, flags, dp, retv, ei, ctx->reference_error_constr);
 }
 
-static HRESULT RegExpErrorConstr_value(script_ctx_t *ctx, DispatchEx *dispex, WORD flags,
+static HRESULT RegExpErrorConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
         DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     TRACE("\n");
     return error_constr(ctx, flags, dp, retv, ei, ctx->regexp_error_constr);
 }
 
-static HRESULT SyntaxErrorConstr_value(script_ctx_t *ctx, DispatchEx *dispex, WORD flags,
+static HRESULT SyntaxErrorConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
         DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     TRACE("\n");
     return error_constr(ctx, flags, dp, retv, ei, ctx->syntax_error_constr);
 }
 
-static HRESULT TypeErrorConstr_value(script_ctx_t *ctx, DispatchEx *dispex, WORD flags,
+static HRESULT TypeErrorConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
         DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     TRACE("\n");
     return error_constr(ctx, flags, dp, retv, ei, ctx->type_error_constr);
 }
 
-static HRESULT URIErrorConstr_value(script_ctx_t *ctx, DispatchEx *dispex, WORD flags,
+static HRESULT URIErrorConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
         DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     TRACE("\n");
diff --git a/dlls/jscript/function.c b/dlls/jscript/function.c
index bd7c99b..e68222b 100644
--- a/dlls/jscript/function.c
+++ b/dlls/jscript/function.c
@@ -37,6 +37,16 @@
     DWORD length;
 } FunctionInstance;
 
+static inline FunctionInstance *function_from_vdisp(vdisp_t *vdisp)
+{
+    return (FunctionInstance*)vdisp->u.jsdisp;
+}
+
+static inline FunctionInstance *function_this(vdisp_t *jsthis)
+{
+    return is_vclass(jsthis, JSCLASS_FUNCTION) ? function_from_vdisp(jsthis) : NULL;
+}
+
 static const WCHAR prototypeW[] = {'p','r','o','t','o','t', 'y', 'p','e',0};
 
 static const WCHAR lengthW[] = {'l','e','n','g','t','h',0};
@@ -85,7 +95,7 @@
     return S_OK;
 }
 
-static HRESULT Arguments_value(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Arguments_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
 {
     FIXME("\n");
@@ -249,14 +259,16 @@
 {
     DispatchEx *this_obj = NULL;
     IDispatch *this_disp;
+    vdisp_t vthis;
     HRESULT hres;
 
     this_disp = get_this(dp);
     if(this_disp)
         this_obj = iface_to_jsdisp((IUnknown*)this_disp);
 
-    hres = function->value_proc(ctx, this_obj ? this_obj : ctx->script_disp,
-            flags, dp, retv, ei, caller);
+    set_jsdisp(&vthis, this_obj ? this_obj : ctx->script_disp);
+    hres = function->value_proc(ctx, &vthis, flags, dp, retv, ei, caller);
+    vdisp_release(&vthis);
 
     if(this_obj)
         jsdisp_release(this_obj);
@@ -270,6 +282,7 @@
 
     if(function->value_proc) {
         DispatchEx *jsthis = NULL;
+        vdisp_t vthis;
 
         if(this_obj) {
             jsthis = iface_to_jsdisp((IUnknown*)this_obj);
@@ -277,8 +290,9 @@
                 FIXME("this_obj is not DispatchEx\n");
         }
 
-        hres = function->value_proc(ctx, jsthis ? jsthis : ctx->script_disp,
-                DISPATCH_METHOD, args, retv, ei, caller);
+        set_jsdisp(&vthis, jsthis ? jsthis : ctx->script_disp);
+        hres = function->value_proc(ctx, &vthis, DISPATCH_METHOD, args, retv, ei, caller);
+        vdisp_release(&vthis);
 
         if(jsthis)
             jsdisp_release(jsthis);
@@ -319,10 +333,10 @@
     return S_OK;
 }
 
-static HRESULT Function_length(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Function_length(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
-    FunctionInstance *This = (FunctionInstance*)dispex;
+    FunctionInstance *This = function_from_vdisp(jsthis);
 
     TRACE("%p %d\n", This, This->length);
 
@@ -339,7 +353,7 @@
     return S_OK;
 }
 
-static HRESULT Function_toString(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Function_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     FunctionInstance *function;
@@ -348,11 +362,9 @@
 
     TRACE("\n");
 
-    if(!is_class(dispex, JSCLASS_FUNCTION))
+    if(!(function = function_this(jsthis)))
         return throw_type_error(ctx, ei, IDS_NOT_FUNC, NULL);
 
-    function = (FunctionInstance*)dispex;
-
     hres = function_to_string(function, &str);
     if(FAILED(hres))
         return hres;
@@ -401,7 +413,7 @@
     return S_OK;
 }
 
-static HRESULT Function_apply(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Function_apply(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
 {
     FunctionInstance *function;
@@ -412,12 +424,11 @@
 
     TRACE("\n");
 
-    if(!is_class(dispex, JSCLASS_FUNCTION)) {
+    if(!(function = function_from_vdisp(jsthis))) {
         FIXME("dispex is not a function\n");
         return E_FAIL;
     }
 
-    function = (FunctionInstance*)dispex;
     argc = arg_cnt(dp);
 
     if(argc) {
@@ -457,7 +468,7 @@
     return hres;
 }
 
-static HRESULT Function_call(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Function_call(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
 {
     FunctionInstance *function;
@@ -468,14 +479,12 @@
 
     TRACE("\n");
 
-    if(!is_class(dispex, JSCLASS_FUNCTION)) {
+    if(!(function = function_from_vdisp(jsthis))) {
         FIXME("dispex is not a function\n");
         return E_FAIL;
     }
 
-    function = (FunctionInstance*)dispex;
     argc = arg_cnt(dp);
-
     if(argc) {
         hres = to_object(ctx, get_arg(dp,0), &this_obj);
         if(FAILED(hres))
@@ -493,19 +502,19 @@
     return hres;
 }
 
-HRESULT Function_value(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+HRESULT Function_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
 {
     FunctionInstance *function;
 
     TRACE("\n");
 
-    if(dispex->builtin_info->class != JSCLASS_FUNCTION) {
+    if(!is_vclass(jsthis, JSCLASS_FUNCTION)) {
         ERR("dispex is not a function\n");
         return E_FAIL;
     }
 
-    function = (FunctionInstance*)dispex;
+    function = (FunctionInstance*)jsthis->u.jsdisp;
 
     switch(flags) {
     case DISPATCH_METHOD:
@@ -568,14 +577,14 @@
     NULL
 };
 
-static HRESULT FunctionConstr_value(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT FunctionConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     FIXME("\n");
     return E_NOTIMPL;
 }
 
-static HRESULT FunctionProt_value(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT FunctionProt_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     FIXME("\n");
diff --git a/dlls/jscript/global.c b/dlls/jscript/global.c
index 9c9deea..d9c54db 100644
--- a/dlls/jscript/global.c
+++ b/dlls/jscript/global.c
@@ -115,7 +115,7 @@
     return S_OK;
 }
 
-static HRESULT JSGlobal_NaN(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT JSGlobal_NaN(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     TRACE("\n");
@@ -133,7 +133,7 @@
     return S_OK;
 }
 
-static HRESULT JSGlobal_Infinity(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT JSGlobal_Infinity(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     TRACE("\n");
@@ -151,7 +151,7 @@
     return S_OK;
 }
 
-static HRESULT JSGlobal_Array(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT JSGlobal_Array(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     TRACE("\n");
@@ -159,7 +159,7 @@
     return constructor_call(ctx->array_constr, flags, dp, retv, ei, sp);
 }
 
-static HRESULT JSGlobal_Boolean(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT JSGlobal_Boolean(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     TRACE("\n");
@@ -167,7 +167,7 @@
     return constructor_call(ctx->bool_constr, flags, dp, retv, ei, sp);
 }
 
-static HRESULT JSGlobal_Date(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT JSGlobal_Date(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     TRACE("\n");
@@ -175,7 +175,7 @@
     return constructor_call(ctx->date_constr, flags, dp, retv, ei, sp);
 }
 
-static HRESULT JSGlobal_Error(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT JSGlobal_Error(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     TRACE("\n");
@@ -183,7 +183,7 @@
     return constructor_call(ctx->error_constr, flags, dp, retv, ei, sp);
 }
 
-static HRESULT JSGlobal_EvalError(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT JSGlobal_EvalError(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     TRACE("\n");
@@ -191,7 +191,7 @@
     return constructor_call(ctx->eval_error_constr, flags, dp, retv, ei, sp);
 }
 
-static HRESULT JSGlobal_RangeError(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT JSGlobal_RangeError(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     TRACE("\n");
@@ -199,7 +199,7 @@
     return constructor_call(ctx->range_error_constr, flags, dp, retv, ei, sp);
 }
 
-static HRESULT JSGlobal_ReferenceError(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT JSGlobal_ReferenceError(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     TRACE("\n");
@@ -207,7 +207,7 @@
     return constructor_call(ctx->reference_error_constr, flags, dp, retv, ei, sp);
 }
 
-static HRESULT JSGlobal_SyntaxError(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT JSGlobal_SyntaxError(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     TRACE("\n");
@@ -215,7 +215,7 @@
     return constructor_call(ctx->syntax_error_constr, flags, dp, retv, ei, sp);
 }
 
-static HRESULT JSGlobal_TypeError(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT JSGlobal_TypeError(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     TRACE("\n");
@@ -223,7 +223,7 @@
     return constructor_call(ctx->type_error_constr, flags, dp, retv, ei, sp);
 }
 
-static HRESULT JSGlobal_URIError(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT JSGlobal_URIError(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     TRACE("\n");
@@ -231,7 +231,7 @@
     return constructor_call(ctx->uri_error_constr, flags, dp, retv, ei, sp);
 }
 
-static HRESULT JSGlobal_Function(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT JSGlobal_Function(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     TRACE("\n");
@@ -239,7 +239,7 @@
     return constructor_call(ctx->function_constr, flags, dp, retv, ei, sp);
 }
 
-static HRESULT JSGlobal_Number(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT JSGlobal_Number(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     TRACE("\n");
@@ -247,7 +247,7 @@
     return constructor_call(ctx->number_constr, flags, dp, retv, ei, sp);
 }
 
-static HRESULT JSGlobal_Object(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT JSGlobal_Object(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     TRACE("\n");
@@ -255,7 +255,7 @@
     return constructor_call(ctx->object_constr, flags, dp, retv, ei, sp);
 }
 
-static HRESULT JSGlobal_String(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT JSGlobal_String(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     TRACE("\n");
@@ -263,7 +263,7 @@
     return constructor_call(ctx->string_constr, flags, dp, retv, ei, sp);
 }
 
-static HRESULT JSGlobal_RegExp(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT JSGlobal_RegExp(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     TRACE("\n");
@@ -271,28 +271,28 @@
     return constructor_call(ctx->regexp_constr, flags, dp, retv, ei, sp);
 }
 
-static HRESULT JSGlobal_ActiveXObject(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT JSGlobal_ActiveXObject(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     FIXME("\n");
     return E_NOTIMPL;
 }
 
-static HRESULT JSGlobal_VBArray(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT JSGlobal_VBArray(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     FIXME("\n");
     return E_NOTIMPL;
 }
 
-static HRESULT JSGlobal_Enumerator(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT JSGlobal_Enumerator(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     FIXME("\n");
     return E_NOTIMPL;
 }
 
-static HRESULT JSGlobal_escape(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT JSGlobal_escape(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     FIXME("\n");
@@ -300,7 +300,7 @@
 }
 
 /* ECMA-262 3rd Edition    15.1.2.1 */
-static HRESULT JSGlobal_eval(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT JSGlobal_eval(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     parser_ctx_t *parser_ctx;
@@ -342,7 +342,7 @@
     return hres;
 }
 
-static HRESULT JSGlobal_isNaN(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT JSGlobal_isNaN(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     VARIANT_BOOL ret = VARIANT_FALSE;
@@ -369,7 +369,7 @@
     return S_OK;
 }
 
-static HRESULT JSGlobal_isFinite(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT JSGlobal_isFinite(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     VARIANT_BOOL ret = VARIANT_FALSE;
@@ -406,7 +406,7 @@
     return 100;
 }
 
-static HRESULT JSGlobal_parseInt(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT JSGlobal_parseInt(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     DOUBLE ret = 0.0;
@@ -474,7 +474,7 @@
     return S_OK;
 }
 
-static HRESULT JSGlobal_parseFloat(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT JSGlobal_parseFloat(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     LONGLONG d = 0, hlp;
@@ -582,7 +582,7 @@
     return -1;
 }
 
-static HRESULT JSGlobal_unescape(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT JSGlobal_unescape(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     BSTR ret, str;
@@ -657,49 +657,49 @@
     return S_OK;
 }
 
-static HRESULT JSGlobal_GetObject(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT JSGlobal_GetObject(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     FIXME("\n");
     return E_NOTIMPL;
 }
 
-static HRESULT JSGlobal_ScriptEngine(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT JSGlobal_ScriptEngine(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     FIXME("\n");
     return E_NOTIMPL;
 }
 
-static HRESULT JSGlobal_ScriptEngineMajorVersion(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT JSGlobal_ScriptEngineMajorVersion(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     FIXME("\n");
     return E_NOTIMPL;
 }
 
-static HRESULT JSGlobal_ScriptEngineMinorVersion(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT JSGlobal_ScriptEngineMinorVersion(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     FIXME("\n");
     return E_NOTIMPL;
 }
 
-static HRESULT JSGlobal_ScriptEngineBuildVersion(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT JSGlobal_ScriptEngineBuildVersion(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     FIXME("\n");
     return E_NOTIMPL;
 }
 
-static HRESULT JSGlobal_CollectGarbage(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT JSGlobal_CollectGarbage(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     FIXME("\n");
     return E_NOTIMPL;
 }
 
-static HRESULT JSGlobal_encodeURI(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT JSGlobal_encodeURI(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     const WCHAR *ptr;
diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h
index c817821..8f9873c 100644
--- a/dlls/jscript/jscript.h
+++ b/dlls/jscript/jscript.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008 Jacek Caban for CodeWeavers
+ * Copyright 2008-2009 Jacek Caban for CodeWeavers
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -86,7 +86,73 @@
     JSCLASS_ARGUMENTS
 } jsclass_t;
 
-typedef HRESULT (*builtin_invoke_t)(script_ctx_t*,DispatchEx*,WORD,DISPPARAMS*,VARIANT*,jsexcept_t*,IServiceProvider*);
+DispatchEx *iface_to_jsdisp(IUnknown*);
+
+typedef struct {
+    union {
+        IDispatch *disp;
+        IDispatchEx *dispex;
+        DispatchEx *jsdisp;
+    } u;
+    DWORD flags;
+} vdisp_t;
+
+#define VDISP_DISPEX  0x0001
+#define VDISP_JSDISP  0x0002
+
+static inline void vdisp_release(vdisp_t *vdisp)
+{
+    IDispatch_Release(vdisp->u.disp);
+}
+
+static inline BOOL is_jsdisp(vdisp_t *vdisp)
+{
+    return (vdisp->flags & VDISP_JSDISP) != 0;
+}
+
+static inline BOOL is_dispex(vdisp_t *vdisp)
+{
+    return (vdisp->flags & VDISP_DISPEX) != 0;
+}
+
+static inline void set_jsdisp(vdisp_t *vdisp, DispatchEx *jsdisp)
+{
+    vdisp->u.jsdisp = jsdisp;
+    vdisp->flags = VDISP_JSDISP | VDISP_DISPEX;
+    IDispatch_AddRef(vdisp->u.disp);
+}
+
+static inline void set_disp(vdisp_t *vdisp, IDispatch *disp)
+{
+    IDispatchEx *dispex;
+    DispatchEx *jsdisp;
+    HRESULT hres;
+
+    jsdisp = iface_to_jsdisp((IUnknown*)disp);
+    if(jsdisp) {
+        vdisp->u.jsdisp = jsdisp;
+        vdisp->flags = VDISP_JSDISP | VDISP_DISPEX;
+        return;
+    }
+
+    hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
+    if(SUCCEEDED(hres)) {
+        vdisp->u.dispex = dispex;
+        vdisp->flags = VDISP_DISPEX;
+        return;
+    }
+
+    IDispatch_AddRef(disp);
+    vdisp->u.disp = disp;
+    vdisp->flags = 0;
+}
+
+static inline DispatchEx *get_jsdisp(vdisp_t *vdisp)
+{
+    return is_jsdisp(vdisp) ? vdisp->u.jsdisp : NULL;
+}
+
+typedef HRESULT (*builtin_invoke_t)(script_ctx_t*,vdisp_t*,WORD,DISPPARAMS*,VARIANT*,jsexcept_t*,IServiceProvider*);
 
 typedef struct {
     const WCHAR *name;
@@ -128,7 +194,6 @@
 HRESULT create_dispex(script_ctx_t*,const builtin_info_t*,DispatchEx*,DispatchEx**);
 HRESULT init_dispex(DispatchEx*,script_ctx_t*,const builtin_info_t*,DispatchEx*);
 HRESULT init_dispex_from_constr(DispatchEx*,script_ctx_t*,const builtin_info_t*,DispatchEx*);
-DispatchEx *iface_to_jsdisp(IUnknown*);
 
 HRESULT disp_call(script_ctx_t*,IDispatch*,DISPID,WORD,DISPPARAMS*,VARIANT*,jsexcept_t*,IServiceProvider*);
 HRESULT jsdisp_call_value(DispatchEx*,WORD,DISPPARAMS*,VARIANT*,jsexcept_t*,IServiceProvider*);
@@ -146,7 +211,7 @@
 
 HRESULT create_builtin_function(script_ctx_t*,builtin_invoke_t,const WCHAR*,const builtin_info_t*,DWORD,
         DispatchEx*,DispatchEx**);
-HRESULT Function_value(script_ctx_t*,DispatchEx*,WORD,DISPPARAMS*,VARIANT*,jsexcept_t*,IServiceProvider*);
+HRESULT Function_value(script_ctx_t*,vdisp_t*,WORD,DISPPARAMS*,VARIANT*,jsexcept_t*,IServiceProvider*);
 
 HRESULT throw_eval_error(script_ctx_t*,jsexcept_t*,UINT,const WCHAR*);
 HRESULT throw_range_error(script_ctx_t*,jsexcept_t*,UINT,const WCHAR*);
@@ -263,6 +328,11 @@
     return jsdisp->builtin_info->class == class;
 }
 
+static inline BOOL is_vclass(vdisp_t *vdisp, jsclass_t class)
+{
+    return is_jsdisp(vdisp) && is_class(vdisp->u.jsdisp, class);
+}
+
 static inline BOOL is_num_vt(enum VARENUM vt)
 {
     return vt == VT_I4 || vt == VT_R8;
diff --git a/dlls/jscript/math.c b/dlls/jscript/math.c
index a0a75af..8de9df9 100644
--- a/dlls/jscript/math.c
+++ b/dlls/jscript/math.c
@@ -73,7 +73,7 @@
 }
 
 /* ECMA-262 3rd Edition    15.8.1.1 */
-static HRESULT Math_E(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Math_E(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     TRACE("\n");
@@ -81,7 +81,7 @@
 }
 
 /* ECMA-262 3rd Edition    15.8.1.4 */
-static HRESULT Math_LOG2E(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Math_LOG2E(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     TRACE("\n");
@@ -89,21 +89,21 @@
 }
 
 /* ECMA-262 3rd Edition    15.8.1.4 */
-static HRESULT Math_LOG10E(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Math_LOG10E(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     TRACE("\n");
     return math_constant(M_LOG10E, flags, retv);
 }
 
-static HRESULT Math_LN2(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Math_LN2(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     TRACE("\n");
     return math_constant(M_LN2, flags, retv);
 }
 
-static HRESULT Math_LN10(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Math_LN10(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     TRACE("\n");
@@ -111,21 +111,21 @@
 }
 
 /* ECMA-262 3rd Edition    15.8.1.6 */
-static HRESULT Math_PI(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Math_PI(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     TRACE("\n");
     return math_constant(M_PI, flags, retv);
 }
 
-static HRESULT Math_SQRT2(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Math_SQRT2(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     TRACE("\n");
     return math_constant(M_SQRT2, flags, retv);
 }
 
-static HRESULT Math_SQRT1_2(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Math_SQRT1_2(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     TRACE("\n");
@@ -133,7 +133,7 @@
 }
 
 /* ECMA-262 3rd Edition    15.8.2.12 */
-static HRESULT Math_abs(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Math_abs(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     VARIANT v;
@@ -158,7 +158,7 @@
     return S_OK;
 }
 
-static HRESULT Math_acos(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Math_acos(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     VARIANT v;
@@ -179,7 +179,7 @@
     return S_OK;
 }
 
-static HRESULT Math_asin(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Math_asin(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     VARIANT v;
@@ -200,7 +200,7 @@
     return S_OK;
 }
 
-static HRESULT Math_atan(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Math_atan(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     VARIANT v;
@@ -221,7 +221,7 @@
     return S_OK;
 }
 
-static HRESULT Math_atan2(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Math_atan2(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     VARIANT v1, v2;
@@ -247,7 +247,7 @@
 }
 
 /* ECMA-262 3rd Edition    15.8.2.6 */
-static HRESULT Math_ceil(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Math_ceil(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     VARIANT v;
@@ -270,7 +270,7 @@
     return S_OK;
 }
 
-static HRESULT Math_cos(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Math_cos(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     VARIANT v;
@@ -291,7 +291,7 @@
     return S_OK;
 }
 
-static HRESULT Math_exp(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Math_exp(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     VARIANT v;
@@ -312,7 +312,7 @@
     return S_OK;
 }
 
-static HRESULT Math_floor(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Math_floor(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     VARIANT v;
@@ -335,7 +335,7 @@
     return S_OK;
 }
 
-static HRESULT Math_log(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Math_log(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     VARIANT v;
@@ -359,7 +359,7 @@
 }
 
 /* ECMA-262 3rd Edition    15.8.2.11 */
-static HRESULT Math_max(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Math_max(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     DOUBLE max, d;
@@ -396,7 +396,7 @@
 }
 
 /* ECMA-262 3rd Edition    15.8.2.12 */
-static HRESULT Math_min(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Math_min(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     DOUBLE min, d;
@@ -433,7 +433,7 @@
 }
 
 /* ECMA-262 3rd Edition    15.8.2.13 */
-static HRESULT Math_pow(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Math_pow(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     VARIANT x, y;
@@ -460,7 +460,7 @@
 }
 
 /* ECMA-262 3rd Edition    15.8.2.14 */
-static HRESULT Math_random(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Math_random(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     UINT r;
@@ -477,7 +477,7 @@
 }
 
 /* ECMA-262 3rd Edition    15.8.2.15 */
-static HRESULT Math_round(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Math_round(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     VARIANT v;
@@ -499,7 +499,7 @@
     return S_OK;
 }
 
-static HRESULT Math_sin(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Math_sin(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     VARIANT v;
@@ -520,7 +520,7 @@
     return S_OK;
 }
 
-static HRESULT Math_sqrt(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Math_sqrt(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     VARIANT v;
@@ -541,7 +541,7 @@
     return S_OK;
 }
 
-static HRESULT Math_tan(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Math_tan(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     VARIANT v;
diff --git a/dlls/jscript/number.c b/dlls/jscript/number.c
index 921b9e5..757316c 100644
--- a/dlls/jscript/number.c
+++ b/dlls/jscript/number.c
@@ -41,8 +41,19 @@
 static const WCHAR valueOfW[] = {'v','a','l','u','e','O','f',0};
 
 #define NUMBER_TOSTRING_BUF_SIZE 64
+
+static inline NumberInstance *number_from_vdisp(vdisp_t *vdisp)
+{
+    return (NumberInstance*)vdisp->u.jsdisp;
+}
+
+static inline NumberInstance *number_this(vdisp_t *jsthis)
+{
+    return is_vclass(jsthis, JSCLASS_NUMBER) ? number_from_vdisp(jsthis) : NULL;
+}
+
 /* ECMA-262 3rd Edition    15.7.4.2 */
-static HRESULT Number_toString(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Number_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     NumberInstance *number;
@@ -53,11 +64,9 @@
 
     TRACE("\n");
 
-    if(!is_class(dispex, JSCLASS_NUMBER))
+    if(!(number = number_this(jsthis)))
         return throw_type_error(ctx, ei, IDS_NOT_NUM, NULL);
 
-    number = (NumberInstance*)dispex;
-
     if(arg_cnt(dp)) {
         hres = to_int32(ctx, get_arg(dp, 0), ei, &radix);
         if(FAILED(hres))
@@ -170,53 +179,53 @@
     return S_OK;
 }
 
-static HRESULT Number_toLocaleString(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Number_toLocaleString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     FIXME("\n");
     return E_NOTIMPL;
 }
 
-static HRESULT Number_toFixed(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Number_toFixed(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     FIXME("\n");
     return E_NOTIMPL;
 }
 
-static HRESULT Number_toExponential(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Number_toExponential(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     FIXME("\n");
     return E_NOTIMPL;
 }
 
-static HRESULT Number_toPrecision(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Number_toPrecision(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     FIXME("\n");
     return E_NOTIMPL;
 }
 
-static HRESULT Number_valueOf(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Number_valueOf(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
+    NumberInstance *number;
+
     TRACE("\n");
 
-    if(!is_class(dispex, JSCLASS_NUMBER))
+    if(!(number = number_this(jsthis)))
         return throw_type_error(ctx, ei, IDS_NOT_NUM, NULL);
 
-    if(retv) {
-        NumberInstance *number = (NumberInstance*)dispex;
+    if(retv)
         *retv = number->num;
-    }
     return S_OK;
 }
 
-static HRESULT Number_value(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Number_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
-    NumberInstance *number = (NumberInstance*)dispex;
+    NumberInstance *number = number_from_vdisp(jsthis);
 
     switch(flags) {
     case INVOKE_FUNC:
@@ -251,7 +260,7 @@
     NULL
 };
 
-static HRESULT NumberConstr_value(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT NumberConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     VARIANT num;
diff --git a/dlls/jscript/object.c b/dlls/jscript/object.c
index 2ceaf09..7dffff7 100644
--- a/dlls/jscript/object.c
+++ b/dlls/jscript/object.c
@@ -32,9 +32,11 @@
 
 static const WCHAR default_valueW[] = {'[','o','b','j','e','c','t',' ','O','b','j','e','c','t',']',0};
 
-static HRESULT Object_toString(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Object_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
+    DispatchEx *jsdisp;
+
     static const WCHAR formatW[] = {'[','o','b','j','e','c','t',' ','%','s',']',0};
 
     static const WCHAR arrayW[] = {'A','r','r','a','y',0};
@@ -53,71 +55,76 @@
 
     TRACE("\n");
 
-    if(names[dispex->builtin_info->class] == NULL) {
-        ERR("dispex->builtin_info->class = %d\n",
-                dispex->builtin_info->class);
+    jsdisp = get_jsdisp(jsthis);
+    if(!jsdisp || names[jsdisp->builtin_info->class] == NULL) {
+        FIXME("jdisp->builtin_info->class = %d\n", jsdisp->builtin_info->class);
         return E_FAIL;
     }
 
     if(retv) {
         V_VT(retv) = VT_BSTR;
-        V_BSTR(retv) = SysAllocStringLen(NULL, 9+strlenW(names[dispex->builtin_info->class]));
+        V_BSTR(retv) = SysAllocStringLen(NULL, 9+strlenW(names[jsdisp->builtin_info->class]));
         if(!V_BSTR(retv))
             return E_OUTOFMEMORY;
 
-        sprintfW(V_BSTR(retv), formatW, names[dispex->builtin_info->class]);
+        sprintfW(V_BSTR(retv), formatW, names[jsdisp->builtin_info->class]);
     }
 
     return S_OK;
 }
 
-static HRESULT Object_toLocaleString(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Object_toLocaleString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     DISPPARAMS params = {NULL, NULL, 0, 0};
 
     TRACE("\n");
 
-    return jsdisp_call_name(dispex, toStringW, DISPATCH_METHOD, &params, retv, ei, sp);
+    if(!is_jsdisp(jsthis)) {
+        FIXME("Host object this\n");
+        return E_FAIL;
+    }
+
+    return jsdisp_call_name(jsthis->u.jsdisp, toStringW, DISPATCH_METHOD, &params, retv, ei, sp);
 }
 
-static HRESULT Object_valueOf(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Object_valueOf(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     TRACE("\n");
 
     if(retv) {
-        IDispatchEx_AddRef(_IDispatchEx_(dispex));
+        IDispatch_AddRef(jsthis->u.disp);
 
         V_VT(retv) = VT_DISPATCH;
-        V_DISPATCH(retv) = (IDispatch*)_IDispatchEx_(dispex);
+        V_DISPATCH(retv) = jsthis->u.disp;
     }
 
     return S_OK;
 }
 
-static HRESULT Object_hasOwnProperty(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Object_hasOwnProperty(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     FIXME("\n");
     return E_NOTIMPL;
 }
 
-static HRESULT Object_propertyIsEnumerable(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Object_propertyIsEnumerable(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     FIXME("\n");
     return E_NOTIMPL;
 }
 
-static HRESULT Object_isPrototypeOf(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Object_isPrototypeOf(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     FIXME("\n");
     return E_NOTIMPL;
 }
 
-static HRESULT Object_value(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT Object_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     TRACE("\n");
@@ -162,7 +169,7 @@
     NULL
 };
 
-static HRESULT ObjectConstr_value(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT ObjectConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
 {
     HRESULT hres;
diff --git a/dlls/jscript/regexp.c b/dlls/jscript/regexp.c
index 02470f7..e911d0f 100644
--- a/dlls/jscript/regexp.c
+++ b/dlls/jscript/regexp.c
@@ -3294,6 +3294,11 @@
     return re;
 }
 
+static inline RegExpInstance *regexp_from_vdisp(vdisp_t *vdisp)
+{
+    return (RegExpInstance*)vdisp->u.jsdisp;
+}
+
 static HRESULT do_regexp_match_next(script_ctx_t *ctx, RegExpInstance *regexp, const WCHAR *str, DWORD len,
         const WCHAR **cp, match_result_t **parens, DWORD *parens_size, DWORD *parens_cnt, match_result_t *ret)
 {
@@ -3425,14 +3430,14 @@
     return S_OK;
 }
 
-static HRESULT RegExp_source(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT RegExp_source(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     TRACE("\n");
 
     switch(flags) {
     case DISPATCH_PROPERTYGET: {
-        RegExpInstance *This = (RegExpInstance*)dispex;
+        RegExpInstance *This = regexp_from_vdisp(jsthis);
 
         V_VT(retv) = VT_BSTR;
         V_BSTR(retv) = SysAllocString(This->str);
@@ -3448,35 +3453,35 @@
     return S_OK;
 }
 
-static HRESULT RegExp_global(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT RegExp_global(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     FIXME("\n");
     return E_NOTIMPL;
 }
 
-static HRESULT RegExp_ignoreCase(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT RegExp_ignoreCase(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     FIXME("\n");
     return E_NOTIMPL;
 }
 
-static HRESULT RegExp_multiline(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT RegExp_multiline(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     FIXME("\n");
     return E_NOTIMPL;
 }
 
-static HRESULT RegExp_lastIndex(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT RegExp_lastIndex(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     TRACE("\n");
 
     switch(flags) {
     case DISPATCH_PROPERTYGET: {
-        RegExpInstance *regexp = (RegExpInstance*)dispex;
+        RegExpInstance *regexp = regexp_from_vdisp(jsthis);
         V_VT(retv) = VT_I4;
         V_I4(retv) = regexp->last_index;
         break;
@@ -3489,7 +3494,7 @@
     return S_OK;
 }
 
-static HRESULT RegExp_toString(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT RegExp_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     FIXME("\n");
@@ -3558,7 +3563,7 @@
     return S_OK;
 }
 
-static HRESULT run_exec(script_ctx_t *ctx, DispatchEx *dispex, VARIANT *arg, jsexcept_t *ei, BSTR *input,
+static HRESULT run_exec(script_ctx_t *ctx, vdisp_t *jsthis, VARIANT *arg, jsexcept_t *ei, BSTR *input,
         match_result_t *match, match_result_t **parens, DWORD *parens_cnt, VARIANT_BOOL *ret)
 {
     RegExpInstance *regexp;
@@ -3567,12 +3572,12 @@
     BSTR string;
     HRESULT hres;
 
-    if(!is_class(dispex, JSCLASS_REGEXP)) {
+    if(!is_vclass(jsthis, JSCLASS_REGEXP)) {
         FIXME("Not a RegExp\n");
         return E_NOTIMPL;
     }
 
-    regexp = (RegExpInstance*)dispex;
+    regexp = regexp_from_vdisp(jsthis);
 
     if(arg) {
         hres = to_string(ctx, arg, ei, &string);
@@ -3609,7 +3614,7 @@
     return S_OK;
 }
 
-static HRESULT RegExp_exec(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT RegExp_exec(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     match_result_t *parens = NULL, match;
@@ -3620,7 +3625,7 @@
 
     TRACE("\n");
 
-    hres = run_exec(ctx, dispex, arg_cnt(dp) ? get_arg(dp,0) : NULL, ei, &string, &match, &parens, &parens_cnt, &b);
+    hres = run_exec(ctx, jsthis, arg_cnt(dp) ? get_arg(dp,0) : NULL, ei, &string, &match, &parens, &parens_cnt, &b);
     if(FAILED(hres))
         return hres;
 
@@ -3643,7 +3648,7 @@
     return hres;
 }
 
-static HRESULT RegExp_test(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT RegExp_test(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     match_result_t match;
@@ -3652,7 +3657,7 @@
 
     TRACE("\n");
 
-    hres = run_exec(ctx, dispex, arg_cnt(dp) ? get_arg(dp,0) : NULL, ei, NULL, &match, NULL, NULL, &b);
+    hres = run_exec(ctx, jsthis, arg_cnt(dp) ? get_arg(dp,0) : NULL, ei, NULL, &match, NULL, NULL, &b);
     if(FAILED(hres))
         return hres;
 
@@ -3663,7 +3668,7 @@
     return S_OK;
 }
 
-static HRESULT RegExp_value(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT RegExp_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     TRACE("\n");
@@ -3828,7 +3833,7 @@
     return S_OK;
 }
 
-static HRESULT RegExpConstr_value(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT RegExpConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     TRACE("\n");
diff --git a/dlls/jscript/string.c b/dlls/jscript/string.c
index 7f12400..4bb8091 100644
--- a/dlls/jscript/string.c
+++ b/dlls/jscript/string.c
@@ -64,17 +64,52 @@
 static const WCHAR localeCompareW[] = {'l','o','c','a','l','e','C','o','m','p','a','r','e',0};
 static const WCHAR fromCharCodeW[] = {'f','r','o','m','C','h','a','r','C','o','d','e',0};
 
-static HRESULT String_length(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static inline StringInstance *string_from_vdisp(vdisp_t *vdisp)
+{
+    return (StringInstance*)vdisp->u.jsdisp;
+}
+
+static inline StringInstance *string_this(vdisp_t *jsthis)
+{
+    return is_vclass(jsthis, JSCLASS_STRING) ? string_from_vdisp(jsthis) : NULL;
+}
+
+static HRESULT get_string_val(script_ctx_t *ctx, vdisp_t *jsthis, jsexcept_t *ei,
+        const WCHAR **str, DWORD *len, BSTR *val_str)
+{
+    StringInstance *string;
+    VARIANT this_var;
+    HRESULT hres;
+
+    if((string = string_this(jsthis))) {
+        *str = string->str;
+        *len = string->length;
+        *val_str = NULL;
+        return S_OK;
+    }
+
+    V_VT(&this_var) = VT_DISPATCH;
+    V_DISPATCH(&this_var) = jsthis->u.disp;
+    hres = to_string(ctx, &this_var, ei, val_str);
+    if(FAILED(hres))
+        return hres;
+
+    *str = *val_str;
+    *len = SysStringLen(*val_str);
+    return S_OK;
+}
+
+static HRESULT String_length(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
-    TRACE("%p\n", dispex);
+    TRACE("%p\n", jsthis);
 
     switch(flags) {
     case DISPATCH_PROPERTYGET: {
-        StringInstance *jsthis = (StringInstance*)dispex;
+        StringInstance *string = string_from_vdisp(jsthis);
 
         V_VT(retv) = VT_I4;
-        V_I4(retv) = jsthis->length;
+        V_I4(retv) = string->length;
         break;
     }
     default:
@@ -85,17 +120,15 @@
     return S_OK;
 }
 
-static HRESULT stringobj_to_string(DispatchEx *dispex, VARIANT *retv)
+static HRESULT stringobj_to_string(vdisp_t *jsthis, VARIANT *retv)
 {
     StringInstance *string;
 
-    if(!is_class(dispex, JSCLASS_STRING)) {
+    if(!(string = string_this(jsthis))) {
         WARN("this is not a string object\n");
         return E_FAIL;
     }
 
-    string = (StringInstance*)dispex;
-
     if(retv) {
         BSTR str = SysAllocString(string->str);
         if(!str)
@@ -108,51 +141,36 @@
 }
 
 /* ECMA-262 3rd Edition    15.5.4.2 */
-static HRESULT String_toString(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT String_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     TRACE("\n");
 
-    return stringobj_to_string(dispex, retv);
+    return stringobj_to_string(jsthis, retv);
 }
 
 /* ECMA-262 3rd Edition    15.5.4.2 */
-static HRESULT String_valueOf(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT String_valueOf(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     TRACE("\n");
 
-    return stringobj_to_string(dispex, retv);
+    return stringobj_to_string(jsthis, retv);
 }
 
-static HRESULT do_attributeless_tag_format(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT do_attributeless_tag_format(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp, const WCHAR *tagname)
 {
-    static const WCHAR tagfmt[] = {'<','%','s','>','%','s','<','/','%','s','>',0};
     const WCHAR *str;
     DWORD length;
     BSTR val_str = NULL;
     HRESULT hres;
 
-    if(!is_class(dispex, JSCLASS_STRING)) {
-        VARIANT this;
+    static const WCHAR tagfmt[] = {'<','%','s','>','%','s','<','/','%','s','>',0};
 
-        V_VT(&this) = VT_DISPATCH;
-        V_DISPATCH(&this) = (IDispatch*)_IDispatchEx_(dispex);
-
-        hres = to_string(ctx, &this, ei, &val_str);
-        if(FAILED(hres))
-            return hres;
-
-        str = val_str;
-        length = SysStringLen(val_str);
-    }
-    else {
-        StringInstance *this = (StringInstance*)dispex;
-
-        str = this->str;
-        length = this->length;
-    }
+    hres = get_string_val(ctx, jsthis, ei, &str, &length, &val_str);
+    if(FAILED(hres))
+        return hres;
 
     if(retv) {
         BSTR ret = SysAllocStringLen(NULL, length + 2*strlenW(tagname) + 5);
@@ -171,7 +189,7 @@
     return S_OK;
 }
 
-static HRESULT do_attribute_tag_format(script_ctx_t *ctx, DispatchEx *dispex, WORD flags,
+static HRESULT do_attribute_tag_format(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
         DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp,
         const WCHAR *tagname, const WCHAR *attr)
 {
@@ -179,16 +197,17 @@
         = {'<','%','s',' ','%','s','=','\"','%','s','\"','>','%','s','<','/','%','s','>',0};
     static const WCHAR undefinedW[] = {'u','n','d','e','f','i','n','e','d',0};
 
+    StringInstance *string;
     const WCHAR *str;
     DWORD length;
-    BSTR attr_value, val_str = NULL;
+    BSTR attr_value, val_str;
     HRESULT hres;
 
-    if(!is_class(dispex, JSCLASS_STRING)) {
+    if(!(string = string_this(jsthis))) {
         VARIANT this;
 
         V_VT(&this) = VT_DISPATCH;
-        V_DISPATCH(&this) = (IDispatch*)_IDispatchEx_(dispex);
+        V_DISPATCH(&this) = jsthis->u.disp;
 
         hres = to_string(ctx, &this, ei, &val_str);
         if(FAILED(hres))
@@ -198,10 +217,8 @@
         length = SysStringLen(val_str);
     }
     else {
-        StringInstance *this = (StringInstance*)dispex;
-
-        str = this->str;
-        length = this->length;
+        str = string->str;
+        length = string->length;
     }
 
     if(arg_cnt(dp)) {
@@ -239,67 +256,51 @@
     return S_OK;
 }
 
-static HRESULT String_anchor(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT String_anchor(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     static const WCHAR fontW[] = {'A',0};
     static const WCHAR colorW[] = {'N','A','M','E',0};
 
-    return do_attribute_tag_format(ctx, dispex, flags, dp, retv, ei, sp, fontW, colorW);
+    return do_attribute_tag_format(ctx, jsthis, flags, dp, retv, ei, sp, fontW, colorW);
 }
 
-static HRESULT String_big(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT String_big(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     static const WCHAR bigtagW[] = {'B','I','G',0};
-    return do_attributeless_tag_format(ctx, dispex, flags, dp, retv, ei, sp, bigtagW);
+    return do_attributeless_tag_format(ctx, jsthis, flags, dp, retv, ei, sp, bigtagW);
 }
 
-static HRESULT String_blink(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT String_blink(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     static const WCHAR blinktagW[] = {'B','L','I','N','K',0};
-    return do_attributeless_tag_format(ctx, dispex, flags, dp, retv, ei, sp, blinktagW);
+    return do_attributeless_tag_format(ctx, jsthis, flags, dp, retv, ei, sp, blinktagW);
 }
 
-static HRESULT String_bold(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT String_bold(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     static const WCHAR boldtagW[] = {'B',0};
-    return do_attributeless_tag_format(ctx, dispex, flags, dp, retv, ei, sp, boldtagW);
+    return do_attributeless_tag_format(ctx, jsthis, flags, dp, retv, ei, sp, boldtagW);
 }
 
 /* ECMA-262 3rd Edition    15.5.4.5 */
-static HRESULT String_charAt(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT String_charAt(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     const WCHAR *str;
     DWORD length;
-    BSTR ret, val_str = NULL;
+    BSTR ret, val_str;
     INT pos = 0;
     HRESULT hres;
 
     TRACE("\n");
 
-    if(!is_class(dispex, JSCLASS_STRING)) {
-        VARIANT this;
-
-        V_VT(&this) = VT_DISPATCH;
-        V_DISPATCH(&this) = (IDispatch*)_IDispatchEx_(dispex);
-
-        hres = to_string(ctx, &this, ei, &val_str);
-        if(FAILED(hres))
-            return hres;
-
-        str = val_str;
-        length = SysStringLen(val_str);
-    }
-    else {
-        StringInstance *this = (StringInstance*)dispex;
-
-        str = this->str;
-        length = this->length;
-    }
+    hres = get_string_val(ctx, jsthis, ei, &str, &length, &val_str);
+    if(FAILED(hres))
+        return hres;
 
     if(arg_cnt(dp)) {
         VARIANT num;
@@ -338,35 +339,19 @@
 }
 
 /* ECMA-262 3rd Edition    15.5.4.5 */
-static HRESULT String_charCodeAt(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT String_charCodeAt(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     const WCHAR *str;
-    BSTR val_str = NULL;
+    BSTR val_str;
     DWORD length, idx = 0;
     HRESULT hres;
 
     TRACE("\n");
 
-    if(!is_class(dispex, JSCLASS_STRING)) {
-        VARIANT this;
-
-        V_VT(&this) = VT_DISPATCH;
-        V_DISPATCH(&this) = (IDispatch*)_IDispatchEx_(dispex);
-
-        hres = to_string(ctx, &this, ei, &val_str);
-        if(FAILED(hres))
-            return hres;
-
-        str = val_str;
-        length = SysStringLen(val_str);
-    }
-    else {
-        StringInstance *this = (StringInstance*)dispex;
-
-        str = this->str;
-        length = this->length;
-    }
+    hres = get_string_val(ctx, jsthis, ei, &str, &length, &val_str);
+    if(FAILED(hres))
+        return hres;
 
     if(arg_cnt(dp) > 0) {
         VARIANT v;
@@ -396,7 +381,7 @@
 }
 
 /* ECMA-262 3rd Edition    15.5.4.6 */
-static HRESULT String_concat(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT String_concat(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     BSTR *strs = NULL, ret = NULL;
@@ -413,7 +398,7 @@
         return E_OUTOFMEMORY;
 
     V_VT(&var) = VT_DISPATCH;
-    V_DISPATCH(&var) = (IDispatch*)_IDispatchEx_(dispex);
+    V_DISPATCH(&var) = jsthis->u.disp;
 
     hres = to_string(ctx, &var, ei, strs);
     if(SUCCEEDED(hres)) {
@@ -453,61 +438,45 @@
     return S_OK;
 }
 
-static HRESULT String_fixed(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT String_fixed(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     static const WCHAR fixedtagW[] = {'T','T',0};
-    return do_attributeless_tag_format(ctx, dispex, flags, dp, retv, ei, sp, fixedtagW);
+    return do_attributeless_tag_format(ctx, jsthis, flags, dp, retv, ei, sp, fixedtagW);
 }
 
-static HRESULT String_fontcolor(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT String_fontcolor(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     static const WCHAR fontW[] = {'F','O','N','T',0};
     static const WCHAR colorW[] = {'C','O','L','O','R',0};
 
-    return do_attribute_tag_format(ctx, dispex, flags, dp, retv, ei, sp, fontW, colorW);
+    return do_attribute_tag_format(ctx, jsthis, flags, dp, retv, ei, sp, fontW, colorW);
 }
 
-static HRESULT String_fontsize(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT String_fontsize(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     static const WCHAR fontW[] = {'F','O','N','T',0};
     static const WCHAR colorW[] = {'S','I','Z','E',0};
 
-    return do_attribute_tag_format(ctx, dispex, flags, dp, retv, ei, sp, fontW, colorW);
+    return do_attribute_tag_format(ctx, jsthis, flags, dp, retv, ei, sp, fontW, colorW);
 }
 
-static HRESULT String_indexOf(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT String_indexOf(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     DWORD length, pos = 0;
     const WCHAR *str;
-    BSTR search_str, val_str = NULL;
+    BSTR search_str, val_str;
     INT ret = -1;
     HRESULT hres;
 
     TRACE("\n");
 
-    if(!is_class(dispex, JSCLASS_STRING)) {
-        VARIANT this;
-
-        V_VT(&this) = VT_DISPATCH;
-        V_DISPATCH(&this) = (IDispatch*)_IDispatchEx_(dispex);
-
-        hres = to_string(ctx, &this, ei, &val_str);
-        if(FAILED(hres))
-            return hres;
-
-        str = val_str;
-        length = SysStringLen(val_str);
-    }
-    else {
-        StringInstance *this = (StringInstance*)dispex;
-
-        str = this->str;
-        length = this->length;
-    }
+    hres = get_string_val(ctx, jsthis, ei, &str, &length, &val_str);
+    if(FAILED(hres))
+        return hres;
 
     if(!arg_cnt(dp)) {
         if(retv) {
@@ -560,18 +529,18 @@
     return S_OK;
 }
 
-static HRESULT String_italics(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT String_italics(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     static const WCHAR italicstagW[] = {'I',0};
-    return do_attributeless_tag_format(ctx, dispex, flags, dp, retv, ei, sp, italicstagW);
+    return do_attributeless_tag_format(ctx, jsthis, flags, dp, retv, ei, sp, italicstagW);
 }
 
 /* ECMA-262 3rd Edition    15.5.4.8 */
-static HRESULT String_lastIndexOf(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT String_lastIndexOf(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
-    BSTR search_str, val_str = NULL;
+    BSTR search_str, val_str;
     DWORD length, pos, search_len;
     const WCHAR *str;
     INT ret = -1;
@@ -579,24 +548,9 @@
 
     TRACE("\n");
 
-    if(is_class(dispex, JSCLASS_STRING)) {
-        StringInstance *this = (StringInstance*)dispex;
-
-        str = this->str;
-        length = this->length;
-    }else {
-        VARIANT this;
-
-        V_VT(&this) = VT_DISPATCH;
-        V_DISPATCH(&this) = (IDispatch*)_IDispatchEx_(dispex);
-
-        hres = to_string(ctx, &this, ei, &val_str);
-        if(FAILED(hres))
-            return hres;
-
-        str = val_str;
-        length = SysStringLen(val_str);
-    }
+    hres = get_string_val(ctx, jsthis, ei, &str, &length, &val_str);
+    if(FAILED(hres))
+        return hres;
 
     if(!arg_cnt(dp)) {
         if(retv) {
@@ -654,17 +608,17 @@
     return S_OK;
 }
 
-static HRESULT String_link(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT String_link(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     static const WCHAR fontW[] = {'A',0};
     static const WCHAR colorW[] = {'H','R','E','F',0};
 
-    return do_attribute_tag_format(ctx, dispex, flags, dp, retv, ei, sp, fontW, colorW);
+    return do_attribute_tag_format(ctx, jsthis, flags, dp, retv, ei, sp, fontW, colorW);
 }
 
 /* ECMA-262 3rd Edition    15.5.4.10 */
-static HRESULT String_match(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT String_match(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     const WCHAR *str;
@@ -709,29 +663,9 @@
     }
     }
 
-    if(!is_class(dispex, JSCLASS_STRING)) {
-        VARIANT this;
-
-        V_VT(&this) = VT_DISPATCH;
-        V_DISPATCH(&this) = (IDispatch*)_IDispatchEx_(dispex);
-
-        hres = to_string(ctx, &this, ei, &val_str);
-        if(FAILED(hres)) {
-            jsdisp_release(regexp);
-            return hres;
-        }
-
-        str = val_str;
-        length = SysStringLen(val_str);
-    }
-    else {
-        StringInstance *this = (StringInstance*)dispex;
-
-        str = this->str;
-        length = this->length;
-    }
-
-    hres = regexp_match(ctx, regexp, str, length, FALSE, &match_result, &match_cnt);
+    hres = get_string_val(ctx, jsthis, ei, &str, &length, &val_str);
+    if(SUCCEEDED(hres))
+        hres = regexp_match(ctx, regexp, str, length, FALSE, &match_result, &match_cnt);
     jsdisp_release(regexp);
     if(FAILED(hres)) {
         SysFreeString(val_str);
@@ -876,12 +810,12 @@
 }
 
 /* ECMA-262 3rd Edition    15.5.4.11 */
-static HRESULT String_replace(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT String_replace(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
 {
     const WCHAR *str;
     DWORD parens_cnt = 0, parens_size=0, rep_len=0, length;
-    BSTR rep_str = NULL, match_str = NULL, ret_str, val_str = NULL;
+    BSTR rep_str = NULL, match_str = NULL, ret_str, val_str;
     DispatchEx *rep_func = NULL, *regexp = NULL;
     match_result_t *parens = NULL, match, **parens_ptr = &parens;
     strbuf_t ret = {NULL,0,0};
@@ -891,25 +825,9 @@
 
     TRACE("\n");
 
-    if(!is_class(dispex, JSCLASS_STRING)) {
-        VARIANT this;
-
-        V_VT(&this) = VT_DISPATCH;
-        V_DISPATCH(&this) = (IDispatch*)_IDispatchEx_(dispex);
-
-        hres = to_string(ctx, &this, ei, &val_str);
-        if(FAILED(hres))
-            return hres;
-
-        str = val_str;
-        length = SysStringLen(val_str);
-    }
-    else {
-        StringInstance *this = (StringInstance*)dispex;
-
-        str = this->str;
-        length = this->length;
-    }
+    hres = get_string_val(ctx, jsthis, ei, &str, &length, &val_str);
+    if(FAILED(hres))
+        return hres;
 
     if(!arg_cnt(dp)) {
         if(retv) {
@@ -1110,7 +1028,7 @@
     return hres;
 }
 
-static HRESULT String_search(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT String_search(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     FIXME("\n");
@@ -1118,11 +1036,11 @@
 }
 
 /* ECMA-262 3rd Edition    15.5.4.13 */
-static HRESULT String_slice(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT String_slice(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     const WCHAR *str;
-    BSTR val_str = NULL;
+    BSTR val_str;
     DWORD length;
     INT start=0, end;
     VARIANT v;
@@ -1130,25 +1048,9 @@
 
     TRACE("\n");
 
-    if(!is_class(dispex, JSCLASS_STRING)) {
-        VARIANT this;
-
-        V_VT(&this) = VT_DISPATCH;
-        V_DISPATCH(&this) = (IDispatch*)_IDispatchEx_(dispex);
-
-        hres = to_string(ctx, &this, ei, &val_str);
-        if(FAILED(hres))
-            return hres;
-
-        str = val_str;
-        length = SysStringLen(val_str);
-    }
-    else {
-        StringInstance *this = (StringInstance*)dispex;
-
-        str = this->str;
-        length = this->length;
-    }
+    hres = get_string_val(ctx, jsthis, ei, &str, &length, &val_str);
+    if(FAILED(hres))
+        return hres;
 
     if(arg_cnt(dp)) {
         hres = to_integer(ctx, get_arg(dp,0), ei, &v);
@@ -1214,14 +1116,14 @@
     return S_OK;
 }
 
-static HRESULT String_small(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT String_small(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     static const WCHAR smalltagW[] = {'S','M','A','L','L',0};
-    return do_attributeless_tag_format(ctx, dispex, flags, dp, retv, ei, sp, smalltagW);
+    return do_attributeless_tag_format(ctx, jsthis, flags, dp, retv, ei, sp, smalltagW);
 }
 
-static HRESULT String_split(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT String_split(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     match_result_t *match_result = NULL;
@@ -1229,7 +1131,7 @@
     const WCHAR *str, *ptr, *ptr2;
     VARIANT *arg, var;
     DispatchEx *array;
-    BSTR val_str = NULL, match_str = NULL;
+    BSTR val_str, match_str = NULL;
     HRESULT hres;
 
     TRACE("\n");
@@ -1239,25 +1141,9 @@
         return E_NOTIMPL;
     }
 
-    if(!is_class(dispex, JSCLASS_STRING)) {
-        VARIANT this;
-
-        V_VT(&this) = VT_DISPATCH;
-        V_DISPATCH(&this) = (IDispatch*)_IDispatchEx_(dispex);
-
-        hres = to_string(ctx, &this, ei, &val_str);
-        if(FAILED(hres))
-            return hres;
-
-        str = val_str;
-        length = SysStringLen(val_str);
-    }
-    else {
-        StringInstance *this = (StringInstance*)dispex;
-
-        str = this->str;
-        length = this->length;
-    }
+    hres = get_string_val(ctx, jsthis, ei, &str, &length, &val_str);
+    if(FAILED(hres))
+        return hres;
 
     arg = get_arg(dp, 0);
     switch(V_VT(arg)) {
@@ -1362,26 +1248,26 @@
     return hres;
 }
 
-static HRESULT String_strike(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT String_strike(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     static const WCHAR striketagW[] = {'S','T','R','I','K','E',0};
-    return do_attributeless_tag_format(ctx, dispex, flags, dp, retv, ei, sp, striketagW);
+    return do_attributeless_tag_format(ctx, jsthis, flags, dp, retv, ei, sp, striketagW);
 }
 
-static HRESULT String_sub(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT String_sub(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     static const WCHAR subtagW[] = {'S','U','B',0};
-    return do_attributeless_tag_format(ctx, dispex, flags, dp, retv, ei, sp, subtagW);
+    return do_attributeless_tag_format(ctx, jsthis, flags, dp, retv, ei, sp, subtagW);
 }
 
 /* ECMA-262 3rd Edition    15.5.4.15 */
-static HRESULT String_substring(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT String_substring(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     const WCHAR *str;
-    BSTR val_str = NULL;
+    BSTR val_str;
     INT start=0, end;
     DWORD length;
     VARIANT v;
@@ -1389,25 +1275,9 @@
 
     TRACE("\n");
 
-    if(!is_class(dispex, JSCLASS_STRING)) {
-        VARIANT this;
-
-        V_VT(&this) = VT_DISPATCH;
-        V_DISPATCH(&this) = (IDispatch*)_IDispatchEx_(dispex);
-
-        hres = to_string(ctx, &this, ei, &val_str);
-        if(FAILED(hres))
-            return hres;
-
-        str = val_str;
-        length = SysStringLen(val_str);
-    }
-    else {
-        StringInstance *this = (StringInstance*)dispex;
-
-        str = this->str;
-        length = this->length;
-    }
+    hres = get_string_val(ctx, jsthis, ei, &str, &length, &val_str);
+    if(FAILED(hres))
+        return hres;
 
     if(arg_cnt(dp) >= 1) {
         hres = to_integer(ctx, get_arg(dp,0), ei, &v);
@@ -1466,10 +1336,10 @@
 }
 
 /* ECMA-262 3rd Edition    B.2.3 */
-static HRESULT String_substr(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT String_substr(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
-    BSTR val_str = NULL;
+    BSTR val_str;
     const WCHAR *str;
     INT start=0, len;
     DWORD length;
@@ -1478,23 +1348,9 @@
 
     TRACE("\n");
 
-    if(is_class(dispex, JSCLASS_STRING)) {
-        StringInstance *this = (StringInstance*)dispex;
-
-        str = this->str;
-        length = this->length;
-    }else {
-        VARIANT this;
-
-        V_VT(&this) = VT_DISPATCH;
-        V_DISPATCH(&this) = (IDispatch*)_IDispatchEx_(dispex);
-        hres = to_string(ctx, &this, ei, &val_str);
-        if(FAILED(hres))
-            return hres;
-
-        str = val_str;
-        length = SysStringLen(val_str);
-    }
+    hres = get_string_val(ctx, jsthis, ei, &str, &length, &val_str);
+    if(FAILED(hres))
+        return hres;
 
     if(arg_cnt(dp) >= 1) {
         hres = to_integer(ctx, get_arg(dp,0), ei, &v);
@@ -1546,42 +1402,26 @@
     return hres;
 }
 
-static HRESULT String_sup(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT String_sup(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     static const WCHAR suptagW[] = {'S','U','P',0};
-    return do_attributeless_tag_format(ctx, dispex, flags, dp, retv, ei, sp, suptagW);
+    return do_attributeless_tag_format(ctx, jsthis, flags, dp, retv, ei, sp, suptagW);
 }
 
-static HRESULT String_toLowerCase(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT String_toLowerCase(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     const WCHAR* str;
     DWORD length;
-    BSTR val_str = NULL;
+    BSTR val_str;
     HRESULT  hres;
 
     TRACE("\n");
 
-    if(!is_class(dispex, JSCLASS_STRING)) {
-        VARIANT this;
-
-        V_VT(&this) = VT_DISPATCH;
-        V_DISPATCH(&this) = (IDispatch*)_IDispatchEx_(dispex);
-
-        hres = to_string(ctx, &this, ei, &val_str);
-        if(FAILED(hres))
-            return hres;
-
-        str = val_str;
-        length = SysStringLen(val_str);
-    }
-    else {
-        StringInstance *this = (StringInstance*)dispex;
-
-        str = this->str;
-        length = this->length;
-    }
+    hres = get_string_val(ctx, jsthis, ei, &str, &length, &val_str);
+    if(FAILED(hres))
+        return hres;
 
     if(retv) {
         if(!val_str) {
@@ -1599,35 +1439,19 @@
     return S_OK;
 }
 
-static HRESULT String_toUpperCase(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT String_toUpperCase(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     const WCHAR* str;
     DWORD length;
-    BSTR val_str = NULL;
+    BSTR val_str;
     HRESULT hres;
 
     TRACE("\n");
 
-    if(!is_class(dispex, JSCLASS_STRING)) {
-        VARIANT this;
-
-        V_VT(&this) = VT_DISPATCH;
-        V_DISPATCH(&this) = (IDispatch*)_IDispatchEx_(dispex);
-
-        hres = to_string(ctx, &this, ei, &val_str);
-        if(FAILED(hres))
-            return hres;
-
-        str = val_str;
-        length = SysStringLen(val_str);
-    }
-    else {
-        StringInstance *this = (StringInstance*)dispex;
-
-        str = this->str;
-        length = this->length;
-    }
+    hres = get_string_val(ctx, jsthis, ei, &str, &length, &val_str);
+    if(FAILED(hres))
+        return hres;
 
     if(retv) {
         if(!val_str) {
@@ -1645,31 +1469,31 @@
     return S_OK;
 }
 
-static HRESULT String_toLocaleLowerCase(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT String_toLocaleLowerCase(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     FIXME("\n");
     return E_NOTIMPL;
 }
 
-static HRESULT String_toLocaleUpperCase(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT String_toLocaleUpperCase(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     FIXME("\n");
     return E_NOTIMPL;
 }
 
-static HRESULT String_localeCompare(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT String_localeCompare(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     FIXME("\n");
     return E_NOTIMPL;
 }
 
-static HRESULT String_value(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT String_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
-    StringInstance *This = (StringInstance*)dispex;
+    StringInstance *This = string_from_vdisp(jsthis);
 
     TRACE("\n");
 
@@ -1747,7 +1571,7 @@
 };
 
 /* ECMA-262 3rd Edition    15.5.3.2 */
-static HRESULT StringConstr_fromCharCode(script_ctx_t *ctx, DispatchEx *dispex, WORD flags,
+static HRESULT StringConstr_fromCharCode(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
         DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     DWORD i, code;
@@ -1777,7 +1601,7 @@
     return S_OK;
 }
 
-static HRESULT StringConstr_value(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
+static HRESULT StringConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     HRESULT hres;