Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com ---
These helpers will be needed by more methods and other helpers (such as the next patch) so it's better to place them at the top and avoid pointless forward declarations.
dlls/msscript.ocx/msscript.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/dlls/msscript.ocx/msscript.c b/dlls/msscript.ocx/msscript.c index 816a99d..9cb8282 100644 --- a/dlls/msscript.ocx/msscript.c +++ b/dlls/msscript.ocx/msscript.c @@ -200,6 +200,16 @@ static struct named_item *host_get_named_item(ScriptHost *host, const WCHAR *nam return NULL; }
+static HRESULT set_script_state(ScriptHost *host, SCRIPTSTATE state) +{ + HRESULT hr; + + hr = IActiveScript_SetScriptState(host->script, state); + if (SUCCEEDED(hr)) + host->script_state = state; + return hr; +} + static inline ScriptControl *impl_from_IScriptControl(IScriptControl *iface) { return CONTAINING_RECORD(iface, ScriptControl, IScriptControl_iface); @@ -954,16 +964,6 @@ static HRESULT WINAPI ScriptControl_AddObject(IScriptControl *iface, BSTR name, return hr; }
-static HRESULT set_script_state(ScriptHost *host, SCRIPTSTATE state) -{ - HRESULT hr; - - hr = IActiveScript_SetScriptState(host->script, state); - if (SUCCEEDED(hr)) - host->script_state = state; - return hr; -} - static HRESULT WINAPI ScriptControl_Reset(IScriptControl *iface) { ScriptControl *This = impl_from_IScriptControl(iface);
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com ---
v2: Don't use VariantCopy on the parameters. This simplifies the code, and is actually what Windows does (test added in next patch verifies this).
dlls/msscript.ocx/msscript.c | 100 +++++++++++++++++++++++++++++++---- 1 file changed, 89 insertions(+), 11 deletions(-)
diff --git a/dlls/msscript.ocx/msscript.c b/dlls/msscript.ocx/msscript.c index 9cb8282..c4c6485 100644 --- a/dlls/msscript.ocx/msscript.c +++ b/dlls/msscript.ocx/msscript.c @@ -20,12 +20,14 @@
#include "windows.h" #include "initguid.h" +#include "dispex.h" #include "ole2.h" #include "olectl.h" #include "objsafe.h" #include "activscp.h" #include "rpcproxy.h" #include "msscript.h" +DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
#include "wine/debug.h" #include "wine/heap.h" @@ -71,6 +73,7 @@ typedef struct ScriptHost {
IActiveScript *script; IActiveScriptParse *parse; + IDispatch *script_dispatch; SCRIPTSTATE script_state; CLSID clsid;
@@ -200,6 +203,17 @@ static struct named_item *host_get_named_item(ScriptHost *host, const WCHAR *nam return NULL; }
+static HRESULT get_script_dispatch(struct ScriptControl *control, IDispatch **disp) +{ + if (!control->host->script_dispatch) + { + HRESULT hr = IActiveScript_GetScriptDispatch(control->host->script, NULL, &control->host->script_dispatch); + if (FAILED(hr)) return hr; + } + *disp = control->host->script_dispatch; + return S_OK; +} + static HRESULT set_script_state(ScriptHost *host, SCRIPTSTATE state) { HRESULT hr; @@ -210,6 +224,19 @@ static HRESULT set_script_state(ScriptHost *host, SCRIPTSTATE state) return hr; }
+static HRESULT start_script(struct ScriptControl *control) +{ + HRESULT hr = S_OK; + + if (!control->host || control->state != Initialized) + return E_FAIL; + + if (control->host->script_state != SCRIPTSTATE_STARTED) + hr = set_script_state(control->host, SCRIPTSTATE_STARTED); + + return hr; +} + static inline ScriptControl *impl_from_IScriptControl(IScriptControl *iface) { return CONTAINING_RECORD(iface, ScriptControl, IScriptControl_iface); @@ -316,7 +343,10 @@ static void release_script_engine(ScriptHost *host)
if (host->parse) IActiveScriptParse_Release(host->parse); + if (host->script_dispatch) + IDispatch_Release(host->script_dispatch);
+ host->script_dispatch = NULL; host->parse = NULL; host->script = NULL;
@@ -539,6 +569,7 @@ static HRESULT init_script_host(const CLSID *clsid, ScriptHost **ret) host->ref = 1; host->script = NULL; host->parse = NULL; + host->script_dispatch = NULL; host->clsid = *clsid; list_init(&host->named_items);
@@ -982,15 +1013,8 @@ static HRESULT parse_script_text(ScriptControl *control, BSTR script_text, DWORD EXCEPINFO excepinfo; HRESULT hr;
- if (!control->host || control->state != Initialized) - return E_FAIL; - - if (control->host->script_state != SCRIPTSTATE_STARTED) - { - hr = set_script_state(control->host, SCRIPTSTATE_STARTED); - if (FAILED(hr)) - return hr; - } + hr = start_script(control); + if (FAILED(hr)) return hr;
hr = IActiveScriptParse_ParseScriptText(control->host->parse, script_text, NULL, NULL, NULL, 0, 1, flag, res, &excepinfo); @@ -1032,8 +1056,62 @@ static HRESULT WINAPI ScriptControl_ExecuteStatement(IScriptControl *iface, BSTR static HRESULT WINAPI ScriptControl_Run(IScriptControl *iface, BSTR procedure_name, SAFEARRAY **parameters, VARIANT *res) { ScriptControl *This = impl_from_IScriptControl(iface); - FIXME("(%p)->(%s %p %p)\n", This, debugstr_w(procedure_name), parameters, res); - return E_NOTIMPL; + IDispatchEx *dispex; + IDispatch *disp; + SAFEARRAY *sa; + DISPPARAMS dp; + DISPID dispid; + HRESULT hr; + UINT i; + + TRACE("(%p)->(%s %p %p)\n", This, debugstr_w(procedure_name), parameters, res); + + if (!parameters || !res) return E_POINTER; + if (!(sa = *parameters)) return E_POINTER; + + V_VT(res) = VT_EMPTY; + if (sa->cDims == 0) return DISP_E_BADINDEX; + if (!(sa->fFeatures & FADF_VARIANT)) return DISP_E_BADVARTYPE; + + hr = start_script(This); + if (FAILED(hr)) return hr; + + hr = get_script_dispatch(This, &disp); + if (FAILED(hr)) return hr; + + hr = IDispatch_GetIDsOfNames(disp, &IID_NULL, &procedure_name, 1, LOCALE_USER_DEFAULT, &dispid); + if (FAILED(hr)) return hr; + + dp.cArgs = sa->rgsabound[0].cElements; + dp.rgdispidNamedArgs = NULL; + dp.cNamedArgs = 0; + dp.rgvarg = heap_alloc(dp.cArgs * sizeof(*dp.rgvarg)); + if (!dp.rgvarg) return E_OUTOFMEMORY; + + hr = SafeArrayLock(sa); + if (SUCCEEDED(hr)) + { + /* The DISPPARAMS are stored in reverse order */ + for (i = 0; i < dp.cArgs; i++) + dp.rgvarg[i] = *(VARIANT*)((char*)(sa->pvData) + (dp.cArgs - i - 1) * sa->cbElements); + SafeArrayUnlock(sa); + + hr = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex); + if (FAILED(hr)) + { + hr = IDispatch_Invoke(disp, dispid, &IID_NULL, LOCALE_USER_DEFAULT, + DISPATCH_METHOD, &dp, res, NULL, NULL); + } + else + { + hr = IDispatchEx_InvokeEx(dispex, dispid, LOCALE_USER_DEFAULT, + DISPATCH_METHOD, &dp, res, NULL, NULL); + IDispatchEx_Release(dispex); + } + } + heap_free(dp.rgvarg); + + return hr; }
static const IScriptControlVtbl ScriptControlVtbl = {
Signed-off-by: Jacek Caban jacek@codeweavers.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/msscript.ocx/tests/msscript.c | 413 ++++++++++++++++++++++++++++- 1 file changed, 411 insertions(+), 2 deletions(-)
diff --git a/dlls/msscript.ocx/tests/msscript.c b/dlls/msscript.ocx/tests/msscript.c index 95b2a69..141cf6e 100644 --- a/dlls/msscript.ocx/tests/msscript.c +++ b/dlls/msscript.ocx/tests/msscript.c @@ -29,6 +29,7 @@
#include "msscript.h" #include "wine/test.h" +DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
#define TESTSCRIPT_CLSID "{178fc164-f585-4e24-9c13-4bb7faf80746}" static const GUID CLSID_TestScript = @@ -92,12 +93,17 @@ DEFINE_EXPECT(CreateInstance); DEFINE_EXPECT(SetInterfaceSafetyOptions); DEFINE_EXPECT(InitNew); DEFINE_EXPECT(Close); +DEFINE_EXPECT(QI_IDispatchEx); +DEFINE_EXPECT(GetIDsOfNames); +DEFINE_EXPECT(Invoke); +DEFINE_EXPECT(InvokeEx); DEFINE_EXPECT(SetScriptSite); DEFINE_EXPECT(QI_IActiveScriptParse); DEFINE_EXPECT(SetScriptState_INITIALIZED); DEFINE_EXPECT(SetScriptState_STARTED); DEFINE_EXPECT(ParseScriptText); DEFINE_EXPECT(AddNamedItem); +DEFINE_EXPECT(GetScriptDispatch);
#define EXPECT_REF(obj,ref) _expect_ref((IUnknown*)obj, ref, __LINE__) static void _expect_ref(IUnknown* obj, ULONG ref, int line) @@ -226,6 +232,193 @@ static const IObjectSafetyVtbl ObjectSafetyVtbl = {
static IObjectSafety ObjectSafety = { &ObjectSafetyVtbl };
+static BOOL DispatchEx_available = FALSE; +static HRESULT WINAPI DispatchEx_QueryInterface(IDispatchEx *iface, REFIID riid, void **ppv) +{ + *ppv = NULL; + + if (IsEqualGUID(&IID_IDispatchEx, riid)) + { + CHECK_EXPECT(QI_IDispatchEx); + if (DispatchEx_available) + { + *ppv = iface; + return S_OK; + } + return E_NOINTERFACE; + } + + ok(0, "unexpected riid %s\n", wine_dbgstr_guid(riid)); + return E_NOINTERFACE; +} + +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) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static BSTR Dispatch_expected_name; +static HRESULT WINAPI DispatchEx_GetIDsOfNames(IDispatchEx *iface, REFIID riid, LPOLESTR *rgszNames, + UINT cNames, LCID lcid, DISPID *rgDispId) +{ + CHECK_EXPECT(GetIDsOfNames); + ok(IsEqualGUID(&IID_NULL, riid), "unexpected riid %s\n", wine_dbgstr_guid(riid)); + ok(lcid == LOCALE_USER_DEFAULT, "unexpected lcid %u\n", lcid); + ok(cNames == 1, "unexpected cNames %u\n", cNames); + ok(Dispatch_expected_name && !lstrcmpW(rgszNames[0], Dispatch_expected_name), + "unexpected name %s (expected %s).\n", wine_dbgstr_w(rgszNames[0]), wine_dbgstr_w(Dispatch_expected_name)); + + *rgDispId = 0xdeadbeef; + return S_OK; +} + +static HRESULT WINAPI DispatchEx_Invoke(IDispatchEx *iface, DISPID dispIdMember, REFIID riid, LCID lcid, + WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + CHECK_EXPECT(Invoke); + ok(IsEqualGUID(&IID_NULL, riid), "unexpected riid %s.\n", wine_dbgstr_guid(riid)); + ok(lcid == LOCALE_USER_DEFAULT, "unexpected lcid %u.\n", lcid); + ok(wFlags == DISPATCH_METHOD, "unexpected wFlags %u.\n", wFlags); + ok(dispIdMember == 0xdeadbeef, "unexpected dispIdMember %d.\n", dispIdMember); + ok(pDispParams->cNamedArgs == 0, "unexpected number of named args %u.\n", pDispParams->cNamedArgs); + ok(!pDispParams->rgdispidNamedArgs, "unexpected named args array %p\n", pDispParams->rgdispidNamedArgs); + ok(pDispParams->cArgs == 2, "unexpected number of args %u.\n", pDispParams->cArgs); + ok(!!pDispParams->rgvarg, "unexpected NULL rgvarg.\n"); + if (pDispParams->rgvarg && pDispParams->cArgs >= 2) + { + if (V_VT(pDispParams->rgvarg) == VT_BSTR) + { + if (!lstrcmpW(V_BSTR(pDispParams->rgvarg), L"change me")) + { + /* Change the string to check whether it's copied or not */ + lstrcpyW(V_BSTR(pDispParams->rgvarg), L"changed"); + } + else + ok(!lstrcmpW(V_BSTR(pDispParams->rgvarg), L"changed"), + "unexpected second parameter %s.\n", wine_dbgstr_w(V_BSTR(pDispParams->rgvarg))); + } + else + ok(0, "unexpected non-string second parameter V_VT = %d.\n", V_VT(pDispParams->rgvarg)); + + ok(V_VT(pDispParams->rgvarg + 1) == VT_I4 && V_I4(pDispParams->rgvarg + 1) == 10, + "unexpected first parameter V_VT = %d, V_I4 = %d.\n", + V_VT(pDispParams->rgvarg + 1), V_I4(pDispParams->rgvarg + 1)); + } + + V_VT(pVarResult) = VT_R8; + V_R8(pVarResult) = 4.2; + return S_OK; +} + +static HRESULT WINAPI DispatchEx_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, + DISPPARAMS *pdp, VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) +{ + CHECK_EXPECT(InvokeEx); + ok(lcid == LOCALE_USER_DEFAULT, "unexpected lcid %u.\n", lcid); + ok(wFlags == DISPATCH_METHOD, "unexpected wFlags %u.\n", wFlags); + ok(id == 0xdeadbeef, "unexpected id %d.\n", id); + ok(pdp->cNamedArgs == 0, "unexpected number of named args %u.\n", pdp->cNamedArgs); + ok(!pdp->rgdispidNamedArgs, "unexpected named args array %p.\n", pdp->rgdispidNamedArgs); + ok(pdp->cArgs == 2, "unexpected number of args %u.\n", pdp->cArgs); + ok(!!pdp->rgvarg, "unexpected NULL rgvarg.\n"); + if (pdp->rgvarg && pdp->cArgs >= 2) + { + if (V_VT(pdp->rgvarg) == VT_BSTR) + ok(!lstrcmpW(V_BSTR(pdp->rgvarg), L"changed"), + "unexpected second parameter %s.\n", wine_dbgstr_w(V_BSTR(pdp->rgvarg))); + else + ok(0, "unexpected non-string second parameter V_VT = %d.\n", V_VT(pdp->rgvarg)); + + ok(V_VT(pdp->rgvarg + 1) == VT_I4 && V_I4(pdp->rgvarg + 1) == 10, + "unexpected first parameter V_VT = %d, V_I4 = %d.\n", + V_VT(pdp->rgvarg + 1), V_I4(pdp->rgvarg + 1)); + } + + V_VT(pvarRes) = VT_I2; + V_I2(pvarRes) = 42; + return S_OK; +} + +static HRESULT WINAPI DispatchEx_DeleteMemberByName(IDispatchEx *iface, BSTR bstrName, DWORD grfdex) +{ + ok(0, "unexpected call\n"); + 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 *pbstrName) +{ + 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 const 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 DispatchEx = { &DispatchExVtbl }; + static HRESULT WINAPI ActiveScript_QueryInterface(IActiveScript *iface, REFIID riid, void **ppv) { *ppv = NULL; @@ -362,8 +555,12 @@ static HRESULT WINAPI ActiveScript_AddTypeLib(IActiveScript *iface, REFGUID rgui static HRESULT WINAPI ActiveScript_GetScriptDispatch(IActiveScript *iface, LPCOLESTR pstrItemName, IDispatch **ppdisp) { - ok(0, "unexpected call\n"); - return E_NOTIMPL; + CHECK_EXPECT(GetScriptDispatch); + ok(!pstrItemName, "pstrItemName not NULL, got %s.\n", wine_dbgstr_w(pstrItemName)); + + *ppdisp = (IDispatch*)&DispatchEx; + + return S_OK; }
static HRESULT WINAPI ActiveScript_GetCurrentScriptThreadID(IActiveScript *iface, @@ -1757,6 +1954,217 @@ static void test_IScriptControl_ExecuteStatement(void) } }
+static void test_IScriptControl_Run(void) +{ + SAFEARRAYBOUND bnd[] = { { 2, 0 }, { 2, 0 } }; + LONG idx0_0[] = { 0, 0 }; + LONG idx0_1[] = { 1, 0 }; + LONG idx1_0[] = { 0, 1 }; + LONG idx1_1[] = { 1, 1 }; + IScriptControl *sc; + SAFEARRAY *params; + VARIANT var; + HRESULT hr; + BSTR str; + + hr = CoCreateInstance(&CLSID_ScriptControl, NULL, CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER, + &IID_IScriptControl, (void**)&sc); + ok(hr == S_OK, "Failed to create IScriptControl interface: 0x%08x.\n", hr); + + params = NULL; + str = a2bstr("identifier"); + hr = IScriptControl_Run(sc, str, ¶ms, &var); + ok(hr == E_POINTER, "IScriptControl_Run returned: 0x%08x.\n", hr); + + params = SafeArrayCreate(VT_VARIANT, 1, bnd); + ok(params != NULL, "Failed to create SafeArray.\n"); + + V_VT(&var) = VT_I4; + V_I4(&var) = 10; + SafeArrayPutElement(params, idx0_0, &var); + V_I4(&var) = 3; + SafeArrayPutElement(params, idx0_1, &var); + + hr = IScriptControl_Run(sc, str, ¶ms, &var); + ok(hr == E_FAIL, "IScriptControl_Run returned: 0x%08x.\n", hr); + + hr = IScriptControl_Run(sc, str, NULL, &var); + ok(hr == E_POINTER, "IScriptControl_Run returned: 0x%08x.\n", hr); + + hr = IScriptControl_Run(sc, str, ¶ms, NULL); + ok(hr == E_POINTER, "IScriptControl_Run returned: 0x%08x.\n", hr); + SysFreeString(str); + + hr = IScriptControl_Run(sc, NULL, ¶ms, &var); + ok(hr == E_FAIL, "IScriptControl_Run returned: 0x%08x.\n", hr); + + str = a2bstr("jscript"); + hr = IScriptControl_put_Language(sc, str); + ok(hr == S_OK, "IScriptControl_put_Language failed: 0x%08x.\n", hr); + SysFreeString(str); + + str = a2bstr("foobar"); + hr = IScriptControl_Run(sc, str, ¶ms, &var); + ok(hr == DISP_E_UNKNOWNNAME, "IScriptControl_Run failed: 0x%08x.\n", hr); + todo_wine CHECK_ERROR(sc, 0); + SysFreeString(str); + + str = a2bstr("function subtract(a, b) { return a - b; }\n"); + hr = IScriptControl_AddCode(sc, str); + ok(hr == S_OK, "IScriptControl_AddCode failed: 0x%08x.\n", hr); + todo_wine CHECK_ERROR(sc, 0); + SysFreeString(str); + + str = a2bstr("Subtract"); + hr = IScriptControl_Run(sc, str, ¶ms, &var); + ok(hr == DISP_E_UNKNOWNNAME, "IScriptControl_Run failed: 0x%08x.\n", hr); + SysFreeString(str); + + str = a2bstr("subtract"); + hr = IScriptControl_Run(sc, str, ¶ms, NULL); + ok(hr == E_POINTER, "IScriptControl_Run failed: 0x%08x.\n", hr); + todo_wine CHECK_ERROR(sc, 0); + + hr = IScriptControl_Run(sc, str, ¶ms, &var); + ok(hr == S_OK, "IScriptControl_Run failed: 0x%08x.\n", hr); + ok((V_VT(&var) == VT_I4) && (V_I4(&var) == 7), "V_VT(var) = %d, V_I4(var) = %d.\n", V_VT(&var), V_I4(&var)); + todo_wine CHECK_ERROR(sc, 0); + SafeArrayDestroy(params); + + /* The array's other dimensions are ignored */ + params = SafeArrayCreate(VT_VARIANT, 2, bnd); + ok(params != NULL, "Failed to create SafeArray.\n"); + + V_VT(&var) = VT_I4; + V_I4(&var) = 10; + SafeArrayPutElement(params, idx0_0, &var); + V_I4(&var) = 3; + SafeArrayPutElement(params, idx0_1, &var); + V_I4(&var) = 90; + SafeArrayPutElement(params, idx1_0, &var); + V_I4(&var) = 80; + SafeArrayPutElement(params, idx1_1, &var); + + hr = IScriptControl_Run(sc, str, ¶ms, &var); + ok(hr == S_OK, "IScriptControl_Run failed: 0x%08x.\n", hr); + ok((V_VT(&var) == VT_I4) && (V_I4(&var) == 7), "V_VT(var) = %d, V_I4(var) = %d.\n", V_VT(&var), V_I4(&var)); + + /* Hack the array's dimensions to 0 */ + params->cDims = 0; + hr = IScriptControl_Run(sc, str, ¶ms, &var); + ok(hr == DISP_E_BADINDEX, "IScriptControl_Run returned: 0x%08x.\n", hr); + ok(V_VT(&var) == VT_EMPTY, "V_VT(var) = %d.\n", V_VT(&var)); + params->cDims = 2; + SysFreeString(str); + IScriptControl_Release(sc); + + /* custom script engine */ + if (have_custom_engine) + { + hr = CoCreateInstance(&CLSID_ScriptControl, NULL, CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER, + &IID_IScriptControl, (void**)&sc); + ok(hr == S_OK, "Failed to create IScriptControl interface: 0x%08x.\n", hr); + + SET_EXPECT(CreateInstance); + SET_EXPECT(SetInterfaceSafetyOptions); + SET_EXPECT(SetScriptSite); + SET_EXPECT(QI_IActiveScriptParse); + SET_EXPECT(InitNew); + str = a2bstr("testscript"); + hr = IScriptControl_put_Language(sc, str); + ok(hr == S_OK, "IScriptControl_put_Language failed: 0x%08x.\n", hr); + SysFreeString(str); + CHECK_CALLED(CreateInstance); + CHECK_CALLED(SetInterfaceSafetyOptions); + CHECK_CALLED(SetScriptSite); + CHECK_CALLED(QI_IActiveScriptParse); + CHECK_CALLED(InitNew); + + V_VT(&var) = VT_BSTR; + V_BSTR(&var) = a2bstr("change me"); + SafeArrayPutElement(params, idx0_1, &var); + VariantClear(&var); + + SET_EXPECT(SetScriptState_STARTED); + SET_EXPECT(GetScriptDispatch); + SET_EXPECT(QI_IDispatchEx); + SET_EXPECT(GetIDsOfNames); + SET_EXPECT(Invoke); + Dispatch_expected_name = a2bstr("function"); + hr = IScriptControl_Run(sc, Dispatch_expected_name, ¶ms, &var); + ok(hr == S_OK, "IScriptControl_Run failed: 0x%08x.\n", hr); + ok((V_VT(&var) == VT_R8) && (V_R8(&var) == 4.2), "V_VT(var) = %d, V_R8(var) = %lf.\n", V_VT(&var), V_R8(&var)); + SysFreeString(Dispatch_expected_name); + CHECK_CALLED(SetScriptState_STARTED); + CHECK_CALLED(GetScriptDispatch); + CHECK_CALLED(QI_IDispatchEx); + CHECK_CALLED(GetIDsOfNames); + CHECK_CALLED(Invoke); + + /* The parameter is supposed to be shared and not copied */ + SafeArrayGetElement(params, idx0_1, &var); + if (V_VT(&var) == VT_BSTR) + ok(!lstrcmpW(V_BSTR(&var), L"changed"), + "String parameter was supposed to be changed, got %s.\n", wine_dbgstr_w(V_BSTR(&var))); + else + ok(0, "String parameter is not VT_BSTR anymore, got %d.\n", V_VT(&var)); + VariantClear(&var); + + /* GetScriptDispatch is cached and not called again */ + CLEAR_CALLED(GetScriptDispatch); + SET_EXPECT(QI_IDispatchEx); + SET_EXPECT(GetIDsOfNames); + SET_EXPECT(Invoke); + Dispatch_expected_name = a2bstr("BarFoo"); + hr = IScriptControl_Run(sc, Dispatch_expected_name, ¶ms, &var); + ok(hr == S_OK, "IScriptControl_Run failed: 0x%08x.\n", hr); + SysFreeString(Dispatch_expected_name); + CHECK_NOT_CALLED(GetScriptDispatch); + CHECK_CALLED(QI_IDispatchEx); + CHECK_CALLED(GetIDsOfNames); + CHECK_CALLED(Invoke); + + /* Make DispatchEx available */ + DispatchEx_available = TRUE; + CLEAR_CALLED(GetScriptDispatch); + SET_EXPECT(QI_IDispatchEx); + SET_EXPECT(GetIDsOfNames); + SET_EXPECT(InvokeEx); + Dispatch_expected_name = a2bstr("FooBar"); + hr = IScriptControl_Run(sc, Dispatch_expected_name, ¶ms, &var); + ok(hr == S_OK, "IScriptControl_Run failed: 0x%08x.\n", hr); + ok((V_VT(&var) == VT_I2) && (V_I2(&var) == 42), "V_VT(var) = %d, V_I2(var) = %d.\n", V_VT(&var), V_I2(&var)); + SysFreeString(Dispatch_expected_name); + CHECK_NOT_CALLED(GetScriptDispatch); + CHECK_CALLED(QI_IDispatchEx); + CHECK_CALLED(GetIDsOfNames); + CHECK_CALLED(InvokeEx); + + /* QueryInterface for IDispatchEx is always called and not cached */ + CLEAR_CALLED(GetScriptDispatch); + SET_EXPECT(QI_IDispatchEx); + SET_EXPECT(GetIDsOfNames); + SET_EXPECT(InvokeEx); + Dispatch_expected_name = a2bstr("1"); + hr = IScriptControl_Run(sc, Dispatch_expected_name, ¶ms, &var); + ok(hr == S_OK, "IScriptControl_Run failed: 0x%08x.\n", hr); + SysFreeString(Dispatch_expected_name); + CHECK_NOT_CALLED(GetScriptDispatch); + CHECK_CALLED(QI_IDispatchEx); + CHECK_CALLED(GetIDsOfNames); + CHECK_CALLED(InvokeEx); + DispatchEx_available = FALSE; + + IActiveScriptSite_Release(site); + + SET_EXPECT(Close); + IScriptControl_Release(sc); + CHECK_CALLED(Close); + } + + SafeArrayDestroy(params); +} + START_TEST(msscript) { IUnknown *unk; @@ -1793,6 +2201,7 @@ START_TEST(msscript) test_IScriptControl_Eval(); test_IScriptControl_AddCode(); test_IScriptControl_ExecuteStatement(); + test_IScriptControl_Run();
init_registry(FALSE);
Hi Gabriel,
On 9/30/19 2:43 PM, Gabriel Ivăncescu wrote:
{
if (!lstrcmpW(V_BSTR(pDispParams->rgvarg), L"change me"))
{
/* Change the string to check whether it's copied or not */
lstrcpyW(V_BSTR(pDispParams->rgvarg), L"changed");
}
else
ok(!lstrcmpW(V_BSTR(pDispParams->rgvarg), L"changed"),
"unexpected second parameter %s.\n", wine_dbgstr_w(V_BSTR(pDispParams->rgvarg)));
}
else
ok(0, "unexpected non-string second parameter V_VT = %d.\n", V_VT(pDispParams->rgvarg));
While I can see why it was interesting for your experimentations, this is not really nice nor something that seems important to have in tests. But please remove this part. The rest of the patch looks good.
Thanks,
Jacek
On 9/30/19 5:38 PM, Jacek Caban wrote:
Hi Gabriel,
On 9/30/19 2:43 PM, Gabriel Ivăncescu wrote:
{ + if (!lstrcmpW(V_BSTR(pDispParams->rgvarg), L"change me")) + { + /* Change the string to check whether it's copied or not */ + lstrcpyW(V_BSTR(pDispParams->rgvarg), L"changed"); + } + else + ok(!lstrcmpW(V_BSTR(pDispParams->rgvarg), L"changed"), + "unexpected second parameter %s.\n", wine_dbgstr_w(V_BSTR(pDispParams->rgvarg))); + } + else + ok(0, "unexpected non-string second parameter V_VT = %d.\n", V_VT(pDispParams->rgvarg));
While I can see why it was interesting for your experimentations, this is not really nice nor something that seems important to have in tests. But please remove this part. The rest of the patch looks good.
Thanks,
Jacek
Ok, I will resend it tomorrow after the others committed so it succeeds. :-)