This implements sending StorageEvents to the same window/doc from where the storage change happened, which seems to be a thing on native IE. For some reason I was unable to have them actually sent to other windows, so that's not implemented since I've no idea how that even gets triggered to test it, and if it does it will probably be in a follow up MR, even though that's *supposed* to be the use of these events���
localStorage sends for `onstoragecommit` on the doc that did the change, while sessionStorage sends for `onstorage` on the window and doc that did the change, depending on compat mode. Although the event sent to the document's `onstorage` seems to be a legacy/old-style event (as tests show).
Tests are on the last patch since events have to be sent properly (else it hangs).
-- v2: mshtml/tests: Add tests for StorageEvents. mshtml: Send StorageEvents when removing an existing item. mshtml: Send StorageEvents when setting an item. mshtml: Implement StorageEvent and send it when clearing the storage. mshtml: Move the MessageEvent construction to a helper. include: Add IDOMStorageEvent and DispDOMStorageEvent interfaces.
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- include/mshtmdid.h | 8 +++++ include/mshtml.idl | 78 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+)
diff --git a/include/mshtmdid.h b/include/mshtmdid.h index f56fc4d6f83..4e25ad8036b 100644 --- a/include/mshtmdid.h +++ b/include/mshtmdid.h @@ -4716,6 +4716,14 @@ #define DISPID_IDOMPROGRESSEVENT_TOTAL DISPID_DOMPROGRESSEVENT+3 #define DISPID_IDOMPROGRESSEVENT_INITPROGRESSEVENT DISPID_DOMPROGRESSEVENT+4
+/* IDOMStorageEvent */ +#define DISPID_IDOMSTORAGEEVENT_KEY DISPID_DOMSTORAGEEVENT+1 +#define DISPID_IDOMSTORAGEEVENT_OLDVALUE DISPID_DOMSTORAGEEVENT+2 +#define DISPID_IDOMSTORAGEEVENT_NEWVALUE DISPID_DOMSTORAGEEVENT+3 +#define DISPID_IDOMSTORAGEEVENT_URL DISPID_DOMSTORAGEEVENT+4 +#define DISPID_IDOMSTORAGEEVENT_STORAGEAREA DISPID_DOMSTORAGEEVENT+5 +#define DISPID_IDOMSTORAGEEVENT_INITSTORAGEEVENT DISPID_DOMSTORAGEEVENT+6 + /* IHTMLControlElement */ #define DISPID_IHTMLCONTROLELEMENT_TABINDEX STDPROPID_XOBJ_TABINDEX #define DISPID_IHTMLCONTROLELEMENT_FOCUS (DISPID_SITE+0) diff --git a/include/mshtml.idl b/include/mshtml.idl index 6caa0c8ee5a..aa243897405 100644 --- a/include/mshtml.idl +++ b/include/mshtml.idl @@ -28661,6 +28661,84 @@ methods: [in] ULONGLONG totalArg); };
+/***************************************************************************** + * IDOMStorageEvent interface + */ +[ + odl, + oleautomation, + dual, + uuid(30510722-98b5-11cf-bb82-00aa00bdce0b) +] +interface IDOMStorageEvent : IDispatch +{ + [propget, id(DISPID_IDOMSTORAGEEVENT_KEY)] + HRESULT key([out, retval] BSTR *p); + + [propget, id(DISPID_IDOMSTORAGEEVENT_OLDVALUE)] + HRESULT oldValue([out, retval] BSTR *p); + + [propget, id(DISPID_IDOMSTORAGEEVENT_NEWVALUE)] + HRESULT newValue([out, retval] BSTR *p); + + [propget, id(DISPID_IDOMSTORAGEEVENT_URL)] + HRESULT url([out, retval] BSTR *p); + + [propget, id(DISPID_IDOMSTORAGEEVENT_STORAGEAREA)] + HRESULT storageArea([out, retval] IHTMLStorage **p); + + [id(DISPID_IDOMSTORAGEEVENT_INITSTORAGEEVENT)] + HRESULT initStorageEvent( + [in] BSTR eventType, + [in] VARIANT_BOOL canBubble, + [in] VARIANT_BOOL cancelable, + [in] BSTR keyArg, + [in] BSTR oldValueArg, + [in] BSTR newValueArg, + [in] BSTR urlArg, + [in] IHTMLStorage *storageAreaArg); +}; + +/***************************************************************************** + * DispDOMStorageEvent dispinterface + */ +[ + hidden, + uuid(30590093-98b5-11cf-bb82-00aa00bdce0b) +] +dispinterface DispDOMStorageEvent +{ +properties: +methods: + WINE_IDOMEVENT_DISPINTERFACE_DECL; + + [propget, id(DISPID_IDOMSTORAGEEVENT_KEY)] + BSTR key(); + + [propget, id(DISPID_IDOMSTORAGEEVENT_OLDVALUE)] + BSTR oldValue(); + + [propget, id(DISPID_IDOMSTORAGEEVENT_NEWVALUE)] + BSTR newValue(); + + [propget, id(DISPID_IDOMSTORAGEEVENT_URL)] + BSTR url(); + + [propget, id(DISPID_IDOMSTORAGEEVENT_STORAGEAREA)] + IHTMLStorage *storageArea(); + + [id(DISPID_IDOMSTORAGEEVENT_INITSTORAGEEVENT)] + void initStorageEvent( + [in] BSTR eventType, + [in] VARIANT_BOOL canBubble, + [in] VARIANT_BOOL cancelable, + [in] BSTR keyArg, + [in] BSTR oldValueArg, + [in] BSTR newValueArg, + [in] BSTR urlArg, + [in] IHTMLStorage *storageAreaArg); +}; + /***************************************************************************** * IHTMLNamespaceCollection interface */
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmlevent.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-)
diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c index 149611174f0..a0b024fd65f 100644 --- a/dlls/mshtml/htmlevent.c +++ b/dlls/mshtml/htmlevent.c @@ -2790,6 +2790,15 @@ static DOMEvent *progress_event_ctor(void *iface, nsIDOMEvent *nsevent, eventid_ return &progress_event->event; }
+static DOMEvent *message_event_ctor(nsIDOMEvent *nsevent, eventid_t event_id, compat_mode_t compat_mode) +{ + DOMMessageEvent *message_event = event_ctor(sizeof(DOMMessageEvent), &DOMMessageEvent_dispex, + DOMMessageEvent_query_interface, DOMMessageEvent_destroy, nsevent, event_id, compat_mode); + if(!message_event) return NULL; + message_event->IDOMMessageEvent_iface.lpVtbl = &DOMMessageEventVtbl; + return &message_event->event; +} + static DOMEvent *alloc_event(nsIDOMEvent *nsevent, compat_mode_t compat_mode, eventid_t event_id) { static const struct { @@ -2805,14 +2814,8 @@ static DOMEvent *alloc_event(nsIDOMEvent *nsevent, compat_mode_t compat_mode, ev DOMEvent *event; unsigned i;
- if(event_id == EVENTID_MESSAGE) { - DOMMessageEvent *message_event = event_ctor(sizeof(DOMMessageEvent), &DOMMessageEvent_dispex, - DOMMessageEvent_query_interface, DOMMessageEvent_destroy, nsevent, event_id, compat_mode); - if(!message_event) - return NULL; - message_event->IDOMMessageEvent_iface.lpVtbl = &DOMMessageEventVtbl; - return &message_event->event; - } + if(event_id == EVENTID_MESSAGE) + return message_event_ctor(nsevent, event_id, compat_mode);
for(i = 0; i < ARRAY_SIZE(types_table); i++) { void *iface;
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmldoc.c | 24 ++-- dlls/mshtml/htmlevent.c | 225 ++++++++++++++++++++++++++++++++++- dlls/mshtml/htmlevent.h | 3 + dlls/mshtml/htmlstorage.c | 65 +++++++++- dlls/mshtml/htmlwindow.c | 2 +- dlls/mshtml/mshtml_private.h | 2 + 6 files changed, 309 insertions(+), 12 deletions(-)
diff --git a/dlls/mshtml/htmldoc.c b/dlls/mshtml/htmldoc.c index fe743e666c1..413a3a4054e 100644 --- a/dlls/mshtml/htmldoc.c +++ b/dlls/mshtml/htmldoc.c @@ -3423,30 +3423,38 @@ static HRESULT WINAPI HTMLDocument6_get_onstorage(IHTMLDocument6 *iface, VARIANT *p) { HTMLDocument *This = impl_from_IHTMLDocument6(iface); - FIXME("(%p)->(%p)\n", This, p); - return E_NOTIMPL; + + TRACE("(%p)->(%p)\n", This, p); + + return get_doc_event(This, EVENTID_STORAGE, p); }
static HRESULT WINAPI HTMLDocument6_put_onstorage(IHTMLDocument6 *iface, VARIANT v) { HTMLDocument *This = impl_from_IHTMLDocument6(iface); - FIXME("(%p)->(%s)\n", This, debugstr_variant(&v)); - return E_NOTIMPL; + + TRACE("(%p)->(%s)\n", This, debugstr_variant(&v)); + + return set_doc_event(This, EVENTID_STORAGE, &v); }
static HRESULT WINAPI HTMLDocument6_get_onstoragecommit(IHTMLDocument6 *iface, VARIANT *p) { HTMLDocument *This = impl_from_IHTMLDocument6(iface); - FIXME("(%p)->(%p)\n", This, p); - return E_NOTIMPL; + + TRACE("(%p)->(%p)\n", This, p); + + return get_doc_event(This, EVENTID_STORAGECOMMIT, p); }
static HRESULT WINAPI HTMLDocument6_put_onstoragecommit(IHTMLDocument6 *iface, VARIANT v) { HTMLDocument *This = impl_from_IHTMLDocument6(iface); - FIXME("(%p)->(%s)\n", This, debugstr_variant(&v)); - return E_NOTIMPL; + + TRACE("(%p)->(%s)\n", This, debugstr_variant(&v)); + + return set_doc_event(This, EVENTID_STORAGECOMMIT, &v); }
static HRESULT WINAPI HTMLDocument6_getElementById(IHTMLDocument6 *iface, diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c index a0b024fd65f..5502a1d041d 100644 --- a/dlls/mshtml/htmlevent.c +++ b/dlls/mshtml/htmlevent.c @@ -191,6 +191,10 @@ static const event_info_t event_info[] = { EVENT_FIXME}, {L"selectstart", EVENT_TYPE_EVENT, DISPID_EVMETH_ONSELECTSTART, EVENT_FIXME | EVENT_BUBBLES | EVENT_CANCELABLE}, + {L"storage", EVENT_TYPE_EVENT, DISPID_EVMETH_ONSTORAGE, + 0}, + {L"storagecommit", EVENT_TYPE_EVENT, DISPID_EVMETH_ONSTORAGECOMMIT, + 0}, {L"submit", EVENT_TYPE_EVENT, DISPID_EVMETH_ONSUBMIT, EVENT_DEFAULTLISTENER | EVENT_HASDEFAULTHANDLERS | EVENT_BUBBLES | EVENT_CANCELABLE}, {L"timeout", EVENT_TYPE_PROGRESS, DISPID_EVPROP_TIMEOUT, @@ -2606,6 +2610,164 @@ static void DOMProgressEvent_destroy(DOMEvent *event) nsIDOMProgressEvent_Release(This->nsevent); }
+typedef struct { + DOMEvent event; + IDOMStorageEvent IDOMStorageEvent_iface; + BSTR key; + BSTR old_value; + BSTR new_value; +} DOMStorageEvent; + +static inline DOMStorageEvent *impl_from_IDOMStorageEvent(IDOMStorageEvent *iface) +{ + return CONTAINING_RECORD(iface, DOMStorageEvent, IDOMStorageEvent_iface); +} + +static HRESULT WINAPI DOMStorageEvent_QueryInterface(IDOMStorageEvent *iface, REFIID riid, void **ppv) +{ + DOMStorageEvent *This = impl_from_IDOMStorageEvent(iface); + return IDOMEvent_QueryInterface(&This->event.IDOMEvent_iface, riid, ppv); +} + +static ULONG WINAPI DOMStorageEvent_AddRef(IDOMStorageEvent *iface) +{ + DOMStorageEvent *This = impl_from_IDOMStorageEvent(iface); + return IDOMEvent_AddRef(&This->event.IDOMEvent_iface); +} + +static ULONG WINAPI DOMStorageEvent_Release(IDOMStorageEvent *iface) +{ + DOMStorageEvent *This = impl_from_IDOMStorageEvent(iface); + return IDOMEvent_Release(&This->event.IDOMEvent_iface); +} + +static HRESULT WINAPI DOMStorageEvent_GetTypeInfoCount(IDOMStorageEvent *iface, UINT *pctinfo) +{ + DOMStorageEvent *This = impl_from_IDOMStorageEvent(iface); + return IDispatchEx_GetTypeInfoCount(&This->event.dispex.IDispatchEx_iface, pctinfo); +} + +static HRESULT WINAPI DOMStorageEvent_GetTypeInfo(IDOMStorageEvent *iface, UINT iTInfo, + LCID lcid, ITypeInfo **ppTInfo) +{ + DOMStorageEvent *This = impl_from_IDOMStorageEvent(iface); + return IDispatchEx_GetTypeInfo(&This->event.dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo); +} + +static HRESULT WINAPI DOMStorageEvent_GetIDsOfNames(IDOMStorageEvent *iface, REFIID riid, + LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId) +{ + DOMStorageEvent *This = impl_from_IDOMStorageEvent(iface); + return IDispatchEx_GetIDsOfNames(&This->event.dispex.IDispatchEx_iface, riid, rgszNames, cNames, + lcid, rgDispId); +} + +static HRESULT WINAPI DOMStorageEvent_Invoke(IDOMStorageEvent *iface, DISPID dispIdMember, + REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, + EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + DOMStorageEvent *This = impl_from_IDOMStorageEvent(iface); + return IDispatchEx_Invoke(&This->event.dispex.IDispatchEx_iface, dispIdMember, riid, lcid, + wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); +} + +static HRESULT WINAPI DOMStorageEvent_get_key(IDOMStorageEvent *iface, BSTR *p) +{ + DOMStorageEvent *This = impl_from_IDOMStorageEvent(iface); + + TRACE("(%p)->(%p)\n", This, p); + + if(This->key) + return (*p = SysAllocStringLen(This->key, SysStringLen(This->key))) ? S_OK : E_OUTOFMEMORY; + *p = NULL; + return S_OK; +} + +static HRESULT WINAPI DOMStorageEvent_get_oldValue(IDOMStorageEvent *iface, BSTR *p) +{ + DOMStorageEvent *This = impl_from_IDOMStorageEvent(iface); + + TRACE("(%p)->(%p)\n", This, p); + + if(This->old_value) + return (*p = SysAllocStringLen(This->old_value, SysStringLen(This->old_value))) ? S_OK : E_OUTOFMEMORY; + *p = NULL; + return S_OK; +} + +static HRESULT WINAPI DOMStorageEvent_get_newValue(IDOMStorageEvent *iface, BSTR *p) +{ + DOMStorageEvent *This = impl_from_IDOMStorageEvent(iface); + + TRACE("(%p)->(%p)\n", This, p); + + if(This->new_value) + return (*p = SysAllocStringLen(This->new_value, SysStringLen(This->new_value))) ? S_OK : E_OUTOFMEMORY; + *p = NULL; + return S_OK; +} + +static HRESULT WINAPI DOMStorageEvent_get_url(IDOMStorageEvent *iface, BSTR *p) +{ + DOMStorageEvent *This = impl_from_IDOMStorageEvent(iface); + FIXME("(%p)->(%p)\n", This, p); + return E_NOTIMPL; +} + +static HRESULT WINAPI DOMStorageEvent_get_storageArea(IDOMStorageEvent *iface, IHTMLStorage **p) +{ + DOMStorageEvent *This = impl_from_IDOMStorageEvent(iface); + FIXME("(%p)->(%p)\n", This, p); + return E_NOTIMPL; +} + +static HRESULT WINAPI DOMStorageEvent_initStorageEvent(IDOMStorageEvent *iface, BSTR type, VARIANT_BOOL can_bubble, + VARIANT_BOOL cancelable, BSTR keyArg, BSTR oldValueArg, + BSTR newValueArg, BSTR urlArg, IHTMLStorage *storageAreaArg) +{ + DOMStorageEvent *This = impl_from_IDOMStorageEvent(iface); + FIXME("(%p)->(%s %x %x %s %s %s %s %p)\n", This, debugstr_w(type), can_bubble, cancelable, + debugstr_w(keyArg), debugstr_w(oldValueArg), debugstr_w(newValueArg), debugstr_w(urlArg), storageAreaArg); + return E_NOTIMPL; +} + +static const IDOMStorageEventVtbl DOMStorageEventVtbl = { + DOMStorageEvent_QueryInterface, + DOMStorageEvent_AddRef, + DOMStorageEvent_Release, + DOMStorageEvent_GetTypeInfoCount, + DOMStorageEvent_GetTypeInfo, + DOMStorageEvent_GetIDsOfNames, + DOMStorageEvent_Invoke, + DOMStorageEvent_get_key, + DOMStorageEvent_get_oldValue, + DOMStorageEvent_get_newValue, + DOMStorageEvent_get_url, + DOMStorageEvent_get_storageArea, + DOMStorageEvent_initStorageEvent +}; + +static DOMStorageEvent *DOMStorageEvent_from_DOMEvent(DOMEvent *event) +{ + return CONTAINING_RECORD(event, DOMStorageEvent, event); +} + +static void *DOMStorageEvent_query_interface(DOMEvent *event, REFIID riid) +{ + DOMStorageEvent *storage_event = DOMStorageEvent_from_DOMEvent(event); + if(IsEqualGUID(&IID_IDOMStorageEvent, riid)) + return &storage_event->IDOMStorageEvent_iface; + return NULL; +} + +static void DOMStorageEvent_destroy(DOMEvent *event) +{ + DOMStorageEvent *storage_event = DOMStorageEvent_from_DOMEvent(event); + SysFreeString(storage_event->key); + SysFreeString(storage_event->old_value); + SysFreeString(storage_event->new_value); +} + static const tid_t DOMEvent_iface_tids[] = { IDOMEvent_tid, 0 @@ -2698,6 +2860,19 @@ dispex_static_data_t DOMProgressEvent_dispex = { DOMProgressEvent_iface_tids };
+static const tid_t DOMStorageEvent_iface_tids[] = { + IDOMEvent_tid, + IDOMStorageEvent_tid, + 0 +}; + +dispex_static_data_t DOMStorageEvent_dispex = { + L"StorageEvent", + NULL, + DispDOMStorageEvent_tid, + DOMStorageEvent_iface_tids +}; + static void *event_ctor(unsigned size, dispex_static_data_t *dispex_data, void *(*query_interface)(DOMEvent*,REFIID), void (*destroy)(DOMEvent*), nsIDOMEvent *nsevent, eventid_t event_id, compat_mode_t compat_mode) { @@ -2799,6 +2974,15 @@ static DOMEvent *message_event_ctor(nsIDOMEvent *nsevent, eventid_t event_id, co return &message_event->event; }
+static DOMEvent *storage_event_ctor(nsIDOMEvent *nsevent, eventid_t event_id, compat_mode_t compat_mode) +{ + DOMStorageEvent *storage_event = event_ctor(sizeof(DOMStorageEvent), &DOMStorageEvent_dispex, + DOMStorageEvent_query_interface, DOMStorageEvent_destroy, nsevent, event_id, compat_mode); + if(!storage_event) return NULL; + storage_event->IDOMStorageEvent_iface.lpVtbl = &DOMStorageEventVtbl; + return &storage_event->event; +} + static DOMEvent *alloc_event(nsIDOMEvent *nsevent, compat_mode_t compat_mode, eventid_t event_id) { static const struct { @@ -2814,8 +2998,12 @@ static DOMEvent *alloc_event(nsIDOMEvent *nsevent, compat_mode_t compat_mode, ev DOMEvent *event; unsigned i;
- if(event_id == EVENTID_MESSAGE) - return message_event_ctor(nsevent, event_id, compat_mode); + switch(event_id) { + case EVENTID_MESSAGE: return message_event_ctor(nsevent, event_id, compat_mode); + case EVENTID_STORAGECOMMIT: + case EVENTID_STORAGE: return storage_event_ctor(nsevent, event_id, compat_mode); + default: break; + }
for(i = 0; i < ARRAY_SIZE(types_table); i++) { void *iface; @@ -2931,6 +3119,39 @@ HRESULT create_message_event(HTMLDocumentNode *doc, VARIANT *data, DOMEvent **re return S_OK; }
+/* Takes ownership of old_value, do not free it on caller side! */ +HRESULT create_storage_event(HTMLDocumentNode *doc, BSTR key, BSTR old_value, BSTR new_value, + BOOL commit, DOMEvent **ret) +{ + DOMStorageEvent *storage_event; + DOMEvent *event; + HRESULT hres; + + hres = create_document_event(doc, commit ? EVENTID_STORAGECOMMIT : EVENTID_STORAGE, &event); + if(FAILED(hres)) { + SysFreeString(old_value); + return hres; + } + storage_event = DOMStorageEvent_from_DOMEvent(event); + + if(commit) + SysFreeString(old_value); + else { + storage_event->old_value = old_value; + if(key && !(storage_event->key = SysAllocString(key))) + goto fail; + if(new_value && !(storage_event->new_value = SysAllocString(new_value))) + goto fail; + } + + *ret = event; + return S_OK; + +fail: + IDOMEvent_Release(&event->IDOMEvent_iface); + return E_OUTOFMEMORY; +} + static HRESULT call_disp_func(IDispatch *disp, DISPPARAMS *dp, VARIANT *retv) { IDispatchEx *dispex; diff --git a/dlls/mshtml/htmlevent.h b/dlls/mshtml/htmlevent.h index ed11e660789..ee0c7831009 100644 --- a/dlls/mshtml/htmlevent.h +++ b/dlls/mshtml/htmlevent.h @@ -58,6 +58,8 @@ typedef enum { EVENTID_SCROLL, EVENTID_SELECTIONCHANGE, EVENTID_SELECTSTART, + EVENTID_STORAGE, + EVENTID_STORAGECOMMIT, EVENTID_SUBMIT, EVENTID_TIMEOUT, EVENTID_UNLOAD, @@ -112,6 +114,7 @@ HRESULT create_document_event(HTMLDocumentNode*,eventid_t,DOMEvent**) DECLSPEC_H 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*,VARIANT*,DOMEvent**) DECLSPEC_HIDDEN; +HRESULT create_storage_event(HTMLDocumentNode*,BSTR,BSTR,BSTR,BOOL,DOMEvent**) DECLSPEC_HIDDEN;
void init_nsevents(HTMLDocumentNode*) DECLSPEC_HIDDEN; void release_nsevents(HTMLDocumentNode*) DECLSPEC_HIDDEN; diff --git a/dlls/mshtml/htmlstorage.c b/dlls/mshtml/htmlstorage.c index 5d56037ff04..7956fb35367 100644 --- a/dlls/mshtml/htmlstorage.c +++ b/dlls/mshtml/htmlstorage.c @@ -29,6 +29,7 @@ #include "wine/debug.h"
#include "mshtml_private.h" +#include "htmlevent.h"
WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
@@ -41,6 +42,7 @@ typedef struct { LONG ref; unsigned num_props; BSTR *props; + HTMLInnerWindow *window; struct session_map_entry *session_storage; WCHAR *filename; HANDLE mutex; @@ -190,6 +192,60 @@ static void release_props(HTMLStorage *This) heap_free(This->props); }
+struct storage_event_task { + task_t header; + HTMLInnerWindow *window; + DOMEvent *event; +}; + +static void storage_event_proc(task_t *_task) +{ + struct storage_event_task *task = (struct storage_event_task*)_task; + HTMLInnerWindow *window = task->window; + DOMEvent *event = task->event; + VARIANT_BOOL cancelled; + + if(event->event_id == EVENTID_STORAGE) { + if(dispex_compat_mode(&window->event_target.dispex) >= COMPAT_MODE_IE9) + dispatch_event(&window->event_target, event); + if(window->doc) + fire_event(&window->doc->node, L"onstorage", NULL, &cancelled); + }else if(window->doc) { + dispatch_event(&window->doc->node.event_target, event); + } +} + +static void storage_event_destr(task_t *_task) +{ + struct storage_event_task *task = (struct storage_event_task*)_task; + IDOMEvent_Release(&task->event->IDOMEvent_iface); + IHTMLWindow2_Release(&task->window->base.IHTMLWindow2_iface); +} + +/* Takes ownership of old_value */ +static HRESULT send_storage_event(HTMLStorage *storage, BSTR key, BSTR old_value, BSTR new_value) +{ + HTMLInnerWindow *window = storage->window; + BOOL local = !!storage->filename; + struct storage_event_task *task; + DOMEvent *event; + HRESULT hres; + + hres = create_storage_event(window->doc, key, old_value, new_value, local, &event); + if(FAILED(hres)) + return hres; + + 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, storage_event_proc, storage_event_destr, window->task_magic); +} + static inline HTMLStorage *impl_from_IHTMLStorage(IHTMLStorage *iface) { return CONTAINING_RECORD(iface, HTMLStorage, IHTMLStorage_iface); @@ -235,6 +291,7 @@ static ULONG WINAPI HTMLStorage_Release(IHTMLStorage *iface) TRACE("(%p) ref=%ld\n", This, ref);
if(!ref) { + IHTMLWindow2_Release(&This->window->base.IHTMLWindow2_iface); release_session_map_entry(This->session_storage); release_dispex(&This->dispex); heap_free(This->filename); @@ -817,8 +874,9 @@ static HRESULT WINAPI HTMLStorage_clear(IHTMLStorage *iface) HRESULT hres = S_OK;
if(!This->filename) { + UINT num_keys = This->session_storage->num_keys; clear_session_storage(This->session_storage); - return S_OK; + return num_keys ? send_storage_event(This, NULL, NULL, NULL) : S_OK; }
WaitForSingleObject(This->mutex, INFINITE); @@ -828,6 +886,8 @@ static HRESULT WINAPI HTMLStorage_clear(IHTMLStorage *iface) hres = HRESULT_FROM_WIN32(error); } ReleaseMutex(This->mutex); + if(hres == S_OK) + hres = send_storage_event(This, NULL, NULL, NULL); return hres; }
@@ -1266,6 +1326,9 @@ HRESULT create_html_storage(HTMLInnerWindow *window, BOOL local, IHTMLStorage **
storage->IHTMLStorage_iface.lpVtbl = &HTMLStorageVtbl; storage->ref = 1; + storage->window = window; + IHTMLWindow2_AddRef(&window->base.IHTMLWindow2_iface); + init_dispatch(&storage->dispex, (IUnknown*)&storage->IHTMLStorage_iface, &HTMLStorage_dispex, dispex_compat_mode(&window->event_target.dispex));
diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index 00eef4d846a..d9941677c47 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -2613,7 +2613,7 @@ HTMLWINDOW7_ONEVENT_PROPERTY_STUB(seeked) HTMLWINDOW7_ONEVENT_PROPERTY_STUB(seeking) HTMLWINDOW7_ONEVENT_PROPERTY_STUB(select) HTMLWINDOW7_ONEVENT_PROPERTY_STUB(stalled) -HTMLWINDOW7_ONEVENT_PROPERTY_STUB(storage) +HTMLWINDOW7_ONEVENT_PROPERTY_IMPL(storage, EVENTID_STORAGE) HTMLWINDOW7_ONEVENT_PROPERTY_IMPL(submit, EVENTID_SUBMIT) HTMLWINDOW7_ONEVENT_PROPERTY_STUB(suspend) HTMLWINDOW7_ONEVENT_PROPERTY_STUB(timeupdate) diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 85f34bb4a9f..59a830f484a 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -91,6 +91,7 @@ typedef struct EventTarget EventTarget; XDIID(DispDOMMessageEvent) \ XDIID(DispDOMMouseEvent) \ XDIID(DispDOMProgressEvent) \ + XDIID(DispDOMStorageEvent) \ XDIID(DispDOMUIEvent) \ XDIID(DispDOMDocumentType) \ XDIID(DispHTMLAnchorElement) \ @@ -154,6 +155,7 @@ typedef struct EventTarget EventTarget; XIID(IDOMMessageEvent) \ XIID(IDOMMouseEvent) \ XIID(IDOMProgressEvent) \ + XIID(IDOMStorageEvent) \ XIID(IDOMUIEvent) \ XIID(IDOMDocumentType) \ XIID(IDocumentEvent) \
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmlstorage.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-)
diff --git a/dlls/mshtml/htmlstorage.c b/dlls/mshtml/htmlstorage.c index 7956fb35367..fa1e773bf71 100644 --- a/dlls/mshtml/htmlstorage.c +++ b/dlls/mshtml/htmlstorage.c @@ -698,7 +698,7 @@ static HRESULT save_document(IXMLDOMDocument *doc, const WCHAR *filename) return hres; }
-static HRESULT set_item(const WCHAR *filename, BSTR key, BSTR value) +static HRESULT set_item(const WCHAR *filename, BSTR key, BSTR value, BSTR *old_value) { IXMLDOMDocument *doc; IXMLDOMNode *root = NULL, *node = NULL; @@ -706,6 +706,7 @@ static HRESULT set_item(const WCHAR *filename, BSTR key, BSTR value) BSTR query = NULL; HRESULT hres;
+ *old_value = NULL; hres = open_document(filename, &doc); if(hres != S_OK) return hres; @@ -722,10 +723,20 @@ static HRESULT set_item(const WCHAR *filename, BSTR key, BSTR value)
hres = IXMLDOMNode_selectSingleNode(root, query, &node); if(hres == S_OK) { + VARIANT old; + hres = IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMElement, (void**)&elem); if(hres != S_OK) goto done;
+ hres = IXMLDOMElement_getAttribute(elem, (BSTR)L"value", &old); + if(hres == S_OK) { + if(V_VT(&old) == VT_BSTR) + *old_value = V_BSTR(&old); + else + VariantClear(&old); + } + hres = set_attribute(elem, L"value", value); if(hres != S_OK) goto done; @@ -760,6 +771,8 @@ done: if(elem) IXMLDOMElement_Release(elem); IXMLDOMDocument_Release(doc); + if(hres != S_OK) + SysFreeString(*old_value); return hres; }
@@ -767,6 +780,7 @@ static HRESULT WINAPI HTMLStorage_setItem(IHTMLStorage *iface, BSTR bstrKey, BST { HTMLStorage *This = impl_from_IHTMLStorage(iface); struct session_entry *session_entry; + BSTR old_value; HRESULT hres;
TRACE("(%p)->(%s %s)\n", This, debugstr_w(bstrKey), debugstr_w(bstrValue)); @@ -787,16 +801,20 @@ static HRESULT WINAPI HTMLStorage_setItem(IHTMLStorage *iface, BSTR bstrKey, BST return E_OUTOFMEMORY; /* native returns this when quota is exceeded */ } This->session_storage->quota -= value_len - old_len; - SysFreeString(session_entry->value); + old_value = session_entry->value; session_entry->value = value; + + hres = send_storage_event(This, bstrKey, old_value, value); } return hres; }
WaitForSingleObject(This->mutex, INFINITE); - hres = set_item(This->filename, bstrKey, bstrValue); + hres = set_item(This->filename, bstrKey, bstrValue, &old_value); ReleaseMutex(This->mutex);
+ if(hres == S_OK) + hres = send_storage_event(This, bstrKey, old_value, bstrValue); return hres; }
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmlstorage.c | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-)
diff --git a/dlls/mshtml/htmlstorage.c b/dlls/mshtml/htmlstorage.c index fa1e773bf71..2b8aa0a295f 100644 --- a/dlls/mshtml/htmlstorage.c +++ b/dlls/mshtml/htmlstorage.c @@ -818,13 +818,15 @@ static HRESULT WINAPI HTMLStorage_setItem(IHTMLStorage *iface, BSTR bstrKey, BST return hres; }
-static HRESULT remove_item(const WCHAR *filename, BSTR key) +static HRESULT remove_item(const WCHAR *filename, BSTR key, BSTR *old_value, BOOL *changed) { IXMLDOMDocument *doc; IXMLDOMNode *root = NULL, *node = NULL; BSTR query = NULL; HRESULT hres;
+ *old_value = NULL; + *changed = FALSE; hres = open_document(filename, &doc); if(hres != S_OK) return hres; @@ -841,6 +843,22 @@ static HRESULT remove_item(const WCHAR *filename, BSTR key)
hres = IXMLDOMNode_selectSingleNode(root, query, &node); if(hres == S_OK) { + IXMLDOMElement *elem; + VARIANT old; + + hres = IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMElement, (void**)&elem); + if(hres == S_OK) { + hres = IXMLDOMElement_getAttribute(elem, (BSTR)L"value", &old); + if(hres == S_OK) { + if(V_VT(&old) == VT_BSTR) + *old_value = V_BSTR(&old); + else + VariantClear(&old); + } + IXMLDOMElement_Release(elem); + *changed = TRUE; + } + hres = IXMLDOMNode_removeChild(root, node, NULL); if(hres != S_OK) goto done; @@ -855,6 +873,8 @@ done: if(node) IXMLDOMNode_Release(node); IXMLDOMDocument_Release(doc); + if(hres != S_OK || !changed) + SysFreeString(*old_value); return hres; }
@@ -862,7 +882,9 @@ static HRESULT WINAPI HTMLStorage_removeItem(IHTMLStorage *iface, BSTR bstrKey) { HTMLStorage *This = impl_from_IHTMLStorage(iface); struct session_entry *session_entry; + BSTR old_value; HRESULT hres; + BOOL changed;
TRACE("(%p)->(%s)\n", This, debugstr_w(bstrKey));
@@ -873,16 +895,20 @@ static HRESULT WINAPI HTMLStorage_removeItem(IHTMLStorage *iface, BSTR bstrKey) This->session_storage->num_keys--; list_remove(&session_entry->list_entry); wine_rb_remove(&This->session_storage->data_map, &session_entry->entry); - SysFreeString(session_entry->value); + old_value = session_entry->value; heap_free(session_entry); + + hres = send_storage_event(This, bstrKey, old_value, NULL); } return hres; }
WaitForSingleObject(This->mutex, INFINITE); - hres = remove_item(This->filename, bstrKey); + hres = remove_item(This->filename, bstrKey, &old_value, &changed); ReleaseMutex(This->mutex);
+ if(hres == S_OK && changed) + hres = send_storage_event(This, bstrKey, old_value, NULL); return hres; }
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/tests/misc.c | 410 ++++++++++++++++++++++++++++++- dlls/mshtml/tests/script.c | 478 ++++++++++++++++++++++++++++++++++++- 2 files changed, 879 insertions(+), 9 deletions(-)
diff --git a/dlls/mshtml/tests/misc.c b/dlls/mshtml/tests/misc.c index 5f38f9d45fb..e7119a3520f 100644 --- a/dlls/mshtml/tests/misc.c +++ b/dlls/mshtml/tests/misc.c @@ -28,6 +28,218 @@ #include "initguid.h" #include "optary.h"
+#define DEFINE_EXPECT(func) \ + static BOOL expect_ ## func = FALSE, called_ ## func = FALSE + +#define SET_EXPECT(func) \ + do { called_ ## func = FALSE; expect_ ## func = TRUE; } while(0) + +#define CHECK_EXPECT2(func) \ + do { \ + ok(expect_ ##func, "unexpected call " #func "\n"); \ + called_ ## func = TRUE; \ + }while(0) + +#define CHECK_EXPECT(func) \ + do { \ + CHECK_EXPECT2(func); \ + expect_ ## func = FALSE; \ + }while(0) + +#define CLEAR_CALLED(func) \ + expect_ ## func = called_ ## func = FALSE + +DEFINE_EXPECT(doc_onstorage); +DEFINE_EXPECT(doc2_onstorage); + +#define test_disp(u,id) _test_disp(__LINE__,u,id) +static void _test_disp(unsigned line, IUnknown *unk, const IID *iid) +{ + IDispatchEx *dispex; + ITypeInfo *typeinfo; + HRESULT hres; + UINT ticnt; + + hres = IUnknown_QueryInterface(unk, &IID_IDispatchEx, (void**)&dispex); + ok_(__FILE__,line)(hres == S_OK, "Could not get IDispatch: %08lx\n", hres); + if(FAILED(hres)) + return; + + ticnt = 0xdeadbeef; + hres = IDispatchEx_GetTypeInfoCount(dispex, &ticnt); + ok_(__FILE__,line)(hres == S_OK, "GetTypeInfoCount failed: %08lx\n", hres); + ok_(__FILE__,line)(ticnt == 1, "ticnt=%u\n", ticnt); + + hres = IDispatchEx_GetTypeInfo(dispex, 0, 0, &typeinfo); + ok_(__FILE__,line)(hres == S_OK, "GetTypeInfo failed: %08lx\n", hres); + + if(SUCCEEDED(hres)) { + TYPEATTR *type_attr; + + hres = ITypeInfo_GetTypeAttr(typeinfo, &type_attr); + ok_(__FILE__,line)(hres == S_OK, "GetTypeAttr failed: %08lx\n", hres); + ok_(__FILE__,line)(IsEqualGUID(&type_attr->guid, iid), + "unexpected guid %s\n", wine_dbgstr_guid(&type_attr->guid)); + + ITypeInfo_ReleaseTypeAttr(typeinfo, type_attr); + ITypeInfo_Release(typeinfo); + } + + IDispatchEx_Release(dispex); +} + +#define test_event_args(a,b,c,d,e,f,g) _test_event_args(__LINE__,a,b,c,d,e,f,g) +static void _test_event_args(unsigned line, const IID *iid, DISPID id, WORD wFlags, DISPPARAMS *pdp, + VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) +{ + ok_(__FILE__,line)(id == DISPID_VALUE, "id = %ld\n", id); + ok_(__FILE__,line)(wFlags == DISPATCH_METHOD, "wFlags = %x\n", wFlags); + ok_(__FILE__,line)(pdp != NULL, "pdp == NULL\n"); + ok_(__FILE__,line)(pdp->cArgs == 1, "pdp->cArgs = %d\n", pdp->cArgs); + ok_(__FILE__,line)(pdp->cNamedArgs == 1, "pdp->cNamedArgs = %d\n", pdp->cNamedArgs); + ok_(__FILE__,line)(pdp->rgdispidNamedArgs[0] == DISPID_THIS, "pdp->rgdispidNamedArgs[0] = %ld\n", + pdp->rgdispidNamedArgs[0]); + ok_(__FILE__,line)(V_VT(pdp->rgvarg) == VT_DISPATCH, "V_VT(rgvarg) = %d\n", V_VT(pdp->rgvarg)); + ok_(__FILE__,line)(pvarRes != NULL, "pvarRes == NULL\n"); + ok_(__FILE__,line)(pei != NULL, "pei == NULL\n"); + ok_(__FILE__,line)(!pspCaller, "pspCaller != NULL\n"); + + if(iid) + _test_disp(line, (IUnknown*)V_DISPATCH(pdp->rgvarg), iid); +} + +static void pump_msgs(BOOL *b) +{ + MSG msg; + + if(b) { + while(!*b && GetMessageW(&msg, NULL, 0, 0)) { + TranslateMessage(&msg); + DispatchMessageW(&msg); + } + }else { + while(PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) { + TranslateMessage(&msg); + DispatchMessageW(&msg); + } + } +} + +static HRESULT WINAPI DispatchEx_QueryInterface(IDispatchEx *iface, REFIID riid, void **ppv) +{ + if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IDispatch) || IsEqualGUID(riid, &IID_IDispatchEx)) { + *ppv = iface; + }else { + *ppv = NULL; + return E_NOINTERFACE; + } + return S_OK; +} + +static ULONG WINAPI DispatchEx_AddRef(IDispatchEx *iface) +{ + return 2; +} + +static ULONG WINAPI DispatchEx_Release(IDispatchEx *iface) +{ + return 1; +} + +static HRESULT WINAPI DispatchEx_GetTypeInfoCount(IDispatchEx *iface, UINT *pctinfo) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DispatchEx_GetTypeInfo(IDispatchEx *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DispatchEx_GetIDsOfNames(IDispatchEx *iface, REFIID riid, + LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DispatchEx_Invoke(IDispatchEx *iface, DISPID dispIdMember, REFIID riid, LCID lcid, + WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DispatchEx_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, + DISPPARAMS *pdp, VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DispatchEx_DeleteMemberByName(IDispatchEx *iface, BSTR bstrName, DWORD grfdex) +{ + ok(0, "unexpected call %s %lx\n", wine_dbgstr_w(bstrName), grfdex); + return E_NOTIMPL; +} + +static HRESULT WINAPI DispatchEx_DeleteMemberByDispID(IDispatchEx *iface, DISPID id) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DispatchEx_GetMemberProperties(IDispatchEx *iface, DISPID id, DWORD grfdexFetch, DWORD *pgrfdex) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DispatchEx_GetMemberName(IDispatchEx *iface, DISPID id, BSTR *pbstrName) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DispatchEx_GetNextDispID(IDispatchEx *iface, DWORD grfdex, DISPID id, DISPID *pid) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DispatchEx_GetNameSpaceParent(IDispatchEx *iface, IUnknown **ppunk) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static const IDispatchExVtbl DispatchEx_vtbl = { + DispatchEx_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 DispatchEx_obj = { &DispatchEx_vtbl }; + static void test_HTMLLoadOptions(void) { IHtmlLoadOptions *loadopts; @@ -193,6 +405,165 @@ static HRESULT get_sessionstorage(IHTMLDocument2 *doc, IHTMLStorage **storage) return hres; }
+static void set_onstorage_handlers(IHTMLDocument2 *doc, IDispatchEx *doc_handler, IDispatchEx *window_handler, BOOL local) +{ + IHTMLWindow7 *window7; + IHTMLWindow2 *window; + IHTMLDocument6 *doc6; + HRESULT hres; + VARIANT var; + + hres = IHTMLDocument2_QueryInterface(doc, &IID_IHTMLDocument6, (void**)&doc6); + if(FAILED(hres)) + win_skip("IHTMLDocument6 not supported\n"); + else { + V_VT(&var) = doc_handler ? VT_DISPATCH : VT_NULL; + V_DISPATCH(&var) = (IDispatch*)doc_handler; + if(local) { + hres = IHTMLDocument6_put_onstoragecommit(doc6, var); + ok(hres == S_OK, "put_onstoragecommit failed: %08lx\n", hres); + V_DISPATCH(&var) = (IDispatch*)&DispatchEx_obj; + } + hres = IHTMLDocument6_put_onstorage(doc6, var); + ok(hres == S_OK, "put_onstorage failed: %08lx\n", hres); + IHTMLDocument6_Release(doc6); + } + + hres = IHTMLDocument2_get_parentWindow(doc, &window); + ok(hres == S_OK, "get_parentWindow failed: %08lx\n", hres); + ok(window != NULL, "window == NULL\n"); + + hres = IHTMLWindow2_QueryInterface(window, &IID_IHTMLWindow7, (void**)&window7); + IHTMLWindow2_Release(window); + if(FAILED(hres)) + win_skip("IHTMLWindow7 not supported\n"); + else { + V_VT(&var) = window_handler ? VT_DISPATCH : VT_NULL; + V_DISPATCH(&var) = (IDispatch*)window_handler; + hres = IHTMLWindow7_put_onstorage(window7, var); + ok(hres == S_OK, "put_onstorage failed: %08lx\n", hres); + IHTMLWindow7_Release(window7); + } +} + +#define check_onstorage(doc) _check_onstorage(&expect_##doc##_onstorage,&called_##doc##_onstorage,__LINE__) +static void _check_onstorage(BOOL *expect, BOOL *called, unsigned line) +{ + /* Native quirks modes only call onstorage on the document, + but not the window, that did the change for some reason. + For localStorage, onstoragecommit is called instead. */ + *expect = TRUE; *called = FALSE; + pump_msgs(called); + CLEAR_CALLED(doc_onstorage); + CLEAR_CALLED(doc2_onstorage); +} + +static HRESULT WINAPI doc_onstorage_func(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, + VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) +{ + test_event_args(&DIID_DispHTMLDocument, id, wFlags, pdp, pvarRes, pei, pspCaller); + CHECK_EXPECT(doc_onstorage); + return S_OK; +} + +static const IDispatchExVtbl doc_onstorage_vtbl = { + DispatchEx_QueryInterface, + DispatchEx_AddRef, + DispatchEx_Release, + DispatchEx_GetTypeInfoCount, + DispatchEx_GetTypeInfo, + DispatchEx_GetIDsOfNames, + DispatchEx_Invoke, + DispatchEx_GetDispID, + doc_onstorage_func, + DispatchEx_DeleteMemberByName, + DispatchEx_DeleteMemberByDispID, + DispatchEx_GetMemberProperties, + DispatchEx_GetMemberName, + DispatchEx_GetNextDispID, + DispatchEx_GetNameSpaceParent +}; +static IDispatchEx doc_onstorage = { &doc_onstorage_vtbl }; + +static HRESULT WINAPI doc_window_onstorage_func(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, + VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) +{ + ok(0, "unexpected call\n"); + return S_OK; +} + +static const IDispatchExVtbl doc_window_onstorage_vtbl = { + DispatchEx_QueryInterface, + DispatchEx_AddRef, + DispatchEx_Release, + DispatchEx_GetTypeInfoCount, + DispatchEx_GetTypeInfo, + DispatchEx_GetIDsOfNames, + DispatchEx_Invoke, + DispatchEx_GetDispID, + doc_window_onstorage_func, + DispatchEx_DeleteMemberByName, + DispatchEx_DeleteMemberByDispID, + DispatchEx_GetMemberProperties, + DispatchEx_GetMemberName, + DispatchEx_GetNextDispID, + DispatchEx_GetNameSpaceParent +}; +static IDispatchEx doc_window_onstorage = { &doc_window_onstorage_vtbl }; + +static HRESULT WINAPI doc2_onstorage_func(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, + VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) +{ + test_event_args(&DIID_DispHTMLDocument, id, wFlags, pdp, pvarRes, pei, pspCaller); + CHECK_EXPECT(doc2_onstorage); + return S_OK; +} + +static const IDispatchExVtbl doc2_onstorage_vtbl = { + DispatchEx_QueryInterface, + DispatchEx_AddRef, + DispatchEx_Release, + DispatchEx_GetTypeInfoCount, + DispatchEx_GetTypeInfo, + DispatchEx_GetIDsOfNames, + DispatchEx_Invoke, + DispatchEx_GetDispID, + doc2_onstorage_func, + DispatchEx_DeleteMemberByName, + DispatchEx_DeleteMemberByDispID, + DispatchEx_GetMemberProperties, + DispatchEx_GetMemberName, + DispatchEx_GetNextDispID, + DispatchEx_GetNameSpaceParent +}; +static IDispatchEx doc2_onstorage = { &doc2_onstorage_vtbl }; + +static HRESULT WINAPI doc2_window_onstorage_func(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, + VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) +{ + ok(0, "unexpected call\n"); + return S_OK; +} + +static const IDispatchExVtbl doc2_window_onstorage_vtbl = { + DispatchEx_QueryInterface, + DispatchEx_AddRef, + DispatchEx_Release, + DispatchEx_GetTypeInfoCount, + DispatchEx_GetTypeInfo, + DispatchEx_GetIDsOfNames, + DispatchEx_Invoke, + DispatchEx_GetDispID, + doc2_window_onstorage_func, + DispatchEx_DeleteMemberByName, + DispatchEx_DeleteMemberByDispID, + DispatchEx_GetMemberProperties, + DispatchEx_GetMemberName, + DispatchEx_GetNextDispID, + DispatchEx_GetNameSpaceParent +}; +static IDispatchEx doc2_window_onstorage = { &doc2_window_onstorage_vtbl }; + static void test_HTMLStorage(void) { IHTMLDocument2 *doc, *doc2; @@ -211,6 +582,9 @@ static void test_HTMLStorage(void) hres = get_localstorage(doc2, &storage2); ok(hres == S_OK, "got %08lx\n", hres);
+ set_onstorage_handlers(doc, &doc_onstorage, &doc_window_onstorage, TRUE); + set_onstorage_handlers(doc2, &doc2_onstorage, &doc2_window_onstorage, TRUE); + key = SysAllocString(L""); V_VT(&var) = 0xdead; hres = IHTMLStorage_getItem(storage, key, &var); @@ -225,9 +599,16 @@ static void test_HTMLStorage(void) ok(hres == S_OK, "get_length failed %08lx\n", hres); ok(length >= 0, "length = %ld\n", length);
- value = SysAllocString(L"null"); + value = SysAllocString(L"NULL"); hres = IHTMLStorage_setItem(storage, key, value); ok(hres == S_OK, "setItem failed: %08lx\n", hres); + SysFreeString(value); + check_onstorage(doc); + + value = SysAllocString(L"null"); + hres = IHTMLStorage_setItem(storage2, key, value); + ok(hres == S_OK, "setItem failed: %08lx\n", hres); + check_onstorage(doc2);
V_VT(&var) = 0xdead; hres = IHTMLStorage_getItem(storage, key, &var); @@ -251,11 +632,17 @@ static void test_HTMLStorage(void) ok(hres == S_OK, "removeItem failed: %08lx\n", hres); SysFreeString(key); SysFreeString(value); + check_onstorage(doc);
key = SysAllocString(L"winetest"); value = SysAllocString(L"winetest"); hres = IHTMLStorage_setItem(storage, key, value); ok(hres == S_OK, "setItem failed: %08lx\n", hres); + check_onstorage(doc); + + set_onstorage_handlers(doc, NULL, NULL, TRUE); + set_onstorage_handlers(doc2, NULL, NULL, TRUE); + pump_msgs(NULL);
/* retrieve value from different storage instance */ V_VT(&var) = 0xdead; @@ -342,6 +729,9 @@ static void test_HTMLStorage(void) hres = get_sessionstorage(doc2, &storage2); ok(hres == S_OK, "got %08lx\n", hres);
+ set_onstorage_handlers(doc, &doc_onstorage, &doc_window_onstorage, FALSE); + set_onstorage_handlers(doc2, &doc2_onstorage, &doc2_window_onstorage, FALSE); + hres = IHTMLStorage_get_length(storage, &lval); ok(hres == S_OK, "get_length failed %08lx\n", hres); ok(lval == 0, "length = %ld\n", lval); @@ -361,10 +751,17 @@ static void test_HTMLStorage(void) hres = IHTMLStorage_removeItem(storage, key); ok(hres == S_OK, "removeItem failed: %08lx\n", hres);
- value = SysAllocString(L"null"); + value = SysAllocString(L"NULL"); hres = IHTMLStorage_setItem(storage, key, value); ok(hres == S_OK, "setItem failed: %08lx\n", hres); SysFreeString(value); + check_onstorage(doc); + + value = SysAllocString(L"null"); + hres = IHTMLStorage_setItem(storage2, key, value); + ok(hres == S_OK, "setItem failed: %08lx\n", hres); + SysFreeString(value); + check_onstorage(doc2);
hres = IHTMLStorage_get_length(storage, &lval); ok(hres == S_OK, "get_length failed %08lx\n", hres); @@ -399,6 +796,7 @@ static void test_HTMLStorage(void) hres = IHTMLStorage_setItem(storage, NULL, value); ok(hres == S_OK, "setItem failed: %08lx\n", hres); SysFreeString(value); + check_onstorage(doc);
V_VT(&var) = 0xdead; hres = IHTMLStorage_getItem(storage2, NULL, &var); @@ -419,6 +817,7 @@ static void test_HTMLStorage(void) key = SysAllocString(L"null-value"); hres = IHTMLStorage_setItem(storage, key, NULL); ok(hres == S_OK, "setItem failed: %08lx\n", hres); + check_onstorage(doc);
V_VT(&var) = 0xdead; hres = IHTMLStorage_getItem(storage2, key, &var); @@ -429,9 +828,16 @@ static void test_HTMLStorage(void)
hres = IHTMLStorage_removeItem(storage, NULL); ok(hres == S_OK, "removeItem failed: %08lx\n", hres); + check_onstorage(doc); + hres = IHTMLStorage_removeItem(storage2, key); ok(hres == S_OK, "removeItem failed: %08lx\n", hres); SysFreeString(key); + check_onstorage(doc2); + + set_onstorage_handlers(doc, NULL, NULL, FALSE); + set_onstorage_handlers(doc2, NULL, NULL, FALSE); + pump_msgs(NULL);
key = SysAllocString(L"aaaa"); value = SysAllocString(L"bbbb"); diff --git a/dlls/mshtml/tests/script.c b/dlls/mshtml/tests/script.c index 14e3a148239..80f34a6606e 100644 --- a/dlls/mshtml/tests/script.c +++ b/dlls/mshtml/tests/script.c @@ -62,7 +62,7 @@ const GUID GUID_CUSTOM_CONFIRMOBJECTSAFETY = #endif
#define DEFINE_EXPECT(func) \ - static BOOL expect_ ## func = FALSE, called_ ## func = FALSE + static BOOL expect_ ## func, called_ ## func
#define SET_EXPECT(func) \ do { called_ ## func = FALSE; expect_ ## func = TRUE; } while(0) @@ -137,6 +137,9 @@ DEFINE_EXPECT(QS_IActiveScriptSite); DEFINE_EXPECT(QS_GetCaller); DEFINE_EXPECT(ChangeType); DEFINE_EXPECT(GetTypeInfo); +DEFINE_EXPECT(doc_onstorage[2]); +DEFINE_EXPECT(doc_onstoragecommit[2]); +DEFINE_EXPECT(window_onstorage[2]);
#define TESTSCRIPT_CLSID "{178fc163-f585-4e24-9c13-4bb7faf80746}" #define TESTACTIVEX_CLSID "{178fc163-f585-4e24-9c13-4bb7faf80646}" @@ -3737,7 +3740,7 @@ static void test_simple_script(void) CHECK_CALLED(Close); }
-static void run_from_moniker(IMoniker *mon) +static void run_from_moniker(IMoniker *mon, IHTMLDocument2 **ret_doc) { IPersistMoniker *persist; IHTMLDocument2 *doc; @@ -3768,6 +3771,11 @@ static void run_from_moniker(IMoniker *mon)
CHECK_CALLED(external_success);
+ if(ret_doc) { + *ret_doc = doc; + return; + } + free_registered_streams(); set_client_site(doc, FALSE); IHTMLDocument2_Release(doc); @@ -3788,12 +3796,12 @@ static void run_js_script(const char *test_name)
hres = CreateURLMoniker(NULL, url, &mon); ok(hres == S_OK, "CreateURLMoniker failed: %08lx\n", hres); - run_from_moniker(mon); + run_from_moniker(mon, NULL);
IMoniker_Release(mon); }
-static void run_from_path(const WCHAR *path, const char *opt) +static void run_from_path(const WCHAR *path, const char *opt, IHTMLDocument2 **doc) { WCHAR buf[255] = L"http://winetest.example.org"; IMoniker *mon; @@ -3808,11 +3816,462 @@ static void run_from_path(const WCHAR *path, const char *opt) SysFreeString(url); ok(hres == S_OK, "CreateUrlMoniker failed: %08lx\n", hres);
- run_from_moniker(mon); + run_from_moniker(mon, doc);
IMoniker_Release(mon); }
+static unsigned onstorage_expect_line, onstorage_expect_document_mode; +static const WCHAR *onstorage_expect_key, *onstorage_expect_old_value, *onstorage_expect_new_value; + +#define check_local_onstorage(a,b,c,d) _check_onstorage(a,b,c,d,TRUE,document_mode,__LINE__) +#define check_session_onstorage(a,b,c,d) _check_onstorage(a,b,c,d,FALSE,document_mode,__LINE__) +static void _check_onstorage(unsigned idx, const WCHAR *key, const WCHAR *old_value, + const WCHAR *new_value, BOOL local, unsigned document_mode, unsigned line) +{ + BOOL *const *expect, *const *called; + MSG msg; + + onstorage_expect_line = line; + onstorage_expect_document_mode = document_mode; + onstorage_expect_key = key; + onstorage_expect_old_value = old_value; + onstorage_expect_new_value = new_value; + + if(local) { + static BOOL *const _expect[] = { expect_doc_onstoragecommit, NULL }; + static BOOL *const _called[] = { called_doc_onstoragecommit, NULL }; + expect = _expect, called = _called; + }else { + if(document_mode < 9) { + static BOOL *const _expect[] = { expect_doc_onstorage, NULL }; + static BOOL *const _called[] = { called_doc_onstorage, NULL }; + expect = _expect, called = _called; + }else { + static BOOL *const _expect[] = { expect_window_onstorage, expect_doc_onstorage, NULL }; + static BOOL *const _called[] = { called_window_onstorage, called_doc_onstorage, NULL }; + expect = _expect, called = _called; + } + } + + (*expect)[idx] = TRUE, (*called)[idx] = FALSE; + do { + while(!(*called)[idx] && GetMessageW(&msg, NULL, 0, 0)) { + TranslateMessage(&msg); + DispatchMessageW(&msg); + } + } while(*++expect && *++called); + CLEAR_CALLED(doc_onstorage[0]); + CLEAR_CALLED(doc_onstoragecommit[0]); + CLEAR_CALLED(window_onstorage[0]); + CLEAR_CALLED(doc_onstorage[1]); + CLEAR_CALLED(doc_onstoragecommit[1]); + CLEAR_CALLED(window_onstorage[1]); +} + +static void test_storage_event(DISPPARAMS *params, BOOL commit) +{ + const WCHAR *expect_key = onstorage_expect_key, *expect_old_value = onstorage_expect_old_value, *expect_new_value = onstorage_expect_new_value; + unsigned line = onstorage_expect_line; + BOOL doc_onstorage = TRUE; + IHTMLEventObj *event_obj; + IDOMStorageEvent *event; + IHTMLWindow2 *window; + IDispatchEx *dispex; + HRESULT hres; + unsigned i; + DISPID id; + BSTR bstr; + + if(onstorage_expect_document_mode < 9) { + ok_(__FILE__,line)(params->cArgs == 1, "cArgs = %u\n", params->cArgs); + ok_(__FILE__,line)(V_VT(¶ms->rgvarg[0]) == VT_DISPATCH, "V_VT(this) = %d\n", V_VT(¶ms->rgvarg[0])); + return; + } + + if(commit) { + expect_key = NULL; + expect_old_value = NULL; + expect_new_value = NULL; + doc_onstorage = FALSE; + } + + ok_(__FILE__,line)(params->cArgs == 2, "cArgs = %u\n", params->cArgs); + ok_(__FILE__,line)(V_VT(¶ms->rgvarg[1]) == VT_DISPATCH, "V_VT(event) = %d\n", V_VT(¶ms->rgvarg[1])); + hres = IDispatch_QueryInterface(V_DISPATCH(¶ms->rgvarg[1]), &IID_IDispatchEx, (void**)&dispex); + ok_(__FILE__,line)(hres == S_OK, "Could not get IDispatchEx: %08lx\n", hres); + + hres = IDispatch_QueryInterface(V_DISPATCH(¶ms->rgvarg[0]), &IID_IHTMLWindow2, (void**)&window); + if(hres == S_OK) { + doc_onstorage = FALSE; + IHTMLWindow2_Release(window); + } + + hres = IDispatchEx_QueryInterface(dispex, &IID_IDOMStorageEvent, (void**)&event); + if(doc_onstorage) { + static const WCHAR *props[] = { L"key", L"oldValue", L"newValue", L"storageArea" }; + ok_(__FILE__,line)(hres != S_OK, "Got IDOMStorageEvent in document.onstorage handler\n"); + + hres = IDispatchEx_QueryInterface(dispex, &IID_IHTMLEventObj, (void**)&event_obj); + ok_(__FILE__,line)(hres == S_OK, "Could not get IHTMLEventObj: %08lx\n", hres); + IHTMLEventObj_Release(event_obj); + + for(i = 0; i < ARRAY_SIZE(props); i++) { + bstr = SysAllocString(props[i]); + hres = IDispatchEx_GetDispID(dispex, bstr, 0, &id); + ok_(__FILE__,line)(hres == DISP_E_UNKNOWNNAME, "GetDispID(%s) failed: %08lx\n", wine_dbgstr_w(bstr), hres); + SysFreeString(bstr); + } + + IDispatchEx_Release(dispex); + return; + } + + ok_(__FILE__,line)(hres == S_OK, "Could not get IDOMStorageEvent: %08lx\n", hres); + IDispatchEx_Release(dispex); + + hres = IDOMStorageEvent_get_key(event, &bstr); + ok_(__FILE__,line)(hres == S_OK, "get_key failed: %08lx\n", hres); + ok_(__FILE__,line)((!bstr || !expect_key) ? (bstr == expect_key) : !wcscmp(bstr, expect_key), + "key = %s\n", wine_dbgstr_w(bstr)); + SysFreeString(bstr); + + hres = IDOMStorageEvent_get_oldValue(event, &bstr); + ok_(__FILE__,line)(hres == S_OK, "get_oldValue failed: %08lx\n", hres); + ok_(__FILE__,line)((!bstr || !expect_old_value) ? (bstr == expect_old_value) : !wcscmp(bstr, expect_old_value), + "oldValue = %s\n", wine_dbgstr_w(bstr)); + SysFreeString(bstr); + + hres = IDOMStorageEvent_get_newValue(event, &bstr); + ok_(__FILE__,line)(hres == S_OK, "get_newValue failed: %08lx\n", hres); + ok_(__FILE__,line)((!bstr || !expect_new_value) ? (bstr == expect_new_value) : !wcscmp(bstr, expect_new_value), + "newValue = %s\n", wine_dbgstr_w(bstr)); + SysFreeString(bstr); + + IDOMStorageEvent_Release(event); +} + +static HRESULT WINAPI doc1_onstorage_func(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, + VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) +{ + test_storage_event(pdp, FALSE); + CHECK_EXPECT(doc_onstorage[0]); + return S_OK; +} + +static const IDispatchExVtbl doc1_onstorage_vtbl = { + DispatchEx_QueryInterface, + DispatchEx_AddRef, + DispatchEx_Release, + DispatchEx_GetTypeInfoCount, + DispatchEx_GetTypeInfo, + DispatchEx_GetIDsOfNames, + DispatchEx_Invoke, + DispatchEx_GetDispID, + doc1_onstorage_func, + DispatchEx_DeleteMemberByName, + DispatchEx_DeleteMemberByDispID, + DispatchEx_GetMemberProperties, + DispatchEx_GetMemberName, + DispatchEx_GetNextDispID, + DispatchEx_GetNameSpaceParent +}; + +static HRESULT WINAPI doc1_onstoragecommit_func(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, + VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) +{ + test_storage_event(pdp, TRUE); + CHECK_EXPECT(doc_onstoragecommit[0]); + return S_OK; +} + +static const IDispatchExVtbl doc1_onstoragecommit_vtbl = { + DispatchEx_QueryInterface, + DispatchEx_AddRef, + DispatchEx_Release, + DispatchEx_GetTypeInfoCount, + DispatchEx_GetTypeInfo, + DispatchEx_GetIDsOfNames, + DispatchEx_Invoke, + DispatchEx_GetDispID, + doc1_onstoragecommit_func, + DispatchEx_DeleteMemberByName, + DispatchEx_DeleteMemberByDispID, + DispatchEx_GetMemberProperties, + DispatchEx_GetMemberName, + DispatchEx_GetNextDispID, + DispatchEx_GetNameSpaceParent +}; + +static HRESULT WINAPI window1_onstorage_func(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, + VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) +{ + test_storage_event(pdp, FALSE); + CHECK_EXPECT(window_onstorage[0]); + SET_EXPECT(doc_onstorage[0]); + return S_OK; +} + +static const IDispatchExVtbl window1_onstorage_vtbl = { + DispatchEx_QueryInterface, + DispatchEx_AddRef, + DispatchEx_Release, + DispatchEx_GetTypeInfoCount, + DispatchEx_GetTypeInfo, + DispatchEx_GetIDsOfNames, + DispatchEx_Invoke, + DispatchEx_GetDispID, + window1_onstorage_func, + DispatchEx_DeleteMemberByName, + DispatchEx_DeleteMemberByDispID, + DispatchEx_GetMemberProperties, + DispatchEx_GetMemberName, + DispatchEx_GetNextDispID, + DispatchEx_GetNameSpaceParent +}; + +static HRESULT WINAPI doc2_onstorage_func(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, + VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) +{ + test_storage_event(pdp, FALSE); + CHECK_EXPECT(doc_onstorage[1]); + return S_OK; +} + +static const IDispatchExVtbl doc2_onstorage_vtbl = { + DispatchEx_QueryInterface, + DispatchEx_AddRef, + DispatchEx_Release, + DispatchEx_GetTypeInfoCount, + DispatchEx_GetTypeInfo, + DispatchEx_GetIDsOfNames, + DispatchEx_Invoke, + DispatchEx_GetDispID, + doc2_onstorage_func, + DispatchEx_DeleteMemberByName, + DispatchEx_DeleteMemberByDispID, + DispatchEx_GetMemberProperties, + DispatchEx_GetMemberName, + DispatchEx_GetNextDispID, + DispatchEx_GetNameSpaceParent +}; + +static HRESULT WINAPI doc2_onstoragecommit_func(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, + VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) +{ + test_storage_event(pdp, TRUE); + CHECK_EXPECT(doc_onstoragecommit[1]); + return S_OK; +} + +static const IDispatchExVtbl doc2_onstoragecommit_vtbl = { + DispatchEx_QueryInterface, + DispatchEx_AddRef, + DispatchEx_Release, + DispatchEx_GetTypeInfoCount, + DispatchEx_GetTypeInfo, + DispatchEx_GetIDsOfNames, + DispatchEx_Invoke, + DispatchEx_GetDispID, + doc2_onstoragecommit_func, + DispatchEx_DeleteMemberByName, + DispatchEx_DeleteMemberByDispID, + DispatchEx_GetMemberProperties, + DispatchEx_GetMemberName, + DispatchEx_GetNextDispID, + DispatchEx_GetNameSpaceParent +}; + +static HRESULT WINAPI window2_onstorage_func(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, + VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) +{ + test_storage_event(pdp, FALSE); + CHECK_EXPECT(window_onstorage[1]); + SET_EXPECT(doc_onstorage[1]); + return S_OK; +} + +static const IDispatchExVtbl window2_onstorage_vtbl = { + DispatchEx_QueryInterface, + DispatchEx_AddRef, + DispatchEx_Release, + DispatchEx_GetTypeInfoCount, + DispatchEx_GetTypeInfo, + DispatchEx_GetIDsOfNames, + DispatchEx_Invoke, + DispatchEx_GetDispID, + window2_onstorage_func, + DispatchEx_DeleteMemberByName, + DispatchEx_DeleteMemberByDispID, + DispatchEx_GetMemberProperties, + DispatchEx_GetMemberName, + DispatchEx_GetNextDispID, + DispatchEx_GetNameSpaceParent +}; + +static void test_storage_events(unsigned document_mode) +{ + static struct { + IDispatchEx onstorage; + IDispatchEx onstoragecommit; + IDispatchEx window_onstorage; + } doc_onstorage_handlers[] = { + { { &doc1_onstorage_vtbl }, { &doc1_onstoragecommit_vtbl }, { &window1_onstorage_vtbl } }, + { { &doc2_onstorage_vtbl }, { &doc2_onstoragecommit_vtbl }, { &window2_onstorage_vtbl } }, + }; + IHTMLStorage *session_storage[2], *local_storage[2]; + IHTMLDocument2 *doc[2]; + BSTR key, value; + HRESULT hres; + VARIANT var; + unsigned i; + + trace("Running test_storage_events in %u mode...\n", document_mode); + + for(i = 0; i < ARRAY_SIZE(doc); i++) { + sprintf(index_html_data, + "<!DOCTYPE html>\n" + "<html>\n" + " <head>\n" + " <meta http-equiv="x-ua-compatible" content="Ie=%u">\n" + " <script src="winetest.js" type="text/javascript"></script>\n" + " <script type="text/javascript">var tests = [ function() { next_test() } ];</script>\n" + " </head>\n" + " <body onload="run_tests();">\n" + " </body>\n" + "</html>\n", document_mode); + + run_from_path(L"/index.html", "test_storage_events", &doc[i]); + } + + for(i = 0; i < ARRAY_SIZE(doc); i++) { + IHTMLWindow6 *window6; + IHTMLWindow7 *window7; + IHTMLWindow2 *window; + IHTMLDocument6 *doc6; + + hres = IHTMLDocument2_get_parentWindow(doc[i], &window); + ok(hres == S_OK, "get_parentWindow[%u] failed: %08lx\n", i, hres); + ok(window != NULL, "window[%u] == NULL\n", i); + + hres = IHTMLWindow2_QueryInterface(window, &IID_IHTMLWindow6, (void**)&window6); + ok(hres == S_OK, "Could not get IHTMLWindow6: %08lx\n", hres); + IHTMLWindow2_Release(window); + + hres = IHTMLWindow6_get_sessionStorage(window6, &session_storage[i]); + ok(hres == S_OK, "get_sessionStorage[%u] failed: %08lx\n", i, hres); + ok(session_storage[i] != NULL, "session_storage[%u] == NULL\n", i); + hres = IHTMLWindow6_get_localStorage(window6, &local_storage[i]); + ok(hres == S_OK, "get_localStorage[%u] failed: %08lx\n", i, hres); + ok(local_storage[i] != NULL, "local_storage[%u] == NULL\n", i); + if(i == 0) { + MSG msg; + IHTMLStorage_clear(local_storage[0]); + while(PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) { + TranslateMessage(&msg); + DispatchMessageW(&msg); + } + } + + hres = IHTMLDocument2_QueryInterface(doc[i], &IID_IHTMLDocument6, (void**)&doc6); + if(SUCCEEDED(hres)) { + V_VT(&var) = VT_DISPATCH; + V_DISPATCH(&var) = (IDispatch*)&doc_onstorage_handlers[i].onstorage; + hres = IHTMLDocument6_put_onstorage(doc6, var); + ok(hres == S_OK, "put_onstorage[%u] failed: %08lx\n", i, hres); + + V_DISPATCH(&var) = (IDispatch*)&doc_onstorage_handlers[i].onstoragecommit; + hres = IHTMLDocument6_put_onstoragecommit(doc6, var); + ok(hres == S_OK, "put_onstoragecommit[%u] failed: %08lx\n", i, hres); + IHTMLDocument6_Release(doc6); + } + + hres = IHTMLWindow6_QueryInterface(window6, &IID_IHTMLWindow7, (void**)&window7); + IHTMLWindow6_Release(window6); + if(SUCCEEDED(hres)) { + V_VT(&var) = VT_DISPATCH; + V_DISPATCH(&var) = (IDispatch*)&doc_onstorage_handlers[i].window_onstorage; + hres = IHTMLWindow7_put_onstorage(window7, var); + ok(hres == S_OK, "put_onstorage[%u] failed: %08lx\n", i, hres); + IHTMLWindow7_Release(window7); + } + } + + /* local storage */ + key = SysAllocString(L"test"); + hres = IHTMLStorage_removeItem(local_storage[0], key); + ok(hres == S_OK, "removeItem failed: %08lx\n", hres); + + value = SysAllocString(L"WINE"); + hres = IHTMLStorage_setItem(local_storage[0], key, value); + ok(hres == S_OK, "setItem failed: %08lx\n", hres); + SysFreeString(value); + check_local_onstorage(0, L"test", NULL, L"WINE"); + + value = SysAllocString(L"wine"); + hres = IHTMLStorage_setItem(local_storage[1], key, value); + ok(hres == S_OK, "setItem failed: %08lx\n", hres); + SysFreeString(value); + check_local_onstorage(1, L"test", L"WINE", L"wine"); + + hres = IHTMLStorage_removeItem(local_storage[0], key); + ok(hres == S_OK, "removeItem failed: %08lx\n", hres); + SysFreeString(key); + check_local_onstorage(0, L"test", L"wine", NULL); + + key = SysAllocString(L"winetest"); + value = SysAllocString(L"WineTest"); + hres = IHTMLStorage_setItem(local_storage[1], key, value); + ok(hres == S_OK, "setItem failed: %08lx\n", hres); + SysFreeString(value); + SysFreeString(key); + check_local_onstorage(1, L"winetest", NULL, L"WineTest"); + + hres = IHTMLStorage_clear(local_storage[0]); + ok(hres == S_OK, "clear failed: %08lx\n", hres); + check_local_onstorage(0, NULL, NULL, NULL); + + /* session storage */ + key = SysAllocString(L"foobar"); + hres = IHTMLStorage_removeItem(session_storage[0], key); + ok(hres == S_OK, "removeItem failed: %08lx\n", hres); + + value = SysAllocString(L"BarFoo"); + hres = IHTMLStorage_setItem(session_storage[0], key, value); + ok(hres == S_OK, "setItem failed: %08lx\n", hres); + SysFreeString(value); + check_session_onstorage(0, L"foobar", NULL, L"BarFoo"); + + value = SysAllocString(L"barfoo"); + hres = IHTMLStorage_setItem(session_storage[1], key, value); + ok(hres == S_OK, "setItem failed: %08lx\n", hres); + SysFreeString(value); + check_session_onstorage(1, L"foobar", L"BarFoo", L"barfoo"); + + hres = IHTMLStorage_removeItem(session_storage[0], key); + ok(hres == S_OK, "removeItem failed: %08lx\n", hres); + SysFreeString(key); + check_session_onstorage(0, L"foobar", L"barfoo", NULL); + + key = SysAllocString(L"winetest"); + value = SysAllocString(L"WineTest"); + hres = IHTMLStorage_setItem(session_storage[1], key, value); + ok(hres == S_OK, "setItem failed: %08lx\n", hres); + SysFreeString(value); + SysFreeString(key); + check_session_onstorage(1, L"winetest", NULL, L"WineTest"); + + hres = IHTMLStorage_clear(session_storage[0]); + ok(hres == S_OK, "clear failed: %08lx\n", hres); + check_session_onstorage(0, NULL, NULL, NULL); + + free_registered_streams(); + set_client_site(doc[0], FALSE); + set_client_site(doc[1], FALSE); + IHTMLDocument2_Release(doc[0]); + IHTMLDocument2_Release(doc[1]); +} + static void run_script_as_http_with_mode(const char *script, const char *opt, const char *document_mode) { trace("Running %s script in %s mode...\n", script, document_mode ? document_mode : "quirks"); @@ -3834,7 +4293,7 @@ static void run_script_as_http_with_mode(const char *script, const char *opt, co document_mode ? "">" : "", script);
- run_from_path(L"/index.html", opt ? opt : script); + run_from_path(L"/index.html", opt ? opt : script, NULL); }
static void test_strict_mode(void) @@ -3856,7 +4315,7 @@ static void test_strict_mode(void) " </body>\n" "</html>\n");
- run_from_path(L"/index.html", "test_strict_mode"); + run_from_path(L"/index.html", "test_strict_mode", NULL); }
static void init_protocol_handler(void) @@ -3893,6 +4352,11 @@ static void run_js_tests(void) init_protocol_handler();
test_strict_mode(); + test_storage_events(0); + test_storage_events(7); + test_storage_events(8); + test_storage_events(9); + test_storage_events(11); run_script_as_http_with_mode("xhr.js", NULL, "9"); run_script_as_http_with_mode("xhr.js", NULL, "10"); run_script_as_http_with_mode("xhr.js", NULL, "11");
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=122793
Your paranoid android.
=== w1064v1507 (64 bit report) ===
mshtml: misc: Timeout
=== w7u_el (32 bit report) ===
mshtml: script.c:3984: Test failed: unexpected call doc_onstoragecommit[0]
=== debian11 (32 bit German report) ===
mshtml: misc.c:465: Test failed: unexpected call doc_onstorage misc.c:465: Test failed: unexpected call doc_onstorage misc.c:465: Test failed: unexpected call doc_onstorage misc.c:465: Test failed: unexpected call doc_onstorage misc.c:465: Test failed: unexpected call doc_onstorage misc.c:465: Test failed: unexpected call doc_onstorage misc.c:465: Test failed: unexpected call doc_onstorage misc.c:465: Test failed: unexpected call doc_onstorage misc.c:465: Test failed: unexpected call doc_onstorage misc.c:465: Test failed: unexpected call doc_onstorage
Sorry, I forgot to update these when I did the WCHAR/BSTR assumption last time and noticed just now, so I pushed an update.