taskschd: Make ITaskFolder::CreateFolder, ITaskFolder::GetFolder and ITaskFolder...
[wine.git] / dlls / taskschd / folder.c
blob6bb0c38002b45d5dab1a8e57a4ec2d9b2b7c3729
1 /*
2 * Copyright 2014 Dmitry Timoshkov
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include <stdarg.h>
21 #define COBJMACROS
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winreg.h"
26 #include "objbase.h"
27 #include "taskschd.h"
28 #include "schrpc.h"
29 #include "taskschd_private.h"
31 #include "wine/unicode.h"
32 #include "wine/debug.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(taskschd);
36 static const char root[] = "Software\\Microsoft\\Windows NT\\CurrentVersion\\Schedule\\TaskCache\\Tree";
38 typedef struct
40 ITaskFolder ITaskFolder_iface;
41 LONG ref;
42 WCHAR *path;
43 } TaskFolder;
45 static inline TaskFolder *impl_from_ITaskFolder(ITaskFolder *iface)
47 return CONTAINING_RECORD(iface, TaskFolder, ITaskFolder_iface);
50 static ULONG WINAPI TaskFolder_AddRef(ITaskFolder *iface)
52 TaskFolder *folder = impl_from_ITaskFolder(iface);
53 return InterlockedIncrement(&folder->ref);
56 static ULONG WINAPI TaskFolder_Release(ITaskFolder *iface)
58 TaskFolder *folder = impl_from_ITaskFolder(iface);
59 LONG ref = InterlockedDecrement(&folder->ref);
61 if (!ref)
63 TRACE("destroying %p\n", iface);
64 heap_free(folder->path);
65 heap_free(folder);
68 return ref;
71 static HRESULT WINAPI TaskFolder_QueryInterface(ITaskFolder *iface, REFIID riid, void **obj)
73 if (!riid || !obj) return E_INVALIDARG;
75 TRACE("%p,%s,%p\n", iface, debugstr_guid(riid), obj);
77 if (IsEqualGUID(riid, &IID_ITaskFolder) ||
78 IsEqualGUID(riid, &IID_IDispatch) ||
79 IsEqualGUID(riid, &IID_IUnknown))
81 ITaskFolder_AddRef(iface);
82 *obj = iface;
83 return S_OK;
86 FIXME("interface %s is not implemented\n", debugstr_guid(riid));
87 *obj = NULL;
88 return E_NOINTERFACE;
91 static HRESULT WINAPI TaskFolder_GetTypeInfoCount(ITaskFolder *iface, UINT *count)
93 FIXME("%p,%p: stub\n", iface, count);
94 return E_NOTIMPL;
97 static HRESULT WINAPI TaskFolder_GetTypeInfo(ITaskFolder *iface, UINT index, LCID lcid, ITypeInfo **info)
99 FIXME("%p,%u,%u,%p: stub\n", iface, index, lcid, info);
100 return E_NOTIMPL;
103 static HRESULT WINAPI TaskFolder_GetIDsOfNames(ITaskFolder *iface, REFIID riid, LPOLESTR *names,
104 UINT count, LCID lcid, DISPID *dispid)
106 FIXME("%p,%s,%p,%u,%u,%p: stub\n", iface, debugstr_guid(riid), names, count, lcid, dispid);
107 return E_NOTIMPL;
110 static HRESULT WINAPI TaskFolder_Invoke(ITaskFolder *iface, DISPID dispid, REFIID riid, LCID lcid, WORD flags,
111 DISPPARAMS *params, VARIANT *result, EXCEPINFO *excepinfo, UINT *argerr)
113 FIXME("%p,%d,%s,%04x,%04x,%p,%p,%p,%p: stub\n", iface, dispid, debugstr_guid(riid), lcid, flags,
114 params, result, excepinfo, argerr);
115 return E_NOTIMPL;
118 static HRESULT WINAPI TaskFolder_get_Name(ITaskFolder *iface, BSTR *name)
120 TaskFolder *folder = impl_from_ITaskFolder(iface);
121 const WCHAR *p_name;
123 TRACE("%p,%p\n", iface, name);
125 if (!name) return E_POINTER;
127 p_name = strrchrW(folder->path, '\\');
128 if (!p_name)
129 p_name = folder->path;
130 else
131 if (p_name[1] != 0) p_name++;
133 *name = SysAllocString(p_name);
134 if (!*name) return E_OUTOFMEMORY;
136 return S_OK;
139 static HRESULT reg_create_folder(const WCHAR *path, HKEY *hfolder)
141 HKEY hroot;
142 DWORD ret, disposition;
144 ret = RegCreateKeyA(HKEY_LOCAL_MACHINE, root, &hroot);
145 if (ret) return HRESULT_FROM_WIN32(ret);
147 while (*path == '\\') path++;
148 ret = RegCreateKeyExW(hroot, path, 0, NULL, 0, KEY_ALL_ACCESS, NULL, hfolder, &disposition);
149 if (ret == ERROR_FILE_NOT_FOUND)
150 ret = ERROR_PATH_NOT_FOUND;
152 if (ret == ERROR_SUCCESS && disposition == REG_OPENED_EXISTING_KEY)
154 RegCloseKey(*hfolder);
155 ret = ERROR_ALREADY_EXISTS;
158 RegCloseKey(hroot);
160 return HRESULT_FROM_WIN32(ret);
163 static HRESULT reg_open_folder(const WCHAR *path, HKEY *hfolder)
165 HKEY hroot;
166 DWORD ret;
168 ret = RegCreateKeyA(HKEY_LOCAL_MACHINE, root, &hroot);
169 if (ret) return HRESULT_FROM_WIN32(ret);
171 while (*path == '\\') path++;
172 ret = RegOpenKeyExW(hroot, path, 0, KEY_ALL_ACCESS, hfolder);
173 if (ret == ERROR_FILE_NOT_FOUND)
174 ret = ERROR_PATH_NOT_FOUND;
176 RegCloseKey(hroot);
178 return HRESULT_FROM_WIN32(ret);
181 static HRESULT reg_delete_folder(const WCHAR *path, const WCHAR *name)
183 HKEY hroot, hfolder;
184 DWORD ret;
186 ret = RegCreateKeyA(HKEY_LOCAL_MACHINE, root, &hroot);
187 if (ret) return HRESULT_FROM_WIN32(ret);
189 while (*path == '\\') path++;
190 ret = RegOpenKeyExW(hroot, path, 0, DELETE, &hfolder);
192 RegCloseKey(hroot);
194 while (*name == '\\') name++;
195 if (ret == ERROR_SUCCESS)
197 ret = RegDeleteKeyW(hfolder, name);
198 RegCloseKey(hfolder);
201 return HRESULT_FROM_WIN32(ret);
204 static inline void reg_close_folder(HKEY hfolder)
206 RegCloseKey(hfolder);
209 static HRESULT WINAPI TaskFolder_get_Path(ITaskFolder *iface, BSTR *path)
211 TaskFolder *folder = impl_from_ITaskFolder(iface);
213 TRACE("%p,%p\n", iface, path);
215 if (!path) return E_POINTER;
217 *path = SysAllocString(folder->path);
218 if (!*path) return E_OUTOFMEMORY;
220 return S_OK;
223 static HRESULT WINAPI TaskFolder_GetFolder(ITaskFolder *iface, BSTR path, ITaskFolder **new_folder)
225 TaskFolder *folder = impl_from_ITaskFolder(iface);
227 TRACE("%p,%s,%p\n", iface, debugstr_w(path), folder);
229 if (!path) return E_INVALIDARG;
230 if (!new_folder) return E_POINTER;
232 return TaskFolder_create(folder->path, path, new_folder, FALSE);
235 static HRESULT WINAPI TaskFolder_GetFolders(ITaskFolder *iface, LONG flags, ITaskFolderCollection **folders)
237 TaskFolder *folder = impl_from_ITaskFolder(iface);
239 TRACE("%p,%x,%p: stub\n", iface, flags, folders);
241 if (!folders) return E_POINTER;
243 if (flags)
244 FIXME("unsupported flags %x\n", flags);
246 return TaskFolderCollection_create(folder->path, folders);
249 static inline BOOL is_variant_null(const VARIANT *var)
251 return V_VT(var) == VT_EMPTY || V_VT(var) == VT_NULL ||
252 (V_VT(var) == VT_BSTR && (V_BSTR(var) == NULL || !*V_BSTR(var)));
255 static HRESULT WINAPI TaskFolder_CreateFolder(ITaskFolder *iface, BSTR path, VARIANT sddl, ITaskFolder **new_folder)
257 TaskFolder *folder = impl_from_ITaskFolder(iface);
258 ITaskFolder *tmp_folder = NULL;
259 HRESULT hr;
261 TRACE("%p,%s,%s,%p\n", iface, debugstr_w(path), debugstr_variant(&sddl), folder);
263 if (!path) return E_INVALIDARG;
265 if (!new_folder) new_folder = &tmp_folder;
267 if (!is_variant_null(&sddl))
268 FIXME("security descriptor %s is ignored\n", debugstr_variant(&sddl));
270 hr = TaskFolder_create(folder->path, path, new_folder, TRUE);
271 if (tmp_folder)
272 ITaskFolder_Release(tmp_folder);
274 return hr;
277 static WCHAR *get_full_path(const WCHAR *parent, const WCHAR *path)
279 static const WCHAR bslash[] = { '\\', 0 };
280 WCHAR *folder_path;
281 int len = 0;
283 if (path) len = strlenW(path);
285 if (parent) len += strlenW(parent);
287 /* +1 if parent is not '\' terminated */
288 folder_path = heap_alloc((len + 2) * sizeof(WCHAR));
289 if (!folder_path) return NULL;
291 folder_path[0] = 0;
293 if (parent)
294 strcpyW(folder_path, parent);
296 if (path && *path)
298 len = strlenW(folder_path);
299 if (!len || folder_path[len - 1] != '\\')
300 strcatW(folder_path, bslash);
302 while (*path == '\\') path++;
303 strcatW(folder_path, path);
306 len = strlenW(folder_path);
307 if (!len)
308 strcatW(folder_path, bslash);
310 return folder_path;
313 static HRESULT WINAPI TaskFolder_DeleteFolder(ITaskFolder *iface, BSTR name, LONG flags)
315 TaskFolder *folder = impl_from_ITaskFolder(iface);
316 WCHAR *folder_path;
317 HRESULT hr;
319 TRACE("%p,%s,%x\n", iface, debugstr_w(name), flags);
321 if (!name || !*name) return E_ACCESSDENIED;
323 if (flags)
324 FIXME("unsupported flags %x\n", flags);
326 folder_path = get_full_path(folder->path, name);
327 if (!folder_path) return E_OUTOFMEMORY;
329 hr = SchRpcDelete(folder_path, 0);
330 heap_free(folder_path);
331 if (hr != S_OK) return hr;
333 return reg_delete_folder(folder->path, name);
336 static HRESULT WINAPI TaskFolder_GetTask(ITaskFolder *iface, BSTR name, IRegisteredTask **task)
338 TaskFolder *folder = impl_from_ITaskFolder(iface);
340 TRACE("%p,%s,%p\n", iface, debugstr_w(name), task);
342 if (!task) return E_POINTER;
344 return RegisteredTask_create(folder->path, name, NULL, 0, task, FALSE);
347 static HRESULT WINAPI TaskFolder_GetTasks(ITaskFolder *iface, LONG flags, IRegisteredTaskCollection **tasks)
349 TaskFolder *folder = impl_from_ITaskFolder(iface);
351 TRACE("%p,%x,%p: stub\n", iface, flags, tasks);
353 if (!tasks) return E_POINTER;
355 return RegisteredTaskCollection_create(folder->path, tasks);
358 static HRESULT WINAPI TaskFolder_DeleteTask(ITaskFolder *iface, BSTR name, LONG flags)
360 FIXME("%p,%s,%x: stub\n", iface, debugstr_w(name), flags);
361 return E_NOTIMPL;
364 static HRESULT WINAPI TaskFolder_RegisterTask(ITaskFolder *iface, BSTR name, BSTR xml, LONG flags,
365 VARIANT user, VARIANT password, TASK_LOGON_TYPE logon,
366 VARIANT sddl, IRegisteredTask **task)
368 ITaskDefinition *taskdef;
369 HRESULT hr;
371 TRACE("%p,%s,%s,%x,%s,%s,%d,%s,%p\n", iface, debugstr_w(name), debugstr_w(xml), flags,
372 debugstr_variant(&user), debugstr_variant(&password), logon, debugstr_variant(&sddl), task);
374 if (!xml) return HRESULT_FROM_WIN32(RPC_X_NULL_REF_POINTER);
376 hr = TaskDefinition_create(&taskdef);
377 if (hr != S_OK) return hr;
379 hr = ITaskDefinition_put_XmlText(taskdef, xml);
380 if (hr == S_OK)
381 hr = ITaskFolder_RegisterTaskDefinition(iface, name, taskdef, flags, user, password, logon, sddl, task);
383 ITaskDefinition_Release(taskdef);
384 return hr;
387 static HRESULT WINAPI TaskFolder_RegisterTaskDefinition(ITaskFolder *iface, BSTR name, ITaskDefinition *definition, LONG flags,
388 VARIANT user, VARIANT password, TASK_LOGON_TYPE logon,
389 VARIANT sddl, IRegisteredTask **task)
391 TaskFolder *folder = impl_from_ITaskFolder(iface);
392 IRegisteredTask *regtask = NULL;
393 HRESULT hr;
395 FIXME("%p,%s,%p,%x,%s,%s,%d,%s,%p: stub\n", iface, debugstr_w(name), definition, flags,
396 debugstr_variant(&user), debugstr_variant(&password), logon, debugstr_variant(&sddl), task);
398 if (!is_variant_null(&sddl))
399 FIXME("security descriptor %s is ignored\n", debugstr_variant(&sddl));
401 if (!is_variant_null(&user) || !is_variant_null(&password))
402 FIXME("user/password are ignored\n");
404 if (!task) task = &regtask;
406 hr = RegisteredTask_create(folder->path, name, definition, logon, task, TRUE);
408 if (regtask)
409 IRegisteredTask_Release(regtask);
411 return hr;
414 static HRESULT WINAPI TaskFolder_GetSecurityDescriptor(ITaskFolder *iface, LONG info, BSTR *sddl)
416 FIXME("%p,%x,%p: stub\n", iface, info, sddl);
417 return E_NOTIMPL;
420 static HRESULT WINAPI TaskFolder_SetSecurityDescriptor(ITaskFolder *iface, BSTR sddl, LONG flags)
422 FIXME("%p,%s,%x: stub\n", iface, debugstr_w(sddl), flags);
423 return E_NOTIMPL;
426 static const ITaskFolderVtbl TaskFolder_vtbl =
428 TaskFolder_QueryInterface,
429 TaskFolder_AddRef,
430 TaskFolder_Release,
431 TaskFolder_GetTypeInfoCount,
432 TaskFolder_GetTypeInfo,
433 TaskFolder_GetIDsOfNames,
434 TaskFolder_Invoke,
435 TaskFolder_get_Name,
436 TaskFolder_get_Path,
437 TaskFolder_GetFolder,
438 TaskFolder_GetFolders,
439 TaskFolder_CreateFolder,
440 TaskFolder_DeleteFolder,
441 TaskFolder_GetTask,
442 TaskFolder_GetTasks,
443 TaskFolder_DeleteTask,
444 TaskFolder_RegisterTask,
445 TaskFolder_RegisterTaskDefinition,
446 TaskFolder_GetSecurityDescriptor,
447 TaskFolder_SetSecurityDescriptor
450 HRESULT TaskFolder_create(const WCHAR *parent, const WCHAR *path, ITaskFolder **obj, BOOL create)
452 TaskFolder *folder;
453 WCHAR *folder_path;
454 HRESULT hr;
455 HKEY hfolder;
457 if (path)
459 int len = strlenW(path);
460 if (len && path[len - 1] == '\\') return ERROR_INVALID_NAME;
463 folder_path = get_full_path(parent, path);
464 if (!folder_path) return E_OUTOFMEMORY;
466 if (create)
468 hr = SchRpcCreateFolder(folder_path, NULL, 0);
470 else
472 DWORD start_index, count, i;
473 TASK_NAMES names;
475 start_index = 0;
476 names = NULL;
477 hr = SchRpcEnumFolders(folder_path, 0, &start_index, 0, &count, &names);
478 if (hr == S_OK)
480 for (i = 0; i < count; i++)
481 MIDL_user_free(names[i]);
482 MIDL_user_free(names);
484 else
486 if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
487 hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
491 if (FAILED(hr))
493 heap_free(folder_path);
494 return hr;
497 hr = create ? reg_create_folder(folder_path, &hfolder) : reg_open_folder(folder_path, &hfolder);
498 if (hr)
500 heap_free(folder_path);
501 return hr;
504 reg_close_folder(hfolder);
506 folder = heap_alloc(sizeof(*folder));
507 if (!folder)
509 heap_free(folder_path);
510 return E_OUTOFMEMORY;
513 folder->ITaskFolder_iface.lpVtbl = &TaskFolder_vtbl;
514 folder->ref = 1;
515 folder->path = folder_path;
516 *obj = &folder->ITaskFolder_iface;
518 TRACE("created %p\n", *obj);
520 return S_OK;