[PATCH] msscript.ocx: Implement the ScriptProcedure enumerator.

Gabriel Ivăncescu gabrielopcode at gmail.com
Mon Aug 17 10:33:51 CDT 2020


Signed-off-by: Gabriel Ivăncescu <gabrielopcode at 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




More information about the wine-devel mailing list