include/mscvpdb.h: Use flexible array members for the rest of structures.
[wine.git] / dlls / schedsvc / schedsvc.c
blob784fc5d944d021b4d94c76f1e9d71f888b12f887
1 /*
2 * Task Scheduler Service
4 * Copyright 2014 Dmitry Timoshkov
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
23 #define COBJMACROS
25 #include "windef.h"
26 #include "initguid.h"
27 #include "objbase.h"
28 #include "xmllite.h"
29 #include "schrpc.h"
30 #include "taskschd.h"
31 #include "wine/debug.h"
33 #include "schedsvc_private.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(schedsvc);
37 static const char bom_utf8[] = { 0xef,0xbb,0xbf };
39 struct task_info
41 BOOL enabled;
44 HRESULT __cdecl SchRpcHighestVersion(DWORD *version)
46 TRACE("%p\n", version);
48 *version = MAKELONG(3, 1);
49 return S_OK;
52 static WCHAR *get_full_name(const WCHAR *path, WCHAR **relative_path)
54 static const WCHAR tasksW[] = { '\\','t','a','s','k','s','\\',0 };
55 WCHAR *target;
56 int len;
58 len = GetSystemDirectoryW(NULL, 0);
59 len += lstrlenW(tasksW) + lstrlenW(path);
61 target = malloc(len * sizeof(WCHAR));
62 if (target)
64 GetSystemDirectoryW(target, len);
65 lstrcatW(target, tasksW);
66 if (relative_path)
67 *relative_path = target + lstrlenW(target) - 1;
68 while (*path == '\\') path++;
69 lstrcatW(target, path);
71 return target;
75 * Recursively create all directories in the path.
77 static HRESULT create_directory(const WCHAR *path)
79 HRESULT hr = S_OK;
80 WCHAR *new_path;
81 int len;
83 new_path = malloc((lstrlenW(path) + 1) * sizeof(WCHAR));
84 if (!new_path) return E_OUTOFMEMORY;
86 lstrcpyW(new_path, path);
88 len = lstrlenW(new_path);
89 while (len && new_path[len - 1] == '\\')
91 new_path[len - 1] = 0;
92 len--;
95 while (!CreateDirectoryW(new_path, NULL))
97 WCHAR *slash;
98 DWORD last_error = GetLastError();
100 if (last_error != ERROR_PATH_NOT_FOUND || !(slash = wcsrchr(new_path, '\\')))
102 hr = HRESULT_FROM_WIN32(last_error);
103 break;
106 len = slash - new_path;
107 new_path[len] = 0;
108 hr = create_directory(new_path);
109 if (hr != S_OK) break;
110 new_path[len] = '\\';
113 free(new_path);
114 return hr;
117 static HRESULT write_xml_utf8(const WCHAR *name, DWORD disposition, const WCHAR *xmlW)
119 static const char comment[] = "<!-- Task definition created by Wine -->\n";
120 HANDLE hfile;
121 DWORD size;
122 char *xml;
123 HRESULT hr = S_OK;
125 hfile = CreateFileW(name, GENERIC_WRITE, 0, NULL, disposition, 0, 0);
126 if (hfile == INVALID_HANDLE_VALUE)
128 if (GetLastError() == ERROR_FILE_EXISTS)
129 return HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS);
131 return HRESULT_FROM_WIN32(GetLastError());
134 size = WideCharToMultiByte(CP_UTF8, 0, xmlW, -1, NULL, 0, NULL, NULL);
135 xml = malloc(size);
136 if (!xml)
138 CloseHandle(hfile);
139 return E_OUTOFMEMORY;
141 WideCharToMultiByte(CP_UTF8, 0, xmlW, -1, xml, size, NULL, NULL);
143 if (!WriteFile(hfile, bom_utf8, sizeof(bom_utf8), &size, NULL))
145 hr = HRESULT_FROM_WIN32(GetLastError());
146 goto failed;
148 if (!WriteFile(hfile, comment, strlen(comment), &size, NULL))
150 hr = HRESULT_FROM_WIN32(GetLastError());
151 goto failed;
154 /* skip XML declaration with UTF-16 specifier */
155 if (!memcmp(xml, "<?xml", 5))
157 const char *p = strchr(xml, '>');
158 if (p++) while (isspace(*p)) p++;
159 else p = xml;
160 if (!WriteFile(hfile, p, strlen(p), &size, NULL))
161 hr = HRESULT_FROM_WIN32(GetLastError());
163 else
165 if (!WriteFile(hfile, xml, strlen(xml), &size, NULL))
166 hr = HRESULT_FROM_WIN32(GetLastError());
169 failed:
170 free(xml);
171 CloseHandle(hfile);
172 return hr;
175 HRESULT __cdecl SchRpcRegisterTask(const WCHAR *path, const WCHAR *xml, DWORD flags, const WCHAR *sddl,
176 DWORD task_logon_type, DWORD n_creds, const TASK_USER_CRED *creds,
177 WCHAR **actual_path, TASK_XML_ERROR_INFO **xml_error_info)
179 WCHAR *full_name, *relative_path;
180 DWORD disposition;
181 HRESULT hr;
183 TRACE("%s,%s,%#lx,%s,%lu,%lu,%p,%p,%p\n", debugstr_w(path), debugstr_w(xml), flags,
184 debugstr_w(sddl), task_logon_type, n_creds, creds, actual_path, xml_error_info);
186 *actual_path = NULL;
187 *xml_error_info = NULL;
189 /* FIXME: assume that validation is performed on the client side */
190 if (flags & TASK_VALIDATE_ONLY) return S_OK;
192 if (path)
194 full_name = get_full_name(path, &relative_path);
195 if (!full_name) return E_OUTOFMEMORY;
197 if (wcschr(path, '\\') || wcschr(path, '/'))
199 WCHAR *p = wcsrchr(full_name, '/');
200 if (!p) p = wcsrchr(full_name, '\\');
201 *p = 0;
202 hr = create_directory(full_name);
203 if (hr != S_OK && hr != HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS))
205 free(full_name);
206 return hr;
208 *p = '\\';
211 else
213 IID iid;
214 WCHAR uuid_str[39];
216 UuidCreate(&iid);
217 StringFromGUID2(&iid, uuid_str, 39);
219 full_name = get_full_name(uuid_str, &relative_path);
220 if (!full_name) return E_OUTOFMEMORY;
221 /* skip leading '\' */
222 relative_path++;
225 switch (flags & (TASK_CREATE | TASK_UPDATE))
227 default:
228 case TASK_CREATE:
229 disposition = CREATE_NEW;
230 break;
232 case TASK_UPDATE:
233 disposition = OPEN_EXISTING;
234 break;
236 case (TASK_CREATE | TASK_UPDATE):
237 disposition = OPEN_ALWAYS;
238 break;
241 hr = write_xml_utf8(full_name, disposition, xml);
242 if (hr == S_OK)
244 *actual_path = wcsdup(relative_path);
245 schedsvc_auto_start();
248 free(full_name);
249 return hr;
252 static int detect_encoding(const void *buffer, DWORD size)
254 if (size >= sizeof(bom_utf8) && !memcmp(buffer, bom_utf8, sizeof(bom_utf8)))
255 return CP_UTF8;
256 else
258 int flags = IS_TEXT_UNICODE_SIGNATURE |
259 IS_TEXT_UNICODE_REVERSE_SIGNATURE |
260 IS_TEXT_UNICODE_ODD_LENGTH;
261 IsTextUnicode(buffer, size, &flags);
262 if (flags & IS_TEXT_UNICODE_SIGNATURE)
263 return -1;
264 if (flags & IS_TEXT_UNICODE_REVERSE_SIGNATURE)
265 return -2;
266 return CP_ACP;
270 static HRESULT read_xml(const WCHAR *name, WCHAR **xml)
272 char *src, *buff;
273 HANDLE hfile;
274 DWORD size, attrs;
275 HRESULT hr = S_OK;
276 int cp;
278 attrs = GetFileAttributesW(name);
279 if (attrs == INVALID_FILE_ATTRIBUTES)
280 return HRESULT_FROM_WIN32(GetLastError());
281 if (attrs & FILE_ATTRIBUTE_DIRECTORY)
282 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
284 hfile = CreateFileW(name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
285 if (hfile == INVALID_HANDLE_VALUE)
286 return HRESULT_FROM_WIN32(GetLastError());
288 size = GetFileSize(hfile, NULL);
289 buff = src = malloc(size + 2);
290 if (!src)
292 CloseHandle(hfile);
293 return E_OUTOFMEMORY;
296 src[size] = 0;
297 src[size + 1] = 0;
299 ReadFile(hfile, src, size, &size, NULL);
300 CloseHandle(hfile);
302 cp = detect_encoding(src, size);
303 if (cp < 0)
305 *xml = (WCHAR *)src;
306 return S_OK;
309 if (cp == CP_UTF8 && size >= sizeof(bom_utf8) && !memcmp(src, bom_utf8, sizeof(bom_utf8)))
310 src += sizeof(bom_utf8);
312 size = MultiByteToWideChar(cp, 0, src, -1, NULL, 0);
313 *xml = malloc(size * sizeof(WCHAR));
314 if (*xml)
315 MultiByteToWideChar(cp, 0, src, -1, *xml, size);
316 else
317 hr = E_OUTOFMEMORY;
318 free(buff);
320 return hr;
323 static HRESULT read_text_value(IXmlReader *reader, WCHAR **value)
325 HRESULT hr;
326 XmlNodeType type;
328 while (IXmlReader_Read(reader, &type) == S_OK)
330 switch (type)
332 case XmlNodeType_Text:
333 if (FAILED(hr = IXmlReader_GetValue(reader, (const WCHAR **)value, NULL)))
334 return hr;
335 TRACE("%s\n", debugstr_w(*value));
336 return S_OK;
338 case XmlNodeType_Whitespace:
339 case XmlNodeType_Comment:
340 break;
342 default:
343 FIXME("unexpected node type %d\n", type);
344 return E_FAIL;
348 return E_FAIL;
351 static HRESULT read_variantbool_value(IXmlReader *reader, VARIANT_BOOL *vbool)
353 WCHAR *value;
354 HRESULT hr;
356 *vbool = VARIANT_FALSE;
358 if (FAILED(hr = read_text_value(reader, &value)))
359 return hr;
361 if (!wcscmp(value, L"true"))
363 *vbool = VARIANT_TRUE;
365 else if (wcscmp(value, L"false"))
367 WARN("unexpected bool value %s\n", debugstr_w(value));
368 return SCHED_E_INVALIDVALUE;
371 return S_OK;
374 static HRESULT read_task_settings(IXmlReader *reader, struct task_info *info)
376 VARIANT_BOOL bool_val;
377 const WCHAR *name;
378 XmlNodeType type;
379 HRESULT hr;
381 if (IXmlReader_IsEmptyElement(reader))
383 TRACE("Settings is empty.\n");
384 return S_OK;
387 while (IXmlReader_Read(reader, &type) == S_OK)
389 switch (type)
391 case XmlNodeType_EndElement:
392 hr = IXmlReader_GetLocalName(reader, &name, NULL);
393 if (hr != S_OK) return hr;
395 TRACE("/%s\n", debugstr_w(name));
397 if (!wcscmp(name, L"Settings"))
398 return S_OK;
400 break;
402 case XmlNodeType_Element:
403 hr = IXmlReader_GetLocalName(reader, &name, NULL);
404 if (hr != S_OK) return hr;
406 TRACE("Element: %s\n", debugstr_w(name));
408 if (!wcscmp(name, L"Enabled"))
410 if (FAILED(hr = read_variantbool_value(reader, &bool_val)))
411 return hr;
412 info->enabled = !!bool_val;
414 break;
415 default:
416 break;
420 WARN("Settings was not terminated\n");
421 return SCHED_E_MALFORMEDXML;
424 static HRESULT read_task_info(IXmlReader *reader, struct task_info *info)
426 const WCHAR *name;
427 XmlNodeType type;
428 HRESULT hr;
430 if (IXmlReader_IsEmptyElement(reader))
432 TRACE("Task is empty\n");
433 return S_OK;
435 while (IXmlReader_Read(reader, &type) == S_OK)
437 switch (type)
439 case XmlNodeType_EndElement:
440 if (FAILED(hr = IXmlReader_GetLocalName(reader, &name, NULL)))
441 return hr;
443 if (!wcscmp(name, L"Task"))
444 return S_OK;
445 break;
447 case XmlNodeType_Element:
448 if (FAILED(hr = IXmlReader_GetLocalName(reader, &name, NULL)))
449 return hr;
451 TRACE("Element: %s\n", debugstr_w(name));
453 if (!wcscmp(name, L"Settings"))
455 if (FAILED(hr = read_task_settings(reader, info)))
456 return hr;
458 break;
460 default:
461 break;
465 WARN("Task was not terminated\n");
466 return SCHED_E_MALFORMEDXML;
470 static HRESULT read_task_info_from_xml(const WCHAR *xml, struct task_info *info)
472 IXmlReader *reader;
473 const WCHAR *name;
474 XmlNodeType type;
475 IStream *stream;
476 HGLOBAL hmem;
477 HRESULT hr;
478 void *buf;
480 memset(info, 0, sizeof(*info));
482 if (!(hmem = GlobalAlloc(0, wcslen(xml) * sizeof(WCHAR))))
483 return E_OUTOFMEMORY;
485 buf = GlobalLock(hmem);
486 memcpy(buf, xml, lstrlenW(xml) * sizeof(WCHAR));
487 GlobalUnlock(hmem);
489 if (FAILED(hr = CreateStreamOnHGlobal(hmem, TRUE, &stream)))
491 GlobalFree(hmem);
492 return hr;
495 if (FAILED(hr = CreateXmlReader(&IID_IXmlReader, (void **)&reader, NULL)))
497 IStream_Release(stream);
498 return hr;
501 if (FAILED(hr = IXmlReader_SetInput(reader, (IUnknown *)stream)))
502 goto done;
504 while (IXmlReader_Read(reader, &type) == S_OK)
506 if (type != XmlNodeType_Element) continue;
507 if (FAILED(hr = IXmlReader_GetLocalName(reader, &name, NULL)))
508 goto done;
510 TRACE("Element: %s\n", debugstr_w(name));
511 if (wcscmp(name, L"Task"))
512 continue;
514 hr = read_task_info(reader, info);
515 break;
518 done:
519 IXmlReader_Release(reader);
520 IStream_Release(stream);
521 if (FAILED(hr))
523 WARN("Failed parsing xml, hr %#lx.\n", hr);
524 return SCHED_E_MALFORMEDXML;
526 return S_OK;
529 HRESULT __cdecl SchRpcRetrieveTask(const WCHAR *path, const WCHAR *languages, ULONG *n_languages, WCHAR **xml)
531 WCHAR *full_name;
532 HRESULT hr;
534 TRACE("%s,%s,%p,%p\n", debugstr_w(path), debugstr_w(languages), n_languages, xml);
536 full_name = get_full_name(path, NULL);
537 if (!full_name) return E_OUTOFMEMORY;
539 hr = read_xml(full_name, xml);
540 if (hr != S_OK) *xml = NULL;
542 free(full_name);
543 return hr;
546 HRESULT __cdecl SchRpcCreateFolder(const WCHAR *path, const WCHAR *sddl, DWORD flags)
548 WCHAR *full_name;
549 HRESULT hr;
551 TRACE("%s,%s,%#lx\n", debugstr_w(path), debugstr_w(sddl), flags);
553 if (flags) return E_INVALIDARG;
555 full_name = get_full_name(path, NULL);
556 if (!full_name) return E_OUTOFMEMORY;
558 hr = create_directory(full_name);
560 free(full_name);
561 return hr;
564 HRESULT __cdecl SchRpcSetSecurity(const WCHAR *path, const WCHAR *sddl, DWORD flags)
566 FIXME("%s,%s,%#lx: stub\n", debugstr_w(path), debugstr_w(sddl), flags);
567 return E_NOTIMPL;
570 HRESULT __cdecl SchRpcGetSecurity(const WCHAR *path, DWORD flags, WCHAR **sddl)
572 FIXME("%s,%#lx,%p: stub\n", debugstr_w(path), flags, sddl);
573 return E_NOTIMPL;
576 static void free_list(TASK_NAMES list, LONG count)
578 LONG i;
580 for (i = 0; i < count; i++)
581 free(list[i]);
583 free(list);
586 static inline BOOL is_directory(const WIN32_FIND_DATAW *data)
588 if (data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
590 if (data->cFileName[0] == '.')
592 if (!data->cFileName[1] || (data->cFileName[1] == '.' && !data->cFileName[2]))
593 return FALSE;
595 return TRUE;
597 return FALSE;
600 static inline BOOL is_file(const WIN32_FIND_DATAW *data)
602 return !(data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
605 HRESULT __cdecl SchRpcEnumFolders(const WCHAR *path, DWORD flags, DWORD *start_index, DWORD n_requested,
606 DWORD *n_names, TASK_NAMES *names)
608 static const WCHAR allW[] = {'\\','*',0};
609 HRESULT hr = S_OK;
610 WCHAR *full_name;
611 WCHAR pathW[MAX_PATH];
612 WIN32_FIND_DATAW data;
613 HANDLE handle;
614 DWORD allocated, count, index;
615 TASK_NAMES list;
617 TRACE("%s,%#lx,%lu,%lu,%p,%p\n", debugstr_w(path), flags, *start_index, n_requested, n_names, names);
619 *n_names = 0;
620 *names = NULL;
622 if (flags & ~TASK_ENUM_HIDDEN) return E_INVALIDARG;
624 if (!n_requested) n_requested = ~0u;
626 full_name = get_full_name(path, NULL);
627 if (!full_name) return E_OUTOFMEMORY;
629 if (lstrlenW(full_name) + 2 > MAX_PATH)
631 free(full_name);
632 return HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE);
635 lstrcpyW(pathW, full_name);
636 lstrcatW(pathW, allW);
638 free(full_name);
640 allocated = 64;
641 list = malloc(allocated * sizeof(list[0]));
642 if (!list) return E_OUTOFMEMORY;
644 index = count = 0;
646 handle = FindFirstFileW(pathW, &data);
647 if (handle == INVALID_HANDLE_VALUE)
649 free(list);
650 if (GetLastError() == ERROR_PATH_NOT_FOUND)
651 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
652 return HRESULT_FROM_WIN32(GetLastError());
657 if (is_directory(&data) && index++ >= *start_index)
659 if (count >= allocated)
661 TASK_NAMES new_list;
662 allocated *= 2;
663 new_list = realloc(list, allocated * sizeof(list[0]));
664 if (!new_list)
666 hr = E_OUTOFMEMORY;
667 break;
669 list = new_list;
672 TRACE("adding %s\n", debugstr_w(data.cFileName));
674 list[count] = wcsdup(data.cFileName);
675 if (!list[count])
677 hr = E_OUTOFMEMORY;
678 break;
681 count++;
683 if (count >= n_requested)
685 hr = S_FALSE;
686 break;
689 } while (FindNextFileW(handle, &data));
691 FindClose(handle);
693 if (FAILED(hr))
695 free_list(list, count);
696 return hr;
699 *n_names = count;
701 if (count)
703 *names = list;
704 *start_index = index;
705 return hr;
708 free(list);
709 *names = NULL;
710 return *start_index ? S_FALSE : S_OK;
713 HRESULT __cdecl SchRpcEnumTasks(const WCHAR *path, DWORD flags, DWORD *start_index, DWORD n_requested,
714 DWORD *n_names, TASK_NAMES *names)
716 static const WCHAR allW[] = {'\\','*',0};
717 HRESULT hr = S_OK;
718 WCHAR *full_name;
719 WCHAR pathW[MAX_PATH];
720 WIN32_FIND_DATAW data;
721 HANDLE handle;
722 DWORD allocated, count, index;
723 TASK_NAMES list;
725 TRACE("%s,%#lx,%lu,%lu,%p,%p\n", debugstr_w(path), flags, *start_index, n_requested, n_names, names);
727 *n_names = 0;
728 *names = NULL;
730 if (flags & ~TASK_ENUM_HIDDEN) return E_INVALIDARG;
732 if (!n_requested) n_requested = ~0u;
734 full_name = get_full_name(path, NULL);
735 if (!full_name) return E_OUTOFMEMORY;
737 if (lstrlenW(full_name) + 2 > MAX_PATH)
739 free(full_name);
740 return HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE);
743 lstrcpyW(pathW, full_name);
744 lstrcatW(pathW, allW);
746 free(full_name);
748 allocated = 64;
749 list = malloc(allocated * sizeof(list[0]));
750 if (!list) return E_OUTOFMEMORY;
752 index = count = 0;
754 handle = FindFirstFileW(pathW, &data);
755 if (handle == INVALID_HANDLE_VALUE)
757 free(list);
758 if (GetLastError() == ERROR_PATH_NOT_FOUND)
759 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
760 return HRESULT_FROM_WIN32(GetLastError());
765 if (is_file(&data) && index++ >= *start_index)
767 if (count >= allocated)
769 TASK_NAMES new_list;
770 allocated *= 2;
771 new_list = realloc(list, allocated * sizeof(list[0]));
772 if (!new_list)
774 hr = E_OUTOFMEMORY;
775 break;
777 list = new_list;
780 TRACE("adding %s\n", debugstr_w(data.cFileName));
782 list[count] = wcsdup(data.cFileName);
783 if (!list[count])
785 hr = E_OUTOFMEMORY;
786 break;
789 count++;
791 if (count >= n_requested)
793 hr = S_FALSE;
794 break;
797 } while (FindNextFileW(handle, &data));
799 FindClose(handle);
801 if (FAILED(hr))
803 free_list(list, count);
804 return hr;
807 *n_names = count;
809 if (count)
811 *names = list;
812 *start_index = index;
813 return hr;
816 free(list);
817 *names = NULL;
818 return *start_index ? S_FALSE : S_OK;
821 HRESULT __cdecl SchRpcEnumInstances(const WCHAR *path, DWORD flags, DWORD *n_guids, GUID **guids)
823 FIXME("%s,%#lx,%p,%p: stub\n", debugstr_w(path), flags, n_guids, guids);
824 return E_NOTIMPL;
827 HRESULT __cdecl SchRpcGetInstanceInfo(GUID guid, WCHAR **path, DWORD *task_state, WCHAR **action,
828 WCHAR **info, DWORD *n_instances, GUID **instances, DWORD *pid)
830 FIXME("%s,%p,%p,%p,%p,%p,%p,%p: stub\n", wine_dbgstr_guid(&guid), path, task_state, action,
831 info, n_instances, instances, pid);
832 return E_NOTIMPL;
835 HRESULT __cdecl SchRpcStopInstance(GUID guid, DWORD flags)
837 FIXME("%s,%#lx: stub\n", wine_dbgstr_guid(&guid), flags);
838 return E_NOTIMPL;
841 HRESULT __cdecl SchRpcStop(const WCHAR *path, DWORD flags)
843 FIXME("%s,%#lx: stub\n", debugstr_w(path), flags);
844 return E_NOTIMPL;
847 HRESULT __cdecl SchRpcRun(const WCHAR *path, DWORD n_args, const WCHAR **args, DWORD flags,
848 DWORD session_id, const WCHAR *user, GUID *guid)
850 FIXME("%s,%lu,%p,%#lx,%#lx,%s,%p: stub\n", debugstr_w(path), n_args, args, flags,
851 session_id, debugstr_w(user), guid);
852 return E_NOTIMPL;
855 HRESULT __cdecl SchRpcDelete(const WCHAR *path, DWORD flags)
857 WCHAR *full_name;
858 HRESULT hr = S_OK;
860 TRACE("%s,%#lx\n", debugstr_w(path), flags);
862 if (flags) return E_INVALIDARG;
864 while (*path == '\\' || *path == '/') path++;
865 if (!*path) return E_ACCESSDENIED;
867 full_name = get_full_name(path, NULL);
868 if (!full_name) return E_OUTOFMEMORY;
870 if (!RemoveDirectoryW(full_name))
872 hr = HRESULT_FROM_WIN32(GetLastError());
873 if (hr == HRESULT_FROM_WIN32(ERROR_DIRECTORY))
874 hr = DeleteFileW(full_name) ? S_OK : HRESULT_FROM_WIN32(GetLastError());
877 free(full_name);
878 return hr;
881 HRESULT __cdecl SchRpcRename(const WCHAR *path, const WCHAR *name, DWORD flags)
883 FIXME("%s,%s,%#lx: stub\n", debugstr_w(path), debugstr_w(name), flags);
884 return E_NOTIMPL;
887 HRESULT __cdecl SchRpcScheduledRuntimes(const WCHAR *path, SYSTEMTIME *start, SYSTEMTIME *end, DWORD flags,
888 DWORD n_requested, DWORD *n_runtimes, SYSTEMTIME **runtimes)
890 FIXME("%s,%p,%p,%#lx,%lu,%p,%p: stub\n", debugstr_w(path), start, end, flags,
891 n_requested, n_runtimes, runtimes);
892 return E_NOTIMPL;
895 HRESULT __cdecl SchRpcGetLastRunInfo(const WCHAR *path, SYSTEMTIME *last_runtime, DWORD *last_return_code)
897 FIXME("%s,%p,%p: stub\n", debugstr_w(path), last_runtime, last_return_code);
898 return E_NOTIMPL;
901 HRESULT __cdecl SchRpcGetTaskInfo(const WCHAR *path, DWORD flags, DWORD *enabled, DWORD *task_state)
903 WCHAR *full_name, *xml;
904 struct task_info info;
905 HRESULT hr;
907 FIXME("%s,%#lx,%p,%p: stub\n", debugstr_w(path), flags, enabled, task_state);
909 full_name = get_full_name(path, NULL);
910 if (!full_name) return E_OUTOFMEMORY;
912 hr = read_xml(full_name, &xml);
913 free(full_name);
914 if (hr != S_OK) return hr;
915 hr = read_task_info_from_xml(xml, &info);
916 free(xml);
917 if (FAILED(hr)) return hr;
919 *enabled = info.enabled;
920 if (flags & SCH_FLAG_STATE)
921 *task_state = *enabled ? TASK_STATE_READY : TASK_STATE_DISABLED;
922 else
923 *task_state = TASK_STATE_UNKNOWN;
924 return S_OK;
927 HRESULT __cdecl SchRpcGetNumberOfMissedRuns(const WCHAR *path, DWORD *runs)
929 FIXME("%s,%p: stub\n", debugstr_w(path), runs);
930 return E_NOTIMPL;
933 HRESULT __cdecl SchRpcEnableTask(const WCHAR *path, DWORD enabled)
935 FIXME("%s,%lu: stub\n", debugstr_w(path), enabled);
936 return E_NOTIMPL;