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);
}