From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/ieframe/ieframe.h | 1 + dlls/ieframe/navigate.c | 49 +++++++++++-- dlls/ieframe/tests/ie.c | 156 ++++++++++++++++++++++++++++++++++++++-- 3 files changed, 198 insertions(+), 8 deletions(-)
diff --git a/dlls/ieframe/ieframe.h b/dlls/ieframe/ieframe.h index b5194f3b5fe..b03fe6e8e83 100644 --- a/dlls/ieframe/ieframe.h +++ b/dlls/ieframe/ieframe.h @@ -277,6 +277,7 @@ HRESULT go_home(DocHost*); HRESULT go_back(DocHost*); HRESULT go_forward(DocHost*); HRESULT refresh_document(DocHost*,const VARIANT*); +HRESULT get_window(DocHost*,IHTMLWindow2**); HRESULT get_location_url(DocHost*,BSTR*); HRESULT set_dochost_url(DocHost*,const WCHAR*); void handle_navigation_error(DocHost*,HRESULT,BSTR,IHTMLWindow2*); diff --git a/dlls/ieframe/navigate.c b/dlls/ieframe/navigate.c index 488ac62fbdf..48cd5997939 100644 --- a/dlls/ieframe/navigate.c +++ b/dlls/ieframe/navigate.c @@ -306,12 +306,13 @@ static HRESULT WINAPI BindStatusCallback_OnProgress(IBindStatusCallback *iface, return S_OK; }
-void handle_navigation_error(DocHost* doc_host, HRESULT hres, BSTR url, IHTMLWindow2 *win2) +void handle_navigation_error(DocHost* doc_host, HRESULT status_code, BSTR url, IHTMLWindow2 *win2) { VARIANT var_status_code, var_frame_name, var_url; DISPPARAMS dispparams; VARIANTARG params[5]; VARIANT_BOOL cancel = VARIANT_FALSE; + HRESULT hres;
dispparams.cArgs = 5; dispparams.cNamedArgs = 0; @@ -324,7 +325,7 @@ void handle_navigation_error(DocHost* doc_host, HRESULT hres, BSTR url, IHTMLWin V_VT(params+1) = VT_VARIANT|VT_BYREF; V_VARIANTREF(params+1) = &var_status_code; V_VT(&var_status_code) = VT_I4; - V_I4(&var_status_code) = hres; + V_I4(&var_status_code) = status_code;
V_VT(params+2) = VT_VARIANT|VT_BYREF; V_VARIANTREF(params+2) = &var_frame_name; @@ -347,8 +348,48 @@ void handle_navigation_error(DocHost* doc_host, HRESULT hres, BSTR url, IHTMLWin call_sink(doc_host->cps.wbe2, DISPID_NAVIGATEERROR, &dispparams); SysFreeString(V_BSTR(&var_frame_name));
- if(!cancel) - FIXME("Navigate to error page\n"); + if(!cancel) { + IHTMLPrivateWindow *priv_window; + IHTMLWindow2 *tmp; + + if(win2) + hres = IHTMLWindow2_QueryInterface(win2, &IID_IHTMLPrivateWindow, (void**)&priv_window); + else { + hres = get_window(doc_host, &tmp); + if(SUCCEEDED(hres)) { + if(!tmp) + hres = E_UNEXPECTED; + else { + hres = IHTMLWindow2_QueryInterface(tmp, &IID_IHTMLPrivateWindow, (void**)&priv_window); + IHTMLWindow2_Release(tmp); + } + } + } + if(SUCCEEDED(hres)) { + /* Error page navigation URL is a local resource (varies on native, also depending on error), + * with the fragment being the original URL of the page that failed to load. We add a query + * with the error code so the generic error page can display the actual error code there. */ + WCHAR buf[32], sysdirbuf[MAX_PATH]; + BSTR nav_url; + UINT len; + + if(SUCCEEDED(status_code)) + len = swprintf(buf, ARRAY_SIZE(buf), L"ERROR.HTM?HTTP %u", status_code); + else + len = swprintf(buf, ARRAY_SIZE(buf), L"ERROR.HTM?0x%08x", status_code); + + len = 6 /* res:// */ + GetSystemDirectoryW(sysdirbuf, ARRAY_SIZE(sysdirbuf)) + + ARRAY_SIZE(L"\shdoclc.dll/")-1 + len + 1 /* # */ + wcslen(url); + + nav_url = SysAllocStringLen(NULL, len); + if(nav_url) { + swprintf(nav_url, len + 1, L"res://%s\shdoclc.dll/%s#%s", sysdirbuf, buf, url); + IHTMLPrivateWindow_SuperNavigate(priv_window, nav_url, NULL, NULL, NULL, NULL, NULL, 2); + SysFreeString(nav_url); + } + IHTMLPrivateWindow_Release(priv_window); + } + } }
static HRESULT WINAPI BindStatusCallback_OnStopBinding(IBindStatusCallback *iface, diff --git a/dlls/ieframe/tests/ie.c b/dlls/ieframe/tests/ie.c index f5f565aa7fd..5e52baedb68 100644 --- a/dlls/ieframe/tests/ie.c +++ b/dlls/ieframe/tests/ie.c @@ -55,9 +55,72 @@ expect_ ## func = called_ ## func = FALSE; \ }while(0)
+DEFINE_EXPECT(Invoke_BEFORENAVIGATE2); DEFINE_EXPECT(Invoke_NAVIGATECOMPLETE2); +DEFINE_EXPECT(Invoke_NAVIGATEERROR); +DEFINE_EXPECT(Invoke_DOCUMENTCOMPLETE);
-static BOOL navigate_complete; +static BOOL navigate_complete, navigation_timed_out; +static const WCHAR *navigate_url; + +static BSTR get_window_url(IDispatch *webbrowser) +{ + IHTMLPrivateWindow *priv_window; + IHTMLLocation *location; + IHTMLWindow2 *window; + IServiceProvider *sp; + IHTMLDocument2 *doc; + HRESULT hres; + BSTR url; + + hres = IDispatch_QueryInterface(webbrowser, &IID_IServiceProvider, (void**)&sp); + ok(hres == S_OK, "QueryInterface(IServiceProvider) failed: %08lx\n", hres); + + hres = IServiceProvider_QueryService(sp, &SID_SHTMLWindow, &IID_IHTMLWindow2, (void**)&window); + ok(hres == S_OK, "Could not get SHTMLWindow service: %08lx\n", hres); + ok(window != NULL, "window = NULL\n"); + IServiceProvider_Release(sp); + + hres = IHTMLWindow2_QueryInterface(window, &IID_IHTMLPrivateWindow, (void**)&priv_window); + ok(hres == E_NOINTERFACE, "QueryInterface(IID_IHTMLPrivateWindow) returned: %08lx\n", hres); + + hres = IHTMLWindow2_get_document(window, &doc); + ok(hres == S_OK, "get_document failed: %08lx\n", hres); + ok(doc != NULL, "doc = NULL\n"); + IHTMLWindow2_Release(window); + + hres = IHTMLDocument2_get_parentWindow(doc, &window); + ok(hres == S_OK, "get_parentWindow failed: %08lx\n", hres); + ok(window != NULL, "window = NULL\n"); + IHTMLDocument2_Release(doc); + + hres = IHTMLWindow2_get_location(window, &location); + ok(hres == S_OK, "get_location failed: %08lx\n", hres); + ok(location != NULL, "location = NULL\n"); + IHTMLWindow2_Release(window); + + hres = IHTMLLocation_get_href(location, &url); + ok(hres == S_OK, "get_href failed: %08lx\n", hres); + ok(url != NULL, "url = NULL\n"); + IHTMLLocation_Release(location); + + return url; +} + +#define test_url(a) _test_url(__LINE__,a) +static void _test_url(unsigned line, const WCHAR *url) +{ + /* If error page, it actually returns the error page's resource URL, followed by #, followed by the original URL. + Since the error page's location varies on native, and depends on the error itself, just check for res:// here. */ + if(called_Invoke_NAVIGATEERROR) { + ok_(__FILE__,line)(!wcsncmp(url, L"res://", ARRAY_SIZE(L"res://")-1), "url is not a local resource: %s\n", wine_dbgstr_w(url)); + url = wcschr(url, '#'); + ok_(__FILE__,line)(url != NULL, "url has no fragment: %s\n", wine_dbgstr_w(url)); + ok_(__FILE__,line)(!wcscmp(url + 1, navigate_url), "url after fragment = %s\n", wine_dbgstr_w(url + 1)); + }else { + ok_(__FILE__,line)(!wcscmp(url, navigate_url), "url = %s\n", wine_dbgstr_w(url)); + } +}
static HRESULT WINAPI Dispatch_QueryInterface(IDispatch *iface, REFIID riid, void **ppv) { @@ -104,10 +167,64 @@ static HRESULT WINAPI Dispatch_Invoke(IDispatch *iface, DISPID dispIdMember, REF LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) { + VARIANT *arg; + BSTR url; + switch(dispIdMember) { + case DISPID_BEFORENAVIGATE2: + CHECK_EXPECT(Invoke_BEFORENAVIGATE2); + + arg = pDispParams->rgvarg + 5; + ok(V_VT(arg) == (VT_BYREF | VT_VARIANT), "VT = %d\n", V_VT(arg)); + ok(V_VT(V_VARIANTREF(arg)) == VT_BSTR, "VT = %d\n", V_VT(V_VARIANTREF(arg))); + + test_url(V_BSTR(V_VARIANTREF(arg))); + return S_OK; case DISPID_NAVIGATECOMPLETE2: CHECK_EXPECT(Invoke_NAVIGATECOMPLETE2); + + arg = pDispParams->rgvarg; + ok(V_VT(arg) == (VT_BYREF | VT_VARIANT), "VT = %d\n", V_VT(arg)); + ok(V_VT(V_VARIANTREF(arg)) == VT_BSTR, "VT = %d\n", V_VT(V_VARIANTREF(arg))); + todo_wine_if(called_Invoke_NAVIGATEERROR) + ok(!wcscmp(V_BSTR(V_VARIANTREF(arg)), navigate_url), "url = %s\n", wine_dbgstr_w(V_BSTR(V_VARIANTREF(arg)))); + + arg = pDispParams->rgvarg + 1; + ok(V_VT(arg) == VT_DISPATCH, "VT = %d\n", V_VT(arg)); + ok(V_DISPATCH(arg) != NULL, "V_DISPATCH = NULL\n"); + url = get_window_url(V_DISPATCH(arg)); + test_url(url); + SysFreeString(url); + return S_OK; + case DISPID_NAVIGATEERROR: + CHECK_EXPECT(Invoke_NAVIGATEERROR); + ok(!called_Invoke_NAVIGATECOMPLETE2, "NAVIGATECOMPLETE2 called before NAVIGATEERROR\n"); + + arg = pDispParams->rgvarg; + ok(V_VT(arg) == (VT_BYREF | VT_BOOL), "VT = %d\n", V_VT(arg)); + ok(*V_BOOLREF(arg) == VARIANT_FALSE, "cancel = %#x\n", *V_BOOLREF(arg)); + + arg = pDispParams->rgvarg + 3; + ok(V_VT(arg) == (VT_BYREF | VT_VARIANT), "VT = %d\n", V_VT(arg)); + ok(V_VT(V_VARIANTREF(arg)) == VT_BSTR, "VT = %d\n", V_VT(V_VARIANTREF(arg))); + ok(!wcscmp(V_BSTR(V_VARIANTREF(arg)), navigate_url), "url = %s\n", wine_dbgstr_w(V_BSTR(V_VARIANTREF(arg)))); + return S_OK; + case DISPID_DOCUMENTCOMPLETE: + CHECK_EXPECT(Invoke_DOCUMENTCOMPLETE); navigate_complete = TRUE; + + arg = pDispParams->rgvarg; + ok(V_VT(arg) == (VT_BYREF | VT_VARIANT), "VT = %d\n", V_VT(arg)); + ok(V_VT(V_VARIANTREF(arg)) == VT_BSTR, "VT = %d\n", V_VT(V_VARIANTREF(arg))); + todo_wine_if(called_Invoke_NAVIGATEERROR) + ok(!wcscmp(V_BSTR(V_VARIANTREF(arg)), navigate_url), "url = %s\n", wine_dbgstr_w(V_BSTR(V_VARIANTREF(arg)))); + + arg = pDispParams->rgvarg + 1; + ok(V_VT(arg) == VT_DISPATCH, "VT = %d\n", V_VT(arg)); + ok(V_DISPATCH(arg) != NULL, "V_DISPATCH = NULL\n"); + url = get_window_url(V_DISPATCH(arg)); + test_url(url); + SysFreeString(url); return S_OK; }
@@ -141,7 +258,8 @@ static void advise_cp(IUnknown *unk, BOOL init)
hres = IConnectionPointContainer_FindConnectionPoint(container, &DIID_DWebBrowserEvents2, &point); IConnectionPointContainer_Release(container); - ok(hres == S_OK, "FindConnectionPoint failed: %08lx\n", hres); + if(!navigation_timed_out) + ok(hres == S_OK, "FindConnectionPoint failed: %08lx\n", hres); if(FAILED(hres)) return;
@@ -211,13 +329,31 @@ static void test_window(IWebBrowser2 *wb) ok(!strcmp(buf, "IEFrame"), "Unexpected class name %s\n", buf); }
-static void test_navigate(IWebBrowser2 *wb, const WCHAR *url) +static void CALLBACK navigate_timeout(HWND hwnd, UINT msg, UINT_PTR timer, DWORD time) +{ + win_skip("Navigation timed out, skipping tests...\n"); + called_Invoke_BEFORENAVIGATE2 = TRUE; + called_Invoke_NAVIGATECOMPLETE2 = TRUE; + called_Invoke_DOCUMENTCOMPLETE = TRUE; + if(expect_Invoke_NAVIGATEERROR) + CHECK_EXPECT(Invoke_NAVIGATEERROR); + navigation_timed_out = TRUE; + navigate_complete = TRUE; +} + +static void test_navigate(IWebBrowser2 *wb, const WCHAR *url, DWORD timeout) { VARIANT urlv, emptyv; + UINT_PTR timer = 0; MSG msg; HRESULT hres;
+ SET_EXPECT(Invoke_BEFORENAVIGATE2); SET_EXPECT(Invoke_NAVIGATECOMPLETE2); + SET_EXPECT(Invoke_DOCUMENTCOMPLETE); + navigation_timed_out = FALSE; + navigate_complete = FALSE; + navigate_url = url;
V_VT(&urlv) = VT_BSTR; V_BSTR(&urlv) = SysAllocString(url); @@ -226,12 +362,20 @@ static void test_navigate(IWebBrowser2 *wb, const WCHAR *url) ok(hres == S_OK, "Navigate2 failed: %08lx\n", hres); SysFreeString(V_BSTR(&urlv));
+ if(timeout) + timer = SetTimer(NULL, 0, timeout, navigate_timeout); + while(!navigate_complete && GetMessageW(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessageW(&msg); }
+ if(timer) + KillTimer(NULL, timer); + + CHECK_CALLED(Invoke_BEFORENAVIGATE2); CHECK_CALLED(Invoke_NAVIGATECOMPLETE2); + CHECK_CALLED(Invoke_DOCUMENTCOMPLETE); }
static void test_busy(IWebBrowser2 *wb) @@ -272,7 +416,11 @@ static void test_InternetExplorer(void) test_visible(wb); test_html_window(wb); test_window(wb); - test_navigate(wb, L"http://test.winehq.org/tests/hello.html"); + test_navigate(wb, L"http://test.winehq.org/tests/hello.html", 0); + + SET_EXPECT(Invoke_NAVIGATEERROR); + test_navigate(wb, L"http://0.0.0.0:1234/#frag?query=foo&wine=bar", 6000); + CHECK_CALLED(Invoke_NAVIGATEERROR);
advise_cp(unk, FALSE);