[PATCH 07/11] mshtml: Implement some builtin props/methods for the function objects.

Gabriel Ivăncescu gabrielopcode at gmail.com
Mon Sep 20 09:46:13 CDT 2021


For document modes <= IE8, which don't use the JS object proxies,
native exposes some of the function prototype properties and methods,
and semi-implements the methods for typical use. This implements the same
limitations on them.

Signed-off-by: Gabriel Ivăncescu <gabrielopcode at gmail.com>
---

Tests follow.

 dlls/mshtml/dispex.c | 172 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 168 insertions(+), 4 deletions(-)

diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c
index f9814b7..01c5656 100644
--- a/dlls/mshtml/dispex.c
+++ b/dlls/mshtml/dispex.c
@@ -34,6 +34,7 @@
 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
 
 #define MAX_ARGS 16
+#define JS_E_INVALID_PROPERTY 0x800a01b6
 
 static CRITICAL_SECTION cs_dispex_static_data;
 static CRITICAL_SECTION_DEBUG cs_dispex_static_data_dbg =
@@ -760,6 +761,19 @@ static HRESULT typeinfo_invoke(DispatchEx *This, func_info_t *func, WORD flags,
     return hres;
 }
 
+static inline BOOL same_disp(IDispatch *disp, DispatchEx *obj)
+{
+    IDispatch *tmp;
+
+    if(!disp || FAILED(IDispatch_QueryInterface(disp, &IID_IDispatch, (void**)&disp)) || !disp)
+        return FALSE;
+    IDispatch_Release(disp);
+    if(FAILED(IDispatchEx_QueryInterface(&obj->IDispatchEx_iface, &IID_IDispatch, (void**)&tmp)))
+        return FALSE;
+    IDispatch_Release(tmp);
+    return disp == tmp;
+}
+
 static inline func_disp_t *impl_from_IUnknown(IUnknown *iface)
 {
     return CONTAINING_RECORD(iface, func_disp_t, IUnknown_iface);
@@ -816,6 +830,113 @@ static const IUnknownVtbl FunctionUnkVtbl = {
     Function_Release
 };
 
+static HRESULT function_apply(func_disp_t *func, DISPPARAMS *dp, VARIANT *res, EXCEPINFO *ei)
+{
+    DISPPARAMS params = { 0 };
+    IDispatch *disp;
+    DISPID dispid;
+    VARIANT *arg;
+    HRESULT hres;
+
+    if(!func->obj)
+        return E_UNEXPECTED;
+
+    if(dp->cNamedArgs) {
+        FIXME("named args not supported\n");
+        return E_NOTIMPL;
+    }
+
+    arg = dp->rgvarg + dp->cArgs - 1;
+    if(dp->cArgs < 1 || V_VT(arg) != VT_DISPATCH || !same_disp(V_DISPATCH(arg), func->obj))
+        return CTL_E_ILLEGALFUNCTIONCALL;
+
+    if(dp->cArgs >= 2) {
+        WCHAR buf[12], *name;
+        ULONG i, err = 0;
+
+        arg--;
+        if((V_VT(arg) & ~VT_BYREF) != VT_DISPATCH)
+            return CTL_E_ILLEGALFUNCTIONCALL;
+        disp = (V_VT(arg) & VT_BYREF) ? *(IDispatch**)(V_BYREF(arg)) : V_DISPATCH(arg);
+
+        /* get the array length */
+        name = buf;
+        memcpy(buf, L"length", sizeof(L"length"));
+        hres = IDispatch_GetIDsOfNames(disp, &IID_NULL, &name, 1, 0, &dispid);
+        if(FAILED(hres) || dispid == DISPID_UNKNOWN)
+            return CTL_E_ILLEGALFUNCTIONCALL;
+
+        hres = IDispatch_Invoke(disp, dispid, &IID_NULL, 0, DISPATCH_PROPERTYGET, NULL, res, ei, &err);
+        if(FAILED(hres))
+            return hres;
+        if(FAILED(VariantChangeType(res, res, 0, VT_UI4))) {
+            VariantClear(res);
+            return CTL_E_ILLEGALFUNCTIONCALL;
+        }
+        params.cArgs = V_UI4(res);
+        V_VT(res) = VT_EMPTY;
+
+        /* alloc new params */
+        if(params.cArgs) {
+            if(!(params.rgvarg = heap_alloc(params.cArgs * sizeof(VARIANTARG))))
+                return E_OUTOFMEMORY;
+            for(i = 0; i < params.cArgs; i++) {
+                arg = params.rgvarg + params.cArgs - i - 1;
+
+                name = buf;
+                swprintf(buf, ARRAY_SIZE(buf), L"%u", i);
+                hres = IDispatch_GetIDsOfNames(disp, &IID_NULL, &name, 1, 0, &dispid);
+                if(FAILED(hres) || dispid == DISPID_UNKNOWN) {
+                    hres = CTL_E_ILLEGALFUNCTIONCALL;
+                    break;
+                }
+                hres = IDispatch_Invoke(disp, dispid, &IID_NULL, 0, DISPATCH_PROPERTYGET, NULL, arg, ei, &err);
+                if(FAILED(hres))
+                    break;
+            }
+            if(FAILED(hres)) {
+                while(i--) VariantClear(params.rgvarg + params.cArgs - i - 1);
+                return hres;
+            }
+        }
+    }
+
+    hres = typeinfo_invoke(func->obj, func->info, DISPATCH_METHOD, &params, res, ei);
+
+    heap_free(params.rgvarg);
+    return hres;
+}
+
+static HRESULT function_call(func_disp_t *func, DISPPARAMS *dp, VARIANT *res, EXCEPINFO *ei)
+{
+    DISPPARAMS params = { dp->rgvarg, NULL, dp->cArgs - 1, 0 };
+    VARIANT *arg;
+
+    if(!func->obj)
+        return E_UNEXPECTED;
+
+    if(dp->cNamedArgs) {
+        FIXME("named args not supported\n");
+        return E_NOTIMPL;
+    }
+
+    arg = dp->rgvarg + dp->cArgs - 1;
+    if(dp->cArgs < 1 || V_VT(arg) != VT_DISPATCH || !same_disp(V_DISPATCH(arg), func->obj))
+        return CTL_E_ILLEGALFUNCTIONCALL;
+
+    return typeinfo_invoke(func->obj, func->info, DISPATCH_METHOD, &params, res, ei);
+}
+
+static const struct {
+    const WCHAR *name;
+    HRESULT (*method)(func_disp_t*,DISPPARAMS*,VARIANT*,EXCEPINFO*);
+} function_props[] = {
+    { L"apply", function_apply },
+    { L"arguments", NULL },
+    { L"call", function_call },
+    { L"length", NULL }
+};
+
 static inline func_disp_t *impl_from_DispatchEx(DispatchEx *iface)
 {
     return CONTAINING_RECORD(iface, func_disp_t, dispex);
@@ -876,10 +997,53 @@ static HRESULT function_value(DispatchEx *dispex, LCID lcid, WORD flags, DISPPAR
     return hres;
 }
 
+static HRESULT function_get_dispid(DispatchEx *dispex, BSTR name, DWORD flags, DISPID *dispid)
+{
+    DWORD i;
+
+    for(i = 0; i < ARRAY_SIZE(function_props); i++) {
+        if(!wcsicmp(name, function_props[i].name)) {
+            if((flags & fdexNameCaseSensitive) && wcscmp(name, function_props[i].name))
+                return DISP_E_UNKNOWNNAME;
+            *dispid = MSHTML_DISPID_CUSTOM_MIN + i;
+            return S_OK;
+        }
+    }
+    return DISP_E_UNKNOWNNAME;
+}
+
+static HRESULT function_invoke(DispatchEx *dispex, DISPID id, LCID lcid, WORD flags, DISPPARAMS *params,
+        VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller)
+{
+    func_disp_t *This = impl_from_DispatchEx(dispex);
+    DWORD idx = id - MSHTML_DISPID_CUSTOM_MIN;
+
+    if(idx >= ARRAY_SIZE(function_props))
+        return DISP_E_UNKNOWNNAME;
+
+    switch(flags) {
+    case DISPATCH_METHOD|DISPATCH_PROPERTYGET:
+        if(!res)
+            return E_INVALIDARG;
+        /* fall through */
+    case DISPATCH_METHOD:
+        if(function_props[idx].method)
+            return function_props[idx].method(This, params, res, ei);
+        return JS_E_INVALID_PROPERTY;
+    case DISPATCH_PROPERTYGET:
+        V_VT(res) = VT_EMPTY;  /* IE returns undefined */
+        break;
+    default:
+        return JS_E_INVALID_PROPERTY;
+    }
+
+    return S_OK;
+}
+
 static const dispex_static_data_vtbl_t function_dispex_vtbl = {
     function_value,
-    NULL,
-    NULL,
+    function_get_dispid,
+    function_invoke,
     NULL
 };
 
@@ -1262,7 +1426,7 @@ static HRESULT invoke_builtin_function(DispatchEx *This, func_info_t *func, DISP
     return V_ERROR(&vhres);
 }
 
-static HRESULT function_invoke(DispatchEx *This, func_info_t *func, WORD flags, DISPPARAMS *dp, VARIANT *res,
+static HRESULT func_invoke(DispatchEx *This, func_info_t *func, WORD flags, DISPPARAMS *dp, VARIANT *res,
         EXCEPINFO *ei, IServiceProvider *caller)
 {
     HRESULT hres;
@@ -1368,7 +1532,7 @@ static HRESULT invoke_builtin_prop(DispatchEx *This, DISPID id, LCID lcid, WORD
     }
 
     if(func->func_disp_idx != -1)
-        return function_invoke(This, func, flags, dp, res, ei, caller);
+        return func_invoke(This, func, flags, dp, res, ei, caller);
 
     switch(flags) {
     case DISPATCH_PROPERTYPUT:
-- 
2.31.1




More information about the wine-devel mailing list