Jacek Caban : mshtml: Added IEventTarget stub implementation.

Alexandre Julliard julliard at winehq.org
Fri Sep 22 15:49:05 CDT 2017


Module: wine
Branch: master
Commit: 455d68467116dd962caceb844a74d8ee4ef8484c
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=455d68467116dd962caceb844a74d8ee4ef8484c

Author: Jacek Caban <jacek at codeweavers.com>
Date:   Thu Sep 21 23:25:55 2017 +0200

mshtml: Added IEventTarget stub implementation.

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

---

 dlls/mshtml/dispex.c         |   8 ++-
 dlls/mshtml/htmlevent.c      | 126 +++++++++++++++++++++++++++++++++++++++++++
 dlls/mshtml/mshtml_private.h |   2 +
 dlls/mshtml/tests/dom.c      |  28 ++++++++++
 4 files changed, 162 insertions(+), 2 deletions(-)

diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c
index 95c17b8..de478f3 100644
--- a/dlls/mshtml/dispex.c
+++ b/dlls/mshtml/dispex.c
@@ -1346,6 +1346,11 @@ HRESULT remove_attribute(DispatchEx *This, DISPID id, VARIANT_BOOL *success)
     }
 }
 
+compat_mode_t dispex_compat_mode(DispatchEx *dispex)
+{
+    return dispex->info->desc->vtbl->get_compat_mode(dispex);
+}
+
 static dispex_data_t *ensure_dispex_info(dispex_static_data_t *desc, compat_mode_t compat_mode)
 {
     if(!desc->info_cache[compat_mode]) {
@@ -1362,8 +1367,7 @@ static BOOL ensure_real_info(DispatchEx *dispex)
     if(dispex->info != dispex->info->desc->delayed_init_info)
         return TRUE;
 
-    dispex->info = ensure_dispex_info(dispex->info->desc,
-                                      dispex->info->desc->vtbl->get_compat_mode(dispex));
+    dispex->info = ensure_dispex_info(dispex->info->desc, dispex_compat_mode(dispex));
     return dispex->info != NULL;
 }
 
diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c
index 0061384..4372066 100644
--- a/dlls/mshtml/htmlevent.c
+++ b/dlls/mshtml/htmlevent.c
@@ -1638,8 +1638,120 @@ HRESULT doc_init_events(HTMLDocumentNode *doc)
     return S_OK;
 }
 
