diff --git a/configure b/configure index 40f783349ea..5ed6ed6c26d 100755 --- a/configure +++ b/configure @@ -20773,6 +20773,7 @@ wine_fn_config_makefile dlls/schannel/tests enable_tests wine_fn_config_makefile dlls/schedsvc enable_schedsvc wine_fn_config_makefile dlls/schedsvc/tests enable_tests wine_fn_config_makefile dlls/scrobj enable_scrobj +wine_fn_config_makefile dlls/scrobj/tests enable_tests wine_fn_config_makefile dlls/scrrun enable_scrrun wine_fn_config_makefile dlls/scrrun/tests enable_tests wine_fn_config_makefile dlls/scsiport.sys enable_scsiport_sys diff --git a/configure.ac b/configure.ac index 250b3c2d5c4..1c912a30a29 100644 --- a/configure.ac +++ b/configure.ac @@ -3641,6 +3641,7 @@ WINE_CONFIG_MAKEFILE(dlls/schannel/tests) WINE_CONFIG_MAKEFILE(dlls/schedsvc) WINE_CONFIG_MAKEFILE(dlls/schedsvc/tests) WINE_CONFIG_MAKEFILE(dlls/scrobj) +WINE_CONFIG_MAKEFILE(dlls/scrobj/tests) WINE_CONFIG_MAKEFILE(dlls/scrrun) WINE_CONFIG_MAKEFILE(dlls/scrrun/tests) WINE_CONFIG_MAKEFILE(dlls/scsiport.sys) diff --git a/dlls/scrobj/tests/Makefile.in b/dlls/scrobj/tests/Makefile.in new file mode 100644 index 00000000000..4e517caefe6 --- /dev/null +++ b/dlls/scrobj/tests/Makefile.in @@ -0,0 +1,8 @@ +TESTDLL = scrobj.dll +IMPORTS = oleaut32 ole32 advapi32 uuid + +C_SRCS = \ + scrobj.c + +RC_SRCS = \ + rsrc.rc diff --git a/dlls/scrobj/tests/rsrc.rc b/dlls/scrobj/tests/rsrc.rc new file mode 100644 index 00000000000..7f38c9f21da --- /dev/null +++ b/dlls/scrobj/tests/rsrc.rc @@ -0,0 +1,20 @@ +/* + * Copyright 2019 Jacek Caban 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 + */ + +/* @makedep: scrobj.wsc */ +scrobj.wsc 40 "scrobj.wsc" diff --git a/dlls/scrobj/tests/scrobj.c b/dlls/scrobj/tests/scrobj.c new file mode 100644 index 00000000000..bfd864dbeec --- /dev/null +++ b/dlls/scrobj/tests/scrobj.c @@ -0,0 +1,1012 @@ +/* + * Copyright 2019 Jacek Caban 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 + */ + +#define COBJMACROS +#define CONST_VTABLE + +#include +#include +#include +#include +#include +#include + +#include "wine/test.h" +#include "wine/heap.h" + +static HRESULT (WINAPI *pDllInstall)(BOOL, const WCHAR *); + +static const CLSID CLSID_WineTest = {0xa8a83483,0xa6ac,0x474d,{0xb2,0x2a,0x9a,0x5f,0x2d,0x68,0xcb,0x7f}}; +#define CLSID_STR "{a8a83483-a6ac-474d-b22a-9a5f2d68cb7f}" + +#define TESTSCRIPT_CLSID "{178fc164-f585-4e24-9c13-4bb7faf80746}" +static const GUID CLSID_TestScript = + {0x178fc164,0xf585,0x4e24,{0x9c,0x13,0x4b,0xb7,0xfa,0xf8,0x07,0x46}}; + +#ifdef _WIN64 + +#define CTXARG_T DWORDLONG +#define IActiveScriptParseVtbl IActiveScriptParse64Vtbl +#define IActiveScriptSiteDebug_Release IActiveScriptSiteDebug64_Release + +#else + +#define CTXARG_T DWORD +#define IActiveScriptParseVtbl IActiveScriptParse32Vtbl +#define IActiveScriptSiteDebug_Release IActiveScriptSiteDebug32_Release + +#endif + +#define DEFINE_EXPECT(func) \ + static BOOL expect_ ## func = FALSE, called_ ## func = FALSE + +#define SET_EXPECT(func) \ + do { called_ ## func = FALSE; expect_ ## func = TRUE; } while(0) + +#define CHECK_EXPECT2(func) \ + do { \ + ok(expect_ ##func, "unexpected call " #func "\n"); \ + called_ ## func = TRUE; \ + }while(0) + +#define CHECK_EXPECT(func) \ + do { \ + CHECK_EXPECT2(func); \ + expect_ ## func = FALSE; \ + }while(0) + +#define CHECK_CALLED(func) \ + do { \ + ok(called_ ## func, "expected " #func "\n"); \ + expect_ ## func = called_ ## func = FALSE; \ + }while(0) + +#define CHECK_CALLED_BROKEN(func) \ + do { \ + ok(called_ ## func || broken(!called_ ## func), "expected " #func "\n"); \ + expect_ ## func = called_ ## func = FALSE; \ + }while(0) + +#define CHECK_NOT_CALLED(func) \ + do { \ + ok(!called_ ## func, "unexpected " #func "\n"); \ + expect_ ## func = called_ ## func = FALSE; \ + }while(0) + +#define CLEAR_CALLED(func) \ + expect_ ## func = called_ ## func = FALSE + +DEFINE_EXPECT(CreateInstance); +DEFINE_EXPECT(InitNew); +DEFINE_EXPECT(Close); +DEFINE_EXPECT(SetScriptSite); +DEFINE_EXPECT(QI_IActiveScriptParse); +DEFINE_EXPECT(SetScriptState_INITIALIZED); +DEFINE_EXPECT(SetScriptState_UNINITIALIZED); +DEFINE_EXPECT(SetScriptState_STARTED); +DEFINE_EXPECT(AddNamedItem_scriptlet); +DEFINE_EXPECT(AddNamedItem_globals); +DEFINE_EXPECT(ParseScriptText); +DEFINE_EXPECT(Clone); +DEFINE_EXPECT(GetScriptDispatch); +DEFINE_EXPECT(GetDispID_vbAddOne); +DEFINE_EXPECT(GetDispID_wtTest); +DEFINE_EXPECT(InvokeEx); + +#define DISPID_WTTEST 100 + +static DWORD parse_flags; +static BOOL support_clone; + +static IActiveScriptSite *site; +static SCRIPTSTATE state; + +static HRESULT WINAPI DispatchEx_QueryInterface(IDispatchEx *iface, REFIID riid, void **ppv) +{ + *ppv = NULL; + + if (IsEqualGUID(riid, &IID_IUnknown) + || IsEqualGUID(riid, &IID_IDispatch) + || IsEqualGUID(riid, &IID_IDispatchEx)) + *ppv = iface; + else + return E_NOINTERFACE; + + return S_OK; +} + +static ULONG WINAPI DispatchEx_AddRef(IDispatchEx *iface) +{ + return 2; +} + +static ULONG WINAPI DispatchEx_Release(IDispatchEx *iface) +{ + return 1; +} + +static HRESULT WINAPI DispatchEx_GetTypeInfoCount(IDispatchEx *iface, UINT *pctinfo) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DispatchEx_GetTypeInfo(IDispatchEx *iface, UINT iTInfo, + LCID lcid, ITypeInfo **ppTInfo) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI DispatchEx_GetIDsOfNames(IDispatchEx *iface, REFIID riid, + LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DispatchEx_Invoke(IDispatchEx *iface, DISPID dispIdMember, + REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, + VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DispatchEx_GetDispID(IDispatchEx *iface, BSTR name, DWORD grfdex, DISPID *pid) +{ + if (!wcscmp(name, L"vbAddOne")) + { + CHECK_EXPECT(GetDispID_vbAddOne); + ok(grfdex == fdexNameCaseInsensitive, "grfdex = %x\n", grfdex); + return DISP_E_UNKNOWNNAME; + } + if (!wcscmp(name, L"wtTest")) + { + CHECK_EXPECT(GetDispID_wtTest); + ok(!grfdex, "grfdex = %x\n", grfdex); + *pid = DISPID_WTTEST; + return S_OK; + } + ok(0, "unexpected name %s\n", wine_dbgstr_w(name)); + return DISP_E_UNKNOWNNAME; +} + +static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD flags, DISPPARAMS *pdp, + VARIANT *res, EXCEPINFO *pei, IServiceProvider *caller) +{ + CHECK_EXPECT(InvokeEx); + ok(id == DISPID_WTTEST, "id = %u\n", id); + ok(lcid == 0x100, "lcid = %x\n", lcid); + ok(flags == DISPATCH_METHOD, "flags = %x\n", flags); + ok(caller == (void*)0xdeadbeef, "called = %p\n", caller); + V_VT(res) = VT_BOOL; + V_BOOL(res) = VARIANT_TRUE; + return S_OK; +} + +static HRESULT WINAPI DispatchEx_DeleteMemberByName(IDispatchEx *iface, BSTR name, DWORD grfdex) +{ + ok(0, "unexpected call %s %x\n", wine_dbgstr_w(name), grfdex); + return E_NOTIMPL; +} + +static HRESULT WINAPI DispatchEx_DeleteMemberByDispID(IDispatchEx *iface, DISPID id) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DispatchEx_GetMemberProperties(IDispatchEx *iface, DISPID id, DWORD grfdexFetch, DWORD *pgrfdex) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DispatchEx_GetMemberName(IDispatchEx *iface, DISPID id, BSTR *name) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DispatchEx_GetNextDispID(IDispatchEx *iface, DWORD grfdex, DISPID id, DISPID *pid) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DispatchEx_GetNameSpaceParent(IDispatchEx *iface, IUnknown **ppunk) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static IDispatchExVtbl DispatchExVtbl = { + DispatchEx_QueryInterface, + DispatchEx_AddRef, + DispatchEx_Release, + DispatchEx_GetTypeInfoCount, + DispatchEx_GetTypeInfo, + DispatchEx_GetIDsOfNames, + DispatchEx_Invoke, + DispatchEx_GetDispID, + DispatchEx_InvokeEx, + DispatchEx_DeleteMemberByName, + DispatchEx_DeleteMemberByDispID, + DispatchEx_GetMemberProperties, + DispatchEx_GetMemberName, + DispatchEx_GetNextDispID, + DispatchEx_GetNameSpaceParent +}; + +static IDispatchEx script_global = { &DispatchExVtbl }; + +static HRESULT WINAPI ActiveScriptParse_QueryInterface(IActiveScriptParse *iface, REFIID riid, void **ppv) +{ + *ppv = NULL; + ok(0, "unexpected call\n"); + return E_NOINTERFACE; +} + +static ULONG WINAPI ActiveScriptParse_AddRef(IActiveScriptParse *iface) +{ + return 2; +} + +static ULONG WINAPI ActiveScriptParse_Release(IActiveScriptParse *iface) +{ + return 1; +} + +static HRESULT WINAPI ActiveScriptParse_InitNew(IActiveScriptParse *iface) +{ + CHECK_EXPECT(InitNew); + return S_OK; +} + +static HRESULT WINAPI ActiveScriptParse_AddScriptlet(IActiveScriptParse *iface, + LPCOLESTR pstrDefaultName, LPCOLESTR pstrCode, LPCOLESTR pstrItemName, + LPCOLESTR pstrSubItemName, LPCOLESTR pstrEventName, LPCOLESTR pstrDelimiter, + CTXARG_T dwSourceContextCookie, ULONG ulStartingLineNumber, DWORD dwFlags, + BSTR *pbstrName, EXCEPINFO *pexcepinfo) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI ActiveScriptParse_ParseScriptText(IActiveScriptParse *iface, + LPCOLESTR code, LPCOLESTR item_name, IUnknown *context, + LPCOLESTR delimiter, CTXARG_T dwSourceContextCookie, ULONG ulStartingLine, + DWORD flags, VARIANT *result, EXCEPINFO *excepinfo) +{ + CHECK_EXPECT(ParseScriptText); + ok(!wcscmp(code, L"WTTest body"), "unexpected code %s\n", wine_dbgstr_w(code)); + ok(!item_name, "pstrItemName = %s\n", wine_dbgstr_w(item_name)); + ok(!context, "punkContext = %p\n", context); + ok(!delimiter, "pstrDelimiter = %s\n", wine_dbgstr_w(delimiter)); + ok(flags == parse_flags, "dwFlags = %x\n", flags); + ok(!result, "pvarResult = NULL\n"); + ok(!excepinfo, "pexcepinfo = %p\n", excepinfo); + return S_OK; +} + +static const IActiveScriptParseVtbl ActiveScriptParseVtbl = { + ActiveScriptParse_QueryInterface, + ActiveScriptParse_AddRef, + ActiveScriptParse_Release, + ActiveScriptParse_InitNew, + ActiveScriptParse_AddScriptlet, + ActiveScriptParse_ParseScriptText +}; + +static IActiveScriptParse ActiveScriptParse = { &ActiveScriptParseVtbl }; + +static HRESULT WINAPI ActiveScript_QueryInterface(IActiveScript *iface, REFIID riid, void **ppv) +{ + if (IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IActiveScript, riid)) + { + *ppv = iface; + return S_OK; + } + + if (IsEqualGUID(&IID_IActiveScriptParse, riid)) + { + CHECK_EXPECT(QI_IActiveScriptParse); + *ppv = &ActiveScriptParse; + return S_OK; + } + + ok(0, "unexpected riid %s\n", wine_dbgstr_guid(riid)); + *ppv = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI ActiveScript_AddRef(IActiveScript *iface) +{ + return 2; +} + +static ULONG WINAPI ActiveScript_Release(IActiveScript *iface) +{ + return 1; +} + +static HRESULT WINAPI ActiveScript_SetScriptSite(IActiveScript *iface, IActiveScriptSite *pass) +{ + IActiveScriptSiteInterruptPoll *poll; + IActiveScriptSiteWindow *window; + IActiveScriptSiteDebug *debug; + IServiceProvider *service; + ICanHandleException *canexpection; + LCID lcid; + HRESULT hres; + + CHECK_EXPECT(SetScriptSite); + + ok(pass != NULL, "pass == NULL\n"); + + hres = IActiveScriptSite_QueryInterface(pass, &IID_IActiveScriptSiteInterruptPoll, (void**)&poll); + ok(hres == E_NOINTERFACE, "Got IActiveScriptSiteInterruptPoll interface: %08x\n", hres); + + hres = IActiveScriptSite_GetLCID(pass, &lcid); + ok(hres == S_OK, "GetLCID failed: %08x\n", hres); + + hres = IActiveScriptSite_OnStateChange(pass, (state = SCRIPTSTATE_INITIALIZED)); + ok(hres == E_NOTIMPL, "OnStateChange failed: %08x\n", hres); + + hres = IActiveScriptSite_QueryInterface(pass, &IID_IActiveScriptSiteDebug, (void**)&debug); + todo_wine + ok(hres == S_OK, "IActiveScriptSiteDebug not supported: %08x\n", hres); + if (SUCCEEDED(hres)) + IActiveScriptSiteDebug_Release(debug); + + hres = IActiveScriptSite_QueryInterface(pass, &IID_ICanHandleException, (void**)&canexpection); + ok(hres == E_NOINTERFACE, "Got IID_ICanHandleException interface: %08x\n", hres); + + hres = IActiveScriptSite_QueryInterface(pass, &IID_IServiceProvider, (void**)&service); + ok(hres == S_OK, "Could not get IServiceProvider interface: %08x\n", hres); + if (SUCCEEDED(hres)) + IServiceProvider_Release(service); + + hres = IActiveScriptSite_QueryInterface(pass, &IID_IActiveScriptSiteWindow, (void**)&window); + ok(hres == S_OK, "Could not get IActiveScriptSiteWindow interface: %08x\n", hres); + if (window) + IActiveScriptSiteWindow_Release(window); + + if (site) + IActiveScriptSite_Release(site); + site = pass; + IActiveScriptSite_AddRef(site); + + return S_OK; +} + +static HRESULT WINAPI ActiveScript_GetScriptSite(IActiveScript *iface, REFIID riid, void **ppv) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI ActiveScript_SetScriptState(IActiveScript *iface, SCRIPTSTATE ss) +{ + switch(ss) + { + case SCRIPTSTATE_INITIALIZED: + CHECK_EXPECT(SetScriptState_INITIALIZED); + break; + case SCRIPTSTATE_UNINITIALIZED: + CHECK_EXPECT(SetScriptState_UNINITIALIZED); + break; + case SCRIPTSTATE_STARTED: + CHECK_EXPECT(SetScriptState_STARTED); + break; + default: + ok(0, "unexpected call, state %u\n", ss); + } + + return S_OK; +} + +static HRESULT WINAPI ActiveScript_GetScriptState(IActiveScript *iface, SCRIPTSTATE *pssState) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI ActiveScript_Close(IActiveScript *iface) +{ + CHECK_EXPECT(Close); + if (site) + { + IActiveScriptSite_Release(site); + site = NULL; + } + return S_OK; +} + +static HRESULT WINAPI ActiveScript_AddNamedItem(IActiveScript *iface, LPCOLESTR name, DWORD flags) +{ + if (!wcscmp(name, L"scriptlet")) + { + CHECK_EXPECT(AddNamedItem_scriptlet); + ok(flags == (SCRIPTITEM_ISVISIBLE|SCRIPTITEM_GLOBALMEMBERS), "got flags %#x\n", flags); + } + else if (!wcscmp(name, L"globals")) + { + CHECK_EXPECT(AddNamedItem_globals); + ok(flags == SCRIPTITEM_ISVISIBLE, "got flags %#x\n", flags); + } + else + { + ok(0, "got name %s\n", wine_dbgstr_w(name)); + return E_FAIL; + } + return S_OK; +} + +static HRESULT WINAPI ActiveScript_AddTypeLib(IActiveScript *iface, REFGUID rguidTypeLib, + DWORD dwMajor, DWORD dwMinor, DWORD dwFlags) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI ActiveScript_GetScriptDispatch(IActiveScript *iface, LPCOLESTR item_name, + IDispatch **ppdisp) +{ + CHECK_EXPECT(GetScriptDispatch); + ok(!item_name, "item name %s\n", wine_dbgstr_w(item_name)); + IDispatch_AddRef(*ppdisp = (IDispatch*)&script_global); + return S_OK; +} + +static HRESULT WINAPI ActiveScript_GetCurrentScriptThreadID(IActiveScript *iface, + SCRIPTTHREADID *pstridThread) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI ActiveScript_GetScriptThreadID(IActiveScript *iface, + DWORD dwWin32ThreadId, SCRIPTTHREADID *pstidThread) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI ActiveScript_GetScriptThreadState(IActiveScript *iface, + SCRIPTTHREADID stidThread, SCRIPTTHREADSTATE *pstsState) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI ActiveScript_InterruptScriptThread(IActiveScript *iface, + SCRIPTTHREADID stidThread, const EXCEPINFO *pexcepinfo, DWORD dwFlags) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI ActiveScript_Clone(IActiveScript *iface, IActiveScript **ppscript) +{ + CHECK_EXPECT(Clone); + + if (support_clone) + { + *ppscript = iface; + return S_OK; + } + + if (parse_flags == SCRIPTTEXT_ISVISIBLE) return E_NOTIMPL; + + CHECK_CALLED(CreateInstance); + CHECK_CALLED(QI_IActiveScriptParse); + CHECK_CALLED(InitNew); + CHECK_CALLED(SetScriptSite); + CHECK_CALLED(ParseScriptText); + CHECK_CALLED(SetScriptState_UNINITIALIZED); + + SET_EXPECT(CreateInstance); + SET_EXPECT(QI_IActiveScriptParse); + SET_EXPECT(InitNew); + SET_EXPECT(SetScriptSite); + SET_EXPECT(AddNamedItem_scriptlet); + SET_EXPECT(AddNamedItem_globals); + SET_EXPECT(GetScriptDispatch); + SET_EXPECT(GetDispID_vbAddOne); + SET_EXPECT(GetDispID_wtTest); + SET_EXPECT(SetScriptState_STARTED); + SET_EXPECT(ParseScriptText); + + parse_flags = SCRIPTTEXT_ISVISIBLE; + return E_NOTIMPL; +} + +static const IActiveScriptVtbl ActiveScriptVtbl = { + ActiveScript_QueryInterface, + ActiveScript_AddRef, + ActiveScript_Release, + ActiveScript_SetScriptSite, + ActiveScript_GetScriptSite, + ActiveScript_SetScriptState, + ActiveScript_GetScriptState, + ActiveScript_Close, + ActiveScript_AddNamedItem, + ActiveScript_AddTypeLib, + ActiveScript_GetScriptDispatch, + ActiveScript_GetCurrentScriptThreadID, + ActiveScript_GetScriptThreadID, + ActiveScript_GetScriptThreadState, + ActiveScript_InterruptScriptThread, + ActiveScript_Clone +}; + +static IActiveScript ActiveScript = { &ActiveScriptVtbl }; + +static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID riid, void **ppv) +{ + *ppv = NULL; + + if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IClassFactory, riid)) { + *ppv = iface; + return S_OK; + } + + if(IsEqualGUID(&IID_IMarshal, riid) || IsEqualGUID(&IID_IClassFactoryEx, riid)) + return E_NOINTERFACE; + + ok(0, "unexpected riid %s\n", wine_dbgstr_guid(riid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI ClassFactory_AddRef(IClassFactory *iface) +{ + return 2; +} + +static ULONG WINAPI ClassFactory_Release(IClassFactory *iface) +{ + return 1; +} + +static HRESULT WINAPI ClassFactory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv) +{ + CHECK_EXPECT(CreateInstance); + + ok(!outer, "outer = %p\n", outer); + ok(IsEqualGUID(&IID_IUnknown, riid), "unexpected riid %s\n", wine_dbgstr_guid(riid)); + *ppv = &ActiveScript; + site = NULL; + return S_OK; +} + +static HRESULT WINAPI ClassFactory_LockServer(IClassFactory *iface, BOOL dolock) +{ + ok(0, "unexpected call\n"); + return S_OK; +} + +static const IClassFactoryVtbl ClassFactoryVtbl = { + ClassFactory_QueryInterface, + ClassFactory_AddRef, + ClassFactory_Release, + ClassFactory_CreateInstance, + ClassFactory_LockServer +}; + +static IClassFactory script_cf = { &ClassFactoryVtbl }; + +static BOOL init_key(const char *key_name, const char *def_value, BOOL init) +{ + HKEY hkey; + DWORD res; + + if(!init) { + RegDeleteKeyA(HKEY_CLASSES_ROOT, key_name); + return TRUE; + } + + res = RegCreateKeyA(HKEY_CLASSES_ROOT, key_name, &hkey); + if(res != ERROR_SUCCESS) + return FALSE; + + if(def_value) + res = RegSetValueA(hkey, NULL, REG_SZ, def_value, strlen(def_value)); + + RegCloseKey(hkey); + + return res == ERROR_SUCCESS; +} + +static BOOL register_script_engine(BOOL init) +{ + DWORD regid; + HRESULT hres; + + if (!init_key("WTScript\\CLSID", TESTSCRIPT_CLSID, init)) return FALSE; + if (!init) return TRUE; + + hres = CoRegisterClassObject(&CLSID_TestScript, (IUnknown *)&script_cf, + CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, ®id); + ok(hres == S_OK, "Could not register script engine: %08x\n", hres); + return TRUE; +} + +static WCHAR *get_test_file(const char *res_name) +{ + WCHAR path[MAX_PATH], buffer[MAX_PATH], *ret; + const char *data; + HANDLE handle; + DWORD size; + HRSRC src; + BOOL res; + + src = FindResourceA(NULL, res_name, (const char *)40); + ok(src != NULL, "Could not find resource %s\n", res_name); + size = SizeofResource(NULL, src); + data = LoadResource(NULL, src); + + GetTempPathW(ARRAY_SIZE(path), path); + GetTempFileNameW(path, L"wsc", 0, buffer); + handle = CreateFileW(buffer, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0); + ok(handle != INVALID_HANDLE_VALUE, "failed to create temp file\n"); + + res = WriteFile(handle, data, size, &size, NULL); + ok(res, "WriteFile failed: %u\n", GetLastError()); + + res = CloseHandle(handle); + ok(res, "CloseHandle failed: %u\n", GetLastError()); + + size = (wcslen(buffer) + 1) * sizeof(WCHAR); + ret = heap_alloc(size); + memcpy(ret, buffer, size); + return ret; +} + +#define test_key_value(a,b) test_key_value_(a,b,__LINE__) +static void test_key_value_(const char *key_name, const char *expect, unsigned line) +{ + char buf[512]; + LONG size = sizeof(buf); + LSTATUS status; + status = RegQueryValueA(HKEY_CLASSES_ROOT, key_name, buf, &size); + ok_(__FILE__,line)(!status, "RegQueryValueA failed: %u\n", status); + if (*expect == '*') + ok_(__FILE__,line)(size >= strlen(expect) + 1 && !strcmp(buf + size - strlen(expect), expect + 1), + "Unexpected value \"%s\", expected \"%s\"\n", buf, expect); + else + ok_(__FILE__,line)(size == strlen(expect) + 1 && !memicmp(buf, expect, size), + "Unexpected value \"%s\", expected \"%s\"\n", buf, expect); +} + +static void test_key_deleted(const char *key_name) +{ + HKEY key; + LSTATUS status; + status = RegOpenKeyA(HKEY_CLASSES_ROOT, key_name, &key); + ok(status == ERROR_FILE_NOT_FOUND, "RegOpenKey(\"%s\") returned %u\n", key_name, status); +} + +static void register_script_object(BOOL do_register, const WCHAR *file_name) +{ + HRESULT hres; + + parse_flags = SCRIPTTEXT_ISPERSISTENT | SCRIPTTEXT_ISVISIBLE; + + SET_EXPECT(CreateInstance); + SET_EXPECT(QI_IActiveScriptParse); + SET_EXPECT(InitNew); + SET_EXPECT(SetScriptSite); + SET_EXPECT(ParseScriptText); + SET_EXPECT(SetScriptState_UNINITIALIZED); + SET_EXPECT(Close); + hres = pDllInstall(do_register, file_name); + todo_wine + CHECK_CALLED(CreateInstance); + todo_wine + CHECK_CALLED(QI_IActiveScriptParse); + todo_wine + CHECK_CALLED(InitNew); + todo_wine + CHECK_CALLED(SetScriptSite); + todo_wine + CHECK_CALLED(ParseScriptText); + todo_wine + CHECK_CALLED(SetScriptState_UNINITIALIZED); + todo_wine + CHECK_CALLED(Close); + todo_wine + ok(hres == S_OK, "DllInstall failed: %08x\n", hres); + if (FAILED(hres)) + return; + + if (do_register) + { + test_key_value("CLSID\\" CLSID_STR, "WineTest object"); + test_key_value("CLSID\\" CLSID_STR "\\InprocServer32", "*\\scrobj.dll"); + test_key_value("CLSID\\" CLSID_STR "\\ProgID", "WineTest.1.23"); + test_key_value("CLSID\\" CLSID_STR "\\VersionIndependentProgID", "WineTest"); + test_key_value("WineTest", "WineTest object"); + test_key_value("WineTest\\CLSID", CLSID_STR); + test_key_value("WineTest.1.23", "WineTest object"); + test_key_value("WineTest.1.23\\CLSID", CLSID_STR); + } + else + { + test_key_deleted("CLSID\\" CLSID_STR); + test_key_deleted("WineTest"); + test_key_deleted("WineTest.1.23"); + } +} + +static void test_create_object(void) +{ + DISPID vb_add_one_id, js_add_two_id, wt_test_id, id; + IDispatchEx *dispex; + IClassFactory *cf; + IDispatch *disp; + IUnknown *unk; + DISPPARAMS dp; + EXCEPINFO ei; + VARIANT v, r; + BSTR str; + HRESULT hres; + + hres = CoGetClassObject(&CLSID_WineTest, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER, NULL, + &IID_IClassFactory, (void**)&cf); + todo_wine + ok(hres == S_OK, "Could not get class factory: %08x\n", hres); + if (FAILED(hres)) + return; + + parse_flags = SCRIPTTEXT_ISPERSISTENT | SCRIPTTEXT_ISVISIBLE; + + /* CreateInstance creates two script engine instances. The first one is for validation + * and is created once per class factry. Then, when object instance is created, it tries + * to clone that or create a new instance from scratch. + * We don't implement Clone in tests, but we use it to check already called functions + * and set new expected once. + */ + SET_EXPECT(CreateInstance); + SET_EXPECT(QI_IActiveScriptParse); + SET_EXPECT(InitNew); + SET_EXPECT(SetScriptSite); + SET_EXPECT(ParseScriptText); + SET_EXPECT(SetScriptState_UNINITIALIZED); + SET_EXPECT(Clone); + hres = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (void**)&unk); + ok(hres == S_OK, "Could not create scriptlet instance: %08x\n", hres); + CHECK_CALLED(Clone); + CHECK_CALLED(CreateInstance); + CHECK_CALLED(QI_IActiveScriptParse); + CHECK_CALLED(InitNew); + CHECK_CALLED(SetScriptSite); + CHECK_CALLED(AddNamedItem_scriptlet); + CHECK_CALLED(AddNamedItem_globals); + CHECK_CALLED(GetScriptDispatch); + todo_wine + CHECK_CALLED(GetDispID_vbAddOne); + CHECK_CALLED(GetDispID_wtTest); + CHECK_CALLED(SetScriptState_STARTED); + CHECK_CALLED(ParseScriptText); + + hres = IUnknown_QueryInterface(unk, &IID_IDispatch, (void**)&disp); + ok(hres == S_OK, "Could not get IDispatch iface: %08x\n", hres); + + IDispatch_Release(disp); + + hres = IUnknown_QueryInterface(unk, &IID_IDispatchEx, (void**)&dispex); + ok(hres == S_OK, "Could not get IDispatch iface: %08x\n", hres); + + str = SysAllocString(L"vbAddOne"); + hres = IDispatchEx_GetDispID(dispex, str, fdexNameCaseSensitive, &vb_add_one_id); + ok(hres == S_OK, "Could not get vkAddOne id: %08x\n", hres); + SysFreeString(str); + + str = SysAllocString(L"jsAddTwo"); + hres = IDispatchEx_GetDispID(dispex, str, fdexNameCaseSensitive, &js_add_two_id); + ok(hres == S_OK, "Could not get jsAddTwo id: %08x\n", hres); + SysFreeString(str); + + str = SysAllocString(L"wtTest"); + hres = IDispatchEx_GetDispID(dispex, str, fdexNameCaseSensitive, &wt_test_id); + ok(hres == S_OK, "Could not get wtTest id: %08x\n", hres); + SysFreeString(str); + + str = SysAllocString(L"vbaddone"); + hres = IDispatchEx_GetDispID(dispex, str, fdexNameCaseSensitive, &id); + ok(hres == DISP_E_UNKNOWNNAME, "invalid case returned: %08x\n", hres); + SysFreeString(str); + + str = SysAllocString(L"vbaddone"); + hres = IDispatchEx_GetDispID(dispex, str, 0, &id); + ok(hres == DISP_E_UNKNOWNNAME, "invalid case returned: %08x\n", hres); + SysFreeString(str); + + str = SysAllocString(L"vbaddone"); + hres = IDispatchEx_GetDispID(dispex, str, fdexNameCaseInsensitive, &id); + ok(hres == S_OK, "case insensitive returned: %08x\n", hres); + ok(id == vb_add_one_id, "id = %u, expected %u\n", id, vb_add_one_id); + SysFreeString(str); + + memset(&ei, 0, sizeof(ei)); + memset(&dp, 0, sizeof(dp)); + V_VT(&v) = VT_I4; + V_I4(&v) = 2; + V_VT(&r) = VT_ERROR; + dp.cArgs = 1; + dp.rgvarg = &v; + hres = IDispatchEx_InvokeEx(dispex, vb_add_one_id, 0, DISPATCH_PROPERTYGET|DISPATCH_METHOD, &dp, &r, &ei, NULL); + ok(hres == S_OK, "InvokeEx failed: %08x\n", hres); + ok(V_VT(&r) == VT_I4, "V_VT(r) = %d\n", V_VT(&r)); + ok(V_I4(&r) == 3, "V_I4(r) = %d\n", V_I4(&r)); + + memset(&ei, 0, sizeof(ei)); + memset(&dp, 0, sizeof(dp)); + V_VT(&v) = VT_I4; + V_I4(&v) = 4; + V_VT(&r) = VT_ERROR; + dp.cArgs = 1; + dp.rgvarg = &v; + hres = IDispatchEx_InvokeEx(dispex, js_add_two_id, 0, DISPATCH_PROPERTYGET|DISPATCH_METHOD, &dp, &r, &ei, NULL); + ok(hres == S_OK, "InvokeEx failed: %08x\n", hres); + ok(V_VT(&r) == VT_I4, "V_VT(r) = %d\n", V_VT(&r)); + ok(V_I4(&r) == 6, "V_I4(r) = %d\n", V_I4(&r)); + + memset(&ei, 0, sizeof(ei)); + memset(&dp, 0, sizeof(dp)); + V_VT(&v) = VT_I4; + V_I4(&v) = 4; + V_VT(&r) = VT_ERROR; + dp.cArgs = 1; + dp.rgvarg = &v; + SET_EXPECT(InvokeEx); + hres = IDispatchEx_InvokeEx(dispex, wt_test_id, 0x100, DISPATCH_PROPERTYGET|DISPATCH_METHOD, &dp, &r, &ei, (void*)0xdeadbeef); + ok(hres == S_OK, "InvokeEx failed: %08x\n", hres); + CHECK_CALLED(InvokeEx); + ok(V_VT(&r) == VT_BOOL, "V_VT(r) = %d\n", V_VT(&r)); + ok(V_BOOL(&r) == VARIANT_TRUE, "V_I4(r) = %d\n", V_I4(&r)); + + memset(&ei, 0, sizeof(ei)); + memset(&dp, 0, sizeof(dp)); + V_VT(&r) = VT_ERROR; + SET_EXPECT(InvokeEx); + hres = IDispatchEx_InvokeEx(dispex, wt_test_id, 0x100, DISPATCH_METHOD, &dp, &r, &ei, (void*)0xdeadbeef); + ok(hres == S_OK, "InvokeEx failed: %08x\n", hres); + CHECK_CALLED(InvokeEx); + ok(V_VT(&r) == VT_BOOL, "V_VT(r) = %d\n", V_VT(&r)); + ok(V_BOOL(&r) == VARIANT_TRUE, "V_I4(r) = %d\n", V_I4(&r)); + + hres = IDispatchEx_InvokeEx(dispex, wt_test_id, 0x100, DISPATCH_PROPERTYGET, &dp, &r, &ei, (void*)0xdeadbeef); + ok(hres == DISP_E_MEMBERNOTFOUND, "InvokeEx returned: %08x\n", hres); + + hres = IDispatchEx_InvokeEx(dispex, 0xdeadbeef, 0, DISPATCH_METHOD, &dp, &r, &ei, (void*)0xdeadbeef); + ok(hres == DISP_E_MEMBERNOTFOUND, "InvokeEx returned: %08x\n", hres); + + hres = IDispatchEx_InvokeEx(dispex, DISPID_VALUE, 0, DISPATCH_METHOD, &dp, &r, &ei, (void*)0xdeadbeef); + ok(hres == DISP_E_MEMBERNOTFOUND, "InvokeEx returned: %08x\n", hres); + + IDispatchEx_Release(dispex); + + SET_EXPECT(SetScriptState_UNINITIALIZED); + SET_EXPECT(Close); + IUnknown_Release(unk); + CHECK_CALLED(SetScriptState_UNINITIALIZED); + CHECK_CALLED(Close); + + parse_flags = SCRIPTTEXT_ISVISIBLE; + + SET_EXPECT(Clone); + SET_EXPECT(CreateInstance); + SET_EXPECT(QI_IActiveScriptParse); + SET_EXPECT(InitNew); + SET_EXPECT(SetScriptSite); + SET_EXPECT(AddNamedItem_scriptlet); + SET_EXPECT(AddNamedItem_globals); + SET_EXPECT(GetScriptDispatch); + SET_EXPECT(GetDispID_vbAddOne); + SET_EXPECT(GetDispID_wtTest); + SET_EXPECT(SetScriptState_STARTED); + SET_EXPECT(ParseScriptText); + hres = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (void**)&unk); + ok(hres == S_OK, "Could not create scriptlet instance: %08x\n", hres); + CHECK_CALLED(Clone); + CHECK_CALLED(CreateInstance); + CHECK_CALLED(QI_IActiveScriptParse); + CHECK_CALLED(InitNew); + CHECK_CALLED(SetScriptSite); + CHECK_CALLED(AddNamedItem_scriptlet); + CHECK_CALLED(AddNamedItem_globals); + CHECK_CALLED(GetScriptDispatch); + todo_wine + CHECK_CALLED(GetDispID_vbAddOne); + CHECK_CALLED(GetDispID_wtTest); + CHECK_CALLED(SetScriptState_STARTED); + CHECK_CALLED(ParseScriptText); + + SET_EXPECT(SetScriptState_UNINITIALIZED); + SET_EXPECT(Close); + IUnknown_Release(unk); + CHECK_CALLED(SetScriptState_UNINITIALIZED); + CHECK_CALLED(Close); + + support_clone = TRUE; + SET_EXPECT(Clone); + SET_EXPECT(QI_IActiveScriptParse); + SET_EXPECT(SetScriptSite); + SET_EXPECT(AddNamedItem_scriptlet); + SET_EXPECT(AddNamedItem_globals); + SET_EXPECT(GetScriptDispatch); + SET_EXPECT(GetDispID_vbAddOne); + SET_EXPECT(GetDispID_wtTest); + SET_EXPECT(SetScriptState_STARTED); + hres = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (void**)&unk); + ok(hres == S_OK, "Could not create scriptlet instance: %08x\n", hres); + CHECK_CALLED(Clone); + CHECK_CALLED(QI_IActiveScriptParse); + CHECK_CALLED(SetScriptSite); + CHECK_CALLED(AddNamedItem_scriptlet); + CHECK_CALLED(AddNamedItem_globals); + CHECK_CALLED(GetScriptDispatch); + todo_wine + CHECK_CALLED(GetDispID_vbAddOne); + CHECK_CALLED(GetDispID_wtTest); + CHECK_CALLED(SetScriptState_STARTED); + + SET_EXPECT(SetScriptState_UNINITIALIZED); + SET_EXPECT(Close); + IUnknown_Release(unk); + CHECK_CALLED(SetScriptState_UNINITIALIZED); + CHECK_CALLED(Close); + + SET_EXPECT(Close); + IClassFactory_Release(cf); + CHECK_CALLED(Close); +} + +START_TEST(scrobj) +{ + HMODULE scrobj_module; + WCHAR *test_file; + HRESULT hres; + + hres = CoInitialize(NULL); + ok(hres == S_OK, "CoInitialize failed: %08x\n", hres); + + scrobj_module = LoadLibraryA("scrobj.dll"); + ok(scrobj_module != NULL, "Could not load scrobj.dll\n"); + + pDllInstall = (void *)GetProcAddress(scrobj_module, "DllInstall"); + ok(pDllInstall != NULL, "DllInstall not found in scrobj.dll\n"); + + if (register_script_engine(TRUE)) + { + test_file = get_test_file("scrobj.wsc"); + + register_script_object(TRUE, test_file); + test_create_object(); + register_script_object(FALSE, test_file); + + register_script_engine(FALSE); + heap_free(test_file); + } + else + skip("Could not register script engine\n"); + + CoUninitialize(); +} diff --git a/dlls/scrobj/tests/scrobj.wsc b/dlls/scrobj/tests/scrobj.wsc new file mode 100644 index 00000000000..41c7626cee9 --- /dev/null +++ b/dlls/scrobj/tests/scrobj.wsc @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + +