From: Oleg Nikulin <owl2@etersoft.ru> Implement Actions_get_Count() to return action count, implement Actions_get_Item() to retrieve actions, modify Actions_Create() to add newly created actions to the internal list, implement Actions_Clear() to clear the internal list. Add tests for IActionCollection. --- dlls/taskschd/task.c | 77 ++++++++++++++++++++++++++++++--- dlls/taskschd/tests/scheduler.c | 70 ++++++++++++++++++++++++++++++ 2 files changed, 140 insertions(+), 7 deletions(-) diff --git a/dlls/taskschd/task.c b/dlls/taskschd/task.c index 7525a52566d..419af3dc753 100644 --- a/dlls/taskschd/task.c +++ b/dlls/taskschd/task.c @@ -2783,6 +2783,8 @@ typedef struct { IActionCollection IActionCollection_iface; LONG ref; + IAction **list; + LONG count; } Actions; static inline Actions *impl_from_IActionCollection(IActionCollection *iface) @@ -2796,6 +2798,16 @@ static ULONG WINAPI Actions_AddRef(IActionCollection *iface) return InterlockedIncrement(&actions->ref); } +static void free_list(IAction **list, LONG count) +{ + LONG i; + + for (i = 0; i < count; i++) + IAction_Release(list[i]); + + free(list); +} + static ULONG WINAPI Actions_Release(IActionCollection *iface) { Actions *actions = impl_from_IActionCollection(iface); @@ -2804,6 +2816,7 @@ static ULONG WINAPI Actions_Release(IActionCollection *iface) if (!ref) { TRACE("destroying %p\n", iface); + free_list(actions->list, actions->count); free(actions); } @@ -2859,14 +2872,35 @@ static HRESULT WINAPI Actions_Invoke(IActionCollection *iface, DISPID dispid, RE static HRESULT WINAPI Actions_get_Count(IActionCollection *iface, LONG *count) { - FIXME("%p,%p: stub\n", iface, count); - return E_NOTIMPL; + Actions *actions = impl_from_IActionCollection(iface); + + TRACE("%p,%p\n", iface, count); + + if (!count) return E_POINTER; + + *count = actions->count; + + return S_OK; } static HRESULT WINAPI Actions_get_Item(IActionCollection *iface, LONG index, IAction **action) { - FIXME("%p,%ld,%p: stub\n", iface, index, action); - return E_NOTIMPL; + Actions *actions = impl_from_IActionCollection(iface); + + TRACE("%p,%ld,%p\n", iface, index, action); + + if (!action) return E_POINTER; + + /* collections are 1 based */ + if (index < 1) + return E_INVALIDARG; + if (index > actions->count) + return E_FAIL; + + *action = actions->list[index - 1]; + IAction_AddRef(*action); + + return S_OK; } static HRESULT WINAPI Actions_get__NewEnum(IActionCollection *iface, IUnknown **penum) @@ -2889,17 +2923,37 @@ static HRESULT WINAPI Actions_put_XmlText(IActionCollection *iface, BSTR xml) static HRESULT WINAPI Actions_Create(IActionCollection *iface, TASK_ACTION_TYPE type, IAction **action) { + Actions *actions = impl_from_IActionCollection(iface); + HRESULT hr; + TRACE("%p,%u,%p\n", iface, type, action); switch (type) { case TASK_ACTION_EXEC: - return ExecAction_create((IExecAction **)action); + hr = ExecAction_create((IExecAction **)action); + break; default: FIXME("unimplemented type %u\n", type); return E_NOTIMPL; } + + if (SUCCEEDED(hr)) + { + IAction **new_array = realloc(actions->list, (actions->count + 1) * sizeof(*new_array)); + if (!new_array) + { + IAction_Release(*action); + *action = NULL; + return E_OUTOFMEMORY; + } + actions->list = new_array; + actions->list[actions->count++] = *action; + IAction_AddRef(*action); + } + + return hr; } static HRESULT WINAPI Actions_Remove(IActionCollection *iface, VARIANT index) @@ -2910,8 +2964,15 @@ static HRESULT WINAPI Actions_Remove(IActionCollection *iface, VARIANT index) static HRESULT WINAPI Actions_Clear(IActionCollection *iface) { - FIXME("%p: stub\n", iface); - return E_NOTIMPL; + Actions *actions = impl_from_IActionCollection(iface); + + TRACE("%p\n", iface); + + free_list(actions->list, actions->count); + actions->list = NULL; + actions->count = 0; + + return S_OK; } static HRESULT WINAPI Actions_get_Context(IActionCollection *iface, BSTR *ctx) @@ -2956,6 +3017,8 @@ static HRESULT Actions_create(IActionCollection **obj) actions->IActionCollection_iface.lpVtbl = &Actions_vtbl; actions->ref = 1; + actions->list = NULL; + actions->count = 0; *obj = &actions->IActionCollection_iface; diff --git a/dlls/taskschd/tests/scheduler.c b/dlls/taskschd/tests/scheduler.c index 025522f322c..99fc7ff9d06 100644 --- a/dlls/taskschd/tests/scheduler.c +++ b/dlls/taskschd/tests/scheduler.c @@ -1640,6 +1640,69 @@ static void create_action(ITaskDefinition *taskdef) IActionCollection_Release(actions); } +static void test_action_collection(IActionCollection *actions_col) +{ + IAction *action; + HRESULT hr; + LONG count; + + /* Collection may already contain actions parsed from XML */ + hr = IActionCollection_Clear(actions_col); + ok(hr == S_OK, "Clear failed: %08lx\n", hr); + + hr = IActionCollection_get_Count(actions_col, NULL); + ok(hr == E_POINTER, "expected E_POINTER, got %#lx\n", hr); + + count = -1; + hr = IActionCollection_get_Count(actions_col, &count); + ok(hr == S_OK, "get_Count failed: %08lx\n", hr); + ok(count == 0, "expected 0, got %ld\n", count); + + hr = IActionCollection_get_Item(actions_col, 1, NULL); + ok(hr == E_POINTER, "expected E_POINTER, got %#lx\n", hr); + + hr = IActionCollection_get_Item(actions_col, 1, &action); + ok(hr == E_FAIL, "expected E_FAIL, got %#lx\n", hr); + + hr = IActionCollection_Create(actions_col, TASK_ACTION_EXEC, &action); + ok(hr == S_OK, "Create failed: %08lx\n", hr); + IAction_Release(action); + + hr = IActionCollection_Create(actions_col, TASK_ACTION_EXEC, &action); + ok(hr == S_OK, "Create failed: %08lx\n", hr); + IAction_Release(action); + + count = -1; + hr = IActionCollection_get_Count(actions_col, &count); + ok(hr == S_OK, "get_Count failed: %08lx\n", hr); + ok(count == 2, "expected 2, got %ld\n", count); + + hr = IActionCollection_get_Item(actions_col, 0, &action); + ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got %#lx\n", hr); + + hr = IActionCollection_get_Item(actions_col, 3, &action); + ok(hr == E_FAIL, "expected E_FAIL, got %#lx\n", hr); + + hr = IActionCollection_get_Item(actions_col, 1, &action); + ok(hr == S_OK, "get_Item failed: %08lx\n", hr); + IAction_Release(action); + + hr = IActionCollection_get_Item(actions_col, 2, &action); + ok(hr == S_OK, "get_Item failed: %08lx\n", hr); + IAction_Release(action); + + hr = IActionCollection_Clear(actions_col); + ok(hr == S_OK, "Clear failed: %08lx\n", hr); + + count = -1; + hr = IActionCollection_get_Count(actions_col, &count); + ok(hr == S_OK, "get_Count failed: %08lx\n", hr); + ok(count == 0, "expected 0, got %ld\n", count); + + hr = IActionCollection_get_Item(actions_col, 1, &action); + ok(hr == E_FAIL, "expected E_FAIL, got %#lx\n", hr); +} + static void test_TaskDefinition(void) { static WCHAR xml0[] = L""; @@ -1742,6 +1805,7 @@ static void test_TaskDefinition(void) VARIANT_FALSE, VARIANT_FALSE, VARIANT_TRUE, VARIANT_TRUE, VARIANT_FALSE, VARIANT_TRUE, VARIANT_TRUE, VARIANT_TRUE }; ITriggerCollection *trigger_col, *trigger_col2; + IActionCollection *actions_col; HRESULT hr; ITaskService *service; ITaskDefinition *taskdef; @@ -1960,6 +2024,12 @@ static void test_TaskDefinition(void) ok(trigger_col == trigger_col2, "Mismatched triggers\n"); ITriggerCollection_Release(trigger_col2); + hr = ITaskDefinition_get_Actions(taskdef, &actions_col); + ok(hr == S_OK, "get_Actions failed: %08lx\n", hr); + ok(actions_col != NULL, "Actions = NULL\n"); + test_action_collection(actions_col); + IActionCollection_Release(actions_col); + IRegistrationInfo_Release(reginfo); ITaskDefinition_Release(taskdef); ITaskService_Release(service); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11065