[PATCH 2/3] msscript: Added basic script hosting stub support

Nikolay Sivov nsivov at codeweavers.com
Sat Jun 11 05:02:39 CDT 2016


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---

This deprecates patch 123111.

 dlls/msscript.ocx/msscript.c        | 237 ++++++++++++++++-
 dlls/msscript.ocx/tests/Makefile.in |   2 +-
 dlls/msscript.ocx/tests/msscript.c  | 488 ++++++++++++++++++++++++++++++++++++
 include/activscp.idl                |  16 ++
 4 files changed, 737 insertions(+), 6 deletions(-)

diff --git a/dlls/msscript.ocx/msscript.c b/dlls/msscript.ocx/msscript.c
index 5a03f0c..b6764f4 100644
--- a/dlls/msscript.ocx/msscript.c
+++ b/dlls/msscript.ocx/msscript.c
@@ -22,6 +22,7 @@
 #include "initguid.h"
 #include "ole2.h"
 #include "olectl.h"
+#include "activscp.h"
 #include "rpcproxy.h"
 #include "msscript.h"
 
@@ -29,14 +30,21 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(msscript);
 
+static const WCHAR vbscriptW[] = {'V','B','S','c','r','i','p','t',0};
+static const WCHAR jscriptW[] = {'J','S','c','r','i','p','t',0};
+
 struct ScriptControl {
     IScriptControl IScriptControl_iface;
     IPersistStreamInit IPersistStreamInit_iface;
     IOleObject IOleObject_iface;
     IOleControl IOleControl_iface;
+    IActiveScriptSite IActiveScriptSite_iface;
     LONG ref;
     IOleClientSite *site;
     SIZEL extent;
+    BSTR lang;
+    IActiveScript *script;
+    SCRIPTSTATE script_state;
 };
 
 static HINSTANCE msscript_instance;
@@ -120,6 +128,29 @@ static void release_typelib(void)
     ITypeLib_Release(typelib);
 }
 
+static void release_script_engine(ScriptControl *sc)
+{
+    if (!sc->script)
+        return;
+
+    switch (sc->script_state) {
+    case SCRIPTSTATE_CONNECTED:
+        IActiveScript_SetScriptState(sc->script, SCRIPTSTATE_DISCONNECTED);
+
+    case SCRIPTSTATE_STARTED:
+    case SCRIPTSTATE_DISCONNECTED:
+    case SCRIPTSTATE_INITIALIZED:
+        IActiveScript_Close(sc->script);
+
+    default:
+        ;
+    }
+
+    sc->script_state = SCRIPTSTATE_UNINITIALIZED;
+    IActiveScript_Release(sc->script);
+    sc->script = NULL;
+}
+
 static inline ScriptControl *impl_from_IScriptControl(IScriptControl *iface)
 {
     return CONTAINING_RECORD(iface, ScriptControl, IScriptControl_iface);
@@ -140,6 +171,133 @@ static inline ScriptControl *impl_from_IOleControl(IOleControl *iface)
     return CONTAINING_RECORD(iface, ScriptControl, IOleControl_iface);
 }
 
