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@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: