Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/mshtml/Makefile.in | 1 + dlls/mshtml/console.c | 294 ++++++++++++++++++++++++++ dlls/mshtml/dispex.c | 21 +- dlls/mshtml/htmlwindow.c | 36 +++- dlls/mshtml/mshtml_private.h | 11 + dlls/mshtml/tests/es5.js | 64 ++++++ include/wine/mshtml_private_iface.idl | 89 ++++++++ 7 files changed, 508 insertions(+), 8 deletions(-) create mode 100644 dlls/mshtml/console.c
diff --git a/dlls/mshtml/Makefile.in b/dlls/mshtml/Makefile.in index 469667081e3..e0b539c92d4 100644 --- a/dlls/mshtml/Makefile.in +++ b/dlls/mshtml/Makefile.in @@ -7,6 +7,7 @@ EXTRADLLFLAGS = -mno-cygwin
C_SRCS = \ conpoint.c \ + console.c \ dispex.c \ editor.c \ htmlanchor.c \ diff --git a/dlls/mshtml/console.c b/dlls/mshtml/console.c new file mode 100644 index 00000000000..58df32896cc --- /dev/null +++ b/dlls/mshtml/console.c @@ -0,0 +1,294 @@ +/* + * Copyright 2021 Paul Gofman for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <stdarg.h> + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "ole2.h" +#include "mshtmdid.h" +#include "shlguid.h" +#include "shobjidl.h" +#include "exdispid.h" + +#include "wine/debug.h" + +#include "mshtml_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(mshtml); + +struct console { + DispatchEx dispex; + IWineMSHTMLConsole IWineMSHTMLConsole_iface; + LONG ref; +}; + +static inline struct console *impl_from_IWineMSHTMLConsole(IWineMSHTMLConsole *iface) +{ + return CONTAINING_RECORD(iface, struct console, IWineMSHTMLConsole_iface); +} + +static HRESULT WINAPI console_QueryInterface(IWineMSHTMLConsole *iface, REFIID riid, void **ppv) +{ + struct console *console = impl_from_IWineMSHTMLConsole(iface); + + TRACE("(%p)->(%s %p)\n", console, debugstr_mshtml_guid(riid), ppv); + + if(IsEqualGUID(&IID_IUnknown, riid)) { + *ppv = &console->IWineMSHTMLConsole_iface; + }else if(IsEqualGUID(&IID_IWineMSHTMLConsole, riid)) { + *ppv = &console->IWineMSHTMLConsole_iface; + }else if(dispex_query_interface(&console->dispex, riid, ppv)) { + return *ppv ? S_OK : E_NOINTERFACE; + }else { + WARN("(%p)->(%s %p)\n", console, debugstr_mshtml_guid(riid), ppv); + *ppv = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown*)*ppv); + return S_OK; +} + +static ULONG WINAPI console_AddRef(IWineMSHTMLConsole *iface) +{ + struct console *console = impl_from_IWineMSHTMLConsole(iface); + LONG ref = InterlockedIncrement(&console->ref); + + TRACE("(%p) ref=%d\n", console, ref); + + return ref; +} + +static ULONG WINAPI console_Release(IWineMSHTMLConsole *iface) +{ + struct console *console = impl_from_IWineMSHTMLConsole(iface); + LONG ref = InterlockedDecrement(&console->ref); + + TRACE("(%p) ref=%d\n", console, ref); + + if(!ref) { + release_dispex(&console->dispex); + heap_free(console); + } + + return ref; +} + +static HRESULT WINAPI console_GetTypeInfoCount(IWineMSHTMLConsole *iface, UINT *pctinfo) +{ + struct console *console = impl_from_IWineMSHTMLConsole(iface); + FIXME("(%p)->(%p)\n", console, pctinfo); + return E_NOTIMPL; +} + +static HRESULT WINAPI console_GetTypeInfo(IWineMSHTMLConsole *iface, UINT iTInfo, + LCID lcid, ITypeInfo **ppTInfo) +{ + struct console *console = impl_from_IWineMSHTMLConsole(iface); + + return IDispatchEx_GetTypeInfo(&console->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo); +} + +static HRESULT WINAPI console_GetIDsOfNames(IWineMSHTMLConsole *iface, REFIID riid, + LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId) +{ + struct console *console = impl_from_IWineMSHTMLConsole(iface); + + return IDispatchEx_GetIDsOfNames(&console->dispex.IDispatchEx_iface, riid, rgszNames, cNames, + lcid, rgDispId); +} + +static HRESULT WINAPI console_Invoke(IWineMSHTMLConsole *iface, DISPID dispIdMember, + REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, + VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + struct console *console = impl_from_IWineMSHTMLConsole(iface); + + return IDispatchEx_Invoke(&console->dispex.IDispatchEx_iface, dispIdMember, riid, lcid, wFlags, + pDispParams, pVarResult, pExcepInfo, puArgErr); +} + +static HRESULT WINAPI console_assert(IWineMSHTMLConsole *iface, VARIANT_BOOL *assertion, VARIANT *vararg_start) +{ + FIXME("iface %p, assertion %p, vararg_start %p stub.\n", iface, assertion, vararg_start); + + return S_OK; +} + +static HRESULT WINAPI console_clear(IWineMSHTMLConsole *iface) +{ + FIXME("iface %p stub.\n", iface); + + return S_OK; +} + +static HRESULT WINAPI console_count(IWineMSHTMLConsole *iface, VARIANT *label) +{ + FIXME("iface %p, label %p stub.\n", iface, label); + + return S_OK; +} + +static HRESULT WINAPI console_debug(IWineMSHTMLConsole *iface, VARIANT *vararg_start) +{ + FIXME("iface %p, vararg_start %p stub.\n", iface, vararg_start); + + return S_OK; +} + +static HRESULT WINAPI console_dir(IWineMSHTMLConsole *iface, VARIANT *object) +{ + FIXME("iface %p, object %p stub.\n", iface, object); + + return S_OK; +} + +static HRESULT WINAPI console_dirxml(IWineMSHTMLConsole *iface, VARIANT *object) +{ + FIXME("iface %p, object %p stub.\n", iface, object); + + return S_OK; +} + +static HRESULT WINAPI console_error(IWineMSHTMLConsole *iface, VARIANT *vararg_start) +{ + FIXME("iface %p, vararg_start %p stub.\n", iface, vararg_start); + + return S_OK; +} + +static HRESULT WINAPI console_group(IWineMSHTMLConsole *iface, VARIANT *label) +{ + FIXME("iface %p, label %p stub.\n", iface, label); + + return S_OK; +} + +static HRESULT WINAPI console_group_collapsed(IWineMSHTMLConsole *iface, VARIANT *label) +{ + FIXME("iface %p, label %p stub.\n", iface, label); + + return S_OK; +} + +static HRESULT WINAPI console_group_end(IWineMSHTMLConsole *iface) +{ + FIXME("iface %p, stub.\n", iface); + + return S_OK; +} + +static HRESULT WINAPI console_info(IWineMSHTMLConsole *iface, VARIANT *vararg_start) +{ + FIXME("iface %p, vararg_start %p stub.\n", iface, vararg_start); + + return S_OK; +} + +static HRESULT WINAPI console_log(IWineMSHTMLConsole *iface, VARIANT *vararg_start) +{ + FIXME("iface %p, vararg_start %p stub.\n", iface, vararg_start); + + return S_OK; +} + +static HRESULT WINAPI console_time(IWineMSHTMLConsole *iface, VARIANT *label) +{ + FIXME("iface %p, label %p stub.\n", iface, label); + + return S_OK; +} + +static HRESULT WINAPI console_time_end(IWineMSHTMLConsole *iface, VARIANT *label) +{ + FIXME("iface %p, label %p stub.\n", iface, label); + + return S_OK; +} + +static HRESULT WINAPI console_trace(IWineMSHTMLConsole *iface, VARIANT *vararg_start) +{ + FIXME("iface %p, vararg_start %p stub.\n", iface, vararg_start); + + return S_OK; +} + +static HRESULT WINAPI console_warn(IWineMSHTMLConsole *iface, VARIANT *vararg_start) +{ + FIXME("iface %p, vararg_start %p stub.\n", iface, vararg_start); + + return S_OK; +} + +static const IWineMSHTMLConsoleVtbl WineMSHTMLConsoleVtbl = { + console_QueryInterface, + console_AddRef, + console_Release, + console_GetTypeInfoCount, + console_GetTypeInfo, + console_GetIDsOfNames, + console_Invoke, + console_assert, + console_clear, + console_count, + console_debug, + console_dir, + console_dirxml, + console_error, + console_group, + console_group_collapsed, + console_group_end, + console_info, + console_log, + console_time, + console_time_end, + console_trace, + console_warn, +}; + +static const tid_t console_iface_tids[] = { + IWineMSHTMLConsole_tid, + 0 +}; +static dispex_static_data_t console_dispex = { + NULL, + IWineMSHTMLConsole_tid, + console_iface_tids +}; + +void create_console(IWineMSHTMLConsole **ret) +{ + struct console *obj; + + obj = heap_alloc_zero(sizeof(*obj)); + if(!obj) + { + ERR("No memory.\n"); + return; + } + + obj->IWineMSHTMLConsole_iface.lpVtbl = &WineMSHTMLConsoleVtbl; + obj->ref = 1; + init_dispatch(&obj->dispex, (IUnknown*)&obj->IWineMSHTMLConsole_iface, &console_dispex, COMPAT_MODE_NONE); + + *ret = &obj->IWineMSHTMLConsole_iface; +} diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index 6d248691d6b..9c517fec2c2 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -111,7 +111,7 @@ struct dispex_dynamic_data_t {
#define FDEX_VERSION_MASK 0xf0000000
-static ITypeLib *typelib; +static ITypeLib *typelib, *typelib_private; static ITypeInfo *typeinfos[LAST_tid]; static struct list dispex_data_list = LIST_INIT(dispex_data_list);
@@ -119,6 +119,8 @@ static REFIID tid_ids[] = { #define XIID(iface) &IID_ ## iface, #define XDIID(iface) &DIID_ ## iface, TID_LIST + NULL, +PRIVATE_TID_LIST #undef XIID #undef XDIID }; @@ -136,7 +138,17 @@ static HRESULT load_typelib(void)
if(InterlockedCompareExchangePointer((void**)&typelib, tl, NULL)) ITypeLib_Release(tl); - return hres; + + hres = LoadRegTypeLib(&LIBID_MSHTML_private, 1, 0, LOCALE_SYSTEM_DEFAULT, &tl); + if(FAILED(hres)) { + ERR("LoadRegTypeLib failed for private typelib: %08x\n", hres); + return hres; + } + + if(InterlockedCompareExchangePointer((void**)&typelib_private, tl, NULL)) + ITypeLib_Release(tl); + + return S_OK; }
static HRESULT get_typeinfo(tid_t tid, ITypeInfo **typeinfo) @@ -151,7 +163,7 @@ static HRESULT get_typeinfo(tid_t tid, ITypeInfo **typeinfo) if(!typeinfos[tid]) { ITypeInfo *ti;
- hres = ITypeLib_GetTypeInfoOfGuid(typelib, tid_ids[tid], &ti); + hres = ITypeLib_GetTypeInfoOfGuid(tid > LAST_public_tid ? typelib_private : typelib, tid_ids[tid], &ti); if(FAILED(hres)) { ERR("GetTypeInfoOfGuid(%s) failed: %08x\n", debugstr_mshtml_guid(tid_ids[tid]), hres); return hres; @@ -197,6 +209,7 @@ void release_typelib(void) ITypeInfo_Release(typeinfos[i]);
ITypeLib_Release(typelib); + ITypeLib_Release(typelib_private); DeleteCriticalSection(&cs_dispex_static_data); }
@@ -210,6 +223,8 @@ HRESULT get_class_typeinfo(const CLSID *clsid, ITypeInfo **typeinfo) return hres;
hres = ITypeLib_GetTypeInfoOfGuid(typelib, clsid, typeinfo); + if (FAILED(hres)) + hres = ITypeLib_GetTypeInfoOfGuid(typelib_private, clsid, typeinfo); if(FAILED(hres)) ERR("GetTypeInfoOfGuid failed: %08x\n", hres); return hres; diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index 4196d1f45ad..3cec8d3a3c5 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -314,6 +314,9 @@ static ULONG WINAPI HTMLWindow2_Release(IHTMLWindow2 *iface) TRACE("(%p) ref=%d\n", This, ref);
if(!ref) { + if (This->console) + IWineMSHTMLConsole_Release(This->console); + if(is_outer_window(This)) release_outer_window(This->outer_window); else @@ -3178,6 +3181,8 @@ HRESULT search_window_props(HTMLInnerWindow *This, BSTR bstrName, DWORD grfdex,
/* DISPIDs not exposed by interfaces */ #define DISPID_IHTMLWINDOW_IE10_REQUESTANIMATIONFRAME 1300 +#define DISPID_IHTMLWINDOW_IE10_CONSOLE 1301 +
static HRESULT WINAPI WindowDispEx_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid) { @@ -3195,11 +3200,18 @@ static HRESULT WINAPI WindowDispEx_GetDispID(IDispatchEx *iface, BSTR bstrName, if(hres != DISP_E_UNKNOWNNAME) return hres;
- if(dispex_compat_mode(&window->event_target.dispex) >= COMPAT_MODE_IE10 && - !wcscmp(bstrName, L"requestAnimationFrame")) { - TRACE("requestAnimationFrame\n"); - *pid = DISPID_IHTMLWINDOW_IE10_REQUESTANIMATIONFRAME; - return S_OK; + if(dispex_compat_mode(&window->event_target.dispex) >= COMPAT_MODE_IE10) + { + if (!wcscmp(bstrName, L"requestAnimationFrame")) { + TRACE("requestAnimationFrame\n"); + *pid = DISPID_IHTMLWINDOW_IE10_REQUESTANIMATIONFRAME; + return S_OK; + } + if (!wcscmp(bstrName, L"console")) { + TRACE("console\n"); + *pid = DISPID_IHTMLWINDOW_IE10_CONSOLE; + return S_OK; + } }
if(This->outer_window) { @@ -3307,6 +3319,18 @@ static HRESULT WINAPI WindowDispEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID
return hres; } + case DISPID_IHTMLWINDOW_IE10_CONSOLE: { + if(!(wFlags & DISPATCH_PROPERTYGET)) { + FIXME("unsupported wFlags %#x\n", wFlags); + return E_INVALIDARG; + } + + V_VT(pvarRes) = VT_DISPATCH; + V_DISPATCH(pvarRes) = (IDispatch *)window->base.console; + IWineMSHTMLConsole_AddRef(window->base.console); + return S_OK; + } + }
return IDispatchEx_InvokeEx(&window->event_target.dispex.IDispatchEx_iface, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller); @@ -3629,6 +3653,8 @@ static void *alloc_window(size_t size) window->IProvideMultipleClassInfo_iface.lpVtbl = &ProvideMultipleClassInfoVtbl; window->ref = 1;
+ create_console(&window->console); + return window; }
diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index e3486aa3314..13b49696fb4 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -40,6 +40,8 @@
#include "nsiface.h"
+#include "wine/mshtml_private_iface.h" + #include <assert.h>
#define NS_ERROR_GENERATE_FAILURE(module,code) \ @@ -270,10 +272,16 @@ typedef struct EventTarget EventTarget; XIID(ISVGTSpanElement) \ XIID(ISVGTextContentElement)
+#define PRIVATE_TID_LIST \ + XDIID(DispWineMSHTMLConsole) \ + XIID(IWineMSHTMLConsole) + typedef enum { #define XIID(iface) iface ## _tid, #define XDIID(iface) iface ## _tid, TID_LIST + LAST_public_tid, +PRIVATE_TID_LIST #undef XIID #undef XDIID LAST_tid @@ -484,6 +492,8 @@ struct HTMLWindow { IObjectIdentity IObjectIdentity_iface; IProvideMultipleClassInfo IProvideMultipleClassInfo_iface;
+ IWineMSHTMLConsole *console; + LONG ref;
HTMLInnerWindow *inner_window; @@ -1399,3 +1409,4 @@ void set_statustext(HTMLDocumentObj*,INT,LPCWSTR) DECLSPEC_HIDDEN; IInternetSecurityManager *get_security_manager(void) DECLSPEC_HIDDEN;
extern HINSTANCE hInst DECLSPEC_HIDDEN; +void create_console(IWineMSHTMLConsole **ret) DECLSPEC_HIDDEN; diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index a520253569c..e57aed5ca35 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -1448,3 +1448,67 @@ sync_test("functions scope", function() { ok(val == 8, "val != 8"); ok(w == 9, "w != 9"); }); + +sync_test("console", function() { + var except + + window.console.log('1', '2'); + console.info('1', '2', '3'); + console.info(); + console.log(); + console.trace(); + console.warn(); + console.debug(); + console.error(); + + console.assert(false, '1'); + console.assert(true, '1'); + console.assert('1'); + + console.clear(); + console.count('1'); + console.count(1); + + + except = false; + try + { + console.countReset('1'); + } + catch(e) + { + except = true; + } + ok(except, "console.countReset: expected exception"); + console.dir(document); + console.dir(); + console.dirxml(document); + console.group('1'); + console.groupCollapsed('1'); + console.groupEnd(); + + except = false; + try + { + console.table(['1', '2']); + } + catch(e) + { + except = true; + } + ok(except, "console.table: expected exception"); + + console.time('1'); + console.timeEnd('1'); + + except = false; + try + { + console.timeLog('1'); + } + catch(e) + { + except = true; + } + ok(except, "console.timeLog: expected exception"); +}); diff --git a/include/wine/mshtml_private_iface.idl b/include/wine/mshtml_private_iface.idl index 52899f0f1a4..09a0401cdb8 100644 --- a/include/wine/mshtml_private_iface.idl +++ b/include/wine/mshtml_private_iface.idl @@ -27,4 +27,93 @@ import "dispex.idl"; ] library MSHTML_private { + +importlib("stdole2.tlb"); + +[ + odl, + oleautomation, + dual, + uuid(fd55b4b6-2813-4fb4-829d-380099474ab1) +] +interface IWineMSHTMLConsole : IDispatch +{ + [id(1)] + HRESULT assert([in] VARIANT_BOOL *assertion, + [in, optional] VARIANT *varargStart); + [id(2)] + HRESULT clear(); + [id(3)] + HRESULT count([in, optional] VARIANT *label); + [id(4)] + HRESULT debug([in, optional] VARIANT *varargStart); + [id(5)] + HRESULT dir([in, optional] VARIANT *object); + [id(6)] + HRESULT dirxml([in, optional] VARIANT *object); + [id(7)] + HRESULT error([in, optional] VARIANT *varargStart); + [id(8)] + HRESULT group([in, optional] VARIANT *label); + [id(9)] + HRESULT groupCollapsed([in, optional] VARIANT *label); + [id(10)] + HRESULT groupEnd(); + [id(11)] + HRESULT info([in, optional] VARIANT *varargStart); + [id(12)] + HRESULT log([in, optional] VARIANT *varargStart); + [id(13)] + HRESULT time([in, optional] VARIANT *label); + [id(14)] + HRESULT timeEnd([in, optional] VARIANT *label); + [id(15)] + HRESULT trace([in, optional] VARIANT *varargStart); + [id(16)] + HRESULT warn([in, optional] VARIANT *varargStart); +} + +[ + hidden, + uuid(fd55b4b6-2813-4fb4-829d-380099474ab1) +] +dispinterface DispWineMSHTMLConsole +{ +properties: +methods: + [id(1)] + void assert([in] VARIANT_BOOL *assertion, + [in, optional] VARIANT *varargStart); + [id(2)] + void clear(); + [id(3)] + void count([in, optional] VARIANT *label); + [id(4)] + void debug([in, optional] VARIANT *varargStart); + [id(5)] + void dir([in, optional] VARIANT *object); + [id(6)] + void dirxml([in, optional] VARIANT *object); + [id(7)] + void error([in, optional] VARIANT *varargStart); + [id(8)] + void group([in, optional] VARIANT *label); + [id(9)] + void groupCollapsed([in, optional] VARIANT *label); + [id(10)] + void groupEnd(); + [id(11)] + void info([in, optional] VARIANT *varargStart); + [id(12)] + void log([in, optional] VARIANT *varargStart); + [id(13)] + void time([in, optional] VARIANT *label); + [id(14)] + void timeEnd([in, optional] VARIANT *label); + [id(15)] + void trace([in, optional] VARIANT *varargStart); + [id(16)] + void warn([in, optional] VARIANT *varargStart); +} + } /* library MSHTML_private */