From 144056bce0f1195ab8f4bdd8b2c40bf5b39e9d50 Mon Sep 17 00:00:00 2001 From: Jacek Caban Date: Tue, 10 Mar 2015 18:27:31 +0100 Subject: [PATCH] mshtml: Allow setting event handlers to strings. --- dlls/mshtml/htmlevent.c | 62 +++++++++++++++++++++++++++++++++---------- dlls/mshtml/htmlevent.h | 8 +++--- dlls/mshtml/htmlwindow.c | 5 ++-- dlls/mshtml/tests/events.c | 2 +- dlls/mshtml/tests/events.html | 19 +++++++++++++ 5 files changed, 75 insertions(+), 21 deletions(-) diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c index e1ece613643..a14ce728c9d 100644 --- a/dlls/mshtml/htmlevent.c +++ b/dlls/mshtml/htmlevent.c @@ -1367,23 +1367,29 @@ void detach_events(HTMLDocumentNode *doc) } -static HRESULT remove_event_handler(event_target_t **event_target, eventid_t eid) +static void remove_event_handler(DispatchEx *dispex, event_target_t **event_target, eventid_t eid) { + VARIANT *store; + HRESULT hres; + + hres = dispex_get_dprop_ref(dispex, event_info[eid].attr_name, FALSE, &store); + if(SUCCEEDED(hres)) + VariantClear(store); + if(*event_target && (*event_target)->event_table[eid] && (*event_target)->event_table[eid]->handler_prop) { IDispatch_Release((*event_target)->event_table[eid]->handler_prop); (*event_target)->event_table[eid]->handler_prop = NULL; } - - return S_OK; } -static HRESULT set_event_handler_disp(event_target_t **event_target_ptr, HTMLDocumentNode *doc, +static HRESULT set_event_handler_disp(DispatchEx *dispex, event_target_t **event_target_ptr, HTMLDocumentNode *doc, eventid_t eid, IDispatch *disp) { event_target_t *event_target; + remove_event_handler(dispex, event_target_ptr, eid); if(!disp) - return remove_event_handler(event_target_ptr, eid); + return S_OK; event_target = get_event_target(event_target_ptr); if(!event_target) @@ -1392,23 +1398,44 @@ static HRESULT set_event_handler_disp(event_target_t **event_target_ptr, HTMLDoc if(!alloc_handler_vector(event_target, eid, 0)) return E_OUTOFMEMORY; - if(event_target->event_table[eid]->handler_prop) - IDispatch_Release(event_target->event_table[eid]->handler_prop); - event_target->event_table[eid]->handler_prop = disp; IDispatch_AddRef(disp); return ensure_nsevent_handler(doc, event_target, eid); } -HRESULT set_event_handler(event_target_t **event_target, HTMLDocumentNode *doc, eventid_t eid, VARIANT *var) +HRESULT set_event_handler(DispatchEx *dispex, event_target_t **event_target, HTMLDocumentNode *doc, eventid_t eid, VARIANT *var) { switch(V_VT(var)) { case VT_NULL: - return remove_event_handler(event_target, eid); + remove_event_handler(dispex, event_target, eid); + return S_OK; case VT_DISPATCH: - return set_event_handler_disp(event_target, doc, eid, V_DISPATCH(var)); + return set_event_handler_disp(dispex, event_target, doc, eid, V_DISPATCH(var)); + + case VT_BSTR: { + VARIANT *v; + HRESULT hres; + + /* + * Setting event handler to string is a rare case and we don't want to + * complicate nor increase memory of event_target_t for that. Instead, + * we store the value in DispatchEx, which can already handle custom + * properties. + */ + remove_event_handler(dispex, event_target, eid); + + hres = dispex_get_dprop_ref(dispex, event_info[eid].attr_name, TRUE, &v); + if(FAILED(hres)) + return hres; + + V_BSTR(v) = SysAllocString(V_BSTR(var)); + if(!V_BSTR(v)) + return E_OUTOFMEMORY; + V_VT(v) = VT_BSTR; + return S_OK; + } default: FIXME("not handler %s\n", debugstr_variant(var)); @@ -1420,8 +1447,15 @@ HRESULT set_event_handler(event_target_t **event_target, HTMLDocumentNode *doc, return S_OK; } -HRESULT get_event_handler(event_target_t **event_target, eventid_t eid, VARIANT *var) +HRESULT get_event_handler(DispatchEx *dispex, event_target_t **event_target, eventid_t eid, VARIANT *var) { + VARIANT *v; + HRESULT hres; + + hres = dispex_get_dprop_ref(dispex, event_info[eid].attr_name, FALSE, &v); + if(SUCCEEDED(hres) && V_VT(v) != VT_EMPTY) + return VariantCopy(var, v); + if(*event_target && (*event_target)->event_table[eid] && (*event_target)->event_table[eid]->handler_prop) { V_VT(var) = VT_DISPATCH; V_DISPATCH(var) = (*event_target)->event_table[eid]->handler_prop; @@ -1507,7 +1541,7 @@ void bind_node_event(HTMLDocumentNode *doc, event_target_t **event_target, HTMLD return; } - set_event_handler_disp(event_target, doc, eid, disp); + set_event_handler_disp(&node->dispex, event_target, doc, eid, disp); } void update_cp_events(HTMLInnerWindow *window, event_target_t **event_target_ptr, cp_static_data_t *cp) @@ -1547,7 +1581,7 @@ void check_event_attr(HTMLDocumentNode *doc, nsIDOMHTMLElement *nselem) if(disp) { hres = get_node(doc, (nsIDOMNode*)nselem, TRUE, &node); if(SUCCEEDED(hres)) { - set_event_handler_disp(get_node_event_target(node), node->doc, i, disp); + set_event_handler_disp(&node->dispex, get_node_event_target(node), node->doc, i, disp); node_release(node); } IDispatch_Release(disp); diff --git a/dlls/mshtml/htmlevent.h b/dlls/mshtml/htmlevent.h index e312a9c8c15..051783458b0 100644 --- a/dlls/mshtml/htmlevent.h +++ b/dlls/mshtml/htmlevent.h @@ -54,8 +54,8 @@ eventid_t str_to_eid(LPCWSTR) DECLSPEC_HIDDEN; void check_event_attr(HTMLDocumentNode*,nsIDOMHTMLElement*) DECLSPEC_HIDDEN; void release_event_target(event_target_t*) DECLSPEC_HIDDEN; void fire_event(HTMLDocumentNode*,eventid_t,BOOL,nsIDOMNode*,nsIDOMEvent*,IDispatch*) DECLSPEC_HIDDEN; -HRESULT set_event_handler(event_target_t**,HTMLDocumentNode*,eventid_t,VARIANT*) DECLSPEC_HIDDEN; -HRESULT get_event_handler(event_target_t**,eventid_t,VARIANT*) DECLSPEC_HIDDEN; +HRESULT set_event_handler(DispatchEx*,event_target_t**,HTMLDocumentNode*,eventid_t,VARIANT*) DECLSPEC_HIDDEN; +HRESULT get_event_handler(DispatchEx*,event_target_t**,eventid_t,VARIANT*) DECLSPEC_HIDDEN; HRESULT attach_event(event_target_t**,HTMLDocument*,BSTR,IDispatch*,VARIANT_BOOL*) DECLSPEC_HIDDEN; HRESULT detach_event(event_target_t*,HTMLDocument*,BSTR,IDispatch*) DECLSPEC_HIDDEN; HRESULT dispatch_event(HTMLDOMNode*,const WCHAR*,VARIANT*,VARIANT_BOOL*) DECLSPEC_HIDDEN; @@ -78,12 +78,12 @@ static inline event_target_t **get_node_event_target(HTMLDOMNode *node) static inline HRESULT set_node_event(HTMLDOMNode *node, eventid_t eid, VARIANT *var) { - return set_event_handler(get_node_event_target(node), node->doc, eid, var); + return set_event_handler(&node->dispex, get_node_event_target(node), node->doc, eid, var); } static inline HRESULT get_node_event(HTMLDOMNode *node, eventid_t eid, VARIANT *var) { - return get_event_handler(get_node_event_target(node), eid, var); + return get_event_handler(&node->dispex, get_node_event_target(node), eid, var); } static inline HRESULT set_doc_event(HTMLDocument *doc, eventid_t eid, VARIANT *var) diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index 6f3cbd41c21..3a31301aa25 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -95,7 +95,8 @@ static inline HRESULT set_window_event(HTMLWindow *window, eventid_t eid, VARIAN return E_FAIL; } - return set_event_handler(&window->inner_window->doc->body_event_target, window->inner_window->doc, eid, var); + return set_event_handler(&window->inner_window->dispex, &window->inner_window->doc->body_event_target, + window->inner_window->doc, eid, var); } static inline HRESULT get_window_event(HTMLWindow *window, eventid_t eid, VARIANT *var) @@ -105,7 +106,7 @@ static inline HRESULT get_window_event(HTMLWindow *window, eventid_t eid, VARIAN return E_FAIL; } - return get_event_handler(&window->inner_window->doc->body_event_target, eid, var); + return get_event_handler(&window->inner_window->dispex, &window->inner_window->doc->body_event_target, eid, var); } static void detach_inner_window(HTMLInnerWindow *window) diff --git a/dlls/mshtml/tests/events.c b/dlls/mshtml/tests/events.c index 8f4e15e5013..e3e7f729718 100644 --- a/dlls/mshtml/tests/events.c +++ b/dlls/mshtml/tests/events.c @@ -1571,7 +1571,7 @@ static void test_onclick(IHTMLDocument2 *doc) V_VT(&v) = VT_BSTR; V_BSTR(&v) = a2bstr("function();"); hres = IHTMLElement_put_onclick(div, v); - todo_wine ok(hres == S_OK, "put_onclick failed: %08x\n", hres); + ok(hres == S_OK, "put_onclick failed: %08x\n", hres); if(hres == S_OK) { V_VT(&v) = VT_EMPTY; diff --git a/dlls/mshtml/tests/events.html b/dlls/mshtml/tests/events.html index ae83ebef039..5a0bbfb695c 100644 --- a/dlls/mshtml/tests/events.html +++ b/dlls/mshtml/tests/events.html @@ -139,6 +139,24 @@ function test_insert_script() { readystatechange_log = "append"; } +var string_handler_called = false; + +function test_string_event_handler() { + var e = document.createElement("div"); + var event_str = "string_handler_called = true;"; + + document.body.appendChild(e); + e.onclick = event_str; + ok(e.onclick === event_str, "e.onclick = " + e.onclick); + e.click(); + ok(string_handler_called === false, "string handler called"); + + e.setAttribute("onclick", event_str); + ok(e.onclick === event_str, "e.onclick = " + e.onclick); + e.click(); + ok(string_handler_called === false, "string handler called"); +} + window.onload = function() { try { ok(inlscr_complete_called, "onreadystatechange not fired"); @@ -159,6 +177,7 @@ window.onload = function() { ondataavailable_test(); test_handler_this(); test_insert_script(); + test_string_event_handler(); }catch(e) { ok(false, "Got an exception: " + e.message); } -- 2.11.4.GIT