Jacek Caban : mshtml: Suport load event in HTMLXMLHttpRequest object.

Alexandre Julliard julliard at winehq.org
Fri Feb 15 14:37:01 CST 2019


Module: wine
Branch: master
Commit: a5c79dc8a908f0bbab9ce6107f270ac332df2f37
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=a5c79dc8a908f0bbab9ce6107f270ac332df2f37

Author: Jacek Caban <jacek at codeweavers.com>
Date:   Fri Feb 15 14:30:04 2019 +0100

mshtml: Suport load event in HTMLXMLHttpRequest object.

Signed-off-by: Jacek Caban <jacek at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/mshtml/tests/script.c   |   1 +
 dlls/mshtml/tests/xhr.js     |   9 +++-
 dlls/mshtml/xmlhttprequest.c | 111 +++++++++++++++++++++++++++++++++++++------
 3 files changed, 106 insertions(+), 15 deletions(-)

diff --git a/dlls/mshtml/tests/script.c b/dlls/mshtml/tests/script.c
index 2e13f9b..c0ddc81 100644
--- a/dlls/mshtml/tests/script.c
+++ b/dlls/mshtml/tests/script.c
@@ -3463,6 +3463,7 @@ static void run_js_tests(void)
 
     init_protocol_handler();
 
+    run_script_as_http_with_mode("xhr.js", NULL, "9");
     run_script_as_http_with_mode("xhr.js", NULL, "11");
     run_script_as_http_with_mode("elements.js", NULL, "11");
     run_script_as_http_with_mode("es5.js", NULL, "11");
