[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, ¶ms, 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, ¶ms, 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