+static inline ScriptControl *impl_from_IActiveScriptSite(IActiveScriptSite *iface)
+{
+    return CONTAINING_RECORD(iface, ScriptControl, IActiveScriptSite_iface);
+}
+
+static HRESULT WINAPI ActiveScriptSite_QueryInterface(IActiveScriptSite *iface, REFIID riid, void **ppv)
+{
+    ScriptControl *This = impl_from_IActiveScriptSite(iface);
+
+    *ppv = NULL;
+
+    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);
+        return E_NOINTERFACE;
+    }
+
+    IUnknown_AddRef((IUnknown*)*ppv);
+    return S_OK;
+}
+
+static ULONG WINAPI ActiveScriptSite_AddRef(IActiveScriptSite *iface)
+{
+    ScriptControl *This = impl_from_IActiveScriptSite(iface);
+    return IScriptControl_AddRef(&This->IScriptControl_iface);
+}
+
+static ULONG WINAPI ActiveScriptSite_Release(IActiveScriptSite *iface)
+{
+    ScriptControl *This = impl_from_IActiveScriptSite(iface);
+    return IScriptControl_Release(&This->IScriptControl_iface);
+}
+
+static HRESULT WINAPI ActiveScriptSite_GetLCID(IActiveScriptSite *iface, LCID *lcid)
+{
+    ScriptControl *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 return_mask, IUnknown **unkitem, ITypeInfo **ti)
+{
+    ScriptControl *This = impl_from_IActiveScriptSite(iface);
+
+    FIXME("(%p)->(%s %x %p %p)\n", This, debugstr_w(name), return_mask, unkitem, ti);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ActiveScriptSite_GetDocVersionString(IActiveScriptSite *iface, BSTR *version)
+{
+    ScriptControl *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)
+{
+    ScriptControl *This = impl_from_IActiveScriptSite(iface);
+
+    FIXME("(%p)->(%p %p)\n", This, result, ei);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ActiveScriptSite_OnStateChange(IActiveScriptSite *iface, SCRIPTSTATE script_state)
+{
+    ScriptControl *This = impl_from_IActiveScriptSite(iface);
+
+    TRACE("(%p)->(%x)\n", This, script_state);
+
+    This->script_state = script_state;
+    return S_OK;
+}
+
+static HRESULT WINAPI ActiveScriptSite_OnScriptError(IActiveScriptSite *iface, IActiveScriptError *pscripterror)
+{
+    ScriptControl *This = impl_from_IActiveScriptSite(iface);
+
+    FIXME("(%p)->(%p)\n", This, pscripterror);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ActiveScriptSite_OnEnterScript(IActiveScriptSite *iface)
+{
+    ScriptControl *This = impl_from_IActiveScriptSite(iface);
+
+    TRACE("(%p)->()\n", This);
+
+    return S_OK;
+}
+
+static HRESULT WINAPI ActiveScriptSite_OnLeaveScript(IActiveScriptSite *iface)
+{
+    ScriptControl *This = impl_from_IActiveScriptSite(iface);
+
+    TRACE("(%p)->()\n", This);
+
+    return S_OK;
+}
+
+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 WINAPI ScriptControl_QueryInterface(IScriptControl *iface, REFIID riid, void **ppv)
 {
     ScriptControl *This = impl_from_IScriptControl(iface);
@@ -193,6 +351,7 @@ static ULONG WINAPI ScriptControl_Release(IScriptControl *iface)
     TRACE("(%p) ref=%d\n", This, ref);
 
     if(!ref) {
+        release_script_engine(This);
         if (This->site)
             IOleClientSite_Release(This->site);
         heap_free(This);
@@ -259,15 +418,79 @@ 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;
+
+    TRACE("(%p)->(%p)\n", This, p);
+
+    if (!p)
+        return E_POINTER;
+
+    if (This->lang) {
+        if (!(*p = SysAllocString(This->lang)))
+            return E_OUTOFMEMORY;
+    }
+    else
+        *p = NULL;
+
+    return S_OK;
+}
+
+static void set_script_name(ScriptControl *sc, BSTR lang)
+{
+    SysFreeString(sc->lang);
+    sc->lang = lang ? SysAllocString(lang) : NULL;
+}
+
+
+static BOOL init_script_engine(ScriptControl *sc)
+{
+    HRESULT hr;
+
+    hr = IActiveScript_SetScriptSite(sc->script, &sc->IActiveScriptSite_iface);
+    if (FAILED(hr)) {
+        WARN("SetScriptSite failed: %08x\n", hr);
+        IActiveScript_Close(sc->script);
+        return FALSE;
+    }
+
+    return TRUE;
 }
 
-static HRESULT WINAPI ScriptControl_put_Language(IScriptControl *iface, BSTR language)
+static HRESULT WINAPI ScriptControl_put_Language(IScriptControl *iface, BSTR lang)
 {
     ScriptControl *This = impl_from_IScriptControl(iface);
-    FIXME("(%p)->(%s)\n", This, debugstr_w(language));
-    return E_NOTIMPL;
+    HRESULT hr;
+    GUID guid;
+
+    TRACE("(%p)->(%s)\n", This, debugstr_w(lang));
+
+    if (!lang) {
+        release_script_engine(This);
+        set_script_name(This, NULL);
+        return S_OK;
+    }
+
+    hr = CLSIDFromProgID(lang, &guid);
+    if (FAILED(hr))
+        return CTL_E_INVALIDPROPERTYVALUE;
+
+    hr = CoCreateInstance(&guid, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER,
+            &IID_IActiveScript, (void**)&This->script);
+    if (FAILED(hr))
+        return CTL_E_INVALIDPROPERTYVALUE;
+    else if (!init_script_engine(This)) {
+        release_script_engine(This);
+        return CTL_E_INVALIDPROPERTYVALUE;
+    }
+
+    /* store engine name */
+    if (!lstrcmpiW(lang, vbscriptW))
+        This->lang = SysAllocString(vbscriptW);
+    else if (!lstrcmpiW(lang, jscriptW))
+        This->lang = SysAllocString(jscriptW);
+    else
+        This->lang = SysAllocString(lang);
+
+    return S_OK;
 }
 
 static HRESULT WINAPI ScriptControl_get_State(IScriptControl *iface, ScriptControlStates *p)
@@ -873,8 +1096,12 @@ static HRESULT WINAPI ScriptControl_CreateInstance(IClassFactory *iface, IUnknow
     script_control->IPersistStreamInit_iface.lpVtbl = &PersistStreamInitVtbl;
     script_control->IOleObject_iface.lpVtbl = &OleObjectVtbl;
     script_control->IOleControl_iface.lpVtbl = &OleControlVtbl;
+    script_control->IActiveScriptSite_iface.lpVtbl = &ActiveScriptSiteVtbl;
     script_control->ref = 1;
     script_control->site = NULL;
+    script_control->lang = NULL;
+    script_control->script_state = SCRIPTSTATE_UNINITIALIZED;
+    script_control->script = NULL;
 
     hdc = GetDC(0);
     dpi_x = GetDeviceCaps(hdc, LOGPIXELSX);
diff --git a/dlls/msscript.ocx/tests/Makefile.in b/dlls/msscript.ocx/tests/Makefile.in
index 8d769d3..cc62590 100644
--- a/dlls/msscript.ocx/tests/Makefile.in
+++ b/dlls/msscript.ocx/tests/Makefile.in
@@ -1,5 +1,5 @@
 TESTDLL   = msscript.ocx
-IMPORTS   = user32 gdi32 ole32
+IMPORTS   = user32 gdi32 ole32 oleaut32 advapi32
 
 C_SRCS = \
 	msscript.c
diff --git a/dlls/msscript.ocx/tests/msscript.c b/dlls/msscript.ocx/tests/msscript.c
index 12f7003..d1d553b 100644
--- a/dlls/msscript.ocx/tests/msscript.c
+++ b/dlls/msscript.ocx/tests/msscript.c
@@ -22,10 +22,411 @@
 #include <initguid.h>
 #include <ole2.h>
 #include <olectl.h>
+#include "dispex.h"
+#include "activscp.h"
+#include "activdbg.h"
+#include "objsafe.h"
 
 #include "msscript.h"
 #include "wine/test.h"
 
+#define TESTSCRIPT_CLSID "{178fc164-f585-4e24-9c13-4bb7faf80746}"
+static const GUID CLSID_TestScript =
+    {0x178fc164,0xf585,0x4e24,{0x9c,0x13,0x4b,0xb7,0xfa,0xf8,0x07,0x46}};
+
+#ifdef _WIN64
+
+#define CTXARG_T DWORDLONG
+#define IActiveScriptParseVtbl IActiveScriptParse64Vtbl
+#define IActiveScriptSiteDebug_Release IActiveScriptSiteDebug64_Release
+
+#else
+
+#define CTXARG_T DWORD
+#define IActiveScriptParseVtbl IActiveScriptParse32Vtbl
+#define IActiveScriptSiteDebug_Release IActiveScriptSiteDebug32_Release
+
+#endif
+
+static IActiveScriptSite *site;
+static SCRIPTSTATE state;
+
+static HRESULT WINAPI ActiveScriptParse_QueryInterface(IActiveScriptParse *iface, REFIID riid, void **ppv)
+{
+    *ppv = NULL;
+    ok(0, "unexpected call\n");
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI ActiveScriptParse_AddRef(IActiveScriptParse *iface)
+{
+    return 2;
+}
+
+static ULONG WINAPI ActiveScriptParse_Release(IActiveScriptParse *iface)
+{
+    return 1;
+}
+
+static HRESULT WINAPI ActiveScriptParse_InitNew(IActiveScriptParse *iface)
+{
+    return S_OK;
+}
+
+static HRESULT WINAPI ActiveScriptParse_AddScriptlet(IActiveScriptParse *iface,
+        LPCOLESTR pstrDefaultName, LPCOLESTR pstrCode, LPCOLESTR pstrItemName,
+        LPCOLESTR pstrSubItemName, LPCOLESTR pstrEventName, LPCOLESTR pstrDelimiter,
+        CTXARG_T dwSourceContextCookie, ULONG ulStartingLineNumber, DWORD dwFlags,
+        BSTR *pbstrName, EXCEPINFO *pexcepinfo)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ActiveScriptParse_ParseScriptText(IActiveScriptParse *iface,
+        LPCOLESTR pstrCode, LPCOLESTR pstrItemName, IUnknown *punkContext,
+        LPCOLESTR pstrDelimiter, CTXARG_T dwSourceContextCookie, ULONG ulStartingLine,
+        DWORD dwFlags, VARIANT *pvarResult, EXCEPINFO *pexcepinfo)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static const IActiveScriptParseVtbl ActiveScriptParseVtbl = {
+    ActiveScriptParse_QueryInterface,
+    ActiveScriptParse_AddRef,
+    ActiveScriptParse_Release,
+    ActiveScriptParse_InitNew,
+    ActiveScriptParse_AddScriptlet,
+    ActiveScriptParse_ParseScriptText
+};
+
+static IActiveScriptParse ActiveScriptParse = { &ActiveScriptParseVtbl };
+
+static HRESULT WINAPI ObjectSafety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv)
+{
+    *ppv = NULL;
+    ok(0, "unexpected call %s\n", wine_dbgstr_guid(riid));
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI ObjectSafety_AddRef(IObjectSafety *iface)
+{
+    return 2;
+}
+
+static ULONG WINAPI ObjectSafety_Release(IObjectSafety *iface)
+{
+    return 1;
+}
+
+static HRESULT WINAPI ObjectSafety_GetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
+        DWORD *pdwSupportedOptions, DWORD *pdwEnabledOptions)
+{
+    ok(IsEqualGUID(&IID_IActiveScriptParse, riid), "unexpected riid %s\n", wine_dbgstr_guid(riid));
+    ok(pdwSupportedOptions != NULL, "pdwSupportedOptions == NULL\n");
+    ok(pdwEnabledOptions != NULL, "pdwEnabledOptions == NULL\n");
+
+    *pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_DISPEX|INTERFACE_USES_SECURITY_MANAGER;
+    *pdwEnabledOptions = INTERFACE_USES_DISPEX;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI ObjectSafety_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
+        DWORD mask, DWORD options)
+{
+    ok(IsEqualGUID(&IID_IActiveScriptParse, riid), "unexpected riid %s\n", wine_dbgstr_guid(riid));
+
+    ok(mask == INTERFACESAFE_FOR_UNTRUSTED_DATA, "option mask = %x\n", mask);
+    ok(options == 0, "options = %x\n", options);
+
+    return S_OK;
+}
+
+static const IObjectSafetyVtbl ObjectSafetyVtbl = {
+    ObjectSafety_QueryInterface,
+    ObjectSafety_AddRef,
+    ObjectSafety_Release,
+    ObjectSafety_GetInterfaceSafetyOptions,
+    ObjectSafety_SetInterfaceSafetyOptions
+};
+
+static IObjectSafety ObjectSafety = { &ObjectSafetyVtbl };
+
+static HRESULT WINAPI ActiveScript_QueryInterface(IActiveScript *iface, REFIID riid, void **ppv)
+{
+    *ppv = NULL;
+
+    if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IActiveScript, riid)) {
+        *ppv = iface;
+        return S_OK;
+    }
+
+    if(IsEqualGUID(&IID_IObjectSafety, riid)) {
+        *ppv = &ObjectSafety;
+        return S_OK;
+    }
+
+    if(IsEqualGUID(&IID_IActiveScriptParse, riid)) {
+        *ppv = &ActiveScriptParse;
+        return S_OK;
+    }
+
+    if(IsEqualGUID(&IID_IActiveScriptGarbageCollector, riid)) {
+        return E_NOINTERFACE;
+    }
+
+    ok(0, "unexpected riid %s\n", wine_dbgstr_guid(riid));
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI ActiveScript_AddRef(IActiveScript *iface)
+{
+    return 2;
+}
+
+static ULONG WINAPI ActiveScript_Release(IActiveScript *iface)
+{
+    return 1;
+}
+
+static HRESULT WINAPI ActiveScript_SetScriptSite(IActiveScript *iface, IActiveScriptSite *pass)
+{
+    IActiveScriptSiteInterruptPoll *poll;
+    IActiveScriptSiteDebug *debug;
+    IServiceProvider *service;
+    ICanHandleException *canexpection;
+    LCID lcid;
+    HRESULT hres;
+
+    ok(pass != NULL, "pass == NULL\n");
+
+    hres = IActiveScriptSite_QueryInterface(pass, &IID_IActiveScriptSiteInterruptPoll, (void**)&poll);
+    ok(hres == E_NOINTERFACE, "Could not get IActiveScriptSiteInterruptPoll interface: %08x\n", hres);
+
+    hres = IActiveScriptSite_GetLCID(pass, &lcid);
+    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);
+    ok(hres == E_NOINTERFACE, "Could not get IActiveScriptSiteDebug interface: %08x\n", hres);
+
+    hres = IActiveScriptSite_QueryInterface(pass, &IID_ICanHandleException, (void**)&canexpection);
+    ok(hres == E_NOINTERFACE, "Could not get IID_ICanHandleException interface: %08x\n", hres);
+
+    hres = IActiveScriptSite_QueryInterface(pass, &IID_IServiceProvider, (void**)&service);
+todo_wine
+    ok(hres == S_OK, "Could not get IServiceProvider interface: %08x\n", hres);
+    if(SUCCEEDED(hres))
+        IServiceProvider_Release(service);
+
+    site = pass;
+    IActiveScriptSite_AddRef(site);
+    return S_OK;
+}
+
+static HRESULT WINAPI ActiveScript_GetScriptSite(IActiveScript *iface, REFIID riid,
+                                            void **ppvObject)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ActiveScript_SetScriptState(IActiveScript *iface, SCRIPTSTATE ss)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ActiveScript_GetScriptState(IActiveScript *iface, SCRIPTSTATE *pssState)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ActiveScript_Close(IActiveScript *iface)
+{
+    return S_OK;
+}
+
+static HRESULT WINAPI ActiveScript_AddNamedItem(IActiveScript *iface,
+        LPCOLESTR pstrName, DWORD dwFlags)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ActiveScript_AddTypeLib(IActiveScript *iface, REFGUID rguidTypeLib,
+                                         DWORD dwMajor, DWORD dwMinor, DWORD dwFlags)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ActiveScript_GetScriptDispatch(IActiveScript *iface, LPCOLESTR pstrItemName,
+                                                IDispatch **ppdisp)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ActiveScript_GetCurrentScriptThreadID(IActiveScript *iface,
+                                                       SCRIPTTHREADID *pstridThread)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ActiveScript_GetScriptThreadID(IActiveScript *iface,
+                                                DWORD dwWin32ThreadId, SCRIPTTHREADID *pstidThread)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ActiveScript_GetScriptThreadState(IActiveScript *iface,
+        SCRIPTTHREADID stidThread, SCRIPTTHREADSTATE *pstsState)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ActiveScript_InterruptScriptThread(IActiveScript *iface,
+        SCRIPTTHREADID stidThread, const EXCEPINFO *pexcepinfo, DWORD dwFlags)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ActiveScript_Clone(IActiveScript *iface, IActiveScript **ppscript)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static const IActiveScriptVtbl ActiveScriptVtbl = {
+    ActiveScript_QueryInterface,
+    ActiveScript_AddRef,
+    ActiveScript_Release,
+    ActiveScript_SetScriptSite,
+    ActiveScript_GetScriptSite,
+    ActiveScript_SetScriptState,
+    ActiveScript_GetScriptState,
+    ActiveScript_Close,
+    ActiveScript_AddNamedItem,
+    ActiveScript_AddTypeLib,
+    ActiveScript_GetScriptDispatch,
+    ActiveScript_GetCurrentScriptThreadID,
+    ActiveScript_GetScriptThreadID,
+    ActiveScript_GetScriptThreadState,
+    ActiveScript_InterruptScriptThread,
+    ActiveScript_Clone
+};
+
+static IActiveScript ActiveScript = { &ActiveScriptVtbl };
+
+static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID riid, void **ppv)
+{
+    *ppv = NULL;
+
+    if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IClassFactory, riid)) {
+        *ppv = iface;
+        return S_OK;
+    }
+
+    if(IsEqualGUID(&IID_IMarshal, riid))
+        return E_NOINTERFACE;
+
+    ok(0, "unexpected riid %s\n", wine_dbgstr_guid(riid));
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI ClassFactory_AddRef(IClassFactory *iface)
+{
+    return 2;
+}
+
+static ULONG WINAPI ClassFactory_Release(IClassFactory *iface)
+{
+    return 1;
+}
+
+static HRESULT WINAPI ClassFactory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv)
+{
+    ok(!outer, "outer = %p\n", outer);
+    ok(IsEqualGUID(&IID_IActiveScript, riid), "unexpected riid %s\n", wine_dbgstr_guid(riid));
+    *ppv = &ActiveScript;
+    return S_OK;
+}
+
+static HRESULT WINAPI ClassFactory_LockServer(IClassFactory *iface, BOOL dolock)
+{
+    ok(0, "unexpected call\n");
+    return S_OK;
+}
+
+static const IClassFactoryVtbl ClassFactoryVtbl = {
+    ClassFactory_QueryInterface,
+    ClassFactory_AddRef,
+    ClassFactory_Release,
+    ClassFactory_CreateInstance,
+    ClassFactory_LockServer
+};
+
+static IClassFactory script_cf = { &ClassFactoryVtbl };
+
+static BOOL init_key(const char *key_name, const char *def_value, BOOL init)
+{
+    HKEY hkey;
+    DWORD res;
+
+    if(!init) {
+        RegDeleteKeyA(HKEY_CLASSES_ROOT, key_name);
+        return TRUE;
+    }
+
+    res = RegCreateKeyA(HKEY_CLASSES_ROOT, key_name, &hkey);
+    if(res != ERROR_SUCCESS)
+        return FALSE;
+
+    if(def_value)
+        res = RegSetValueA(hkey, NULL, REG_SZ, def_value, strlen(def_value));
+
+    RegCloseKey(hkey);
+
+    return res == ERROR_SUCCESS;
+}
+
+static BOOL init_registry(BOOL init)
+{
+    return init_key("TestScript\\CLSID", TESTSCRIPT_CLSID, init)
+        && init_key("CLSID\\"TESTSCRIPT_CLSID"\\Implemented Categories\\{F0B7A1A1-9847-11CF-8F20-00805F2CD064}",
+                    NULL, init)
+        && init_key("CLSID\\"TESTSCRIPT_CLSID"\\Implemented Categories\\{F0B7A1A2-9847-11CF-8F20-00805F2CD064}",
+                    NULL, init);
+}
+
+static BOOL register_script_engine(void)
+{
+    DWORD regid;
+    HRESULT hres;
+
+    if(!init_registry(TRUE)) {
+        init_registry(FALSE);
+        return FALSE;
+    }
+
+    hres = CoRegisterClassObject(&CLSID_TestScript, (IUnknown *)&script_cf,
+                                 CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &regid);
+    ok(hres == S_OK, "Could not register script engine: %08x\n", hres);
+
+    return TRUE;
+}
+
 static HRESULT WINAPI OleClientSite_QueryInterface(IOleClientSite *iface, REFIID riid, void **obj)
 {
     if (IsEqualIID(riid, &IID_IOleClientSite) || IsEqualIID(riid, &IID_IUnknown))
@@ -213,6 +614,92 @@ static void test_olecontrol(void)
     IOleControl_Release(olecontrol);
 }
 
