From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmlevent.c | 35 +++++++++-- dlls/mshtml/htmlevent.h | 1 + dlls/mshtml/htmlwindow.c | 116 ++++++++++++++++++++++++++++++++++- dlls/mshtml/mshtml_private.h | 1 + dlls/mshtml/tests/events.c | 18 ++++++ dlls/mshtml/tests/script.c | 18 ++++++ 6 files changed, 182 insertions(+), 7 deletions(-)
diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c index 59cb44a6475..2ba912f5fb3 100644 --- a/dlls/mshtml/htmlevent.c +++ b/dlls/mshtml/htmlevent.c @@ -318,6 +318,21 @@ static void remove_event_listener(EventTarget *event_target, const WCHAR *type_n } }
+static IEventTarget *get_event_target_iface(EventTarget *event_target) +{ + const event_target_vtbl_t *vtbl = dispex_get_vtbl(&event_target->dispex); + IEventTarget *ret; + + if(vtbl->get_dispatch_this) { + IDispatch *disp = vtbl->get_dispatch_this(&event_target->dispex); + IDispatch_QueryInterface(disp, &IID_IEventTarget, (void**)&ret); + }else { + ret = &event_target->IEventTarget_iface; + IEventTarget_AddRef(ret); + } + return ret; +} + static HRESULT get_gecko_target(IEventTarget*,nsIDOMEventTarget**);
typedef struct { @@ -1049,7 +1064,7 @@ static HRESULT WINAPI DOMEvent_get_currentTarget(IDOMEvent *iface, IEventTarget TRACE("(%p)->(%p)\n", This, p);
if(This->current_target) - IEventTarget_AddRef(*p = &This->current_target->IEventTarget_iface); + *p = get_event_target_iface(This->current_target); else *p = NULL; return S_OK; @@ -1082,7 +1097,7 @@ static HRESULT WINAPI DOMEvent_get_target(IDOMEvent *iface, IEventTarget **p) TRACE("(%p)->(%p)\n", This, p);
if(This->target) - IEventTarget_AddRef(*p = &This->target->IEventTarget_iface); + *p = get_event_target_iface(This->target); else *p = NULL; return S_OK; @@ -3573,10 +3588,10 @@ static BOOL is_cp_event(cp_static_data_t *data, DISPID dispid) static void call_event_handlers(EventTarget *event_target, DOMEvent *event, dispatch_mode_t dispatch_mode) { const listener_container_t *container = get_listener_container(event_target, event->type, FALSE); + const event_target_vtbl_t *vtbl = dispex_get_vtbl(&event_target->dispex); event_listener_t *listener, listeners_buf[8], *listeners = listeners_buf; unsigned listeners_cnt, listeners_size; ConnectionPointContainer *cp_container = NULL; - const event_target_vtbl_t *vtbl = NULL; BOOL skip_onevent_listener = FALSE; VARIANT v; HRESULT hres; @@ -3597,9 +3612,14 @@ static void call_event_handlers(EventTarget *event_target, DOMEvent *event, disp V_VT(&arg) = VT_DISPATCH; V_DISPATCH(&arg) = (IDispatch*)&event_target->dispex.IDispatchEx_iface; V_VT(&v) = VT_EMPTY; + if(vtbl->get_dispatch_this) + V_DISPATCH(&arg) = vtbl->get_dispatch_this(&event_target->dispex); + IDispatch_AddRef(V_DISPATCH(&arg));
TRACE("%p %s >>>\n", event_target, debugstr_w(event->type)); hres = call_disp_func(listener->function, &dp, &v); + IDispatch_Release(V_DISPATCH(&arg)); + if(hres == S_OK) { TRACE("%p %s <<< %s\n", event_target, debugstr_w(event->type), debugstr_variant(&v));
@@ -3673,6 +3693,10 @@ static void call_event_handlers(EventTarget *event_target, DOMEvent *event, disp
V_VT(args) = VT_DISPATCH; V_DISPATCH(args) = (IDispatch*)&event_target->dispex.IDispatchEx_iface; + if(vtbl->get_dispatch_this) + V_DISPATCH(args) = vtbl->get_dispatch_this(&event_target->dispex); + IDispatch_AddRef(V_DISPATCH(args)); + V_VT(args+1) = VT_DISPATCH; V_DISPATCH(args+1) = dispatch_mode == DISPATCH_LEGACY ? (IDispatch*)event->event_obj : (IDispatch*)&event->IDOMEvent_iface; @@ -3680,6 +3704,8 @@ static void call_event_handlers(EventTarget *event_target, DOMEvent *event, disp
TRACE("%p %s >>>\n", event_target, debugstr_w(event->type)); hres = call_disp_func(listener->function, &dp, &v); + IDispatch_Release(V_DISPATCH(args)); + if(hres == S_OK) { TRACE("%p %s <<< %s\n", event_target, debugstr_w(event->type), debugstr_variant(&v)); @@ -3729,8 +3755,7 @@ static void call_event_handlers(EventTarget *event_target, DOMEvent *event, disp if(listeners != listeners_buf) free(listeners);
- if(event->phase != DEP_CAPTURING_PHASE && event_info[event->event_id].dispid - && (vtbl = dispex_get_vtbl(&event_target->dispex))->get_cp_container) + if(event->phase != DEP_CAPTURING_PHASE && event_info[event->event_id].dispid && vtbl->get_cp_container) cp_container = vtbl->get_cp_container(&event_target->dispex); if(cp_container) { if(cp_container->cps) { diff --git a/dlls/mshtml/htmlevent.h b/dlls/mshtml/htmlevent.h index cf33daa4709..9150e04b239 100644 --- a/dlls/mshtml/htmlevent.h +++ b/dlls/mshtml/htmlevent.h @@ -128,6 +128,7 @@ void detach_nsevent(HTMLDocumentNode*,const WCHAR*); /* We extend dispex vtbl for EventTarget functions to avoid separated vtbl. */ typedef struct { dispex_static_data_vtbl_t dispex_vtbl; + IDispatch *(*get_dispatch_this)(DispatchEx*); nsISupports *(*get_gecko_target)(DispatchEx*); void (*bind_event)(DispatchEx*,eventid_t); EventTarget *(*get_parent_event_target)(DispatchEx*); diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index 1c97e63789a..de09a99000f 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -260,9 +260,19 @@ static HRESULT WINAPI outer_window_QueryInterface(IHTMLWindow2 *iface, REFIID ri }else if(IsEqualGUID(&IID_nsCycleCollectionISupports, riid)) { *ppv = &This->base.IHTMLWindow2_iface; return S_OK; - }else { - return EventTarget_QI(&This->base.inner_window->event_target, riid, ppv); + }else if(IsEqualGUID(&IID_IEventTarget, riid)) { + if(!This->base.inner_window->doc || This->base.inner_window->doc->document_mode < COMPAT_MODE_IE9) { + *ppv = NULL; + return E_NOINTERFACE; + } + *ppv = &This->IEventTarget_iface; + IHTMLWindow2_AddRef(&This->base.IHTMLWindow2_iface); + return S_OK; } + + WARN("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv); + *ppv = NULL; + return E_NOINTERFACE; }
static ULONG WINAPI outer_window_AddRef(IHTMLWindow2 *iface) @@ -3771,6 +3781,100 @@ static const IDispatchExVtbl WindowDispExVtbl = { WindowDispEx_GetNameSpaceParent };
+static inline HTMLOuterWindow *impl_from_IEventTarget(IEventTarget *iface) +{ + return CONTAINING_RECORD(iface, HTMLOuterWindow, IEventTarget_iface); +} + +static HRESULT WINAPI WindowEventTarget_QueryInterface(IEventTarget *iface, REFIID riid, void **ppv) +{ + HTMLOuterWindow *This = impl_from_IEventTarget(iface); + + return IHTMLWindow2_QueryInterface(&This->base.IHTMLWindow2_iface, riid, ppv); +} + +static ULONG WINAPI WindowEventTarget_AddRef(IEventTarget *iface) +{ + HTMLOuterWindow *This = impl_from_IEventTarget(iface); + + return IHTMLWindow2_AddRef(&This->base.IHTMLWindow2_iface); +} + +static ULONG WINAPI WindowEventTarget_Release(IEventTarget *iface) +{ + HTMLOuterWindow *This = impl_from_IEventTarget(iface); + + return IHTMLWindow2_Release(&This->base.IHTMLWindow2_iface); +} + +static HRESULT WINAPI WindowEventTarget_GetTypeInfoCount(IEventTarget *iface, UINT *pctinfo) +{ + HTMLOuterWindow *This = impl_from_IEventTarget(iface); + + return IDispatchEx_GetTypeInfoCount(&This->base.IDispatchEx_iface, pctinfo); +} + +static HRESULT WINAPI WindowEventTarget_GetTypeInfo(IEventTarget *iface, UINT iTInfo, + LCID lcid, ITypeInfo **ppTInfo) +{ + HTMLOuterWindow *This = impl_from_IEventTarget(iface); + + return IDispatchEx_GetTypeInfo(&This->base.IDispatchEx_iface, iTInfo, lcid, ppTInfo); +} + +static HRESULT WINAPI WindowEventTarget_GetIDsOfNames(IEventTarget *iface, REFIID riid, LPOLESTR *rgszNames, + UINT cNames, LCID lcid, DISPID *rgDispId) +{ + HTMLOuterWindow *This = impl_from_IEventTarget(iface); + + return IDispatchEx_GetIDsOfNames(&This->base.IDispatchEx_iface, riid, rgszNames, cNames, lcid, rgDispId); +} + +static HRESULT WINAPI WindowEventTarget_Invoke(IEventTarget *iface, DISPID dispIdMember, REFIID riid, LCID lcid, + WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + HTMLOuterWindow *This = impl_from_IEventTarget(iface); + + return IDispatchEx_Invoke(&This->base.IDispatchEx_iface, dispIdMember, riid, lcid, wFlags, pDispParams, + pVarResult, pExcepInfo, puArgErr); +} + +static HRESULT WINAPI WindowEventTarget_addEventListener(IEventTarget *iface, BSTR type, IDispatch *listener, + VARIANT_BOOL capture) +{ + HTMLOuterWindow *This = impl_from_IEventTarget(iface); + + return IEventTarget_addEventListener(&This->base.inner_window->event_target.IEventTarget_iface, type, listener, capture); +} + +static HRESULT WINAPI WindowEventTarget_removeEventListener(IEventTarget *iface, BSTR type, IDispatch *listener, + VARIANT_BOOL capture) +{ + HTMLOuterWindow *This = impl_from_IEventTarget(iface); + + return IEventTarget_removeEventListener(&This->base.inner_window->event_target.IEventTarget_iface, type, listener, capture); +} + +static HRESULT WINAPI WindowEventTarget_dispatchEvent(IEventTarget *iface, IDOMEvent *event_iface, VARIANT_BOOL *result) +{ + HTMLOuterWindow *This = impl_from_IEventTarget(iface); + + return IEventTarget_dispatchEvent(&This->base.inner_window->event_target.IEventTarget_iface, event_iface, result); +} + +static const IEventTargetVtbl EventTargetVtbl = { + WindowEventTarget_QueryInterface, + WindowEventTarget_AddRef, + WindowEventTarget_Release, + WindowEventTarget_GetTypeInfoCount, + WindowEventTarget_GetTypeInfo, + WindowEventTarget_GetIDsOfNames, + WindowEventTarget_Invoke, + WindowEventTarget_addEventListener, + WindowEventTarget_removeEventListener, + WindowEventTarget_dispatchEvent +}; + static inline HTMLWindow *impl_from_IServiceProvider(IServiceProvider *iface) { return CONTAINING_RECORD(iface, HTMLWindow, IServiceProvider_iface); @@ -4075,6 +4179,12 @@ static compat_mode_t HTMLWindow_get_compat_mode(DispatchEx *dispex) return lock_document_mode(This->doc); }
+static IDispatch *HTMLWindow_get_dispatch_this(DispatchEx *dispex) +{ + HTMLInnerWindow *This = impl_from_DispatchEx(dispex); + return (IDispatch*)&This->base.outer_window->base.IHTMLWindow2_iface; +} + static nsISupports *HTMLWindow_get_gecko_target(DispatchEx *dispex) { HTMLInnerWindow *This = impl_from_DispatchEx(dispex); @@ -4193,6 +4303,7 @@ static const event_target_vtbl_t HTMLWindow_event_target_vtbl = { .next_dispid = HTMLWindow_next_dispid, .get_compat_mode = HTMLWindow_get_compat_mode, }, + .get_dispatch_this = HTMLWindow_get_dispatch_this, .get_gecko_target = HTMLWindow_get_gecko_target, .bind_event = HTMLWindow_bind_event, .set_current_event = HTMLWindow_set_current_event @@ -4351,6 +4462,7 @@ HRESULT create_outer_window(GeckoBrowser *browser, mozIDOMWindowProxy *mozwindow if(!window) return E_OUTOFMEMORY; window->base.IHTMLWindow2_iface.lpVtbl = &outer_window_HTMLWindow2Vtbl; + window->IEventTarget_iface.lpVtbl = &EventTargetVtbl;
window->base.outer_window = window; window->base.inner_window = NULL; diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 1ea9e79a18a..859ce374951 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -551,6 +551,7 @@ struct HTMLWindow {
struct HTMLOuterWindow { HTMLWindow base; + IEventTarget IEventTarget_iface;
nsCycleCollectingAutoRefCnt ccref; LONG task_magic; diff --git a/dlls/mshtml/tests/events.c b/dlls/mshtml/tests/events.c index 7f7515bbcef..f972c2a8316 100644 --- a/dlls/mshtml/tests/events.c +++ b/dlls/mshtml/tests/events.c @@ -1469,8 +1469,26 @@ EVENT_HANDLER_FUNC_OBJ(onvisibilitychange); static HRESULT WINAPI onbeforeunload(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) { + IEventTarget *event_target; + IHTMLWindow2 *window2; + IDOMEvent *event; + HRESULT hres; + CHECK_EXPECT(onbeforeunload); test_event_args(NULL, id, wFlags, pdp, pvarRes, pei, pspCaller); + + hres = IDispatch_QueryInterface(V_DISPATCH(&pdp->rgvarg[1]), &IID_IDOMEvent, (void**)&event); + ok(hres == S_OK, "Could not get IDOMEvent iface: %08lx\n", hres); + hres = IDOMEvent_get_target(event, &event_target); + ok(hres == S_OK, "get_target failed: %08lx\n", hres); + IDOMEvent_Release(event); + + hres = IEventTarget_QueryInterface(event_target, &IID_IHTMLWindow2, (void**)&window2); + ok(hres == S_OK, "Could not get IHTMLWindow2 iface: %08lx\n", hres); + ok(window2 == window, "event_target's window iface != window\n"); + IHTMLWindow2_Release(window2); + + IEventTarget_Release(event_target); return S_OK; }
diff --git a/dlls/mshtml/tests/script.c b/dlls/mshtml/tests/script.c index ec4cf8a8587..dc5dac98ee7 100644 --- a/dlls/mshtml/tests/script.c +++ b/dlls/mshtml/tests/script.c @@ -197,6 +197,21 @@ static BOOL skip_loadobject_tests; static IActiveScriptSite *site, *site2; static SCRIPTSTATE state, state2;
+static BOOL iface_cmp(IUnknown *iface1, IUnknown *iface2) +{ + IUnknown *unk1, *unk2; + + if(iface1 == iface2) + return TRUE; + + IUnknown_QueryInterface(iface1, &IID_IHTMLWindow2, (void**)&unk1); + IUnknown_Release(unk1); + IUnknown_QueryInterface(iface2, &IID_IHTMLWindow2, (void**)&unk2); + IUnknown_Release(unk2); + + return unk1 == unk2; +} + static BOOL init_key(const WCHAR *key_name, const WCHAR *def_value, BOOL init) { HKEY hkey; @@ -4483,6 +4498,9 @@ static void test_exec_script(IHTMLDocument2 *doc, const WCHAR *codew, const WCHA hres = IHTMLDocument2_get_parentWindow(doc, &window); ok(hres == S_OK, "get_parentWindow failed: %08lx\n", hres);
+ todo_wine + ok(iface_cmp((IUnknown *)window, (IUnknown *)window_dispex), "window != dispex_window\n"); + code = SysAllocString(codew); lang = SysAllocString(langw);