msscript.ocx: Implement the ScriptProcedure enumerator.

Signed-off-by: Gabriel Ivăncescu <gabrielopcode@gmail.com>
Signed-off-by: Jacek Caban <jacek@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Gabriel Ivăncescu 2020-08-17 18:33:51 +03:00 committed by Alexandre Julliard
parent 6e0e890fba
commit 3a9c50e3ff
2 changed files with 272 additions and 2 deletions

View File

@ -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,

View File

@ -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);