From: Jacek Caban jacek@codeweavers.com
Based on patch by Gabriel Ivăncescu. --- dlls/mshtml/dispex.c | 96 +++++++++++++++++++++++++++- dlls/mshtml/htmlwindow.c | 12 +++- dlls/mshtml/mshtml_private_iface.idl | 1 + dlls/mshtml/tests/documentmode.js | 52 +++++++++++++++ 4 files changed, 159 insertions(+), 2 deletions(-)
diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index a6cb664469f..65e04343b88 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -799,6 +799,33 @@ static HRESULT typeinfo_invoke(DispatchEx *This, func_info_t *func, WORD flags, return hres; }
+static HRESULT function_call(func_disp_t *func, DISPPARAMS *dp, LCID lcid, VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) +{ + DISPPARAMS params = { dp->rgvarg, NULL, dp->cArgs - 1, 0 }; + IWineJSDispatchHost *this_iface; + VARIANT *arg; + HRESULT hres; + + arg = dp->rgvarg + dp->cArgs - 1; + if(dp->cArgs < 1 || V_VT(arg) != VT_DISPATCH || !V_DISPATCH(arg)) + return CTL_E_ILLEGALFUNCTIONCALL; + + hres = IDispatch_QueryInterface(V_DISPATCH(arg), &IID_IWineJSDispatchHost, (void**)&this_iface); + if(FAILED(hres)) + return CTL_E_ILLEGALFUNCTIONCALL; + + hres = IWineJSDispatchHost_CallFunction(this_iface, func->info->id, func->info->tid, ¶ms, res, ei, caller); + IWineJSDispatchHost_Release(this_iface); + return (hres == E_UNEXPECTED) ? CTL_E_ILLEGALFUNCTIONCALL : hres; +} + +static const struct { + const WCHAR *name; + HRESULT (*invoke)(func_disp_t*,DISPPARAMS*,LCID,VARIANT*,EXCEPINFO*,IServiceProvider*); +} function_props[] = { + { L"call", function_call } +}; + static inline func_disp_t *impl_from_DispatchEx(DispatchEx *iface) { return CONTAINING_RECORD(iface, func_disp_t, dispex); @@ -866,9 +893,58 @@ 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((flags & fdexNameCaseInsensitive) ? wcsicmp(name, function_props[i].name) : wcscmp(name, function_props[i].name)) + continue; + *dispid = MSHTML_DISPID_CUSTOM_MIN + i; + return S_OK; + } + return DISP_E_UNKNOWNNAME; +} + +static HRESULT function_get_name(DispatchEx *dispex, DISPID id, BSTR *name) +{ + DWORD idx = id - MSHTML_DISPID_CUSTOM_MIN; + + if(idx >= ARRAY_SIZE(function_props)) + return DISP_E_MEMBERNOTFOUND; + + return (*name = SysAllocString(function_props[idx].name)) ? S_OK : E_OUTOFMEMORY; +} + +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_MEMBERNOTFOUND; + + switch(flags) { + case DISPATCH_METHOD|DISPATCH_PROPERTYGET: + if(!res) + return E_INVALIDARG; + /* fall through */ + case DISPATCH_METHOD: + return function_props[idx].invoke(This, params, lcid, res, ei, caller); + default: + return MSHTML_E_INVALID_PROPERTY; + } + + return S_OK; +} + static const dispex_static_data_vtbl_t function_dispex_vtbl = { .destructor = function_destructor, .value = function_value, + .get_dispid = function_get_dispid, + .get_name = function_get_name, + .invoke = function_invoke };
static const tid_t function_iface_tids[] = {0}; @@ -1980,6 +2056,23 @@ static HRESULT WINAPI DispatchEx_GetNameSpaceParent(IWineJSDispatchHost *iface, return E_NOTIMPL; }
+static HRESULT WINAPI DispatchEx_CallFunction(IWineJSDispatchHost *iface, DISPID id, UINT32 iid, DISPPARAMS *dp, VARIANT *ret, + EXCEPINFO *ei, IServiceProvider *caller) +{ + DispatchEx *This = impl_from_IWineJSDispatchHost(iface); + func_info_t *func; + HRESULT hres; + + TRACE("%s (%p)->(%lx %x %p %p %p %p)\n", This->info->desc->name, This, id, iid, dp, ret, ei, caller); + + hres = get_builtin_func(This->info, id, &func); + if(FAILED(hres)) + return hres; + if(func->tid != iid || func->func_disp_idx < 0) + return E_UNEXPECTED; + return call_builtin_function(This, func, dp, ret, ei, caller); +} + static IWineJSDispatchHostVtbl JSDispatchHostVtbl = { DispatchEx_QueryInterface, DispatchEx_AddRef, @@ -1995,7 +2088,8 @@ static IWineJSDispatchHostVtbl JSDispatchHostVtbl = { DispatchEx_GetMemberProperties, DispatchEx_GetMemberName, DispatchEx_GetNextDispID, - DispatchEx_GetNameSpaceParent + DispatchEx_GetNameSpaceParent, + DispatchEx_CallFunction, };
static nsresult NSAPI dispex_traverse(void *ccp, void *p, nsCycleCollectionTraversalCallback *cb) diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index 1f4fe6ffd7a..cf0920783d7 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -3440,6 +3440,15 @@ static HRESULT WINAPI WindowDispEx_GetNameSpaceParent(IWineJSDispatchHost *iface return S_OK; }
+static HRESULT WINAPI WindowDispEx_CallFunction(IWineJSDispatchHost *iface, DISPID id, UINT32 iid, DISPPARAMS *dp, VARIANT *ret, + EXCEPINFO *ei, IServiceProvider *caller) +{ + HTMLOuterWindow *This = impl_from_IWineJSDispatchHost(iface); + + return IWineJSDispatchHost_CallFunction(&This->base.inner_window->event_target.dispex.IWineJSDispatchHost_iface, + id, iid, dp, ret, ei, caller); +} + static const IWineJSDispatchHostVtbl WindowDispExVtbl = { WindowDispEx_QueryInterface, WindowDispEx_AddRef, @@ -3455,7 +3464,8 @@ static const IWineJSDispatchHostVtbl WindowDispExVtbl = { WindowDispEx_GetMemberProperties, WindowDispEx_GetMemberName, WindowDispEx_GetNextDispID, - WindowDispEx_GetNameSpaceParent + WindowDispEx_GetNameSpaceParent, + WindowDispEx_CallFunction, };
static inline HTMLOuterWindow *impl_from_IEventTarget(IEventTarget *iface) diff --git a/dlls/mshtml/mshtml_private_iface.idl b/dlls/mshtml/mshtml_private_iface.idl index 46bf692b240..f4292e298d0 100644 --- a/dlls/mshtml/mshtml_private_iface.idl +++ b/dlls/mshtml/mshtml_private_iface.idl @@ -266,4 +266,5 @@ interface IWineXMLHttpRequestPrivate : IDispatch ] interface IWineJSDispatchHost : IDispatchEx { + HRESULT CallFunction(DISPID id, UINT32 iid, DISPPARAMS *dp, VARIANT *ret, EXCEPINFO *ei, IServiceProvider *caller); } diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 23fd2128e5f..327d744f00d 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -352,6 +352,58 @@ sync_test("builtin_toString", function() { } });
+sync_test("builtin_obj", function() { + var v = document.documentMode; + var f = document.createElement; + var e; + + if(v < 9) { + ok(!(window instanceof Object), "window instance of Object"); + ok(!(document instanceof Object), "document instance of Object"); + ok(!("arguments" in f), "arguments in f"); + ok(!("length" in f), "length in f"); + e = 0; + try { + f.toString(); + }catch(ex) { + e = ex.number; + } + ok(e === 0xa01b6 - 0x80000000, "[f.toString] e = " + e); + try { + window.toString.call(null); + ok(false, "expected exception calling window.toString with null context"); + }catch(ex) {} + } + + e = 0; + try { + f.call(Object, "div"); + }catch(ex) { + e = ex.number; + } + todo_wine_if(v >= 9). + ok(e === (v < 9 ? 0xa0005 : 0x0ffff) - 0x80000000, "[f.call(Object, 'div')] e = " + e); + + e = 0; + try { + f.call(null, "div"); + }catch(ex) { + e = ex.number; + } + todo_wine_if(v >= 9). + ok(e === (v < 9 ? 0xa0005 : 0x0ffff) - 0x80000000, "[f.call(null, 'div')] e = " + e); + + var elem1 = f.call(document, "div"); + var elem2 = f.call(document, "br"); + document.body.appendChild(elem1); + document.body.appendChild(elem2); + elem1.onclick = function() { ok(false, "unexpected elem1.onclick"); }; + var clicked = false; + elem2.onclick = function() { clicked = true; }; + elem1.click.call(elem2); + ok(clicked === true, "elem2.onclick not called"); +}); + sync_test("elem_props", function() { var elem = document.documentElement;