msscript: Initial support for hosting script engines.

Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com>
Signed-off-by: Jacek Caban <jacek@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Nikolay Sivov 2016-07-16 22:34:18 +03:00 committed by Alexandre Julliard
parent 1fda7ca72e
commit b22dfdc98c
2 changed files with 291 additions and 12 deletions

View file

@ -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);

View file

@ -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");
}