Signed-off-by: Gabriel Ivăncescu <gabrielopcode(a)gmail.com>
---
dlls/msscript.ocx/msscript.c | 194 ++++++++++++++++++++++++++++-
dlls/msscript.ocx/tests/msscript.c | 80 ++++++++++++
2 files changed, 272 insertions(+), 2 deletions(-)
diff --git a/dlls/msscript.ocx/msscript.c b/dlls/msscript.ocx/msscript.c
index a339e70..d493065 100644
--- a/dlls/msscript.ocx/msscript.c
+++ b/dlls/msscript.ocx/msscript.c
@@ -110,6 +110,15 @@ struct ScriptProcedureCollection {
struct list hash_table[43];
};
+struct procedure_enum {
+ IEnumVARIANT IEnumVARIANT_iface;
+ LONG ref;
+
+ WORD pos;
+ WORD count;
+ ScriptProcedureCollection *procedures;
+};
+
struct ScriptHost {
IActiveScriptSite IActiveScriptSite_iface;
IActiveScriptSiteWindow IActiveScriptSiteWindow_iface;
@@ -532,6 +541,11 @@ static inline struct module_enum *module_enum_from_IEnumVARIANT(IEnumVARIANT *if
return CONTAINING_RECORD(iface, struct module_enum, IEnumVARIANT_iface);
}
+static inline struct procedure_enum *procedure_enum_from_IEnumVARIANT(IEnumVARIANT *iface)
+{
+ return CONTAINING_RECORD(iface, struct procedure_enum, IEnumVARIANT_iface);
+}
+
/* IActiveScriptSite */
static HRESULT WINAPI ActiveScriptSite_QueryInterface(IActiveScriptSite *iface, REFIID riid, void **ppv)
{
@@ -976,6 +990,151 @@ done:
return hr;
}
+static HRESULT WINAPI procedure_enum_QueryInterface(IEnumVARIANT *iface, REFIID riid, void **ppv)
+{
+ struct procedure_enum *This = procedure_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 procedure_enum_AddRef(IEnumVARIANT *iface)
+{
+ struct procedure_enum *This = procedure_enum_from_IEnumVARIANT(iface);
+ LONG ref = InterlockedIncrement(&This->ref);
+
+ TRACE("(%p) ref=%d\n", This, ref);
+
+ return ref;
+}
+
+static ULONG WINAPI procedure_enum_Release(IEnumVARIANT *iface)
+{
+ struct procedure_enum *This = procedure_enum_from_IEnumVARIANT(iface);
+ LONG ref = InterlockedDecrement(&This->ref);
+
+ TRACE("(%p) ref=%d\n", This, ref);
+
+ if (!ref)
+ {
+ IScriptProcedureCollection_Release(&This->procedures->IScriptProcedureCollection_iface);
+ heap_free(This);
+ }
+
+ return ref;
+}
+
+static HRESULT WINAPI procedure_enum_Next(IEnumVARIANT *iface, ULONG celt, VARIANT *rgVar, ULONG *pCeltFetched)
+{
+ struct procedure_enum *This = procedure_enum_from_IEnumVARIANT(iface);
+ FUNCDESC *desc;
+ ITypeInfo *ti;
+ UINT i, num;
+ HRESULT hr;
+
+ TRACE("(%p)->(%u %p %p)\n", This, celt, rgVar, pCeltFetched);
+
+ if (!rgVar) return E_POINTER;
+ if (!This->procedures->module->host) return E_FAIL;
+
+ hr = start_script(This->procedures->module->host);
+ if (FAILED(hr)) return hr;
+
+ hr = get_script_typeinfo(This->procedures->module, &ti);
+ if (FAILED(hr)) return hr;
+
+ num = min(celt, This->count - This->pos);
+ for (i = 0; i < num; i++)
+ {
+ hr = ITypeInfo_GetFuncDesc(ti, This->pos + i, &desc);
+ if (FAILED(hr)) break;
+
+ hr = get_script_procedure(This->procedures, ti, desc, (IScriptProcedure**)&V_DISPATCH(rgVar + i));
+ if (FAILED(hr)) break;
+
+ V_VT(rgVar + i) = VT_DISPATCH;
+ }
+
+ if (FAILED(hr))
+ {
+ while (i--)
+ VariantClear(rgVar + i);
+ if (pCeltFetched) *pCeltFetched = 0;
+ return hr;
+ }
+
+ This->pos += i;
+
+ if (pCeltFetched) *pCeltFetched = i;
+ return i == celt ? S_OK : S_FALSE;
+}
+
+static HRESULT WINAPI procedure_enum_Skip(IEnumVARIANT *iface, ULONG celt)
+{
+ struct procedure_enum *This = procedure_enum_from_IEnumVARIANT(iface);
+
+ TRACE("(%p)->(%u)\n", This, celt);
+
+ if (This->count - This->pos < celt)
+ {
+ This->pos = This->count;
+ return S_FALSE;
+ }
+ This->pos += celt;
+ return S_OK;
+}
+
+static HRESULT WINAPI procedure_enum_Reset(IEnumVARIANT *iface)
+{
+ struct procedure_enum *This = procedure_enum_from_IEnumVARIANT(iface);
+
+ TRACE("(%p)\n", This);
+
+ This->pos = 0;
+ return S_OK;
+}
+
+static HRESULT WINAPI procedure_enum_Clone(IEnumVARIANT *iface, IEnumVARIANT **ppEnum)
+{
+ struct procedure_enum *This = procedure_enum_from_IEnumVARIANT(iface);
+ struct procedure_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;
+ IScriptProcedureCollection_AddRef(&This->procedures->IScriptProcedureCollection_iface);
+
+ *ppEnum = &clone->IEnumVARIANT_iface;
+ return S_OK;
+}
+
+static const IEnumVARIANTVtbl procedure_enum_vtbl = {
+ procedure_enum_QueryInterface,
+ procedure_enum_AddRef,
+ procedure_enum_Release,
+ procedure_enum_Next,
+ procedure_enum_Skip,
+ procedure_enum_Reset,
+ procedure_enum_Clone
+};
+
static HRESULT WINAPI ScriptProcedureCollection_QueryInterface(IScriptProcedureCollection *iface, REFIID riid, void **ppv)
{
ScriptProcedureCollection *This = impl_from_IScriptProcedureCollection(iface);
@@ -1091,10 +1250,41 @@ static HRESULT WINAPI ScriptProcedureCollection_Invoke(IScriptProcedureCollectio
static HRESULT WINAPI ScriptProcedureCollection_get__NewEnum(IScriptProcedureCollection *iface, IUnknown **ppenumProcedures)
{
ScriptProcedureCollection *This = impl_from_IScriptProcedureCollection(iface);
+ struct procedure_enum *proc_enum;
+ TYPEATTR *attr;
+ ITypeInfo *ti;
+ UINT count;
+ HRESULT hr;
- FIXME("(%p)->(%p)\n", This, ppenumProcedures);
+ TRACE("(%p)->(%p)\n", This, ppenumProcedures);
- return E_NOTIMPL;
+ if (!ppenumProcedures) return E_POINTER;
+ if (!This->module->host) return E_FAIL;
+
+ hr = start_script(This->module->host);
+ if (FAILED(hr)) return hr;
+
+ hr = get_script_typeinfo(This->module, &ti);
+ if (FAILED(hr)) return hr;
+
+ hr = ITypeInfo_GetTypeAttr(ti, &attr);
+ if (FAILED(hr)) return hr;
+
+ count = attr->cFuncs;
+ ITypeInfo_ReleaseTypeAttr(ti, attr);
+
+ if (!(proc_enum = heap_alloc(sizeof(*proc_enum))))
+ return E_OUTOFMEMORY;
+
+ proc_enum->IEnumVARIANT_iface.lpVtbl = &procedure_enum_vtbl;
+ proc_enum->ref = 1;
+ proc_enum->pos = 0;
+ proc_enum->count = count;
+ proc_enum->procedures = This;
+ IScriptProcedureCollection_AddRef(&This->IScriptProcedureCollection_iface);
+
+ *ppenumProcedures = (IUnknown*)&proc_enum->IEnumVARIANT_iface;
+ return S_OK;
}
static HRESULT WINAPI ScriptProcedureCollection_get_Item(IScriptProcedureCollection *iface, VARIANT index,
diff --git a/dlls/msscript.ocx/tests/msscript.c b/dlls/msscript.ocx/tests/msscript.c
index 7233af5..085913a 100644
--- a/dlls/msscript.ocx/tests/msscript.c
+++ b/dlls/msscript.ocx/tests/msscript.c
@@ -3293,9 +3293,12 @@ static void test_IScriptControl_get_CodeObject(void)
static void test_IScriptControl_get_Procedures(void)
{
IScriptProcedureCollection *procs, *procs2;
+ IEnumVARIANT *enumvar, *enumvar2;
IScriptProcedure *proc, *proc2;
IScriptControl *sc;
+ IUnknown *unknown;
VARIANT_BOOL vbool;
+ ULONG fetched;
VARIANT var;
LONG count;
HRESULT hr;
@@ -3548,6 +3551,44 @@ static void test_IScriptControl_get_Procedures(void)
ok(hr == E_INVALIDARG, "IScriptProcedureCollection_get_Item returned: 0x%08x.\n", hr);
CHECK_CALLED(GetFuncDesc);
+ /* _NewEnum never caches the function count */
+ hr = IScriptProcedureCollection_get__NewEnum(procs, NULL);
+ ok(hr == E_POINTER, "IScriptProcedureCollection_get__NewEnum returned: 0x%08x.\n", hr);
+ SET_EXPECT(GetTypeAttr);
+ SET_EXPECT(ReleaseTypeAttr);
+ hr = IScriptProcedureCollection_get__NewEnum(procs, &unknown);
+ ok(hr == S_OK, "IScriptProcedureCollection_get__NewEnum failed: 0x%08x.\n", hr);
+ CHECK_CALLED(GetTypeAttr);
+ CHECK_CALLED(ReleaseTypeAttr);
+ 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);
+ IEnumVARIANT_Release(enumvar);
+ IUnknown_Release(unknown);
+ SET_EXPECT(GetTypeAttr);
+ SET_EXPECT(ReleaseTypeAttr);
+ hr = IScriptProcedureCollection_get__NewEnum(procs, &unknown);
+ ok(hr == S_OK, "IScriptProcedureCollection_get__NewEnum failed: 0x%08x.\n", hr);
+ CHECK_CALLED(GetTypeAttr);
+ CHECK_CALLED(ReleaseTypeAttr);
+ hr = IUnknown_QueryInterface(unknown, &IID_IEnumVARIANT, (void**)&enumvar);
+ ok(hr == S_OK, "Failed to query for IEnumVARIANT: 0x%08x.\n", hr);
+ IUnknown_Release(unknown);
+
+ 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);
+
for (i = 0; i < ARRAY_SIZE(custom_engine_funcs); i++)
{
/* Querying by index still goes through the Bind process */
@@ -3583,6 +3624,25 @@ static void test_IScriptControl_get_Procedures(void)
CHECK_CALLED(GetNames);
CHECK_CALLED(ReleaseFuncDesc);
+ /* Compare with the enumerator */
+ SET_EXPECT(GetFuncDesc);
+ SET_EXPECT(GetNames);
+ SET_EXPECT(ReleaseFuncDesc);
+ hr = IEnumVARIANT_Next(enumvar, 1, &var, &fetched);
+ ok(hr == S_OK, "IEnumVARIANT_Next for index %u failed: 0x%08x.\n", i, hr);
+ ok(fetched == 1, "got %u.\n", fetched);
+ ok(V_VT(&var) == VT_DISPATCH, "V_VT(var) = %d.\n", V_VT(&var));
+ CHECK_CALLED(GetFuncDesc);
+ CHECK_CALLED(GetNames);
+ CHECK_CALLED(ReleaseFuncDesc);
+ hr = IDispatch_QueryInterface(V_DISPATCH(&var), &IID_IScriptProcedure, (void**)&proc2);
+ ok(hr == S_OK, "Failed to query IScriptProcedure for index %u: 0x%08x.\n", i, hr);
+ VariantClear(&var);
+
+ ok(proc == proc2, "proc and proc2 are not the same for %s and enum index %u.\n",
+ wine_dbgstr_w(custom_engine_funcs[i].name), i);
+ IScriptProcedure_Release(proc2);
+
/* Verify the properties */
hr = IScriptProcedure_get_Name(proc, &str);
ok(hr == S_OK, "get_Name for %s failed: 0x%08x.\n", wine_dbgstr_w(custom_engine_funcs[i].name), hr);
@@ -3601,6 +3661,26 @@ static void test_IScriptControl_get_Procedures(void)
IScriptProcedure_Release(proc);
}
+ 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_Reset(enumvar);
+ ok(hr == S_OK, "IEnumVARIANT_Reset failed: 0x%08x.\n", hr);
+ hr = IEnumVARIANT_Skip(enumvar, ARRAY_SIZE(custom_engine_funcs) - 1);
+ ok(hr == S_OK, "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_OK, "IEnumVARIANT_Skip 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);
IScriptProcedureCollection_Release(procs);
IActiveScriptSite_Release(site);
--
2.21.0