+static void test_Language(void)
+{
+    static const WCHAR vbW[] = {'V','B','S','c','r','i','p','t',0};
+    static const WCHAR jsW[] = {'J','S','c','r','i','p','t',0};
+    static const WCHAR vb2W[] = {'v','B','s','c','r','i','p','t',0};
+    static const WCHAR dummyW[] = {'d','u','m','m','y',0};
+    IScriptControl *sc;
+    HRESULT hr;
+    BSTR str;
+
+    hr = CoCreateInstance(&CLSID_ScriptControl, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER,
+            &IID_IScriptControl, (void**)&sc);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+
+    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);
+    ok(str == NULL, "got %s\n", wine_dbgstr_w(str));
+
+    str = SysAllocString(vbW);
+    hr = IScriptControl_put_Language(sc, str);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+    SysFreeString(str);
+
+    str = SysAllocString(vb2W);
+    hr = IScriptControl_put_Language(sc, str);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+    SysFreeString(str);
+
+    hr = IScriptControl_get_Language(sc, &str);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+    ok(!lstrcmpW(str, vbW), "got %s\n", wine_dbgstr_w(str));
+    SysFreeString(str);
+
+    str = SysAllocString(dummyW);
+    hr = IScriptControl_put_Language(sc, str);
+    ok(hr == CTL_E_INVALIDPROPERTYVALUE, "got 0x%08x\n", hr);
+    SysFreeString(str);
+
+    hr = IScriptControl_get_Language(sc, &str);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+    ok(!lstrcmpW(str, vbW), "got %s\n", wine_dbgstr_w(str));
+    SysFreeString(str);
+
+    str = SysAllocString(jsW);
+    hr = IScriptControl_put_Language(sc, str);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+    SysFreeString(str);
+
+    hr = IScriptControl_get_Language(sc, &str);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+    ok(!lstrcmpW(str, jsW), "got %s\n", wine_dbgstr_w(str));
+    SysFreeString(str);
+
+    hr = IScriptControl_put_Language(sc, NULL);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+
+    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));
+
+    /* custom script engine */
+    if (register_script_engine()) {
+        static const WCHAR testscriptW[] = {'t','e','s','t','s','c','r','i','p','t',0};
+
+        str = SysAllocString(testscriptW);
+        hr = IScriptControl_put_Language(sc, str);
+        ok(hr == S_OK, "got 0x%08x\n", hr);
+        SysFreeString(str);
+
+        hr = IScriptControl_get_Language(sc, &str);
+        ok(hr == S_OK, "got 0x%08x\n", hr);
+        ok(!lstrcmpW(testscriptW, str), "%s\n", wine_dbgstr_w(str));
+        SysFreeString(str);
+
+        init_registry(FALSE);
+    }
+    else
+        skip("Could not register TestScript engine\n");
+
+    IScriptControl_Release(sc);
+}
+
 START_TEST(msscript)
 {
     IUnknown *unk;
@@ -231,6 +718,7 @@ START_TEST(msscript)
     test_oleobject();
     test_persiststreaminit();
     test_olecontrol();
+    test_Language();
 
     CoUninitialize();
 }
