-- v3: mshtml: Return proper errors when navigating with no browser. mshtml: Set outer window to uninitialized page when document obj is released.
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmlwindow.c | 2 +- dlls/mshtml/navigate.c | 5 +- dlls/mshtml/nsevents.c | 8 ++-- dlls/mshtml/oleobj.c | 71 +++++++++++++++++++++++++++- dlls/mshtml/tests/events.c | 92 +++++++++++++++++++++++++++++++++++++ dlls/mshtml/tests/htmldoc.c | 36 ++++++++++++++- dlls/mshtml/tests/script.c | 17 +++++++ 7 files changed, 222 insertions(+), 9 deletions(-)
diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index 2034ae8487a..388a8ddd1e8 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -2906,7 +2906,7 @@ static HRESULT WINAPI HTMLPrivateWindow_GetAddressBarUrl(IHTMLPrivateWindow *ifa if(!url) return E_INVALIDARG;
- *url = SysAllocString(This->outer_window->url); + *url = SysAllocString(This->outer_window->url ? This->outer_window->url : L"about:blank"); return S_OK; }
diff --git a/dlls/mshtml/navigate.c b/dlls/mshtml/navigate.c index 8172abd8040..53f18bdc8d6 100644 --- a/dlls/mshtml/navigate.c +++ b/dlls/mshtml/navigate.c @@ -1012,7 +1012,10 @@ static HRESULT on_start_nsrequest(nsChannelBSC *This)
if(This->bsc.binding) process_document_response_headers(This->bsc.window->doc, This->bsc.binding); - if(This->bsc.window->base.outer_window->readystate != READYSTATE_LOADING) + + if(!(This->bsc.bindf & BINDF_ASYNCHRONOUS)) + This->bsc.window->doc->skip_mutation_notif = TRUE; + else if(This->bsc.window->base.outer_window->readystate != READYSTATE_LOADING) set_ready_state(This->bsc.window->base.outer_window, READYSTATE_LOADING); }
diff --git a/dlls/mshtml/nsevents.c b/dlls/mshtml/nsevents.c index 78a54c83955..7bbddd33d2b 100644 --- a/dlls/mshtml/nsevents.c +++ b/dlls/mshtml/nsevents.c @@ -190,7 +190,7 @@ static nsresult handle_blur(HTMLDocumentNode *doc, nsIDOMEvent *event)
TRACE("(%p)\n", doc);
- if(!doc->doc_obj) + if(doc->skip_mutation_notif || !doc->doc_obj) return NS_ERROR_FAILURE; doc_obj = doc->doc_obj;
@@ -208,6 +208,8 @@ static nsresult handle_focus(HTMLDocumentNode *doc, nsIDOMEvent *event)
TRACE("(%p)\n", doc);
+ if(doc->skip_mutation_notif || !doc->doc_obj) + return NS_ERROR_FAILURE; doc_obj = doc->doc_obj;
if(!doc_obj->focus) { @@ -336,7 +338,7 @@ static nsresult handle_load(HTMLDocumentNode *doc, nsIDOMEvent *event)
if(!doc->outer_window) return NS_ERROR_FAILURE; - if(doc->doc_obj && doc->doc_obj->doc_node == doc) { + if(!doc->skip_mutation_notif && doc->doc_obj && doc->doc_obj->doc_node == doc) { doc_obj = doc->doc_obj; IUnknown_AddRef(doc_obj->outer_unk); } @@ -391,7 +393,7 @@ static nsresult handle_beforeunload(HTMLDocumentNode *doc, nsIDOMEvent *nsevent) DOMEvent *event; HRESULT hres;
- if(!(window = doc->window)) + if(!(window = doc->window) || doc->unload_sent) return NS_OK;
/* Gecko dispatches this to the document, but IE dispatches it to the window */ diff --git a/dlls/mshtml/oleobj.c b/dlls/mshtml/oleobj.c index 870500ff0ab..e104a61e0fb 100644 --- a/dlls/mshtml/oleobj.c +++ b/dlls/mshtml/oleobj.c @@ -35,6 +35,7 @@
#include "mshtml_private.h" #include "htmlevent.h" +#include "binding.h"
WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
@@ -3403,6 +3404,60 @@ static ULONG WINAPI HTMLDocumentObj_AddRef(IUnknown *iface) return ref; }
+static void set_window_uninitialized(HTMLOuterWindow *window) +{ + nsChannelBSC *channelbsc; + nsWineURI *nsuri; + IMoniker *mon; + HRESULT hres; + IUri *uri; + + window->readystate = READYSTATE_UNINITIALIZED; + set_current_uri(window, NULL); + if(window->mon) { + IMoniker_Release(window->mon); + window->mon = NULL; + } + + if(!window->base.inner_window) + return; + + hres = create_uri(L"about:blank", 0, &uri); + if(FAILED(hres)) + return; + + hres = create_doc_uri(uri, &nsuri); + IUri_Release(uri); + if(FAILED(hres)) + return; + + hres = CreateURLMoniker(NULL, L"about:blank", &mon); + if(SUCCEEDED(hres)) { + hres = create_channelbsc(mon, NULL, NULL, 0, TRUE, &channelbsc); + IMoniker_Release(mon); + + if(SUCCEEDED(hres)) { + channelbsc->bsc.bindf = 0; /* synchronous binding */ + + if(window->base.inner_window->doc) + remove_target_tasks(window->base.inner_window->task_magic); + abort_window_bindings(window->base.inner_window); + + hres = load_nsuri(window, nsuri, NULL, channelbsc, LOAD_FLAGS_BYPASS_CACHE); + if(SUCCEEDED(hres)) + hres = create_pending_window(window, channelbsc); + IBindStatusCallback_Release(&channelbsc->bsc.IBindStatusCallback_iface); + } + } + nsISupports_Release((nsISupports*)nsuri); + if(FAILED(hres)) + return; + + window->load_flags |= BINDING_REPLACE; + window->base.inner_window->doc->unload_sent = TRUE; + start_binding(window->pending_window, &window->pending_window->bscallback->bsc, NULL); +} + static ULONG WINAPI HTMLDocumentObj_Release(IUnknown *iface) { HTMLDocumentObj *This = impl_from_IUnknown(iface); @@ -3412,8 +3467,20 @@ static ULONG WINAPI HTMLDocumentObj_Release(IUnknown *iface)
if(!ref) { if(This->doc_node) { - This->doc_node->doc_obj = NULL; - IHTMLDOMNode_Release(&This->doc_node->node.IHTMLDOMNode_iface); + /* Protect against re-entry by grabbing it here */ + This->ref++; + set_window_uninitialized(This->window); + + if(This->doc_node) { + HTMLDocumentNode *doc_node = This->doc_node; + + This->doc_node = NULL; + doc_node->doc_obj = NULL; + IHTMLDOMNode_Release(&doc_node->node.IHTMLDOMNode_iface); + } + + /* Since we grabbed it, releasing it here will take care of freeing it */ + return HTMLDocumentObj_Release(&This->IUnknown_inner); } if(This->window) IHTMLWindow2_Release(&This->window->base.IHTMLWindow2_iface); diff --git a/dlls/mshtml/tests/events.c b/dlls/mshtml/tests/events.c index f972c2a8316..a4b50b91fa6 100644 --- a/dlls/mshtml/tests/events.c +++ b/dlls/mshtml/tests/events.c @@ -5999,6 +5999,97 @@ static void test_empty_document(void) IHTMLDocument2_Release(doc); }
+static void test_document_close(void) +{ + IHTMLPrivateWindow *priv_window; + IHTMLDocument2 *doc, *doc_node; + IHTMLDocument3 *doc3; + IHTMLWindow2 *window; + IHTMLElement *elem; + HRESULT hres; + BSTR bstr; + + doc = create_document_with_origin(input_doc_str); + if(!doc) + return; + + hres = IHTMLDocument2_get_parentWindow(doc, &window); + ok(hres == S_OK, "get_parentWindow failed: %08lx\n", hres); + + hres = IHTMLWindow2_get_document(window, &doc_node); + ok(hres == S_OK, "get_document failed: %08lx\n", hres); + + hres = IHTMLWindow2_QueryInterface(window, &IID_IHTMLPrivateWindow, (void**)&priv_window); + ok(hres == S_OK, "Could not get IHTMLPrivateWindow) interface: %08lx\n", hres); + hres = IHTMLPrivateWindow_GetAddressBarUrl(priv_window, &bstr); + ok(hres == S_OK, "GetAddressBarUrl failed: %08lx\n", hres); + ok(!wcscmp(bstr, L"http://winetest.example.org/"), "unexpected address bar: %s\n", wine_dbgstr_w(bstr)); + IHTMLPrivateWindow_Release(priv_window); + SysFreeString(bstr); + + elem = get_elem_id(doc_node, L"inputid"); + IHTMLElement_Release(elem); + + set_client_site(doc, FALSE); + IHTMLDocument2_Release(doc); + + hres = IHTMLWindow2_get_document(window, &doc); + ok(hres == S_OK, "get_document failed: %08lx\n", hres); + ok(doc != doc_node, "doc == doc_node\n"); + + hres = IHTMLDocument2_get_readyState(doc_node, &bstr); + ok(hres == S_OK, "get_readyState failed: %08lx\n", hres); + ok(!wcscmp(bstr, L"uninitialized"), "readyState = %s\n", wine_dbgstr_w(bstr)); + SysFreeString(bstr); + + hres = IHTMLDocument2_get_readyState(doc, &bstr); + ok(hres == S_OK, "get_readyState failed: %08lx\n", hres); + ok(!wcscmp(bstr, L"uninitialized"), "readyState = %s\n", wine_dbgstr_w(bstr)); + SysFreeString(bstr); + + hres = IHTMLWindow2_QueryInterface(window, &IID_IHTMLPrivateWindow, (void**)&priv_window); + ok(hres == S_OK, "Could not get IHTMLPrivateWindow) interface: %08lx\n", hres); + hres = IHTMLPrivateWindow_GetAddressBarUrl(priv_window, &bstr); + ok(hres == S_OK, "GetAddressBarUrl failed: %08lx\n", hres); + ok(!wcscmp(bstr, L"about:blank"), "unexpected address bar: %s\n", wine_dbgstr_w(bstr)); + IHTMLPrivateWindow_Release(priv_window); + SysFreeString(bstr); + + bstr = SysAllocString(L"inputid"); + doc3 = get_doc3_iface((IUnknown*)doc); + hres = IHTMLDocument3_getElementById(doc3, bstr, &elem); + ok(hres == S_OK, "getElementById returned: %08lx\n", hres); + ok(elem == NULL, "elem != NULL\n"); + IHTMLDocument3_Release(doc3); + SysFreeString(bstr); + + IHTMLDocument2_Release(doc_node); + IHTMLDocument2_Release(doc); + IHTMLWindow2_Release(window); + + doc = create_document(); + if(!doc) + return; + set_client_site(doc, TRUE); + + hres = IHTMLDocument2_get_parentWindow(doc, &window); + ok(hres == S_OK, "get_parentWindow failed: %08lx\n", hres); + + hres = IHTMLWindow2_get_document(window, &doc_node); + ok(hres == S_OK, "get_document failed: %08lx\n", hres); + + set_client_site(doc, FALSE); + IHTMLDocument2_Release(doc); + + hres = IHTMLWindow2_get_document(window, &doc); + ok(hres == S_OK, "get_document failed: %08lx\n", hres); + ok(doc != doc_node, "doc == doc_node\n"); + + IHTMLDocument2_Release(doc_node); + IHTMLDocument2_Release(doc); + IHTMLWindow2_Release(window); +} + static void test_storage_events(const char *doc_str) { static struct { @@ -6365,6 +6456,7 @@ START_TEST(events) }
test_empty_document(); + test_document_close(); test_storage_events(empty_doc_str); test_sync_xhr_events(empty_doc_str); if(is_ie9plus) { diff --git a/dlls/mshtml/tests/htmldoc.c b/dlls/mshtml/tests/htmldoc.c index 9874540e973..4db4777dca4 100644 --- a/dlls/mshtml/tests/htmldoc.c +++ b/dlls/mshtml/tests/htmldoc.c @@ -8461,10 +8461,12 @@ static void test_doc_domain(IHTMLDocument2 *doc)
static void test_HTMLDocument_http(BOOL with_wbapp) { + IHTMLDocument2 *doc, *doc_node; + IHTMLWindow2 *window; IMoniker *http_mon; - IHTMLDocument2 *doc; - ULONG ref; HRESULT hres; + ULONG ref; + BSTR bstr;
trace("Testing HTMLDocument (http%s)...\n", with_wbapp ? " with IWebBrowserApp" : "");
@@ -8529,12 +8531,42 @@ static void test_HTMLDocument_http(BOOL with_wbapp) test_IsDirty(doc, S_FALSE); test_GetCurMoniker((IUnknown*)doc, NULL, prev_url, support_wbapp);
+ hres = IHTMLDocument2_get_parentWindow(doc, &window); + ok(hres == S_OK, "get_parentWindow failed: %08lx\n", hres); + + hres = IHTMLWindow2_get_document(window, &doc_node); + ok(hres == S_OK, "get_document failed: %08lx\n", hres); + + hres = IHTMLDocument2_get_readyState(doc_node, &bstr); + ok(hres == S_OK, "get_readyState failed: %08lx\n", hres); + todo_wine_if(support_wbapp) + ok(!wcscmp(bstr, support_wbapp ? L"interactive" : L"complete"), "readyState = %s\n", wine_dbgstr_w(bstr)); + SysFreeString(bstr); + if(view) IOleDocumentView_Release(view); view = NULL;
release_document(doc);
+ hres = IHTMLWindow2_get_document(window, &doc); + ok(hres == S_OK, "get_document failed: %08lx\n", hres); + ok(doc != doc_node, "doc == doc_node\n"); + + hres = IHTMLDocument2_get_readyState(doc_node, &bstr); + ok(hres == S_OK, "get_readyState failed: %08lx\n", hres); + ok(!wcscmp(bstr, L"uninitialized"), "readyState = %s\n", wine_dbgstr_w(bstr)); + SysFreeString(bstr); + + hres = IHTMLDocument2_get_readyState(doc, &bstr); + ok(hres == S_OK, "get_readyState failed: %08lx\n", hres); + ok(!wcscmp(bstr, L"uninitialized"), "readyState = %s\n", wine_dbgstr_w(bstr)); + SysFreeString(bstr); + + IHTMLDocument2_Release(doc_node); + IHTMLDocument2_Release(doc); + IHTMLWindow2_Release(window); + ref = IMoniker_Release(http_mon); ok(!ref, "ref=%ld, expected 0\n", ref); } diff --git a/dlls/mshtml/tests/script.c b/dlls/mshtml/tests/script.c index dc5dac98ee7..de1fd056169 100644 --- a/dlls/mshtml/tests/script.c +++ b/dlls/mshtml/tests/script.c @@ -4525,7 +4525,10 @@ static void test_exec_script(IHTMLDocument2 *doc, const WCHAR *codew, const WCHA
static void test_simple_script(void) { + IHTMLDocument2 *doc_node; + IHTMLWindow2 *window; IHTMLDocument2 *doc; + HRESULT hres;
doc = create_document(); if(!doc) @@ -4596,6 +4599,12 @@ static void test_simple_script(void) if(window_dispex) IDispatchEx_Release(window_dispex);
+ hres = IHTMLDocument2_get_parentWindow(doc, &window); + ok(hres == S_OK, "get_parentWindow failed: %08lx\n", hres); + + hres = IHTMLWindow2_get_document(window, &doc_node); + ok(hres == S_OK, "get_document failed: %08lx\n", hres); + SET_EXPECT(SetScriptState_DISCONNECTED); SET_EXPECT(Close); SET_EXPECT(Close2); @@ -4605,6 +4614,14 @@ static void test_simple_script(void) CHECK_CALLED(SetScriptState_DISCONNECTED); CHECK_CALLED(Close); CHECK_CALLED(Close2); + + hres = IHTMLWindow2_get_document(window, &doc); + ok(hres == S_OK, "get_document failed: %08lx\n", hres); + ok(doc != doc_node, "doc == doc_node\n"); + + IHTMLDocument2_Release(doc_node); + IHTMLDocument2_Release(doc); + IHTMLWindow2_Release(window); }
static void run_from_moniker(IMoniker *mon)
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmlwindow.c | 2 +- dlls/mshtml/navigate.c | 3 +++ dlls/mshtml/tests/events.c | 22 +++++++++++++++++++++- 3 files changed, 25 insertions(+), 2 deletions(-)
diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index 388a8ddd1e8..7bc2507619b 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -2832,7 +2832,7 @@ static HRESULT WINAPI HTMLPrivateWindow_SuperNavigate(IHTMLPrivateWindow *iface, FIXME("unimplemented flags %lx\n", flags & ~2);
if(!window || !window->browser) - return E_UNEXPECTED; + return E_FAIL;
if(window->browser->doc->hostui) { hres = IDocHostUIHandler_TranslateUrl(window->browser->doc->hostui, 0, url, &translated_url); diff --git a/dlls/mshtml/navigate.c b/dlls/mshtml/navigate.c index 53f18bdc8d6..9bc0c0db7d7 100644 --- a/dlls/mshtml/navigate.c +++ b/dlls/mshtml/navigate.c @@ -2681,6 +2681,9 @@ HRESULT navigate_url(HTMLOuterWindow *window, const WCHAR *new_url, IUri *base_u BSTR display_uri; HRESULT hres;
+ if(!window->browser) + return E_UNEXPECTED; + if(new_url && base_uri) hres = CoInternetCombineUrlEx(base_uri, new_url, URL_ESCAPE_SPACES_ONLY|URL_DONT_ESCAPE_EXTRA_INFO, &nav_uri, 0); diff --git a/dlls/mshtml/tests/events.c b/dlls/mshtml/tests/events.c index a4b50b91fa6..06c077d996d 100644 --- a/dlls/mshtml/tests/events.c +++ b/dlls/mshtml/tests/events.c @@ -6003,11 +6003,13 @@ static void test_document_close(void) { IHTMLPrivateWindow *priv_window; IHTMLDocument2 *doc, *doc_node; + IHTMLLocation *location; IHTMLDocument3 *doc3; IHTMLWindow2 *window; IHTMLElement *elem; + BSTR bstr, bstr2; HRESULT hres; - BSTR bstr; + VARIANT v;
doc = create_document_with_origin(input_doc_str); if(!doc) @@ -6087,6 +6089,24 @@ static void test_document_close(void)
IHTMLDocument2_Release(doc_node); IHTMLDocument2_Release(doc); + + bstr = SysAllocString(L"about:blank"); + hres = IHTMLWindow2_get_location(window, &location); + ok(hres == S_OK, "get_location failed: %08lx\n", hres); + hres = IHTMLLocation_put_href(location, bstr); + ok(hres == E_UNEXPECTED, "put_href returned: %08lx\n", hres); + IHTMLLocation_Release(location); + + V_VT(&v) = VT_EMPTY; + bstr2 = SysAllocString(L""); + hres = IHTMLWindow2_QueryInterface(window, &IID_IHTMLPrivateWindow, (void**)&priv_window); + ok(hres == S_OK, "Could not get IHTMLPrivateWindow) interface: %08lx\n", hres); + hres = IHTMLPrivateWindow_SuperNavigate(priv_window, bstr, bstr2, NULL, NULL, &v, &v, 0); + ok(hres == E_FAIL, "SuperNavigate returned: %08lx\n", hres); + IHTMLPrivateWindow_Release(priv_window); + SysFreeString(bstr2); + SysFreeString(bstr); + IHTMLWindow2_Release(window); }
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=138771
Your paranoid android.
=== w7u_2qxl (32 bit report) ===
mshtml: events.c:6097: Test failed: put_href returned: 80004004
=== w7u_adm (32 bit report) ===
mshtml: events.c:6097: Test failed: put_href returned: 80004004
=== w7u_el (32 bit report) ===
mshtml: events.c:6097: Test failed: put_href returned: 80004004
=== w8 (32 bit report) ===
mshtml: events.c:6097: Test failed: put_href returned: 80004004
=== w8adm (32 bit report) ===
mshtml: events.c:6097: Test failed: put_href returned: 80004004
=== w864 (32 bit report) ===
mshtml: events.c:6097: Test failed: put_href returned: 80004004
=== w1064v1809 (32 bit report) ===
mshtml: events.c:6097: Test failed: put_href returned: 80004004
=== w1064_tsign (32 bit report) ===
mshtml: events.c:6097: Test failed: put_href returned: 80004004
=== w10pro64 (32 bit report) ===
mshtml: events.c:6097: Test failed: put_href returned: 80004004
=== w10pro64_en_AE_u8 (32 bit report) ===
mshtml: events.c:6097: Test failed: put_href returned: 80004004
=== w11pro64 (32 bit report) ===
mshtml: events.c:6097: Test failed: put_href returned: 80004004
=== w7pro64 (64 bit report) ===
mshtml: events.c:6097: Test failed: put_href returned: 80004004
=== w864 (64 bit report) ===
mshtml: events.c:6097: Test failed: put_href returned: 80004004
=== w1064v1809 (64 bit report) ===
mshtml: events.c:6097: Test failed: put_href returned: 80004004
=== w1064_2qxl (64 bit report) ===
mshtml: events.c:6097: Test failed: put_href returned: 80004004
=== w1064_adm (64 bit report) ===
mshtml: events.c:6097: Test failed: put_href returned: 80004004
=== w1064_tsign (64 bit report) ===
mshtml: events.c:6097: Test failed: put_href returned: 80004004
=== w10pro64 (64 bit report) ===
mshtml: events.c:6097: Test failed: put_href returned: 80004004
=== w10pro64_ar (64 bit report) ===
mshtml: events.c:6097: Test failed: put_href returned: 80004004
=== w10pro64_ja (64 bit report) ===
mshtml: events.c:6097: Test failed: put_href returned: 80004004
=== w10pro64_zh_CN (64 bit report) ===
mshtml: events.c:6097: Test failed: put_href returned: 80004004
=== w11pro64_amd (64 bit report) ===
mshtml: events.c:6097: Test failed: put_href returned: 80004004
=== w10pro64_ja (64 bit report) ===
mshtml: htmldoc.c:352: Test failed: expected Exec_SETTITLE