-- v3: mshtml/tests: Test builtin function default value getter with custom mshtml: Expose the IHTMLEventObj5 props to scripts. mshtml: Implement `initMessageEvent` for MessageEvents. mshtml: Implement `origin` prop for MessageEvents. mshtml: Implement `data` getter for MessageEvent objs. mshtml: Return E_ABORT from postMessage called without a caller mshtml: Implement `source` prop for MessageEvents. mshtml: Use a hook to implement postMessage.
From: Gabriel Ivăncescu gabrielopcode@gmail.com
We need the caller ServiceProvider to obtain the source.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmlwindow.c | 373 +++++++++++++++------------ dlls/mshtml/mshtml_private_iface.idl | 2 - 2 files changed, 211 insertions(+), 164 deletions(-)
diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index fa99c453989..8cefa5e6e6d 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -2234,6 +2234,87 @@ static HRESULT WINAPI HTMLWindow6_get_maxConnectionsPerServer(IHTMLWindow6 *ifac return E_NOTIMPL; }
+static HRESULT check_target_origin(HTMLInnerWindow *window, const WCHAR *target_origin) +{ + BOOL no_port = FALSE; + IUri *uri, *target; + DWORD port, port2; + BSTR bstr, bstr2; + HRESULT hres; + + if(!target_origin) + return E_INVALIDARG; + + if(!wcscmp(target_origin, L"*")) + return S_OK; + + hres = create_uri(target_origin, Uri_CREATE_NOFRAG | Uri_CREATE_NO_DECODE_EXTRA_INFO, &target); + if(FAILED(hres)) + return hres; + + if(!(uri = window->base.outer_window->uri)) { + FIXME("window with no URI\n"); + hres = S_FALSE; + goto done; + } + + bstr = NULL; + hres = IUri_GetSchemeName(uri, &bstr); + if(hres != S_OK) { + SysFreeString(bstr); + goto done; + } + hres = IUri_GetSchemeName(target, &bstr2); + if(SUCCEEDED(hres)) { + if(hres == S_OK && wcsicmp(bstr, bstr2)) + hres = S_FALSE; + SysFreeString(bstr2); + } + SysFreeString(bstr); + if(hres != S_OK) + goto done; + + bstr = NULL; + hres = IUri_GetHost(uri, &bstr); + if(hres != S_OK) { + SysFreeString(bstr); + goto done; + } + hres = IUri_GetHost(target, &bstr2); + if(SUCCEEDED(hres)) { + if(hres == S_OK && wcsicmp(bstr, bstr2)) + hres = S_FALSE; + SysFreeString(bstr2); + } + SysFreeString(bstr); + if(hres != S_OK) + goto done; + + /* Legacy modes ignore port */ + if(dispex_compat_mode(&window->event_target.dispex) < COMPAT_MODE_IE9) + goto done; + + hres = IUri_GetPort(uri, &port); + if(hres != S_OK) { + if(FAILED(hres)) + goto done; + no_port = TRUE; /* some protocols don't have ports (e.g. res) */ + } + hres = IUri_GetPort(target, &port2); + if(hres != S_OK) { + if(FAILED(hres)) + goto done; + if(no_port) + hres = S_OK; + }else if(no_port || port != port2) { + hres = S_FALSE; + } + +done: + IUri_Release(target); + return hres; +} + struct post_message_task { event_task_t header; DOMEvent *event; @@ -2251,6 +2332,77 @@ static void post_message_destr(event_task_t *_task) IDOMEvent_Release(&task->event->IDOMEvent_iface); }
+static HRESULT post_message(HTMLInnerWindow *window, VARIANT msg, BSTR targetOrigin, VARIANT transfer, + IServiceProvider *caller, compat_mode_t compat_mode) +{ + DOMEvent *event; + HRESULT hres; + + if(V_VT(&transfer) != VT_EMPTY && V_VT(&transfer) != VT_ERROR) + FIXME("transfer not implemented, ignoring\n"); + + hres = check_target_origin(window, targetOrigin); + if(hres != S_OK) + return SUCCEEDED(hres) ? S_OK : hres; + + switch(V_VT(&msg)) { + case VT_EMPTY: + case VT_NULL: + case VT_VOID: + case VT_I1: + case VT_I2: + case VT_I4: + case VT_I8: + case VT_UI1: + case VT_UI2: + case VT_UI4: + case VT_UI8: + case VT_INT: + case VT_UINT: + case VT_R4: + case VT_R8: + case VT_BOOL: + case VT_BSTR: + case VT_CY: + case VT_DATE: + case VT_DECIMAL: + case VT_HRESULT: + break; + case VT_ERROR: + V_VT(&msg) = VT_EMPTY; + break; + default: + FIXME("Unsupported vt %d\n", V_VT(&msg)); + return E_NOTIMPL; + } + + if(!window->doc) { + FIXME("No document\n"); + return E_FAIL; + } + + hres = create_message_event(window->doc, &msg, &event); + if(FAILED(hres)) + return hres; + + if(compat_mode >= COMPAT_MODE_IE9) { + struct post_message_task *task; + if(!(task = malloc(sizeof(*task)))) { + IDOMEvent_Release(&event->IDOMEvent_iface); + return E_OUTOFMEMORY; + } + + /* Because message events can be sent to different windows, they get blocked by any context */ + task->header.thread_blocked = TRUE; + task->event = event; + return push_event_task(&task->header, window, post_message_proc, post_message_destr, window->task_magic); + } + + dispatch_event(&window->event_target, event); + IDOMEvent_Release(&event->IDOMEvent_iface); + return S_OK; +} + static HRESULT WINAPI HTMLWindow6_postMessage(IHTMLWindow6 *iface, BSTR msg, VARIANT targetOrigin) { HTMLWindow *This = impl_from_IHTMLWindow6(iface); @@ -2264,7 +2416,8 @@ static HRESULT WINAPI HTMLWindow6_postMessage(IHTMLWindow6 *iface, BSTR msg, VAR V_VT(&var) = VT_BSTR; V_BSTR(&var) = msg; V_VT(&transfer) = VT_EMPTY; - return IWineHTMLWindowPrivate_postMessage(&This->IWineHTMLWindowPrivate_iface, var, V_BSTR(&targetOrigin), transfer); + return post_message(This->inner_window, var, V_BSTR(&targetOrigin), transfer, NULL, + dispex_compat_mode(&This->inner_window->event_target.dispex)); }
static HRESULT WINAPI HTMLWindow6_toStaticHTML(IHTMLWindow6 *iface, BSTR bstrHTML, BSTR *pbstrStaticHTML) @@ -3197,162 +3350,6 @@ static HRESULT WINAPI window_private_matchMedia(IWineHTMLWindowPrivate *iface, B return create_media_query_list(This, media_query, media_query_list); }
-static HRESULT check_target_origin(HTMLInnerWindow *window, const WCHAR *target_origin) -{ - BOOL no_port = FALSE; - IUri *uri, *target; - DWORD port, port2; - BSTR bstr, bstr2; - HRESULT hres; - - if(!target_origin) - return E_INVALIDARG; - - if(!wcscmp(target_origin, L"*")) - return S_OK; - - hres = create_uri(target_origin, Uri_CREATE_NOFRAG | Uri_CREATE_NO_DECODE_EXTRA_INFO, &target); - if(FAILED(hres)) - return hres; - - if(!(uri = window->base.outer_window->uri)) { - FIXME("window with no URI\n"); - hres = S_FALSE; - goto done; - } - - bstr = NULL; - hres = IUri_GetSchemeName(uri, &bstr); - if(hres != S_OK) { - SysFreeString(bstr); - goto done; - } - hres = IUri_GetSchemeName(target, &bstr2); - if(SUCCEEDED(hres)) { - if(hres == S_OK && wcsicmp(bstr, bstr2)) - hres = S_FALSE; - SysFreeString(bstr2); - } - SysFreeString(bstr); - if(hres != S_OK) - goto done; - - bstr = NULL; - hres = IUri_GetHost(uri, &bstr); - if(hres != S_OK) { - SysFreeString(bstr); - goto done; - } - hres = IUri_GetHost(target, &bstr2); - if(SUCCEEDED(hres)) { - if(hres == S_OK && wcsicmp(bstr, bstr2)) - hres = S_FALSE; - SysFreeString(bstr2); - } - SysFreeString(bstr); - if(hres != S_OK) - goto done; - - /* Legacy modes ignore port */ - if(dispex_compat_mode(&window->event_target.dispex) < COMPAT_MODE_IE9) - goto done; - - hres = IUri_GetPort(uri, &port); - if(hres != S_OK) { - if(FAILED(hres)) - goto done; - no_port = TRUE; /* some protocols don't have ports (e.g. res) */ - } - hres = IUri_GetPort(target, &port2); - if(hres != S_OK) { - if(FAILED(hres)) - goto done; - if(no_port) - hres = S_OK; - }else if(no_port || port != port2) { - hres = S_FALSE; - } - -done: - IUri_Release(target); - return hres; -} - -static HRESULT WINAPI window_private_postMessage(IWineHTMLWindowPrivate *iface, VARIANT msg, BSTR targetOrigin, VARIANT transfer) -{ - HTMLWindow *This = impl_from_IWineHTMLWindowPrivateVtbl(iface); - HTMLInnerWindow *window = This->inner_window; - DOMEvent *event; - HRESULT hres; - - TRACE("iface %p, msg %s, targetOrigin %s, transfer %s\n", iface, debugstr_variant(&msg), - debugstr_w(targetOrigin), debugstr_variant(&transfer)); - - if(V_VT(&transfer) != VT_EMPTY && V_VT(&transfer) != VT_ERROR) - FIXME("transfer not implemented, ignoring\n"); - - hres = check_target_origin(window, targetOrigin); - if(hres != S_OK) - return SUCCEEDED(hres) ? S_OK : hres; - - switch(V_VT(&msg)) { - case VT_EMPTY: - case VT_NULL: - case VT_VOID: - case VT_I1: - case VT_I2: - case VT_I4: - case VT_I8: - case VT_UI1: - case VT_UI2: - case VT_UI4: - case VT_UI8: - case VT_INT: - case VT_UINT: - case VT_R4: - case VT_R8: - case VT_BOOL: - case VT_BSTR: - case VT_CY: - case VT_DATE: - case VT_DECIMAL: - case VT_HRESULT: - break; - case VT_ERROR: - V_VT(&msg) = VT_EMPTY; - break; - default: - FIXME("Unsupported vt %d\n", V_VT(&msg)); - return E_NOTIMPL; - } - - if(!window->doc) { - FIXME("No document\n"); - return E_FAIL; - } - - hres = create_message_event(window->doc, &msg, &event); - if(FAILED(hres)) - return hres; - - if(dispex_compat_mode(&window->event_target.dispex) >= COMPAT_MODE_IE9) { - struct post_message_task *task; - if(!(task = malloc(sizeof(*task)))) { - IDOMEvent_Release(&event->IDOMEvent_iface); - return E_OUTOFMEMORY; - } - - /* Because message events can be sent to different windows, they get blocked by any context */ - task->header.thread_blocked = TRUE; - task->event = event; - return push_event_task(&task->header, window, post_message_proc, post_message_destr, window->task_magic); - } - - dispatch_event(&window->event_target, event); - IDOMEvent_Release(&event->IDOMEvent_iface); - return S_OK; -} - static HRESULT WINAPI window_private_get_console(IWineHTMLWindowPrivate *iface, IDispatch **console) { HTMLWindow *This = impl_from_IWineHTMLWindowPrivateVtbl(iface); @@ -3401,7 +3398,6 @@ static const IWineHTMLWindowPrivateVtbl WineHTMLWindowPrivateVtbl = { window_private_cancelAnimationFrame, window_private_get_console, window_private_matchMedia, - window_private_postMessage, window_private_get_MutationObserver };
@@ -4219,6 +4215,57 @@ static HRESULT IHTMLWindow3_setTimeout_hook(DispatchEx *dispex, WORD flags, DISP return dispex_call_builtin(dispex, DISPID_IHTMLWINDOW3_SETTIMEOUT, &new_dp, res, ei, caller); }
+static HRESULT IHTMLWindow6_postMessage_hook(DispatchEx *dispex, WORD flags, DISPPARAMS *dp, VARIANT *res, + EXCEPINFO *ei, IServiceProvider *caller) +{ + HTMLInnerWindow *This = impl_from_DispatchEx(dispex); + BSTR targetOrigin, converted_msg = NULL; + VARIANT msg, transfer, converted; + compat_mode_t compat_mode; + HRESULT hres; + + if(!(flags & DISPATCH_METHOD) || dp->cArgs < 2 || dp->cNamedArgs) + return S_FALSE; + compat_mode = dispex_compat_mode(&This->event_target.dispex); + + msg = dp->rgvarg[dp->cArgs - 1]; + V_VT(&transfer) = VT_EMPTY; + if(compat_mode >= COMPAT_MODE_IE10 && dp->cArgs > 2) + transfer = dp->rgvarg[dp->cArgs - 3]; + + TRACE("(%p)->(msg %s, targetOrigin %s, transfer %s)\n", This, debugstr_variant(&msg), + debugstr_variant(&dp->rgvarg[dp->cArgs - 2]), debugstr_variant(&transfer)); + + if(compat_mode < COMPAT_MODE_IE10 && V_VT(&msg) != VT_BSTR) { + hres = change_type(&msg, &dp->rgvarg[dp->cArgs - 1], VT_BSTR, caller); + if(FAILED(hres)) + return hres; + converted_msg = V_BSTR(&msg); + } + + if(V_VT(&dp->rgvarg[dp->cArgs - 2]) == VT_BSTR) { + targetOrigin = V_BSTR(&dp->rgvarg[dp->cArgs - 2]); + V_BSTR(&converted) = NULL; + }else { + if(compat_mode < COMPAT_MODE_IE10) { + SysFreeString(converted_msg); + return E_INVALIDARG; + } + hres = change_type(&converted, &dp->rgvarg[dp->cArgs - 2], VT_BSTR, caller); + if(FAILED(hres)) { + SysFreeString(converted_msg); + return hres; + } + targetOrigin = V_BSTR(&converted); + } + + hres = post_message(This, msg, targetOrigin, transfer, caller, compat_mode); + + SysFreeString(V_BSTR(&converted)); + SysFreeString(converted_msg); + return hres; +} + static void HTMLWindow_init_dispex_info(dispex_data_t *info, compat_mode_t compat_mode) { static const dispex_hook_t window2_hooks[] = { @@ -4244,6 +4291,10 @@ static void HTMLWindow_init_dispex_info(dispex_data_t *info, compat_mode_t compa {DISPID_IHTMLWINDOW4_CREATEPOPUP, NULL}, {DISPID_UNKNOWN} }; + static const dispex_hook_t window6_hooks[] = { + {DISPID_IHTMLWINDOW6_POSTMESSAGE, IHTMLWindow6_postMessage_hook}, + {DISPID_UNKNOWN} + };
/* Hide props not available in IE10 */ static const dispex_hook_t private_ie10_hooks[] = { @@ -4259,6 +4310,7 @@ static void HTMLWindow_init_dispex_info(dispex_data_t *info, compat_mode_t compa dispex_info_add_interface(info, IWineHTMLWindowPrivate_tid, compat_mode >= COMPAT_MODE_IE11 ? NULL : private_ie10_hooks);
+ dispex_info_add_interface(info, IHTMLWindow6_tid, window6_hooks); dispex_info_add_interface(info, IHTMLWindow5_tid, NULL); dispex_info_add_interface(info, IHTMLWindow4_tid, compat_mode >= COMPAT_MODE_IE11 ? window4_ie11_hooks : NULL); dispex_info_add_interface(info, IHTMLWindow3_tid, compat_mode >= COMPAT_MODE_IE11 ? window3_ie11_hooks : window3_hooks); @@ -4290,10 +4342,7 @@ static const event_target_vtbl_t HTMLWindow_event_target_vtbl = { .set_current_event = HTMLWindow_set_current_event };
-static const tid_t HTMLWindow_iface_tids[] = { - IHTMLWindow6_tid, - 0 -}; +static const tid_t HTMLWindow_iface_tids[] = { 0 };
static dispex_static_data_t HTMLWindow_dispex = { "Window", diff --git a/dlls/mshtml/mshtml_private_iface.idl b/dlls/mshtml/mshtml_private_iface.idl index e4d97361ce1..503593d1c25 100644 --- a/dlls/mshtml/mshtml_private_iface.idl +++ b/dlls/mshtml/mshtml_private_iface.idl @@ -131,8 +131,6 @@ interface IWineHTMLWindowPrivate : IDispatch HRESULT console([retval, out] IDispatch **console); [id(53)] HRESULT matchMedia([in] BSTR media_query, [retval, out] IDispatch **media_query_list); - [id(54)] - HRESULT postMessage([in] VARIANT msg, [in] BSTR targetOrigin, [in, optional] VARIANT transfer); [propget, id(DISPID_IWINEHTMLWINDOWPRIVATE_MUTATIONOBSERVER)] HRESULT MutationObserver([retval, out] IDispatch **observer_ctor); }
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmlevent.c | 31 +- dlls/mshtml/htmlevent.h | 2 +- dlls/mshtml/htmlwindow.c | 69 +++- dlls/mshtml/tests/documentmode.js | 1 + dlls/mshtml/tests/events.c | 601 ++++++++++++++++++++++++++++++ dlls/mshtml/tests/events.js | 14 +- 6 files changed, 708 insertions(+), 10 deletions(-)
diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c index 36a7fa6c83c..4e1cfd2b695 100644 --- a/dlls/mshtml/htmlevent.c +++ b/dlls/mshtml/htmlevent.c @@ -1841,11 +1841,19 @@ static HRESULT WINAPI HTMLEventObj5_get_data(IHTMLEventObj5 *iface, BSTR *p) static HRESULT WINAPI HTMLEventObj5_get_source(IHTMLEventObj5 *iface, IDispatch **p) { HTMLEventObj *This = impl_from_IHTMLEventObj5(iface); + IDOMMessageEvent *message_event; + HRESULT hres;
- FIXME("(%p)->(%p)\n", This, p); + TRACE("(%p)->(%p)\n", This, p);
- *p = NULL; - return S_OK; + if(!This->event || FAILED(IDOMEvent_QueryInterface(&This->event->IDOMEvent_iface, &IID_IDOMMessageEvent, (void**)&message_event))) { + *p = NULL; + return S_OK; + } + + hres = IDOMMessageEvent_get_source(message_event, (IHTMLWindow2**)p); + IDOMMessageEvent_Release(message_event); + return hres; }
static HRESULT WINAPI HTMLEventObj5_put_origin(IHTMLEventObj5 *iface, BSTR v) @@ -3652,6 +3660,7 @@ static void DOMCustomEvent_destructor(DispatchEx *dispex) typedef struct { DOMEvent event; IDOMMessageEvent IDOMMessageEvent_iface; + IHTMLWindow2 *source; VARIANT data; } DOMMessageEvent;
@@ -3746,8 +3755,12 @@ static HRESULT WINAPI DOMMessageEvent_get_origin(IDOMMessageEvent *iface, BSTR * static HRESULT WINAPI DOMMessageEvent_get_source(IDOMMessageEvent *iface, IHTMLWindow2 **p) { DOMMessageEvent *This = impl_from_IDOMMessageEvent(iface); - FIXME("(%p)->(%p)\n", This, p); - return E_NOTIMPL; + + TRACE("(%p)->(%p)\n", This, p); + + if((*p = This->source)) + IHTMLWindow2_AddRef(This->source); + return S_OK; }
static HRESULT WINAPI DOMMessageEvent_initMessageEvent(IDOMMessageEvent *iface, BSTR type, VARIANT_BOOL can_bubble, @@ -3793,6 +3806,8 @@ static void DOMMessageEvent_traverse(DispatchEx *dispex, nsCycleCollectionTraver DOMMessageEvent *message_event = DOMMessageEvent_from_DOMEvent(DOMEvent_from_DispatchEx(dispex)); DOMEvent_traverse(&message_event->event.dispex, cb); traverse_variant(&message_event->data, "data", cb); + if(message_event->source) + note_cc_edge((nsISupports*)message_event->source, "MessageEvent.source", cb); }
static void DOMMessageEvent_unlink(DispatchEx *dispex) @@ -3800,6 +3815,7 @@ static void DOMMessageEvent_unlink(DispatchEx *dispex) DOMMessageEvent *message_event = DOMMessageEvent_from_DOMEvent(DOMEvent_from_DispatchEx(dispex)); DOMEvent_unlink(&message_event->event.dispex); unlink_variant(&message_event->data); + unlink_ref(&message_event->source); }
static void DOMMessageEvent_destructor(DispatchEx *dispex) @@ -4575,7 +4591,7 @@ HRESULT create_document_event(HTMLDocumentNode *doc, eventid_t event_id, DOMEven return S_OK; }
-HRESULT create_message_event(HTMLDocumentNode *doc, VARIANT *data, DOMEvent **ret) +HRESULT create_message_event(HTMLDocumentNode *doc, IHTMLWindow2 *source, VARIANT *data, DOMEvent **ret) { DOMMessageEvent *message_event; DOMEvent *event; @@ -4593,6 +4609,9 @@ HRESULT create_message_event(HTMLDocumentNode *doc, VARIANT *data, DOMEvent **re return hres; }
+ message_event->source = source; + IHTMLWindow2_AddRef(message_event->source); + *ret = event; return S_OK; } diff --git a/dlls/mshtml/htmlevent.h b/dlls/mshtml/htmlevent.h index 2d86ba08782..645e99a4c19 100644 --- a/dlls/mshtml/htmlevent.h +++ b/dlls/mshtml/htmlevent.h @@ -116,7 +116,7 @@ void dispatch_event(EventTarget*,DOMEvent*); HRESULT create_document_event(HTMLDocumentNode*,eventid_t,DOMEvent**); HRESULT create_document_event_str(HTMLDocumentNode*,const WCHAR*,IDOMEvent**); HRESULT create_event_from_nsevent(nsIDOMEvent*,compat_mode_t,DOMEvent**); -HRESULT create_message_event(HTMLDocumentNode*,VARIANT*,DOMEvent**); +HRESULT create_message_event(HTMLDocumentNode*,IHTMLWindow2*,VARIANT*,DOMEvent**); HRESULT create_storage_event(HTMLDocumentNode*,BSTR,BSTR,BSTR,const WCHAR*,BOOL,DOMEvent**);
void init_nsevents(HTMLDocumentNode*); diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index 8cefa5e6e6d..f3059ac66be 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -28,6 +28,7 @@ #include "wininet.h" #include "shlguid.h" #include "shobjidl.h" +#include "activscp.h" #include "exdispid.h"
#define NO_SHLWAPI_REG @@ -2315,6 +2316,61 @@ done: return hres; }
+static IHTMLWindow2 *get_source_window(IServiceProvider *caller, compat_mode_t compat_mode) +{ + IOleCommandTarget *cmdtarget, *parent_cmdtarget; + IServiceProvider *parent; + IHTMLWindow2 *source; + HRESULT hres; + VARIANT var; + + if(!caller) + return NULL; + + hres = IServiceProvider_QueryService(caller, &IID_IActiveScriptSite, &IID_IOleCommandTarget, (void**)&cmdtarget); + if(hres != S_OK) + cmdtarget = NULL; + + if(compat_mode < COMPAT_MODE_IE9) { + /* Legacy modes query caller unconditionally, and use it instead, if it has a command target */ + hres = IServiceProvider_QueryService(caller, &SID_GetCaller, &IID_IServiceProvider, (void**)&parent); + if(hres == S_OK && parent) { + hres = IServiceProvider_QueryService(parent, &IID_IActiveScriptSite, &IID_IOleCommandTarget, (void**)&parent_cmdtarget); + IServiceProvider_Release(parent); + if(hres == S_OK && parent_cmdtarget) { + if(cmdtarget) + IOleCommandTarget_Release(cmdtarget); + cmdtarget = parent_cmdtarget; + } + } + } + + if(!cmdtarget) + return NULL; + + V_VT(&var) = VT_EMPTY; + hres = IOleCommandTarget_Exec(cmdtarget, &CGID_ScriptSite, CMDID_SCRIPTSITE_SECURITY_WINDOW, 0, NULL, &var); + IOleCommandTarget_Release(cmdtarget); + if(hres != S_OK) + return NULL; + + /* Native assumes it's VT_DISPATCH and doesn't check it */ + hres = IDispatch_QueryInterface(V_DISPATCH(&var), &IID_IHTMLWindow2, (void**)&source); + IDispatch_Release(V_DISPATCH(&var)); + if(hres != S_OK) + return NULL; + + if(compat_mode < COMPAT_MODE_IE9) { + IHTMLWindow2 *tmp; + hres = IHTMLWindow2_get_self(source, &tmp); + if(hres == S_OK) { + IHTMLWindow2_Release(source); + source = tmp; + } + } + return source; +} + struct post_message_task { event_task_t header; DOMEvent *event; @@ -2335,6 +2391,7 @@ static void post_message_destr(event_task_t *_task) static HRESULT post_message(HTMLInnerWindow *window, VARIANT msg, BSTR targetOrigin, VARIANT transfer, IServiceProvider *caller, compat_mode_t compat_mode) { + IHTMLWindow2 *source; DOMEvent *event; HRESULT hres;
@@ -2345,6 +2402,13 @@ static HRESULT post_message(HTMLInnerWindow *window, VARIANT msg, BSTR targetOri if(hres != S_OK) return SUCCEEDED(hres) ? S_OK : hres;
+ source = get_source_window(caller, compat_mode); + if(!source) { + if(compat_mode < COMPAT_MODE_IE9) + return E_ABORT; + IHTMLWindow2_AddRef(source = &window->base.outer_window->base.IHTMLWindow2_iface); + } + switch(V_VT(&msg)) { case VT_EMPTY: case VT_NULL: @@ -2373,15 +2437,18 @@ static HRESULT post_message(HTMLInnerWindow *window, VARIANT msg, BSTR targetOri break; default: FIXME("Unsupported vt %d\n", V_VT(&msg)); + IHTMLWindow2_Release(source); return E_NOTIMPL; }
if(!window->doc) { FIXME("No document\n"); + IHTMLWindow2_Release(source); return E_FAIL; }
- hres = create_message_event(window->doc, &msg, &event); + hres = create_message_event(window->doc, source, &msg, &event); + IHTMLWindow2_Release(source); if(FAILED(hres)) return hres;
diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 9f46de12466..bec247b42d1 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -2928,6 +2928,7 @@ async_test("postMessage", function() { ok(e === undefined, "e = " + e); else { ok(e.data === (v < 10 ? "10" : 10), "e.data = " + e.data); + ok(e.source === window, "e.source = " + e.source); next_test(); } } diff --git a/dlls/mshtml/tests/events.c b/dlls/mshtml/tests/events.c index bea5e1598a8..ffeb585ed52 100644 --- a/dlls/mshtml/tests/events.c +++ b/dlls/mshtml/tests/events.c @@ -26,6 +26,7 @@ #include "windef.h" #include "winbase.h" #include "ole2.h" +#include "activscp.h" #include "mshtml.h" #include "mshtmdid.h" #include "mshtmhst.h" @@ -100,6 +101,7 @@ DEFINE_EXPECT(submit_onclick_attached_check_cancel); DEFINE_EXPECT(submit_onclick_setret); DEFINE_EXPECT(elem2_cp_onclick); DEFINE_EXPECT(iframe_onload); +DEFINE_EXPECT(onmessage); DEFINE_EXPECT(visibilitychange); DEFINE_EXPECT(onbeforeunload); DEFINE_EXPECT(iframe_onbeforeunload); @@ -115,6 +117,15 @@ DEFINE_EXPECT(doc2_onstoragecommit); DEFINE_EXPECT(window2_onstorage); DEFINE_EXPECT(async_xhr_done); DEFINE_EXPECT(sync_xhr_done); +DEFINE_EXPECT(QS_IActiveScriptSite); +DEFINE_EXPECT(QS_IActiveScriptSite_parent); +DEFINE_EXPECT(QS_IActiveScriptSite_parent2); +DEFINE_EXPECT(QS_IActiveScriptSite_parent3); +DEFINE_EXPECT(QS_IActiveScriptSite_parent4); +DEFINE_EXPECT(QS_GetCaller); +DEFINE_EXPECT(QS_GetCaller_parent2); +DEFINE_EXPECT(QS_GetCaller_parent3); +DEFINE_EXPECT(cmdtarget_Exec);
static HWND container_hwnd = NULL; static IHTMLWindow2 *window; @@ -173,6 +184,14 @@ static const char input_doc_str[] = static const char iframe_doc_str[] = "<html><body><iframe id="ifr">Testing</iframe></body></html>";
+static const char iframe_doc_ie9_str[] = + "<html><head><meta http-equiv="x-ua-compatible" content="IE=9" /></head>" + "<body><iframe id="ifr">Testing</iframe></body></html>"; + +static const char iframe_doc_ie11_str[] = + "<html><head><meta http-equiv="x-ua-compatible" content="IE=11" /></head>" + "<body><iframe id="ifr">Testing</iframe></body></html>"; + static void navigate(IHTMLDocument2*,const WCHAR*);
static BOOL iface_cmp(void *iface1, void *iface2) @@ -1486,6 +1505,80 @@ static HRESULT WINAPI iframe_onreadystatechange(IDispatchEx *iface, DISPID id, L
EVENT_HANDLER_FUNC_OBJ(iframe_onreadystatechange);
+static IHTMLWindow2 *onmessage_source; + +static HRESULT WINAPI onmessage(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, + VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) +{ + IHTMLWindow2 *source, *self; + HRESULT hres; + BSTR bstr; + + CHECK_EXPECT(onmessage); + + if(document_mode < 9) { + IHTMLEventObj5 *event_obj5; + IHTMLEventObj *event_obj; + IDispatch *disp; + + hres = IHTMLWindow2_get_event(window, &event_obj); + ok(hres == S_OK, "get_event failed: %08lx\n", hres); + + hres = IHTMLEventObj_get_type(event_obj, &bstr); + ok(hres == S_OK, "get_type failed: %08lx\n", hres); + ok(!wcscmp(bstr, L"message"), "event type = %s\n", wine_dbgstr_w(bstr)); + SysFreeString(bstr); + + hres = IHTMLEventObj_QueryInterface(event_obj, &IID_IHTMLEventObj5, (void**)&event_obj5); + ok(hres == S_OK, "Could not get IHTMLEventObj5: %08lx\n", hres); + IHTMLEventObj_Release(event_obj); + + hres = IHTMLEventObj5_get_url(event_obj5, &bstr); + ok(hres == S_OK, "get_url failed: %08lx\n", hres); + ok(!bstr, "url = %s\n", wine_dbgstr_w(bstr)); + + hres = IHTMLEventObj5_get_source(event_obj5, &disp); + ok(hres == S_OK, "get_source failed: %08lx\n", hres); + + hres = IDispatch_QueryInterface(disp, &IID_IHTMLWindow2, (void**)&source); + ok(hres == S_OK, "Could not get IHTMLWindow2: %08lx\n", hres); + IDispatch_Release(disp); + + hres = IHTMLWindow2_get_self(onmessage_source, &self); + ok(hres == S_OK, "get_self failed: %08lx\n", hres); + ok(source == self, "source != onmessage_source.self\n"); + IHTMLWindow2_Release(source); + IHTMLWindow2_Release(self); + + bstr = SysAllocString(L"foobar"); + hres = IHTMLEventObj5_put_url(event_obj5, bstr); + ok(hres == DISP_E_MEMBERNOTFOUND, "put_url returned: %08lx\n", hres); + SysFreeString(bstr); + + IHTMLEventObj5_Release(event_obj5); + }else { + IDOMMessageEvent *msg; + + hres = IDispatch_QueryInterface(V_DISPATCH(&pdp->rgvarg[1]), &IID_IDOMMessageEvent, (void**)&msg); + ok(hres == S_OK, "Could not get IDOMMessageEvent: %08lx\n", hres); + + hres = IDOMMessageEvent_get_data(msg, &bstr); + ok(hres == S_OK, "get_data failed: %08lx\n", hres); + ok(!wcscmp(bstr, L"foobar"), "data = %s\n", wine_dbgstr_w(bstr)); + SysFreeString(bstr); + + hres = IDOMMessageEvent_get_source(msg, &source); + ok(hres == S_OK, "get_source failed: %08lx\n", hres); + ok(source == onmessage_source, "source != onmessage_source\n"); + IHTMLWindow2_Release(source); + + IDOMMessageEvent_Release(msg); + } + return S_OK; +} + +EVENT_HANDLER_FUNC_OBJ(onmessage); + static HRESULT WINAPI onvisibilitychange(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) { @@ -1891,6 +1984,359 @@ static void pump_msgs(BOOL *b) } }
+static IOleCommandTarget cmdtarget, cmdtarget_stub; + +static HRESULT WINAPI cmdtarget_QueryInterface(IOleCommandTarget *iface, REFIID riid, void **ppv) +{ + if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IOleCommandTarget)) + *ppv = &cmdtarget; + else { + ok(0, "unexpected riid %s\n", wine_dbgstr_guid(riid)); + *ppv = NULL; + return E_NOINTERFACE; + } + return S_OK; +} + +static ULONG WINAPI cmdtarget_AddRef(IOleCommandTarget *iface) +{ + return 2; +} + +static ULONG WINAPI cmdtarget_Release(IOleCommandTarget *iface) +{ + return 1; +} + +static HRESULT WINAPI cmdtarget_QueryStatus(IOleCommandTarget *iface, const GUID *pguidCmdGroup, + ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT *pCmdText) +{ + ok(0, "unexpected call\n"); + return OLECMDERR_E_UNKNOWNGROUP; +} + +static HRESULT WINAPI cmdtarget_Exec(IOleCommandTarget *iface, const GUID *pguidCmdGroup, + DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut) +{ + CHECK_EXPECT2(cmdtarget_Exec); + ok(pguidCmdGroup && IsEqualGUID(pguidCmdGroup, &CGID_ScriptSite), "pguidCmdGroup = %s\n", wine_dbgstr_guid(pguidCmdGroup)); + ok(nCmdID == CMDID_SCRIPTSITE_SECURITY_WINDOW, "nCmdID = %lu\n", nCmdID); + ok(!nCmdexecopt, "nCmdexecopt = %lu\n", nCmdexecopt); + ok(!pvaIn, "pvaIn != NULL\n"); + ok(pvaOut != NULL, "pvaOut = NULL\n"); + + /* Native ignores the VT and assumes VT_DISPATCH, and releases it + without VariantClear, since it crashes without AddRef below... */ + V_VT(pvaOut) = VT_NULL; + V_DISPATCH(pvaOut) = (IDispatch*)onmessage_source; + IDispatch_AddRef(V_DISPATCH(pvaOut)); + return S_OK; +} + +static const IOleCommandTargetVtbl cmdtarget_vtbl = { + cmdtarget_QueryInterface, + cmdtarget_AddRef, + cmdtarget_Release, + cmdtarget_QueryStatus, + cmdtarget_Exec +}; + +static IOleCommandTarget cmdtarget = { &cmdtarget_vtbl }; + +static HRESULT WINAPI cmdtarget_stub_QueryInterface(IOleCommandTarget *iface, REFIID riid, void **ppv) +{ + if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IOleCommandTarget)) + *ppv = &cmdtarget_stub; + else { + ok(0, "unexpected riid %s\n", wine_dbgstr_guid(riid)); + *ppv = NULL; + return E_NOINTERFACE; + } + return S_OK; +} + +static HRESULT WINAPI cmdtarget_stub_QueryStatus(IOleCommandTarget *iface, const GUID *pguidCmdGroup, + ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT *pCmdText) +{ + ok(0, "unexpected call\n"); + return OLECMDERR_E_UNKNOWNGROUP; +} + +static HRESULT WINAPI cmdtarget_stub_Exec(IOleCommandTarget *iface, const GUID *pguidCmdGroup, + DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut) +{ + ok(0, "unexpected call\n"); + return OLECMDERR_E_UNKNOWNGROUP; +} + +static const IOleCommandTargetVtbl cmdtarget_stub_vtbl = { + cmdtarget_stub_QueryInterface, + cmdtarget_AddRef, + cmdtarget_Release, + cmdtarget_stub_QueryStatus, + cmdtarget_stub_Exec +}; + +static IOleCommandTarget cmdtarget_stub = { &cmdtarget_stub_vtbl }; + +static IServiceProvider caller_sp, caller_sp_parent, caller_sp_stub, caller_sp2, caller_sp2_parent, caller_sp2_parent3; + +static HRESULT WINAPI caller_sp_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv) +{ + if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IServiceProvider)) + *ppv = &caller_sp; + else { + ok(0, "unexpected riid %s\n", wine_dbgstr_guid(riid)); + *ppv = NULL; + return E_NOINTERFACE; + } + return S_OK; +} + +static ULONG WINAPI caller_sp_AddRef(IServiceProvider *iface) +{ + return 2; +} + +static ULONG WINAPI caller_sp_Release(IServiceProvider *iface) +{ + return 1; +} + +static HRESULT WINAPI caller_sp_QueryService(IServiceProvider *iface, REFGUID guidService, + REFIID riid, void **ppv) +{ + if(IsEqualGUID(guidService, &IID_IActiveScriptSite)) { + CHECK_EXPECT2(QS_IActiveScriptSite); + ok(IsEqualGUID(riid, &IID_IOleCommandTarget), "unexpected riid %s\n", wine_dbgstr_guid(riid)); + *ppv = (document_mode < 9) ? NULL : &cmdtarget; + return (document_mode < 9) ? E_NOINTERFACE : S_OK; + } + + if(IsEqualGUID(guidService, &SID_GetCaller)) { + CHECK_EXPECT(QS_GetCaller); + SET_EXPECT(QS_IActiveScriptSite_parent); + ok(IsEqualGUID(riid, &IID_IServiceProvider), "unexpected riid %s\n", wine_dbgstr_guid(riid)); + *ppv = &caller_sp_parent; + return S_OK; + } + + ok(0, "unexpected service %s\n", wine_dbgstr_guid(guidService)); + *ppv = NULL; + return E_NOINTERFACE; +} + +static const IServiceProviderVtbl caller_sp_vtbl = { + caller_sp_QueryInterface, + caller_sp_AddRef, + caller_sp_Release, + caller_sp_QueryService +}; + +static IServiceProvider caller_sp = { &caller_sp_vtbl }; + +static HRESULT WINAPI caller_sp_parent_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv) +{ + if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IServiceProvider)) + *ppv = &caller_sp_parent; + else { + ok(0, "unexpected riid %s\n", wine_dbgstr_guid(riid)); + *ppv = NULL; + return E_NOINTERFACE; + } + return S_OK; +} + +static HRESULT WINAPI caller_sp_parent_QueryService(IServiceProvider *iface, REFGUID guidService, + REFIID riid, void **ppv) +{ + if(IsEqualGUID(guidService, &IID_IActiveScriptSite)) { + CHECK_EXPECT(QS_IActiveScriptSite_parent); + ok(IsEqualGUID(riid, &IID_IOleCommandTarget), "unexpected riid %s\n", wine_dbgstr_guid(riid)); + *ppv = NULL; + return E_NOINTERFACE; + } + + ok(0, "unexpected service %s\n", wine_dbgstr_guid(guidService)); + *ppv = NULL; + return E_NOINTERFACE; +} + +static const IServiceProviderVtbl caller_sp_parent_vtbl = { + caller_sp_parent_QueryInterface, + caller_sp_AddRef, + caller_sp_Release, + caller_sp_parent_QueryService +}; + +static IServiceProvider caller_sp_parent = { &caller_sp_parent_vtbl }; + +static HRESULT WINAPI caller_sp_stub_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv) +{ + if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IServiceProvider)) + *ppv = &caller_sp_stub; + else { + ok(0, "unexpected riid %s\n", wine_dbgstr_guid(riid)); + *ppv = NULL; + return E_NOINTERFACE; + } + return S_OK; +} + +static HRESULT WINAPI caller_sp_stub_QueryService(IServiceProvider *iface, REFGUID guidService, + REFIID riid, void **ppv) +{ + if(IsEqualGUID(guidService, &IID_IActiveScriptSite)) { + CHECK_EXPECT2(QS_IActiveScriptSite); + *ppv = NULL; + return E_NOINTERFACE; + } + + if(IsEqualGUID(guidService, &SID_GetCaller)) { + CHECK_EXPECT(QS_GetCaller); + ok(IsEqualGUID(riid, &IID_IServiceProvider), "unexpected riid %s\n", wine_dbgstr_guid(riid)); + *ppv = NULL; + return S_OK; + } + + ok(0, "unexpected service %s\n", wine_dbgstr_guid(guidService)); + *ppv = NULL; + return E_NOINTERFACE; +} + +static const IServiceProviderVtbl caller_sp_stub_vtbl = { + caller_sp_stub_QueryInterface, + caller_sp_AddRef, + caller_sp_Release, + caller_sp_stub_QueryService +}; + +static IServiceProvider caller_sp_stub = { &caller_sp_stub_vtbl }; + +static HRESULT WINAPI caller_sp2_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv) +{ + if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IServiceProvider)) + *ppv = &caller_sp2; + else { + ok(0, "unexpected riid %s\n", wine_dbgstr_guid(riid)); + *ppv = NULL; + return E_NOINTERFACE; + } + return S_OK; +} + +static HRESULT WINAPI caller_sp2_QueryService(IServiceProvider *iface, REFGUID guidService, + REFIID riid, void **ppv) +{ + if(IsEqualGUID(guidService, &IID_IActiveScriptSite)) { + CHECK_EXPECT2(QS_IActiveScriptSite_parent2); + ok(IsEqualGUID(riid, &IID_IOleCommandTarget), "unexpected riid %s\n", wine_dbgstr_guid(riid)); + *ppv = (document_mode < 9) ? &cmdtarget_stub : &cmdtarget; + return S_OK; + } + + if(IsEqualGUID(guidService, &SID_GetCaller)) { + CHECK_EXPECT(QS_GetCaller_parent2); + SET_EXPECT(QS_IActiveScriptSite_parent3); + ok(IsEqualGUID(riid, &IID_IServiceProvider), "unexpected riid %s\n", wine_dbgstr_guid(riid)); + *ppv = &caller_sp2_parent; + return S_OK; + } + + ok(0, "unexpected service %s\n", wine_dbgstr_guid(guidService)); + *ppv = NULL; + return E_NOINTERFACE; +} + +static const IServiceProviderVtbl caller_sp2_vtbl = { + caller_sp2_QueryInterface, + caller_sp_AddRef, + caller_sp_Release, + caller_sp2_QueryService +}; + +static IServiceProvider caller_sp2 = { &caller_sp2_vtbl }; + +static HRESULT WINAPI caller_sp2_parent_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv) +{ + if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IServiceProvider)) + *ppv = &caller_sp2_parent; + else { + ok(0, "unexpected riid %s\n", wine_dbgstr_guid(riid)); + *ppv = NULL; + return E_NOINTERFACE; + } + return S_OK; +} + +static HRESULT WINAPI caller_sp2_parent_QueryService(IServiceProvider *iface, REFGUID guidService, + REFIID riid, void **ppv) +{ + if(IsEqualGUID(guidService, &IID_IActiveScriptSite)) { + CHECK_EXPECT2(QS_IActiveScriptSite_parent3); + ok(IsEqualGUID(riid, &IID_IOleCommandTarget), "unexpected riid %s\n", wine_dbgstr_guid(riid)); + *ppv = &cmdtarget; + return S_OK; + } + + if(IsEqualGUID(guidService, &SID_GetCaller)) { + CHECK_EXPECT(QS_GetCaller_parent3); + SET_EXPECT(QS_IActiveScriptSite_parent4); + ok(IsEqualGUID(riid, &IID_IServiceProvider), "unexpected riid %s\n", wine_dbgstr_guid(riid)); + *ppv = &caller_sp2_parent3; + return S_OK; + } + + ok(0, "unexpected service %s\n", wine_dbgstr_guid(guidService)); + *ppv = NULL; + return E_NOINTERFACE; +} + +static const IServiceProviderVtbl caller_sp2_parent_vtbl = { + caller_sp2_parent_QueryInterface, + caller_sp_AddRef, + caller_sp_Release, + caller_sp2_parent_QueryService +}; + +static IServiceProvider caller_sp2_parent = { &caller_sp2_parent_vtbl }; + +static HRESULT WINAPI caller_sp2_parent3_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv) +{ + if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IServiceProvider)) + *ppv = &caller_sp2_parent3; + else { + ok(0, "unexpected riid %s\n", wine_dbgstr_guid(riid)); + *ppv = NULL; + return E_NOINTERFACE; + } + return S_OK; +} + +static HRESULT WINAPI caller_sp2_parent3_QueryService(IServiceProvider *iface, REFGUID guidService, + REFIID riid, void **ppv) +{ + if(IsEqualGUID(guidService, &IID_IActiveScriptSite)) { + CHECK_EXPECT(QS_IActiveScriptSite_parent4); + ok(IsEqualGUID(riid, &IID_IOleCommandTarget), "unexpected riid %s\n", wine_dbgstr_guid(riid)); + *ppv = NULL; + return S_OK; + } + + ok(0, "unexpected service %s\n", wine_dbgstr_guid(guidService)); + *ppv = NULL; + return E_NOINTERFACE; +} + +static const IServiceProviderVtbl caller_sp2_parent3_vtbl = { + caller_sp2_parent3_QueryInterface, + caller_sp_AddRef, + caller_sp_Release, + caller_sp2_parent3_QueryService +}; + +static IServiceProvider caller_sp2_parent3 = { &caller_sp2_parent3_vtbl }; + static IConnectionPoint *get_cp(IUnknown *unk, REFIID riid) { IConnectionPointContainer *cp_container; @@ -2728,6 +3174,158 @@ static void test_focus(IHTMLDocument2 *doc) IHTMLElement4_Release(div); }
+static void test_message_event(IHTMLDocument2 *doc) +{ + IHTMLFrameBase2 *iframe; + DISPPARAMS dp = { 0 }; + IHTMLWindow6 *window6; + IHTMLDocument6 *doc6; + IHTMLElement2 *elem; + IHTMLWindow2 *child; + IDispatchEx *dispex; + DISPID dispid; + HRESULT hres; + VARIANT v[2]; + BSTR bstr; + + hres = IHTMLWindow2_QueryInterface(window, &IID_IHTMLWindow6, (void**)&window6); + ok(hres == S_OK, "Could not get IHTMLWindow6 iface: %08lx\n", hres); + + hres = IHTMLDocument2_QueryInterface(doc, &IID_IHTMLDocument6, (void**)&doc6); + ok(hres == S_OK, "Could not get IHTMLDocument6 iface: %08lx\n", hres); + bstr = SysAllocString(L"ifr"); + hres = IHTMLDocument6_getElementById(doc6, bstr, &elem); + ok(hres == S_OK, "getElementById failed: %08lx\n", hres); + IHTMLDocument6_Release(doc6); + SysFreeString(bstr); + + hres = IHTMLElement2_QueryInterface(elem, &IID_IHTMLFrameBase2, (void**)&iframe); + ok(hres == S_OK, "Could not get IHTMLFrameBase2 iface: %08lx\n", hres); + IHTMLElement2_Release(elem); + hres = IHTMLFrameBase2_get_contentWindow(iframe, &child); + ok(hres == S_OK, "get_contentWindow failed: %08lx\n", hres); + IHTMLFrameBase2_Release(iframe); + + dp.cArgs = 2; + dp.rgvarg = v; + V_VT(&v[0]) = VT_DISPATCH; + V_DISPATCH(&v[0]) = (IDispatch*)&onmessage_obj; + hres = IHTMLWindow6_put_onmessage(window6, v[0]); + ok(hres == S_OK, "put_onmessage failed: %08lx\n", hres); + + V_VT(&v[0]) = VT_EMPTY; + hres = IHTMLWindow6_get_onmessage(window6, &v[0]); + ok(hres == S_OK, "get_onmessage failed: %08lx\n", hres); + ok(V_VT(&v[0]) == VT_DISPATCH, "V_VT(onmessage) = %d\n", V_VT(&v[0])); + ok(V_DISPATCH(&v[0]) == (IDispatch*)&onmessage_obj, "V_DISPATCH(onmessage) = %p\n", V_DISPATCH(&v[0])); + IHTMLWindow6_Release(window6); + + if(document_mode >= 9) + add_event_listener((IUnknown*)doc, L"message", (IDispatch*)&onmessage_obj, VARIANT_TRUE); + + V_VT(&v[1]) = VT_BSTR; + V_BSTR(&v[1]) = SysAllocString(L"foobar"); + V_VT(&v[0]) = VT_BSTR; + V_BSTR(&v[0]) = SysAllocString(L"*"); + + hres = IHTMLWindow2_QueryInterface(window, &IID_IDispatchEx, (void**)&dispex); + ok(hres == S_OK, "Could not get IDispatchEx iface: %08lx\n", hres); + + bstr = SysAllocString(L"postMessage"); + hres = IDispatchEx_GetDispID(dispex, bstr, fdexNameCaseSensitive, &dispid); + ok(hres == S_OK, "GetDispID(postMessage) failed: %08lx\n", hres); + SysFreeString(bstr); + + onmessage_source = window; + hres = IDispatchEx_InvokeEx(dispex, dispid, 0, DISPATCH_METHOD, &dp, NULL, NULL, NULL); + ok(hres == (document_mode < 9 ? E_ABORT : S_OK), "InvokeEx(postMessage) returned: %08lx\n", hres); + if(hres == S_OK) { + SET_EXPECT(onmessage); + pump_msgs(&called_onmessage); + CHECK_CALLED(onmessage); + } + + if(document_mode < 9) + SET_EXPECT(QS_GetCaller); + SET_EXPECT(QS_IActiveScriptSite); + hres = IDispatchEx_InvokeEx(dispex, dispid, 0, DISPATCH_METHOD, &dp, NULL, NULL, &caller_sp_stub); + ok(hres == (document_mode < 9 ? E_ABORT : S_OK), "InvokeEx(postMessage) returned: %08lx\n", hres); + CHECK_CALLED(QS_IActiveScriptSite); + if(document_mode < 9) + CHECK_CALLED(QS_GetCaller); + else { + SET_EXPECT(onmessage); + pump_msgs(&called_onmessage); + CHECK_CALLED(onmessage); + } + + onmessage_source = child; + if(document_mode < 9) { + SET_EXPECT(QS_GetCaller); + SET_EXPECT(QS_IActiveScriptSite_parent); + }else { + SET_EXPECT(cmdtarget_Exec); + } + SET_EXPECT(QS_IActiveScriptSite); + hres = IDispatchEx_InvokeEx(dispex, dispid, 0, DISPATCH_METHOD, &dp, NULL, NULL, &caller_sp); + ok(hres == (document_mode < 9 ? E_ABORT : S_OK), "InvokeEx(postMessage) failed: %08lx\n", hres); + CHECK_CALLED(QS_IActiveScriptSite); + if(hres == S_OK) { + CHECK_CALLED(cmdtarget_Exec); + SET_EXPECT(onmessage); + pump_msgs(&called_onmessage); + CHECK_CALLED(onmessage); + } + + if(document_mode < 9) { + SET_EXPECT(QS_GetCaller_parent2); + SET_EXPECT(onmessage); + } + SET_EXPECT(QS_IActiveScriptSite_parent2); + SET_EXPECT(cmdtarget_Exec); + hres = IDispatchEx_InvokeEx(dispex, dispid, 0, DISPATCH_METHOD, &dp, NULL, NULL, &caller_sp2); + ok(hres == S_OK, "InvokeEx(postMessage) failed: %08lx\n", hres); + CHECK_CALLED(cmdtarget_Exec); + CHECK_CALLED(QS_IActiveScriptSite_parent2); + if(document_mode < 9) { + CHECK_CALLED(QS_IActiveScriptSite_parent3); + CHECK_CALLED(QS_GetCaller_parent2); + CHECK_CALLED(onmessage); + pump_msgs(NULL); + }else { + SET_EXPECT(onmessage); + pump_msgs(&called_onmessage); + CHECK_CALLED(onmessage); + } + + if(document_mode < 9) { + SET_EXPECT(QS_GetCaller_parent3); + SET_EXPECT(onmessage); + } + SET_EXPECT(QS_IActiveScriptSite_parent3); + SET_EXPECT(cmdtarget_Exec); + hres = IDispatchEx_InvokeEx(dispex, dispid, 0, DISPATCH_METHOD, &dp, NULL, NULL, &caller_sp2_parent); + ok(hres == S_OK, "InvokeEx(postMessage) failed: %08lx\n", hres); + CHECK_CALLED(cmdtarget_Exec); + CHECK_CALLED(QS_IActiveScriptSite_parent3); + if(document_mode < 9) { + CHECK_CALLED(QS_IActiveScriptSite_parent4); + CHECK_CALLED(QS_GetCaller_parent3); + CHECK_CALLED(onmessage); + pump_msgs(NULL); + }else { + SET_EXPECT(onmessage); + pump_msgs(&called_onmessage); + CHECK_CALLED(onmessage); + } + + onmessage_source = NULL; + VariantClear(&v[0]); + VariantClear(&v[1]); + IHTMLWindow2_Release(child); + IDispatchEx_Release(dispex); +} + static void test_visibilitychange(IHTMLDocument2 *doc) { if(!winetest_interactive) { @@ -6746,10 +7344,13 @@ START_TEST(events) run_test(input_doc_str, test_focus); run_test(empty_doc_str, test_submit); run_test(empty_doc_ie9_str, test_submit); + run_test(iframe_doc_str, test_message_event); run_test(iframe_doc_str, test_iframe_connections); if(is_ie9plus) { run_test_from_res(L"doc_with_prop.html", test_doc_obj); run_test_from_res(L"doc_with_prop_ie9.html", test_doc_obj); + run_test(iframe_doc_ie9_str, test_message_event); + run_test(iframe_doc_ie11_str, test_message_event); run_test_from_res(L"doc_with_prop_ie9.html", test_visibilitychange); run_test_from_res(L"blank_ie10.html", test_visibilitychange); run_test_from_res(L"iframe.html", test_unload_event); diff --git a/dlls/mshtml/tests/events.js b/dlls/mshtml/tests/events.js index 3b29798e9a1..a5f66a2f031 100644 --- a/dlls/mshtml/tests/events.js +++ b/dlls/mshtml/tests/events.js @@ -824,14 +824,24 @@ async_test("img_wrong_content_type", function() { });
async_test("message event", function() { - var listener_called = false; + var listener_called = false, iframe = document.createElement("iframe");
window.addEventListener("message", function(e) { + if(listener_called) { + ok(e.data === "echo", "e.data (diff origin) = " + e.data); + ok(e.source === iframe.contentWindow, "e.source (diff origin) not iframe.contentWindow"); + next_test(); + return; + } listener_called = true; ok(e.data === "test", "e.data = " + e.data); ok(e.bubbles === false, "bubbles = " + e.bubbles); ok(e.cancelable === false, "cancelable = " + e.cancelable); - next_test(); + ok(e.source === window, "e.source = " + e.source); + + iframe.onload = function() { iframe.contentWindow.postMessage("echo", "hTtP://WinEtesT.difFerent.ORG:1234"); } + iframe.src = "http://winetest.different.org:1234/xhr_iframe.html"; + document.body.appendChild(iframe); });
window.postMessage("test", "httP://wineTest.example.org");
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmlwindow.c | 8 ++------ dlls/mshtml/tests/events.c | 5 ++++- 2 files changed, 6 insertions(+), 7 deletions(-)
diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index f3059ac66be..5a4707153e5 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -2473,18 +2473,14 @@ static HRESULT post_message(HTMLInnerWindow *window, VARIANT msg, BSTR targetOri static HRESULT WINAPI HTMLWindow6_postMessage(IHTMLWindow6 *iface, BSTR msg, VARIANT targetOrigin) { HTMLWindow *This = impl_from_IHTMLWindow6(iface); - VARIANT var, transfer;
TRACE("(%p)->(%s %s)\n", This, debugstr_w(msg), debugstr_variant(&targetOrigin));
if(V_VT(&targetOrigin) != VT_BSTR) return E_INVALIDARG;
- V_VT(&var) = VT_BSTR; - V_BSTR(&var) = msg; - V_VT(&transfer) = VT_EMPTY; - return post_message(This->inner_window, var, V_BSTR(&targetOrigin), transfer, NULL, - dispex_compat_mode(&This->inner_window->event_target.dispex)); + /* This can't obtain the source, and never works even in IE9+ modes... */ + return E_ABORT; }
static HRESULT WINAPI HTMLWindow6_toStaticHTML(IHTMLWindow6 *iface, BSTR bstrHTML, BSTR *pbstrStaticHTML) diff --git a/dlls/mshtml/tests/events.c b/dlls/mshtml/tests/events.c index ffeb585ed52..aa1a60365f2 100644 --- a/dlls/mshtml/tests/events.c +++ b/dlls/mshtml/tests/events.c @@ -3218,7 +3218,6 @@ static void test_message_event(IHTMLDocument2 *doc) ok(hres == S_OK, "get_onmessage failed: %08lx\n", hres); ok(V_VT(&v[0]) == VT_DISPATCH, "V_VT(onmessage) = %d\n", V_VT(&v[0])); ok(V_DISPATCH(&v[0]) == (IDispatch*)&onmessage_obj, "V_DISPATCH(onmessage) = %p\n", V_DISPATCH(&v[0])); - IHTMLWindow6_Release(window6);
if(document_mode >= 9) add_event_listener((IUnknown*)doc, L"message", (IDispatch*)&onmessage_obj, VARIANT_TRUE); @@ -3227,6 +3226,10 @@ static void test_message_event(IHTMLDocument2 *doc) V_BSTR(&v[1]) = SysAllocString(L"foobar"); V_VT(&v[0]) = VT_BSTR; V_BSTR(&v[0]) = SysAllocString(L"*"); + bstr = SysAllocString(L"foobar"); + hres = IHTMLWindow6_postMessage(window6, V_BSTR(&v[1]), v[0]); + ok(hres == E_ABORT, "postMessage returned: %08lx\n", hres); + IHTMLWindow6_Release(window6);
hres = IHTMLWindow2_QueryInterface(window, &IID_IDispatchEx, (void**)&dispex); ok(hres == S_OK, "Could not get IDispatchEx iface: %08lx\n", hres);
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmlevent.c | 14 +++++++++++--- dlls/mshtml/tests/events.c | 5 +++++ 2 files changed, 16 insertions(+), 3 deletions(-)
diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c index 4e1cfd2b695..adf5422c995 100644 --- a/dlls/mshtml/htmlevent.c +++ b/dlls/mshtml/htmlevent.c @@ -1831,11 +1831,19 @@ static HRESULT WINAPI HTMLEventObj5_put_data(IHTMLEventObj5 *iface, BSTR v) static HRESULT WINAPI HTMLEventObj5_get_data(IHTMLEventObj5 *iface, BSTR *p) { HTMLEventObj *This = impl_from_IHTMLEventObj5(iface); + IDOMMessageEvent *message_event; + HRESULT hres;
- FIXME("(%p)->(%p)\n", This, p); + TRACE("(%p)->(%p)\n", This, p);
- *p = NULL; - return S_OK; + if(!This->event || FAILED(IDOMEvent_QueryInterface(&This->event->IDOMEvent_iface, &IID_IDOMMessageEvent, (void**)&message_event))) { + *p = NULL; + return S_OK; + } + + hres = IDOMMessageEvent_get_data(message_event, p); + IDOMMessageEvent_Release(message_event); + return hres; }
static HRESULT WINAPI HTMLEventObj5_get_source(IHTMLEventObj5 *iface, IDispatch **p) diff --git a/dlls/mshtml/tests/events.c b/dlls/mshtml/tests/events.c index aa1a60365f2..8641a2aae7d 100644 --- a/dlls/mshtml/tests/events.c +++ b/dlls/mshtml/tests/events.c @@ -1537,6 +1537,11 @@ static HRESULT WINAPI onmessage(IDispatchEx *iface, DISPID id, LCID lcid, WORD w ok(hres == S_OK, "get_url failed: %08lx\n", hres); ok(!bstr, "url = %s\n", wine_dbgstr_w(bstr));
+ hres = IHTMLEventObj5_get_data(event_obj5, &bstr); + ok(hres == S_OK, "get_data failed: %08lx\n", hres); + ok(!wcscmp(bstr, L"foobar"), "data = %s\n", wine_dbgstr_w(bstr)); + SysFreeString(bstr); + hres = IHTMLEventObj5_get_source(event_obj5, &disp); ok(hres == S_OK, "get_source failed: %08lx\n", hres);
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmlevent.c | 53 +++++++++++++++++++++++++++---- dlls/mshtml/tests/documentmode.js | 1 + dlls/mshtml/tests/events.c | 13 ++++++++ dlls/mshtml/tests/events.js | 2 ++ 4 files changed, 63 insertions(+), 6 deletions(-)
diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c index adf5422c995..f6684d9d6ee 100644 --- a/dlls/mshtml/htmlevent.c +++ b/dlls/mshtml/htmlevent.c @@ -25,6 +25,7 @@ #include "winuser.h" #include "ole2.h" #include "mshtmdid.h" +#include "wininet.h"
#include "mshtml_private.h" #include "htmlevent.h" @@ -1876,11 +1877,19 @@ static HRESULT WINAPI HTMLEventObj5_put_origin(IHTMLEventObj5 *iface, BSTR v) static HRESULT WINAPI HTMLEventObj5_get_origin(IHTMLEventObj5 *iface, BSTR *p) { HTMLEventObj *This = impl_from_IHTMLEventObj5(iface); + IDOMMessageEvent *message_event; + HRESULT hres;
- FIXME("(%p)->(%p)\n", This, p); + TRACE("(%p)->(%p)\n", This, p);
- *p = NULL; - return S_OK; + if(!This->event || FAILED(IDOMEvent_QueryInterface(&This->event->IDOMEvent_iface, &IID_IDOMMessageEvent, (void**)&message_event))) { + *p = NULL; + return S_OK; + } + + hres = IDOMMessageEvent_get_origin(message_event, p); + IDOMMessageEvent_Release(message_event); + return hres; }
static HRESULT WINAPI HTMLEventObj5_put_issession(IHTMLEventObj5 *iface, VARIANT_BOOL v) @@ -3669,6 +3678,7 @@ typedef struct { DOMEvent event; IDOMMessageEvent IDOMMessageEvent_iface; IHTMLWindow2 *source; + BSTR origin; VARIANT data; } DOMMessageEvent;
@@ -3756,8 +3766,14 @@ static HRESULT DOMMessageEvent_get_data_hook(DispatchEx *dispex, WORD flags, DIS static HRESULT WINAPI DOMMessageEvent_get_origin(IDOMMessageEvent *iface, BSTR *p) { DOMMessageEvent *This = impl_from_IDOMMessageEvent(iface); - FIXME("(%p)->(%p)\n", This, p); - return E_NOTIMPL; + + TRACE("(%p)->(%p)\n", This, p); + + if(This->origin) + return (*p = SysAllocStringLen(This->origin, SysStringLen(This->origin))) ? S_OK : E_OUTOFMEMORY; + + *p = NULL; + return S_OK; }
static HRESULT WINAPI DOMMessageEvent_get_source(IDOMMessageEvent *iface, IHTMLWindow2 **p) @@ -3829,6 +3845,7 @@ static void DOMMessageEvent_unlink(DispatchEx *dispex) static void DOMMessageEvent_destructor(DispatchEx *dispex) { DOMMessageEvent *message_event = DOMMessageEvent_from_DOMEvent(DOMEvent_from_DispatchEx(dispex)); + SysFreeString(message_event->origin); VariantClear(&message_event->data); DOMEvent_destructor(dispex); } @@ -4601,14 +4618,38 @@ HRESULT create_document_event(HTMLDocumentNode *doc, eventid_t event_id, DOMEven
HRESULT create_message_event(HTMLDocumentNode *doc, IHTMLWindow2 *source, VARIANT *data, DOMEvent **ret) { + URL_COMPONENTSW url = { sizeof(url) }; DOMMessageEvent *message_event; + IHTMLLocation *location; DOMEvent *event; HRESULT hres; + BSTR origin;
- hres = create_document_event(doc, EVENTID_MESSAGE, &event); + hres = IHTMLWindow2_get_location(source, &location); + if(FAILED(hres)) + return hres; + + hres = IHTMLLocation_get_href(location, &origin); + IHTMLLocation_Release(location); if(FAILED(hres)) return hres; + + url.dwUrlPathLength = 1; + if(origin && InternetCrackUrlW(origin, 0, 0, &url)) { + BSTR tmp = SysAllocStringLen(origin, url.lpszUrlPath - origin); + SysFreeString(origin); + if(!tmp) + return E_OUTOFMEMORY; + origin = tmp; + } + + hres = create_document_event(doc, EVENTID_MESSAGE, &event); + if(FAILED(hres)) { + SysFreeString(origin); + return hres; + } message_event = DOMMessageEvent_from_DOMEvent(event); + message_event->origin = origin;
V_VT(&message_event->data) = VT_EMPTY; hres = VariantCopy(&message_event->data, data); diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index bec247b42d1..94183ad015e 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -2929,6 +2929,7 @@ async_test("postMessage", function() { else { ok(e.data === (v < 10 ? "10" : 10), "e.data = " + e.data); ok(e.source === window, "e.source = " + e.source); + ok(e.origin === "http://winetest.example.org", "e.origin = " + e.origin); next_test(); } } diff --git a/dlls/mshtml/tests/events.c b/dlls/mshtml/tests/events.c index 8641a2aae7d..0dd622b15c3 100644 --- a/dlls/mshtml/tests/events.c +++ b/dlls/mshtml/tests/events.c @@ -1542,6 +1542,11 @@ static HRESULT WINAPI onmessage(IDispatchEx *iface, DISPID id, LCID lcid, WORD w ok(!wcscmp(bstr, L"foobar"), "data = %s\n", wine_dbgstr_w(bstr)); SysFreeString(bstr);
+ hres = IHTMLEventObj5_get_origin(event_obj5, &bstr); + ok(hres == S_OK, "get_origin failed: %08lx\n", hres); + ok(!wcscmp(bstr, L"about:"), "origin = %s\n", wine_dbgstr_w(bstr)); + SysFreeString(bstr); + hres = IHTMLEventObj5_get_source(event_obj5, &disp); ok(hres == S_OK, "get_source failed: %08lx\n", hres);
@@ -1558,6 +1563,9 @@ static HRESULT WINAPI onmessage(IDispatchEx *iface, DISPID id, LCID lcid, WORD w bstr = SysAllocString(L"foobar"); hres = IHTMLEventObj5_put_url(event_obj5, bstr); ok(hres == DISP_E_MEMBERNOTFOUND, "put_url returned: %08lx\n", hres); + + hres = IHTMLEventObj5_put_origin(event_obj5, bstr); + ok(hres == DISP_E_MEMBERNOTFOUND, "put_origin returned: %08lx\n", hres); SysFreeString(bstr);
IHTMLEventObj5_Release(event_obj5); @@ -1572,6 +1580,11 @@ static HRESULT WINAPI onmessage(IDispatchEx *iface, DISPID id, LCID lcid, WORD w ok(!wcscmp(bstr, L"foobar"), "data = %s\n", wine_dbgstr_w(bstr)); SysFreeString(bstr);
+ hres = IDOMMessageEvent_get_origin(msg, &bstr); + ok(hres == S_OK, "get_origin failed: %08lx\n", hres); + ok(!wcscmp(bstr, L"about:"), "origin = %s\n", wine_dbgstr_w(bstr)); + SysFreeString(bstr); + hres = IDOMMessageEvent_get_source(msg, &source); ok(hres == S_OK, "get_source failed: %08lx\n", hres); ok(source == onmessage_source, "source != onmessage_source\n"); diff --git a/dlls/mshtml/tests/events.js b/dlls/mshtml/tests/events.js index a5f66a2f031..a130917cfda 100644 --- a/dlls/mshtml/tests/events.js +++ b/dlls/mshtml/tests/events.js @@ -830,6 +830,7 @@ async_test("message event", function() { if(listener_called) { ok(e.data === "echo", "e.data (diff origin) = " + e.data); ok(e.source === iframe.contentWindow, "e.source (diff origin) not iframe.contentWindow"); + ok(e.origin === "http://winetest.different.org:1234", "e.origin (diff origin) = " + e.origin); next_test(); return; } @@ -838,6 +839,7 @@ async_test("message event", function() { ok(e.bubbles === false, "bubbles = " + e.bubbles); ok(e.cancelable === false, "cancelable = " + e.cancelable); ok(e.source === window, "e.source = " + e.source); + ok(e.origin === "http://winetest.example.org", "e.origin = " + e.origin);
iframe.onload = function() { iframe.contentWindow.postMessage("echo", "hTtP://WinEtesT.difFerent.ORG:1234"); } iframe.src = "http://winetest.different.org:1234/xhr_iframe.html";
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmlevent.c | 48 ++++++++++- dlls/mshtml/tests/documentmode.js | 29 +++++++ dlls/mshtml/tests/events.c | 130 ++++++++++++++++++++++++++++++ dlls/mshtml/tests/events.js | 1 + 4 files changed, 206 insertions(+), 2 deletions(-)
diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c index f6684d9d6ee..b86b7513477 100644 --- a/dlls/mshtml/htmlevent.c +++ b/dlls/mshtml/htmlevent.c @@ -3741,6 +3741,11 @@ static HRESULT WINAPI DOMMessageEvent_get_data(IDOMMessageEvent *iface, BSTR *p)
TRACE("(%p)->(%p)\n", This, p);
+ if(V_VT(&This->data) == VT_EMPTY) { + *p = SysAllocString(L""); + return S_OK; + } + if(V_VT(&This->data) != VT_BSTR) { FIXME("non-string data\n"); return E_NOTIMPL; @@ -3792,9 +3797,48 @@ static HRESULT WINAPI DOMMessageEvent_initMessageEvent(IDOMMessageEvent *iface, BSTR last_event_id, IHTMLWindow2 *source) { DOMMessageEvent *This = impl_from_IDOMMessageEvent(iface); - FIXME("(%p)->(%s %x %x %s %s %s %p)\n", This, debugstr_w(type), can_bubble, cancelable, + BSTR new_origin = NULL; + BSTR new_data = NULL; + HRESULT hres; + + TRACE("(%p)->(%s %x %x %s %s %s %p)\n", This, debugstr_w(type), can_bubble, cancelable, debugstr_w(data), debugstr_w(origin), debugstr_w(last_event_id), source); - return E_NOTIMPL; + + if(This->event.target) { + TRACE("called on already dispatched event\n"); + return S_OK; + } + + if((data && !(new_data = SysAllocString(data))) || + (origin && !(new_origin = SysAllocString(origin)))) { + hres = E_OUTOFMEMORY; + goto fail; + } + + hres = IDOMEvent_initEvent(&This->event.IDOMEvent_iface, type, can_bubble, cancelable); + if(FAILED(hres)) + goto fail; + + if(new_data) { + VariantClear(&This->data); + V_VT(&This->data) = VT_BSTR; + V_BSTR(&This->data) = new_data; + } + if(new_origin) { + SysFreeString(This->origin); + This->origin = new_origin; + } + if(This->source) + IHTMLWindow2_Release(This->source); + This->source = source; + if(source) + IHTMLWindow2_AddRef(source); + return S_OK; + +fail: + SysFreeString(new_origin); + SysFreeString(new_data); + return hres; }
static const IDOMMessageEventVtbl DOMMessageEventVtbl = { diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 94183ad015e..5249e042182 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -2919,6 +2919,32 @@ sync_test("MutationObserver", function() { test_exposed("takeRecords"); });
+sync_test("initMessageEvent", function() { + var e, v = document.documentMode; + if(!document.createEvent) + return; + e = document.createEvent("MessageEvent"); + ok(e.data === (v < 10 ? "" : undefined), "e.data = " + e.data); + ok(e.bubbles === false, "bubbles = " + e.bubbles); + ok(e.cancelable === false, "cancelable = " + e.cancelable); + ok(e.source === null, "e.source = " + e.source); + ok(e.origin === "", "e.origin = " + e.origin); + + e.initMessageEvent("blah", true, true, 137, "wine", 1234, window); + ok(e.data === "137", "e.data = " + e.data); + ok(e.bubbles === true, "bubbles = " + e.bubbles); + ok(e.cancelable === true, "cancelable = " + e.cancelable); + ok(e.source === window, "e.source = " + e.source); + ok(e.origin === "wine", "e.origin = " + e.origin); + + e.initMessageEvent("abcd", false, false, "testdata", "origin", 42, null); + ok(e.data === "testdata", "e.data = " + e.data); + ok(e.bubbles === false, "bubbles = " + e.bubbles); + ok(e.cancelable === false, "cancelable = " + e.cancelable); + ok(e.source === null, "e.source = " + e.source); + ok(e.origin === "origin", "e.origin = " + e.origin); +}); + async_test("postMessage", function() { var v = document.documentMode; var onmessage_called = false; @@ -2930,6 +2956,9 @@ async_test("postMessage", function() { ok(e.data === (v < 10 ? "10" : 10), "e.data = " + e.data); ok(e.source === window, "e.source = " + e.source); ok(e.origin === "http://winetest.example.org", "e.origin = " + e.origin); + + e = document.createEvent("MessageEvent"); + ok(e.data === (v < 10 ? "" : undefined), "created e.data = " + e.data); next_test(); } } diff --git a/dlls/mshtml/tests/events.c b/dlls/mshtml/tests/events.c index 0dd622b15c3..9760d6bcb9a 100644 --- a/dlls/mshtml/tests/events.c +++ b/dlls/mshtml/tests/events.c @@ -3345,6 +3345,136 @@ static void test_message_event(IHTMLDocument2 *doc) VariantClear(&v[1]); IHTMLWindow2_Release(child); IDispatchEx_Release(dispex); + + if(document_mode >= 9) { + IDOMMessageEvent *msg_event = NULL; + IDocumentEvent *doc_event; + IHTMLWindow2 *source; + IDOMEvent *event; + UINT argerr; + + hres = IHTMLDocument2_QueryInterface(doc, &IID_IDocumentEvent, (void**)&doc_event); + ok(hres == S_OK, "Could not get IDocumentEvent iface: %08lx\n", hres); + + bstr = SysAllocString(L"MessageEvent"); + hres = IDocumentEvent_createEvent(doc_event, bstr, &event); + ok(hres == S_OK, "createEvent failed: %08lx\n", hres); + IDocumentEvent_Release(doc_event); + SysFreeString(bstr); + + hres = IDOMEvent_QueryInterface(event, &IID_IDOMMessageEvent, (void**)&msg_event); + ok(hres == S_OK, "Could not get IDOMMessageEvent iface: %08lx\n", hres); + ok(msg_event != NULL, "msg_event = NULL\n"); + IDOMEvent_Release(event); + + hres = IDOMMessageEvent_get_source(msg_event, &source); + ok(hres == S_OK, "get_source failed: %08lx\n", hres); + ok(source == NULL, "uninitialized source != NULL\n"); + + hres = IDOMMessageEvent_get_origin(msg_event, &bstr); + ok(hres == S_OK, "get_origin failed: %08lx\n", hres); + ok(!bstr, "uninitialized origin = %s\n", wine_dbgstr_w(bstr)); + + /* IE10+ crash when using the get_data from the interface (because it's not a string yet?) */ + if(document_mode < 10) { + hres = IDOMMessageEvent_get_data(msg_event, &bstr); + ok(hres == S_OK, "get_data failed: %08lx\n", hres); + ok(!wcscmp(bstr, L""), "uninitialized data = %s\n", wine_dbgstr_w(bstr)); + SysFreeString(bstr); + + bstr = SysAllocString(L"foobar"); + hres = IDOMMessageEvent_initMessageEvent(msg_event, bstr, VARIANT_FALSE, VARIANT_FALSE, bstr, bstr, NULL, window); + ok(hres == S_OK, "initMessageEvent failed: %08lx\n", hres); + SysFreeString(bstr); + + hres = IDOMMessageEvent_get_data(msg_event, &bstr); + ok(hres == S_OK, "get_data failed: %08lx\n", hres); + ok(!wcscmp(bstr, L"foobar"), "data = %s\n", wine_dbgstr_w(bstr)); + SysFreeString(bstr); + + hres = IDOMMessageEvent_get_source(msg_event, &source); + ok(hres == S_OK, "get_source failed: %08lx\n", hres); + ok(source == window, "source != window\n"); + IHTMLWindow2_Release(source); + + hres = IDOMMessageEvent_get_origin(msg_event, &bstr); + ok(hres == S_OK, "get_origin failed: %08lx\n", hres); + ok(!wcscmp(bstr, L"foobar"), "origin = %s\n", wine_dbgstr_w(bstr)); + SysFreeString(bstr); + + bstr = SysAllocString(L"barfoo"); + hres = IDOMMessageEvent_initMessageEvent(msg_event, bstr, VARIANT_FALSE, VARIANT_FALSE, NULL, NULL, NULL, NULL); + ok(hres == S_OK, "initMessageEvent failed: %08lx\n", hres); + SysFreeString(bstr); + + hres = IDOMMessageEvent_get_data(msg_event, &bstr); + ok(hres == S_OK, "get_data failed: %08lx\n", hres); + ok(!wcscmp(bstr, L"foobar"), "data = %s\n", wine_dbgstr_w(bstr)); + SysFreeString(bstr); + + hres = IDOMMessageEvent_get_source(msg_event, &source); + ok(hres == S_OK, "get_source failed: %08lx\n", hres); + ok(source == NULL, "source != NULL\n"); + + hres = IDOMMessageEvent_get_origin(msg_event, &bstr); + ok(hres == S_OK, "get_origin failed: %08lx\n", hres); + ok(broken(!bstr) /* win10-21h2 */ || !wcscmp(bstr, L"foobar"), "origin = %s\n", wine_dbgstr_w(bstr)); + SysFreeString(bstr); + }else { + bstr = SysAllocString(L"data"); + hres = IDOMMessageEvent_GetIDsOfNames(msg_event, &IID_NULL, &bstr, 1, 0, &dispid); + ok(hres == S_OK, "GetIDsOfNames(data) failed: %08lx\n", hres); + SysFreeString(bstr); + + dp.cArgs = 0; + dp.rgvarg = NULL; + hres = IDOMMessageEvent_Invoke(msg_event, dispid, &IID_NULL, 0, DISPATCH_PROPERTYGET, &dp, &v[0], NULL, &argerr); + ok(hres == S_OK, "Invoke(data) failed: %08lx\n", hres); + ok(V_VT(&v[0]) == VT_EMPTY, "V_VT(uninitialized data) = %d\n", V_VT(&v[0])); + + bstr = SysAllocString(L"foobar"); + hres = IDOMMessageEvent_initMessageEvent(msg_event, bstr, VARIANT_FALSE, VARIANT_FALSE, bstr, bstr, NULL, window); + ok(hres == S_OK, "initMessageEvent failed: %08lx\n", hres); + SysFreeString(bstr); + + hres = IDOMMessageEvent_Invoke(msg_event, dispid, &IID_NULL, 0, DISPATCH_PROPERTYGET, &dp, &v[0], NULL, &argerr); + ok(hres == S_OK, "Invoke(data) failed: %08lx\n", hres); + ok(V_VT(&v[0]) == VT_BSTR, "V_VT(data) = %d\n", V_VT(&v[0])); + ok(!wcscmp(V_BSTR(&v[0]), L"foobar"), "V_BSTR(data) = %s\n", wine_dbgstr_w(V_BSTR(&v[0]))); + VariantClear(&v[0]); + + hres = IDOMMessageEvent_get_source(msg_event, &source); + ok(hres == S_OK, "get_source failed: %08lx\n", hres); + ok(source == window, "source != window\n"); + IHTMLWindow2_Release(source); + + hres = IDOMMessageEvent_get_origin(msg_event, &bstr); + ok(hres == S_OK, "get_origin failed: %08lx\n", hres); + ok(!wcscmp(bstr, L"foobar"), "origin = %s\n", wine_dbgstr_w(bstr)); + SysFreeString(bstr); + + bstr = SysAllocString(L"barfoo"); + hres = IDOMMessageEvent_initMessageEvent(msg_event, bstr, VARIANT_FALSE, VARIANT_FALSE, NULL, NULL, NULL, NULL); + ok(hres == S_OK, "initMessageEvent failed: %08lx\n", hres); + SysFreeString(bstr); + + hres = IDOMMessageEvent_Invoke(msg_event, dispid, &IID_NULL, 0, DISPATCH_PROPERTYGET, &dp, &v[0], NULL, &argerr); + ok(hres == S_OK, "Invoke(data) failed: %08lx\n", hres); + ok(V_VT(&v[0]) == VT_BSTR, "V_VT(data) = %d\n", V_VT(&v[0])); + ok(!wcscmp(V_BSTR(&v[0]), L"foobar"), "V_BSTR(data) = %s\n", wine_dbgstr_w(V_BSTR(&v[0]))); + + hres = IDOMMessageEvent_get_source(msg_event, &source); + ok(hres == S_OK, "get_source failed: %08lx\n", hres); + ok(source == NULL, "source != NULL\n"); + + hres = IDOMMessageEvent_get_origin(msg_event, &bstr); + ok(hres == S_OK, "get_origin failed: %08lx\n", hres); + ok(broken(!bstr) /* win10-21h2 */ || !wcscmp(bstr, L"foobar"), "origin = %s\n", wine_dbgstr_w(bstr)); + SysFreeString(bstr); + } + + IDOMMessageEvent_Release(msg_event); + } }
static void test_visibilitychange(IHTMLDocument2 *doc) diff --git a/dlls/mshtml/tests/events.js b/dlls/mshtml/tests/events.js index a130917cfda..9282d48bacc 100644 --- a/dlls/mshtml/tests/events.js +++ b/dlls/mshtml/tests/events.js @@ -835,6 +835,7 @@ async_test("message event", function() { return; } listener_called = true; + e.initMessageEvent("blah", true, true, "barfoo", "wine", 1234, window); ok(e.data === "test", "e.data = " + e.data); ok(e.bubbles === false, "bubbles = " + e.bubbles); ok(e.cancelable === false, "cancelable = " + e.cancelable);
From: Gabriel Ivăncescu gabrielopcode@gmail.com
It's mostly implemented, and issession isn't even exposed.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmlevent.c | 1 + dlls/mshtml/mshtml_private.h | 1 + dlls/mshtml/tests/events.html | 7 ++++++- 3 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c index b86b7513477..1ae3a0de384 100644 --- a/dlls/mshtml/htmlevent.c +++ b/dlls/mshtml/htmlevent.c @@ -2065,6 +2065,7 @@ static const dispex_static_data_vtbl_t HTMLEventObj_dispex_vtbl = { };
static const tid_t HTMLEventObj_iface_tids[] = { + IHTMLEventObj5_tid, IHTMLEventObj_tid, 0 }; diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index db37375c089..9609fb5edcb 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -208,6 +208,7 @@ typedef struct EventTarget EventTarget; XIID(IHTMLElementCollection) \ XIID(IHTMLEmbedElement) \ XIID(IHTMLEventObj) \ + XIID(IHTMLEventObj5) \ XIID(IHTMLFiltersCollection) \ XIID(IHTMLFormElement) \ XIID(IHTMLFrameBase) \ diff --git a/dlls/mshtml/tests/events.html b/dlls/mshtml/tests/events.html index 6f9b3dacbbc..76473277e3c 100644 --- a/dlls/mshtml/tests/events.html +++ b/dlls/mshtml/tests/events.html @@ -284,7 +284,12 @@ function test_attach_in_attach() { }
function test_event_obj_props(e) { - var i, props; + var i, props = [ + "altKey", "button", "cancelBubble", "clientX", "clientY", "ctrlKey", "data", "fromElement", "keyCode", "offsetX", "offsetY", + "origin", "qualifier", "reason", "returnValue", "screenX", "screenY", "shiftKey", "source", "srcElement", "srcFilter", + "toElement", "type", "url", "x", "y" ]; + for(i = 0; i < props.length; i++) + ok(props[i] in e, props[i] + " not in event obj");
props = [ "imeCompositionChange", "imeNotifyCommand", "imeNotifyData", "imeRequest", "imeRequestData", "issession", "keyboardLayout" ]; for(i = 0; i < props.length; i++)
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/tests/script.c | 146 +++++++++++++++++++++++++++++++++++++ 1 file changed, 146 insertions(+)
diff --git a/dlls/mshtml/tests/script.c b/dlls/mshtml/tests/script.c index 5c969e4a3d9..e6acf5ae5b1 100644 --- a/dlls/mshtml/tests/script.c +++ b/dlls/mshtml/tests/script.c @@ -147,8 +147,11 @@ DEFINE_EXPECT(external_success); DEFINE_EXPECT(QS_VariantConversion); DEFINE_EXPECT(QS_IActiveScriptSite); DEFINE_EXPECT(QS_GetCaller); +DEFINE_EXPECT(QS_IActiveScriptSite2); +DEFINE_EXPECT(QS_GetCaller2); DEFINE_EXPECT(ChangeType_bstr); DEFINE_EXPECT(ChangeType_dispatch); +DEFINE_EXPECT(cmdtarget_Exec); DEFINE_EXPECT(GetTypeInfo);
#define TESTACTIVEX_CLSID "{178fc163-f585-4e24-9c13-4bb7faf80646}" @@ -489,6 +492,8 @@ static IPropertyNotifySinkVtbl PropertyNotifySinkVtbl = {
static IPropertyNotifySink PropertyNotifySink = { &PropertyNotifySinkVtbl };
+static IOleCommandTarget cmdtarget; + static HRESULT WINAPI VariantChangeType_QueryInterface(IVariantChangeType *iface, REFIID riid, void **ppv) { ok(0, "unexpected call %s\n", wine_dbgstr_guid(riid)); @@ -595,6 +600,52 @@ static const IServiceProviderVtbl ServiceProviderVtbl = {
static IServiceProvider caller_sp = { &ServiceProviderVtbl };
+static HRESULT WINAPI ServiceProvider2_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv) +{ + ok(0, "unexpected call\n"); + return E_NOINTERFACE; +} + +static ULONG WINAPI ServiceProvider2_AddRef(IServiceProvider *iface) +{ + return 2; +} + +static ULONG WINAPI ServiceProvider2_Release(IServiceProvider *iface) +{ + return 1; +} + +static HRESULT WINAPI ServiceProvider2_QueryService(IServiceProvider *iface, REFGUID guidService, + REFIID riid, void **ppv) +{ + if(IsEqualGUID(guidService, &IID_IActiveScriptSite)) { + CHECK_EXPECT(QS_IActiveScriptSite2); + ok(IsEqualGUID(riid, &IID_IOleCommandTarget), "unexpected riid %s\n", wine_dbgstr_guid(riid)); + *ppv = &cmdtarget; + return S_OK; + } + + if(IsEqualGUID(guidService, &SID_GetCaller)) { + CHECK_EXPECT(QS_GetCaller2); + ok(IsEqualGUID(riid, &IID_IServiceProvider), "unexpected riid %s\n", wine_dbgstr_guid(riid)); + *ppv = NULL; + return S_OK; + } + + ok(0, "unexpected service %s\n", wine_dbgstr_guid(guidService)); + return E_NOINTERFACE; +} + +static const IServiceProviderVtbl ServiceProvider2Vtbl = { + ServiceProvider2_QueryInterface, + ServiceProvider2_AddRef, + ServiceProvider2_Release, + ServiceProvider2_QueryService +}; + +static IServiceProvider caller_sp2 = { &ServiceProvider2Vtbl }; + static HRESULT WINAPI DispatchEx_QueryInterface(IDispatchEx *iface, REFIID riid, void **ppv) { *ppv = NULL; @@ -1465,6 +1516,88 @@ static IDispatchExVtbl externalDispVtbl = {
static IDispatchEx externalDisp = { &externalDispVtbl };
+static HRESULT WINAPI DispatchExStub_QueryInterface(IDispatchEx *iface, REFIID riid, void **ppv) +{ + ok(0, "unexpected call %s\n", wine_dbgstr_guid(riid)); + return E_NOINTERFACE; +} + +static IDispatchExVtbl DispatchExStubVtbl = { + DispatchExStub_QueryInterface, + DispatchEx_AddRef, + DispatchEx_Release, + DispatchEx_GetTypeInfoCount, + DispatchEx_GetTypeInfo, + DispatchEx_GetIDsOfNames, + DispatchEx_Invoke, + DispatchEx_GetDispID, + DispatchEx_InvokeEx, + DispatchEx_DeleteMemberByName, + DispatchEx_DeleteMemberByDispID, + DispatchEx_GetMemberProperties, + DispatchEx_GetMemberName, + DispatchEx_GetNextDispID, + DispatchEx_GetNameSpaceParent +}; + +static IDispatchEx DispatchExStub = { &DispatchExStubVtbl }; + +static HRESULT WINAPI cmdtarget_QueryInterface(IOleCommandTarget *iface, REFIID riid, void **ppv) +{ + if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IOleCommandTarget)) + *ppv = &cmdtarget; + else { + ok(0, "unexpected riid %s\n", wine_dbgstr_guid(riid)); + *ppv = NULL; + return E_NOINTERFACE; + } + return S_OK; +} + +static ULONG WINAPI cmdtarget_AddRef(IOleCommandTarget *iface) +{ + return 2; +} + +static ULONG WINAPI cmdtarget_Release(IOleCommandTarget *iface) +{ + return 1; +} + +static HRESULT WINAPI cmdtarget_QueryStatus(IOleCommandTarget *iface, const GUID *pguidCmdGroup, + ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT *pCmdText) +{ + ok(0, "unexpected call\n"); + return OLECMDERR_E_UNKNOWNGROUP; +} + +static HRESULT WINAPI cmdtarget_Exec(IOleCommandTarget *iface, const GUID *pguidCmdGroup, + DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut) +{ + CHECK_EXPECT2(cmdtarget_Exec); + ok(pguidCmdGroup && IsEqualGUID(pguidCmdGroup, &CGID_ScriptSite), "pguidCmdGroup = %s\n", wine_dbgstr_guid(pguidCmdGroup)); + ok(nCmdID == CMDID_SCRIPTSITE_SECURITY_WINDOW, "nCmdID = %lu\n", nCmdID); + ok(!nCmdexecopt, "nCmdexecopt = %lu\n", nCmdexecopt); + ok(!pvaIn, "pvaIn != NULL\n"); + ok(pvaOut != NULL, "pvaOut = NULL\n"); + + /* Looks like native just uses this for some sort of hardcoded security check + * without actually using the IDispatchEx interface or QI? (for ACCESSDENIED) */ + V_VT(pvaOut) = VT_DISPATCH; + V_DISPATCH(pvaOut) = (IDispatch*)&DispatchExStub; + return S_OK; +} + +static const IOleCommandTargetVtbl cmdtarget_vtbl = { + cmdtarget_QueryInterface, + cmdtarget_AddRef, + cmdtarget_Release, + cmdtarget_QueryStatus, + cmdtarget_Exec +}; + +static IOleCommandTarget cmdtarget = { &cmdtarget_vtbl }; + static HRESULT QueryInterface(REFIID,void**);
static HRESULT WINAPI DocHostUIHandler_QueryInterface(IDocHostUIHandler2 *iface, REFIID riid, void **ppv) @@ -2740,6 +2873,19 @@ static void test_func(IDispatchEx *obj) todo_wine CHECK_CALLED(QS_IActiveScriptSite); todo_wine CHECK_CALLED(QS_GetCaller);
+ SET_EXPECT(QS_IActiveScriptSite2); + SET_EXPECT(QS_GetCaller2); + SET_EXPECT(cmdtarget_Exec); + hres = dispex_propget(dispex, DISPID_VALUE, &var, &caller_sp2); + ok(hres == S_OK, "InvokeEx returned: %08lx, expected S_OK\n", hres); + ok(V_VT(&var) == VT_BSTR, "V_VT(var) = %d\n", V_VT(&var)); + ok(!lstrcmpW(V_BSTR(&var), L"\nfunction toString() {\n [native code]\n}\n"), + "V_BSTR(var) = %s\n", wine_dbgstr_w(V_BSTR(&var))); + VariantClear(&var); + todo_wine CHECK_CALLED(QS_IActiveScriptSite2); + todo_wine CHECK_CALLED(QS_GetCaller2); + todo_wine CHECK_CALLED(cmdtarget_Exec); + IDispatchEx_Release(dispex); }
This merge request was approved by Jacek Caban.