+static inline EventTarget *impl_from_IEventTarget(IEventTarget *iface)
+{
+    return CONTAINING_RECORD(iface, EventTarget, IEventTarget_iface);
+}
+
+static HRESULT WINAPI EventTarget_QueryInterface(IEventTarget *iface, REFIID riid, void **ppv)
+{
+    EventTarget *This = impl_from_IEventTarget(iface);
+    return IDispatchEx_QueryInterface(&This->dispex.IDispatchEx_iface, riid, ppv);
+}
+
+static ULONG WINAPI EventTarget_AddRef(IEventTarget *iface)
+{
+    EventTarget *This = impl_from_IEventTarget(iface);
+    return IDispatchEx_AddRef(&This->dispex.IDispatchEx_iface);
+}
+
+static ULONG WINAPI EventTarget_Release(IEventTarget *iface)
+{
+    EventTarget *This = impl_from_IEventTarget(iface);
+    return IDispatchEx_Release(&This->dispex.IDispatchEx_iface);
+}
+
+static HRESULT WINAPI EventTarget_GetTypeInfoCount(IEventTarget *iface, UINT *pctinfo)
+{
+    EventTarget *This = impl_from_IEventTarget(iface);
+    return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
+}
+
+static HRESULT WINAPI EventTarget_GetTypeInfo(IEventTarget *iface, UINT iTInfo,
+                                              LCID lcid, ITypeInfo **ppTInfo)
+{
+    EventTarget *This = impl_from_IEventTarget(iface);
+    return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
+}
+
+static HRESULT WINAPI EventTarget_GetIDsOfNames(IEventTarget *iface, REFIID riid, LPOLESTR *rgszNames,
+                                                UINT cNames, LCID lcid, DISPID *rgDispId)
+{
+    EventTarget *This = impl_from_IEventTarget(iface);
+    return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid,
+            rgszNames, cNames, lcid, rgDispId);
+}
+
+static HRESULT WINAPI EventTarget_Invoke(IEventTarget *iface, DISPID dispIdMember,
+                                         REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
+                                         VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
+{
+    EventTarget *This = impl_from_IEventTarget(iface);
+    return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, dispIdMember,
+            riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
+}
+
+static HRESULT WINAPI EventTarget_addEventListener(IEventTarget *iface, BSTR type,
+                                                   IDispatch *listener, VARIANT_BOOL capture)
+{
+    EventTarget *This = impl_from_IEventTarget(iface);
+    FIXME("(%p)->(%s %p %x)\n", This, debugstr_w(type), listener, capture);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI EventTarget_removeEventListener(IEventTarget *iface, BSTR type,
+                                                      IDispatch *listener, VARIANT_BOOL capture)
+{
+    EventTarget *This = impl_from_IEventTarget(iface);
+    FIXME("(%p)->(%s %p %x)\n", This, debugstr_w(type), listener, capture);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI EventTarget_dispatchEvent(IEventTarget *iface, IDOMEvent *event, VARIANT_BOOL *result)
+{
+    EventTarget *This = impl_from_IEventTarget(iface);
+    FIXME("(%p)->(%p %p)\n", This, event, result);
+    return E_NOTIMPL;
+}
+
+static const IEventTargetVtbl EventTargetVtbl = {
+    EventTarget_QueryInterface,
+    EventTarget_AddRef,
+    EventTarget_Release,
+    EventTarget_GetTypeInfoCount,
+    EventTarget_GetTypeInfo,
+    EventTarget_GetIDsOfNames,
+    EventTarget_Invoke,
+    EventTarget_addEventListener,
+    EventTarget_removeEventListener,
+    EventTarget_dispatchEvent
+};
+
+#define DELAY_INIT_VTBL ((const IEventTargetVtbl*)1)
+
+static BOOL use_event_quirks(EventTarget *event_target)
+{
+    if(event_target->IEventTarget_iface.lpVtbl == DELAY_INIT_VTBL) {
+        event_target->IEventTarget_iface.lpVtbl =
+            dispex_compat_mode(&event_target->dispex) >= COMPAT_MODE_IE9
+            ? &EventTargetVtbl : NULL;
+    }
+    return !event_target->IEventTarget_iface.lpVtbl;
+}
+
 HRESULT EventTarget_QI(EventTarget *event_target, REFIID riid, void **ppv)
 {
+    if(IsEqualGUID(riid, &IID_IEventTarget)) {
+        if(use_event_quirks(event_target)) {
+            WARN("IEventTarget queried, but not supported by in document mode\n");
+            *ppv = NULL;
+            return E_NOINTERFACE;
+        }
+        IEventTarget_AddRef(&event_target->IEventTarget_iface);
+        *ppv = &event_target->IEventTarget_iface;
+        return S_OK;
+    }
+
     if(dispex_query_interface(&event_target->dispex, riid, ppv))
         return *ppv ? S_OK : E_NOINTERFACE;
 
@@ -1658,6 +1770,20 @@ void EventTarget_Init(EventTarget *event_target, IUnknown *outer, dispex_static_
 {
     init_dispex_with_compat_mode(&event_target->dispex, outer, dispex_data, compat_mode);
     wine_rb_init(&event_target->handler_map, event_id_cmp);
+
+    /*
+     * IEventTarget is supported by the object or not depending on compatibility mode.
+     * We use NULL vtbl for objects in compatibility mode not supporting the interface.
+     * For targets that don't know compatibility mode at creation time, we set vtbl
+     * to special DELAY_INIT_VTBL value so that vtbl will be set to proper value
+     * when it's needed.
+     */
+    if(compat_mode == COMPAT_MODE_QUIRKS && dispex_data->vtbl && dispex_data->vtbl->get_compat_mode)
+        event_target->IEventTarget_iface.lpVtbl = DELAY_INIT_VTBL;
+    else if(compat_mode < COMPAT_MODE_IE9)
+        event_target->IEventTarget_iface.lpVtbl = NULL;
+    else
+        event_target->IEventTarget_iface.lpVtbl = &EventTargetVtbl;
 }
 
 void release_event_target(EventTarget *event_target)
diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h
index f509b43..1727f2c 100644
--- a/dlls/mshtml/mshtml_private.h
+++ b/dlls/mshtml/mshtml_private.h
@@ -333,6 +333,7 @@ void release_typelib(void) DECLSPEC_HIDDEN;
 HRESULT get_class_typeinfo(const CLSID*,ITypeInfo**) DECLSPEC_HIDDEN;
 const dispex_static_data_vtbl_t *dispex_get_vtbl(DispatchEx*) DECLSPEC_HIDDEN;
 void dispex_info_add_interface(dispex_data_t*,tid_t,const DISPID*) 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)
 {
@@ -379,6 +380,7 @@ typedef struct {
 
 struct EventTarget {
     DispatchEx dispex;
+    IEventTarget IEventTarget_iface;
     struct wine_rb_tree handler_map;
 };
 
diff --git a/dlls/mshtml/tests/dom.c b/dlls/mshtml/tests/dom.c
index d7cfedd..0ce4872 100644
--- a/dlls/mshtml/tests/dom.c
+++ b/dlls/mshtml/tests/dom.c
@@ -10582,7 +10582,10 @@ static float expected_document_mode;
 
 static void test_document_mode(IHTMLDocument2 *doc2)
 {
+    IEventTarget *event_target;
+    IHTMLDocument2 *doc_node;
     IHTMLDocument6 *doc;
+    IHTMLElement *body;
     VARIANT v;
     HRESULT hres;
 
@@ -10605,6 +10608,31 @@ static void test_document_mode(IHTMLDocument2 *doc2)
     ok(V_VT(&v) == VT_R4, "V_VT(documentMode) = %u\n", V_VT(&v));
     ok(V_R4(&v) == expected_document_mode, "documentMode = %f\n", V_R4(&v));
     IHTMLDocument6_Release(doc);
+
+    doc_node = get_doc_node(doc2);
+
+    hres = IHTMLDocument2_QueryInterface(doc_node, &IID_IEventTarget, (void**)&event_target);
+    if(expected_document_mode >= 9) {
+        ok(hres == S_OK, "Could not get IEventTarget interface: %08x\n", hres);
+        IEventTarget_Release(event_target);
+    }else {
+        ok(hres == E_NOINTERFACE, "QI(IEventTarget) returned %08x\n", hres);
+    }
+
+    IHTMLDocument2_Release(doc_node);
+
+
+    body = doc_get_body(doc2);
+
+    hres = IHTMLElement_QueryInterface(body, &IID_IEventTarget, (void**)&event_target);
+    if(expected_document_mode >= 9) {
+        ok(hres == S_OK, "Could not get IEventTarget interface: %08x\n", hres);
+        IEventTarget_Release(event_target);
+    }else {
+        ok(hres == E_NOINTERFACE, "QI(IEventTarget) returned %08x\n", hres);
+    }
+
+    IHTMLElement_Release(body);
 }
 
 static void test_quirks_mode(void)




More information about the wine-cvs mailing list