[PATCH] msscript: Initial support for hosting script engines

Nikolay Sivov nsivov at codeweavers.com
Thu Jul 14 09:35:27 CDT 2016


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/msscript.ocx/msscript.c       | 286 ++++++++++++++++++++++++++++++++++++-
 dlls/msscript.ocx/tests/msscript.c |  15 +-
 2 files changed, 289 insertions(+), 12 deletions(-)

diff --git a/dlls/msscript.ocx/msscript.c b/dlls/msscript.ocx/msscript.c
index bc3f5c1..3abd929 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,220 @@ 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;
+}
+
+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);
+    if (FAILED(hr))
+        FIXME("SetInterfaceSafetyOptions failed, %#x\n", hr);
+    IObjectSafety_Release(objsafety);
+
+    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:
+    IActiveScriptSite_Release(&host->IActiveScriptSite_iface);
+    return hr;
+}
+
 static HRESULT WINAPI ScriptControl_QueryInterface(IScriptControl *iface, REFIID riid, void **ppv)
 {
     ScriptControl *This = impl_from_IScriptControl(iface);
@@ -257,6 +498,10 @@ static ULONG WINAPI ScriptControl_Release(IScriptControl *iface)
     if(!ref) {
         if (This->site)
             IOleClientSite_Release(This->site);
+        if (This->host) {
+            release_script_engine(This->host);
+            IActiveScriptSite_Release(&This->host->IActiveScriptSite_iface);
+        }
         heap_free(This);
     }
 
@@ -321,15 +566,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 = SysAllocStringLen(progidW, lstrlenW(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) {
+        IActiveScriptSite_Release(&This->host->IActiveScriptSite_iface);
+        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 +1656,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 f4e6306..0768174 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");
 }
-- 
2.8.1




More information about the wine-patches mailing list