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 = {