Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com ---
So it's near the other helpers and will be needed for later patches in the series.
dlls/msscript.ocx/msscript.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-)
diff --git a/dlls/msscript.ocx/msscript.c b/dlls/msscript.ocx/msscript.c index c4c6485..6d098cd 100644 --- a/dlls/msscript.ocx/msscript.c +++ b/dlls/msscript.ocx/msscript.c @@ -237,6 +237,20 @@ static HRESULT start_script(struct ScriptControl *control) return hr; }
+static HRESULT parse_script_text(ScriptControl *control, BSTR script_text, DWORD flag, VARIANT *res) +{ + EXCEPINFO excepinfo; + HRESULT hr; + + hr = start_script(control); + if (FAILED(hr)) return hr; + + hr = IActiveScriptParse_ParseScriptText(control->host->parse, script_text, NULL, + NULL, NULL, 0, 1, flag, res, &excepinfo); + /* FIXME: more error handling */ + return hr; +} + static inline ScriptControl *impl_from_IScriptControl(IScriptControl *iface) { return CONTAINING_RECORD(iface, ScriptControl, IScriptControl_iface); @@ -1008,20 +1022,6 @@ static HRESULT WINAPI ScriptControl_Reset(IScriptControl *iface) return set_script_state(This->host, SCRIPTSTATE_INITIALIZED); }
-static HRESULT parse_script_text(ScriptControl *control, BSTR script_text, DWORD flag, VARIANT *res) -{ - EXCEPINFO excepinfo; - HRESULT hr; - - hr = start_script(control); - if (FAILED(hr)) return hr; - - hr = IActiveScriptParse_ParseScriptText(control->host->parse, script_text, NULL, - NULL, NULL, 0, 1, flag, res, &excepinfo); - /* FIXME: more error handling */ - return hr; -} - static HRESULT WINAPI ScriptControl_AddCode(IScriptControl *iface, BSTR code) { ScriptControl *This = impl_from_IScriptControl(iface);
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/msscript.ocx/msscript.c | 166 ++++++++++++++++++++++++++++++++++- 1 file changed, 163 insertions(+), 3 deletions(-)
diff --git a/dlls/msscript.ocx/msscript.c b/dlls/msscript.ocx/msscript.c index 6d098cd..7a18a84 100644 --- a/dlls/msscript.ocx/msscript.c +++ b/dlls/msscript.ocx/msscript.c @@ -106,6 +106,9 @@ struct ScriptControl { IAdviseSink *view_sink; DWORD view_sink_flags;
+ /* modules */ + IScriptModuleCollection IScriptModuleCollection_iface; + ScriptHost *host; };
@@ -113,6 +116,7 @@ static HINSTANCE msscript_instance;
typedef enum tid_t { IScriptControl_tid, + IScriptModuleCollection_tid, LAST_tid } tid_t;
@@ -120,7 +124,8 @@ static ITypeLib *typelib; static ITypeInfo *typeinfos[LAST_tid];
static REFIID tid_ids[] = { - &IID_IScriptControl + &IID_IScriptControl, + &IID_IScriptModuleCollection, };
static HRESULT load_typelib(void) @@ -291,6 +296,11 @@ static inline ScriptControl *impl_from_IConnectionPointContainer(IConnectionPoin return CONTAINING_RECORD(iface, ScriptControl, IConnectionPointContainer_iface); }
+static inline ScriptControl *impl_from_IScriptModuleCollection(IScriptModuleCollection *iface) +{ + return CONTAINING_RECORD(iface, ScriptControl, IScriptModuleCollection_iface); +} + static inline ConnectionPoint *impl_from_IConnectionPoint(IConnectionPoint *iface) { return CONTAINING_RECORD(iface, ConnectionPoint, IConnectionPoint_iface); @@ -565,6 +575,151 @@ static const IServiceProviderVtbl ServiceProviderVtbl = { ServiceProvider_QueryService };
+static HRESULT WINAPI ScriptModuleCollection_QueryInterface(IScriptModuleCollection *iface, REFIID riid, void **ppv) +{ + ScriptControl *This = impl_from_IScriptModuleCollection(iface); + + if (IsEqualGUID(&IID_IDispatch, riid) || IsEqualGUID(&IID_IUnknown, riid) || + IsEqualGUID(&IID_IScriptModuleCollection, riid)) + { + *ppv = &This->IScriptModuleCollection_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 ScriptModuleCollection_AddRef(IScriptModuleCollection *iface) +{ + ScriptControl *This = impl_from_IScriptModuleCollection(iface); + return IScriptControl_AddRef(&This->IScriptControl_iface); +} + +static ULONG WINAPI ScriptModuleCollection_Release(IScriptModuleCollection *iface) +{ + ScriptControl *This = impl_from_IScriptModuleCollection(iface); + return IScriptControl_Release(&This->IScriptControl_iface); +} + +static HRESULT WINAPI ScriptModuleCollection_GetTypeInfoCount(IScriptModuleCollection *iface, UINT *pctinfo) +{ + ScriptControl *This = impl_from_IScriptModuleCollection(iface); + + TRACE("(%p)->(%p)\n", This, pctinfo); + + *pctinfo = 1; + return S_OK; +} + +static HRESULT WINAPI ScriptModuleCollection_GetTypeInfo(IScriptModuleCollection *iface, UINT iTInfo, + LCID lcid, ITypeInfo **ppTInfo) +{ + ScriptControl *This = impl_from_IScriptModuleCollection(iface); + + TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo); + + return get_typeinfo(IScriptModuleCollection_tid, ppTInfo); +} + +static HRESULT WINAPI ScriptModuleCollection_GetIDsOfNames(IScriptModuleCollection *iface, REFIID riid, + LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId) +{ + ScriptControl *This = impl_from_IScriptModuleCollection(iface); + ITypeInfo *typeinfo; + HRESULT hr; + + TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId); + + hr = get_typeinfo(IScriptModuleCollection_tid, &typeinfo); + if (SUCCEEDED(hr)) + { + hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId); + ITypeInfo_Release(typeinfo); + } + + return hr; +} + +static HRESULT WINAPI ScriptModuleCollection_Invoke(IScriptModuleCollection *iface, DISPID dispIdMember, + REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, + EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + ScriptControl *This = impl_from_IScriptModuleCollection(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(IScriptModuleCollection_tid, &typeinfo); + if(SUCCEEDED(hr)) + { + hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags, + pDispParams, pVarResult, pExcepInfo, puArgErr); + ITypeInfo_Release(typeinfo); + } + + return hr; +} + +static HRESULT WINAPI ScriptModuleCollection_get__NewEnum(IScriptModuleCollection *iface, IUnknown **ppenumContexts) +{ + ScriptControl *This = impl_from_IScriptModuleCollection(iface); + + FIXME("(%p)->(%p)\n", This, ppenumContexts); + + return E_NOTIMPL; +} + +static HRESULT WINAPI ScriptModuleCollection_get_Item(IScriptModuleCollection *iface, VARIANT index, + IScriptModule **ppmod) +{ + ScriptControl *This = impl_from_IScriptModuleCollection(iface); + + FIXME("(%p)->(%s %p)\n", This, wine_dbgstr_variant(&index), ppmod); + + return E_NOTIMPL; +} + +static HRESULT WINAPI ScriptModuleCollection_get_Count(IScriptModuleCollection *iface, LONG *plCount) +{ + ScriptControl *This = impl_from_IScriptModuleCollection(iface); + + FIXME("(%p)->(%p)\n", This, plCount); + + return E_NOTIMPL; +} + +static HRESULT WINAPI ScriptModuleCollection_Add(IScriptModuleCollection *iface, BSTR name, + VARIANT *object, IScriptModule **ppmod) +{ + ScriptControl *This = impl_from_IScriptModuleCollection(iface); + + FIXME("(%p)->(%s %s %p)\n", This, wine_dbgstr_w(name), wine_dbgstr_variant(object), ppmod); + + return E_NOTIMPL; +} + +static const IScriptModuleCollectionVtbl ScriptModuleCollectionVtbl = { + ScriptModuleCollection_QueryInterface, + ScriptModuleCollection_AddRef, + ScriptModuleCollection_Release, + ScriptModuleCollection_GetTypeInfoCount, + ScriptModuleCollection_GetTypeInfo, + ScriptModuleCollection_GetIDsOfNames, + ScriptModuleCollection_Invoke, + ScriptModuleCollection_get__NewEnum, + ScriptModuleCollection_get_Item, + ScriptModuleCollection_get_Count, + ScriptModuleCollection_Add +}; + static HRESULT init_script_host(const CLSID *clsid, ScriptHost **ret) { IObjectSafety *objsafety; @@ -936,8 +1091,12 @@ static HRESULT WINAPI ScriptControl_put_UseSafeSubset(IScriptControl *iface, VAR static HRESULT WINAPI ScriptControl_get_Modules(IScriptControl *iface, IScriptModuleCollection **p) { ScriptControl *This = impl_from_IScriptControl(iface); - FIXME("(%p)->(%p)\n", This, p); - return E_NOTIMPL; + + TRACE("(%p)->(%p)\n", This, p); + + *p = &This->IScriptModuleCollection_iface; + IScriptControl_AddRef(iface); + return S_OK; }
static HRESULT WINAPI ScriptControl_get_Error(IScriptControl *iface, IScriptError **p) @@ -2031,6 +2190,7 @@ static HRESULT WINAPI ScriptControl_CreateInstance(IClassFactory *iface, IUnknow script_control->IViewObjectEx_iface.lpVtbl = &ViewObjectExVtbl; script_control->IPointerInactive_iface.lpVtbl = &PointerInactiveVtbl; script_control->IConnectionPointContainer_iface.lpVtbl = &ConnectionPointContainerVtbl; + script_control->IScriptModuleCollection_iface.lpVtbl = &ScriptModuleCollectionVtbl; script_control->ref = 1; script_control->site = NULL; script_control->cp_list = NULL;
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);
On 4/9/20 5:34 PM, Gabriel Ivăncescu wrote:
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.
An alternative to that is to separate actual data of such script_module, using separate refcount, and IScriptModule accessor object.
On 09/04/2020 23:27, Nikolay Sivov wrote:
On 4/9/20 5:34 PM, Gabriel Ivăncescu wrote:
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.
An alternative to that is to separate actual data of such script_module, using separate refcount, and IScriptModule accessor object.
Sorry, I completely missed this reply earlier for some reason...
But, wouldn't this alternative require that we duplicate the module's data? Let's look at the module's name: it's required both by the Module Collection (to retrieve a module, or add one without conflict) and by an individual Module interface (since it can be orphaned, see put_Language which releases the modules from the Script Control).
Obviously, it's possible that no module is held externally and we only query for module names using the Module Collection. In this case, the module must *not* hold a ref to the Script Control, hence the hold trick.
However, if a module is retrieved, then the module data would have to be duplicated/allocated in a different spot, and refcount to the Script Control added, since it's now externally held with a refcount of 1.
It's, IMO, way more complicated than the current approach.
Thanks, Gabriel
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/msscript.ocx/msscript.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/dlls/msscript.ocx/msscript.c b/dlls/msscript.ocx/msscript.c index 6bf41ff..91e6dfa 100644 --- a/dlls/msscript.ocx/msscript.c +++ b/dlls/msscript.ocx/msscript.c @@ -71,6 +71,7 @@ typedef struct ScriptModule {
BSTR name; ScriptControl *control; + IDispatch *script_dispatch; } ScriptModule;
typedef struct ScriptHost { @@ -81,7 +82,6 @@ typedef struct ScriptHost {
IActiveScript *script; IActiveScriptParse *parse; - IDispatch *script_dispatch; SCRIPTSTATE script_state; CLSID clsid;
@@ -220,14 +220,15 @@ static struct named_item *host_get_named_item(ScriptHost *host, const WCHAR *nam return NULL; }
-static HRESULT get_script_dispatch(struct ScriptControl *control, IDispatch **disp) +static HRESULT get_script_dispatch(ScriptModule *module, IDispatch **disp) { - if (!control->host->script_dispatch) + if (!module->script_dispatch) { - HRESULT hr = IActiveScript_GetScriptDispatch(control->host->script, NULL, &control->host->script_dispatch); + HRESULT hr = IActiveScript_GetScriptDispatch(module->control->host->script, + module->name, &module->script_dispatch); if (FAILED(hr)) return hr; } - *disp = control->host->script_dispatch; + *disp = module->script_dispatch; return S_OK; }
@@ -384,10 +385,7 @@ static void release_script_engine(ScriptHost *host)
if (host->parse) IActiveScriptParse_Release(host->parse); - if (host->script_dispatch) - IDispatch_Release(host->script_dispatch);
- host->script_dispatch = NULL; host->parse = NULL; host->script = NULL;
@@ -594,6 +592,8 @@ static const IServiceProviderVtbl ServiceProviderVtbl = {
static void destroy_module(ScriptModule *module) { + if (module->script_dispatch) + IDispatch_Release(module->script_dispatch); SysFreeString(module->name); heap_free(module); } @@ -994,7 +994,6 @@ static HRESULT init_script_host(const CLSID *clsid, ScriptHost **ret) host->ref = 1; host->script = NULL; host->parse = NULL; - host->script_dispatch = NULL; host->clsid = *clsid; list_init(&host->named_items);
@@ -1505,11 +1504,12 @@ static HRESULT WINAPI ScriptControl_Run(IScriptControl *iface, BSTR procedure_na V_VT(res) = VT_EMPTY; if (sa->cDims == 0) return DISP_E_BADINDEX; if (!(sa->fFeatures & FADF_VARIANT)) return DISP_E_BADVARTYPE; + if (!This->modules) return E_FAIL;
hr = start_script(This); if (FAILED(hr)) return hr;
- hr = get_script_dispatch(This, &disp); + hr = get_script_dispatch(This->modules[0], &disp); if (FAILED(hr)) return hr;
hr = IDispatch_GetIDsOfNames(disp, &IID_NULL, &procedure_name, 1, LOCALE_USER_DEFAULT, &dispid);
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/msscript.ocx/msscript.c | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-)
diff --git a/dlls/msscript.ocx/msscript.c b/dlls/msscript.ocx/msscript.c index 91e6dfa..393f39e 100644 --- a/dlls/msscript.ocx/msscript.c +++ b/dlls/msscript.ocx/msscript.c @@ -255,15 +255,17 @@ static HRESULT start_script(struct ScriptControl *control) return hr; }
-static HRESULT parse_script_text(ScriptControl *control, BSTR script_text, DWORD flag, VARIANT *res) +static HRESULT parse_script_text(ScriptModule *module, BSTR script_text, DWORD flag, VARIANT *res) { EXCEPINFO excepinfo; HRESULT hr;
- hr = start_script(control); + if (!module->control) return E_FAIL; + + hr = start_script(module->control); if (FAILED(hr)) return hr;
- hr = IActiveScriptParse_ParseScriptText(control->host->parse, script_text, NULL, + hr = IActiveScriptParse_ParseScriptText(module->control->host->parse, script_text, module->name, NULL, NULL, 0, 1, flag, res, &excepinfo); /* FIXME: more error handling */ return hr; @@ -761,27 +763,31 @@ static HRESULT WINAPI ScriptModule_AddCode(IScriptModule *iface, BSTR code) { ScriptModule *This = impl_from_IScriptModule(iface);
- FIXME("(%p)->(%s)\n", This, debugstr_w(code)); + TRACE("(%p)->(%s)\n", This, debugstr_w(code));
- return E_NOTIMPL; + return parse_script_text(This, code, SCRIPTTEXT_ISVISIBLE, NULL); }
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); + TRACE("(%p)->(%s, %p)\n", This, debugstr_w(expression), res);
- return E_NOTIMPL; + if (!res) + return E_POINTER; + V_VT(res) = VT_EMPTY; + + return parse_script_text(This, expression, SCRIPTTEXT_ISEXPRESSION, res); }
static HRESULT WINAPI ScriptModule_ExecuteStatement(IScriptModule *iface, BSTR statement) { ScriptModule *This = impl_from_IScriptModule(iface);
- FIXME("(%p)->(%s)\n", This, debugstr_w(statement)); + TRACE("(%p)->(%s)\n", This, debugstr_w(statement));
- return E_NOTIMPL; + return parse_script_text(This, statement, 0, NULL); }
static HRESULT WINAPI ScriptModule_Run(IScriptModule *iface, BSTR procedure_name, SAFEARRAY **parameters, VARIANT *res) @@ -1460,7 +1466,9 @@ static HRESULT WINAPI ScriptControl_AddCode(IScriptControl *iface, BSTR code)
TRACE("(%p)->(%s).\n", This, debugstr_w(code));
- return parse_script_text(This, code, SCRIPTTEXT_ISVISIBLE, NULL); + if (!This->modules) + return E_FAIL; + return parse_script_text(This->modules[0], code, SCRIPTTEXT_ISVISIBLE, NULL); }
static HRESULT WINAPI ScriptControl_Eval(IScriptControl *iface, BSTR expression, VARIANT *res) @@ -1473,7 +1481,9 @@ static HRESULT WINAPI ScriptControl_Eval(IScriptControl *iface, BSTR expression, return E_POINTER; V_VT(res) = VT_EMPTY;
- return parse_script_text(This, expression, SCRIPTTEXT_ISEXPRESSION, res); + if (!This->modules) + return E_FAIL; + return parse_script_text(This->modules[0], expression, SCRIPTTEXT_ISEXPRESSION, res); }
static HRESULT WINAPI ScriptControl_ExecuteStatement(IScriptControl *iface, BSTR statement) @@ -1482,7 +1492,9 @@ static HRESULT WINAPI ScriptControl_ExecuteStatement(IScriptControl *iface, BSTR
TRACE("(%p)->(%s)\n", This, debugstr_w(statement));
- return parse_script_text(This, statement, 0, NULL); + if (!This->modules) + return E_FAIL; + return parse_script_text(This->modules[0], statement, 0, NULL); }
static HRESULT WINAPI ScriptControl_Run(IScriptControl *iface, BSTR procedure_name, SAFEARRAY **parameters, VARIANT *res)
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/msscript.ocx/msscript.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/dlls/msscript.ocx/msscript.c b/dlls/msscript.ocx/msscript.c index 393f39e..3cb0215 100644 --- a/dlls/msscript.ocx/msscript.c +++ b/dlls/msscript.ocx/msscript.c @@ -736,9 +736,13 @@ static HRESULT WINAPI ScriptModule_get_Name(IScriptModule *iface, BSTR *pbstrNam { ScriptModule *This = impl_from_IScriptModule(iface);
- FIXME("(%p)->(%p)\n", This, pbstrName); + TRACE("(%p)->(%p)\n", This, pbstrName);
- return E_NOTIMPL; + if (!pbstrName) return E_POINTER; + if (!This->control) return E_FAIL; + + *pbstrName = SysAllocString(This->name ? This->name : L"Global"); + return *pbstrName ? S_OK : E_OUTOFMEMORY; }
static HRESULT WINAPI ScriptModule_get_CodeObject(IScriptModule *iface, IDispatch **ppdispObject)
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/msscript.ocx/msscript.c | 96 +++++++++++++++++++----------------- 1 file changed, 51 insertions(+), 45 deletions(-)
diff --git a/dlls/msscript.ocx/msscript.c b/dlls/msscript.ocx/msscript.c index 3cb0215..3cbc7a4 100644 --- a/dlls/msscript.ocx/msscript.c +++ b/dlls/msscript.ocx/msscript.c @@ -271,6 +271,56 @@ static HRESULT parse_script_text(ScriptModule *module, BSTR script_text, DWORD f return hr; }
+static HRESULT run_procedure(ScriptModule *module, BSTR procedure_name, SAFEARRAY *args, VARIANT *res) +{ + IDispatchEx *dispex; + IDispatch *disp; + DISPPARAMS dp; + DISPID dispid; + HRESULT hr; + UINT i; + + hr = start_script(module->control); + if (FAILED(hr)) return hr; + + hr = get_script_dispatch(module, &disp); + if (FAILED(hr)) return hr; + + hr = IDispatch_GetIDsOfNames(disp, &IID_NULL, &procedure_name, 1, LOCALE_USER_DEFAULT, &dispid); + if (FAILED(hr)) return hr; + + dp.cArgs = args->rgsabound[0].cElements; + dp.rgdispidNamedArgs = NULL; + dp.cNamedArgs = 0; + dp.rgvarg = heap_alloc(dp.cArgs * sizeof(*dp.rgvarg)); + if (!dp.rgvarg) return E_OUTOFMEMORY; + + hr = SafeArrayLock(args); + if (SUCCEEDED(hr)) + { + /* The DISPPARAMS are stored in reverse order */ + for (i = 0; i < dp.cArgs; i++) + dp.rgvarg[i] = *(VARIANT*)((char*)(args->pvData) + (dp.cArgs - i - 1) * args->cbElements); + SafeArrayUnlock(args); + + hr = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex); + if (FAILED(hr)) + { + hr = IDispatch_Invoke(disp, dispid, &IID_NULL, LOCALE_USER_DEFAULT, + DISPATCH_METHOD, &dp, res, NULL, NULL); + } + else + { + hr = IDispatchEx_InvokeEx(dispex, dispid, LOCALE_USER_DEFAULT, + DISPATCH_METHOD, &dp, res, NULL, NULL); + IDispatchEx_Release(dispex); + } + } + heap_free(dp.rgvarg); + + return hr; +} + static inline ScriptControl *impl_from_IScriptControl(IScriptControl *iface) { return CONTAINING_RECORD(iface, ScriptControl, IScriptControl_iface); @@ -1504,13 +1554,7 @@ static HRESULT WINAPI ScriptControl_ExecuteStatement(IScriptControl *iface, BSTR static HRESULT WINAPI ScriptControl_Run(IScriptControl *iface, BSTR procedure_name, SAFEARRAY **parameters, VARIANT *res) { ScriptControl *This = impl_from_IScriptControl(iface); - IDispatchEx *dispex; - IDispatch *disp; SAFEARRAY *sa; - DISPPARAMS dp; - DISPID dispid; - HRESULT hr; - UINT i;
TRACE("(%p)->(%s %p %p)\n", This, debugstr_w(procedure_name), parameters, res);
@@ -1522,45 +1566,7 @@ static HRESULT WINAPI ScriptControl_Run(IScriptControl *iface, BSTR procedure_na if (!(sa->fFeatures & FADF_VARIANT)) return DISP_E_BADVARTYPE; if (!This->modules) return E_FAIL;
- hr = start_script(This); - if (FAILED(hr)) return hr; - - hr = get_script_dispatch(This->modules[0], &disp); - if (FAILED(hr)) return hr; - - hr = IDispatch_GetIDsOfNames(disp, &IID_NULL, &procedure_name, 1, LOCALE_USER_DEFAULT, &dispid); - if (FAILED(hr)) return hr; - - dp.cArgs = sa->rgsabound[0].cElements; - dp.rgdispidNamedArgs = NULL; - dp.cNamedArgs = 0; - dp.rgvarg = heap_alloc(dp.cArgs * sizeof(*dp.rgvarg)); - if (!dp.rgvarg) return E_OUTOFMEMORY; - - hr = SafeArrayLock(sa); - if (SUCCEEDED(hr)) - { - /* The DISPPARAMS are stored in reverse order */ - for (i = 0; i < dp.cArgs; i++) - dp.rgvarg[i] = *(VARIANT*)((char*)(sa->pvData) + (dp.cArgs - i - 1) * sa->cbElements); - SafeArrayUnlock(sa); - - hr = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex); - if (FAILED(hr)) - { - hr = IDispatch_Invoke(disp, dispid, &IID_NULL, LOCALE_USER_DEFAULT, - DISPATCH_METHOD, &dp, res, NULL, NULL); - } - else - { - hr = IDispatchEx_InvokeEx(dispex, dispid, LOCALE_USER_DEFAULT, - DISPATCH_METHOD, &dp, res, NULL, NULL); - IDispatchEx_Release(dispex); - } - } - heap_free(dp.rgvarg); - - return hr; + return run_procedure(This->modules[0], procedure_name, sa, res); }
static const IScriptControlVtbl ScriptControlVtbl = {
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/msscript.ocx/msscript.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/dlls/msscript.ocx/msscript.c b/dlls/msscript.ocx/msscript.c index 3cbc7a4..d5fdca7 100644 --- a/dlls/msscript.ocx/msscript.c +++ b/dlls/msscript.ocx/msscript.c @@ -847,10 +847,19 @@ static HRESULT WINAPI ScriptModule_ExecuteStatement(IScriptModule *iface, BSTR s static HRESULT WINAPI ScriptModule_Run(IScriptModule *iface, BSTR procedure_name, SAFEARRAY **parameters, VARIANT *res) { ScriptModule *This = impl_from_IScriptModule(iface); + SAFEARRAY *sa;
- FIXME("(%p)->(%s %p %p)\n", This, debugstr_w(procedure_name), parameters, res); + TRACE("(%p)->(%s %p %p)\n", This, debugstr_w(procedure_name), parameters, res);
- return E_NOTIMPL; + if (!parameters || !res) return E_POINTER; + if (!(sa = *parameters)) return E_POINTER; + + V_VT(res) = VT_EMPTY; + if (sa->cDims == 0) return DISP_E_BADINDEX; + if (!(sa->fFeatures & FADF_VARIANT)) return DISP_E_BADVARTYPE; + if (!This->control) return E_FAIL; + + return run_procedure(This, procedure_name, sa, res); }
static const IScriptModuleVtbl ScriptModuleVtbl = {
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/msscript.ocx/msscript.c | 59 +++++++++++++++++++++--------------- 1 file changed, 35 insertions(+), 24 deletions(-)
diff --git a/dlls/msscript.ocx/msscript.c b/dlls/msscript.ocx/msscript.c index d5fdca7..0745e09 100644 --- a/dlls/msscript.ocx/msscript.c +++ b/dlls/msscript.ocx/msscript.c @@ -255,6 +255,40 @@ static HRESULT start_script(struct ScriptControl *control) return hr; }
+static HRESULT add_script_object(ScriptHost *host, BSTR name, IDispatch *object, DWORD flags) +{ + struct named_item *item; + HRESULT hr; + + if (host_get_named_item(host, name)) + return E_INVALIDARG; + + item = heap_alloc(sizeof(*item)); + if (!item) + return E_OUTOFMEMORY; + + item->name = SysAllocString(name); + if (!item->name) + { + heap_free(item); + return E_OUTOFMEMORY; + } + IDispatch_AddRef(item->disp = object); + list_add_tail(&host->named_items, &item->entry); + + hr = IActiveScript_AddNamedItem(host->script, name, flags); + if (FAILED(hr)) + { + list_remove(&item->entry); + IDispatch_Release(item->disp); + SysFreeString(item->name); + heap_free(item); + return hr; + } + + return hr; +} + static HRESULT parse_script_text(ScriptModule *module, BSTR script_text, DWORD flag, VARIANT *res) { EXCEPINFO excepinfo; @@ -1473,8 +1507,6 @@ static HRESULT WINAPI ScriptControl_AddObject(IScriptControl *iface, BSTR name, { ScriptControl *This = impl_from_IScriptControl(iface); DWORD flags = SCRIPTITEM_ISVISIBLE | SCRIPTITEM_ISSOURCE; - struct named_item *item; - HRESULT hr;
TRACE("(%p)->(%s %p %x)\n", This, debugstr_w(name), object, add_members);
@@ -1484,30 +1516,9 @@ static HRESULT WINAPI ScriptControl_AddObject(IScriptControl *iface, BSTR name, if (!This->host) return E_FAIL;
- if (host_get_named_item(This->host, name)) - return E_INVALIDARG; - - item = heap_alloc(sizeof(*item)); - if (!item) - return E_OUTOFMEMORY; - - item->name = SysAllocString(name); - IDispatch_AddRef(item->disp = object); - list_add_tail(&This->host->named_items, &item->entry); - if (add_members) flags |= SCRIPTITEM_GLOBALMEMBERS; - hr = IActiveScript_AddNamedItem(This->host->script, name, flags); - if (FAILED(hr)) { - list_remove(&item->entry); - IDispatch_Release(item->disp); - SysFreeString(item->name); - heap_free(item); - return hr; - } - - - return hr; + return add_script_object(This->host, name, object, flags); }
static HRESULT WINAPI ScriptControl_Reset(IScriptControl *iface)
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/msscript.ocx/msscript.c | 41 ++++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-)
diff --git a/dlls/msscript.ocx/msscript.c b/dlls/msscript.ocx/msscript.c index 0745e09..e3b7b86 100644 --- a/dlls/msscript.ocx/msscript.c +++ b/dlls/msscript.ocx/msscript.c @@ -704,6 +704,23 @@ static void release_modules(ScriptControl *control) heap_free(control->modules); }
+static UINT find_module(ScriptControl *control, BSTR name) +{ + UINT i, len = SysStringLen(name); + + if (len == sizeof("Global") - 1 && !wcsicmp(name, L"Global")) + return 0; + + for (i = 1; i < control->num_modules; i++) + { + BSTR modname = control->modules[i]->name; + if (SysStringLen(modname) == len && !wcsicmp(name, modname)) + return i; + } + + return ~0; +} + static HRESULT WINAPI ScriptModule_QueryInterface(IScriptModule *iface, REFIID riid, void **ppv) { ScriptModule *This = impl_from_IScriptModule(iface); @@ -1037,10 +1054,30 @@ static HRESULT WINAPI ScriptModuleCollection_get_Item(IScriptModuleCollection *i IScriptModule **ppmod) { ScriptControl *This = impl_from_IScriptModuleCollection(iface); + HRESULT hr; + UINT i;
- FIXME("(%p)->(%s %p)\n", This, wine_dbgstr_variant(&index), ppmod); + TRACE("(%p)->(%s %p)\n", This, wine_dbgstr_variant(&index), ppmod);
- return E_NOTIMPL; + if (!ppmod) return E_POINTER; + + if (V_VT(&index) == VT_BSTR) + { + i = find_module(This, V_BSTR(&index)); + if (i == ~0) return CTL_E_ILLEGALFUNCTIONCALL; + } + else + { + hr = VariantChangeType(&index, &index, 0, VT_INT); + if (FAILED(hr)) return hr; + + i = V_INT(&index) - 1; + if (i >= This->num_modules) return 0x800a0009; + } + + *ppmod = &This->modules[i]->IScriptModule_iface; + IScriptModule_AddRef(*ppmod); + return S_OK; }
static HRESULT WINAPI ScriptModuleCollection_get_Count(IScriptModuleCollection *iface, LONG *plCount)
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/msscript.ocx/msscript.c | 42 ++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-)
diff --git a/dlls/msscript.ocx/msscript.c b/dlls/msscript.ocx/msscript.c index e3b7b86..f0a4853 100644 --- a/dlls/msscript.ocx/msscript.c +++ b/dlls/msscript.ocx/msscript.c @@ -197,6 +197,11 @@ static void release_typelib(void) ITypeLib_Release(typelib); }
+static inline BOOL is_power_of_2(unsigned x) +{ + return !(x & (x - 1)); +} + static void clear_named_items(ScriptHost *host) { struct named_item *item, *item1; @@ -1096,10 +1101,43 @@ static HRESULT WINAPI ScriptModuleCollection_Add(IScriptModuleCollection *iface, VARIANT *object, IScriptModule **ppmod) { ScriptControl *This = impl_from_IScriptModuleCollection(iface); + ScriptModule *mod, **mods; + HRESULT hr;
- FIXME("(%p)->(%s %s %p)\n", This, wine_dbgstr_w(name), wine_dbgstr_variant(object), ppmod); + TRACE("(%p)->(%s %s %p)\n", This, wine_dbgstr_w(name), wine_dbgstr_variant(object), ppmod);
- return E_NOTIMPL; + if (!ppmod) return E_POINTER; + if (!name || V_VT(object) != VT_DISPATCH || find_module(This, name) != ~0) + return E_INVALIDARG; + if (!This->host) return E_FAIL; + + /* See if we need to grow the array */ + if (is_power_of_2(This->num_modules)) + { + mods = heap_realloc(This->modules, This->num_modules * 2 * sizeof(*This->modules)); + if (!mods) return E_OUTOFMEMORY; + This->modules = mods; + } + + mod = alloc_module(This, name); + if (!mod) return E_OUTOFMEMORY; + + /* If no object, Windows only calls AddNamedItem without adding a NULL object */ + if (V_DISPATCH(object)) + hr = add_script_object(This->host, name, V_DISPATCH(object), 0); + else + hr = IActiveScript_AddNamedItem(This->host->script, name, SCRIPTITEM_CODEONLY); + + if (FAILED(hr)) + { + destroy_module(mod); + return hr; + } + This->modules[This->num_modules++] = mod; + + *ppmod = &mod->IScriptModule_iface; + IScriptModule_AddRef(*ppmod); + return S_OK; }
static const IScriptModuleCollectionVtbl ScriptModuleCollectionVtbl = {
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/msscript.ocx/msscript.c | 150 ++++++++++++++++++++++++++++++++++- 1 file changed, 148 insertions(+), 2 deletions(-)
diff --git a/dlls/msscript.ocx/msscript.c b/dlls/msscript.ocx/msscript.c index f0a4853..a691413 100644 --- a/dlls/msscript.ocx/msscript.c +++ b/dlls/msscript.ocx/msscript.c @@ -65,6 +65,13 @@ struct named_item { IDispatch *disp; };
+struct script_mod_enum { + IEnumVARIANT IEnumVARIANT_iface; + LONG ref; + UINT pos; + ScriptControl *control; +}; + typedef struct ScriptModule { IScriptModule IScriptModule_iface; LONG ref; @@ -430,6 +437,11 @@ static inline ScriptHost *impl_from_IServiceProvider(IServiceProvider *iface) return CONTAINING_RECORD(iface, ScriptHost, IServiceProvider_iface); }
+static inline struct script_mod_enum *script_mod_enum_from_IEnumVARIANT(IEnumVARIANT *iface) +{ + return CONTAINING_RECORD(iface, struct script_mod_enum, IEnumVARIANT_iface); +} + /* IActiveScriptSite */ static HRESULT WINAPI ActiveScriptSite_QueryInterface(IActiveScriptSite *iface, REFIID riid, void **ppv) { @@ -935,6 +947,127 @@ static const IScriptModuleVtbl ScriptModuleVtbl = { ScriptModule_Run };
+static HRESULT WINAPI script_mod_enum_QueryInterface(IEnumVARIANT *iface, REFIID riid, void **ppv) +{ + struct script_mod_enum *This = script_mod_enum_from_IEnumVARIANT(iface); + + if (IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IEnumVARIANT, riid)) + { + *ppv = &This->IEnumVARIANT_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 script_mod_enum_AddRef(IEnumVARIANT *iface) +{ + struct script_mod_enum *This = script_mod_enum_from_IEnumVARIANT(iface); + LONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p) ref=%d\n", This, ref); + + return ref; +} + +static ULONG WINAPI script_mod_enum_Release(IEnumVARIANT *iface) +{ + struct script_mod_enum *This = script_mod_enum_from_IEnumVARIANT(iface); + LONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p) ref=%d\n", This, ref); + + if (!ref) + { + IScriptControl_Release(&This->control->IScriptControl_iface); + heap_free(This); + } + + return ref; +} + +static HRESULT WINAPI script_mod_enum_Next(IEnumVARIANT *iface, ULONG celt, VARIANT *rgVar, ULONG *pCeltFetched) +{ + struct script_mod_enum *This = script_mod_enum_from_IEnumVARIANT(iface); + UINT i, num; + + TRACE("(%p)->(%u %p %p)\n", This, celt, rgVar, pCeltFetched); + + if (!rgVar) return E_POINTER; + + num = min(celt, This->control->num_modules - This->pos); + for (i = 0; i < num; i++) + { + V_VT(rgVar + i) = VT_DISPATCH; + V_DISPATCH(rgVar + i) = (IDispatch*)(&This->control->modules[This->pos++]->IScriptModule_iface); + IDispatch_AddRef(V_DISPATCH(rgVar + i)); + } + + if (pCeltFetched) *pCeltFetched = i; + return i == celt ? S_OK : S_FALSE; +} + +static HRESULT WINAPI script_mod_enum_Skip(IEnumVARIANT *iface, ULONG celt) +{ + struct script_mod_enum *This = script_mod_enum_from_IEnumVARIANT(iface); + + TRACE("(%p)->(%u)\n", This, celt); + + if (This->control->num_modules - This->pos < celt) + { + This->pos = This->control->num_modules; + return S_FALSE; + } + This->pos += celt; + return S_OK; +} + +static HRESULT WINAPI script_mod_enum_Reset(IEnumVARIANT *iface) +{ + struct script_mod_enum *This = script_mod_enum_from_IEnumVARIANT(iface); + + TRACE("(%p)\n", This); + + This->pos = 0; + return S_OK; +} + +static HRESULT WINAPI script_mod_enum_Clone(IEnumVARIANT *iface, IEnumVARIANT **ppEnum) +{ + struct script_mod_enum *This = script_mod_enum_from_IEnumVARIANT(iface); + struct script_mod_enum *clone; + + TRACE("(%p)->(%p)\n", This, ppEnum); + + if (!ppEnum) return E_POINTER; + + if (!(clone = heap_alloc(sizeof(*clone)))) + return E_OUTOFMEMORY; + + *clone = *This; + clone->ref = 1; + IScriptControl_AddRef(&This->control->IScriptControl_iface); + + *ppEnum = &clone->IEnumVARIANT_iface; + return S_OK; +} + +static const IEnumVARIANTVtbl script_mod_enum_vtbl = { + script_mod_enum_QueryInterface, + script_mod_enum_AddRef, + script_mod_enum_Release, + script_mod_enum_Next, + script_mod_enum_Skip, + script_mod_enum_Reset, + script_mod_enum_Clone +}; + static ScriptModule *alloc_module(ScriptControl *control, BSTR name) { ScriptModule *module = heap_alloc_zero(sizeof(*module)); @@ -1049,10 +1182,23 @@ static HRESULT WINAPI ScriptModuleCollection_Invoke(IScriptModuleCollection *ifa static HRESULT WINAPI ScriptModuleCollection_get__NewEnum(IScriptModuleCollection *iface, IUnknown **ppenumContexts) { ScriptControl *This = impl_from_IScriptModuleCollection(iface); + struct script_mod_enum *mod_enum;
- FIXME("(%p)->(%p)\n", This, ppenumContexts); + TRACE("(%p)->(%p)\n", This, ppenumContexts);
- return E_NOTIMPL; + if (!ppenumContexts) return E_POINTER; + + if (!(mod_enum = heap_alloc(sizeof(*mod_enum)))) + return E_OUTOFMEMORY; + + mod_enum->IEnumVARIANT_iface.lpVtbl = &script_mod_enum_vtbl; + mod_enum->ref = 1; + mod_enum->pos = 0; + mod_enum->control = This; + IScriptControl_AddRef(&This->IScriptControl_iface); + + *ppenumContexts = (IUnknown*)&mod_enum->IEnumVARIANT_iface; + return S_OK; }
static HRESULT WINAPI ScriptModuleCollection_get_Item(IScriptModuleCollection *iface, VARIANT index,
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/msscript.ocx/tests/msscript.c | 360 ++++++++++++++++++++++++++++- 1 file changed, 356 insertions(+), 4 deletions(-)
diff --git a/dlls/msscript.ocx/tests/msscript.c b/dlls/msscript.ocx/tests/msscript.c index 22db28e..2466547 100644 --- a/dlls/msscript.ocx/tests/msscript.c +++ b/dlls/msscript.ocx/tests/msscript.c @@ -150,6 +150,7 @@ static HRESULT WINAPI ActiveScriptParse_AddScriptlet(IActiveScriptParse *iface, return E_NOTIMPL; }
+static const WCHAR *parse_item_name; static DWORD parse_flags = 0;
static HRESULT WINAPI ActiveScriptParse_ParseScriptText(IActiveScriptParse *iface, @@ -158,7 +159,8 @@ static HRESULT WINAPI ActiveScriptParse_ParseScriptText(IActiveScriptParse *ifac DWORD dwFlags, VARIANT *pvarResult, EXCEPINFO *pexcepinfo) { ok(!!pstrCode, "got wrong pointer: %p.\n", pstrCode); - ok(!pstrItemName, "got wrong pointer: %p.\n", pstrItemName); + ok(!lstrcmpW(pstrItemName, parse_item_name), "got wrong item name: %s (expected %s).\n", + wine_dbgstr_w(pstrItemName), wine_dbgstr_w(parse_item_name)); ok(!punkContext, "got wrong pointer: %p.\n", punkContext); ok(!pstrDelimiter, "got wrong pointer: %p.\n", pstrDelimiter); ok(!dwSourceContextCookie, "got wrong value: %s.\n", wine_dbgstr_longlong(dwSourceContextCookie)); @@ -522,12 +524,13 @@ static HRESULT WINAPI ActiveScript_Close(IActiveScript *iface) return E_NOTIMPL; }
+static const WCHAR *AddNamedItem_expected_name; +static DWORD AddNamedItem_expected_flags; static HRESULT WINAPI ActiveScript_AddNamedItem(IActiveScript *iface, LPCOLESTR name, DWORD flags) { - static const WCHAR oW[] = {'o',0}; CHECK_EXPECT(AddNamedItem); - ok(!lstrcmpW(name, oW), "got name %s\n", wine_dbgstr_w(name)); - ok(flags == (SCRIPTITEM_ISVISIBLE|SCRIPTITEM_ISSOURCE|SCRIPTITEM_GLOBALMEMBERS), "got flags %#x\n", flags); + ok(!lstrcmpW(name, AddNamedItem_expected_name), "got name %s\n", wine_dbgstr_w(name)); + ok(flags == AddNamedItem_expected_flags, "got flags %#x\n", flags); return S_OK; }
@@ -1413,6 +1416,8 @@ static void test_AddObject(void) ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
SET_EXPECT(AddNamedItem); + AddNamedItem_expected_name = objname; + AddNamedItem_expected_flags = SCRIPTITEM_ISVISIBLE|SCRIPTITEM_ISSOURCE|SCRIPTITEM_GLOBALMEMBERS; hr = IScriptControl_AddObject(sc, objname, &testdisp, VARIANT_TRUE); ok(hr == S_OK, "got 0x%08x\n", hr); CHECK_CALLED(AddNamedItem); @@ -1693,6 +1698,7 @@ static void test_IScriptControl_Eval(void)
SET_EXPECT(SetScriptState_STARTED); SET_EXPECT(ParseScriptText); + parse_item_name = NULL; parse_flags = SCRIPTTEXT_ISEXPRESSION; script_str = SysAllocString(L"var1 = 1 + 1"); V_VT(&var) = VT_NULL; @@ -1806,6 +1812,7 @@ static void test_IScriptControl_AddCode(void)
SET_EXPECT(SetScriptState_STARTED); SET_EXPECT(ParseScriptText); + parse_item_name = NULL; parse_flags = SCRIPTTEXT_ISVISIBLE; code_str = SysAllocString(L"1 + 1"); hr = IScriptControl_AddCode(sc, code_str); @@ -1823,6 +1830,7 @@ static void test_IScriptControl_AddCode(void)
/* Call Eval() after AddCode() for checking if it will call SetScriptState() again. */ SET_EXPECT(ParseScriptText); + parse_item_name = NULL; parse_flags = SCRIPTTEXT_ISEXPRESSION; code_str = SysAllocString(L"var2 = 10 + var1"); V_VT(&var) = VT_NULL; @@ -1905,6 +1913,7 @@ static void test_IScriptControl_ExecuteStatement(void)
SET_EXPECT(SetScriptState_STARTED); SET_EXPECT(ParseScriptText); + parse_item_name = NULL; parse_flags = 0; str = SysAllocString(L"1 + 1"); hr = IScriptControl_ExecuteStatement(sc, str); @@ -2125,6 +2134,348 @@ static void test_IScriptControl_Run(void) SafeArrayDestroy(params); }
+static void test_IScriptControl_get_Modules(void) +{ + IEnumVARIANT *enumvar, *enumvar2; + IScriptModuleCollection *mods; + VARIANT var, vars[3]; + IScriptModule *mod; + IScriptControl *sc; + IUnknown *unknown; + ULONG fetched; + LONG count; + HRESULT hr; + BSTR str; + UINT i; + + hr = CoCreateInstance(&CLSID_ScriptControl, NULL, CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER, + &IID_IScriptControl, (void**)&sc); + ok(hr == S_OK, "Failed to create IScriptControl interface: 0x%08x.\n", hr); + + hr = IScriptControl_get_Modules(sc, &mods); + ok(hr == E_FAIL, "IScriptControl_get_Modules returned: 0x%08x.\n", hr); + + str = SysAllocString(L"jscript"); + hr = IScriptControl_put_Language(sc, str); + ok(hr == S_OK, "IScriptControl_put_Language failed: 0x%08x.\n", hr); + SysFreeString(str); + + hr = IScriptControl_get_Modules(sc, &mods); + ok(hr == S_OK, "IScriptControl_get_Modules failed: 0x%08x.\n", hr); + + hr = IScriptModuleCollection_get_Count(mods, NULL); + ok(hr == E_POINTER, "IScriptModuleCollection_get_Count returned: 0x%08x.\n", hr); + hr = IScriptModuleCollection_get_Count(mods, &count); + ok(hr == S_OK, "IScriptModuleCollection_get_Count failed: 0x%08x.\n", hr); + ok(count == 1, "count is not 1, got %d.\n", count); + + V_VT(&var) = VT_I4; + V_I4(&var) = -1; + hr = IScriptModuleCollection_get_Item(mods, var, NULL); + ok(hr == E_POINTER, "IScriptModuleCollection_get_Item returned: 0x%08x.\n", hr); + hr = IScriptModuleCollection_get_Item(mods, var, &mod); + ok(hr == 0x800a0009, "IScriptModuleCollection_get_Item returned: 0x%08x.\n", hr); + + V_VT(&var) = VT_EMPTY; + str = SysAllocString(L"foobar"); + hr = IScriptModuleCollection_Add(mods, str, &var, &mod); + ok(hr == E_INVALIDARG, "IScriptModuleCollection_Add returned: 0x%08x.\n", hr); + hr = IScriptModuleCollection_Add(mods, str, &var, NULL); + ok(hr == E_POINTER, "IScriptModuleCollection_Add returned: 0x%08x.\n", hr); + V_VT(&var) = VT_DISPATCH; + V_DISPATCH(&var) = NULL; + hr = IScriptModuleCollection_Add(mods, NULL, &var, &mod); + ok(hr == E_INVALIDARG, "IScriptModuleCollection_Add returned: 0x%08x.\n", hr); + hr = IScriptModuleCollection_Add(mods, str, &var, &mod); + ok(hr == S_OK, "IScriptModuleCollection_Add failed: 0x%08x.\n", hr); + IScriptModule_Release(mod); + SysFreeString(str); + + /* Grab an enumerator before we add another module */ + hr = IScriptModuleCollection_get__NewEnum(mods, NULL); + ok(hr == E_POINTER, "IScriptModuleCollection_get__NewEnum returned: 0x%08x.\n", hr); + hr = IScriptModuleCollection_get__NewEnum(mods, &unknown); + ok(hr == S_OK, "IScriptModuleCollection_get__NewEnum failed: 0x%08x.\n", hr); + hr = IUnknown_QueryInterface(unknown, &IID_IEnumVARIANT, (void**)&enumvar); + ok(hr == S_OK, "Failed to query for IEnumVARIANT: 0x%08x.\n", hr); + ok((char*)unknown == (char*)enumvar, "unknown and enumvar are not the same (%p vs %p).\n", unknown, enumvar); + IUnknown_Release(unknown); + + str = SysAllocString(L"some other Module"); + hr = IScriptModuleCollection_Add(mods, str, &var, &mod); + ok(hr == S_OK, "IScriptModuleCollection_Add failed: 0x%08x.\n", hr); + IScriptModule_Release(mod); + SysFreeString(str); + + /* Adding a module with the same name is invalid (case insensitive) */ + str = SysAllocString(L"FooBar"); + hr = IScriptModuleCollection_Add(mods, str, &var, &mod); + ok(hr == E_INVALIDARG, "IScriptModuleCollection_Add failed: 0x%08x.\n", hr); + SysFreeString(str); + + hr = IScriptModuleCollection_get_Count(mods, &count); + ok(hr == S_OK, "IScriptModuleCollection_get_Count failed: 0x%08x.\n", hr); + ok(count == 3, "count is not 3, got %d.\n", count); + V_VT(&var) = VT_I4; + V_I4(&var) = count + 1; + hr = IScriptModuleCollection_get_Item(mods, var, &mod); + ok(hr == 0x800a0009, "IScriptModuleCollection_get_Item returned: 0x%08x.\n", hr); + V_VT(&var) = VT_BSTR; + V_BSTR(&var) = SysAllocString(L"non-existent module"); + hr = IScriptModuleCollection_get_Item(mods, var, &mod); + ok(hr == CTL_E_ILLEGALFUNCTIONCALL, "IScriptModuleCollection_get_Item returned: 0x%08x.\n", hr); + ok(V_VT(&var) == VT_BSTR, "var type not BSTR, got %d.\n", V_VT(&var)); + VariantClear(&var); + + V_VT(&var) = VT_I4; + V_I4(&var) = 1; + hr = IScriptModuleCollection_get_Item(mods, var, &mod); + ok(hr == S_OK, "IScriptModuleCollection_get_Item failed: 0x%08x.\n", hr); + hr = IScriptModule_get_Name(mod, NULL); + ok(hr == E_POINTER, "IScriptModule_get_Name returned: 0x%08x.\n", hr); + hr = IScriptModule_get_Name(mod, &str); + ok(hr == S_OK, "IScriptModule_get_Name failed: 0x%08x.\n", hr); + ok(!lstrcmpW(str, L"Global"), "got %s.\n", wine_dbgstr_w(str)); + SysFreeString(str); + str = SysAllocString(L"function add(a, b) { return a + b; }\n"); + hr = IScriptModule_AddCode(mod, str); + ok(hr == S_OK, "IScriptModule_AddCode failed: 0x%08x.\n", hr); + IScriptModule_Release(mod); + SysFreeString(str); + + V_VT(&var) = VT_BSTR; + V_BSTR(&var) = SysAllocString(L"some other module"); + hr = IScriptModuleCollection_get_Item(mods, var, &mod); + ok(hr == S_OK, "IScriptModuleCollection_get_Item failed: 0x%08x.\n", hr); + ok(V_VT(&var) == VT_BSTR, "var type not BSTR, got %d.\n", V_VT(&var)); + VariantClear(&var); + hr = IScriptModule_get_Name(mod, &str); + ok(hr == S_OK, "IScriptModule_get_Name failed: 0x%08x.\n", hr); + ok(!lstrcmpW(str, L"some other Module"), "got %s.\n", wine_dbgstr_w(str)); + IScriptModule_Release(mod); + SysFreeString(str); + + V_VT(&var) = VT_R8; + V_R8(&var) = 2.0; + hr = IScriptModuleCollection_get_Item(mods, var, &mod); + ok(hr == S_OK, "IScriptModuleCollection_get_Item failed: 0x%08x.\n", hr); + hr = IScriptModule_get_Name(mod, &str); + ok(hr == S_OK, "IScriptModule_get_Name failed: 0x%08x.\n", hr); + ok(!lstrcmpW(str, L"foobar"), "got %s.\n", wine_dbgstr_w(str)); + SysFreeString(str); + str = SysAllocString(L"function sub(a, b) { return a - b; }\n"); + hr = IScriptModule_AddCode(mod, str); + ok(hr == S_OK, "IScriptModule_AddCode failed: 0x%08x.\n", hr); + IScriptModule_Release(mod); + SysFreeString(str); + + /* Test the enumerator, should be updated */ + fetched = 0xdeadbeef; + hr = IEnumVARIANT_Next(enumvar, 0, NULL, NULL); + ok(hr == E_POINTER, "IEnumVARIANT_Next returned: 0x%08x.\n", hr); + hr = IEnumVARIANT_Next(enumvar, 0, NULL, &fetched); + ok(hr == E_POINTER, "IEnumVARIANT_Next failed: 0x%08x.\n", hr); + ok(fetched == 0xdeadbeef, "got %u.\n", fetched); + hr = IEnumVARIANT_Next(enumvar, 0, &var, &fetched); + ok(hr == S_OK, "IEnumVARIANT_Next returned: 0x%08x.\n", hr); + ok(fetched == 0, "got %u.\n", fetched); + hr = IEnumVARIANT_Next(enumvar, 0, &var, NULL); + ok(hr == S_OK, "IEnumVARIANT_Next returned: 0x%08x.\n", hr); + hr = IEnumVARIANT_Clone(enumvar, NULL); + ok(hr == E_POINTER, "IEnumVARIANT_Clone failed: 0x%08x.\n", hr); + + hr = IEnumVARIANT_Next(enumvar, ARRAY_SIZE(vars), vars, &fetched); + ok(hr == S_OK, "IEnumVARIANT_Next failed: 0x%08x.\n", hr); + ok(fetched == ARRAY_SIZE(vars), "got %u.\n", fetched); + hr = IEnumVARIANT_Next(enumvar, 1, &var, &fetched); + ok(hr == S_FALSE, "IEnumVARIANT_Next failed: 0x%08x.\n", hr); + ok(fetched == 0, "got %u.\n", fetched); + hr = IEnumVARIANT_Skip(enumvar, 0); + ok(hr == S_OK, "IEnumVARIANT_Skip failed: 0x%08x.\n", hr); + hr = IEnumVARIANT_Skip(enumvar, 1); + ok(hr == S_FALSE, "IEnumVARIANT_Skip failed: 0x%08x.\n", hr); + hr = IEnumVARIANT_Clone(enumvar, &enumvar2); + ok(hr == S_OK, "IEnumVARIANT_Clone failed: 0x%08x.\n", hr); + hr = IEnumVARIANT_Skip(enumvar2, 1); + ok(hr == S_FALSE, "IEnumVARIANT_Skip failed: 0x%08x.\n", hr); + IEnumVARIANT_Release(enumvar2); + IEnumVARIANT_Release(enumvar); + + for (i = 0; i < ARRAY_SIZE(vars); i++) + { + ok(V_VT(&vars[i]) == VT_DISPATCH, "V_VT(vars[%u]) = %d.\n", i, V_VT(&vars[i])); + hr = IDispatch_QueryInterface(V_DISPATCH(&vars[i]), &IID_IScriptModule, (void**)&mod); + ok(hr == S_OK, "Failed to query IScriptModule from vars[%u]: 0x%08x.\n", i, hr); + IScriptModule_Release(mod); + VariantClear(&vars[i]); + } + + /* The 'Global' module is the same as the script control */ + str = SysAllocString(L"add(10, 5)"); + hr = IScriptControl_Eval(sc, str, &var); + ok(hr == S_OK, "IScriptControl_Eval failed: 0x%08x.\n", hr); + ok(V_VT(&var) == VT_I4 && V_I4(&var) == 15, "V_VT(var) = %d, V_I4(var) = %d.\n", V_VT(&var), V_I4(&var)); + SysFreeString(str); + str = SysAllocString(L"sub(10, 5)"); + hr = IScriptControl_Eval(sc, str, &var); + ok(FAILED(hr), "IScriptControl_Eval succeeded: 0x%08x.\n", hr); + SysFreeString(str); + + /* Grab a module ref and change the language to something valid */ + V_VT(&var) = VT_I2; + V_I2(&var) = 3; + hr = IScriptModuleCollection_get_Item(mods, var, &mod); + ok(hr == S_OK, "IScriptModuleCollection_get_Item failed: 0x%08x.\n", hr); + str = SysAllocString(L"vbscript"); + hr = IScriptControl_put_Language(sc, str); + ok(hr == S_OK, "IScriptControl_put_Language failed: 0x%08x.\n", hr); + SysFreeString(str); + + /* The module collection changes and module ref is invalid */ + hr = IScriptModuleCollection_get_Count(mods, &count); + ok(hr == S_OK, "IScriptModuleCollection_get_Count failed: 0x%08x.\n", hr); + ok(count == 1, "count is not 1, got %d.\n", count); + hr = IScriptModule_get_Name(mod, &str); + ok(hr == E_FAIL, "IScriptModule_get_Name returned: 0x%08x.\n", hr); + str = SysAllocString(L"function closed() { }\n"); + hr = IScriptModule_AddCode(mod, str); + ok(hr == E_FAIL, "IScriptModule_AddCode failed: 0x%08x.\n", hr); + SysFreeString(str); + str = SysAllocString(L"sub closed\nend sub"); + hr = IScriptModule_AddCode(mod, str); + ok(hr == E_FAIL, "IScriptModule_AddCode failed: 0x%08x.\n", hr); + IScriptModule_Release(mod); + SysFreeString(str); + + IScriptModuleCollection_Release(mods); + IScriptControl_Release(sc); + + /* custom script engine */ + if (have_custom_engine) + { + BSTR code_str; + + hr = CoCreateInstance(&CLSID_ScriptControl, NULL, CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER, + &IID_IScriptControl, (void**)&sc); + ok(hr == S_OK, "Failed to create IScriptControl interface: 0x%08x.\n", hr); + + SET_EXPECT(CreateInstance); + SET_EXPECT(SetInterfaceSafetyOptions); + SET_EXPECT(SetScriptSite); + SET_EXPECT(QI_IActiveScriptParse); + SET_EXPECT(InitNew); + str = SysAllocString(L"testscript"); + hr = IScriptControl_put_Language(sc, str); + ok(hr == S_OK, "IScriptControl_put_Language failed: 0x%08x.\n", hr); + SysFreeString(str); + CHECK_CALLED(CreateInstance); + CHECK_CALLED(SetInterfaceSafetyOptions); + CHECK_CALLED(SetScriptSite); + CHECK_CALLED(QI_IActiveScriptParse); + CHECK_CALLED(InitNew); + + hr = IScriptControl_get_Modules(sc, &mods); + ok(hr == S_OK, "IScriptControl_get_Modules failed: 0x%08x.\n", hr); + + /* Add a module with a non-null object and add some code to it */ + SET_EXPECT(AddNamedItem); + str = SysAllocString(L"modname"); + AddNamedItem_expected_name = str; + AddNamedItem_expected_flags = 0; + V_VT(&var) = VT_DISPATCH; + V_DISPATCH(&var) = &testdisp; + hr = IScriptModuleCollection_Add(mods, str, &var, &mod); + ok(hr == S_OK, "IScriptModuleCollection_Add failed: 0x%08x.\n", hr); + VariantClear(&var); + CHECK_CALLED(AddNamedItem); + + unknown = (IUnknown*)0xdeadbeef; + hr = IActiveScriptSite_GetItemInfo(site, str, SCRIPTINFO_IUNKNOWN, &unknown, NULL); + ok(hr == S_OK, "IActiveScriptSite_GetItemInfo failed: 0x%08x.\n", hr); + ok(unknown == (IUnknown*)&testdisp, "Unexpected IUnknown for the item: %p.\n", unknown); + IUnknown_Release(unknown); + + SET_EXPECT(SetScriptState_STARTED); + SET_EXPECT(ParseScriptText); + parse_item_name = str; + parse_flags = SCRIPTTEXT_ISVISIBLE; + code_str = SysAllocString(L"some code"); + hr = IScriptModule_AddCode(mod, code_str); + ok(hr == S_OK, "IScriptControl_AddCode failed: 0x%08x.\n", hr); + CHECK_CALLED(SetScriptState_STARTED); + CHECK_CALLED(ParseScriptText); + SysFreeString(code_str); + SysFreeString(str); + + /* Keep the module ref before changing the language */ + SET_EXPECT(Close); + hr = IScriptControl_put_Language(sc, NULL); + ok(hr == S_OK, "IScriptControl_put_Language failed: 0x%08x.\n", hr); + CHECK_CALLED(Close); + IScriptModuleCollection_Release(mods); + IActiveScriptSite_Release(site); + IScriptControl_Release(sc); + IScriptModule_Release(mod); + + /* Now try holding a module ref while closing the script */ + hr = CoCreateInstance(&CLSID_ScriptControl, NULL, CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER, + &IID_IScriptControl, (void**)&sc); + ok(hr == S_OK, "Failed to create IScriptControl interface: 0x%08x.\n", hr); + + SET_EXPECT(CreateInstance); + SET_EXPECT(SetInterfaceSafetyOptions); + SET_EXPECT(SetScriptSite); + SET_EXPECT(QI_IActiveScriptParse); + SET_EXPECT(InitNew); + str = SysAllocString(L"testscript"); + hr = IScriptControl_put_Language(sc, str); + ok(hr == S_OK, "IScriptControl_put_Language failed: 0x%08x.\n", hr); + SysFreeString(str); + CHECK_CALLED(CreateInstance); + CHECK_CALLED(SetInterfaceSafetyOptions); + CHECK_CALLED(SetScriptSite); + CHECK_CALLED(QI_IActiveScriptParse); + CHECK_CALLED(InitNew); + + hr = IScriptControl_get_Modules(sc, &mods); + ok(hr == S_OK, "IScriptControl_get_Modules failed: 0x%08x.\n", hr); + + SET_EXPECT(AddNamedItem); + str = SysAllocString(L"foo"); + AddNamedItem_expected_name = str; + AddNamedItem_expected_flags = SCRIPTITEM_CODEONLY; + V_VT(&var) = VT_DISPATCH; + V_DISPATCH(&var) = NULL; + hr = IScriptModuleCollection_Add(mods, str, &var, &mod); + ok(hr == S_OK, "IScriptModuleCollection_Add failed: 0x%08x.\n", hr); + VariantClear(&var); + CHECK_CALLED(AddNamedItem); + + unknown = (IUnknown*)0xdeadbeef; + hr = IActiveScriptSite_GetItemInfo(site, str, SCRIPTINFO_IUNKNOWN, &unknown, NULL); + ok(hr == TYPE_E_ELEMENTNOTFOUND, "IActiveScriptSite_GetItemInfo returned: 0x%08x.\n", hr); + IScriptModuleCollection_Release(mods); + IActiveScriptSite_Release(site); + IScriptControl_Release(sc); + + SET_EXPECT(SetScriptState_STARTED); + SET_EXPECT(ParseScriptText); + parse_item_name = str; + parse_flags = SCRIPTTEXT_ISVISIBLE; + code_str = SysAllocString(L"code after close"); + hr = IScriptModule_AddCode(mod, code_str); + ok(hr == S_OK, "IScriptControl_AddCode failed: 0x%08x.\n", hr); + CHECK_CALLED(SetScriptState_STARTED); + CHECK_CALLED(ParseScriptText); + SysFreeString(code_str); + SysFreeString(str); + + SET_EXPECT(Close); + IScriptModule_Release(mod); + CHECK_CALLED(Close); + } +} + START_TEST(msscript) { IUnknown *unk; @@ -2162,6 +2513,7 @@ START_TEST(msscript) test_IScriptControl_AddCode(); test_IScriptControl_ExecuteStatement(); test_IScriptControl_Run(); + test_IScriptControl_get_Modules();
init_registry(FALSE);