mshtml: Semi-implement non-string primitive data for postMessage.

IE10 and up actually pass cloned data without converting them to strings,
using the Structured Clone Algorithm. Implement support for the basic
variant types for now.

Signed-off-by: Gabriel Ivăncescu <gabrielopcode@gmail.com>
This commit is contained in:
Gabriel Ivăncescu 2022-08-10 18:07:38 +03:00 committed by Alexandre Julliard
parent 0d4817fadb
commit 619312fd76
5 changed files with 126 additions and 38 deletions

View file

@ -2314,7 +2314,7 @@ static void DOMCustomEvent_destroy(DOMEvent *event)
typedef struct {
DOMEvent event;
IDOMMessageEvent IDOMMessageEvent_iface;
WCHAR *data;
VARIANT data;
} DOMMessageEvent;
static inline DOMMessageEvent *impl_from_IDOMMessageEvent(IDOMMessageEvent *iface)
@ -2376,7 +2376,26 @@ static HRESULT WINAPI DOMMessageEvent_get_data(IDOMMessageEvent *iface, BSTR *p)
TRACE("(%p)->(%p)\n", This, p);
return (*p = SysAllocString(This->data)) ? S_OK : E_OUTOFMEMORY;
if(V_VT(&This->data) != VT_BSTR) {
FIXME("non-string data\n");
return E_NOTIMPL;
}
return (*p = SysAllocString(V_BSTR(&This->data))) ? S_OK : E_OUTOFMEMORY;
}
static HRESULT DOMMessageEvent_get_data_hook(DispatchEx *dispex, WORD flags, DISPPARAMS *dp, VARIANT *res,
EXCEPINFO *ei, IServiceProvider *caller)
{
DOMMessageEvent *This = CONTAINING_RECORD(dispex, DOMMessageEvent, event.dispex);
if(!(flags & DISPATCH_PROPERTYGET) || !res)
return S_FALSE;
TRACE("(%p)->(%p)\n", This, res);
V_VT(res) = VT_EMPTY;
return VariantCopy(res, &This->data);
}
static HRESULT WINAPI DOMMessageEvent_get_origin(IDOMMessageEvent *iface, BSTR *p)
@ -2433,7 +2452,16 @@ static void *DOMMessageEvent_query_interface(DOMEvent *event, REFIID riid)
static void DOMMessageEvent_destroy(DOMEvent *event)
{
DOMMessageEvent *message_event = DOMMessageEvent_from_DOMEvent(event);
heap_free(message_event->data);
VariantClear(&message_event->data);
}
static void DOMMessageEvent_init_dispex_info(dispex_data_t *info, compat_mode_t compat_mode)
{
static const dispex_hook_t hooks[] = {
{DISPID_IDOMMESSAGEEVENT_DATA, DOMMessageEvent_get_data_hook},
{DISPID_UNKNOWN}
};
dispex_info_add_interface(info, IDOMMessageEvent_tid, compat_mode >= COMPAT_MODE_IE10 ? hooks : NULL);
}
typedef struct {
@ -2646,7 +2674,6 @@ static dispex_static_data_t DOMCustomEvent_dispex = {
static const tid_t DOMMessageEvent_iface_tids[] = {
IDOMEvent_tid,
IDOMMessageEvent_tid,
0
};
@ -2654,7 +2681,8 @@ dispex_static_data_t DOMMessageEvent_dispex = {
L"MessageEvent",
NULL,
DispDOMMessageEvent_tid,
DOMMessageEvent_iface_tids
DOMMessageEvent_iface_tids,
DOMMessageEvent_init_dispex_info
};
static const tid_t DOMProgressEvent_iface_tids[] = {
@ -2878,7 +2906,7 @@ HRESULT create_document_event(HTMLDocumentNode *doc, eventid_t event_id, DOMEven
return S_OK;
}
HRESULT create_message_event(HTMLDocumentNode *doc, BSTR data, DOMEvent **ret)
HRESULT create_message_event(HTMLDocumentNode *doc, VARIANT *data, DOMEvent **ret)
{
DOMMessageEvent *message_event;
DOMEvent *event;
@ -2889,9 +2917,11 @@ HRESULT create_message_event(HTMLDocumentNode *doc, BSTR data, DOMEvent **ret)
return hres;
message_event = DOMMessageEvent_from_DOMEvent(event);
if(!(message_event->data = heap_strdupW(data))) {
V_VT(&message_event->data) = VT_EMPTY;
hres = VariantCopy(&message_event->data, data);
if(FAILED(hres)) {
IDOMEvent_Release(&event->IDOMEvent_iface);
return E_OUTOFMEMORY;
return hres;
}
*ret = event;

View file

@ -111,7 +111,7 @@ void dispatch_event(EventTarget*,DOMEvent*) DECLSPEC_HIDDEN;
HRESULT create_document_event(HTMLDocumentNode*,eventid_t,DOMEvent**) DECLSPEC_HIDDEN;
HRESULT create_document_event_str(HTMLDocumentNode*,const WCHAR*,IDOMEvent**) DECLSPEC_HIDDEN;
HRESULT create_event_from_nsevent(nsIDOMEvent*,compat_mode_t,DOMEvent**) DECLSPEC_HIDDEN;
HRESULT create_message_event(HTMLDocumentNode*,BSTR,DOMEvent**) DECLSPEC_HIDDEN;
HRESULT create_message_event(HTMLDocumentNode*,VARIANT*,DOMEvent**) DECLSPEC_HIDDEN;
void init_nsevents(HTMLDocumentNode*) DECLSPEC_HIDDEN;
void release_nsevents(HTMLDocumentNode*) DECLSPEC_HIDDEN;

View file

@ -2216,37 +2216,17 @@ static void post_message_destr(task_t *_task)
static HRESULT WINAPI HTMLWindow6_postMessage(IHTMLWindow6 *iface, BSTR msg, VARIANT targetOrigin)
{
HTMLWindow *This = impl_from_IHTMLWindow6(iface);
DOMEvent *event;
HRESULT hres;
VARIANT var, transfer;
FIXME("(%p)->(%s %s) semi-stub\n", This, debugstr_w(msg), debugstr_variant(&targetOrigin));
if(!This->inner_window->doc) {
FIXME("No document\n");
return E_FAIL;
}
if(V_VT(&targetOrigin) != VT_BSTR)
return E_INVALIDARG;
hres = create_message_event(This->inner_window->doc, msg, &event);
if(FAILED(hres))
return hres;
if(dispex_compat_mode(&This->inner_window->event_target.dispex) >= COMPAT_MODE_IE9) {
struct post_message_task *task;
if(!(task = heap_alloc(sizeof(*task)))) {
IDOMEvent_Release(&event->IDOMEvent_iface);
return E_OUTOFMEMORY;
}
task->event = event;
task->window = This->inner_window;
IHTMLWindow2_AddRef(&task->window->base.IHTMLWindow2_iface);
return push_task(&task->header, post_message_proc, post_message_destr,
This->inner_window->task_magic);
}
dispatch_event(&This->inner_window->event_target, event);
IDOMEvent_Release(&event->IDOMEvent_iface);
return S_OK;
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);
}
static HRESULT WINAPI HTMLWindow6_toStaticHTML(IHTMLWindow6 *iface, BSTR bstrHTML, BSTR *pbstrStaticHTML)
@ -3175,6 +3155,77 @@ static HRESULT WINAPI window_private_matchMedia(IWineHTMLWindowPrivate *iface, B
return create_media_query_list(This, media_query, media_query_list);
}
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)
FIXME("transfer not implemented, ignoring\n");
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 = heap_alloc(sizeof(*task)))) {
IDOMEvent_Release(&event->IDOMEvent_iface);
return E_OUTOFMEMORY;
}
task->event = event;
task->window = window;
IHTMLWindow2_AddRef(&task->window->base.IHTMLWindow2_iface);
return push_task(&task->header, 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);
@ -3202,6 +3253,7 @@ static const IWineHTMLWindowPrivateVtbl WineHTMLWindowPrivateVtbl = {
window_private_cancelAnimationFrame,
window_private_get_console,
window_private_matchMedia,
window_private_postMessage,
};
static inline HTMLWindow *impl_from_IWineHTMLWindowCompatPrivateVtbl(IWineHTMLWindowCompatPrivate *iface)

View file

@ -112,6 +112,8 @@ 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);
}
[

View file

@ -2078,10 +2078,14 @@ sync_test("__defineSetter__", function() {
async_test("postMessage", function() {
var v = document.documentMode;
var onmessage_called = false;
window.onmessage = function() {
window.onmessage = function(e) {
onmessage_called = true;
if(v < 9)
ok(e === undefined, "e = " + e);
else
ok(e.data === (v < 10 ? "10" : 10), "e.data = " + e.data);
next_test();
}
window.postMessage("test", "*");
window.postMessage(10, "*");
ok(onmessage_called == (v < 9 ? true : false), "onmessage not called");
});