diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c
index b04fb810232..64ad5552274 100644
--- a/dlls/mshtml/dispex.c
+++ b/dlls/mshtml/dispex.c
@@ -52,6 +52,7 @@ typedef struct {
DISPID id;
BSTR name;
tid_t tid;
+ dispex_hook_invoke_t hook;
SHORT call_vtbl_off;
SHORT put_vtbl_off;
SHORT get_vtbl_off;
@@ -230,7 +231,8 @@ static BOOL is_arg_type_supported(VARTYPE vt)
return FALSE;
}
-static void add_func_info(dispex_data_t *data, tid_t tid, const FUNCDESC *desc, ITypeInfo *dti)
+static void add_func_info(dispex_data_t *data, tid_t tid, const FUNCDESC *desc, ITypeInfo *dti,
+ dispex_hook_invoke_t hook)
{
func_info_t *info;
BSTR name;
@@ -262,6 +264,7 @@ static void add_func_info(dispex_data_t *data, tid_t tid, const FUNCDESC *desc,
info->tid = tid;
info->func_disp_idx = -1;
info->prop_vt = VT_EMPTY;
+ info->hook = hook;
}else {
SysFreeString(name);
}
@@ -326,10 +329,9 @@ static void add_func_info(dispex_data_t *data, tid_t tid, const FUNCDESC *desc,
}
}
-static HRESULT process_interface(dispex_data_t *data, tid_t tid, ITypeInfo *disp_typeinfo, const DISPID *blacklist_dispids)
+static HRESULT process_interface(dispex_data_t *data, tid_t tid, ITypeInfo *disp_typeinfo, const dispex_hook_t *hooks)
{
unsigned i = 7; /* skip IDispatch functions */
- const DISPID *blacklist_iter;
ITypeInfo *typeinfo;
FUNCDESC *funcdesc;
HRESULT hres;
@@ -339,20 +341,25 @@ static HRESULT process_interface(dispex_data_t *data, tid_t tid, ITypeInfo *disp
return hres;
while(1) {
+ const dispex_hook_t *hook = NULL;
+
hres = ITypeInfo_GetFuncDesc(typeinfo, i++, &funcdesc);
if(FAILED(hres))
break;
- if(blacklist_dispids) {
- for(blacklist_iter = blacklist_dispids; *blacklist_iter != DISPID_UNKNOWN; blacklist_iter++) {
- if(*blacklist_iter == funcdesc->memid)
+ if(hooks) {
+ for(hook = hooks; hook->dispid != DISPID_UNKNOWN; hook++) {
+ if(hook->dispid == funcdesc->memid)
break;
}
+ if(hook->dispid == DISPID_UNKNOWN)
+ hook = NULL;
}
- if(!blacklist_dispids || *blacklist_iter == DISPID_UNKNOWN) {
+ if(!hook || hook->invoke) {
TRACE("adding...\n");
- add_func_info(data, tid, funcdesc, disp_typeinfo ? disp_typeinfo : typeinfo);
+ add_func_info(data, tid, funcdesc, disp_typeinfo ? disp_typeinfo : typeinfo,
+ hook ? hook->invoke : NULL);
}
ITypeInfo_ReleaseFuncDesc(typeinfo, funcdesc);
@@ -361,11 +368,11 @@ static HRESULT process_interface(dispex_data_t *data, tid_t tid, ITypeInfo *disp
return S_OK;
}
-void dispex_info_add_interface(dispex_data_t *info, tid_t tid, const DISPID *blacklist_dispids)
+void dispex_info_add_interface(dispex_data_t *info, tid_t tid, const dispex_hook_t *hooks)
{
HRESULT hres;
- hres = process_interface(info, tid, NULL, blacklist_dispids);
+ hres = process_interface(info, tid, NULL, hooks);
if(FAILED(hres))
ERR("process_interface failed: %08x\n", hres);
}
@@ -1239,6 +1246,12 @@ static HRESULT invoke_builtin_prop(DispatchEx *This, DISPID id, LCID lcid, WORD
if(FAILED(hres))
return hres;
+ if(func->hook) {
+ hres = func->hook(This, lcid, flags, dp, res, ei, caller);
+ if(hres != S_FALSE)
+ return hres;
+ }
+
if(func->func_disp_idx != -1)
return function_invoke(This, func, flags, dp, res, ei, caller);
diff --git a/dlls/mshtml/htmlelem.c b/dlls/mshtml/htmlelem.c
index dc712f30579..1bd4ec4899d 100644
--- a/dlls/mshtml/htmlelem.c
+++ b/dlls/mshtml/htmlelem.c
@@ -5398,11 +5398,14 @@ static IHTMLEventObj *HTMLElement_set_current_event(DispatchEx *dispex, IHTMLEve
void HTMLElement_init_dispex_info(dispex_data_t *info, compat_mode_t mode)
{
- static const DISPID elem2_ie11_blacklist[] = {DISPID_IHTMLELEMENT2_DOSCROLL, DISPID_UNKNOWN};
+ static const dispex_hook_t elem2_ie11_hooks[] = {
+ {DISPID_IHTMLELEMENT2_DOSCROLL, NULL},
+ {DISPID_UNKNOWN}
+ };
HTMLDOMNode_init_dispex_info(info, mode);
- dispex_info_add_interface(info, IHTMLElement2_tid, mode >= COMPAT_MODE_IE11 ? elem2_ie11_blacklist : NULL);
+ dispex_info_add_interface(info, IHTMLElement2_tid, mode >= COMPAT_MODE_IE11 ? elem2_ie11_hooks : NULL);
if(mode >= COMPAT_MODE_IE8)
dispex_info_add_interface(info, IElementSelector_tid, NULL);
diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c
index 46697b30b9c..d93a43ee6d3 100644
--- a/dlls/mshtml/htmlevent.c
+++ b/dlls/mshtml/htmlevent.c
@@ -2051,6 +2051,11 @@ static inline EventTarget *impl_from_IEventTarget(IEventTarget *iface)
return CONTAINING_RECORD(iface, EventTarget, IEventTarget_iface);
}
+static inline EventTarget *impl_from_DispatchEx(DispatchEx *iface)
+{
+ return CONTAINING_RECORD(iface, EventTarget, dispex);
+}
+
static HRESULT WINAPI EventTarget_QueryInterface(IEventTarget *iface, REFIID riid, void **ppv)
{
EventTarget *This = impl_from_IEventTarget(iface);
@@ -2162,6 +2167,27 @@ static HRESULT WINAPI EventTarget_dispatchEvent(IEventTarget *iface, IDOMEvent *
return E_NOTIMPL;
}
+HRESULT IEventTarget_addEventListener_hook(DispatchEx *dispex, LCID lcid, WORD flags,
+ DISPPARAMS *dp, VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller)
+{
+ /* If only two arguments were given, implicitly set capture to false */
+ if((flags & DISPATCH_METHOD) && dp->cArgs == 2 && !dp->cNamedArgs) {
+ VARIANT args[3];
+ DISPPARAMS new_dp = {args, NULL, 3, 0};
+ V_VT(args) = VT_BOOL;
+ V_BOOL(args) = VARIANT_FALSE;
+ args[1] = dp->rgvarg[0];
+ args[2] = dp->rgvarg[1];
+
+ TRACE("implicit capture\n");
+
+ return IDispatchEx_InvokeEx(&dispex->IDispatchEx_iface, DISPID_IEVENTTARGET_ADDEVENTLISTENER,
+ lcid, flags, &new_dp, res, ei, caller);
+ }
+
+ return S_FALSE; /* fallback to default */
+}
+
static const IEventTargetVtbl EventTargetVtbl = {
EventTarget_QueryInterface,
EventTarget_AddRef,
@@ -2210,8 +2236,13 @@ HRESULT EventTarget_QI(EventTarget *event_target, REFIID riid, void **ppv)
void EventTarget_init_dispex_info(dispex_data_t *dispex_info, compat_mode_t compat_mode)
{
+ static const dispex_hook_t IEventTarget_hooks[] = {
+ {DISPID_IEVENTTARGET_ADDEVENTLISTENER, IEventTarget_addEventListener_hook},
+ {DISPID_UNKNOWN}
+ };
+
if(compat_mode >= COMPAT_MODE_IE9)
- dispex_info_add_interface(dispex_info, IEventTarget_tid, NULL);
+ dispex_info_add_interface(dispex_info, IEventTarget_tid, IEventTarget_hooks);
}
static int event_id_cmp(const void *key, const struct wine_rb_entry *entry)
diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h
index 69fe90c8108..f55f064dae7 100644
--- a/dlls/mshtml/mshtml_private.h
+++ b/dlls/mshtml/mshtml_private.h
@@ -283,6 +283,14 @@ typedef struct {
dispex_data_t *delayed_init_info;
} dispex_static_data_t;
+typedef HRESULT (*dispex_hook_invoke_t)(DispatchEx*,LCID,WORD,DISPPARAMS*,VARIANT*,
+ EXCEPINFO*,IServiceProvider*);
+
+typedef struct {
+ DISPID dispid;
+ dispex_hook_invoke_t invoke;
+} dispex_hook_t;
+
struct DispatchEx {
IDispatchEx IDispatchEx_iface;
@@ -331,7 +339,7 @@ void dispex_unlink(DispatchEx*) DECLSPEC_HIDDEN;
void release_typelib(void) DECLSPEC_HIDDEN;
HRESULT get_class_typeinfo(const CLSID*,ITypeInfo**) DECLSPEC_HIDDEN;
const void *dispex_get_vtbl(DispatchEx*) DECLSPEC_HIDDEN;
-void dispex_info_add_interface(dispex_data_t*,tid_t,const DISPID*) DECLSPEC_HIDDEN;
+void dispex_info_add_interface(dispex_data_t*,tid_t,const dispex_hook_t*) DECLSPEC_HIDDEN;
compat_mode_t dispex_compat_mode(DispatchEx*) DECLSPEC_HIDDEN;
static inline void init_dispex(DispatchEx *dispex, IUnknown *outer, dispex_static_data_t *desc)
diff --git a/dlls/mshtml/tests/events.js b/dlls/mshtml/tests/events.js
index 4c552b65085..d613c9d5bdc 100644
--- a/dlls/mshtml/tests/events.js
+++ b/dlls/mshtml/tests/events.js
@@ -62,6 +62,7 @@ function test_listener_order() {
document.body.onclick = record_call("body.onclick");
document.body.addEventListener("click", record_call("body.click(capture)"), true);
document.body.addEventListener("click", record_call("body.click(bubble)"), false);
+ document.body.addEventListener("click", record_call("body.click(bubble2)"));
document.body.attachEvent("onclick", record_call("body.click(attached)"));
div.attachEvent("onclick", record_call("div.click(attached)"));
@@ -74,9 +75,9 @@ function test_listener_order() {
div.click();
ok(calls === "window.click(capture),document.click(capture),body.click(capture),"
+ "div.click(attached),div.click(bubble),div.onclick,div.click(capture1),"
- + "div.click(capture2),body.onclick,body.click(bubble),body.click(attached),"
- + "document.click(attached),document.click(bubble),document.onclick,"
- + "window.click(bubble),", "calls = " + calls);
+ + "div.click(capture2),body.onclick,body.click(bubble),body.click(bubble2),"
+ + "body.click(attached),document.click(attached),document.click(bubble),"
+ + "document.onclick,window.click(bubble),", "calls = " + calls);
div.onclick = record_call("new div.onclick");
@@ -84,9 +85,9 @@ function test_listener_order() {
div.click();
ok(calls === "window.click(capture),document.click(capture),body.click(capture),"
+ "div.click(attached),div.click(bubble),new div.onclick,div.click(capture1),"
- + "div.click(capture2),body.onclick,body.click(bubble),body.click(attached),"
- + "document.click(attached),document.click(bubble),document.onclick,"
- + "window.click(bubble),", "calls = " + calls);
+ + "div.click(capture2),body.onclick,body.click(bubble),body.click(bubble2),"
+ + "body.click(attached),document.click(attached),document.click(bubble),"
+ + "document.onclick,window.click(bubble),", "calls = " + calls);
next_test();
}