diff --git a/include/activscp.idl b/include/activscp.idl
index 8a3d75d..e539b04 100644
--- a/include/activscp.idl
+++ b/include/activscp.idl
@@ -71,6 +71,11 @@ typedef enum tagSCRIPTUICHANDLING {
     SCRIPTUICHANDLING_NOUIDEFAULT = 2
 } SCRIPTUICHANDLING;
 
+typedef enum tagSCRIPTGCTYPE {
+    SCRIPTGCTYPE_NORMAL     = 0,
+    SCRIPTGCTYPE_EXHAUSTIVE = 1
+} SCRIPTGCTYPE;
+
 typedef DWORD SCRIPTTHREADID;
 cpp_quote("#define SCRIPTTHREADID_CURRENT ((SCRIPTTHREADID)-1)")
 cpp_quote("#define SCRIPTTHREADID_BASE ((SCRIPTTHREADID)-2)")
@@ -551,3 +556,14 @@ interface IActiveScriptProperty : IUnknown
             [in] VARIANT *pvarIndex,
             [in] VARIANT *pvarValue);
 }
+
+[
+    object,
+    uuid(6aa2c4a0-2b53-11d4-a2a0-00104bd35090),
+    pointer_default(unique)
+]
+interface IActiveScriptGarbageCollector : IUnknown
+{
+    HRESULT CollectGarbage(
+            [in] SCRIPTGCTYPE gctype);
+}
-- 
2.8.1




More information about the wine-patches mailing list