-- v2: mshtml: Handle cNames > 1 in GetIDsOfNames properly. mshtml: Forward IDispatchEx to the document node. mshtml: Forward toString to the document node. mshtml: Expose IEventTarget on HTMLDocumentObj and forward it to the doc node.
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/mshtml_private.h | 1 + dlls/mshtml/oleobj.c | 61 ++++++++++++++ dlls/mshtml/tests/events.c | 154 +++++++++++++++++++++++++++++++++-- 3 files changed, 210 insertions(+), 6 deletions(-)
diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 7df5c5e8b30..e7f5481b886 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -677,6 +677,7 @@ struct HTMLDocumentObj { IObjectSafety IObjectSafety_iface; IServiceProvider IServiceProvider_iface; ITargetContainer ITargetContainer_iface; + IEventTarget IEventTarget_iface;
IWindowForBindingUI IWindowForBindingUI_iface;
diff --git a/dlls/mshtml/oleobj.c b/dlls/mshtml/oleobj.c index de6fd028218..5c7673b1649 100644 --- a/dlls/mshtml/oleobj.c +++ b/dlls/mshtml/oleobj.c @@ -3238,6 +3238,58 @@ static const IDocumentRangeVtbl DocObjDocumentRangeVtbl = { DocObjDocumentRange_createRange };
+/********************************************************** + * IEventTarget implementation + */ +static inline HTMLDocumentObj *impl_from_IEventTarget(IEventTarget *iface) +{ + return CONTAINING_RECORD(iface, HTMLDocumentObj, IEventTarget_iface); +} + +HTMLDOCUMENTOBJ_IDISPATCH_METHODS(EventTarget) + +static HRESULT WINAPI DocObjEventTarget_addEventListener(IEventTarget *iface, BSTR type, IDispatch *listener, + VARIANT_BOOL capture) +{ + HTMLDocumentObj *This = impl_from_IEventTarget(iface); + + if(!This->doc_node) + return E_UNEXPECTED; + return IEventTarget_addEventListener(&This->doc_node->node.event_target.IEventTarget_iface, type, listener, capture); +} + +static HRESULT WINAPI DocObjEventTarget_removeEventListener(IEventTarget *iface, BSTR type, IDispatch *listener, + VARIANT_BOOL capture) +{ + HTMLDocumentObj *This = impl_from_IEventTarget(iface); + + if(!This->doc_node) + return E_UNEXPECTED; + return IEventTarget_removeEventListener(&This->doc_node->node.event_target.IEventTarget_iface, type, listener, capture); +} + +static HRESULT WINAPI DocObjEventTarget_dispatchEvent(IEventTarget *iface, IDOMEvent *event_iface, VARIANT_BOOL *result) +{ + HTMLDocumentObj *This = impl_from_IEventTarget(iface); + + if(!This->doc_node) + return E_UNEXPECTED; + return IEventTarget_dispatchEvent(&This->doc_node->node.event_target.IEventTarget_iface, event_iface, result); +} + +static const IEventTargetVtbl DocObjEventTargetVtbl = { + DocObjEventTarget_QueryInterface, + DocObjEventTarget_AddRef, + DocObjEventTarget_Release, + DocObjEventTarget_GetTypeInfoCount, + DocObjEventTarget_GetTypeInfo, + DocObjEventTarget_GetIDsOfNames, + DocObjEventTarget_Invoke, + DocObjEventTarget_addEventListener, + DocObjEventTarget_removeEventListener, + DocObjEventTarget_dispatchEvent +}; + static inline HTMLDocumentObj *impl_from_IUnknown(IUnknown *iface) { return CONTAINING_RECORD(iface, HTMLDocumentObj, IUnknown_inner); @@ -3339,6 +3391,14 @@ static HRESULT WINAPI HTMLDocumentObj_QueryInterface(IUnknown *iface, REFIID rii *ppv = &This->ITargetContainer_iface; }else if(IsEqualGUID(&IID_IConnectionPointContainer, riid)) { *ppv = &This->cp_container.IConnectionPointContainer_iface; + }else if(IsEqualGUID(&IID_IEventTarget, riid)) { + /* IEventTarget is conditionally exposed. This breaks COM rules when + it changes its compat mode, but it is how native works (see tests). */ + if(!This->doc_node || dispex_compat_mode(&This->doc_node->node.event_target.dispex) < COMPAT_MODE_IE9) { + *ppv = NULL; + return E_NOINTERFACE; + } + *ppv = &This->IEventTarget_iface; }else if(IsEqualGUID(&CLSID_CMarkup, riid)) { FIXME("(%p)->(CLSID_CMarkup %p)\n", This, ppv); *ppv = NULL; @@ -3734,6 +3794,7 @@ static HRESULT create_document_object(BOOL is_mhtml, IUnknown *outer, REFIID rii doc->IMarkupContainer_iface.lpVtbl = &DocObjMarkupContainerVtbl; doc->IDisplayServices_iface.lpVtbl = &DocObjDisplayServicesVtbl; doc->IDocumentRange_iface.lpVtbl = &DocObjDocumentRangeVtbl; + doc->IEventTarget_iface.lpVtbl = &DocObjEventTargetVtbl;
doc->outer_unk = outer ? outer : &doc->IUnknown_inner;
diff --git a/dlls/mshtml/tests/events.c b/dlls/mshtml/tests/events.c index 8175205b830..2c72773909c 100644 --- a/dlls/mshtml/tests/events.c +++ b/dlls/mshtml/tests/events.c @@ -60,6 +60,7 @@ #define CLEAR_CALLED(func) \ expect_ ## func = called_ ## func = FALSE
+DEFINE_EXPECT(docobj_onclick); DEFINE_EXPECT(document_onclick); DEFINE_EXPECT(body_onclick); DEFINE_EXPECT(doc_onclick_attached); @@ -965,6 +966,15 @@ static HRESULT WINAPI DispatchEx_GetNameSpaceParent(IDispatchEx *iface, IUnknown }; \ static IDispatchEx event ## _obj = { &event ## FuncVtbl };
+static HRESULT WINAPI docobj_onclick(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, + VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) +{ + CHECK_EXPECT(docobj_onclick); + return S_OK; +} + +EVENT_HANDLER_FUNC_OBJ(docobj_onclick); + static HRESULT WINAPI document_onclick(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) { @@ -3321,9 +3331,11 @@ static HRESULT WINAPI DocumentSite_ActivateMe(IOleDocumentSite *iface, IOleDocum hres = IOleDocumentView_QueryInterface(pViewToActivate, &IID_IOleDocument, (void**)&document); ok(hres == S_OK, "could not get IOleDocument: %08lx\n", hres);
- hres = IOleDocument_CreateView(document, &InPlaceSite, NULL, 0, &view); + if(!view) { + hres = IOleDocument_CreateView(document, &InPlaceSite, NULL, 0, &view); + ok(hres == S_OK, "CreateView failed: %08lx\n", hres); + } IOleDocument_Release(document); - ok(hres == S_OK, "CreateView failed: %08lx\n", hres);
hres = IOleDocumentView_SetInPlaceSite(view, &InPlaceSite); ok(hres == S_OK, "SetInPlaceSite failed: %08lx\n", hres); @@ -3812,6 +3824,44 @@ static void set_client_site(IHTMLDocument2 *doc, BOOL set)
IOleObject_Release(oleobj); } + +static void navigate(IHTMLDocument2 *doc, const WCHAR *url) +{ + IPersistMoniker *persist; + IHlinkTarget *hlink; + IMoniker *mon; + HRESULT hres; + BSTR bstr; + MSG msg; + + /* We can't use normal navigation, because Windows ignores the temporary + pluggable namespace handlers on top-level window navigation. */ + doc_complete = FALSE; + bstr = SysAllocString(url); + hres = CreateURLMoniker(NULL, bstr, &mon); + SysFreeString(bstr); + ok(hres == S_OK, "CreateUrlMoniker failed: %08lx\n", hres); + + hres = IHTMLDocument2_QueryInterface(doc, &IID_IPersistMoniker, (void**)&persist); + ok(hres == S_OK, "Could not get IPersistMoniker iface: %08lx\n", hres); + + hres = IPersistMoniker_Load(persist, FALSE, mon, NULL, 0); + ok(hres == S_OK, "Load failed: %08lx\n", hres); + IPersistMoniker_Release(persist); + IMoniker_Release(mon); + + hres = IHTMLDocument2_QueryInterface(doc, &IID_IHlinkTarget, (void**)&hlink); + ok(hres == S_OK, "Could not get IHlinkTarget iface: %08lx\n", hres); + hres = IHlinkTarget_Navigate(hlink, 0, NULL); + ok(hres == S_OK, "Navigate failed: %08lx\n", hres); + IHlinkTarget_Release(hlink); + + while(!doc_complete && GetMessageW(&msg, NULL, 0, 0)) { + TranslateMessage(&msg); + DispatchMessageW(&msg); + } +} + static IHTMLDocument2 *create_document(void) { IHTMLDocument2 *doc; @@ -3826,7 +3876,7 @@ static IHTMLDocument2 *create_document(void) return SUCCEEDED(hres) ? doc : NULL; }
-static IHTMLDocument2 *create_document_with_origin(const char *str) +static IHTMLDocument2 *create_document_with_origin(const WCHAR *origin_url, const char *str) { IInternetSession *internet_session; IPersistMoniker *persist; @@ -3856,7 +3906,7 @@ static IHTMLDocument2 *create_document_with_origin(const char *str) set_client_site(doc, TRUE); do_advise((IUnknown*)doc, &IID_IPropertyNotifySink, (IUnknown*)&PropertyNotifySink);
- url = SysAllocString(L"http://winetest.example.org"); + url = SysAllocString(origin_url); hres = CreateURLMoniker(NULL, url, &mon); SysFreeString(url); ok(hres == S_OK, "CreateUrlMoniker failed: %08lx\n", hres); @@ -4008,7 +4058,7 @@ static void test_storage_events(const char *doc_str) unsigned i;
for(i = 0; i < ARRAY_SIZE(doc); i++) - doc[i] = create_document_with_origin(doc_str); + doc[i] = create_document_with_origin(L"http://winetest.example.org", doc_str);
document_mode = 0; for(i = 0; i < ARRAY_SIZE(doc); i++) { @@ -4204,6 +4254,95 @@ done: IHTMLDocument2_Release(doc[1]); }
+static void test_doc_obj(const char *doc_str) +{ + IHTMLDocument2 *doc = create_document_with_origin(L"http://winetest.example.org", doc_str); + IEventTarget *event_target; + IHTMLDocument6 *doc6; + IHTMLElement *body; + HRESULT hres; + VARIANT res; + BSTR bstr; + + hres = IHTMLDocument2_QueryInterface(doc, &IID_IHTMLDocument6, (void**)&doc6); + ok(hres == S_OK, "Could not get IHTMLDocument6: %08lx\n", hres); + + hres = IHTMLDocument6_get_documentMode(doc6, &res); + ok(hres == S_OK, "get_documentMode failed: %08lx\n", hres); + ok(V_VT(&res) == VT_R4, "V_VT(documentMode) = %u\n", V_VT(&res)); + IHTMLDocument6_Release(doc6); + document_mode = V_R4(&res); + + event_target = (void*)0xdeadbeef; + hres = IHTMLDocument2_QueryInterface(doc, &IID_IEventTarget, (void**)&event_target); + if(document_mode < 9) { + ok(hres == E_NOINTERFACE, "hres = %08lx, expected E_NOINTERFACE\n", hres); + ok(!event_target, "event_target != NULL\n"); + }else { + IHTMLDocument2 *tmp; + + ok(hres == S_OK, "hres = %08lx, expected S_OK\n", hres); + ok(!!event_target, "event_target = NULL\n"); + + bstr = SysAllocString(L"click"); + IEventTarget_addEventListener(event_target, bstr, (IDispatch*)&docobj_onclick_obj, TRUE); + ok(hres == S_OK, "addEventListener failed: %08lx\n", hres); + SysFreeString(bstr); + + hres = IEventTarget_QueryInterface(event_target, &IID_IHTMLDocument2, (void**)&tmp); + ok(hres == S_OK, "Could not get IHTMLDocument2: %08lx\n", hres); + IEventTarget_Release(event_target); + + ok(doc == tmp, "IHTMLDocument2 from IEventTarget not same as original\n"); + IHTMLDocument2_Release(tmp); + + body = doc_get_body(doc); + SET_EXPECT(docobj_onclick); + hres = IHTMLElement_click(body); + ok(hres == S_OK, "click failed: %08lx\n", hres); + IHTMLElement_Release(body); + + pump_msgs(&called_docobj_onclick); + CHECK_CALLED(docobj_onclick); + } + + /* Navigate to a different document mode page, checking using the same doc obj. + Test that it breaks COM rules, since IEventTarget is conditionally exposed. + All the events registered on the old doc node are also removed. */ + protocol_doc_str = document_mode < 9 ? empty_doc_ie9_str : empty_doc_str; + navigate(doc, L"http://winetest.example.org/foobar"); + + hres = IHTMLDocument2_QueryInterface(doc, &IID_IHTMLDocument6, (void**)&doc6); + ok(hres == S_OK, "Could not get IHTMLDocument6: %08lx\n", hres); + + hres = IHTMLDocument6_get_documentMode(doc6, &res); + ok(hres == S_OK, "get_documentMode failed: %08lx\n", hres); + ok(V_VT(&res) == VT_R4, "V_VT(documentMode) = %u\n", V_VT(&res)); + ok(V_R4(&res) == (document_mode < 9 ? 9.0f : 5.0f), "V_R4(documentMode) = %f\n", V_R4(&res)); + IHTMLDocument6_Release(doc6); + document_mode = V_R4(&res); + + event_target = (void*)0xdeadbeef; + hres = IHTMLDocument2_QueryInterface(doc, &IID_IEventTarget, (void**)&event_target); + if(document_mode < 9) { + ok(hres == E_NOINTERFACE, "hres = %08lx, expected E_NOINTERFACE\n", hres); + ok(!event_target, "event_target != NULL\n"); + + body = doc_get_body(doc); + hres = IHTMLElement_click(body); + ok(hres == S_OK, "click failed: %08lx\n", hres); + IHTMLElement_Release(body); + pump_msgs(NULL); + }else { + ok(hres == S_OK, "hres = %08lx, expected S_OK\n", hres); + ok(!!event_target, "event_target = NULL\n"); + IEventTarget_Release(event_target); + } + + set_client_site(doc, FALSE); + IHTMLDocument2_Release(doc); +} + static BOOL check_ie(void) { IHTMLDocument2 *doc; @@ -4257,8 +4396,11 @@ START_TEST(events)
test_empty_document(); test_storage_events(empty_doc_str); - if(is_ie9plus) + if(is_ie9plus) { test_storage_events(empty_doc_ie9_str); + test_doc_obj(empty_doc_str); + test_doc_obj(empty_doc_ie9_str); + }
DestroyWindow(container_hwnd); }else {
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/oleobj.c | 11 +---------- dlls/mshtml/tests/events.c | 7 +++++++ 2 files changed, 8 insertions(+), 10 deletions(-)
diff --git a/dlls/mshtml/oleobj.c b/dlls/mshtml/oleobj.c index 5c7673b1649..7821abdb390 100644 --- a/dlls/mshtml/oleobj.c +++ b/dlls/mshtml/oleobj.c @@ -2384,16 +2384,7 @@ HTMLDOCUMENTOBJ_FWD_TO_NODE_1(HTMLDocument2, put_onbeforeupdate, VARIANT) HTMLDOCUMENTOBJ_FWD_TO_NODE_1(HTMLDocument2, get_onbeforeupdate, VARIANT*) HTMLDOCUMENTOBJ_FWD_TO_NODE_1(HTMLDocument2, put_onerrorupdate, VARIANT) HTMLDOCUMENTOBJ_FWD_TO_NODE_1(HTMLDocument2, get_onerrorupdate, VARIANT*) - -static HRESULT WINAPI DocObjHTMLDocument2_toString(IHTMLDocument2 *iface, BSTR *String) -{ - HTMLDocumentObj *This = impl_from_IHTMLDocument2(iface); - - TRACE("(%p)->(%p)\n", This, String); - - return dispex_to_string(&This->dispex, String); -} - +HTMLDOCUMENTOBJ_FWD_TO_NODE_1(HTMLDocument2, toString, BSTR*) HTMLDOCUMENTOBJ_FWD_TO_NODE_3(HTMLDocument2, createStyleSheet, BSTR,LONG,IHTMLStyleSheet**)
static const IHTMLDocument2Vtbl DocObjHTMLDocument2Vtbl = { diff --git a/dlls/mshtml/tests/events.c b/dlls/mshtml/tests/events.c index 2c72773909c..b6a0c32d8a8 100644 --- a/dlls/mshtml/tests/events.c +++ b/dlls/mshtml/tests/events.c @@ -4306,6 +4306,13 @@ static void test_doc_obj(const char *doc_str) CHECK_CALLED(docobj_onclick); }
+ bstr = NULL; + hres = IHTMLDocument2_toString(doc, &bstr); + ok(hres == S_OK, "toString failed: %08lx\n", hres); + todo_wine_if(document_mode >= 9) + ok(!wcscmp(bstr, (document_mode < 9 ? L"[object]" : L"[object Document]")), "toString returned %s\n", wine_dbgstr_w(bstr)); + SysFreeString(bstr); + /* Navigate to a different document mode page, checking using the same doc obj. Test that it breaks COM rules, since IEventTarget is conditionally exposed. All the events registered on the old doc node are also removed. */
From: Gabriel Ivăncescu gabrielopcode@gmail.com
And get rid of the dispex since it's useless now.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/mshtml_private.h | 1 - dlls/mshtml/oleobj.c | 165 ++++++----------------------------- dlls/mshtml/tests/dom.c | 27 ++++++ dlls/mshtml/tests/events.c | 99 ++++++++++++++++++++- 4 files changed, 151 insertions(+), 141 deletions(-)
diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index e7f5481b886..e3971258b13 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -640,7 +640,6 @@ struct ConnectionPoint { };
struct HTMLDocumentObj { - DispatchEx dispex; IUnknown IUnknown_inner; IDispatchEx IDispatchEx_iface; ICustomDoc ICustomDoc_iface; diff --git a/dlls/mshtml/oleobj.c b/dlls/mshtml/oleobj.c index 7821abdb390..54ce4e0a159 100644 --- a/dlls/mshtml/oleobj.c +++ b/dlls/mshtml/oleobj.c @@ -27,6 +27,7 @@ #include "ole2.h" #include "shlguid.h" #include "shdeprecated.h" +#include "mscoree.h" #include "mshtmdid.h" #include "idispids.h"
@@ -3410,8 +3411,12 @@ static HRESULT WINAPI HTMLDocumentObj_QueryInterface(IUnknown *iface, REFIID rii TRACE("(%p)->(IID_IStdMarshalInfo %p) returning NULL\n", This, ppv); *ppv = NULL; return E_NOINTERFACE; - }else if(dispex_query_interface(&This->dispex, riid, ppv)) { - return *ppv ? S_OK : E_NOINTERFACE; + }else if(IsEqualGUID(&IID_IDispatchJS, riid) || + IsEqualGUID(&IID_UndocumentedScriptIface, riid) || + IsEqualGUID(&IID_IMarshal, riid) || + IsEqualGUID(&IID_IManagedObject, riid)) { + *ppv = NULL; + return E_NOINTERFACE; }else { FIXME("Unimplemented interface %s\n", debugstr_mshtml_guid(riid)); *ppv = NULL; @@ -3472,7 +3477,6 @@ static ULONG WINAPI HTMLDocumentObj_Release(IUnknown *iface)
remove_target_tasks(This->task_magic); ConnectionPointContainer_Destroy(&This->cp_container); - release_dispex(&This->dispex);
if(This->nscontainer) detach_gecko_browser(This->nscontainer); @@ -3490,123 +3494,50 @@ static const IUnknownVtbl HTMLDocumentObjVtbl = {
/********************************************************** * IDispatchEx implementation + * + * Forwarding this breaks Dispatch rules by potentially retrieving + * a different DISPID for the same name, if the node was changed + * while using the same doc obj, but it is how native works. */ static inline HTMLDocumentObj *impl_from_IDispatchEx(IDispatchEx *iface) { return CONTAINING_RECORD(iface, HTMLDocumentObj, IDispatchEx_iface); }
-static HRESULT WINAPI DocObjDispatchEx_QueryInterface(IDispatchEx *iface, REFIID riid, void **ppv) -{ - HTMLDocumentObj *This = impl_from_IDispatchEx(iface); - return IUnknown_QueryInterface(This->outer_unk, riid, ppv); -} - -static ULONG WINAPI DocObjDispatchEx_AddRef(IDispatchEx *iface) -{ - HTMLDocumentObj *This = impl_from_IDispatchEx(iface); - return IUnknown_AddRef(This->outer_unk); -} - -static ULONG WINAPI DocObjDispatchEx_Release(IDispatchEx *iface) -{ - HTMLDocumentObj *This = impl_from_IDispatchEx(iface); - return IUnknown_Release(This->outer_unk); -} - -static HRESULT WINAPI DocObjDispatchEx_GetTypeInfoCount(IDispatchEx *iface, UINT *pctinfo) -{ - HTMLDocumentObj *This = impl_from_IDispatchEx(iface); - return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo); -} - -static HRESULT WINAPI DocObjDispatchEx_GetTypeInfo(IDispatchEx *iface, UINT iTInfo, LCID lcid, - ITypeInfo **ppTInfo) -{ - HTMLDocumentObj *This = impl_from_IDispatchEx(iface); - return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo); -} - -static HRESULT WINAPI DocObjDispatchEx_GetIDsOfNames(IDispatchEx *iface, REFIID riid, LPOLESTR *rgszNames, - UINT cNames, LCID lcid, DISPID *rgDispId) -{ - HTMLDocumentObj *This = impl_from_IDispatchEx(iface); - return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid, rgszNames, cNames, lcid, rgDispId); -} +HTMLDOCUMENTOBJ_IUNKNOWN_METHODS(DispatchEx) +HTMLDOCUMENTOBJ_FWD_TO_NODE_1(DispatchEx, GetTypeInfoCount, UINT*) +HTMLDOCUMENTOBJ_FWD_TO_NODE_3(DispatchEx, GetTypeInfo, UINT,LCID,ITypeInfo**) +HTMLDOCUMENTOBJ_FWD_TO_NODE_5(DispatchEx, GetIDsOfNames, REFIID,LPOLESTR*,UINT,LCID,DISPID*)
static HRESULT WINAPI DocObjDispatchEx_Invoke(IDispatchEx *iface, DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) { HTMLDocumentObj *This = impl_from_IDispatchEx(iface); - return IDispatchEx_InvokeEx(&This->IDispatchEx_iface, dispIdMember, lcid, wFlags, pDispParams, + + if(!This->doc_node) + return E_UNEXPECTED; + return IDispatchEx_InvokeEx(&This->doc_node->IDispatchEx_iface, dispIdMember, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, NULL); }
-static HRESULT WINAPI DocObjDispatchEx_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid) -{ - HTMLDocumentObj *This = impl_from_IDispatchEx(iface); - return IDispatchEx_GetDispID(&This->dispex.IDispatchEx_iface, bstrName, grfdex, pid); -} +HTMLDOCUMENTOBJ_FWD_TO_NODE_3(DispatchEx, GetDispID, BSTR,DWORD,DISPID*)
static HRESULT WINAPI DocObjDispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) { HTMLDocumentObj *This = impl_from_IDispatchEx(iface);
- if(This->window) { - switch(id) { - case DISPID_READYSTATE: - TRACE("DISPID_READYSTATE\n"); - - if(!(wFlags & DISPATCH_PROPERTYGET)) - return E_INVALIDARG; - - V_VT(pvarRes) = VT_I4; - V_I4(pvarRes) = This->window->readystate; - return S_OK; - default: - break; - } - } - - return IDispatchEx_InvokeEx(&This->dispex.IDispatchEx_iface, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller); -} - -static HRESULT WINAPI DocObjDispatchEx_DeleteMemberByName(IDispatchEx *iface, BSTR bstrName, DWORD grfdex) -{ - HTMLDocumentObj *This = impl_from_IDispatchEx(iface); - return IDispatchEx_DeleteMemberByName(&This->dispex.IDispatchEx_iface, bstrName, grfdex); -} - -static HRESULT WINAPI DocObjDispatchEx_DeleteMemberByDispID(IDispatchEx *iface, DISPID id) -{ - HTMLDocumentObj *This = impl_from_IDispatchEx(iface); - return IDispatchEx_DeleteMemberByDispID(&This->dispex.IDispatchEx_iface, id); -} - -static HRESULT WINAPI DocObjDispatchEx_GetMemberProperties(IDispatchEx *iface, DISPID id, DWORD grfdexFetch, DWORD *pgrfdex) -{ - HTMLDocumentObj *This = impl_from_IDispatchEx(iface); - return IDispatchEx_GetMemberProperties(&This->dispex.IDispatchEx_iface, id, grfdexFetch, pgrfdex); -} - -static HRESULT WINAPI DocObjDispatchEx_GetMemberName(IDispatchEx *iface, DISPID id, BSTR *pbstrName) -{ - HTMLDocumentObj *This = impl_from_IDispatchEx(iface); - return IDispatchEx_GetMemberName(&This->dispex.IDispatchEx_iface, id, pbstrName); -} - -static HRESULT WINAPI DocObjDispatchEx_GetNextDispID(IDispatchEx *iface, DWORD grfdex, DISPID id, DISPID *pid) -{ - HTMLDocumentObj *This = impl_from_IDispatchEx(iface); - return IDispatchEx_GetNextDispID(&This->dispex.IDispatchEx_iface, grfdex, id, pid); + if(!This->doc_node) + return E_UNEXPECTED; + return IDispatchEx_InvokeEx(&This->doc_node->IDispatchEx_iface, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller); }
-static HRESULT WINAPI DocObjDispatchEx_GetNameSpaceParent(IDispatchEx *iface, IUnknown **ppunk) -{ - HTMLDocumentObj *This = impl_from_IDispatchEx(iface); - return IDispatchEx_GetNameSpaceParent(&This->dispex.IDispatchEx_iface, ppunk); -} +HTMLDOCUMENTOBJ_FWD_TO_NODE_2(DispatchEx, DeleteMemberByName, BSTR,DWORD) +HTMLDOCUMENTOBJ_FWD_TO_NODE_1(DispatchEx, DeleteMemberByDispID, DISPID) +HTMLDOCUMENTOBJ_FWD_TO_NODE_3(DispatchEx, GetMemberProperties, DISPID,DWORD,DWORD*) +HTMLDOCUMENTOBJ_FWD_TO_NODE_2(DispatchEx, GetMemberName, DISPID,BSTR*) +HTMLDOCUMENTOBJ_FWD_TO_NODE_3(DispatchEx, GetNextDispID, DWORD,DISPID,DISPID*) +HTMLDOCUMENTOBJ_FWD_TO_NODE_1(DispatchEx, GetNameSpaceParent, IUnknown**)
static const IDispatchExVtbl DocObjDispatchExVtbl = { DocObjDispatchEx_QueryInterface, @@ -3712,43 +3643,6 @@ static const cpc_entry_t HTMLDocumentObj_cpc[] = { {NULL} };
-static HRESULT HTMLDocumentObj_location_hook(DispatchEx *dispex, WORD flags, DISPPARAMS *dp, VARIANT *res, - EXCEPINFO *ei, IServiceProvider *caller) -{ - HTMLDocumentObj *This = CONTAINING_RECORD(dispex, HTMLDocumentObj, dispex); - - if(!(flags & DISPATCH_PROPERTYPUT) || !This->window) - return S_FALSE; - - return IDispatchEx_InvokeEx(&This->window->base.IDispatchEx_iface, DISPID_IHTMLWINDOW2_LOCATION, - 0, flags, dp, res, ei, caller); -} - -static const tid_t HTMLDocumentObj_iface_tids[] = { - IHTMLDocument3_tid, - IHTMLDocument4_tid, - IHTMLDocument5_tid, - 0 -}; - -static void HTMLDocumentObj_init_dispex_info(dispex_data_t *info, compat_mode_t mode) -{ - static const dispex_hook_t document2_hooks[] = { - {DISPID_IHTMLDOCUMENT2_URL, NULL, L"URL"}, - {DISPID_IHTMLDOCUMENT2_LOCATION, HTMLDocumentObj_location_hook}, - {DISPID_UNKNOWN} - }; - dispex_info_add_interface(info, IHTMLDocument2_tid, document2_hooks); -} - -static dispex_static_data_t HTMLDocumentObj_dispex = { - L"HTMLDocumentObj", - NULL, - DispHTMLDocument_tid, - HTMLDocumentObj_iface_tids, - HTMLDocumentObj_init_dispex_info -}; - static HRESULT create_document_object(BOOL is_mhtml, IUnknown *outer, REFIID riid, void **ppv) { HTMLDocumentObj *doc; @@ -3789,7 +3683,6 @@ static HRESULT create_document_object(BOOL is_mhtml, IUnknown *outer, REFIID rii
doc->outer_unk = outer ? outer : &doc->IUnknown_inner;
- init_dispatch(&doc->dispex, (IUnknown*)&doc->ICustomDoc_iface, &HTMLDocumentObj_dispex, COMPAT_MODE_QUIRKS); ConnectionPointContainer_Init(&doc->cp_container, &doc->IUnknown_inner, HTMLDocumentObj_cpc); HTMLDocumentObj_Persist_Init(doc); HTMLDocumentObj_Service_Init(doc); diff --git a/dlls/mshtml/tests/dom.c b/dlls/mshtml/tests/dom.c index 70b047ccbe1..c31de136cd8 100644 --- a/dlls/mshtml/tests/dom.c +++ b/dlls/mshtml/tests/dom.c @@ -9477,10 +9477,37 @@ static void test_elems(IHTMLDocument2 *doc) elem = get_doc_elem_by_id(doc, L"objid"); ok(elem != NULL, "elem == NULL\n"); if(elem) { + IDispatchEx *dispex = get_dispex_iface((IUnknown*)doc); + DISPPARAMS dp = { 0 }; + DISPID dispid; + VARIANT var; + BSTR name; + test_object_vspace((IUnknown*)elem, 100); test_object_name(elem, L"objname"); + + name = SysAllocString(L"objname"); + hres = IDispatchEx_GetDispID(dispex, name, fdexNameCaseSensitive, &dispid); + ok(hres == S_OK, "GetDispID(objname) returned: %08lx\n", hres); + SysFreeString(name); + + hres = IDispatchEx_Invoke(dispex, dispid, &IID_NULL, 0, DISPATCH_PROPERTYGET, &dp, &var, NULL, NULL); + ok(hres == S_OK, "Invoke(objname) failed: %08lx\n", hres); + ok(V_VT(&var) == VT_DISPATCH, "VT = %d\n", V_VT(&var)); + ok(V_DISPATCH(&var) != NULL, "objname = null\n"); + + elem2 = get_elem_iface((IUnknown*)V_DISPATCH(&var)); + IDispatch_Release(V_DISPATCH(&var)); + + test_object_vspace((IUnknown*)elem2, 100); + test_object_name(elem2, L"objname"); + todo_wine + ok(elem != elem2, "elem == elem2\n"); + IHTMLElement_Release(elem2); + set_object_name(elem, L"test"); set_object_name(elem, NULL); + IDispatchEx_Release(dispex); IHTMLElement_Release(elem); }
diff --git a/dlls/mshtml/tests/events.c b/dlls/mshtml/tests/events.c index b6a0c32d8a8..b9ae375640b 100644 --- a/dlls/mshtml/tests/events.c +++ b/dlls/mshtml/tests/events.c @@ -133,6 +133,14 @@ static const char readystate_doc_ie9_str[] = "<head><meta http-equiv="x-ua-compatible" content="IE=9" /></head>" "<body><iframe id="iframe"></iframe></body></html>";
+static const char doc_with_prop_str[] = + "<html><body onload="document.prop = 137;"></body></html>"; + +static const char doc_with_prop_ie9_str[] = + "<html>" + "<head><meta http-equiv="x-ua-compatible" content="IE=9" /></head>" + "<body onload="document.prop = 137;"></body></html>"; + static const char img_doc_str[] = "<html><body><img id="imgid"></img></body></html>";
@@ -4257,11 +4265,14 @@ done: static void test_doc_obj(const char *doc_str) { IHTMLDocument2 *doc = create_document_with_origin(L"http://winetest.example.org", doc_str); + DISPID dispid, import_node_id, has_own_prop_id; IEventTarget *event_target; + DISPPARAMS dp = { 0 }; IHTMLDocument6 *doc6; + IDispatchEx *dispex; IHTMLElement *body; + VARIANT res, arg; HRESULT hres; - VARIANT res; BSTR bstr;
hres = IHTMLDocument2_QueryInterface(doc, &IID_IHTMLDocument6, (void**)&doc6); @@ -4313,9 +4324,74 @@ static void test_doc_obj(const char *doc_str) ok(!wcscmp(bstr, (document_mode < 9 ? L"[object]" : L"[object Document]")), "toString returned %s\n", wine_dbgstr_w(bstr)); SysFreeString(bstr);
+ /* IHTMLDocument6 prop */ + bstr = SysAllocString(L"onstoragecommit"); + hres = IHTMLDocument2_GetIDsOfNames(doc, &IID_NULL, &bstr, 1, 0, &dispid); + ok(hres == S_OK, "GetIDsOfNames(onstoragecommit) returned: %08lx\n", hres); + SysFreeString(bstr); + + /* IHTMLDocument7 method */ + bstr = SysAllocString(L"importNode"); + hres = IHTMLDocument2_GetIDsOfNames(doc, &IID_NULL, &bstr, 1, 0, &dispid); + ok(hres == (document_mode < 9 ? DISP_E_UNKNOWNNAME : S_OK), "GetIDsOfNames(importNode) returned: %08lx\n", hres); + + hres = IHTMLDocument2_QueryInterface(doc, &IID_IDispatchEx, (void**)&dispex); + ok(hres == S_OK, "Could not get IDispatchEx: %08lx\n", hres); + + hres = IDispatchEx_GetDispID(dispex, bstr, fdexNameEnsure, &import_node_id); + ok(hres == S_OK, "GetDispID(importNode) returned: %08lx\n", hres); + if(document_mode >= 9) + ok(import_node_id == dispid, "GetDispID(importNode) != GetIDsOfNames(importNode)\n"); + IDispatchEx_Release(dispex); + SysFreeString(bstr); + + /* prop set via script on node */ + bstr = SysAllocString(L"prop"); + hres = IHTMLDocument2_GetIDsOfNames(doc, &IID_NULL, &bstr, 1, 0, &dispid); + ok(hres == S_OK, "GetIDsOfNames(prop) returned: %08lx\n", hres); + SysFreeString(bstr); + + hres = IHTMLDocument2_Invoke(doc, dispid, &IID_NULL, 0, DISPATCH_PROPERTYGET, &dp, &res, NULL, NULL); + ok(hres == S_OK, "Invoke(prop) failed: %08lx\n", hres); + ok(V_VT(&res) == VT_I4, "VT(prop) = %d\n", V_VT(&res)); + ok(V_I4(&res) == 137, "prop = %ld\n", V_I4(&res)); + + /* jscript prop on prototype chain */ + bstr = SysAllocString(L"hasOwnProperty"); + hres = IHTMLDocument2_GetIDsOfNames(doc, &IID_NULL, &bstr, 1, 0, &has_own_prop_id); + todo_wine_if(document_mode >= 9) + ok(hres == (document_mode < 9 ? DISP_E_UNKNOWNNAME : S_OK), "GetIDsOfNames(hasOwnProperty) returned: %08lx\n", hres); + SysFreeString(bstr); + + if(hres == S_OK) { + dp.cArgs = 1; + dp.rgvarg = &arg; + V_VT(&arg) = VT_BSTR; + V_BSTR(&arg) = SysAllocString(L"createElement"); + hres = IHTMLDocument2_Invoke(doc, has_own_prop_id, &IID_NULL, 0, DISPATCH_METHOD, &dp, &res, NULL, NULL); + ok(hres == S_OK, "Invoke(hasOwnProperty("createElement")) failed: %08lx\n", hres); + ok(V_VT(&res) == VT_BOOL, "VT = %d\n", V_VT(&res)); + todo_wine + ok(V_BOOL(&res) == VARIANT_FALSE, "hasOwnProperty("createElement") = %d\n", V_BOOL(&res)); + + hres = IHTMLDocument2_GetIDsOfNames(doc, &IID_NULL, &V_BSTR(&arg), 1, 0, &dispid); + ok(hres == S_OK, "GetIDsOfNames(createElement) returned: %08lx\n", hres); + SysFreeString(V_BSTR(&arg)); + + V_BSTR(&arg) = SysAllocString(L"prop"); + hres = IHTMLDocument2_Invoke(doc, has_own_prop_id, &IID_NULL, 0, DISPATCH_METHOD, &dp, &res, NULL, NULL); + ok(hres == S_OK, "Invoke(hasOwnProperty("prop")) failed: %08lx\n", hres); + ok(V_VT(&res) == VT_BOOL, "VT = %d\n", V_VT(&res)); + ok(V_BOOL(&res) == VARIANT_TRUE, "hasOwnProperty("prop") = %d\n", V_BOOL(&res)); + SysFreeString(V_BSTR(&arg)); + } + /* Navigate to a different document mode page, checking using the same doc obj. Test that it breaks COM rules, since IEventTarget is conditionally exposed. - All the events registered on the old doc node are also removed. */ + All the events registered on the old doc node are also removed. + + DISPIDs are forwarded to the node, and thus it also breaks Dispatch rules, + where the same name will potentially receive a different DISPID. */ protocol_doc_str = document_mode < 9 ? empty_doc_ie9_str : empty_doc_str; navigate(doc, L"http://winetest.example.org/foobar");
@@ -4340,10 +4416,25 @@ static void test_doc_obj(const char *doc_str) ok(hres == S_OK, "click failed: %08lx\n", hres); IHTMLElement_Release(body); pump_msgs(NULL); + + hres = IHTMLDocument2_QueryInterface(doc, &IID_IDispatchEx, (void**)&dispex); + ok(hres == S_OK, "Could not get IDispatchEx: %08lx\n", hres); + + bstr = SysAllocString(L"importNode"); + hres = IDispatchEx_GetDispID(dispex, bstr, fdexNameEnsure, &dispid); + ok(hres == S_OK, "GetDispID(importNode) returned: %08lx\n", hres); + ok(dispid != import_node_id, "importNode on new doc node == old importNode\n"); + IDispatchEx_Release(dispex); + SysFreeString(bstr); }else { ok(hres == S_OK, "hres = %08lx, expected S_OK\n", hres); ok(!!event_target, "event_target = NULL\n"); IEventTarget_Release(event_target); + + bstr = SysAllocString(L"importNode"); + hres = IHTMLDocument2_GetIDsOfNames(doc, &IID_NULL, &bstr, 1, 0, &dispid); + ok(hres == S_OK, "GetIDsOfNames(importNode) returned: %08lx\n", hres); + ok(dispid != import_node_id, "importNode on new doc node == old created importNode\n"); }
set_client_site(doc, FALSE); @@ -4405,8 +4496,8 @@ START_TEST(events) test_storage_events(empty_doc_str); if(is_ie9plus) { test_storage_events(empty_doc_ie9_str); - test_doc_obj(empty_doc_str); - test_doc_obj(empty_doc_ie9_str); + test_doc_obj(doc_with_prop_str); + test_doc_obj(doc_with_prop_ie9_str); }
DestroyWindow(container_hwnd);
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Native ignores any cNames > 1 and doesn't even fill the dispids for them. Note that it was already wrong; the multiple dispids are supposed to correspond to the member's argument names, not extra dispids.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/dispex.c | 13 ++-- dlls/mshtml/htmlwindow.c | 12 ++-- dlls/mshtml/tests/dom.c | 101 +++++++++++++++++++++++++++++ dlls/mshtml/tests/xmlhttprequest.c | 31 +++++++++ 4 files changed, 142 insertions(+), 15 deletions(-)
diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index d8aaf819f58..c70deb67209 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -1636,19 +1636,16 @@ static HRESULT WINAPI DispatchEx_GetIDsOfNames(IDispatchEx *iface, REFIID riid, LCID lcid, DISPID *rgDispId) { DispatchEx *This = impl_from_IDispatchEx(iface); - UINT i; - HRESULT hres; + HRESULT hres = S_OK;
TRACE("(%p)->(%s %p %u %lu %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
- for(i=0; i < cNames; i++) { - hres = IDispatchEx_GetDispID(&This->IDispatchEx_iface, rgszNames[i], 0, rgDispId+i); - if(FAILED(hres)) - return hres; - } + /* Native ignores all cNames > 1, and doesn't even fill them */ + if(cNames) + hres = IDispatchEx_GetDispID(&This->IDispatchEx_iface, rgszNames[0], 0, rgDispId);
- return S_OK; + return hres; }
static HRESULT WINAPI DispatchEx_Invoke(IDispatchEx *iface, DISPID dispIdMember, diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index 7014a4cd4b4..c2475afd1f6 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -3476,19 +3476,17 @@ static HRESULT WINAPI WindowDispEx_GetIDsOfNames(IDispatchEx *iface, REFIID riid LCID lcid, DISPID *rgDispId) { HTMLWindow *This = impl_from_IDispatchEx(iface); - UINT i; - HRESULT hres; + HRESULT hres = S_OK;
WARN("(%p)->(%s %p %u %lu %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
- for(i=0; i < cNames; i++) { + /* Native ignores all cNames > 1, and doesn't even fill them */ + if(cNames) { /* We shouldn't use script's IDispatchEx here, so we shouldn't use GetDispID */ - hres = IDispatchEx_GetDispID(&This->IDispatchEx_iface, rgszNames[i], 0, rgDispId+i); - if(FAILED(hres)) - return hres; + hres = IDispatchEx_GetDispID(&This->IDispatchEx_iface, rgszNames[0], 0, rgDispId); }
- return S_OK; + return hres; }
static HRESULT WINAPI WindowDispEx_Invoke(IDispatchEx *iface, DISPID dispIdMember, diff --git a/dlls/mshtml/tests/dom.c b/dlls/mshtml/tests/dom.c index c31de136cd8..4e6ad469b28 100644 --- a/dlls/mshtml/tests/dom.c +++ b/dlls/mshtml/tests/dom.c @@ -27,6 +27,7 @@ #include "ole2.h" #include "mshtml.h" #include "mshtmcid.h" +#include "mshtmdid.h" #include "mshtmhst.h" #include "docobj.h" #include "hlink.h" @@ -5288,6 +5289,98 @@ static void _test_doc_set_title(unsigned line, IHTMLDocument2 *doc, const WCHAR SysFreeString(tmp); }
+static void test_doc_GetIDsOfNames(IHTMLDocument2 *doc) +{ + DISPID dispids[3]; + HRESULT hres; + BSTR bstr[3]; + + bstr[0] = SysAllocString(L"createStyleSheet"); + bstr[1] = SysAllocString(L"bstrHref"); + bstr[2] = SysAllocString(L"lIndex"); + dispids[0] = 0; + dispids[1] = 0xdead; + dispids[2] = 0xbeef; + hres = IHTMLDocument2_GetIDsOfNames(doc, &IID_NULL, bstr, 3, 0, dispids); + ok(hres == S_OK, "GetIDsOfNames failed: %08lx\n", hres); + ok(dispids[0] == DISPID_IHTMLDOCUMENT2_CREATESTYLESHEET, "createStyleSheet dispid = %ld\n", dispids[0]); + ok(dispids[1] == 0xdead, "bstrHref dispid = %ld\n", dispids[1]); + ok(dispids[2] == 0xbeef, "lIndex dispid = %ld\n", dispids[2]); + SysFreeString(bstr[2]); + SysFreeString(bstr[1]); + SysFreeString(bstr[0]); +} + +static void test_window_GetIDsOfNames(IHTMLWindow2 *window) +{ + DISPID dispids[3]; + HRESULT hres; + BSTR bstr[3]; + + bstr[0] = SysAllocString(L"showHelp"); + bstr[1] = SysAllocString(L"helpURL"); + bstr[2] = SysAllocString(L"helpArg"); + dispids[0] = 0; + dispids[1] = 0xdead; + dispids[2] = 0xbeef; + hres = IHTMLWindow2_GetIDsOfNames(window, &IID_NULL, bstr, 3, 0, dispids); + ok(hres == S_OK, "GetIDsOfNames failed: %08lx\n", hres); + ok(dispids[0] == DISPID_IHTMLWINDOW2_SHOWHELP, "showHelp dispid = %ld\n", dispids[0]); + ok(dispids[1] == 0xdead, "helpURL dispid = %ld\n", dispids[1]); + ok(dispids[2] == 0xbeef, "helpArg dispid = %ld\n", dispids[2]); + SysFreeString(bstr[2]); + SysFreeString(bstr[1]); + SysFreeString(bstr[0]); +} + +static void test_elem_GetIDsOfNames(IHTMLElement *elem) +{ + DISPID dispids[3]; + HRESULT hres; + BSTR bstr[3]; + + /* IE9+ use something like js proxies even on native and have different dispids */ + if(compat_mode >= COMPAT_IE9) + return; + + bstr[0] = SysAllocString(L"insertAdjacentText"); + bstr[1] = SysAllocString(L"where"); + bstr[2] = SysAllocString(L"text"); + dispids[0] = 0; + dispids[1] = 0xdead; + dispids[2] = 0xbeef; + hres = IHTMLElement_GetIDsOfNames(elem, &IID_NULL, bstr, 3, 0, dispids); + ok(hres == S_OK, "GetIDsOfNames failed: %08lx\n", hres); + ok(dispids[0] == DISPID_IHTMLELEMENT_INSERTADJACENTTEXT, "insertAdjacentText dispid = %ld\n", dispids[0]); + ok(dispids[1] == 0xdead, "where dispid = %ld\n", dispids[1]); + ok(dispids[2] == 0xbeef, "text dispid = %ld\n", dispids[2]); + SysFreeString(bstr[2]); + SysFreeString(bstr[1]); + SysFreeString(bstr[0]); +} + +static void test_attr_GetIDsOfNames(IHTMLDOMAttribute *attr) +{ + DISPID dispids[3]; + HRESULT hres; + BSTR bstr[3]; + + bstr[0] = SysAllocString(L"insertBefore"); + bstr[1] = SysAllocString(L"newChild"); + bstr[2] = SysAllocString(L"refChild"); + dispids[0] = 0; + dispids[1] = 0xdead; + dispids[2] = 0xbeef; + hres = IHTMLDOMAttribute_GetIDsOfNames(attr, &IID_NULL, bstr, 3, 0, dispids); + ok(hres == S_OK, "GetIDsOfNames failed: %08lx\n", hres); + ok(dispids[0] == DISPID_IHTMLDOMATTRIBUTE2_INSERTBEFORE, "insertBefore dispid = %ld\n", dispids[0]); + ok(dispids[1] == 0xdead, "newChild dispid = %ld\n", dispids[1]); + ok(dispids[2] == 0xbeef, "refChild dispid = %ld\n", dispids[2]); + SysFreeString(bstr[2]); + SysFreeString(bstr[1]); + SysFreeString(bstr[0]); +} + static void test_elem_bounding_client_rect(IUnknown *unk) { IHTMLRectCollection *rects; @@ -5462,6 +5555,7 @@ static IHTMLElement *get_elem_by_id(IHTMLDocument2 *doc, const WCHAR *id, BOOL e elem = get_elem_iface((IUnknown*)disp); IDispatch_Release(disp);
+ test_elem_GetIDsOfNames(elem); return elem; }
@@ -5482,6 +5576,8 @@ static IHTMLElement *get_doc_elem_by_id(IHTMLDocument2 *doc, const WCHAR *id)
IHTMLDocument3_Release(doc3);
+ if(elem) + test_elem_GetIDsOfNames(elem); return elem; }
@@ -6854,6 +6950,8 @@ static void test_doc_elem(IHTMLDocument2 *doc) HRESULT hres; BSTR bstr;
+ test_doc_GetIDsOfNames(doc); + hres = IHTMLDocument2_QueryInterface(doc, &IID_IHTMLDocument3, (void**)&doc3); ok(hres == S_OK, "QueryInterface(IID_IHTMLDocument3) failed: %08lx\n", hres);
@@ -6875,6 +6973,7 @@ static void test_doc_elem(IHTMLDocument2 *doc) owner_doc = get_owner_doc((IUnknown*)elem); ok(iface_cmp((IUnknown *)doc_node, (IUnknown *)owner_doc), "doc_node != owner_doc\n"); IHTMLDocument2_Release(owner_doc); + test_doc_GetIDsOfNames(doc_node);
owner_doc = get_owner_doc((IUnknown*)doc_node); ok(!owner_doc, "owner_doc = %p\n", owner_doc); @@ -7158,6 +7257,7 @@ static void test_window(IHTMLDocument2 *doc) win_skip("IID_ITravelLogClient not supported\n");
test_disp((IUnknown*)window, &DIID_DispHTMLWindow2, &CLSID_HTMLWindow2, L"[object]"); + test_window_GetIDsOfNames(window);
hres = IHTMLWindow2_get_document(window, &doc2); ok(hres == S_OK, "get_document failed: %08lx\n", hres); @@ -9796,6 +9896,7 @@ static void test_attr(IHTMLDocument2 *doc, IHTMLElement *elem) test_no_iface((IUnknown*)attr, &IID_IHTMLDOMNode); test_attr_specified(attr, VARIANT_TRUE); test_attr_parent(attr); + test_attr_GetIDsOfNames(attr);
attr2 = get_elem_attr_node((IUnknown*)elem, L"id", TRUE); ok(iface_cmp((IUnknown*)attr, (IUnknown*)attr2), "attr != attr2\n"); diff --git a/dlls/mshtml/tests/xmlhttprequest.c b/dlls/mshtml/tests/xmlhttprequest.c index 6aef9f5a35d..a3ec54ffef6 100644 --- a/dlls/mshtml/tests/xmlhttprequest.c +++ b/dlls/mshtml/tests/xmlhttprequest.c @@ -25,6 +25,7 @@ #include "winbase.h" #include "ole2.h" #include "mshtml.h" +#include "mshtmdid.h" #include "objsafe.h" #include "wine/test.h"
@@ -402,6 +403,35 @@ static void create_xmlhttprequest(IHTMLDocument2 *doc) ok(xhr != NULL, "xhr == NULL\n"); }
+static void test_GetIDsOfNames(IHTMLDocument2 *doc) +{ + DISPID dispids[3]; + HRESULT hres; + BSTR bstr[3]; + + create_xmlhttprequest(doc); + if(!xhr) + return; + + bstr[0] = SysAllocString(L"open"); + bstr[1] = SysAllocString(L"bstrMethod"); + bstr[2] = SysAllocString(L"varAsync"); + dispids[0] = 0; + dispids[1] = 0xdead; + dispids[2] = 0xbeef; + hres = IHTMLXMLHttpRequest_GetIDsOfNames(xhr, &IID_NULL, bstr, 3, 0, dispids); + ok(hres == S_OK, "GetIDsOfNames failed: %08lx\n", hres); + ok(dispids[0] == DISPID_IHTMLXMLHTTPREQUEST_OPEN, "open dispid = %ld\n", dispids[0]); + ok(dispids[1] == 0xdead, "bstrMethod dispid = %ld\n", dispids[1]); + ok(dispids[2] == 0xbeef, "varAsync dispid = %ld\n", dispids[2]); + SysFreeString(bstr[2]); + SysFreeString(bstr[1]); + SysFreeString(bstr[0]); + + IHTMLXMLHttpRequest_Release(xhr); + xhr = NULL; +} + static void test_header(const struct HEADER_TYPE expect[], int num) { int i; @@ -1100,6 +1130,7 @@ START_TEST(xmlhttprequest) content_type = SysAllocString(L"Content-Type"); doc = create_doc_from_url(start_url); if(doc) { + test_GetIDsOfNames(doc); test_sync_xhr(doc, xml_url, expect_response_text); test_sync_xhr(doc, large_page_url, NULL); test_async_xhr(doc, xml_url, expect_response_text);
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 tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=126077
Your paranoid android.
=== w10pro64 (32 bit report) ===
mshtml: events.c:1116: Test failed: unexpected call img_onerror events: Timeout
=== w10pro64 (64 bit report) ===
mshtml: events.c:1116: Test failed: unexpected call img_onerror events: Timeout
On Fri Nov 11 18:24:52 2022 +0000, Gabriel Ivăncescu wrote:
Unfortunately those don't help. The Protocol handler is not called at all after the navigation is issued (tracing all the methods). Even reporting the mime type on the old page didn't change a thing. It's also useful to note that this happens on all navigations, not just `put_href`. `replace` for example, but also `window.navigate` or `window.open` (with _self obviously). However, I looked at why `navigation.js` works, since it navigates, but it turns out this is only an issue on top-level windows. iframes work fine and do use the protocol handler (I changed the URL from `about:blank` to something with http for the handler, traced and it gets called…). I don't know if this is deliberate or a bug in Windows' urlmon. But it seems it ignores temporary pluggable namespace handlers when doing any sort of navigation on the top level window. But only the top-level. I resorted to keep the `IPersistMoniker_Load` way, but I had to add `IHlinkTarget_Navigate`, otherwise unload events wouldn't be dispatched (this is for next MR, not tested here).
Note that it works fine in `test_put_href`, so it seems to be specific to something we do in events.c rather than a Windows bug.
On Fri Nov 11 19:55:15 2022 +0000, Jacek Caban wrote:
Note that it works fine in `test_put_href`, so it seems to be specific to something we do in events.c rather than a Windows bug.
It's only the temporary pluggable namespace handlers that seem bugged. `htmldoc.c` (and `test_put_href`) doesn't use that, it uses real URLs, but it doesn't really test compat modes there though.
On Fri Nov 11 20:43:05 2022 +0000, Gabriel Ivăncescu wrote:
It's only the temporary pluggable namespace handlers that seem bugged. `htmldoc.c` (and `test_put_href`) doesn't use that, it uses real URLs, but it doesn't really test compat modes there though.
The theory about pluggable protocols does not sound convincing, but you don't really need them for those tests. You could, for example, use res: protocol.
On Fri Nov 11 20:57:33 2022 +0000, Jacek Caban wrote:
The theory about pluggable protocols does not sound convincing, but you don't really need them for those tests. You could, for example, use res: protocol.
So I managed to finally get it done with some hurdles. I used res protocol now, but native gave E_ACCESSDENIED when navigating unless the source was also from a res (with some extra things after load, like `IHlinkTarget_Navigate`, I took it mostly from `htmldoc.c`).
Then, it still exhibited a similar issue as before, and I noticed even navigating to `about:blank` had the same issue while the one in htmldoc did not, so it turns out I had to include `IServiceProvider` implementation and a bunch of other interfaces exposed from the services, so most of the patch is now boilerplate with E_NOTIMPL methods, but it finally works.