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