-- v4: mshtml: Implement document.referrer. mshtml: Implement document.mimeType. mshtml: Get rid of a EVENTID_LAST special case. mshtml: Allow null or undefined func in addEventListener. mshtml: Allow null or undefined listeners in attachEvent/detachEvent. jscript: Implement VariantChangeType for VT_DISPATCH and VT_UNKNOWN.
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/jsutils.c | 10 ++++++++++ dlls/jscript/tests/caller.c | 24 +++++++++++++++++++++--- 2 files changed, 31 insertions(+), 3 deletions(-)
diff --git a/dlls/jscript/jsutils.c b/dlls/jscript/jsutils.c index 96e42625dc6..166fdc696b9 100644 --- a/dlls/jscript/jsutils.c +++ b/dlls/jscript/jsutils.c @@ -955,6 +955,16 @@ HRESULT variant_change_type(script_ctx_t *ctx, VARIANT *dst, VARIANT *src, VARTY case VT_NULL: hres = V_VT(src) == VT_NULL ? S_OK : E_NOTIMPL; break; + case VT_UNKNOWN: + case VT_DISPATCH: + if(V_VT(src) != vt) + hres = E_NOTIMPL; + else { + IUnknown_AddRef(V_UNKNOWN(src)); + V_UNKNOWN(dst) = V_UNKNOWN(src); + hres = S_OK; + } + break; default: FIXME("vt %d not implemented\n", vt); hres = E_NOTIMPL; diff --git a/dlls/jscript/tests/caller.c b/dlls/jscript/tests/caller.c index 0da8c9abb08..836f5a820a1 100644 --- a/dlls/jscript/tests/caller.c +++ b/dlls/jscript/tests/caller.c @@ -97,14 +97,14 @@ static void _call_change_type(unsigned line, IVariantChangeType *change_type, VA HRESULT hres;
VariantInit(dst); - if(V_VT(src) == VT_DISPATCH && vt != VT_BOOL) { + if(V_VT(src) != vt && vt != VT_BOOL && (V_VT(src) == VT_DISPATCH || V_VT(src) == VT_UNKNOWN)) { SET_EXPECT(OnEnterScript); SET_EXPECT(OnLeaveScript); } hres = IVariantChangeType_ChangeType(change_type, dst, src, 0, vt); ok_(__FILE__,line)(hres == S_OK, "ChangeType(%d) failed: %08lx\n", vt, hres); ok_(__FILE__,line)(V_VT(dst) == vt, "V_VT(dst) = %d\n", V_VT(dst)); - if(V_VT(src) == VT_DISPATCH && vt != VT_BOOL) { + if(V_VT(src) != vt && vt != VT_BOOL && (V_VT(src) == VT_DISPATCH || V_VT(src) == VT_UNKNOWN)) { CHECK_CALLED(OnEnterScript); CHECK_CALLED(OnLeaveScript); } @@ -118,7 +118,7 @@ static void _change_type_fail(unsigned line, IVariantChangeType *change_type, VA
V_VT(&v) = VT_EMPTY; hres = IVariantChangeType_ChangeType(change_type, &v, src, 0, vt); - ok_(__FILE__,line)(hres == exhres, "ChangeType failed: %08lx, expected %08lx\n", hres, exhres); + ok_(__FILE__,line)(hres == exhres, "ChangeType failed: %08lx, expected %08lx [%d]\n", hres, exhres, V_VT(src)); }
static void test_change_type(IVariantChangeType *change_type, VARIANT *src, const conv_results_t *ex) @@ -158,6 +158,20 @@ static void test_change_type(IVariantChangeType *change_type, VARIANT *src, cons
call_change_type(change_type, &v, src, VT_I2); ok(V_I2(&v) == (INT16)ex->int_result, "V_I2(v) = %d, expected %d\n", V_I2(&v), ex->int_result); + + if(V_VT(src) != VT_UNKNOWN) + change_type_fail(change_type, src, VT_UNKNOWN, E_NOTIMPL); + else { + call_change_type(change_type, &v, src, VT_UNKNOWN); + ok(V_UNKNOWN(&v) == V_UNKNOWN(src), "V_UNKNOWN(v) != V_UNKNOWN(src)\n"); + } + + if(V_VT(src) != VT_DISPATCH) + change_type_fail(change_type, src, VT_DISPATCH, E_NOTIMPL); + else { + call_change_type(change_type, &v, src, VT_DISPATCH); + ok(V_DISPATCH(&v) == V_DISPATCH(src), "V_DISPATCH(v) != V_DISPATCH(src)\n"); + } }
static void test_change_types(IVariantChangeType *change_type, IDispatch *obj_disp) @@ -200,6 +214,10 @@ static void test_change_types(IVariantChangeType *change_type, IDispatch *obj_di V_VT(&v) = VT_NULL; test_change_type(change_type, &v, &null_results);
+ V_VT(&v) = VT_UNKNOWN; + V_UNKNOWN(&v) = (IUnknown*)obj_disp; + test_change_type(change_type, &v, &obj_results); + V_VT(&v) = VT_DISPATCH; V_DISPATCH(&v) = obj_disp; test_change_type(change_type, &v, &obj_results);
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/dispex.c | 11 +++++++- dlls/mshtml/htmlevent.c | 5 ++++ dlls/mshtml/tests/script.c | 57 ++++++++++++++++++++++++++++++++++++-- 3 files changed, 70 insertions(+), 3 deletions(-)
diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index ebb1a675d91..d8aaf819f58 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -1072,7 +1072,8 @@ HRESULT change_type(VARIANT *dst, VARIANT *src, VARTYPE vt, IServiceProvider *ca if(SUCCEEDED(hres)) { hres = IVariantChangeType_ChangeType(change_type, dst, src, LOCALE_NEUTRAL, vt); IVariantChangeType_Release(change_type); - return hres; + if(SUCCEEDED(hres)) + return S_OK; } }
@@ -1084,6 +1085,14 @@ HRESULT change_type(VARIANT *dst, VARIANT *src, VARTYPE vt, IServiceProvider *ca return S_OK; } break; + case VT_UNKNOWN: + case VT_DISPATCH: + if(V_VT(src) == VT_EMPTY || V_VT(src) == VT_NULL) { + V_VT(dst) = vt; + V_DISPATCH(dst) = NULL; + return S_OK; + } + break; }
return VariantChangeType(dst, src, 0, vt); diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c index 581d949a447..ebedff82564 100644 --- a/dlls/mshtml/htmlevent.c +++ b/dlls/mshtml/htmlevent.c @@ -3870,6 +3870,11 @@ HRESULT attach_event(EventTarget *event_target, BSTR name, IDispatch *disp, VARI event_listener_t *listener; eventid_t eid;
+ if(!disp) { + *res = VARIANT_FALSE; + return S_OK; + } + eid = attr_to_eid(name); if(eid == EVENTID_LAST) { WARN("Unknown event\n"); diff --git a/dlls/mshtml/tests/script.c b/dlls/mshtml/tests/script.c index 14e3a148239..1a0ee4eb2c7 100644 --- a/dlls/mshtml/tests/script.c +++ b/dlls/mshtml/tests/script.c @@ -362,6 +362,8 @@ static ULONG WINAPI VariantChangeType_Release(IVariantChangeType *iface) return 1; }
+static BOOL ChangeType_expect_null_dispatch; + static HRESULT WINAPI VariantChangeType_ChangeType(IVariantChangeType *iface, VARIANT *dst, VARIANT *src, LCID lcid, VARTYPE vt) { CHECK_EXPECT(ChangeType); @@ -369,9 +371,15 @@ static HRESULT WINAPI VariantChangeType_ChangeType(IVariantChangeType *iface, VA ok(dst != NULL, "dst = NULL\n"); ok(V_VT(dst) == VT_EMPTY, "V_VT(dst) = %d\n", V_VT(dst)); ok(src != NULL, "src = NULL\n"); + ok(lcid == LOCALE_NEUTRAL, "lcid = %ld\n", lcid); + if(ChangeType_expect_null_dispatch) { + ok(V_VT(src) == VT_NULL, "V_VT(src) = %d\n", V_VT(src)); + ok(vt == VT_DISPATCH, "vt = %d\n", vt); + /* native jscript returns E_NOTIMPL, use a "valid" error to test that it doesn't matter */ + return E_OUTOFMEMORY; + } ok(V_VT(src) == VT_I4, "V_VT(src) = %d\n", V_VT(src)); ok(V_I4(src) == 0xf0f0f0, "V_I4(src) = %lx\n", V_I4(src)); - ok(lcid == LOCALE_NEUTRAL, "lcid = %ld\n", lcid); ok(vt == VT_BSTR, "vt = %d\n", vt);
V_VT(dst) = VT_BSTR; @@ -2292,10 +2300,13 @@ static void test_global_id(void)
static void test_arg_conv(IHTMLWindow2 *window) { + DISPPARAMS dp = { 0 }; IHTMLDocument2 *doc; IDispatchEx *dispex; IHTMLElement *elem; - VARIANT v; + VARIANT v, args[2]; + DISPID id; + BSTR bstr; HRESULT hres;
hres = IHTMLWindow2_get_document(window, &doc); @@ -2323,7 +2334,49 @@ static void test_arg_conv(IHTMLWindow2 *window) ok(hres == S_OK, "InvokeEx failed: %08lx\n", hres); ok(V_VT(&v) == VT_BSTR, "V_VT(var)=%d\n", V_VT(&v)); ok(!V_BSTR(&v), "V_BSTR(&var) = %s\n", wine_dbgstr_w(V_BSTR(&v))); + IDispatchEx_Release(dispex); + + hres = IHTMLWindow2_QueryInterface(window, &IID_IDispatchEx, (void**)&dispex); + ok(hres == S_OK, "Could not get IDispatchEx iface: %08lx\n", hres); + + SET_EXPECT(GetScriptDispatch); + bstr = SysAllocString(L"attachEvent"); + hres = IDispatchEx_GetDispID(dispex, bstr, fdexNameCaseSensitive, &id); + ok(hres == S_OK, "GetDispID failed: %08lx\n", hres); + CHECK_CALLED(GetScriptDispatch); + SysFreeString(bstr); + + ChangeType_expect_null_dispatch = TRUE; + SET_EXPECT(QS_VariantConversion); + SET_EXPECT(ChangeType); + dp.cArgs = 2; + dp.rgvarg = args; + V_VT(&args[1]) = VT_BSTR; + V_BSTR(&args[1]) = SysAllocString(L"onload"); + V_VT(&args[0]) = VT_NULL; + hres = IDispatchEx_InvokeEx(dispex, id, LOCALE_NEUTRAL, DISPATCH_METHOD, &dp, &v, NULL, &caller_sp); + ok(hres == S_OK, "InvokeEx failed: %08lx\n", hres); + ok(V_VT(&v) == VT_BOOL, "V_VT(var) = %d\n", V_VT(&v)); + ok(V_BOOL(&v) == VARIANT_FALSE, "V_BOOL(var) = %d\n", V_BOOL(&v)); + CHECK_CALLED(QS_VariantConversion); + CHECK_CALLED(ChangeType); + + SET_EXPECT(GetScriptDispatch); + bstr = SysAllocString(L"detachEvent"); + hres = IDispatchEx_GetDispID(dispex, bstr, fdexNameCaseSensitive, &id); + ok(hres == S_OK, "GetDispID failed: %08lx\n", hres); + CHECK_CALLED(GetScriptDispatch); + SysFreeString(bstr); + + SET_EXPECT(QS_VariantConversion); + SET_EXPECT(ChangeType); + hres = IDispatchEx_InvokeEx(dispex, id, LOCALE_NEUTRAL, DISPATCH_METHOD, &dp, NULL, NULL, &caller_sp); + ok(hres == S_OK, "InvokeEx failed: %08lx\n", hres); + CHECK_CALLED(QS_VariantConversion); + CHECK_CALLED(ChangeType);
+ ChangeType_expect_null_dispatch = FALSE; + SysFreeString(V_BSTR(&args[1])); IDispatchEx_Release(dispex); }
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmlevent.c | 3 +++ dlls/mshtml/tests/events.c | 2 ++ dlls/mshtml/tests/events.js | 15 +++++++++++++++ 3 files changed, 20 insertions(+)
diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c index ebedff82564..7deb51ad1e9 100644 --- a/dlls/mshtml/htmlevent.c +++ b/dlls/mshtml/htmlevent.c @@ -4105,6 +4105,9 @@ static HRESULT WINAPI EventTarget_addEventListener(IEventTarget *iface, BSTR typ
TRACE("(%p)->(%s %p %x)\n", This, debugstr_w(type), function, capture);
+ if(!function) + return S_OK; + container = get_listener_container(This, type, TRUE); if(!container) return E_OUTOFMEMORY; diff --git a/dlls/mshtml/tests/events.c b/dlls/mshtml/tests/events.c index 1819bc6bdd9..b53851d61bf 100644 --- a/dlls/mshtml/tests/events.c +++ b/dlls/mshtml/tests/events.c @@ -1898,6 +1898,7 @@ static void test_onclick(IHTMLDocument2 *doc) VariantClear(&v);
if(document_mode >= 9) { + add_event_listener((IUnknown*)div, L"click", NULL, VARIANT_FALSE); add_event_listener((IUnknown*)div, L"click", (IDispatch*)&div_onclick_capture_obj, VARIANT_TRUE); add_event_listener((IUnknown*)div, L"click", (IDispatch*)&div_onclick_bubble_obj, VARIANT_FALSE); } @@ -2052,6 +2053,7 @@ static void test_onclick(IHTMLDocument2 *doc) doc_detach_event(doc, L"onclick", (IDispatch*)&doc_onclick_attached_obj);
if(document_mode >= 9) { + remove_event_listener((IUnknown*)div, L"click", NULL, VARIANT_FALSE); remove_event_listener((IUnknown*)div, L"click", (IDispatch*)&div_onclick_capture_obj, VARIANT_TRUE); remove_event_listener((IUnknown*)div, L"click", (IDispatch*)&div_onclick_bubble_obj, VARIANT_FALSE); } diff --git a/dlls/mshtml/tests/events.js b/dlls/mshtml/tests/events.js index 997e583ad20..156330e984b 100644 --- a/dlls/mshtml/tests/events.js +++ b/dlls/mshtml/tests/events.js @@ -198,6 +198,21 @@ sync_test("add_remove_listener", function() { calls = ""; div.click(); ok(calls === "", "calls = " + calls); + + /* test undefined function argument */ + div.addEventListener("click", undefined, false); + + calls = ""; + div.click(); + ok(calls === "", "calls = " + calls); + + div.addEventListener("click", listener, false); + div.removeEventListener("click", undefined); + + calls = ""; + div.click(); + ok(calls === "listener,", "calls = " + calls); + div.removeEventListener("click", listener); });
sync_test("event_phase", function() {
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com ---
The special entry has no flags, so there's no need for this. --- dlls/mshtml/htmlevent.c | 2 -- 1 file changed, 2 deletions(-)
diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c index 7deb51ad1e9..59a8d50d40e 100644 --- a/dlls/mshtml/htmlevent.c +++ b/dlls/mshtml/htmlevent.c @@ -3674,8 +3674,6 @@ HRESULT ensure_doc_nsevent_handler(HTMLDocumentNode *doc, nsIDOMNode *nsnode, ev doc->event_vector[eid] = TRUE; eid = EVENTID_BLUR; break; - case EVENTID_LAST: - return S_OK; default: break; }
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmldoc.c | 23 ++++++- dlls/mshtml/main.c | 103 ++++++++++++++++++++++++++++++ dlls/mshtml/mshtml_private.h | 1 + dlls/mshtml/tests/Makefile.in | 2 +- dlls/mshtml/tests/documentmode.js | 1 + dlls/mshtml/tests/htmldoc.c | 101 +++++++++++++++++++++++++++++ dlls/mshtml/tests/script.c | 99 ++++++++++++++++++++++++++++ 7 files changed, 327 insertions(+), 3 deletions(-)
diff --git a/dlls/mshtml/htmldoc.c b/dlls/mshtml/htmldoc.c index e3ef57ecfee..e7722f9c602 100644 --- a/dlls/mshtml/htmldoc.c +++ b/dlls/mshtml/htmldoc.c @@ -1245,8 +1245,27 @@ static HRESULT WINAPI HTMLDocument_get_defaultCharset(IHTMLDocument2 *iface, BST static HRESULT WINAPI HTMLDocument_get_mimeType(IHTMLDocument2 *iface, BSTR *p) { HTMLDocumentNode *This = impl_from_IHTMLDocument2(iface); - FIXME("(%p)->(%p)\n", This, p); - return E_NOTIMPL; + const PRUnichar *content_type; + nsAString nsstr; + nsresult nsres; + HRESULT hres; + + TRACE("(%p)->(%p)\n", This, p); + + *p = NULL; + + if(This->window && This->window->base.outer_window->readystate == READYSTATE_UNINITIALIZED) + return (*p = SysAllocString(L"")) ? S_OK : E_FAIL; + + nsAString_InitDepend(&nsstr, NULL); + nsres = nsIDOMHTMLDocument_GetContentType(This->nsdoc, &nsstr); + if(NS_FAILED(nsres)) + return map_nsresult(nsres); + + nsAString_GetData(&nsstr, &content_type); + hres = get_mime_type_display_name(content_type, p); + nsAString_Finish(&nsstr); + return hres; }
static HRESULT WINAPI HTMLDocument_get_fileSize(IHTMLDocument2 *iface, BSTR *p) diff --git a/dlls/mshtml/main.c b/dlls/mshtml/main.c index ae14137bc54..cfc183b0a32 100644 --- a/dlls/mshtml/main.c +++ b/dlls/mshtml/main.c @@ -126,6 +126,109 @@ BSTR charset_string_from_cp(UINT cp) return SysAllocString(info.wszWebCharset); }
+HRESULT get_mime_type_display_name(const WCHAR *content_type, BSTR *ret) +{ + /* undocumented */ + extern BOOL WINAPI GetMIMETypeSubKeyW(LPCWSTR,LPWSTR,DWORD); + + WCHAR buffer[128], ext[128], *str, *progid; + DWORD type, len; + LSTATUS status; + HRESULT hres; + CLSID clsid; + HKEY key; + + str = buffer; + if(!GetMIMETypeSubKeyW(content_type, buffer, ARRAY_SIZE(buffer))) { + len = wcslen(content_type) + 32; + for(;;) { + if(!(str = heap_alloc(len * sizeof(WCHAR)))) + return E_OUTOFMEMORY; + if(GetMIMETypeSubKeyW(content_type, str, len)) + break; + heap_free(str); + len *= 2; + } + } + + status = RegOpenKeyExW(HKEY_CLASSES_ROOT, str, 0, KEY_QUERY_VALUE, &key); + if(str != buffer) + heap_free(str); + if(status != ERROR_SUCCESS) + goto no_mime_database; + + len = sizeof(ext); + status = RegQueryValueExW(key, L"Extension", NULL, &type, (BYTE*)ext, &len); + if(status != ERROR_SUCCESS || type != REG_SZ) { + len = sizeof(buffer); + status = RegQueryValueExW(key, L"CLSID", NULL, &type, (BYTE*)buffer, &len); + if(status != ERROR_SUCCESS || type != REG_SZ || CLSIDFromString(buffer, &clsid) != S_OK) + goto fail; + + hres = ProgIDFromCLSID(&clsid, &progid); + if(hres == E_OUTOFMEMORY) { + RegCloseKey(key); + return hres; + } + if(hres != S_OK) + goto fail; + }else { + progid = ext; + } + + len = ARRAY_SIZE(buffer); + str = buffer; + for(;;) { + hres = AssocQueryStringW(ASSOCF_NOTRUNCATE, ASSOCSTR_FRIENDLYDOCNAME, progid, NULL, str, &len); + if(hres == S_OK && len) + break; + if(str != buffer) + heap_free(str); + if(hres != E_POINTER) { + if(progid != ext) { + CoTaskMemFree(progid); + goto fail; + } + + /* Try from CLSID */ + len = sizeof(buffer); + status = RegQueryValueExW(key, L"CLSID", NULL, &type, (BYTE*)buffer, &len); + if(status != ERROR_SUCCESS || type != REG_SZ || CLSIDFromString(buffer, &clsid) != S_OK) + goto fail; + + hres = ProgIDFromCLSID(&clsid, &progid); + if(hres == E_OUTOFMEMORY) { + RegCloseKey(key); + return hres; + } + if(hres != S_OK) + goto fail; + + len = ARRAY_SIZE(buffer); + str = buffer; + continue; + } + str = heap_alloc(len * sizeof(WCHAR)); + } + if(progid != ext) + CoTaskMemFree(progid); + RegCloseKey(key); + + *ret = SysAllocString(str); + if(str != buffer) + heap_free(str); + return *ret ? S_OK : E_OUTOFMEMORY; + +fail: + RegCloseKey(key); +no_mime_database: + WARN("Did not find MIME in database for %s\n", debugstr_w(content_type)); + + /* native seems to return "File" when it doesn't know the content type */ + *ret = SysAllocString(L"File"); + return *ret ? S_OK : E_OUTOFMEMORY; +} + IInternetSecurityManager *get_security_manager(void) { if(!security_manager) { diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 49393c977cc..c403b4efc54 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -1455,6 +1455,7 @@ extern void *call_thiscall_func; compat_mode_t get_max_compat_mode(IUri*) DECLSPEC_HIDDEN; UINT cp_from_charset_string(BSTR) DECLSPEC_HIDDEN; BSTR charset_string_from_cp(UINT) DECLSPEC_HIDDEN; +HRESULT get_mime_type_display_name(const WCHAR*,BSTR*) DECLSPEC_HIDDEN; HINSTANCE get_shdoclc(void) DECLSPEC_HIDDEN; void set_statustext(HTMLDocumentObj*,INT,LPCWSTR) DECLSPEC_HIDDEN; IInternetSecurityManager *get_security_manager(void) DECLSPEC_HIDDEN; diff --git a/dlls/mshtml/tests/Makefile.in b/dlls/mshtml/tests/Makefile.in index fac78316986..ce258d13ada 100644 --- a/dlls/mshtml/tests/Makefile.in +++ b/dlls/mshtml/tests/Makefile.in @@ -1,5 +1,5 @@ TESTDLL = mshtml.dll -IMPORTS = ole32 oleaut32 wininet user32 urlmon gdi32 advapi32 +IMPORTS = ole32 oleaut32 shlwapi wininet user32 urlmon gdi32 advapi32 C_SRCS = \ activex.c \ dom.c \ diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index a9ff38d5781..a0f170c73b4 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -311,6 +311,7 @@ sync_test("doc_props", function() { }
var v = document.documentMode; + ok(document.mimeType === external.getExpectedMimeType("text/html"), "mimeType = " + document.mimeType);
test_exposed("onstorage", v < 9); test_exposed("textContent", v >= 9); diff --git a/dlls/mshtml/tests/htmldoc.c b/dlls/mshtml/tests/htmldoc.c index 7764f256ab0..158efece93c 100644 --- a/dlls/mshtml/tests/htmldoc.c +++ b/dlls/mshtml/tests/htmldoc.c @@ -27,6 +27,7 @@ #include "winbase.h" #include "initguid.h" #include "ole2.h" +#include "shlwapi.h" #include "mshtml.h" #include "docobj.h" #include "docobjectservice.h" @@ -449,6 +450,85 @@ static void _test_current_url(unsigned line, IUnknown *unk, const WCHAR *exurl) IHTMLDocument2_Release(doc); }
+static BSTR get_mime_type_display_name(const WCHAR *content_type) +{ + WCHAR buffer[128], ext[128], *str, *progid; + HKEY key, type_key; + DWORD type, len; + LSTATUS status; + HRESULT hres; + CLSID clsid; + BSTR ret; + + status = RegOpenKeyExW(HKEY_CLASSES_ROOT, L"MIME\Database\Content Type", 0, KEY_READ, &key); + if(status != ERROR_SUCCESS) + goto no_mime_database; + + status = RegOpenKeyExW(key, content_type, 0, KEY_QUERY_VALUE, &type_key); + RegCloseKey(key); + if(status != ERROR_SUCCESS) + goto no_mime_database; + + len = sizeof(ext); + status = RegQueryValueExW(type_key, L"Extension", NULL, &type, (BYTE*)ext, &len); + if(status != ERROR_SUCCESS || type != REG_SZ) { + len = sizeof(buffer); + status = RegQueryValueExW(type_key, L"CLSID", NULL, &type, (BYTE*)buffer, &len); + + if(status != ERROR_SUCCESS || type != REG_SZ || CLSIDFromString(buffer, &clsid) != S_OK || + ProgIDFromCLSID(&clsid, &progid) != S_OK) + goto fail; + }else { + /* For some reason w1064v1809 testbot uses .htm here, despite .html being set in the database */ + if(!wcscmp(ext, L".html")) + wcscpy(ext, L".htm"); + progid = ext; + } + + len = ARRAY_SIZE(buffer); + str = buffer; + for(;;) { + hres = AssocQueryStringW(ASSOCF_NOTRUNCATE, ASSOCSTR_FRIENDLYDOCNAME, progid, NULL, str, &len); + if(hres == S_OK && len) + break; + if(str != buffer) + free(str); + if(hres != E_POINTER) { + if(progid != ext) { + CoTaskMemFree(progid); + goto fail; + } + + /* Try from CLSID */ + len = sizeof(buffer); + status = RegQueryValueExW(type_key, L"CLSID", NULL, &type, (BYTE*)buffer, &len); + + if(status != ERROR_SUCCESS || type != REG_SZ || CLSIDFromString(buffer, &clsid) != S_OK || + ProgIDFromCLSID(&clsid, &progid) != S_OK) + goto fail; + + len = ARRAY_SIZE(buffer); + str = buffer; + continue; + } + str = malloc(len * sizeof(WCHAR)); + } + if(progid != ext) + CoTaskMemFree(progid); + RegCloseKey(type_key); + + ret = SysAllocString(str); + if(str != buffer) + free(str); + return ret; + +fail: + RegCloseKey(type_key); +no_mime_database: + trace("Did not find MIME in database for %s\n", debugstr_w(content_type)); + return SysAllocString(L"File"); +} + DEFINE_GUID(IID_External_unk,0x30510406,0x98B5,0x11CF,0xBB,0x82,0x00,0xAA,0x00,0xBD,0xCE,0x0B);
static HRESULT WINAPI External_QueryInterface(IDispatch *iface, REFIID riid, void **ppv) @@ -7680,6 +7760,25 @@ static void test_QueryInterface(IHTMLDocument2 *htmldoc) IUnknown_Release(qi); }
+static void test_mimeType(IHTMLDocument2 *doc, const WCHAR *content_type) +{ + BSTR mime_type = (BSTR)0xdeadbeef; + HRESULT hres; + + hres = IHTMLDocument2_get_mimeType(doc, &mime_type); + if(content_type) { + BSTR display_name = get_mime_type_display_name(content_type); + ok(hres == S_OK, "get_mimeType returned %08lx\n", hres); + ok(!wcscmp(mime_type, display_name), "mime type = %s, expected %s\n", + debugstr_w(mime_type), debugstr_w(display_name)); + SysFreeString(display_name); + }else { + ok(hres == S_OK || broken(hres == E_FAIL), "get_mimeType returned %08lx\n", hres); + ok(!mime_type || !mime_type[0], "mime type = %s\n", debugstr_w(mime_type)); + } + SysFreeString(mime_type); +} + static void init_test(enum load_state_t ls) { doc_unk = NULL; doc_hwnd = last_hwnd = NULL; @@ -7733,6 +7832,7 @@ static void test_HTMLDocument(BOOL do_load, BOOL mime) test_GetCurMoniker((IUnknown*)doc, &Moniker, NULL, FALSE); test_elem_from_point(doc); } + test_mimeType(doc, do_load ? L"text/html" : NULL);
test_MSHTML_QueryStatus(doc, OLECMDF_SUPPORTED); test_OleCommandTarget_fail(doc); @@ -7844,6 +7944,7 @@ static void test_MHTMLDocument(void) set_custom_uihandler(doc, &CustomDocHostUIHandler); test_GetCurMoniker((IUnknown*)doc, NULL, L"mhtml:winetest:doc", FALSE); test_download(0); + test_mimeType(doc, L"text/html");
test_exec_onunload(doc); test_UIDeactivate(); diff --git a/dlls/mshtml/tests/script.c b/dlls/mshtml/tests/script.c index 1a0ee4eb2c7..de79717f5c8 100644 --- a/dlls/mshtml/tests/script.c +++ b/dlls/mshtml/tests/script.c @@ -26,6 +26,7 @@ #include "windef.h" #include "winbase.h" #include "ole2.h" +#include "shlwapi.h" #include "wininet.h" #include "docobj.h" #include "dispex.h" @@ -156,6 +157,7 @@ DEFINE_EXPECT(GetTypeInfo); #define DISPID_EXTERNAL_IS_ENGLISH 0x300009 #define DISPID_EXTERNAL_LIST_SEP 0x30000A #define DISPID_EXTERNAL_TEST_VARS 0x30000B +#define DISPID_EXTERNAL_GETMIMETYPE 0x30000C
static const GUID CLSID_TestScript = {0x178fc163,0xf585,0x4e24,{0x9c,0x13,0x4b,0xb7,0xfa,0xf8,0x07,0x46}}; @@ -199,6 +201,85 @@ static BOOL init_key(const char *key_name, const char *def_value, BOOL init) return res == ERROR_SUCCESS; }
+static BSTR get_mime_type_display_name(const WCHAR *content_type) +{ + WCHAR buffer[128], ext[128], *str, *progid; + HKEY key, type_key; + DWORD type, len; + LSTATUS status; + HRESULT hres; + CLSID clsid; + BSTR ret; + + status = RegOpenKeyExW(HKEY_CLASSES_ROOT, L"MIME\Database\Content Type", 0, KEY_READ, &key); + if(status != ERROR_SUCCESS) + goto no_mime_database; + + status = RegOpenKeyExW(key, content_type, 0, KEY_QUERY_VALUE, &type_key); + RegCloseKey(key); + if(status != ERROR_SUCCESS) + goto no_mime_database; + + len = sizeof(ext); + status = RegQueryValueExW(type_key, L"Extension", NULL, &type, (BYTE*)ext, &len); + if(status != ERROR_SUCCESS || type != REG_SZ) { + len = sizeof(buffer); + status = RegQueryValueExW(type_key, L"CLSID", NULL, &type, (BYTE*)buffer, &len); + + if(status != ERROR_SUCCESS || type != REG_SZ || CLSIDFromString(buffer, &clsid) != S_OK || + ProgIDFromCLSID(&clsid, &progid) != S_OK) + goto fail; + }else { + /* For some reason w1064v1809 testbot uses .htm here, despite .html being set in the database */ + if(!wcscmp(ext, L".html")) + wcscpy(ext, L".htm"); + progid = ext; + } + + len = ARRAY_SIZE(buffer); + str = buffer; + for(;;) { + hres = AssocQueryStringW(ASSOCF_NOTRUNCATE, ASSOCSTR_FRIENDLYDOCNAME, progid, NULL, str, &len); + if(hres == S_OK && len) + break; + if(str != buffer) + free(str); + if(hres != E_POINTER) { + if(progid != ext) { + CoTaskMemFree(progid); + goto fail; + } + + /* Try from CLSID */ + len = sizeof(buffer); + status = RegQueryValueExW(type_key, L"CLSID", NULL, &type, (BYTE*)buffer, &len); + + if(status != ERROR_SUCCESS || type != REG_SZ || CLSIDFromString(buffer, &clsid) != S_OK || + ProgIDFromCLSID(&clsid, &progid) != S_OK) + goto fail; + + len = ARRAY_SIZE(buffer); + str = buffer; + continue; + } + str = malloc(len * sizeof(WCHAR)); + } + if(progid != ext) + CoTaskMemFree(progid); + RegCloseKey(type_key); + + ret = SysAllocString(str); + if(str != buffer) + free(str); + return ret; + +fail: + RegCloseKey(type_key); +no_mime_database: + trace("Did not find MIME in database for %s\n", debugstr_w(content_type)); + return SysAllocString(L"File"); +} + static void test_script_vars(unsigned argc, VARIANTARG *argv) { static const WCHAR *const jsobj_names[] = { L"abc", L"foO", L"bar", L"TostRing", L"hasownpropERty" }; @@ -711,6 +792,10 @@ static HRESULT WINAPI externalDisp_GetDispID(IDispatchEx *iface, BSTR bstrName, *pid = DISPID_EXTERNAL_TEST_VARS; return S_OK; } + if(!lstrcmpW(bstrName, L"getExpectedMimeType")) { + *pid = DISPID_EXTERNAL_GETMIMETYPE; + return S_OK; + }
ok(0, "unexpected name %s\n", wine_dbgstr_w(bstrName)); return DISP_E_UNKNOWNNAME; @@ -944,6 +1029,20 @@ static HRESULT WINAPI externalDisp_InvokeEx(IDispatchEx *iface, DISPID id, LCID test_script_vars(pdp->cArgs, pdp->rgvarg); return S_OK;
+ case DISPID_EXTERNAL_GETMIMETYPE: + ok(pdp != NULL, "pdp == NULL\n"); + ok(pdp->rgvarg != NULL, "rgvarg == NULL\n"); + ok(V_VT(pdp->rgvarg) == VT_BSTR, "VT(rgvarg) = %d\n", V_VT(pdp->rgvarg)); + ok(!pdp->rgdispidNamedArgs, "rgdispidNamedArgs != NULL\n"); + ok(pdp->cArgs == 1, "cArgs = %d\n", pdp->cArgs); + ok(!pdp->cNamedArgs, "cNamedArgs = %d\n", pdp->cNamedArgs); + ok(pvarRes != NULL, "pvarRes == NULL\n"); + ok(V_VT(pvarRes) == VT_EMPTY, "V_VT(pvarRes) = %d\n", V_VT(pvarRes)); + ok(pei != NULL, "pei == NULL\n"); + V_BSTR(pvarRes) = get_mime_type_display_name(V_BSTR(pdp->rgvarg)); + V_VT(pvarRes) = V_BSTR(pvarRes) ? VT_BSTR : VT_NULL; + return S_OK; + default: ok(0, "unexpected call\n"); return E_NOTIMPL;
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmldoc.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-)
diff --git a/dlls/mshtml/htmldoc.c b/dlls/mshtml/htmldoc.c index e7722f9c602..54a8fe7980d 100644 --- a/dlls/mshtml/htmldoc.c +++ b/dlls/mshtml/htmldoc.c @@ -1040,11 +1040,23 @@ static HRESULT WINAPI HTMLDocument_get_vlinkColor(IHTMLDocument2 *iface, VARIANT static HRESULT WINAPI HTMLDocument_get_referrer(IHTMLDocument2 *iface, BSTR *p) { HTMLDocumentNode *This = impl_from_IHTMLDocument2(iface); + const PRUnichar *referrer; + nsAString nsstr; + nsresult nsres;
- FIXME("(%p)->(%p)\n", This, p); + TRACE("(%p)->(%p)\n", This, p);
*p = NULL; - return S_OK; + + nsAString_InitDepend(&nsstr, NULL); + nsres = nsIDOMHTMLDocument_GetReferrer(This->nsdoc, &nsstr); + if(NS_FAILED(nsres)) + return map_nsresult(nsres); + + nsAString_GetData(&nsstr, &referrer); + *p = SysAllocString(referrer); + nsAString_Finish(&nsstr); + return *p || !referrer ? S_OK : E_OUTOFMEMORY; }
static HRESULT WINAPI HTMLDocument_get_location(IHTMLDocument2 *iface, IHTMLLocation **p)
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=125516
Your paranoid android.
=== w10pro64 (32 bit report) ===
mshtml: events.c:1098: Test failed: unexpected call img_onerror events: Timeout
=== w10pro64 (64 bit report) ===
mshtml: events.c:1098: Test failed: unexpected call img_onerror events: Timeout
=== w10pro64 (32 bit report) ===
mshtml: htmldoc.c:3164: Test failed: Incorrect error code: -2146697211 htmldoc.c:3169: Test failed: Page address: L"http://test.winehq.org/tests/winehq_snapshot/" htmldoc.c:5951: Test failed: expected OnChanged_1012 htmldoc.c:5952: Test failed: expected Exec_HTTPEQUIV htmldoc.c:5954: Test failed: expected Exec_SETTITLE htmldoc.c:5995: Test failed: expected FireNavigateComplete2
Sorry for the noise, the commit message was too long and I messed up the last commit also when pushing.
Jacek Caban (@jacek) commented about dlls/mshtml/htmldoc.c:
- FIXME("(%p)->(%p)\n", This, p);
TRACE("(%p)->(%p)\n", This, p);
*p = NULL;
- return S_OK;
- nsAString_InitDepend(&nsstr, NULL);
- nsres = nsIDOMHTMLDocument_GetReferrer(This->nsdoc, &nsstr);
- if(NS_FAILED(nsres))
return map_nsresult(nsres);
- nsAString_GetData(&nsstr, &referrer);
- *p = SysAllocString(referrer);
- nsAString_Finish(&nsstr);
- return *p || !referrer ? S_OK : E_OUTOFMEMORY;
You could just use `return_nsstr()` here.
Jacek Caban (@jacek) commented about dlls/mshtml/main.c:
len = wcslen(content_type) + 32;
for(;;) {
if(!(str = heap_alloc(len * sizeof(WCHAR))))
return E_OUTOFMEMORY;
if(GetMIMETypeSubKeyW(content_type, str, len))
break;
heap_free(str);
len *= 2;
}
- }
- status = RegOpenKeyExW(HKEY_CLASSES_ROOT, str, 0, KEY_QUERY_VALUE, &key);
- if(str != buffer)
heap_free(str);
- if(status != ERROR_SUCCESS)
goto no_mime_database;
You could just initialize key to NULL and use regular fail code path here.
Jacek Caban (@jacek) commented about dlls/mshtml/tests/script.c:
ok(dst != NULL, "dst = NULL\n"); ok(V_VT(dst) == VT_EMPTY, "V_VT(dst) = %d\n", V_VT(dst)); ok(src != NULL, "src = NULL\n");
- ok(lcid == LOCALE_NEUTRAL, "lcid = %ld\n", lcid);
- if(ChangeType_expect_null_dispatch) {
ok(V_VT(src) == VT_NULL, "V_VT(src) = %d\n", V_VT(src));
ok(vt == VT_DISPATCH, "vt = %d\n", vt);
/* native jscript returns E_NOTIMPL, use a "valid" error to test that it doesn't matter */
return E_OUTOFMEMORY;
- }
I think it would be better to avoid having ChangeType_expect_null_dispatch, you could just structure it like:
``` switch(vt) { case VT_BSTR: CHECK_EXPECT(ChangeType_bstr); .... case VT_DISPATCH: CHECK_EXPECT(ChangeType_dispatch); .... default: ok(0, "unexpected vt %u", vt); } ```