From b22dfdc98ce594e446b9d8e3e4dd6b7303d984da Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Sat, 16 Jul 2016 22:34:18 +0300 Subject: [PATCH] msscript: Initial support for hosting script engines. Signed-off-by: Nikolay Sivov Signed-off-by: Jacek Caban Signed-off-by: Alexandre Julliard --- dlls/msscript.ocx/msscript.c | 288 ++++++++++++++++++++++++++++- dlls/msscript.ocx/tests/msscript.c | 15 +- 2 files changed, 291 insertions(+), 12 deletions(-) diff --git a/dlls/msscript.ocx/msscript.c b/dlls/msscript.ocx/msscript.c index bc3f5c1cae4..4a1b3787aec 100644 --- a/dlls/msscript.ocx/msscript.c +++ b/dlls/msscript.ocx/msscript.c @@ -22,6 +22,8 @@ #include "initguid.h" #include "ole2.h" #include "olectl.h" +#include "objsafe.h" +#include "activscp.h" #include "rpcproxy.h" #include "msscript.h" @@ -29,6 +31,20 @@ WINE_DEFAULT_DEBUG_CHANNEL(msscript); +#ifdef _WIN64 + +#define IActiveScriptParse_Release IActiveScriptParse64_Release +#define IActiveScriptParse_InitNew IActiveScriptParse64_InitNew +#define IActiveScriptParse_ParseScriptText IActiveScriptParse64_ParseScriptText + +#else + +#define IActiveScriptParse_Release IActiveScriptParse32_Release +#define IActiveScriptParse_InitNew IActiveScriptParse32_InitNew +#define IActiveScriptParse_ParseScriptText IActiveScriptParse32_ParseScriptText + +#endif + struct ScriptControl; typedef struct ConnectionPoint ConnectionPoint; @@ -39,6 +55,15 @@ struct ConnectionPoint { ConnectionPoint *next; }; +typedef struct ScriptHost { + IActiveScriptSite IActiveScriptSite_iface; + LONG ref; + + IActiveScript *script; + IActiveScriptParse *parse; + CLSID clsid; +} ScriptHost; + struct ScriptControl { IScriptControl IScriptControl_iface; IPersistStreamInit IPersistStreamInit_iface; @@ -56,6 +81,8 @@ struct ScriptControl { ConnectionPoint *cp_list; ConnectionPoint cp_scsource; ConnectionPoint cp_propnotif; + + ScriptHost *host; }; static HINSTANCE msscript_instance; @@ -184,6 +211,224 @@ static inline ConnectionPoint *impl_from_IConnectionPoint(IConnectionPoint *ifac return CONTAINING_RECORD(iface, ConnectionPoint, IConnectionPoint_iface); } +static inline ScriptHost *impl_from_IActiveScriptSite(IActiveScriptSite *iface) +{ + return CONTAINING_RECORD(iface, ScriptHost, IActiveScriptSite_iface); +} + +/* IActiveScriptSite */ +static HRESULT WINAPI ActiveScriptSite_QueryInterface(IActiveScriptSite *iface, REFIID riid, void **ppv) +{ + ScriptHost *This = impl_from_IActiveScriptSite(iface); + + if(IsEqualGUID(&IID_IUnknown, riid)) { + TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv); + *ppv = &This->IActiveScriptSite_iface; + }else if(IsEqualGUID(&IID_IActiveScriptSite, riid)) { + TRACE("(%p)->(IID_IActiveScriptSite %p)\n", This, ppv); + *ppv = &This->IActiveScriptSite_iface; + }else { + FIXME("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv); + *ppv = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown*)*ppv); + return S_OK; +} + +static ULONG WINAPI ActiveScriptSite_AddRef(IActiveScriptSite *iface) +{ + ScriptHost *This = impl_from_IActiveScriptSite(iface); + LONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p) ref=%d\n", This, ref); + + return ref; +} + +static void release_script_engine(ScriptHost *host) +{ + if (host->script) { + IActiveScript_Close(host->script); + IActiveScript_Release(host->script); + } + + if (host->parse) + IActiveScriptParse_Release(host->parse); + + host->parse = NULL; + host->script = NULL; + + IActiveScriptSite_Release(&host->IActiveScriptSite_iface); +} + +static ULONG WINAPI ActiveScriptSite_Release(IActiveScriptSite *iface) +{ + ScriptHost *This = impl_from_IActiveScriptSite(iface); + LONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p) ref=%d\n", This, ref); + + if(!ref) + heap_free(This); + + return ref; +} + +static HRESULT WINAPI ActiveScriptSite_GetLCID(IActiveScriptSite *iface, LCID *lcid) +{ + ScriptHost *This = impl_from_IActiveScriptSite(iface); + + TRACE("(%p, %p)\n", This, lcid); + + *lcid = GetUserDefaultLCID(); + return S_OK; +} + +static HRESULT WINAPI ActiveScriptSite_GetItemInfo(IActiveScriptSite *iface, LPCOLESTR name, DWORD returnmask, + IUnknown **item, ITypeInfo **ti) +{ + ScriptHost *This = impl_from_IActiveScriptSite(iface); + + FIXME("(%p, %s, %#x, %p, %p)\n", This, debugstr_w(name), returnmask, item, ti); + + return E_NOTIMPL; +} + +static HRESULT WINAPI ActiveScriptSite_GetDocVersionString(IActiveScriptSite *iface, BSTR *version) +{ + ScriptHost *This = impl_from_IActiveScriptSite(iface); + + FIXME("(%p, %p)\n", This, version); + + return E_NOTIMPL; +} + +static HRESULT WINAPI ActiveScriptSite_OnScriptTerminate(IActiveScriptSite *iface, const VARIANT *result, + const EXCEPINFO *ei) +{ + ScriptHost *This = impl_from_IActiveScriptSite(iface); + + FIXME("(%p, %s, %p)\n", This, debugstr_variant(result), ei); + + return E_NOTIMPL; +} + +static HRESULT WINAPI ActiveScriptSite_OnStateChange(IActiveScriptSite *iface, SCRIPTSTATE state) +{ + ScriptHost *This = impl_from_IActiveScriptSite(iface); + + FIXME("(%p, %d)\n", This, state); + + return E_NOTIMPL; +} + +static HRESULT WINAPI ActiveScriptSite_OnScriptError(IActiveScriptSite *iface, IActiveScriptError *script_error) +{ + ScriptHost *This = impl_from_IActiveScriptSite(iface); + + FIXME("(%p, %p)\n", This, script_error); + + return E_NOTIMPL; +} + +static HRESULT WINAPI ActiveScriptSite_OnEnterScript(IActiveScriptSite *iface) +{ + ScriptHost *This = impl_from_IActiveScriptSite(iface); + + FIXME("(%p)\n", This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI ActiveScriptSite_OnLeaveScript(IActiveScriptSite *iface) +{ + ScriptHost *This = impl_from_IActiveScriptSite(iface); + + FIXME("(%p)\n", This); + + return E_NOTIMPL; +} + +static const IActiveScriptSiteVtbl ActiveScriptSiteVtbl = { + ActiveScriptSite_QueryInterface, + ActiveScriptSite_AddRef, + ActiveScriptSite_Release, + ActiveScriptSite_GetLCID, + ActiveScriptSite_GetItemInfo, + ActiveScriptSite_GetDocVersionString, + ActiveScriptSite_OnScriptTerminate, + ActiveScriptSite_OnStateChange, + ActiveScriptSite_OnScriptError, + ActiveScriptSite_OnEnterScript, + ActiveScriptSite_OnLeaveScript +}; + +static HRESULT init_script_host(const CLSID *clsid, ScriptHost **ret) +{ + IObjectSafety *objsafety; + ScriptHost *host; + HRESULT hr; + + *ret = NULL; + + host = heap_alloc(sizeof(*host)); + if (!host) + return E_OUTOFMEMORY; + + host->IActiveScriptSite_iface.lpVtbl = &ActiveScriptSiteVtbl; + host->ref = 1; + host->script = NULL; + host->parse = NULL; + host->clsid = *clsid; + + hr = CoCreateInstance(&host->clsid, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER, + &IID_IActiveScript, (void**)&host->script); + if (FAILED(hr)) { + WARN("Failed to create an instance for %s, %#x\n", debugstr_guid(clsid), hr); + goto failed; + } + + hr = IActiveScript_QueryInterface(host->script, &IID_IObjectSafety, (void**)&objsafety); + if (FAILED(hr)) { + FIXME("Could not get IObjectSafety, %#x\n", hr); + goto failed; + } + + hr = IObjectSafety_SetInterfaceSafetyOptions(objsafety, &IID_IActiveScriptParse, INTERFACESAFE_FOR_UNTRUSTED_DATA, 0); + IObjectSafety_Release(objsafety); + if (FAILED(hr)) { + FIXME("SetInterfaceSafetyOptions failed, %#x\n", hr); + goto failed; + } + + hr = IActiveScript_SetScriptSite(host->script, &host->IActiveScriptSite_iface); + if (FAILED(hr)) { + WARN("SetScriptSite failed, %#x\n", hr); + goto failed; + } + + hr = IActiveScript_QueryInterface(host->script, &IID_IActiveScriptParse, (void**)&host->parse); + if (FAILED(hr)) { + WARN("Failed to get IActiveScriptParse, %#x\n", hr); + goto failed; + } + + hr = IActiveScriptParse_InitNew(host->parse); + if (FAILED(hr)) { + WARN("InitNew failed, %#x\n", hr); + goto failed; + } + + *ret = host; + return S_OK; + +failed: + release_script_engine(host); + return hr; +} + static HRESULT WINAPI ScriptControl_QueryInterface(IScriptControl *iface, REFIID riid, void **ppv) { ScriptControl *This = impl_from_IScriptControl(iface); @@ -257,6 +502,8 @@ static ULONG WINAPI ScriptControl_Release(IScriptControl *iface) if(!ref) { if (This->site) IOleClientSite_Release(This->site); + if (This->host) + release_script_engine(This->host); heap_free(This); } @@ -321,15 +568,47 @@ static HRESULT WINAPI ScriptControl_Invoke(IScriptControl *iface, DISPID dispIdM static HRESULT WINAPI ScriptControl_get_Language(IScriptControl *iface, BSTR *p) { ScriptControl *This = impl_from_IScriptControl(iface); - FIXME("(%p)->(%p)\n", This, p); - return E_NOTIMPL; + LPOLESTR progidW; + HRESULT hr; + + TRACE("(%p)->(%p)\n", This, p); + + if (!p) + return E_POINTER; + + *p = NULL; + + if (!This->host) + return S_OK; + + hr = ProgIDFromCLSID(&This->host->clsid, &progidW); + if (FAILED(hr)) + return hr; + + *p = SysAllocString(progidW); + CoTaskMemFree(progidW); + return *p ? S_OK : E_OUTOFMEMORY; } static HRESULT WINAPI ScriptControl_put_Language(IScriptControl *iface, BSTR language) { ScriptControl *This = impl_from_IScriptControl(iface); - FIXME("(%p)->(%s)\n", This, debugstr_w(language)); - return E_NOTIMPL; + CLSID clsid; + + TRACE("(%p)->(%s)\n", This, debugstr_w(language)); + + if (language && FAILED(CLSIDFromProgID(language, &clsid))) + return CTL_E_INVALIDPROPERTYVALUE; + + if (This->host) { + release_script_engine(This->host); + This->host = NULL; + } + + if (!language) + return S_OK; + + return init_script_host(&clsid, &This->host); } static HRESULT WINAPI ScriptControl_get_State(IScriptControl *iface, ScriptControlStates *p) @@ -1379,6 +1658,7 @@ static HRESULT WINAPI ScriptControl_CreateInstance(IClassFactory *iface, IUnknow script_control->ref = 1; script_control->site = NULL; script_control->cp_list = NULL; + script_control->host = NULL; ConnectionPoint_Init(&script_control->cp_scsource, script_control, &DIID_DScriptControlSource); ConnectionPoint_Init(&script_control->cp_propnotif, script_control, &IID_IPropertyNotifySink); diff --git a/dlls/msscript.ocx/tests/msscript.c b/dlls/msscript.ocx/tests/msscript.c index f4e63060f73..07681749842 100644 --- a/dlls/msscript.ocx/tests/msscript.c +++ b/dlls/msscript.ocx/tests/msscript.c @@ -92,6 +92,7 @@ DEFINE_EXPECT(SetInterfaceSafetyOptions); DEFINE_EXPECT(InitNew); DEFINE_EXPECT(Close); DEFINE_EXPECT(SetScriptSite); +DEFINE_EXPECT(QI_IActiveScriptParse); #define EXPECT_REF(obj,ref) _expect_ref((IUnknown*)obj, ref, __LINE__) static void _expect_ref(IUnknown* obj, ULONG ref, int line) @@ -220,6 +221,7 @@ static HRESULT WINAPI ActiveScript_QueryInterface(IActiveScript *iface, REFIID r } if(IsEqualGUID(&IID_IActiveScriptParse, riid)) { + CHECK_EXPECT(QI_IActiveScriptParse); *ppv = &ActiveScriptParse; return S_OK; } @@ -261,7 +263,6 @@ static HRESULT WINAPI ActiveScript_SetScriptSite(IActiveScript *iface, IActiveSc ok(hres == S_OK, "GetLCID failed: %08x\n", hres); hres = IActiveScriptSite_OnStateChange(pass, (state = SCRIPTSTATE_INITIALIZED)); -todo_wine ok(hres == E_NOTIMPL, "OnStateChange failed: %08x\n", hres); hres = IActiveScriptSite_QueryInterface(pass, &IID_IActiveScriptSiteDebug, (void**)&debug); @@ -683,14 +684,12 @@ static void test_Language(void) &IID_IScriptControl, (void**)&sc); ok(hr == S_OK, "got 0x%08x\n", hr); -todo_wine { hr = IScriptControl_get_Language(sc, NULL); ok(hr == E_POINTER, "got 0x%08x\n", hr); str = (BSTR)0xdeadbeef; hr = IScriptControl_get_Language(sc, &str); ok(hr == S_OK, "got 0x%08x\n", hr); -if (hr == S_OK) ok(str == NULL, "got %s\n", wine_dbgstr_w(str)); str = SysAllocString(vbW); @@ -715,7 +714,6 @@ if (hr == S_OK) hr = IScriptControl_get_Language(sc, &str); ok(hr == S_OK, "got 0x%08x\n", hr); -if (hr == S_OK) ok(!lstrcmpW(str, vbW), "got %s\n", wine_dbgstr_w(str)); SysFreeString(str); @@ -725,7 +723,7 @@ if (hr == S_OK) SysFreeString(str); hr = IScriptControl_get_Language(sc, &str); -if (hr == S_OK) + ok(hr == S_OK, "got 0x%08x\n", hr); ok(!lstrcmpW(str, jsW), "got %s\n", wine_dbgstr_w(str)); SysFreeString(str); @@ -735,8 +733,8 @@ if (hr == S_OK) hr = IScriptControl_get_Language(sc, &str); ok(hr == S_OK, "got 0x%08x\n", hr); ok(str == NULL, "got %s\n", wine_dbgstr_w(str)); + IScriptControl_Release(sc); -} /* custom script engine */ if (register_script_engine()) { @@ -746,10 +744,10 @@ if (hr == S_OK) &IID_IScriptControl, (void**)&sc); ok(hr == S_OK, "got 0x%08x\n", hr); - todo_wine { SET_EXPECT(CreateInstance); SET_EXPECT(SetInterfaceSafetyOptions); SET_EXPECT(SetScriptSite); + SET_EXPECT(QI_IActiveScriptParse); SET_EXPECT(InitNew); str = SysAllocString(testscriptW); @@ -760,8 +758,10 @@ if (hr == S_OK) CHECK_CALLED(CreateInstance); CHECK_CALLED(SetInterfaceSafetyOptions); CHECK_CALLED(SetScriptSite); + CHECK_CALLED(QI_IActiveScriptParse); CHECK_CALLED(InitNew); hr = IScriptControl_get_Language(sc, &str); + todo_wine ok(hr == S_OK, "got 0x%08x\n", hr); if (hr == S_OK) ok(!lstrcmpW(testscriptW, str), "%s\n", wine_dbgstr_w(str)); @@ -775,7 +775,6 @@ if (hr == S_OK) CHECK_CALLED(Close); } - } else skip("Could not register TestScript engine\n"); }