diff --git a/dlls/mshtml/tests/xhr.js b/dlls/mshtml/tests/xhr.js
index fb198c1..8c42816 100644
--- a/dlls/mshtml/tests/xhr.js
+++ b/dlls/mshtml/tests/xhr.js
@@ -18,14 +18,21 @@
 
 function test_xhr() {
     var xhr = new XMLHttpRequest();
+    var complete_cnt = 0;
 
     xhr.onreadystatechange = function() {
         if(xhr.readyState != 4)
             return;
 
         ok(xhr.responseText === "Testing...", "unexpected responseText " + xhr.responseText);
-        next_test();
+        if(complete_cnt++)
+            next_test();
     }
+    var onload_func = xhr.onload = function() {
+        if(complete_cnt++)
+            next_test();
+    };
+    ok(xhr.onload === onload_func, "xhr.onload != onload_func");
 
     xhr.open("POST", "echo.php", true);
     xhr.setRequestHeader("X-Test", "True");
diff --git a/dlls/mshtml/xmlhttprequest.c b/dlls/mshtml/xmlhttprequest.c
index 5164570..e235bf9 100644
--- a/dlls/mshtml/xmlhttprequest.c
+++ b/dlls/mshtml/xmlhttprequest.c
@@ -36,6 +36,8 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
 
+#define MSHTML_DISPID_HTMLXMLHTTPREQUEST_ONLOAD MSHTML_DISPID_CUSTOM_MIN
+
 static HRESULT bstr_to_nsacstr(BSTR bstr, nsACString *str)
 {
     char *cstr = heap_strdupWtoU(bstr);
@@ -96,6 +98,8 @@ typedef struct {
     nsIDOMEventListener nsIDOMEventListener_iface;
     LONG ref;
     HTMLXMLHttpRequest *xhr;
+    BOOL readystatechange_event;
+    BOOL load_event;
 } XMLHttpReqEventListener;
 
 struct HTMLXMLHttpRequest {
@@ -113,15 +117,27 @@ static void detach_xhr_event_listener(XMLHttpReqEventListener *event_listener)
     nsAString str;
     nsresult nsres;
 
+    static const WCHAR loadW[] = {'l','o','a','d',0};
     static const WCHAR readystatechangeW[] =
         {'o','n','r','e','a','d','y','s','t','a','t','e','c','h','a','n','g','e',0};
 
     nsres = nsIXMLHttpRequest_QueryInterface(event_listener->xhr->nsxhr, &IID_nsIDOMEventTarget, (void**)&event_target);
     assert(nsres == NS_OK);
 
-    nsAString_InitDepend(&str, readystatechangeW);
-    nsres = nsIDOMEventTarget_RemoveEventListener(event_target, &str, &event_listener->nsIDOMEventListener_iface, FALSE);
-    nsAString_Finish(&str);
+    if(event_listener->readystatechange_event) {
+        nsAString_InitDepend(&str, readystatechangeW);
+        nsres = nsIDOMEventTarget_RemoveEventListener(event_target, &str, &event_listener->nsIDOMEventListener_iface, FALSE);
+        nsAString_Finish(&str);
+        assert(nsres == NS_OK);
+    }
+
+    if(event_listener->load_event) {
+        nsAString_InitDepend(&str, loadW);
+        nsres = nsIDOMEventTarget_RemoveEventListener(event_target, &str, &event_listener->nsIDOMEventListener_iface, FALSE);
+        nsAString_Finish(&str);
+        assert(nsres == NS_OK);
+    }
+
     nsIDOMEventTarget_Release(event_target);
 
     event_listener->xhr->event_listener = NULL;
@@ -738,6 +754,49 @@ static inline HTMLXMLHttpRequest *impl_from_DispatchEx(DispatchEx *iface)
     return CONTAINING_RECORD(iface, HTMLXMLHttpRequest, event_target.dispex);
 }
 
+static HRESULT HTMLXMLHttpRequest_get_dispid(DispatchEx *dispex, BSTR name, DWORD flags, DISPID *dispid)
+{
+    static const WCHAR onloadW[] = {'o','n','l','o','a','d',0};
+
+    /* onload event handler property is supported, but not exposed by any interface. We implement as a custom property. */
+    if(!strcmpW(onloadW, name)) {
+        *dispid = MSHTML_DISPID_HTMLXMLHTTPREQUEST_ONLOAD;
+        return S_OK;
+    }
+
+    return DISP_E_UNKNOWNNAME;
+}
+
+static HRESULT HTMLXMLHttpRequest_invoke(DispatchEx *dispex, DISPID id, LCID lcid, WORD flags, DISPPARAMS *params,
+        VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller)
+{
+    HTMLXMLHttpRequest *This = impl_from_DispatchEx(dispex);
+
+    if(id == MSHTML_DISPID_HTMLXMLHTTPREQUEST_ONLOAD) {
+        switch(flags) {
+        case DISPATCH_PROPERTYGET:
+            TRACE("(%p) get onload\n", This);
+            return get_event_handler(&This->event_target, EVENTID_LOAD, res);
+
+        case DISPATCH_PROPERTYPUT:
+            if(params->cArgs != 1 || (params->cNamedArgs == 1 && *params->rgdispidNamedArgs != DISPID_PROPERTYPUT)
+               || params->cNamedArgs > 1) {
+                FIXME("invalid args\n");
+                return E_INVALIDARG;
+            }
+
+            TRACE("(%p)->(%p) set onload\n", This, params->rgvarg);
+            return set_event_handler(&This->event_target, EVENTID_LOAD, params->rgvarg);
+
+        default:
+            FIXME("Unimplemented flags %x\n", flags);
+            return E_NOTIMPL;
+        }
+    }
+
+    return DISP_E_UNKNOWNNAME;
+}
+
 static nsISupports *HTMLXMLHttpRequest_get_gecko_target(DispatchEx *dispex)
 {
     HTMLXMLHttpRequest *This = impl_from_DispatchEx(dispex);
@@ -748,37 +807,61 @@ static void HTMLXMLHttpRequest_bind_event(DispatchEx *dispex, eventid_t eid)
 {
     HTMLXMLHttpRequest *This = impl_from_DispatchEx(dispex);
     nsIDOMEventTarget *nstarget;
+    const WCHAR *type_name;
     nsAString type_str;
     nsresult nsres;
 
     static const WCHAR readystatechangeW[] = {'r','e','a','d','y','s','t','a','t','e','c','h','a','n','g','e',0};
+    static const WCHAR loadW[] = {'l','o','a','d',0};
 
     TRACE("(%p)\n", This);
 
-    if(eid != EVENTID_READYSTATECHANGE || This->event_listener)
+    switch(eid) {
+    case EVENTID_READYSTATECHANGE:
+        type_name = readystatechangeW;
+        break;
+    case EVENTID_LOAD:
+        type_name = loadW;
+        break;
+    default:
         return;
+    }
 
-    This->event_listener = heap_alloc(sizeof(*This->event_listener));
-    if(!This->event_listener)
-        return;
+    if(!This->event_listener) {
+        This->event_listener = heap_alloc(sizeof(*This->event_listener));
+        if(!This->event_listener)
+            return;
 
-    This->event_listener->nsIDOMEventListener_iface.lpVtbl = &XMLHttpReqEventListenerVtbl;
-    This->event_listener->ref = 1;
-    This->event_listener->xhr = This;
+        This->event_listener->nsIDOMEventListener_iface.lpVtbl = &XMLHttpReqEventListenerVtbl;
+        This->event_listener->ref = 1;
+        This->event_listener->xhr = This;
+        This->event_listener->readystatechange_event = FALSE;
+        This->event_listener->load_event = FALSE;
+    }
 
     nsres = nsIXMLHttpRequest_QueryInterface(This->nsxhr, &IID_nsIDOMEventTarget, (void**)&nstarget);
     assert(nsres == NS_OK);
 
-    nsAString_InitDepend(&type_str, readystatechangeW);
+    nsAString_InitDepend(&type_str, type_name);
     nsres = nsIDOMEventTarget_AddEventListener(nstarget, &type_str, &This->event_listener->nsIDOMEventListener_iface, FALSE, TRUE, 2);
     nsAString_Finish(&type_str);
-    nsIDOMEventTarget_Release(nstarget);
     if(NS_FAILED(nsres))
-        ERR("AddEventListener failed: %08x\n", nsres);
+        ERR("AddEventListener(%s) failed: %08x\n", debugstr_w(type_name), nsres);
+
+    nsIDOMEventTarget_Release(nstarget);
+
+    if(eid == EVENTID_READYSTATECHANGE)
+        This->event_listener->readystatechange_event = TRUE;
+    else
+        This->event_listener->load_event = TRUE;
 }
 
 static event_target_vtbl_t HTMLXMLHttpRequest_event_target_vtbl = {
-    {NULL},
+    {
+        NULL,
+        HTMLXMLHttpRequest_get_dispid,
+        HTMLXMLHttpRequest_invoke
+    },
     HTMLXMLHttpRequest_get_gecko_target,
     HTMLXMLHttpRequest_bind_event
 };




More information about the wine-cvs mailing list