Signed-off-by: Gabriel Ivăncescu gabrielopcode@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.
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);