This fixes some inconsistency issues when it comes to inner vs outer windows. On second patch I keep ref again to outer windows from the inner windows, and there are several reasons for this:
* It fixes the existing tests to match native IE. * It simplifies the code (it's always valid now, no second-guessing or what-ifs needed) and gets rid of `outer_window` in HTMLDocumentNode. * It **fixes** the `outer_window` in HTMLDocumentNode → it was basically prone to crashes in niche cases since it didn't hold a ref before. We can't couple it to the inner `window` field either, because that one gets detached, and that will fail *existing* tests. For example: `events.c:3224: Test failed: put_URL failed: 80004005`. * Instead of having to keep outer window refs in specific objects, it's simpler to have it consistent everywhere.
For now only the external caller changes are kept and a leak fix.
-- v3: mshtml: Don't NULL out the doc's window when unlinking the window. mshtml: Return outer window to external callers.
From: Gabriel Ivăncescu gabrielopcode@gmail.com
UIEvent.view is still todo_wine because it returns NULL for some reason, but it is clear from the existing tests that it must match the outer window.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmlevent.c | 2 +- dlls/mshtml/htmlwindow.c | 15 ++++++++------- dlls/mshtml/script.c | 4 ++-- dlls/mshtml/tests/dom.c | 15 +++++++++++++-- dlls/mshtml/tests/events.c | 12 ++++++++++++ dlls/mshtml/tests/jstest.html | 4 ++-- dlls/mshtml/tests/script.c | 1 - 7 files changed, 38 insertions(+), 15 deletions(-)
diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c index d6ad65b1d0b..6ee133d848a 100644 --- a/dlls/mshtml/htmlevent.c +++ b/dlls/mshtml/htmlevent.c @@ -1338,7 +1338,7 @@ static HRESULT WINAPI DOMUIEvent_get_view(IDOMUIEvent *iface, IHTMLWindow2 **p) mozIDOMWindowProxy_Release(moz_window); } if(view) - IHTMLWindow2_AddRef((*p = &view->base.inner_window->base.IHTMLWindow2_iface)); + IHTMLWindow2_AddRef((*p = &view->base.IHTMLWindow2_iface)); else *p = NULL; return S_OK; diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index 38723919f15..fc17635542d 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -504,11 +504,12 @@ static HRESULT WINAPI HTMLWindow2_get_length(IHTMLWindow2 *iface, LONG *p) static HRESULT WINAPI HTMLWindow2_get_frames(IHTMLWindow2 *iface, IHTMLFramesCollection2 **p) { HTMLWindow *This = impl_from_IHTMLWindow2(iface); + FIXME("(%p)->(%p): semi-stub\n", This, p);
/* FIXME: Should return a separate Window object */ - *p = (IHTMLFramesCollection2*)&This->IHTMLWindow2_iface; - IHTMLWindow2_AddRef(iface); + *p = (IHTMLFramesCollection2*)&This->outer_window->base.IHTMLWindow2_iface; + IHTMLWindow2_AddRef(&This->outer_window->base.IHTMLWindow2_iface); return S_OK; }
@@ -993,8 +994,8 @@ static HRESULT WINAPI HTMLWindow2_get_self(IHTMLWindow2 *iface, IHTMLWindow2 **p TRACE("(%p)->(%p)\n", This, p);
/* FIXME: We should return kind of proxy window here. */ - IHTMLWindow2_AddRef(&This->IHTMLWindow2_iface); - *p = &This->IHTMLWindow2_iface; + *p = &This->outer_window->base.IHTMLWindow2_iface; + IHTMLWindow2_AddRef(*p); return S_OK; }
@@ -1019,8 +1020,8 @@ static HRESULT WINAPI HTMLWindow2_get_window(IHTMLWindow2 *iface, IHTMLWindow2 * TRACE("(%p)->(%p)\n", This, p);
/* FIXME: We should return kind of proxy window here. */ - IHTMLWindow2_AddRef(&This->IHTMLWindow2_iface); - *p = &This->IHTMLWindow2_iface; + *p = &This->outer_window->base.IHTMLWindow2_iface; + IHTMLWindow2_AddRef(*p); return S_OK; }
@@ -4132,7 +4133,7 @@ static HRESULT HTMLWindow_invoke(DispatchEx *dispex, DISPID id, LCID lcid, WORD return DISP_E_MEMBERNOTFOUND;
V_VT(res) = VT_DISPATCH; - V_DISPATCH(res) = (IDispatch*)&frame->base.inner_window->base.IHTMLWindow2_iface; + V_DISPATCH(res) = (IDispatch*)&frame->base.IHTMLWindow2_iface; IDispatch_AddRef(V_DISPATCH(res)); return S_OK; } diff --git a/dlls/mshtml/script.c b/dlls/mshtml/script.c index 149abcf70e2..cad0f17671a 100644 --- a/dlls/mshtml/script.c +++ b/dlls/mshtml/script.c @@ -374,11 +374,11 @@ static HRESULT WINAPI ActiveScriptSite_GetItemInfo(IActiveScriptSite *iface, LPC if(wcscmp(pstrName, L"window")) return DISP_E_MEMBERNOTFOUND;
- if(!This->window) + if(!This->window || !This->window->base.outer_window) return E_FAIL;
/* FIXME: Return proxy object */ - *ppiunkItem = (IUnknown*)&This->window->base.IHTMLWindow2_iface; + *ppiunkItem = (IUnknown*)&This->window->base.outer_window->base.IHTMLWindow2_iface; IUnknown_AddRef(*ppiunkItem);
return S_OK; diff --git a/dlls/mshtml/tests/dom.c b/dlls/mshtml/tests/dom.c index b7079447cf2..58a1cc6cf20 100644 --- a/dlls/mshtml/tests/dom.c +++ b/dlls/mshtml/tests/dom.c @@ -7319,9 +7319,10 @@ static void test_window(IHTMLDocument2 *doc)
hres = IHTMLWindow2_get_self(window, &self); ok(hres == S_OK, "get_self failed: %08lx\n", hres); - ok(window2 != NULL, "self == NULL\n"); + ok(self != NULL, "self == NULL\n");
ok(self == window2, "self != window2\n"); + todo_wine ok(window != window2, "window == window2\n");
IHTMLWindow2_Release(window2);
@@ -10931,7 +10932,7 @@ static void test_frames_collection(IHTMLFramesCollection2 *frames, const WCHAR *
static void test_frameset(IHTMLDocument2 *doc) { - IHTMLWindow2 *window; + IHTMLWindow2 *window, *window2, *self; IHTMLFramesCollection2 *frames; IHTMLDocument6 *doc6; IHTMLElement *elem; @@ -10946,6 +10947,16 @@ static void test_frameset(IHTMLDocument2 *doc) if(FAILED(hres)) return;
+ hres = IHTMLFramesCollection2_QueryInterface(frames, &IID_IHTMLWindow2, (void**)&window2); + ok(hres == S_OK, "QueryInterface(IID_IHTMLWindow2) failed: 0x%08lx\n", hres); + todo_wine ok(window != window2, "window == window2\n"); + + hres = IHTMLWindow2_get_self(window, &self); + ok(hres == S_OK, "get_self failed: %08lx\n", hres); + ok(self == window2, "self != window2\n"); + IHTMLWindow2_Release(window2); + IHTMLWindow2_Release(self); + test_frames_collection(frames, L"fr1"); IHTMLFramesCollection2_Release(frames);
diff --git a/dlls/mshtml/tests/events.c b/dlls/mshtml/tests/events.c index 64b07c750dc..e5b9984e546 100644 --- a/dlls/mshtml/tests/events.c +++ b/dlls/mshtml/tests/events.c @@ -3343,6 +3343,7 @@ static void test_doc_obj(IHTMLDocument2 *doc) IHTMLPerformance *perf, *perf2; IOmHistory *history, *history2; IHTMLScreen *screen, *screen2; + IHTMLWindow2 *self, *window2; IEventTarget *event_target; DISPPARAMS dp = { 0 }; IHTMLWindow7 *window7; @@ -3504,6 +3505,11 @@ static void test_doc_obj(IHTMLDocument2 *doc) IHTMLWindow7_Release(window7); VariantClear(&res);
+ /* Test "proxy" windows as well, they're actually outer window proxies, but not the same */ + hres = IHTMLWindow2_get_self(window, &self); + ok(hres == S_OK, "get_self failed: %08lx\n", hres); + ok(self != NULL, "self == NULL\n"); + /* Add props to location, since it gets lost on navigation, despite being same object */ bstr = SysAllocString(L"wineTestProp"); hres = IHTMLLocation_QueryInterface(location, &IID_IDispatchEx, (void**)&dispex); @@ -3658,6 +3664,12 @@ static void test_doc_obj(IHTMLDocument2 *doc) IHTMLPerformance_Release(perf); IHTMLWindow7_Release(window7); VariantClear(&res); + + hres = IHTMLWindow2_get_self(window, &window2); + ok(hres == S_OK, "get_self failed: %08lx\n", hres); + ok(self == window2, "self != window2\n"); + IHTMLWindow2_Release(window2); + IHTMLWindow2_Release(self); }
static void test_create_event(IHTMLDocument2 *doc) diff --git a/dlls/mshtml/tests/jstest.html b/dlls/mshtml/tests/jstest.html index 3bf9f316e7a..81fbea0c493 100644 --- a/dlls/mshtml/tests/jstest.html +++ b/dlls/mshtml/tests/jstest.html @@ -76,8 +76,8 @@ function test_document_name_as_index() { ok("iframeid" in window, "iframeid is not in window"); e = document.getElementById("iframeid"); ok(!!e, "e is null"); - ok(iframeid != e, "iframeid == e"); - ok(iframeid.frameElement === e, "frameid != e.contentWindow"); + ok(iframeid === e.contentWindow.self, "frameid != e.contentWindow.self"); + ok(iframeid.frameElement === e, "frameid.frameElement != e"); }
function test_remove_style_attribute() { diff --git a/dlls/mshtml/tests/script.c b/dlls/mshtml/tests/script.c index de1fd056169..68ad3002a7f 100644 --- a/dlls/mshtml/tests/script.c +++ b/dlls/mshtml/tests/script.c @@ -4498,7 +4498,6 @@ static void test_exec_script(IHTMLDocument2 *doc, const WCHAR *codew, const WCHA hres = IHTMLDocument2_get_parentWindow(doc, &window); ok(hres == S_OK, "get_parentWindow failed: %08lx\n", hres);
- todo_wine ok(iface_cmp((IUnknown *)window, (IUnknown *)window_dispex), "window != dispex_window\n");
code = SysAllocString(codew);
From: Gabriel Ivăncescu gabrielopcode@gmail.com
This would cause a leak since we have a cyclic ref now.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmlwindow.c | 1 - 1 file changed, 1 deletion(-)
diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index fc17635542d..11c7c6d892d 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -3969,7 +3969,6 @@ static void HTMLWindow_unlink(DispatchEx *dispex)
if(This->doc) { HTMLDocumentNode *doc = This->doc; - This->doc->window = NULL; This->doc = NULL; IHTMLDOMNode_Release(&doc->node.IHTMLDOMNode_iface); }
On Fri Nov 10 15:36:39 2023 +0000, Jacek Caban wrote:
For example `get_cookie` on a detached document would use URL from another document.
I see, I will look into them, thanks.
This merge request was approved by Jacek Caban.
On Fri Nov 10 15:44:39 2023 +0000, Gabriel Ivăncescu wrote:
I see, I will look into them, thanks.
I'm still reviewing them, but I looked at get_cookie now, and I believe all the usages that use the document's `outer_window` currently should not be affected in any way.
Note that the doc's `outer_window` is permanently kept right now with no sort of reference other than at creation able to be NULL (for windowless documents created via `createHTMLDocument` for instance). After the patches, at least it becomes NULL when the outer window is killed instead of crashing/accessing invalid memory, so it actually has *less* impact.
That's why I'm reviewing only cases where we actually access it via `window->base.outer_window`, but let me know if I'm missing something…