This should fix some rare crashes in e.g. FFXIV Launcher (requires Proton patches to have it working though).
-- v3: mshtml: Use already available window local variable in refresh task. mshtml: Grab refs to windows upfront before sending pagehide events. mshtml: Hold ref to the frame element during readyState notifications. mshtml: Check if browser was detached during notifications while navigating. mshtml: Hold ref to outer window when navigating. mshtml: Hold ref to inner window when calling external code. mshtml: Hold ref to HTMLDocumentObj when calling external code.
From: Gabriel Ivăncescu gabrielopcode@gmail.com
It's possible for it (and the GeckoBrowser) to get detached and destroyed while processing an external callback notification.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmldoc.c | 6 +++- dlls/mshtml/mutation.c | 10 ++++-- dlls/mshtml/navigate.c | 75 +++++++++++++++++++++++++++++------------- dlls/mshtml/nsevents.c | 15 +++++---- dlls/mshtml/nsio.c | 11 +++++-- dlls/mshtml/olecmd.c | 9 ++++- dlls/mshtml/persist.c | 18 ++++++---- dlls/mshtml/view.c | 3 ++ 8 files changed, 105 insertions(+), 42 deletions(-)
diff --git a/dlls/mshtml/htmldoc.c b/dlls/mshtml/htmldoc.c index 2b885d479ab..f3a370848da 100644 --- a/dlls/mshtml/htmldoc.c +++ b/dlls/mshtml/htmldoc.c @@ -854,6 +854,7 @@ static HRESULT WINAPI HTMLDocument_get_scripts(IHTMLDocument2 *iface, IHTMLEleme static HRESULT WINAPI HTMLDocument_put_designMode(IHTMLDocument2 *iface, BSTR v) { HTMLDocumentNode *This = impl_from_IHTMLDocument2(iface); + HTMLDocumentObj *doc_obj; HRESULT hres;
TRACE("(%p)->(%s)\n", This, debugstr_w(v)); @@ -863,7 +864,10 @@ static HRESULT WINAPI HTMLDocument_put_designMode(IHTMLDocument2 *iface, BSTR v) return E_NOTIMPL; }
- hres = setup_edit_mode(This->doc_obj); + doc_obj = This->doc_obj; + IUnknown_AddRef(doc_obj->outer_unk); + hres = setup_edit_mode(doc_obj); + IUnknown_Release(doc_obj->outer_unk); if(FAILED(hres)) return hres;
diff --git a/dlls/mshtml/mutation.c b/dlls/mshtml/mutation.c index e308c1af31b..05ebf706dd0 100644 --- a/dlls/mshtml/mutation.c +++ b/dlls/mshtml/mutation.c @@ -291,17 +291,21 @@ static void parse_complete(HTMLDocumentObj *doc)
static nsresult run_end_load(HTMLDocumentNode *This, nsISupports *arg1, nsISupports *arg2) { + HTMLDocumentObj *doc_obj = This->doc_obj; + TRACE("(%p)\n", This);
- if(!This->doc_obj) + if(!doc_obj) return NS_OK;
- if(This == This->doc_obj->doc_node) { + if(This == doc_obj->doc_node) { /* * This should be done in the worker thread that parses HTML, * but we don't have such thread (Gecko parses HTML for us). */ - parse_complete(This->doc_obj); + IUnknown_AddRef(doc_obj->outer_unk); + parse_complete(doc_obj); + IUnknown_Release(doc_obj->outer_unk); }
bind_event_scripts(This); diff --git a/dlls/mshtml/navigate.c b/dlls/mshtml/navigate.c index b8d7937f071..b2fc0473aa1 100644 --- a/dlls/mshtml/navigate.c +++ b/dlls/mshtml/navigate.c @@ -1651,6 +1651,7 @@ static void handle_extern_mime_navigation(nsChannelBSC *This) return;
doc_obj = This->bsc.window->base.outer_window->browser->doc; + IUnknown_AddRef(doc_obj->outer_unk);
hres = IOleClientSite_QueryInterface(doc_obj->client, &IID_IOleCommandTarget, (void**)&cmdtrg); if(SUCCEEDED(hres)) { @@ -1662,17 +1663,17 @@ static void handle_extern_mime_navigation(nsChannelBSC *This)
if(!doc_obj->webbrowser) { FIXME("unimplemented in non-webbrowser mode\n"); - return; + goto done; }
uri = get_moniker_uri(This->bsc.mon); if(!uri) - return; + goto done;
hres = CreateBindCtx(0, &bind_ctx); if(FAILED(hres)) { IUri_Release(uri); - return; + goto done; }
V_VT(&flags) = VT_I4; @@ -1701,6 +1702,9 @@ static void handle_extern_mime_navigation(nsChannelBSC *This) }
IUri_Release(uri); + +done: + IUnknown_Release(doc_obj->outer_unk); }
static HRESULT nsChannelBSC_on_progress(BSCallback *bsc, ULONG progress, ULONG total, ULONG status_code, LPCWSTR status_text) @@ -2066,25 +2070,31 @@ static void navigate_javascript_proc(task_t *_task) { navigate_javascript_task_t *task = (navigate_javascript_task_t*)_task; HTMLOuterWindow *window = task->window; + HTMLDocumentObj *doc = NULL; BSTR code = NULL; VARIANT v; HRESULT hres;
- task->window->readystate = READYSTATE_COMPLETE; + window->readystate = READYSTATE_COMPLETE; + if(window->browser) { + doc = window->browser->doc; + IUnknown_AddRef(doc->outer_unk); + }
hres = IUri_GetPath(task->uri, &code); if(hres != S_OK) { SysFreeString(code); - return; + goto done; }
hres = UrlUnescapeW(code, NULL, NULL, URL_UNESCAPE_INPLACE); if(FAILED(hres)) { SysFreeString(code); - return; + goto done; }
- set_download_state(window->browser->doc, 1); + if(doc) + set_download_state(doc, 1);
V_VT(&v) = VT_EMPTY; hres = exec_script(window->base.inner_window, code, L"jscript", &v); @@ -2094,10 +2104,16 @@ static void navigate_javascript_proc(task_t *_task) VariantClear(&v); }
- if(window->browser->doc->view_sink) - IAdviseSink_OnViewChange(window->browser->doc->view_sink, DVASPECT_CONTENT, -1); + if(doc) { + if(doc->view_sink) + IAdviseSink_OnViewChange(doc->view_sink, DVASPECT_CONTENT, -1); + + set_download_state(doc, 0); + }
- set_download_state(window->browser->doc, 0); +done: + if(doc) + IUnknown_Release(doc->outer_unk); }
static void navigate_javascript_task_destr(task_t *_task) @@ -2199,9 +2215,12 @@ static HRESULT navigate_fragment(HTMLOuterWindow *window, IUri *uri) SysFreeString(frag);
if(window->browser->doc->doc_object_service) { - IDocObjectService_FireNavigateComplete2(window->browser->doc->doc_object_service, &window->base.IHTMLWindow2_iface, 0x10); - IDocObjectService_FireDocumentComplete(window->browser->doc->doc_object_service, &window->base.IHTMLWindow2_iface, 0); + HTMLDocumentObj *doc_obj = window->browser->doc;
+ IUnknown_AddRef(doc_obj->outer_unk); + IDocObjectService_FireNavigateComplete2(doc_obj->doc_object_service, &window->base.IHTMLWindow2_iface, 0x10); + IDocObjectService_FireDocumentComplete(doc_obj->doc_object_service, &window->base.IHTMLWindow2_iface, 0); + IUnknown_Release(doc_obj->outer_unk); }
return S_OK; @@ -2209,6 +2228,7 @@ static HRESULT navigate_fragment(HTMLOuterWindow *window, IUri *uri)
HRESULT super_navigate(HTMLOuterWindow *window, IUri *uri, DWORD flags, const WCHAR *headers, BYTE *post_data, DWORD post_data_size) { + HTMLDocumentObj *doc_obj; nsChannelBSC *bsc; IUri *uri_nofrag; IMoniker *mon; @@ -2219,10 +2239,13 @@ HRESULT super_navigate(HTMLOuterWindow *window, IUri *uri, DWORD flags, const WC if(!uri_nofrag) return E_FAIL;
- if(window->browser->doc->client && !(flags & BINDING_REFRESH)) { + doc_obj = window->browser->doc; + IUnknown_AddRef(doc_obj->outer_unk); + + if(doc_obj->client && !(flags & BINDING_REFRESH)) { IOleCommandTarget *cmdtrg;
- hres = IOleClientSite_QueryInterface(window->browser->doc->client, &IID_IOleCommandTarget, (void**)&cmdtrg); + hres = IOleClientSite_QueryInterface(doc_obj->client, &IID_IOleCommandTarget, (void**)&cmdtrg); if(SUCCEEDED(hres)) { VARIANT in, out; BSTR url_str; @@ -2249,14 +2272,15 @@ HRESULT super_navigate(HTMLOuterWindow *window, IUri *uri, DWORD flags, const WC if(SUCCEEDED(hres) && eq) { IUri_Release(uri_nofrag); TRACE("fragment navigate\n"); - return navigate_fragment(window, uri); + hres = navigate_fragment(window, uri); + goto done; } }
hres = CreateURLMonikerEx2(NULL, uri_nofrag, &mon, URL_MK_UNIFORM); IUri_Release(uri_nofrag); if(FAILED(hres)) - return hres; + goto done;
/* FIXME: Why not set_ready_state? */ window->readystate = READYSTATE_UNINITIALIZED; @@ -2264,10 +2288,10 @@ HRESULT super_navigate(HTMLOuterWindow *window, IUri *uri, DWORD flags, const WC hres = create_channelbsc(mon, headers, post_data, post_data_size, TRUE, &bsc); if(FAILED(hres)) { IMoniker_Release(mon); - return hres; + goto done; }
- prepare_for_binding(window->browser->doc, mon, flags); + prepare_for_binding(doc_obj, mon, flags);
hres = IUri_GetScheme(uri, &scheme); if(hres == S_OK && scheme == URL_SCHEME_JAVASCRIPT) { @@ -2277,13 +2301,15 @@ HRESULT super_navigate(HTMLOuterWindow *window, IUri *uri, DWORD flags, const WC IMoniker_Release(mon);
task = malloc(sizeof(*task)); - if(!task) - return E_OUTOFMEMORY; + if(!task) { + hres = E_OUTOFMEMORY; + goto done; + }
/* Why silently? */ window->readystate = READYSTATE_COMPLETE; if(!(flags & BINDING_FROMHIST)) - call_docview_84(window->browser->doc); + call_docview_84(doc_obj);
IUri_AddRef(uri); task->window = window; @@ -2302,13 +2328,14 @@ HRESULT super_navigate(HTMLOuterWindow *window, IUri *uri, DWORD flags, const WC if(!task) { IBindStatusCallback_Release(&bsc->bsc.IBindStatusCallback_iface); IMoniker_Release(mon); - return E_OUTOFMEMORY; + hres = E_OUTOFMEMORY; + goto done; }
/* Silently and repeated when real loading starts? */ window->readystate = READYSTATE_LOADING; if(!(flags & (BINDING_FROMHIST|BINDING_REFRESH))) - call_docview_84(window->browser->doc); + call_docview_84(doc_obj);
task->window = window; task->bscallback = bsc; @@ -2320,6 +2347,8 @@ HRESULT super_navigate(HTMLOuterWindow *window, IUri *uri, DWORD flags, const WC hres = push_task(&task->header, navigate_proc, navigate_task_destr, window->task_magic); }
+done: + IUnknown_Release(doc_obj->outer_unk); return hres; }
diff --git a/dlls/mshtml/nsevents.c b/dlls/mshtml/nsevents.c index b3616b64964..177981acc25 100644 --- a/dlls/mshtml/nsevents.c +++ b/dlls/mshtml/nsevents.c @@ -339,9 +339,10 @@ 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->doc_obj && doc->doc_obj->doc_node == doc) { doc_obj = doc->doc_obj; - + IUnknown_AddRef(doc_obj->outer_unk); + } connect_scripts(doc->window);
if(doc_obj) @@ -357,11 +358,13 @@ static nsresult handle_load(HTMLDocumentNode *doc, nsIDOMEvent *event) set_statustext(doc_obj, IDS_STATUS_DONE, NULL);
update_title(doc_obj); - }
- if(doc_obj && doc_obj->doc_object_service && !(doc->outer_window->load_flags & BINDING_REFRESH)) - IDocObjectService_FireDocumentComplete(doc_obj->doc_object_service, - &doc->outer_window->base.IHTMLWindow2_iface, 0); + if(doc_obj->doc_object_service && !(doc->outer_window->load_flags & BINDING_REFRESH)) + IDocObjectService_FireDocumentComplete(doc_obj->doc_object_service, + &doc->outer_window->base.IHTMLWindow2_iface, 0); + + IUnknown_Release(doc_obj->outer_unk); + }
doc->window->performance_timing->load_event_start_time = get_time_stamp();
diff --git a/dlls/mshtml/nsio.c b/dlls/mshtml/nsio.c index 509a83efbd3..d29bb43544e 100644 --- a/dlls/mshtml/nsio.c +++ b/dlls/mshtml/nsio.c @@ -217,6 +217,9 @@ static BOOL exec_shldocvw_67(HTMLDocumentObj *doc, BSTR url) IOleCommandTarget *cmdtrg = NULL; HRESULT hres;
+ if(!doc->client) + return TRUE; + hres = IOleClientSite_QueryInterface(doc->client, &IID_IOleCommandTarget, (void**)&cmdtrg); if(SUCCEEDED(hres)) { VARIANT varUrl, varRes; @@ -252,6 +255,7 @@ static nsresult before_async_open(nsChannel *channel, GeckoBrowser *container, B hres = IUri_GetDisplayUri(channel->uri->uri, &display_uri); if(FAILED(hres)) return NS_ERROR_FAILURE; + IUnknown_AddRef(doc->outer_unk);
if(doc->hostui) { OLECHAR *new_url; @@ -261,7 +265,7 @@ static nsresult before_async_open(nsChannel *channel, GeckoBrowser *container, B FIXME("TranslateUrl returned new URL %s -> %s\n", debugstr_w(display_uri), debugstr_w(new_url)); CoTaskMemFree(new_url); *cancel = TRUE; - return NS_OK; + goto done; } CoTaskMemFree(new_url); } @@ -270,13 +274,16 @@ static nsresult before_async_open(nsChannel *channel, GeckoBrowser *container, B if(!exec_shldocvw_67(doc, display_uri)) { SysFreeString(display_uri); *cancel = FALSE; - return NS_OK; + goto done; }
hres = hlink_frame_navigate(doc, display_uri, channel, 0, cancel); SysFreeString(display_uri); if(FAILED(hres)) *cancel = TRUE; + +done: + IUnknown_Release(doc->outer_unk); return NS_OK; }
diff --git a/dlls/mshtml/olecmd.c b/dlls/mshtml/olecmd.c index 9e59778ccb9..8f51292e5fc 100644 --- a/dlls/mshtml/olecmd.c +++ b/dlls/mshtml/olecmd.c @@ -687,12 +687,19 @@ static HRESULT exec_browsemode(HTMLDocumentNode *doc, DWORD cmdexecopt, VARIANT
static HRESULT exec_editmode(HTMLDocumentNode *doc, DWORD cmdexecopt, VARIANT *in, VARIANT *out) { + HTMLDocumentObj *doc_obj; + HRESULT hres; + TRACE("(%p)->(%08lx %p %p)\n", doc, cmdexecopt, in, out);
if(in || out) FIXME("unsupported args\n");
- return setup_edit_mode(doc->browser->doc); + doc_obj = doc->browser->doc; + IUnknown_AddRef(doc_obj->outer_unk); + hres = setup_edit_mode(doc_obj); + IUnknown_Release(doc_obj->outer_unk); + return hres; }
static HRESULT exec_htmleditmode(HTMLDocumentNode *doc, DWORD cmdexecopt, VARIANT *in, VARIANT *out) diff --git a/dlls/mshtml/persist.c b/dlls/mshtml/persist.c index 486643d8b21..620f6428d35 100644 --- a/dlls/mshtml/persist.c +++ b/dlls/mshtml/persist.c @@ -208,6 +208,8 @@ static void set_progress_proc(task_t *_task)
TRACE("(%p)\n", doc);
+ IUnknown_AddRef(doc->outer_unk); + if(doc->client) IOleClientSite_QueryInterface(doc->client, &IID_IOleCommandTarget, (void**)&olecmd);
@@ -238,6 +240,8 @@ static void set_progress_proc(task_t *_task) hostinfo.cbSize, hostinfo.dwFlags, hostinfo.dwDoubleClick, debugstr_w(hostinfo.pchHostCss), debugstr_w(hostinfo.pchHostNS)); } + + IUnknown_Release(doc->outer_unk); }
static void set_progress_destr(task_t *_task) @@ -252,13 +256,14 @@ static void set_downloading_proc(task_t *_task)
TRACE("(%p)\n", doc);
+ IUnknown_AddRef(doc->outer_unk); set_statustext(doc, IDS_STATUS_DOWNLOADINGFROM, task->url);
if(task->set_download) set_download_state(doc, 1);
if(!doc->client) - return; + goto done;
if(doc->view_sink) IAdviseSink_OnViewChange(doc->view_sink, DVASPECT_CONTENT, -1); @@ -272,6 +277,9 @@ static void set_downloading_proc(task_t *_task) IDropTarget_Release(drop_target); } } + +done: + IUnknown_Release(doc->outer_unk); }
static void set_downloading_task_destr(task_t *_task) @@ -341,16 +349,12 @@ HRESULT set_moniker(HTMLOuterWindow *window, IMoniker *mon, IUri *nav_uri, IBind BOOL set_download) { download_proc_task_t *download_task; - HTMLDocumentObj *doc_obj = NULL; nsChannelBSC *bscallback; nsWineURI *nsuri; LPOLESTR url; IUri *uri; HRESULT hres;
- if(is_main_content_window(window)) - doc_obj = window->browser->doc; - hres = IMoniker_GetDisplayName(mon, pibc, NULL, &url); if(FAILED(hres)) { WARN("GetDisplayName failed: %08lx\n", hres); @@ -401,7 +405,9 @@ HRESULT set_moniker(HTMLOuterWindow *window, IMoniker *mon, IUri *nav_uri, IBind return hres; }
- if(doc_obj) { + if(is_main_content_window(window)) { + HTMLDocumentObj *doc_obj = window->browser->doc; + HTMLDocument_LockContainer(doc_obj, TRUE);
if(doc_obj->frame) { diff --git a/dlls/mshtml/view.c b/dlls/mshtml/view.c index 6b7ecb0bc27..346fccf4955 100644 --- a/dlls/mshtml/view.c +++ b/dlls/mshtml/view.c @@ -117,6 +117,7 @@ static LRESULT on_timer(HTMLDocumentObj *This)
if(!This->update) return 0; + IUnknown_AddRef(This->outer_unk);
if(This->update & UPDATE_UI) { if(This->hostui) @@ -138,6 +139,8 @@ static LRESULT on_timer(HTMLDocumentObj *This)
update_title(This); This->update = 0; + + IUnknown_Release(This->outer_unk); return 0; }
From: Gabriel Ivăncescu gabrielopcode@gmail.com
It's possible for it to get detached while processing an external callback notification, such as when navigation happens during it.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/mutation.c | 12 ++++++++---- dlls/mshtml/navigate.c | 12 ++++++++++-- dlls/mshtml/persist.c | 8 ++++++-- 3 files changed, 24 insertions(+), 8 deletions(-)
diff --git a/dlls/mshtml/mutation.c b/dlls/mshtml/mutation.c index 05ebf706dd0..89bba9cb195 100644 --- a/dlls/mshtml/mutation.c +++ b/dlls/mshtml/mutation.c @@ -292,11 +292,13 @@ static void parse_complete(HTMLDocumentObj *doc) static nsresult run_end_load(HTMLDocumentNode *This, nsISupports *arg1, nsISupports *arg2) { HTMLDocumentObj *doc_obj = This->doc_obj; + HTMLInnerWindow *window = This->window;
TRACE("(%p)\n", This);
if(!doc_obj) return NS_OK; + IHTMLWindow2_AddRef(&window->base.IHTMLWindow2_iface);
if(This == doc_obj->doc_node) { /* @@ -310,8 +312,11 @@ static nsresult run_end_load(HTMLDocumentNode *This, nsISupports *arg1, nsISuppo
bind_event_scripts(This);
- This->window->performance_timing->dom_interactive_time = get_time_stamp(); - set_ready_state(This->outer_window, READYSTATE_INTERACTIVE); + if(This->window == window) { + window->performance_timing->dom_interactive_time = get_time_stamp(); + set_ready_state(This->outer_window, READYSTATE_INTERACTIVE); + } + IHTMLWindow2_Release(&window->base.IHTMLWindow2_iface); return NS_OK; }
@@ -368,14 +373,13 @@ static nsresult run_insert_script(HTMLDocumentNode *doc, nsISupports *script_ifa free(iter); }
- IHTMLWindow2_Release(&window->base.IHTMLWindow2_iface); - if(nsparser) { window->parser_callback_cnt--; nsIParser_EndEvaluatingParserInsertedScript(nsparser); nsIParser_Release(nsparser); }
+ IHTMLWindow2_Release(&window->base.IHTMLWindow2_iface); IHTMLScriptElement_Release(&script_elem->IHTMLScriptElement_iface);
return NS_OK; diff --git a/dlls/mshtml/navigate.c b/dlls/mshtml/navigate.c index b2fc0473aa1..c78dfde43dc 100644 --- a/dlls/mshtml/navigate.c +++ b/dlls/mshtml/navigate.c @@ -1419,8 +1419,11 @@ static void stop_request_task_destr(task_t *_task)
static HRESULT async_stop_request(nsChannelBSC *This) { + HTMLInnerWindow *window = This->bsc.window; stop_request_task_t *task; + HRESULT hres;
+ IHTMLWindow2_AddRef(&window->base.IHTMLWindow2_iface); if(!This->bsc.read) { TRACE("No data read, calling OnStartRequest\n"); on_start_nsrequest(This); @@ -1433,7 +1436,9 @@ static HRESULT async_stop_request(nsChannelBSC *This) IBindStatusCallback_AddRef(&This->bsc.IBindStatusCallback_iface); task->bsc = This;
- return push_task(&task->header, stop_request_proc, stop_request_task_destr, This->bsc.window->task_magic); + hres = push_task(&task->header, stop_request_proc, stop_request_task_destr, window->task_magic); + IHTMLWindow2_Release(&window->base.IHTMLWindow2_iface); + return hres; }
static void handle_navigation_error(nsChannelBSC *This, DWORD result) @@ -2069,6 +2074,7 @@ typedef struct { static void navigate_javascript_proc(task_t *_task) { navigate_javascript_task_t *task = (navigate_javascript_task_t*)_task; + HTMLInnerWindow *inner_window = task->window->base.inner_window; HTMLOuterWindow *window = task->window; HTMLDocumentObj *doc = NULL; BSTR code = NULL; @@ -2080,6 +2086,7 @@ static void navigate_javascript_proc(task_t *_task) doc = window->browser->doc; IUnknown_AddRef(doc->outer_unk); } + IHTMLWindow2_AddRef(&inner_window->base.IHTMLWindow2_iface);
hres = IUri_GetPath(task->uri, &code); if(hres != S_OK) { @@ -2097,7 +2104,7 @@ static void navigate_javascript_proc(task_t *_task) set_download_state(doc, 1);
V_VT(&v) = VT_EMPTY; - hres = exec_script(window->base.inner_window, code, L"jscript", &v); + hres = exec_script(inner_window, code, L"jscript", &v); SysFreeString(code); if(SUCCEEDED(hres) && V_VT(&v) != VT_EMPTY) { FIXME("javascirpt URL returned %s\n", debugstr_variant(&v)); @@ -2112,6 +2119,7 @@ static void navigate_javascript_proc(task_t *_task) }
done: + IHTMLWindow2_Release(&inner_window->base.IHTMLWindow2_iface); if(doc) IUnknown_Release(doc->outer_unk); } diff --git a/dlls/mshtml/persist.c b/dlls/mshtml/persist.c index 620f6428d35..35ffd7824dd 100644 --- a/dlls/mshtml/persist.c +++ b/dlls/mshtml/persist.c @@ -437,20 +437,24 @@ HRESULT set_moniker(HTMLOuterWindow *window, IMoniker *mon, IUri *nav_uri, IBind
static void notif_readystate(HTMLOuterWindow *window) { + HTMLInnerWindow *inner_window = window->base.inner_window; DOMEvent *event; HRESULT hres;
window->readystate_pending = FALSE;
+ IHTMLWindow2_AddRef(&inner_window->base.IHTMLWindow2_iface); + if(is_main_content_window(window)) call_property_onchanged(&window->browser->doc->cp_container, DISPID_READYSTATE);
- hres = create_document_event(window->base.inner_window->doc, EVENTID_READYSTATECHANGE, &event); + hres = create_document_event(inner_window->doc, EVENTID_READYSTATECHANGE, &event); if(SUCCEEDED(hres)) { event->no_event_obj = TRUE; - dispatch_event(&window->base.inner_window->doc->node.event_target, event); + dispatch_event(&inner_window->doc->node.event_target, event); IDOMEvent_Release(&event->IDOMEvent_iface); } + IHTMLWindow2_Release(&inner_window->base.IHTMLWindow2_iface);
if(window->frame_element) { hres = create_document_event(window->frame_element->element.node.doc, EVENTID_READYSTATECHANGE, &event);
From: Gabriel Ivăncescu gabrielopcode@gmail.com
It's possible for it to get destroyed while processing an external callback notification.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/navigate.c | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-)
diff --git a/dlls/mshtml/navigate.c b/dlls/mshtml/navigate.c index c78dfde43dc..de16232c3e3 100644 --- a/dlls/mshtml/navigate.c +++ b/dlls/mshtml/navigate.c @@ -1948,8 +1948,12 @@ typedef struct { static void start_doc_binding_proc(task_t *_task) { start_doc_binding_task_t *task = (start_doc_binding_task_t*)_task; + HTMLOuterWindow *window = task->window; + + IHTMLWindow2_AddRef(&window->base.IHTMLWindow2_iface); + set_current_mon(window, task->pending_window->bscallback->bsc.mon, task->flags); + IHTMLWindow2_Release(&window->base.IHTMLWindow2_iface);
- set_current_mon(task->window, task->pending_window->bscallback->bsc.mon, task->flags); start_binding(task->pending_window, &task->pending_window->bscallback->bsc, NULL); }
@@ -2016,6 +2020,7 @@ void abort_window_bindings(HTMLInnerWindow *window)
HRESULT channelbsc_load_stream(HTMLInnerWindow *pending_window, IMoniker *mon, IStream *stream) { + HTMLOuterWindow *window = pending_window->base.outer_window; nsChannelBSC *bscallback = pending_window->bscallback; HRESULT hres = S_OK;
@@ -2028,7 +2033,9 @@ HRESULT channelbsc_load_stream(HTMLInnerWindow *pending_window, IMoniker *mon, I if(!bscallback->nschannel->content_type) return E_OUTOFMEMORY;
- set_current_mon(pending_window->base.outer_window, mon, 0); + IHTMLWindow2_AddRef(&window->base.IHTMLWindow2_iface); + set_current_mon(window, mon, 0); + IHTMLWindow2_Release(&window->base.IHTMLWindow2_iface);
bscallback->bsc.window = pending_window; if(stream) @@ -2143,14 +2150,19 @@ typedef struct { static void navigate_proc(task_t *_task) { navigate_task_t *task = (navigate_task_t*)_task; + HTMLOuterWindow *window = task->window; HRESULT hres;
- hres = set_moniker(task->window, task->mon, task->uri, NULL, task->bscallback, TRUE); + IHTMLWindow2_AddRef(&window->base.IHTMLWindow2_iface); + + hres = set_moniker(window, task->mon, task->uri, NULL, task->bscallback, TRUE); if(SUCCEEDED(hres)) { - set_current_mon(task->window, task->bscallback->bsc.mon, task->flags); - set_current_uri(task->window, task->uri); - start_binding(task->window->pending_window, &task->bscallback->bsc, NULL); + set_current_mon(window, task->bscallback->bsc.mon, task->flags); + set_current_uri(window, task->uri); + start_binding(window->pending_window, &task->bscallback->bsc, NULL); } + + IHTMLWindow2_Release(&window->base.IHTMLWindow2_iface); }
static void navigate_task_destr(task_t *_task) @@ -2676,14 +2688,16 @@ HRESULT navigate_url(HTMLOuterWindow *window, const WCHAR *new_url, IUri *base_u hres = create_uri(new_url, 0, &nav_uri); if(FAILED(hres)) return hres; + IHTMLWindow2_AddRef(&window->base.IHTMLWindow2_iface);
hres = translate_uri(window, nav_uri, &display_uri, &uri); IUri_Release(nav_uri); - if(FAILED(hres)) - return hres; + if(SUCCEEDED(hres)) { + hres = navigate_uri(window, uri, display_uri, NULL, flags); + IUri_Release(uri); + SysFreeString(display_uri); + }
- hres = navigate_uri(window, uri, display_uri, NULL, flags); - IUri_Release(uri); - SysFreeString(display_uri); + IHTMLWindow2_Release(&window->base.IHTMLWindow2_iface); return hres; }
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/navigate.c | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/dlls/mshtml/navigate.c b/dlls/mshtml/navigate.c index de16232c3e3..eb365c99af9 100644 --- a/dlls/mshtml/navigate.c +++ b/dlls/mshtml/navigate.c @@ -2559,6 +2559,9 @@ static HRESULT navigate_uri(HTMLOuterWindow *window, IUri *uri, const WCHAR *dis } }
+ if(!window->browser) + return S_OK; + if(is_main_content_window(window)) return super_navigate(window, uri, flags, headers, post_data, post_data_len); }
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/persist.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/dlls/mshtml/persist.c b/dlls/mshtml/persist.c index 35ffd7824dd..78e8f609187 100644 --- a/dlls/mshtml/persist.c +++ b/dlls/mshtml/persist.c @@ -438,12 +438,15 @@ HRESULT set_moniker(HTMLOuterWindow *window, IMoniker *mon, IUri *nav_uri, IBind static void notif_readystate(HTMLOuterWindow *window) { HTMLInnerWindow *inner_window = window->base.inner_window; + HTMLFrameBase *frame_element = window->frame_element; DOMEvent *event; HRESULT hres;
window->readystate_pending = FALSE;
IHTMLWindow2_AddRef(&inner_window->base.IHTMLWindow2_iface); + if(frame_element) + IHTMLDOMNode_AddRef(&frame_element->element.node.IHTMLDOMNode_iface);
if(is_main_content_window(window)) call_property_onchanged(&window->browser->doc->cp_container, DISPID_READYSTATE); @@ -456,12 +459,13 @@ static void notif_readystate(HTMLOuterWindow *window) } IHTMLWindow2_Release(&inner_window->base.IHTMLWindow2_iface);
- if(window->frame_element) { - hres = create_document_event(window->frame_element->element.node.doc, EVENTID_READYSTATECHANGE, &event); + if(frame_element) { + hres = create_document_event(frame_element->element.node.doc, EVENTID_READYSTATECHANGE, &event); if(SUCCEEDED(hres)) { - dispatch_event(&window->frame_element->element.node.event_target, event); + dispatch_event(&frame_element->element.node.event_target, event); IDOMEvent_Release(&event->IDOMEvent_iface); } + IHTMLDOMNode_Release(&frame_element->element.node.IHTMLDOMNode_iface); } }
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/view.c | 74 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 51 insertions(+), 23 deletions(-)
diff --git a/dlls/mshtml/view.c b/dlls/mshtml/view.c index 346fccf4955..3f31e609e39 100644 --- a/dlls/mshtml/view.c +++ b/dlls/mshtml/view.c @@ -414,45 +414,73 @@ HRESULT call_set_active_object(IOleInPlaceUIWindow *window, IOleInPlaceActiveObj return IOleInPlaceUIWindow_SetActiveObject(window, act_obj, act_obj ? html_documentW : NULL); }
-static void send_unload_events_impl(HTMLInnerWindow *window) +static unsigned get_window_list_num(HTMLInnerWindow *window) { HTMLOuterWindow *child; + unsigned ret = 1; + + LIST_FOR_EACH_ENTRY(child, &window->children, HTMLOuterWindow, sibling_entry) + ret += get_window_list_num(child->base.inner_window); + return ret; +} + +static HTMLInnerWindow **get_window_list(HTMLInnerWindow *window, HTMLInnerWindow **output) +{ + HTMLOuterWindow *child; + + *output++ = window; + IHTMLWindow2_AddRef(&window->base.IHTMLWindow2_iface); + + LIST_FOR_EACH_ENTRY(child, &window->children, HTMLOuterWindow, sibling_entry) + output = get_window_list(child->base.inner_window, output); + return output; +} + +static void send_unload_events(HTMLDocumentObj *doc) +{ + HTMLInnerWindow **windows, *window; DOMEvent *event; + unsigned i, num; HRESULT hres;
- if(!window) + if(!doc->window || !doc->doc_node->content_ready) + return; + window = doc->window->base.inner_window; + + /* Grab list of all windows ahead, and keep refs, + since it can be detached from under our feet. */ + num = get_window_list_num(window); + if(!(windows = malloc(num * sizeof(*windows)))) return; + get_window_list(window, windows); + + for(i = 0; i < num; i++) { + window = windows[i];
- if(window->doc && !window->doc->unload_sent) { - window->doc->unload_sent = TRUE; + if(window->doc && !window->doc->unload_sent) { + window->doc->unload_sent = TRUE; + + /* Native sends pagehide events prior to unload on the same window + before it moves on to the next window, so they're interleaved. */ + if(window->doc->document_mode >= COMPAT_MODE_IE11) { + hres = create_document_event(window->doc, EVENTID_PAGEHIDE, &event); + if(SUCCEEDED(hres)) { + dispatch_event(&window->event_target, event); + IDOMEvent_Release(&event->IDOMEvent_iface); + } + }
- /* Native sends pagehide events prior to unload on the same window - before it moves on to the next window, so they're interleaved. */ - if(window->doc->document_mode >= COMPAT_MODE_IE11) { - hres = create_document_event(window->doc, EVENTID_PAGEHIDE, &event); + hres = create_document_event(window->doc, EVENTID_UNLOAD, &event); if(SUCCEEDED(hres)) { dispatch_event(&window->event_target, event); IDOMEvent_Release(&event->IDOMEvent_iface); } }
- hres = create_document_event(window->doc, EVENTID_UNLOAD, &event); - if(SUCCEEDED(hres)) { - dispatch_event(&window->event_target, event); - IDOMEvent_Release(&event->IDOMEvent_iface); - } + IHTMLWindow2_Release(&window->base.IHTMLWindow2_iface); }
- LIST_FOR_EACH_ENTRY(child, &window->children, HTMLOuterWindow, sibling_entry) - send_unload_events_impl(child->base.inner_window); -} - -static void send_unload_events(HTMLDocumentObj *doc) -{ - if(!doc->window || !doc->doc_node->content_ready) - return; - - send_unload_events_impl(doc->window->base.inner_window); + free(windows); }
/**********************************************************
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/olecmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/mshtml/olecmd.c b/dlls/mshtml/olecmd.c index 8f51292e5fc..27690b44e79 100644 --- a/dlls/mshtml/olecmd.c +++ b/dlls/mshtml/olecmd.c @@ -438,7 +438,7 @@ static void refresh_proc(task_t *_task) IOleCommandTarget_Exec(window->browser->doc->client_cmdtrg, &CGID_ShellDocView, 37, 0, &var, NULL); }
- load_uri(task->window, task->window->uri, BINDING_REFRESH|BINDING_NOFRAG); + load_uri(window, window->uri, BINDING_REFRESH|BINDING_NOFRAG); }
static void refresh_destr(task_t *_task)
This merge request was approved by Jacek Caban.