[PATCH resend 03/13] msscript.ocx: Add initial IScriptModule stub implementation.

Gabriel Ivăncescu gabrielopcode at gmail.com
Tue May 26 07:41:57 CDT 2020


Signed-off-by: Gabriel Ivăncescu <gabrielopcode at gmail.com>
---

We have to treat a ref count of 0 in a special manner when they are linked
to the script control, because the modules must exist even when they have
no external refs (as the script control can still use them).

However, as evidenced by the tests, they must *not* keep a ref to the script
control in this case, as it would create a circular ref and make no sense,
anyway.

The alternative solution to allocate separate data for modules would
require copying the data to multiple places (one for Module Collection,
and one for orphaned Modules) which is more complicated, in my opinion.

 dlls/msscript.ocx/msscript.c | 279 ++++++++++++++++++++++++++++++++++-
 1 file changed, 277 insertions(+), 2 deletions(-)

diff --git a/dlls/msscript.ocx/msscript.c b/dlls/msscript.ocx/msscript.c
index 7a18a84..6bf41ff 100644
--- a/dlls/msscript.ocx/msscript.c
+++ b/dlls/msscript.ocx/msscript.c
@@ -65,6 +65,14 @@ struct named_item {
     IDispatch *disp;
 };
 
+typedef struct ScriptModule {
+    IScriptModule IScriptModule_iface;
+    LONG ref;
+
+    BSTR name;
+    ScriptControl *control;
+} ScriptModule;
+
 typedef struct ScriptHost {
     IActiveScriptSite IActiveScriptSite_iface;
     IActiveScriptSiteWindow IActiveScriptSiteWindow_iface;
@@ -107,6 +115,8 @@ struct ScriptControl {
     DWORD view_sink_flags;
 
     /* modules */
+    UINT num_modules;
+    ScriptModule **modules;
     IScriptModuleCollection IScriptModuleCollection_iface;
 
     ScriptHost *host;
@@ -117,6 +127,7 @@ static HINSTANCE msscript_instance;
 typedef enum tid_t {
     IScriptControl_tid,
     IScriptModuleCollection_tid,
+    IScriptModule_tid,
     LAST_tid
 } tid_t;
 
@@ -126,6 +137,7 @@ static ITypeInfo *typeinfos[LAST_tid];
 static REFIID tid_ids[] = {
     &IID_IScriptControl,
     &IID_IScriptModuleCollection,
+    &IID_IScriptModule
 };
 
 static HRESULT load_typelib(void)
@@ -301,6 +313,11 @@ static inline ScriptControl *impl_from_IScriptModuleCollection(IScriptModuleColl
     return CONTAINING_RECORD(iface, ScriptControl, IScriptModuleCollection_iface);
 }
 
+static inline ScriptModule *impl_from_IScriptModule(IScriptModule *iface)
+{
+    return CONTAINING_RECORD(iface, ScriptModule, IScriptModule_iface);
+}
+
 static inline ConnectionPoint *impl_from_IConnectionPoint(IConnectionPoint *iface)
 {
     return CONTAINING_RECORD(iface, ConnectionPoint, IConnectionPoint_iface);
@@ -575,6 +592,242 @@ static const IServiceProviderVtbl ServiceProviderVtbl = {
     ServiceProvider_QueryService
 };
 
+static void destroy_module(ScriptModule *module)
+{
+    SysFreeString(module->name);
+    heap_free(module);
+}
+
+static void release_modules(ScriptControl *control)
+{
+    UINT i = control->num_modules - 1;
+
+    if (!control->modules) return;
+    do
+    {
+        /* Unlink it from the script control if it's held */
+        if (control->modules[i]->ref)
+        {
+            control->modules[i]->control = NULL;
+            IScriptControl_Release(&control->IScriptControl_iface);
+        }
+        else
+            destroy_module(control->modules[i]);
+    } while (i--);
+
+    heap_free(control->modules);
+}
+
+static HRESULT WINAPI ScriptModule_QueryInterface(IScriptModule *iface, REFIID riid, void **ppv)
+{
+    ScriptModule *This = impl_from_IScriptModule(iface);
+
+    if (IsEqualGUID(&IID_IDispatch, riid) || IsEqualGUID(&IID_IUnknown, riid) ||
+        IsEqualGUID(&IID_IScriptModule, riid))
+    {
+        *ppv = &This->IScriptModule_iface;
+    }
+    else
+    {
+        WARN("unsupported interface: (%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
+        *ppv = NULL;
+        return E_NOINTERFACE;
+    }
+
+    IUnknown_AddRef((IUnknown*)*ppv);
+    return S_OK;
+}
+
+static ULONG WINAPI ScriptModule_AddRef(IScriptModule *iface)
+{
+    ScriptModule *This = impl_from_IScriptModule(iface);
+    LONG ref = InterlockedIncrement(&This->ref);
+
+    TRACE("(%p) ref=%d\n", This, ref);
+
+    if (ref == 1)
+        IScriptControl_AddRef(&This->control->IScriptControl_iface);
+
+    return ref;
+}
+
+static ULONG WINAPI ScriptModule_Release(IScriptModule *iface)
+{
+    ScriptModule *This = impl_from_IScriptModule(iface);
+    LONG ref = InterlockedDecrement(&This->ref);
+
+    TRACE("(%p) ref=%d\n", This, ref);
+
+    if (!ref)
+    {
+        if (This->control)
+            IScriptControl_Release(&This->control->IScriptControl_iface);
+        else
+            destroy_module(This);
+    }
+
+    return ref;
+}
+
+static HRESULT WINAPI ScriptModule_GetTypeInfoCount(IScriptModule *iface, UINT *pctinfo)
+{
+    ScriptModule *This = impl_from_IScriptModule(iface);
+
+    TRACE("(%p)->(%p)\n", This, pctinfo);
+
+    *pctinfo = 1;
+    return S_OK;
+}
+
+static HRESULT WINAPI ScriptModule_GetTypeInfo(IScriptModule *iface, UINT iTInfo,
+        LCID lcid, ITypeInfo **ppTInfo)
+{
+    ScriptModule *This = impl_from_IScriptModule(iface);
+
+    TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
+
+    return get_typeinfo(IScriptModule_tid, ppTInfo);
+}
+
+static HRESULT WINAPI ScriptModule_GetIDsOfNames(IScriptModule *iface, REFIID riid,
+        LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
+{
+    ScriptModule *This = impl_from_IScriptModule(iface);
+    ITypeInfo *typeinfo;
+    HRESULT hr;
+
+    TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
+
+    hr = get_typeinfo(IScriptModule_tid, &typeinfo);
+    if (SUCCEEDED(hr))
+    {
+        hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
+        ITypeInfo_Release(typeinfo);
+    }
+
+    return hr;
+}
+
+static HRESULT WINAPI ScriptModule_Invoke(IScriptModule *iface, DISPID dispIdMember,
+        REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult,
+        EXCEPINFO *pExcepInfo, UINT *puArgErr)
+{
+    ScriptModule *This = impl_from_IScriptModule(iface);
+    ITypeInfo *typeinfo;
+    HRESULT hr;
+
+    TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
+           lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
+
+    hr = get_typeinfo(IScriptModule_tid, &typeinfo);
+    if(SUCCEEDED(hr))
+    {
+        hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
+                              pDispParams, pVarResult, pExcepInfo, puArgErr);
+        ITypeInfo_Release(typeinfo);
+    }
+
+    return hr;
+}
+
+static HRESULT WINAPI ScriptModule_get_Name(IScriptModule *iface, BSTR *pbstrName)
+{
+    ScriptModule *This = impl_from_IScriptModule(iface);
+
+    FIXME("(%p)->(%p)\n", This, pbstrName);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ScriptModule_get_CodeObject(IScriptModule *iface, IDispatch **ppdispObject)
+{
+    ScriptModule *This = impl_from_IScriptModule(iface);
+
+    FIXME("(%p)->(%p)\n", This, ppdispObject);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ScriptModule_get_Procedures(IScriptModule *iface, IScriptProcedureCollection **ppdispProcedures)
+{
+    ScriptModule *This = impl_from_IScriptModule(iface);
+
+    FIXME("(%p)->(%p)\n", This, ppdispProcedures);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ScriptModule_AddCode(IScriptModule *iface, BSTR code)
+{
+    ScriptModule *This = impl_from_IScriptModule(iface);
+
+    FIXME("(%p)->(%s)\n", This, debugstr_w(code));
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ScriptModule_Eval(IScriptModule *iface, BSTR expression, VARIANT *res)
+{
+    ScriptModule *This = impl_from_IScriptModule(iface);
+
+    FIXME("(%p)->(%s, %p)\n", This, debugstr_w(expression), res);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ScriptModule_ExecuteStatement(IScriptModule *iface, BSTR statement)
+{
+    ScriptModule *This = impl_from_IScriptModule(iface);
+
+    FIXME("(%p)->(%s)\n", This, debugstr_w(statement));
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ScriptModule_Run(IScriptModule *iface, BSTR procedure_name, SAFEARRAY **parameters, VARIANT *res)
+{
+    ScriptModule *This = impl_from_IScriptModule(iface);
+
+    FIXME("(%p)->(%s %p %p)\n", This, debugstr_w(procedure_name), parameters, res);
+
+    return E_NOTIMPL;
+}
+
+static const IScriptModuleVtbl ScriptModuleVtbl = {
+    ScriptModule_QueryInterface,
+    ScriptModule_AddRef,
+    ScriptModule_Release,
+    ScriptModule_GetTypeInfoCount,
+    ScriptModule_GetTypeInfo,
+    ScriptModule_GetIDsOfNames,
+    ScriptModule_Invoke,
+    ScriptModule_get_Name,
+    ScriptModule_get_CodeObject,
+    ScriptModule_get_Procedures,
+    ScriptModule_AddCode,
+    ScriptModule_Eval,
+    ScriptModule_ExecuteStatement,
+    ScriptModule_Run
+};
+
+static ScriptModule *alloc_module(ScriptControl *control, BSTR name)
+{
+    ScriptModule *module = heap_alloc_zero(sizeof(*module));
+
+    if (!module) return NULL;
+    if (name && !(module->name = SysAllocString(name)))
+    {
+        heap_free(module);
+        return NULL;
+    }
+
+    /* Don't keep a ref unless it's externally held, to match Windows behavior */
+    module->IScriptModule_iface.lpVtbl = &ScriptModuleVtbl;
+    module->control = control;
+
+    return module;
+}
+
 static HRESULT WINAPI ScriptModuleCollection_QueryInterface(IScriptModuleCollection *iface, REFIID riid, void **ppv)
 {
     ScriptControl *This = impl_from_IScriptModuleCollection(iface);
@@ -691,9 +944,12 @@ static HRESULT WINAPI ScriptModuleCollection_get_Count(IScriptModuleCollection *
 {
     ScriptControl *This = impl_from_IScriptModuleCollection(iface);
 
-    FIXME("(%p)->(%p)\n", This, plCount);
+    TRACE("(%p)->(%p)\n", This, plCount);
 
-    return E_NOTIMPL;
+    if (!plCount) return E_POINTER;
+
+    *plCount = This->num_modules;
+    return S_OK;
 }
 
 static HRESULT WINAPI ScriptModuleCollection_Add(IScriptModuleCollection *iface, BSTR name,
@@ -864,6 +1120,7 @@ static ULONG WINAPI ScriptControl_Release(IScriptControl *iface)
             IOleClientSite_Release(This->site);
         if (This->host)
             release_script_engine(This->host);
+        release_modules(This);
         heap_free(This);
     }
 
@@ -965,6 +1222,21 @@ static HRESULT WINAPI ScriptControl_put_Language(IScriptControl *iface, BSTR lan
         This->host = NULL;
     }
 
+    release_modules(This);
+
+    /* Alloc the global module */
+    This->modules = heap_alloc(sizeof(*This->modules));
+    if (!This->modules) return E_OUTOFMEMORY;
+
+    This->modules[0] = alloc_module(This, NULL);
+    if (!This->modules[0])
+    {
+        heap_free(This->modules);
+        This->modules = NULL;
+        return E_OUTOFMEMORY;
+    }
+    This->num_modules = 1;
+
     if (!language)
         return S_OK;
 
@@ -1094,6 +1366,8 @@ static HRESULT WINAPI ScriptControl_get_Modules(IScriptControl *iface, IScriptMo
 
     TRACE("(%p)->(%p)\n", This, p);
 
+    if (!This->modules) return E_FAIL;
+
     *p = &This->IScriptModuleCollection_iface;
     IScriptControl_AddRef(iface);
     return S_OK;
@@ -2201,6 +2475,7 @@ static HRESULT WINAPI ScriptControl_CreateInstance(IClassFactory *iface, IUnknow
     script_control->allow_ui = VARIANT_TRUE;
     script_control->use_safe_subset = VARIANT_FALSE;
     script_control->state = Initialized;
+    script_control->modules = NULL;
 
     ConnectionPoint_Init(&script_control->cp_scsource, script_control, &DIID_DScriptControlSource);
     ConnectionPoint_Init(&script_control->cp_propnotif, script_control, &IID_IPropertyNotifySink);
-- 
2.21.0




More information about the wine-devel mailing list