mstask: Implement ITask::DeleteTrigger().
[wine.git] / dlls / mstask / task.c
blob2525a1a33a734ee1c764c8ef5bf56f910af17299
1 /*
2 * Copyright (C) 2008 Google (Roy Shea)
3 * Copyright (C) 2018 Dmitry Timoshkov
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include <stdarg.h>
22 #define COBJMACROS
24 #include "windef.h"
25 #include "winbase.h"
26 #include "objbase.h"
27 #include "taskschd.h"
28 #include "mstask.h"
29 #include "mstask_private.h"
30 #include "wine/debug.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(mstask);
34 typedef struct
36 USHORT product_version;
37 USHORT file_version;
38 UUID uuid;
39 USHORT name_size_offset;
40 USHORT trigger_offset;
41 USHORT error_retry_count;
42 USHORT error_retry_interval;
43 USHORT idle_deadline;
44 USHORT idle_wait;
45 UINT priority;
46 UINT maximum_runtime;
47 UINT exit_code;
48 HRESULT status;
49 UINT flags;
50 SYSTEMTIME last_runtime;
51 } FIXDLEN_DATA;
53 typedef struct
55 ITask ITask_iface;
56 IPersistFile IPersistFile_iface;
57 LONG ref;
58 ITaskDefinition *task;
59 IExecAction *action;
60 LPWSTR task_name;
61 HRESULT status;
62 WORD idle_minutes, deadline_minutes;
63 DWORD priority, maxRunTime;
64 LPWSTR accountName;
65 DWORD trigger_count;
66 TASK_TRIGGER *trigger;
67 } TaskImpl;
69 static inline TaskImpl *impl_from_ITask(ITask *iface)
71 return CONTAINING_RECORD(iface, TaskImpl, ITask_iface);
74 static inline TaskImpl *impl_from_IPersistFile( IPersistFile *iface )
76 return CONTAINING_RECORD(iface, TaskImpl, IPersistFile_iface);
79 static void TaskDestructor(TaskImpl *This)
81 TRACE("%p\n", This);
82 if (This->action)
83 IExecAction_Release(This->action);
84 ITaskDefinition_Release(This->task);
85 HeapFree(GetProcessHeap(), 0, This->task_name);
86 HeapFree(GetProcessHeap(), 0, This->accountName);
87 HeapFree(GetProcessHeap(), 0, This->trigger);
88 HeapFree(GetProcessHeap(), 0, This);
89 InterlockedDecrement(&dll_ref);
92 static HRESULT WINAPI MSTASK_ITask_QueryInterface(
93 ITask* iface,
94 REFIID riid,
95 void **ppvObject)
97 TaskImpl * This = impl_from_ITask(iface);
99 TRACE("IID: %s\n", debugstr_guid(riid));
100 if (ppvObject == NULL)
101 return E_POINTER;
103 if (IsEqualGUID(riid, &IID_IUnknown) ||
104 IsEqualGUID(riid, &IID_ITask))
106 *ppvObject = &This->ITask_iface;
107 ITask_AddRef(iface);
108 return S_OK;
110 else if (IsEqualGUID(riid, &IID_IPersistFile))
112 *ppvObject = &This->IPersistFile_iface;
113 ITask_AddRef(iface);
114 return S_OK;
117 WARN("Unknown interface: %s\n", debugstr_guid(riid));
118 *ppvObject = NULL;
119 return E_NOINTERFACE;
122 static ULONG WINAPI MSTASK_ITask_AddRef(
123 ITask* iface)
125 TaskImpl *This = impl_from_ITask(iface);
126 ULONG ref;
127 TRACE("\n");
128 ref = InterlockedIncrement(&This->ref);
129 return ref;
132 static ULONG WINAPI MSTASK_ITask_Release(
133 ITask* iface)
135 TaskImpl * This = impl_from_ITask(iface);
136 ULONG ref;
137 TRACE("\n");
138 ref = InterlockedDecrement(&This->ref);
139 if (ref == 0)
140 TaskDestructor(This);
141 return ref;
144 static HRESULT WINAPI MSTASK_ITask_CreateTrigger(ITask *iface, WORD *idx, ITaskTrigger **task_trigger)
146 TaskImpl *This = impl_from_ITask(iface);
147 TASK_TRIGGER *new_trigger;
148 HRESULT hr;
150 TRACE("(%p, %p, %p)\n", iface, idx, task_trigger);
152 hr = TaskTriggerConstructor((void **)task_trigger);
153 if (hr != S_OK) return hr;
155 if (This->trigger)
156 new_trigger = heap_realloc(This->trigger, sizeof(This->trigger[0]) * (This->trigger_count + 1));
157 else
158 new_trigger = heap_alloc(sizeof(This->trigger[0]));
159 if (!new_trigger)
161 ITaskTrigger_Release(*task_trigger);
162 return E_OUTOFMEMORY;
165 This->trigger = new_trigger;
167 hr = ITaskTrigger_GetTrigger(*task_trigger, &This->trigger[This->trigger_count]);
168 if (hr == S_OK)
169 *idx = This->trigger_count++;
171 return hr;
174 static HRESULT WINAPI MSTASK_ITask_DeleteTrigger(ITask *iface, WORD idx)
176 TaskImpl *This = impl_from_ITask(iface);
178 TRACE("(%p, %u)\n", iface, idx);
180 if (idx >= This->trigger_count)
181 return SCHED_E_TRIGGER_NOT_FOUND;
183 This->trigger_count--;
184 memmove(&This->trigger[idx], &This->trigger[idx + 1], (This->trigger_count - idx) * sizeof(This->trigger[0]));
185 /* this shouldn't fail in practice since we're shrinking the memory block */
186 This->trigger = heap_realloc(This->trigger, sizeof(This->trigger[0]) * This->trigger_count);
188 return S_OK;
191 static HRESULT WINAPI MSTASK_ITask_GetTriggerCount(ITask *iface, WORD *count)
193 TaskImpl *This = impl_from_ITask(iface);
195 TRACE("(%p, %p)\n", iface, count);
197 *count = This->trigger_count;
198 return S_OK;
201 static HRESULT WINAPI MSTASK_ITask_GetTrigger(
202 ITask* iface,
203 WORD iTrigger,
204 ITaskTrigger **ppTrigger)
206 FIXME("(%p, %d, %p): stub\n", iface, iTrigger, ppTrigger);
207 return E_NOTIMPL;
210 static HRESULT WINAPI MSTASK_ITask_GetTriggerString(
211 ITask* iface,
212 WORD iTrigger,
213 LPWSTR *ppwszTrigger)
215 FIXME("(%p, %d, %p): stub\n", iface, iTrigger, ppwszTrigger);
216 return E_NOTIMPL;
219 static HRESULT WINAPI MSTASK_ITask_GetRunTimes(
220 ITask* iface,
221 const LPSYSTEMTIME pstBegin,
222 const LPSYSTEMTIME pstEnd,
223 WORD *pCount,
224 LPSYSTEMTIME *rgstTaskTimes)
226 FIXME("(%p, %p, %p, %p, %p): stub\n", iface, pstBegin, pstEnd, pCount,
227 rgstTaskTimes);
228 return E_NOTIMPL;
231 static HRESULT WINAPI MSTASK_ITask_GetNextRunTime(
232 ITask* iface,
233 SYSTEMTIME *pstNextRun)
235 FIXME("(%p, %p): stub\n", iface, pstNextRun);
236 return E_NOTIMPL;
239 static HRESULT WINAPI MSTASK_ITask_SetIdleWait(
240 ITask* iface,
241 WORD wIdleMinutes,
242 WORD wDeadlineMinutes)
244 FIXME("(%p, %d, %d): stub\n", iface, wIdleMinutes, wDeadlineMinutes);
245 return E_NOTIMPL;
248 static HRESULT WINAPI MSTASK_ITask_GetIdleWait(ITask *iface, WORD *idle_minutes, WORD *deadline_minutes)
250 TaskImpl *This = impl_from_ITask(iface);
252 TRACE("(%p, %p, %p): stub\n", iface, idle_minutes, deadline_minutes);
254 *idle_minutes = This->idle_minutes;
255 *deadline_minutes = This->deadline_minutes;
256 return S_OK;
259 static HRESULT WINAPI MSTASK_ITask_Run(
260 ITask* iface)
262 FIXME("(%p): stub\n", iface);
263 return E_NOTIMPL;
266 static HRESULT WINAPI MSTASK_ITask_Terminate(
267 ITask* iface)
269 FIXME("(%p): stub\n", iface);
270 return E_NOTIMPL;
273 static HRESULT WINAPI MSTASK_ITask_EditWorkItem(
274 ITask* iface,
275 HWND hParent,
276 DWORD dwReserved)
278 FIXME("(%p, %p, %d): stub\n", iface, hParent, dwReserved);
279 return E_NOTIMPL;
282 static HRESULT WINAPI MSTASK_ITask_GetMostRecentRunTime(ITask *iface, SYSTEMTIME *st)
284 FIXME("(%p, %p): stub\n", iface, st);
286 memset(st, 0, sizeof(*st));
287 return SCHED_S_TASK_HAS_NOT_RUN;
290 static HRESULT WINAPI MSTASK_ITask_GetStatus(ITask *iface, HRESULT *status)
292 TaskImpl *This = impl_from_ITask(iface);
294 TRACE("(%p, %p)\n", iface, status);
296 *status = This->status;
297 return S_OK;
300 static HRESULT WINAPI MSTASK_ITask_GetExitCode(ITask *iface, DWORD *exit_code)
302 FIXME("(%p, %p): stub\n", iface, exit_code);
304 *exit_code = 0;
305 return SCHED_S_TASK_HAS_NOT_RUN;
308 static HRESULT WINAPI MSTASK_ITask_SetComment(ITask *iface, LPCWSTR comment)
310 TaskImpl *This = impl_from_ITask(iface);
311 IRegistrationInfo *info;
312 HRESULT hr;
314 TRACE("(%p, %s)\n", iface, debugstr_w(comment));
316 if (!comment || !comment[0])
317 comment = NULL;
319 hr = ITaskDefinition_get_RegistrationInfo(This->task, &info);
320 if (hr == S_OK)
322 hr = IRegistrationInfo_put_Description(info, (BSTR)comment);
323 IRegistrationInfo_Release(info);
325 return hr;
328 static HRESULT WINAPI MSTASK_ITask_GetComment(ITask *iface, LPWSTR *comment)
330 TaskImpl *This = impl_from_ITask(iface);
331 IRegistrationInfo *info;
332 HRESULT hr;
333 BSTR description;
334 DWORD len;
336 TRACE("(%p, %p)\n", iface, comment);
338 hr = ITaskDefinition_get_RegistrationInfo(This->task, &info);
339 if (hr != S_OK) return hr;
341 hr = IRegistrationInfo_get_Description(info, &description);
342 if (hr == S_OK)
344 len = description ? lstrlenW(description) + 1 : 1;
345 *comment = CoTaskMemAlloc(len * sizeof(WCHAR));
346 if (*comment)
348 if (!description)
349 *comment[0] = 0;
350 else
351 lstrcpyW(*comment, description);
352 hr = S_OK;
354 else
355 hr = E_OUTOFMEMORY;
357 SysFreeString(description);
360 IRegistrationInfo_Release(info);
361 return hr;
364 static HRESULT WINAPI MSTASK_ITask_SetCreator(ITask *iface, LPCWSTR creator)
366 TaskImpl *This = impl_from_ITask(iface);
367 IRegistrationInfo *info;
368 HRESULT hr;
370 TRACE("(%p, %s)\n", iface, debugstr_w(creator));
372 if (!creator || !creator[0])
373 creator = NULL;
375 hr = ITaskDefinition_get_RegistrationInfo(This->task, &info);
376 if (hr == S_OK)
378 hr = IRegistrationInfo_put_Author(info, (BSTR)creator);
379 IRegistrationInfo_Release(info);
381 return hr;
384 static HRESULT WINAPI MSTASK_ITask_GetCreator(ITask *iface, LPWSTR *creator)
386 TaskImpl *This = impl_from_ITask(iface);
387 IRegistrationInfo *info;
388 HRESULT hr;
389 BSTR author;
390 DWORD len;
392 TRACE("(%p, %p)\n", iface, creator);
394 hr = ITaskDefinition_get_RegistrationInfo(This->task, &info);
395 if (hr != S_OK) return hr;
397 hr = IRegistrationInfo_get_Author(info, &author);
398 if (hr == S_OK)
400 len = author ? lstrlenW(author) + 1 : 1;
401 *creator = CoTaskMemAlloc(len * sizeof(WCHAR));
402 if (*creator)
404 if (!author)
405 *creator[0] = 0;
406 else
407 lstrcpyW(*creator, author);
408 hr = S_OK;
410 else
411 hr = E_OUTOFMEMORY;
413 SysFreeString(author);
416 IRegistrationInfo_Release(info);
417 return hr;
420 static HRESULT WINAPI MSTASK_ITask_SetWorkItemData(
421 ITask* iface,
422 WORD cBytes,
423 BYTE rgbData[])
425 FIXME("(%p, %d, %p): stub\n", iface, cBytes, rgbData);
426 return E_NOTIMPL;
429 static HRESULT WINAPI MSTASK_ITask_GetWorkItemData(
430 ITask* iface,
431 WORD *pcBytes,
432 BYTE **ppBytes)
434 FIXME("(%p, %p, %p): stub\n", iface, pcBytes, ppBytes);
435 return E_NOTIMPL;
438 static HRESULT WINAPI MSTASK_ITask_SetErrorRetryCount(
439 ITask* iface,
440 WORD wRetryCount)
442 FIXME("(%p, %d): stub\n", iface, wRetryCount);
443 return E_NOTIMPL;
446 static HRESULT WINAPI MSTASK_ITask_GetErrorRetryCount(ITask *iface, WORD *count)
448 TRACE("(%p, %p)\n", iface, count);
449 return E_NOTIMPL;
452 static HRESULT WINAPI MSTASK_ITask_SetErrorRetryInterval(
453 ITask* iface,
454 WORD wRetryInterval)
456 FIXME("(%p, %d): stub\n", iface, wRetryInterval);
457 return E_NOTIMPL;
460 static HRESULT WINAPI MSTASK_ITask_GetErrorRetryInterval(ITask *iface, WORD *interval)
462 TRACE("(%p, %p)\n", iface, interval);
463 return E_NOTIMPL;
466 static HRESULT WINAPI MSTASK_ITask_SetFlags(
467 ITask* iface,
468 DWORD dwFlags)
470 FIXME("(%p, 0x%08x): stub\n", iface, dwFlags);
471 return E_NOTIMPL;
474 static HRESULT WINAPI MSTASK_ITask_GetFlags(ITask *iface, DWORD *flags)
476 FIXME("(%p, %p): stub\n", iface, flags);
477 *flags = 0;
478 return S_OK;
481 static HRESULT WINAPI MSTASK_ITask_SetAccountInformation(
482 ITask* iface,
483 LPCWSTR pwszAccountName,
484 LPCWSTR pwszPassword)
486 DWORD n;
487 TaskImpl *This = impl_from_ITask(iface);
488 LPWSTR tmp_account_name;
490 TRACE("(%p, %s, %s): partial stub\n", iface, debugstr_w(pwszAccountName),
491 debugstr_w(pwszPassword));
493 if (pwszPassword)
494 FIXME("Partial stub ignores passwords\n");
496 n = (lstrlenW(pwszAccountName) + 1);
497 tmp_account_name = HeapAlloc(GetProcessHeap(), 0, n * sizeof(WCHAR));
498 if (!tmp_account_name)
499 return E_OUTOFMEMORY;
500 lstrcpyW(tmp_account_name, pwszAccountName);
501 HeapFree(GetProcessHeap(), 0, This->accountName);
502 This->accountName = tmp_account_name;
503 return S_OK;
506 static HRESULT WINAPI MSTASK_ITask_GetAccountInformation(
507 ITask* iface,
508 LPWSTR *ppwszAccountName)
510 DWORD n;
511 TaskImpl *This = impl_from_ITask(iface);
513 TRACE("(%p, %p): partial stub\n", iface, ppwszAccountName);
515 /* This implements the WinXP behavior when accountName has not yet
516 * set. Win2K behaves differently, returning SCHED_E_CANNOT_OPEN_TASK */
517 if (!This->accountName)
518 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
520 n = (lstrlenW(This->accountName) + 1);
521 *ppwszAccountName = CoTaskMemAlloc(n * sizeof(WCHAR));
522 if (!*ppwszAccountName)
523 return E_OUTOFMEMORY;
524 lstrcpyW(*ppwszAccountName, This->accountName);
525 return S_OK;
528 static HRESULT WINAPI MSTASK_ITask_SetApplicationName(ITask *iface, LPCWSTR appname)
530 TaskImpl *This = impl_from_ITask(iface);
531 DWORD len;
533 TRACE("(%p, %s)\n", iface, debugstr_w(appname));
535 /* Empty application name */
536 if (!appname || !appname[0])
537 return IExecAction_put_Path(This->action, NULL);
539 /* Attempt to set pwszApplicationName to a path resolved application name */
540 len = SearchPathW(NULL, appname, NULL, 0, NULL, NULL);
541 if (len)
543 LPWSTR tmp_name;
544 HRESULT hr;
546 tmp_name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
547 if (!tmp_name)
548 return E_OUTOFMEMORY;
549 len = SearchPathW(NULL, appname, NULL, len, tmp_name, NULL);
550 if (len)
551 hr = IExecAction_put_Path(This->action, tmp_name);
552 else
553 hr = HRESULT_FROM_WIN32(GetLastError());
555 HeapFree(GetProcessHeap(), 0, tmp_name);
556 return hr;
559 /* If unable to path resolve name, simply set to appname */
560 return IExecAction_put_Path(This->action, (BSTR)appname);
563 static HRESULT WINAPI MSTASK_ITask_GetApplicationName(ITask *iface, LPWSTR *appname)
565 TaskImpl *This = impl_from_ITask(iface);
566 HRESULT hr;
567 BSTR path;
568 DWORD len;
570 TRACE("(%p, %p)\n", iface, appname);
572 hr = IExecAction_get_Path(This->action, &path);
573 if (hr != S_OK) return hr;
575 len = path ? lstrlenW(path) + 1 : 1;
576 *appname = CoTaskMemAlloc(len * sizeof(WCHAR));
577 if (*appname)
579 if (!path)
580 *appname[0] = 0;
581 else
582 lstrcpyW(*appname, path);
583 hr = S_OK;
585 else
586 hr = E_OUTOFMEMORY;
588 SysFreeString(path);
589 return hr;
592 static HRESULT WINAPI MSTASK_ITask_SetParameters(ITask *iface, LPCWSTR params)
594 TaskImpl *This = impl_from_ITask(iface);
596 TRACE("(%p, %s)\n", iface, debugstr_w(params));
598 /* Empty parameter list */
599 if (!params || !params[0])
600 params = NULL;
602 return IExecAction_put_Arguments(This->action, (BSTR)params);
605 static HRESULT WINAPI MSTASK_ITask_GetParameters(ITask *iface, LPWSTR *params)
607 TaskImpl *This = impl_from_ITask(iface);
608 HRESULT hr;
609 BSTR args;
610 DWORD len;
612 TRACE("(%p, %p)\n", iface, params);
614 hr = IExecAction_get_Arguments(This->action, &args);
615 if (hr != S_OK) return hr;
617 len = args ? lstrlenW(args) + 1 : 1;
618 *params = CoTaskMemAlloc(len * sizeof(WCHAR));
619 if (*params)
621 if (!args)
622 *params[0] = 0;
623 else
624 lstrcpyW(*params, args);
625 hr = S_OK;
627 else
628 hr = E_OUTOFMEMORY;
630 SysFreeString(args);
631 return hr;
634 static HRESULT WINAPI MSTASK_ITask_SetWorkingDirectory(ITask * iface, LPCWSTR workdir)
636 TaskImpl *This = impl_from_ITask(iface);
638 TRACE("(%p, %s)\n", iface, debugstr_w(workdir));
640 if (!workdir || !workdir[0])
641 workdir = NULL;
643 return IExecAction_put_WorkingDirectory(This->action, (BSTR)workdir);
646 static HRESULT WINAPI MSTASK_ITask_GetWorkingDirectory(ITask *iface, LPWSTR *workdir)
648 TaskImpl *This = impl_from_ITask(iface);
649 HRESULT hr;
650 BSTR dir;
651 DWORD len;
653 TRACE("(%p, %p)\n", iface, workdir);
655 hr = IExecAction_get_WorkingDirectory(This->action, &dir);
656 if (hr != S_OK) return hr;
658 len = dir ? lstrlenW(dir) + 1 : 1;
659 *workdir = CoTaskMemAlloc(len * sizeof(WCHAR));
660 if (*workdir)
662 if (!dir)
663 *workdir[0] = 0;
664 else
665 lstrcpyW(*workdir, dir);
666 hr = S_OK;
668 else
669 hr = E_OUTOFMEMORY;
671 SysFreeString(dir);
672 return hr;
675 static HRESULT WINAPI MSTASK_ITask_SetPriority(
676 ITask* iface,
677 DWORD dwPriority)
679 FIXME("(%p, 0x%08x): stub\n", iface, dwPriority);
680 return E_NOTIMPL;
683 static HRESULT WINAPI MSTASK_ITask_GetPriority(ITask *iface, DWORD *priority)
685 TaskImpl *This = impl_from_ITask(iface);
687 TRACE("(%p, %p)\n", iface, priority);
689 *priority = This->priority;
690 return S_OK;
693 static HRESULT WINAPI MSTASK_ITask_SetTaskFlags(
694 ITask* iface,
695 DWORD dwFlags)
697 FIXME("(%p, 0x%08x): stub\n", iface, dwFlags);
698 return E_NOTIMPL;
701 static HRESULT WINAPI MSTASK_ITask_GetTaskFlags(ITask *iface, DWORD *flags)
703 FIXME("(%p, %p): stub\n", iface, flags);
704 *flags = 0;
705 return S_OK;
708 static HRESULT WINAPI MSTASK_ITask_SetMaxRunTime(
709 ITask* iface,
710 DWORD dwMaxRunTime)
712 TaskImpl *This = impl_from_ITask(iface);
714 TRACE("(%p, %d)\n", iface, dwMaxRunTime);
716 This->maxRunTime = dwMaxRunTime;
717 return S_OK;
720 static HRESULT WINAPI MSTASK_ITask_GetMaxRunTime(
721 ITask* iface,
722 DWORD *pdwMaxRunTime)
724 TaskImpl *This = impl_from_ITask(iface);
726 TRACE("(%p, %p)\n", iface, pdwMaxRunTime);
728 *pdwMaxRunTime = This->maxRunTime;
729 return S_OK;
732 static HRESULT WINAPI MSTASK_IPersistFile_QueryInterface(
733 IPersistFile* iface,
734 REFIID riid,
735 void **ppvObject)
737 TaskImpl *This = impl_from_IPersistFile(iface);
738 TRACE("(%p, %s, %p)\n", iface, debugstr_guid(riid), ppvObject);
739 return ITask_QueryInterface(&This->ITask_iface, riid, ppvObject);
742 static ULONG WINAPI MSTASK_IPersistFile_AddRef(
743 IPersistFile* iface)
745 TaskImpl *This = impl_from_IPersistFile(iface);
746 ULONG ref;
747 TRACE("\n");
748 ref = InterlockedIncrement(&This->ref);
749 return ref;
752 static ULONG WINAPI MSTASK_IPersistFile_Release(
753 IPersistFile* iface)
755 TaskImpl *This = impl_from_IPersistFile(iface);
756 ULONG ref;
757 TRACE("\n");
758 ref = InterlockedDecrement(&This->ref);
759 if (ref == 0)
760 TaskDestructor(This);
761 return ref;
764 static HRESULT WINAPI MSTASK_IPersistFile_GetClassID(IPersistFile *iface, CLSID *clsid)
766 TRACE("(%p, %p)\n", iface, clsid);
768 *clsid = CLSID_CTask;
769 return S_OK;
772 static HRESULT WINAPI MSTASK_IPersistFile_IsDirty(
773 IPersistFile* iface)
775 FIXME("(%p): stub\n", iface);
776 return E_NOTIMPL;
779 static HRESULT WINAPI MSTASK_IPersistFile_Load(
780 IPersistFile* iface,
781 LPCOLESTR pszFileName,
782 DWORD dwMode)
784 FIXME("(%p, %p, 0x%08x): stub\n", iface, pszFileName, dwMode);
785 return E_NOTIMPL;
788 static BOOL write_signature(HANDLE hfile)
790 struct
792 USHORT SignatureVersion;
793 USHORT ClientVersion;
794 BYTE md5[64];
795 } signature;
796 DWORD size;
798 signature.SignatureVersion = 0x0001;
799 signature.ClientVersion = 0x0001;
800 memset(&signature.md5, 0, sizeof(signature.md5));
802 return WriteFile(hfile, &signature, sizeof(signature), &size, NULL);
805 static BOOL write_reserved_data(HANDLE hfile)
807 static const struct
809 USHORT size;
810 BYTE data[8];
811 } user = { 8, { 0xff,0x0f,0x1d,0,0,0,0,0 } };
812 DWORD size;
814 return WriteFile(hfile, &user, sizeof(user), &size, NULL);
817 static BOOL write_user_data(HANDLE hfile, BYTE *data, WORD data_size)
819 DWORD size;
821 if (!WriteFile(hfile, &data_size, sizeof(data_size), &size, NULL))
822 return FALSE;
824 if (!data_size) return TRUE;
826 return WriteFile(hfile, data, data_size, &size, NULL);
829 static HRESULT write_triggers(ITask *task, HANDLE hfile)
831 WORD count, i, idx = 0xffff;
832 DWORD size;
833 HRESULT hr;
834 ITaskTrigger *trigger;
836 hr = ITask_GetTriggerCount(task, &count);
837 if (hr != S_OK) return hr;
839 if (!WriteFile(hfile, &count, sizeof(count), &size, NULL))
840 return HRESULT_FROM_WIN32(GetLastError());
842 /* Windows saves a .job with at least 1 trigger */
843 if (!count)
845 hr = ITask_CreateTrigger(task, &idx, &trigger);
846 if (hr != S_OK) return hr;
847 ITaskTrigger_Release(trigger);
849 count = 1;
852 for (i = 0; i < count; i++)
854 TASK_TRIGGER task_trigger;
856 hr = ITask_GetTrigger(task, i, &trigger);
857 if (hr != S_OK) return hr;
859 hr = ITaskTrigger_GetTrigger(trigger, &task_trigger);
860 ITaskTrigger_Release(trigger);
861 if (hr != S_OK) break;
863 if (!WriteFile(hfile, &task_trigger, sizeof(task_trigger), &size, NULL))
864 return HRESULT_FROM_WIN32(GetLastError());
867 if (idx != 0xffff)
868 ITask_DeleteTrigger(task, idx);
870 return hr;
873 static BOOL write_unicode_string(HANDLE hfile, const WCHAR *str)
875 USHORT count;
876 DWORD size;
878 count = str ? (lstrlenW(str) + 1) : 0;
879 if (!WriteFile(hfile, &count, sizeof(count), &size, NULL))
880 return FALSE;
882 if (!str) return TRUE;
884 count *= sizeof(WCHAR);
885 return WriteFile(hfile, str, count, &size, NULL);
888 static HRESULT WINAPI MSTASK_IPersistFile_Save(IPersistFile *iface, LPCOLESTR task_name, BOOL remember)
890 static WCHAR authorW[] = { 'W','i','n','e',0 };
891 static WCHAR commentW[] = { 'C','r','e','a','t','e','d',' ','b','y',' ','W','i','n','e',0 };
892 FIXDLEN_DATA fixed;
893 WORD word, user_data_size = 0;
894 HANDLE hfile;
895 DWORD size, ver, disposition;
896 TaskImpl *This = impl_from_IPersistFile(iface);
897 ITask *task = &This->ITask_iface;
898 LPWSTR appname = NULL, params = NULL, workdir = NULL, creator = NULL, comment = NULL;
899 BYTE *user_data = NULL;
900 HRESULT hr;
902 TRACE("(%p, %s, %d)\n", iface, debugstr_w(task_name), remember);
904 disposition = task_name ? CREATE_NEW : OPEN_ALWAYS;
906 if (!task_name)
908 task_name = This->task_name;
909 remember = FALSE;
912 ITask_GetComment(task, &comment);
913 if (!comment) comment = commentW;
914 ITask_GetCreator(task, &creator);
915 if (!creator) creator = authorW;
916 ITask_GetApplicationName(task, &appname);
917 ITask_GetParameters(task, &params);
918 ITask_GetWorkingDirectory(task, &workdir);
919 ITask_GetWorkItemData(task, &user_data_size, &user_data);
921 ver = GetVersion();
922 fixed.product_version = MAKEWORD(ver >> 8, ver);
923 fixed.file_version = 0x0001;
924 CoCreateGuid(&fixed.uuid);
925 fixed.name_size_offset = sizeof(fixed) + sizeof(USHORT); /* FIXDLEN_DATA + Instance Count */
926 fixed.trigger_offset = sizeof(fixed) + sizeof(USHORT); /* FIXDLEN_DATA + Instance Count */
927 fixed.trigger_offset += sizeof(USHORT); /* Application Name */
928 if (appname)
929 fixed.trigger_offset += (lstrlenW(appname) + 1) * sizeof(WCHAR);
930 fixed.trigger_offset += sizeof(USHORT); /* Parameters */
931 if (params)
932 fixed.trigger_offset += (lstrlenW(params) + 1) * sizeof(WCHAR);
933 fixed.trigger_offset += sizeof(USHORT); /* Working Directory */
934 if (workdir)
935 fixed.trigger_offset += (lstrlenW(workdir) + 1) * sizeof(WCHAR);
936 fixed.trigger_offset += sizeof(USHORT); /* Author */
937 if (creator)
938 fixed.trigger_offset += (lstrlenW(creator) + 1) * sizeof(WCHAR);
939 fixed.trigger_offset += sizeof(USHORT); /* Comment */
940 if (comment)
941 fixed.trigger_offset += (lstrlenW(comment) + 1) * sizeof(WCHAR);
942 fixed.trigger_offset += sizeof(USHORT) + user_data_size; /* User Data */
943 fixed.trigger_offset += 10; /* Reserved Data */
945 fixed.error_retry_count = 0;
946 fixed.error_retry_interval = 0;
947 fixed.idle_wait = This->idle_minutes;
948 fixed.idle_deadline = This->deadline_minutes;
949 fixed.priority = This->priority;
950 fixed.maximum_runtime = This->maxRunTime;
951 fixed.exit_code = 0;
952 fixed.status = SCHED_S_TASK_HAS_NOT_RUN;
953 fixed.flags = 0;
954 memset(&fixed.last_runtime, 0, sizeof(fixed.last_runtime));
956 hfile = CreateFileW(task_name, GENERIC_WRITE, 0, NULL, disposition, 0, 0);
957 if (hfile == INVALID_HANDLE_VALUE)
958 return HRESULT_FROM_WIN32(GetLastError());
960 if (!WriteFile(hfile, &fixed, sizeof(fixed), &size, NULL))
962 hr = HRESULT_FROM_WIN32(GetLastError());
963 goto failed;
966 /* Instance Count */
967 word = 0;
968 if (!WriteFile(hfile, &word, sizeof(word), &size, NULL))
970 hr = HRESULT_FROM_WIN32(GetLastError());
971 goto failed;
973 /* Application Name */
974 if (!write_unicode_string(hfile, appname))
976 hr = HRESULT_FROM_WIN32(GetLastError());
977 goto failed;
979 /* Parameters */
980 if (!write_unicode_string(hfile, params))
982 hr = HRESULT_FROM_WIN32(GetLastError());
983 goto failed;
985 /* Working Directory */
986 if (!write_unicode_string(hfile, workdir))
988 hr = HRESULT_FROM_WIN32(GetLastError());
989 goto failed;
991 /* Author */
992 if (!write_unicode_string(hfile, creator))
994 hr = HRESULT_FROM_WIN32(GetLastError());
995 goto failed;
997 /* Comment */
998 if (!write_unicode_string(hfile, comment))
1000 hr = HRESULT_FROM_WIN32(GetLastError());
1001 goto failed;
1004 /* User Data */
1005 if (!write_user_data(hfile, user_data, user_data_size))
1007 hr = HRESULT_FROM_WIN32(GetLastError());
1008 goto failed;
1011 /* Reserved Data */
1012 if (!write_reserved_data(hfile))
1014 hr = HRESULT_FROM_WIN32(GetLastError());
1015 goto failed;
1018 /* Triggers */
1019 hr = write_triggers(task, hfile);
1020 if (hr != S_OK)
1021 goto failed;
1023 /* Signature */
1024 if (!write_signature(hfile))
1026 hr = HRESULT_FROM_WIN32(GetLastError());
1027 goto failed;
1030 hr = S_OK;
1032 failed:
1033 CoTaskMemFree(appname);
1034 CoTaskMemFree(params);
1035 CoTaskMemFree(workdir);
1036 if (creator != authorW)
1037 CoTaskMemFree(creator);
1038 if (comment != commentW)
1039 CoTaskMemFree(comment);
1040 CoTaskMemFree(user_data);
1042 CloseHandle(hfile);
1043 if (hr != S_OK)
1044 DeleteFileW(task_name);
1045 else if (remember)
1047 HeapFree(GetProcessHeap(), 0, This->task_name);
1048 This->task_name = heap_strdupW(task_name);
1050 return hr;
1053 static HRESULT WINAPI MSTASK_IPersistFile_SaveCompleted(
1054 IPersistFile* iface,
1055 LPCOLESTR pszFileName)
1057 FIXME("(%p, %p): stub\n", iface, pszFileName);
1058 return E_NOTIMPL;
1061 static HRESULT WINAPI MSTASK_IPersistFile_GetCurFile(
1062 IPersistFile* iface,
1063 LPOLESTR *ppszFileName)
1065 FIXME("(%p, %p): stub\n", iface, ppszFileName);
1066 return E_NOTIMPL;
1069 static const ITaskVtbl MSTASK_ITaskVtbl =
1071 MSTASK_ITask_QueryInterface,
1072 MSTASK_ITask_AddRef,
1073 MSTASK_ITask_Release,
1074 MSTASK_ITask_CreateTrigger,
1075 MSTASK_ITask_DeleteTrigger,
1076 MSTASK_ITask_GetTriggerCount,
1077 MSTASK_ITask_GetTrigger,
1078 MSTASK_ITask_GetTriggerString,
1079 MSTASK_ITask_GetRunTimes,
1080 MSTASK_ITask_GetNextRunTime,
1081 MSTASK_ITask_SetIdleWait,
1082 MSTASK_ITask_GetIdleWait,
1083 MSTASK_ITask_Run,
1084 MSTASK_ITask_Terminate,
1085 MSTASK_ITask_EditWorkItem,
1086 MSTASK_ITask_GetMostRecentRunTime,
1087 MSTASK_ITask_GetStatus,
1088 MSTASK_ITask_GetExitCode,
1089 MSTASK_ITask_SetComment,
1090 MSTASK_ITask_GetComment,
1091 MSTASK_ITask_SetCreator,
1092 MSTASK_ITask_GetCreator,
1093 MSTASK_ITask_SetWorkItemData,
1094 MSTASK_ITask_GetWorkItemData,
1095 MSTASK_ITask_SetErrorRetryCount,
1096 MSTASK_ITask_GetErrorRetryCount,
1097 MSTASK_ITask_SetErrorRetryInterval,
1098 MSTASK_ITask_GetErrorRetryInterval,
1099 MSTASK_ITask_SetFlags,
1100 MSTASK_ITask_GetFlags,
1101 MSTASK_ITask_SetAccountInformation,
1102 MSTASK_ITask_GetAccountInformation,
1103 MSTASK_ITask_SetApplicationName,
1104 MSTASK_ITask_GetApplicationName,
1105 MSTASK_ITask_SetParameters,
1106 MSTASK_ITask_GetParameters,
1107 MSTASK_ITask_SetWorkingDirectory,
1108 MSTASK_ITask_GetWorkingDirectory,
1109 MSTASK_ITask_SetPriority,
1110 MSTASK_ITask_GetPriority,
1111 MSTASK_ITask_SetTaskFlags,
1112 MSTASK_ITask_GetTaskFlags,
1113 MSTASK_ITask_SetMaxRunTime,
1114 MSTASK_ITask_GetMaxRunTime
1117 static const IPersistFileVtbl MSTASK_IPersistFileVtbl =
1119 MSTASK_IPersistFile_QueryInterface,
1120 MSTASK_IPersistFile_AddRef,
1121 MSTASK_IPersistFile_Release,
1122 MSTASK_IPersistFile_GetClassID,
1123 MSTASK_IPersistFile_IsDirty,
1124 MSTASK_IPersistFile_Load,
1125 MSTASK_IPersistFile_Save,
1126 MSTASK_IPersistFile_SaveCompleted,
1127 MSTASK_IPersistFile_GetCurFile
1130 HRESULT TaskConstructor(ITaskService *service, const WCHAR *name, ITask **task)
1132 static const WCHAR tasksW[] = { '\\','T','a','s','k','s','\\',0 };
1133 static const WCHAR jobW[] = { '.','j','o','b',0 };
1134 TaskImpl *This;
1135 WCHAR task_name[MAX_PATH];
1136 ITaskDefinition *taskdef;
1137 IActionCollection *actions;
1138 HRESULT hr;
1140 TRACE("(%s, %p)\n", debugstr_w(name), task);
1142 if (strchrW(name, '.')) return E_INVALIDARG;
1144 GetWindowsDirectoryW(task_name, MAX_PATH);
1145 lstrcatW(task_name, tasksW);
1146 lstrcatW(task_name, name);
1147 lstrcatW(task_name, jobW);
1149 hr = ITaskService_NewTask(service, 0, &taskdef);
1150 if (hr != S_OK) return hr;
1152 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
1153 if (!This)
1155 ITaskDefinition_Release(taskdef);
1156 return E_OUTOFMEMORY;
1159 This->ITask_iface.lpVtbl = &MSTASK_ITaskVtbl;
1160 This->IPersistFile_iface.lpVtbl = &MSTASK_IPersistFileVtbl;
1161 This->ref = 1;
1162 This->task = taskdef;
1163 This->task_name = heap_strdupW(task_name);
1164 This->status = SCHED_S_TASK_NOT_SCHEDULED;
1165 This->idle_minutes = 10;
1166 This->deadline_minutes = 60;
1167 This->priority = NORMAL_PRIORITY_CLASS;
1168 This->accountName = NULL;
1169 This->trigger_count = 0;
1170 This->trigger = NULL;
1172 /* Default time is 3 days = 259200000 ms */
1173 This->maxRunTime = 259200000;
1175 hr = ITaskDefinition_get_Actions(This->task, &actions);
1176 if (hr == S_OK)
1178 hr = IActionCollection_Create(actions, TASK_ACTION_EXEC, (IAction **)&This->action);
1179 IActionCollection_Release(actions);
1180 if (hr == S_OK)
1182 *task = &This->ITask_iface;
1183 InterlockedIncrement(&dll_ref);
1184 return S_OK;
1188 ITaskDefinition_Release(This->task);
1189 ITask_Release(&This->ITask_iface);
1190 return hr;