| /* |
| * Copyright 2014 Dmitry Timoshkov |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
| */ |
| |
| #include <stdarg.h> |
| |
| #define COBJMACROS |
| |
| #include "windef.h" |
| #include "winbase.h" |
| #include "objbase.h" |
| #include "taskschd.h" |
| #include "schrpc.h" |
| #include "taskschd_private.h" |
| |
| #include "wine/unicode.h" |
| #include "wine/debug.h" |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(taskschd); |
| |
| typedef struct |
| { |
| ITaskFolderCollection ITaskFolderCollection_iface; |
| LONG ref; |
| WCHAR *path; |
| TASK_NAMES list; |
| DWORD count; |
| } TaskFolderCollection; |
| |
| static HRESULT NewEnum_create(TaskFolderCollection *folders, IUnknown **obj); |
| |
| static inline TaskFolderCollection *impl_from_ITaskFolderCollection(ITaskFolderCollection *iface) |
| { |
| return CONTAINING_RECORD(iface, TaskFolderCollection, ITaskFolderCollection_iface); |
| } |
| |
| static ULONG WINAPI folders_AddRef(ITaskFolderCollection *iface) |
| { |
| TaskFolderCollection *folders = impl_from_ITaskFolderCollection(iface); |
| return InterlockedIncrement(&folders->ref); |
| } |
| |
| static void free_list(LPWSTR *list, DWORD count) |
| { |
| LONG i; |
| |
| for (i = 0; i < count; i++) |
| MIDL_user_free(list[i]); |
| |
| MIDL_user_free(list); |
| } |
| |
| static ULONG WINAPI folders_Release(ITaskFolderCollection *iface) |
| { |
| TaskFolderCollection *folders = impl_from_ITaskFolderCollection(iface); |
| LONG ref = InterlockedDecrement(&folders->ref); |
| |
| if (!ref) |
| { |
| TRACE("destroying %p\n", iface); |
| free_list(folders->list, folders->count); |
| heap_free(folders->path); |
| heap_free(folders); |
| } |
| |
| return ref; |
| } |
| |
| static HRESULT WINAPI folders_QueryInterface(ITaskFolderCollection *iface, REFIID riid, void **obj) |
| { |
| if (!riid || !obj) return E_INVALIDARG; |
| |
| TRACE("%p,%s,%p\n", iface, debugstr_guid(riid), obj); |
| |
| if (IsEqualGUID(riid, &IID_ITaskFolderCollection) || |
| IsEqualGUID(riid, &IID_IDispatch) || |
| IsEqualGUID(riid, &IID_IUnknown)) |
| { |
| ITaskFolderCollection_AddRef(iface); |
| *obj = iface; |
| return S_OK; |
| } |
| |
| FIXME("interface %s is not implemented\n", debugstr_guid(riid)); |
| *obj = NULL; |
| return E_NOINTERFACE; |
| } |
| |
| static HRESULT WINAPI folders_GetTypeInfoCount(ITaskFolderCollection *iface, UINT *count) |
| { |
| FIXME("%p,%p: stub\n", iface, count); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI folders_GetTypeInfo(ITaskFolderCollection *iface, UINT index, LCID lcid, ITypeInfo **info) |
| { |
| FIXME("%p,%u,%u,%p: stub\n", iface, index, lcid, info); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI folders_GetIDsOfNames(ITaskFolderCollection *iface, REFIID riid, LPOLESTR *names, |
| UINT count, LCID lcid, DISPID *dispid) |
| { |
| FIXME("%p,%s,%p,%u,%u,%p: stub\n", iface, debugstr_guid(riid), names, count, lcid, dispid); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI folders_Invoke(ITaskFolderCollection *iface, DISPID dispid, REFIID riid, LCID lcid, WORD flags, |
| DISPPARAMS *params, VARIANT *result, EXCEPINFO *excepinfo, UINT *argerr) |
| { |
| FIXME("%p,%d,%s,%04x,%04x,%p,%p,%p,%p: stub\n", iface, dispid, debugstr_guid(riid), lcid, flags, |
| params, result, excepinfo, argerr); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI folders_get_Count(ITaskFolderCollection *iface, LONG *count) |
| { |
| TaskFolderCollection *folders = impl_from_ITaskFolderCollection(iface); |
| |
| TRACE("%p,%p\n", iface, count); |
| |
| if (!count) return E_POINTER; |
| |
| *count = folders->count; |
| |
| return S_OK; |
| } |
| |
| static LONG get_var_int(const VARIANT *var) |
| { |
| switch(V_VT(var)) |
| { |
| case VT_I1: |
| case VT_UI1: |
| return V_UI1(var); |
| |
| case VT_I2: |
| case VT_UI2: |
| return V_UI2(var); |
| |
| case VT_I4: |
| case VT_UI4: |
| return V_UI4(var); |
| |
| case VT_I8: |
| case VT_UI8: |
| return V_UI8(var); |
| |
| case VT_INT: |
| case VT_UINT: |
| return V_UINT(var); |
| |
| default: |
| FIXME("unsupported variant type %d\n", V_VT(var)); |
| return 0; |
| } |
| } |
| |
| static HRESULT WINAPI folders_get_Item(ITaskFolderCollection *iface, VARIANT index, ITaskFolder **folder) |
| { |
| TaskFolderCollection *folders = impl_from_ITaskFolderCollection(iface); |
| LONG idx; |
| |
| TRACE("%p,%s,%p\n", iface, debugstr_variant(&index), folder); |
| |
| if (!folder) return E_POINTER; |
| |
| if (V_VT(&index) == VT_BSTR) |
| return TaskFolder_create(folders->path, V_BSTR(&index), folder, FALSE); |
| |
| idx = get_var_int(&index); |
| /* collections are 1 based */ |
| if (idx < 1 || idx > folders->count) |
| return E_INVALIDARG; |
| |
| return TaskFolder_create(folders->path, folders->list[idx - 1], folder, FALSE); |
| } |
| |
| static HRESULT WINAPI folders_get__NewEnum(ITaskFolderCollection *iface, IUnknown **penum) |
| { |
| TaskFolderCollection *folders = impl_from_ITaskFolderCollection(iface); |
| |
| TRACE("%p,%p\n", iface, penum); |
| |
| if (!penum) return E_POINTER; |
| |
| return NewEnum_create(folders, penum); |
| } |
| |
| static const ITaskFolderCollectionVtbl TaskFolderCollection_vtbl = |
| { |
| folders_QueryInterface, |
| folders_AddRef, |
| folders_Release, |
| folders_GetTypeInfoCount, |
| folders_GetTypeInfo, |
| folders_GetIDsOfNames, |
| folders_Invoke, |
| folders_get_Count, |
| folders_get_Item, |
| folders_get__NewEnum |
| }; |
| |
| HRESULT TaskFolderCollection_create(const WCHAR *path, ITaskFolderCollection **obj) |
| { |
| TaskFolderCollection *folders; |
| HRESULT hr; |
| TASK_NAMES list; |
| DWORD start_index, count; |
| |
| start_index = 0; |
| list = NULL; |
| hr = SchRpcEnumFolders(path, 0, &start_index, 0, &count, &list); |
| if (hr != S_OK) return hr; |
| |
| folders = heap_alloc(sizeof(*folders)); |
| if (!folders) |
| { |
| free_list(list, count); |
| return E_OUTOFMEMORY; |
| } |
| |
| folders->ITaskFolderCollection_iface.lpVtbl = &TaskFolderCollection_vtbl; |
| folders->ref = 1; |
| folders->path = heap_strdupW(path); |
| folders->count = count; |
| folders->list = list; |
| *obj = &folders->ITaskFolderCollection_iface; |
| |
| TRACE("created %p\n", *obj); |
| |
| return S_OK; |
| } |
| |
| typedef struct |
| { |
| IEnumVARIANT IEnumVARIANT_iface; |
| LONG ref, pos; |
| TaskFolderCollection *folders; |
| } EnumVARIANT; |
| |
| static inline EnumVARIANT *impl_from_IEnumVARIANT(IEnumVARIANT *iface) |
| { |
| return CONTAINING_RECORD(iface, EnumVARIANT, IEnumVARIANT_iface); |
| } |
| |
| static HRESULT WINAPI enumvar_QueryInterface(IEnumVARIANT *iface, REFIID riid, void **obj) |
| { |
| if (!riid || !obj) return E_INVALIDARG; |
| |
| TRACE("%p,%s,%p\n", iface, debugstr_guid(riid), obj); |
| |
| if (IsEqualGUID(riid, &IID_IEnumVARIANT) || |
| IsEqualGUID(riid, &IID_IUnknown)) |
| { |
| IEnumVARIANT_AddRef(iface); |
| *obj = iface; |
| return S_OK; |
| } |
| |
| FIXME("interface %s is not implemented\n", debugstr_guid(riid)); |
| *obj = NULL; |
| return E_NOINTERFACE; |
| } |
| |
| static ULONG WINAPI enumvar_AddRef(IEnumVARIANT *iface) |
| { |
| EnumVARIANT *enumvar = impl_from_IEnumVARIANT(iface); |
| return InterlockedIncrement(&enumvar->ref); |
| } |
| |
| static ULONG WINAPI enumvar_Release(IEnumVARIANT *iface) |
| { |
| EnumVARIANT *enumvar = impl_from_IEnumVARIANT(iface); |
| LONG ref = InterlockedDecrement(&enumvar->ref); |
| |
| if (!ref) |
| { |
| TRACE("destroying %p\n", iface); |
| ITaskFolderCollection_Release(&enumvar->folders->ITaskFolderCollection_iface); |
| heap_free(enumvar); |
| } |
| |
| return ref; |
| } |
| |
| static HRESULT WINAPI enumvar_Next(IEnumVARIANT *iface, ULONG celt, VARIANT *var, ULONG *fetched) |
| { |
| EnumVARIANT *enumvar = impl_from_IEnumVARIANT(iface); |
| LONG i; |
| |
| TRACE("%p,%u,%p,%p\n", iface, celt, var, fetched); |
| |
| for (i = 0; i < celt && enumvar->pos < enumvar->folders->count; i++) |
| { |
| ITaskFolder *folder; |
| HRESULT hr; |
| |
| hr = TaskFolder_create(enumvar->folders->path, enumvar->folders->list[enumvar->pos++], &folder, FALSE); |
| if (hr) return hr; |
| |
| if (!var) |
| { |
| ITaskFolder_Release(folder); |
| return E_POINTER; |
| } |
| |
| V_VT(&var[i]) = VT_DISPATCH; |
| V_DISPATCH(&var[i]) = (IDispatch *)folder; |
| } |
| |
| if (fetched) *fetched = i; |
| |
| return i == celt ? S_OK : S_FALSE; |
| } |
| |
| static HRESULT WINAPI enumvar_Skip(IEnumVARIANT *iface, ULONG celt) |
| { |
| EnumVARIANT *enumvar = impl_from_IEnumVARIANT(iface); |
| |
| TRACE("%p,%u\n", iface, celt); |
| |
| enumvar->pos += celt; |
| |
| if (enumvar->pos > enumvar->folders->count) |
| { |
| enumvar->pos = enumvar->folders->count; |
| return S_FALSE; |
| } |
| |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI enumvar_Reset(IEnumVARIANT *iface) |
| { |
| EnumVARIANT *enumvar = impl_from_IEnumVARIANT(iface); |
| |
| TRACE("%p\n", iface); |
| |
| enumvar->pos = 0; |
| |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI enumvar_Clone(IEnumVARIANT *iface, IEnumVARIANT **penum) |
| { |
| EnumVARIANT *enumvar = impl_from_IEnumVARIANT(iface); |
| |
| TRACE("%p,%p\n", iface, penum); |
| |
| return NewEnum_create(enumvar->folders, (IUnknown **)penum); |
| } |
| |
| static const struct IEnumVARIANTVtbl EnumVARIANT_vtbl = |
| { |
| enumvar_QueryInterface, |
| enumvar_AddRef, |
| enumvar_Release, |
| enumvar_Next, |
| enumvar_Skip, |
| enumvar_Reset, |
| enumvar_Clone |
| }; |
| |
| static HRESULT NewEnum_create(TaskFolderCollection *folders, IUnknown **obj) |
| { |
| EnumVARIANT *enumvar; |
| |
| enumvar = heap_alloc(sizeof(*enumvar)); |
| if (!enumvar) return E_OUTOFMEMORY; |
| |
| enumvar->IEnumVARIANT_iface.lpVtbl = &EnumVARIANT_vtbl; |
| enumvar->ref = 1; |
| enumvar->pos = 0; |
| enumvar->folders = folders; |
| ITaskFolderCollection_AddRef(&folders->ITaskFolderCollection_iface); |
| |
| *obj = (IUnknown *)&enumvar->IEnumVARIANT_iface; |
| |
| TRACE("created %p\n", *obj); |
| |
| return S_OK; |
| } |