mstask: Initialize task file name in the task constructor.
[wine.git] / dlls / mstask / task.c
blob58ff601eacafb0bc4fba4ccc2b985008ab59807b
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 } TaskImpl;
67 static inline TaskImpl *impl_from_ITask(ITask *iface)
69 return CONTAINING_RECORD(iface, TaskImpl, ITask_iface);
72 static inline TaskImpl *impl_from_IPersistFile( IPersistFile *iface )
74 return CONTAINING_RECORD(iface, TaskImpl, IPersistFile_iface);
77 static void TaskDestructor(TaskImpl *This)
79 TRACE("%p\n", This);
80 if (This->action)
81 IExecAction_Release(This->action);
82 ITaskDefinition_Release(This->task);
83 HeapFree(GetProcessHeap(), 0, This->task_name);
84 HeapFree(GetProcessHeap(), 0, This->accountName);
85 HeapFree(GetProcessHeap(), 0, This);
86 InterlockedDecrement(&dll_ref);
89 static HRESULT WINAPI MSTASK_ITask_QueryInterface(
90 ITask* iface,
91 REFIID riid,
92 void **ppvObject)
94 TaskImpl * This = impl_from_ITask(iface);
96 TRACE("IID: %s\n", debugstr_guid(riid));
97 if (ppvObject == NULL)
98 return E_POINTER;
100 if (IsEqualGUID(riid, &IID_IUnknown) ||
101 IsEqualGUID(riid, &IID_ITask))
103 *ppvObject = &This->ITask_iface;
104 ITask_AddRef(iface);
105 return S_OK;
107 else if (IsEqualGUID(riid, &IID_IPersistFile))
109 *ppvObject = &This->IPersistFile_iface;
110 ITask_AddRef(iface);
111 return S_OK;
114 WARN("Unknown interface: %s\n", debugstr_guid(riid));
115 *ppvObject = NULL;
116 return E_NOINTERFACE;
119 static ULONG WINAPI MSTASK_ITask_AddRef(
120 ITask* iface)
122 TaskImpl *This = impl_from_ITask(iface);
123 ULONG ref;
124 TRACE("\n");
125 ref = InterlockedIncrement(&This->ref);
126 return ref;
129 static ULONG WINAPI MSTASK_ITask_Release(
130 ITask* iface)
132 TaskImpl * This = impl_from_ITask(iface);
133 ULONG ref;
134 TRACE("\n");
135 ref = InterlockedDecrement(&This->ref);
136 if (ref == 0)
137 TaskDestructor(This);
138 return ref;
141 static HRESULT WINAPI MSTASK_ITask_CreateTrigger(
142 ITask* iface,
143 WORD *piNewTrigger,
144 ITaskTrigger **ppTrigger)
146 TRACE("(%p, %p, %p)\n", iface, piNewTrigger, ppTrigger);
147 return TaskTriggerConstructor((LPVOID *)ppTrigger);
150 static HRESULT WINAPI MSTASK_ITask_DeleteTrigger(
151 ITask* iface,
152 WORD iTrigger)
154 FIXME("(%p, %d): stub\n", iface, iTrigger);
155 return E_NOTIMPL;
158 static HRESULT WINAPI MSTASK_ITask_GetTriggerCount(
159 ITask* iface,
160 WORD *plCount)
162 FIXME("(%p, %p): stub\n", iface, plCount);
163 return E_NOTIMPL;
166 static HRESULT WINAPI MSTASK_ITask_GetTrigger(
167 ITask* iface,
168 WORD iTrigger,
169 ITaskTrigger **ppTrigger)
171 FIXME("(%p, %d, %p): stub\n", iface, iTrigger, ppTrigger);
172 return E_NOTIMPL;
175 static HRESULT WINAPI MSTASK_ITask_GetTriggerString(
176 ITask* iface,
177 WORD iTrigger,
178 LPWSTR *ppwszTrigger)
180 FIXME("(%p, %d, %p): stub\n", iface, iTrigger, ppwszTrigger);
181 return E_NOTIMPL;
184 static HRESULT WINAPI MSTASK_ITask_GetRunTimes(
185 ITask* iface,
186 const LPSYSTEMTIME pstBegin,
187 const LPSYSTEMTIME pstEnd,
188 WORD *pCount,
189 LPSYSTEMTIME *rgstTaskTimes)
191 FIXME("(%p, %p, %p, %p, %p): stub\n", iface, pstBegin, pstEnd, pCount,
192 rgstTaskTimes);
193 return E_NOTIMPL;
196 static HRESULT WINAPI MSTASK_ITask_GetNextRunTime(
197 ITask* iface,
198 SYSTEMTIME *pstNextRun)
200 FIXME("(%p, %p): stub\n", iface, pstNextRun);
201 return E_NOTIMPL;
204 static HRESULT WINAPI MSTASK_ITask_SetIdleWait(
205 ITask* iface,
206 WORD wIdleMinutes,
207 WORD wDeadlineMinutes)
209 FIXME("(%p, %d, %d): stub\n", iface, wIdleMinutes, wDeadlineMinutes);
210 return E_NOTIMPL;
213 static HRESULT WINAPI MSTASK_ITask_GetIdleWait(ITask *iface, WORD *idle_minutes, WORD *deadline_minutes)
215 TaskImpl *This = impl_from_ITask(iface);
217 TRACE("(%p, %p, %p): stub\n", iface, idle_minutes, deadline_minutes);
219 *idle_minutes = This->idle_minutes;
220 *deadline_minutes = This->deadline_minutes;
221 return S_OK;
224 static HRESULT WINAPI MSTASK_ITask_Run(
225 ITask* iface)
227 FIXME("(%p): stub\n", iface);
228 return E_NOTIMPL;
231 static HRESULT WINAPI MSTASK_ITask_Terminate(
232 ITask* iface)
234 FIXME("(%p): stub\n", iface);
235 return E_NOTIMPL;
238 static HRESULT WINAPI MSTASK_ITask_EditWorkItem(
239 ITask* iface,
240 HWND hParent,
241 DWORD dwReserved)
243 FIXME("(%p, %p, %d): stub\n", iface, hParent, dwReserved);
244 return E_NOTIMPL;
247 static HRESULT WINAPI MSTASK_ITask_GetMostRecentRunTime(ITask *iface, SYSTEMTIME *st)
249 FIXME("(%p, %p): stub\n", iface, st);
251 memset(st, 0, sizeof(*st));
252 return SCHED_S_TASK_HAS_NOT_RUN;
255 static HRESULT WINAPI MSTASK_ITask_GetStatus(ITask *iface, HRESULT *status)
257 TaskImpl *This = impl_from_ITask(iface);
259 TRACE("(%p, %p)\n", iface, status);
261 *status = This->status;
262 return S_OK;
265 static HRESULT WINAPI MSTASK_ITask_GetExitCode(ITask *iface, DWORD *exit_code)
267 FIXME("(%p, %p): stub\n", iface, exit_code);
269 *exit_code = 0;
270 return SCHED_S_TASK_HAS_NOT_RUN;
273 static HRESULT WINAPI MSTASK_ITask_SetComment(ITask *iface, LPCWSTR comment)
275 TaskImpl *This = impl_from_ITask(iface);
276 IRegistrationInfo *info;
277 HRESULT hr;
279 TRACE("(%p, %s)\n", iface, debugstr_w(comment));
281 if (!comment || !comment[0])
282 comment = NULL;
284 hr = ITaskDefinition_get_RegistrationInfo(This->task, &info);
285 if (hr == S_OK)
287 hr = IRegistrationInfo_put_Description(info, (BSTR)comment);
288 IRegistrationInfo_Release(info);
290 return hr;
293 static HRESULT WINAPI MSTASK_ITask_GetComment(ITask *iface, LPWSTR *comment)
295 TaskImpl *This = impl_from_ITask(iface);
296 IRegistrationInfo *info;
297 HRESULT hr;
298 BSTR description;
299 DWORD len;
301 TRACE("(%p, %p)\n", iface, comment);
303 hr = ITaskDefinition_get_RegistrationInfo(This->task, &info);
304 if (hr != S_OK) return hr;
306 hr = IRegistrationInfo_get_Description(info, &description);
307 if (hr == S_OK)
309 len = description ? lstrlenW(description) + 1 : 1;
310 *comment = CoTaskMemAlloc(len * sizeof(WCHAR));
311 if (*comment)
313 if (!description)
314 *comment[0] = 0;
315 else
316 lstrcpyW(*comment, description);
317 hr = S_OK;
319 else
320 hr = E_OUTOFMEMORY;
322 SysFreeString(description);
325 IRegistrationInfo_Release(info);
326 return hr;
329 static HRESULT WINAPI MSTASK_ITask_SetCreator(ITask *iface, LPCWSTR creator)
331 TaskImpl *This = impl_from_ITask(iface);
332 IRegistrationInfo *info;
333 HRESULT hr;
335 TRACE("(%p, %s)\n", iface, debugstr_w(creator));
337 if (!creator || !creator[0])
338 creator = NULL;
340 hr = ITaskDefinition_get_RegistrationInfo(This->task, &info);
341 if (hr == S_OK)
343 hr = IRegistrationInfo_put_Author(info, (BSTR)creator);
344 IRegistrationInfo_Release(info);
346 return hr;
349 static HRESULT WINAPI MSTASK_ITask_GetCreator(ITask *iface, LPWSTR *creator)
351 TaskImpl *This = impl_from_ITask(iface);
352 IRegistrationInfo *info;
353 HRESULT hr;
354 BSTR author;
355 DWORD len;
357 TRACE("(%p, %p)\n", iface, creator);
359 hr = ITaskDefinition_get_RegistrationInfo(This->task, &info);
360 if (hr != S_OK) return hr;
362 hr = IRegistrationInfo_get_Author(info, &author);
363 if (hr == S_OK)
365 len = author ? lstrlenW(author) + 1 : 1;
366 *creator = CoTaskMemAlloc(len * sizeof(WCHAR));
367 if (*creator)
369 if (!author)
370 *creator[0] = 0;
371 else
372 lstrcpyW(*creator, author);
373 hr = S_OK;
375 else
376 hr = E_OUTOFMEMORY;
378 SysFreeString(author);
381 IRegistrationInfo_Release(info);
382 return hr;
385 static HRESULT WINAPI MSTASK_ITask_SetWorkItemData(
386 ITask* iface,
387 WORD cBytes,
388 BYTE rgbData[])
390 FIXME("(%p, %d, %p): stub\n", iface, cBytes, rgbData);
391 return E_NOTIMPL;
394 static HRESULT WINAPI MSTASK_ITask_GetWorkItemData(
395 ITask* iface,
396 WORD *pcBytes,
397 BYTE **ppBytes)
399 FIXME("(%p, %p, %p): stub\n", iface, pcBytes, ppBytes);
400 return E_NOTIMPL;
403 static HRESULT WINAPI MSTASK_ITask_SetErrorRetryCount(
404 ITask* iface,
405 WORD wRetryCount)
407 FIXME("(%p, %d): stub\n", iface, wRetryCount);
408 return E_NOTIMPL;
411 static HRESULT WINAPI MSTASK_ITask_GetErrorRetryCount(ITask *iface, WORD *count)
413 TRACE("(%p, %p)\n", iface, count);
414 return E_NOTIMPL;
417 static HRESULT WINAPI MSTASK_ITask_SetErrorRetryInterval(
418 ITask* iface,
419 WORD wRetryInterval)
421 FIXME("(%p, %d): stub\n", iface, wRetryInterval);
422 return E_NOTIMPL;
425 static HRESULT WINAPI MSTASK_ITask_GetErrorRetryInterval(ITask *iface, WORD *interval)
427 TRACE("(%p, %p)\n", iface, interval);
428 return E_NOTIMPL;
431 static HRESULT WINAPI MSTASK_ITask_SetFlags(
432 ITask* iface,
433 DWORD dwFlags)
435 FIXME("(%p, 0x%08x): stub\n", iface, dwFlags);
436 return E_NOTIMPL;
439 static HRESULT WINAPI MSTASK_ITask_GetFlags(ITask *iface, DWORD *flags)
441 FIXME("(%p, %p): stub\n", iface, flags);
442 *flags = 0;
443 return S_OK;
446 static HRESULT WINAPI MSTASK_ITask_SetAccountInformation(
447 ITask* iface,
448 LPCWSTR pwszAccountName,
449 LPCWSTR pwszPassword)
451 DWORD n;
452 TaskImpl *This = impl_from_ITask(iface);
453 LPWSTR tmp_account_name;
455 TRACE("(%p, %s, %s): partial stub\n", iface, debugstr_w(pwszAccountName),
456 debugstr_w(pwszPassword));
458 if (pwszPassword)
459 FIXME("Partial stub ignores passwords\n");
461 n = (lstrlenW(pwszAccountName) + 1);
462 tmp_account_name = HeapAlloc(GetProcessHeap(), 0, n * sizeof(WCHAR));
463 if (!tmp_account_name)
464 return E_OUTOFMEMORY;
465 lstrcpyW(tmp_account_name, pwszAccountName);
466 HeapFree(GetProcessHeap(), 0, This->accountName);
467 This->accountName = tmp_account_name;
468 return S_OK;
471 static HRESULT WINAPI MSTASK_ITask_GetAccountInformation(
472 ITask* iface,
473 LPWSTR *ppwszAccountName)
475 DWORD n;
476 TaskImpl *This = impl_from_ITask(iface);
478 TRACE("(%p, %p): partial stub\n", iface, ppwszAccountName);
480 /* This implements the WinXP behavior when accountName has not yet
481 * set. Win2K behaves differently, returning SCHED_E_CANNOT_OPEN_TASK */
482 if (!This->accountName)
483 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
485 n = (lstrlenW(This->accountName) + 1);
486 *ppwszAccountName = CoTaskMemAlloc(n * sizeof(WCHAR));
487 if (!*ppwszAccountName)
488 return E_OUTOFMEMORY;
489 lstrcpyW(*ppwszAccountName, This->accountName);
490 return S_OK;
493 static HRESULT WINAPI MSTASK_ITask_SetApplicationName(ITask *iface, LPCWSTR appname)
495 TaskImpl *This = impl_from_ITask(iface);
496 DWORD len;
498 TRACE("(%p, %s)\n", iface, debugstr_w(appname));
500 /* Empty application name */
501 if (!appname || !appname[0])
502 return IExecAction_put_Path(This->action, NULL);
504 /* Attempt to set pwszApplicationName to a path resolved application name */
505 len = SearchPathW(NULL, appname, NULL, 0, NULL, NULL);
506 if (len)
508 LPWSTR tmp_name;
509 HRESULT hr;
511 tmp_name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
512 if (!tmp_name)
513 return E_OUTOFMEMORY;
514 len = SearchPathW(NULL, appname, NULL, len, tmp_name, NULL);
515 if (len)
516 hr = IExecAction_put_Path(This->action, tmp_name);
517 else
518 hr = HRESULT_FROM_WIN32(GetLastError());
520 HeapFree(GetProcessHeap(), 0, tmp_name);
521 return hr;
524 /* If unable to path resolve name, simply set to appname */
525 return IExecAction_put_Path(This->action, (BSTR)appname);
528 static HRESULT WINAPI MSTASK_ITask_GetApplicationName(ITask *iface, LPWSTR *appname)
530 TaskImpl *This = impl_from_ITask(iface);
531 HRESULT hr;
532 BSTR path;
533 DWORD len;
535 TRACE("(%p, %p)\n", iface, appname);
537 hr = IExecAction_get_Path(This->action, &path);
538 if (hr != S_OK) return hr;
540 len = path ? lstrlenW(path) + 1 : 1;
541 *appname = CoTaskMemAlloc(len * sizeof(WCHAR));
542 if (*appname)
544 if (!path)
545 *appname[0] = 0;
546 else
547 lstrcpyW(*appname, path);
548 hr = S_OK;
550 else
551 hr = E_OUTOFMEMORY;
553 SysFreeString(path);
554 return hr;
557 static HRESULT WINAPI MSTASK_ITask_SetParameters(ITask *iface, LPCWSTR params)
559 TaskImpl *This = impl_from_ITask(iface);
561 TRACE("(%p, %s)\n", iface, debugstr_w(params));
563 /* Empty parameter list */
564 if (!params || !params[0])
565 params = NULL;
567 return IExecAction_put_Arguments(This->action, (BSTR)params);
570 static HRESULT WINAPI MSTASK_ITask_GetParameters(ITask *iface, LPWSTR *params)
572 TaskImpl *This = impl_from_ITask(iface);
573 HRESULT hr;
574 BSTR args;
575 DWORD len;
577 TRACE("(%p, %p)\n", iface, params);
579 hr = IExecAction_get_Arguments(This->action, &args);
580 if (hr != S_OK) return hr;
582 len = args ? lstrlenW(args) + 1 : 1;
583 *params = CoTaskMemAlloc(len * sizeof(WCHAR));
584 if (*params)
586 if (!args)
587 *params[0] = 0;
588 else
589 lstrcpyW(*params, args);
590 hr = S_OK;
592 else
593 hr = E_OUTOFMEMORY;
595 SysFreeString(args);
596 return hr;
599 static HRESULT WINAPI MSTASK_ITask_SetWorkingDirectory(ITask * iface, LPCWSTR workdir)
601 TaskImpl *This = impl_from_ITask(iface);
603 TRACE("(%p, %s)\n", iface, debugstr_w(workdir));
605 if (!workdir || !workdir[0])
606 workdir = NULL;
608 return IExecAction_put_WorkingDirectory(This->action, (BSTR)workdir);
611 static HRESULT WINAPI MSTASK_ITask_GetWorkingDirectory(ITask *iface, LPWSTR *workdir)
613 TaskImpl *This = impl_from_ITask(iface);
614 HRESULT hr;
615 BSTR dir;
616 DWORD len;
618 TRACE("(%p, %p)\n", iface, workdir);
620 hr = IExecAction_get_WorkingDirectory(This->action, &dir);
621 if (hr != S_OK) return hr;
623 len = dir ? lstrlenW(dir) + 1 : 1;
624 *workdir = CoTaskMemAlloc(len * sizeof(WCHAR));
625 if (*workdir)
627 if (!dir)
628 *workdir[0] = 0;
629 else
630 lstrcpyW(*workdir, dir);
631 hr = S_OK;
633 else
634 hr = E_OUTOFMEMORY;
636 SysFreeString(dir);
637 return hr;
640 static HRESULT WINAPI MSTASK_ITask_SetPriority(
641 ITask* iface,
642 DWORD dwPriority)
644 FIXME("(%p, 0x%08x): stub\n", iface, dwPriority);
645 return E_NOTIMPL;
648 static HRESULT WINAPI MSTASK_ITask_GetPriority(ITask *iface, DWORD *priority)
650 TaskImpl *This = impl_from_ITask(iface);
652 TRACE("(%p, %p)\n", iface, priority);
654 *priority = This->priority;
655 return S_OK;
658 static HRESULT WINAPI MSTASK_ITask_SetTaskFlags(
659 ITask* iface,
660 DWORD dwFlags)
662 FIXME("(%p, 0x%08x): stub\n", iface, dwFlags);
663 return E_NOTIMPL;
666 static HRESULT WINAPI MSTASK_ITask_GetTaskFlags(ITask *iface, DWORD *flags)
668 FIXME("(%p, %p): stub\n", iface, flags);
669 *flags = 0;
670 return S_OK;
673 static HRESULT WINAPI MSTASK_ITask_SetMaxRunTime(
674 ITask* iface,
675 DWORD dwMaxRunTime)
677 TaskImpl *This = impl_from_ITask(iface);
679 TRACE("(%p, %d)\n", iface, dwMaxRunTime);
681 This->maxRunTime = dwMaxRunTime;
682 return S_OK;
685 static HRESULT WINAPI MSTASK_ITask_GetMaxRunTime(
686 ITask* iface,
687 DWORD *pdwMaxRunTime)
689 TaskImpl *This = impl_from_ITask(iface);
691 TRACE("(%p, %p)\n", iface, pdwMaxRunTime);
693 *pdwMaxRunTime = This->maxRunTime;
694 return S_OK;
697 static HRESULT WINAPI MSTASK_IPersistFile_QueryInterface(
698 IPersistFile* iface,
699 REFIID riid,
700 void **ppvObject)
702 TaskImpl *This = impl_from_IPersistFile(iface);
703 TRACE("(%p, %s, %p)\n", iface, debugstr_guid(riid), ppvObject);
704 return ITask_QueryInterface(&This->ITask_iface, riid, ppvObject);
707 static ULONG WINAPI MSTASK_IPersistFile_AddRef(
708 IPersistFile* iface)
710 TaskImpl *This = impl_from_IPersistFile(iface);
711 ULONG ref;
712 TRACE("\n");
713 ref = InterlockedIncrement(&This->ref);
714 return ref;
717 static ULONG WINAPI MSTASK_IPersistFile_Release(
718 IPersistFile* iface)
720 TaskImpl *This = impl_from_IPersistFile(iface);
721 ULONG ref;
722 TRACE("\n");
723 ref = InterlockedDecrement(&This->ref);
724 if (ref == 0)
725 TaskDestructor(This);
726 return ref;
729 static HRESULT WINAPI MSTASK_IPersistFile_GetClassID(IPersistFile *iface, CLSID *clsid)
731 TRACE("(%p, %p)\n", iface, clsid);
733 *clsid = CLSID_CTask;
734 return S_OK;
737 static HRESULT WINAPI MSTASK_IPersistFile_IsDirty(
738 IPersistFile* iface)
740 FIXME("(%p): stub\n", iface);
741 return E_NOTIMPL;
744 static HRESULT WINAPI MSTASK_IPersistFile_Load(
745 IPersistFile* iface,
746 LPCOLESTR pszFileName,
747 DWORD dwMode)
749 FIXME("(%p, %p, 0x%08x): stub\n", iface, pszFileName, dwMode);
750 return E_NOTIMPL;
753 static BOOL write_signature(HANDLE hfile)
755 struct
757 USHORT SignatureVersion;
758 USHORT ClientVersion;
759 BYTE md5[64];
760 } signature;
761 DWORD size;
763 signature.SignatureVersion = 0x0001;
764 signature.ClientVersion = 0x0001;
765 memset(&signature.md5, 0, sizeof(signature.md5));
767 return WriteFile(hfile, &signature, sizeof(signature), &size, NULL);
770 static BOOL write_reserved_data(HANDLE hfile)
772 static const struct
774 USHORT size;
775 BYTE data[8];
776 } user = { 8, { 0xff,0x0f,0x1d,0,0,0,0,0 } };
777 DWORD size;
779 return WriteFile(hfile, &user, sizeof(user), &size, NULL);
782 static BOOL write_user_data(HANDLE hfile, BYTE *data, WORD data_size)
784 DWORD size;
786 if (!WriteFile(hfile, &data_size, sizeof(data_size), &size, NULL))
787 return FALSE;
789 if (!data_size) return TRUE;
791 return WriteFile(hfile, data, data_size, &size, NULL);
794 static HRESULT write_triggers(ITask *task, HANDLE hfile)
796 WORD count, i, idx = 0xffff;
797 DWORD size;
798 HRESULT hr;
799 ITaskTrigger *trigger;
801 hr = ITask_GetTriggerCount(task, &count);
802 if (hr != S_OK) return hr;
804 if (!WriteFile(hfile, &count, sizeof(count), &size, NULL))
805 return HRESULT_FROM_WIN32(GetLastError());
807 /* Windows saves a .job with at least 1 trigger */
808 if (!count)
810 hr = ITask_CreateTrigger(task, &idx, &trigger);
811 if (hr != S_OK) return hr;
812 ITaskTrigger_Release(trigger);
814 count = 1;
817 for (i = 0; i < count; i++)
819 TASK_TRIGGER task_trigger;
821 hr = ITask_GetTrigger(task, i, &trigger);
822 if (hr != S_OK) return hr;
824 hr = ITaskTrigger_GetTrigger(trigger, &task_trigger);
825 ITaskTrigger_Release(trigger);
826 if (hr != S_OK) break;
828 if (!WriteFile(hfile, &task_trigger, sizeof(task_trigger), &size, NULL))
829 return HRESULT_FROM_WIN32(GetLastError());
832 if (idx != 0xffff)
833 ITask_DeleteTrigger(task, idx);
835 return hr;
838 static BOOL write_unicode_string(HANDLE hfile, const WCHAR *str)
840 USHORT count;
841 DWORD size;
843 count = str ? (lstrlenW(str) + 1) : 0;
844 if (!WriteFile(hfile, &count, sizeof(count), &size, NULL))
845 return FALSE;
847 if (!str) return TRUE;
849 count *= sizeof(WCHAR);
850 return WriteFile(hfile, str, count, &size, NULL);
853 static HRESULT WINAPI MSTASK_IPersistFile_Save(IPersistFile *iface, LPCOLESTR task_name, BOOL remember)
855 static WCHAR authorW[] = { 'W','i','n','e',0 };
856 static WCHAR commentW[] = { 'C','r','e','a','t','e','d',' ','b','y',' ','W','i','n','e',0 };
857 FIXDLEN_DATA fixed;
858 WORD word, user_data_size = 0;
859 HANDLE hfile;
860 DWORD size, ver, disposition;
861 TaskImpl *This = impl_from_IPersistFile(iface);
862 ITask *task = &This->ITask_iface;
863 LPWSTR appname = NULL, params = NULL, workdir = NULL, creator = NULL, comment = NULL;
864 BYTE *user_data = NULL;
865 HRESULT hr;
867 TRACE("(%p, %s, %d)\n", iface, debugstr_w(task_name), remember);
869 disposition = task_name ? CREATE_NEW : OPEN_ALWAYS;
871 if (!task_name)
873 task_name = This->task_name;
874 remember = FALSE;
877 ITask_GetComment(task, &comment);
878 if (!comment) comment = commentW;
879 ITask_GetCreator(task, &creator);
880 if (!creator) creator = authorW;
881 ITask_GetApplicationName(task, &appname);
882 ITask_GetParameters(task, &params);
883 ITask_GetWorkingDirectory(task, &workdir);
884 ITask_GetWorkItemData(task, &user_data_size, &user_data);
886 ver = GetVersion();
887 fixed.product_version = MAKEWORD(ver >> 8, ver);
888 fixed.file_version = 0x0001;
889 CoCreateGuid(&fixed.uuid);
890 fixed.name_size_offset = sizeof(fixed) + sizeof(USHORT); /* FIXDLEN_DATA + Instance Count */
891 fixed.trigger_offset = sizeof(fixed) + sizeof(USHORT); /* FIXDLEN_DATA + Instance Count */
892 fixed.trigger_offset += sizeof(USHORT); /* Application Name */
893 if (appname)
894 fixed.trigger_offset += (lstrlenW(appname) + 1) * sizeof(WCHAR);
895 fixed.trigger_offset += sizeof(USHORT); /* Parameters */
896 if (params)
897 fixed.trigger_offset += (lstrlenW(params) + 1) * sizeof(WCHAR);
898 fixed.trigger_offset += sizeof(USHORT); /* Working Directory */
899 if (workdir)
900 fixed.trigger_offset += (lstrlenW(workdir) + 1) * sizeof(WCHAR);
901 fixed.trigger_offset += sizeof(USHORT); /* Author */
902 if (creator)
903 fixed.trigger_offset += (lstrlenW(creator) + 1) * sizeof(WCHAR);
904 fixed.trigger_offset += sizeof(USHORT); /* Comment */
905 if (comment)
906 fixed.trigger_offset += (lstrlenW(comment) + 1) * sizeof(WCHAR);
907 fixed.trigger_offset += sizeof(USHORT) + user_data_size; /* User Data */
908 fixed.trigger_offset += 10; /* Reserved Data */
910 fixed.error_retry_count = 0;
911 fixed.error_retry_interval = 0;
912 fixed.idle_wait = This->idle_minutes;
913 fixed.idle_deadline = This->deadline_minutes;
914 fixed.priority = This->priority;
915 fixed.maximum_runtime = This->maxRunTime;
916 fixed.exit_code = 0;
917 fixed.status = SCHED_S_TASK_HAS_NOT_RUN;
918 fixed.flags = 0;
919 memset(&fixed.last_runtime, 0, sizeof(fixed.last_runtime));
921 hfile = CreateFileW(task_name, GENERIC_WRITE, 0, NULL, disposition, 0, 0);
922 if (hfile == INVALID_HANDLE_VALUE)
923 return HRESULT_FROM_WIN32(GetLastError());
925 if (!WriteFile(hfile, &fixed, sizeof(fixed), &size, NULL))
927 hr = HRESULT_FROM_WIN32(GetLastError());
928 goto failed;
931 /* Instance Count */
932 word = 0;
933 if (!WriteFile(hfile, &word, sizeof(word), &size, NULL))
935 hr = HRESULT_FROM_WIN32(GetLastError());
936 goto failed;
938 /* Application Name */
939 if (!write_unicode_string(hfile, appname))
941 hr = HRESULT_FROM_WIN32(GetLastError());
942 goto failed;
944 /* Parameters */
945 if (!write_unicode_string(hfile, params))
947 hr = HRESULT_FROM_WIN32(GetLastError());
948 goto failed;
950 /* Working Directory */
951 if (!write_unicode_string(hfile, workdir))
953 hr = HRESULT_FROM_WIN32(GetLastError());
954 goto failed;
956 /* Author */
957 if (!write_unicode_string(hfile, creator))
959 hr = HRESULT_FROM_WIN32(GetLastError());
960 goto failed;
962 /* Comment */
963 if (!write_unicode_string(hfile, comment))
965 hr = HRESULT_FROM_WIN32(GetLastError());
966 goto failed;
969 /* User Data */
970 if (!write_user_data(hfile, user_data, user_data_size))
972 hr = HRESULT_FROM_WIN32(GetLastError());
973 goto failed;
976 /* Reserved Data */
977 if (!write_reserved_data(hfile))
979 hr = HRESULT_FROM_WIN32(GetLastError());
980 goto failed;
983 /* Trigegrs */
984 if (!write_triggers(hfile, task))
986 hr = HRESULT_FROM_WIN32(GetLastError());
987 goto failed;
990 /* Signature */
991 if (!write_signature(hfile))
993 hr = HRESULT_FROM_WIN32(GetLastError());
994 goto failed;
997 hr = S_OK;
999 failed:
1000 CoTaskMemFree(appname);
1001 CoTaskMemFree(params);
1002 CoTaskMemFree(workdir);
1003 if (creator != authorW)
1004 CoTaskMemFree(creator);
1005 if (comment != commentW)
1006 CoTaskMemFree(comment);
1007 CoTaskMemFree(user_data);
1009 CloseHandle(hfile);
1010 if (hr != S_OK)
1011 DeleteFileW(task_name);
1012 else if (remember)
1014 HeapFree(GetProcessHeap(), 0, This->task_name);
1015 This->task_name = heap_strdupW(task_name);
1017 return hr;
1020 static HRESULT WINAPI MSTASK_IPersistFile_SaveCompleted(
1021 IPersistFile* iface,
1022 LPCOLESTR pszFileName)
1024 FIXME("(%p, %p): stub\n", iface, pszFileName);
1025 return E_NOTIMPL;
1028 static HRESULT WINAPI MSTASK_IPersistFile_GetCurFile(
1029 IPersistFile* iface,
1030 LPOLESTR *ppszFileName)
1032 FIXME("(%p, %p): stub\n", iface, ppszFileName);
1033 return E_NOTIMPL;
1036 static const ITaskVtbl MSTASK_ITaskVtbl =
1038 MSTASK_ITask_QueryInterface,
1039 MSTASK_ITask_AddRef,
1040 MSTASK_ITask_Release,
1041 MSTASK_ITask_CreateTrigger,
1042 MSTASK_ITask_DeleteTrigger,
1043 MSTASK_ITask_GetTriggerCount,
1044 MSTASK_ITask_GetTrigger,
1045 MSTASK_ITask_GetTriggerString,
1046 MSTASK_ITask_GetRunTimes,
1047 MSTASK_ITask_GetNextRunTime,
1048 MSTASK_ITask_SetIdleWait,
1049 MSTASK_ITask_GetIdleWait,
1050 MSTASK_ITask_Run,
1051 MSTASK_ITask_Terminate,
1052 MSTASK_ITask_EditWorkItem,
1053 MSTASK_ITask_GetMostRecentRunTime,
1054 MSTASK_ITask_GetStatus,
1055 MSTASK_ITask_GetExitCode,
1056 MSTASK_ITask_SetComment,
1057 MSTASK_ITask_GetComment,
1058 MSTASK_ITask_SetCreator,
1059 MSTASK_ITask_GetCreator,
1060 MSTASK_ITask_SetWorkItemData,
1061 MSTASK_ITask_GetWorkItemData,
1062 MSTASK_ITask_SetErrorRetryCount,
1063 MSTASK_ITask_GetErrorRetryCount,
1064 MSTASK_ITask_SetErrorRetryInterval,
1065 MSTASK_ITask_GetErrorRetryInterval,
1066 MSTASK_ITask_SetFlags,
1067 MSTASK_ITask_GetFlags,
1068 MSTASK_ITask_SetAccountInformation,
1069 MSTASK_ITask_GetAccountInformation,
1070 MSTASK_ITask_SetApplicationName,
1071 MSTASK_ITask_GetApplicationName,
1072 MSTASK_ITask_SetParameters,
1073 MSTASK_ITask_GetParameters,
1074 MSTASK_ITask_SetWorkingDirectory,
1075 MSTASK_ITask_GetWorkingDirectory,
1076 MSTASK_ITask_SetPriority,
1077 MSTASK_ITask_GetPriority,
1078 MSTASK_ITask_SetTaskFlags,
1079 MSTASK_ITask_GetTaskFlags,
1080 MSTASK_ITask_SetMaxRunTime,
1081 MSTASK_ITask_GetMaxRunTime
1084 static const IPersistFileVtbl MSTASK_IPersistFileVtbl =
1086 MSTASK_IPersistFile_QueryInterface,
1087 MSTASK_IPersistFile_AddRef,
1088 MSTASK_IPersistFile_Release,
1089 MSTASK_IPersistFile_GetClassID,
1090 MSTASK_IPersistFile_IsDirty,
1091 MSTASK_IPersistFile_Load,
1092 MSTASK_IPersistFile_Save,
1093 MSTASK_IPersistFile_SaveCompleted,
1094 MSTASK_IPersistFile_GetCurFile
1097 HRESULT TaskConstructor(ITaskService *service, const WCHAR *name, ITask **task)
1099 static const WCHAR tasksW[] = { '\\','T','a','s','k','s','\\',0 };
1100 static const WCHAR jobW[] = { '.','j','o','b',0 };
1101 TaskImpl *This;
1102 WCHAR task_name[MAX_PATH];
1103 ITaskDefinition *taskdef;
1104 IActionCollection *actions;
1105 HRESULT hr;
1107 TRACE("(%s, %p)\n", debugstr_w(name), task);
1109 if (strchrW(name, '.')) return E_INVALIDARG;
1111 GetWindowsDirectoryW(task_name, MAX_PATH);
1112 lstrcatW(task_name, tasksW);
1113 lstrcatW(task_name, name);
1114 lstrcatW(task_name, jobW);
1116 hr = ITaskService_NewTask(service, 0, &taskdef);
1117 if (hr != S_OK) return hr;
1119 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
1120 if (!This)
1122 ITaskDefinition_Release(taskdef);
1123 return E_OUTOFMEMORY;
1126 This->ITask_iface.lpVtbl = &MSTASK_ITaskVtbl;
1127 This->IPersistFile_iface.lpVtbl = &MSTASK_IPersistFileVtbl;
1128 This->ref = 1;
1129 This->task = taskdef;
1130 This->task_name = heap_strdupW(task_name);
1131 This->status = SCHED_S_TASK_NOT_SCHEDULED;
1132 This->idle_minutes = 10;
1133 This->deadline_minutes = 60;
1134 This->priority = NORMAL_PRIORITY_CLASS;
1135 This->accountName = NULL;
1137 /* Default time is 3 days = 259200000 ms */
1138 This->maxRunTime = 259200000;
1140 hr = ITaskDefinition_get_Actions(This->task, &actions);
1141 if (hr == S_OK)
1143 hr = IActionCollection_Create(actions, TASK_ACTION_EXEC, (IAction **)&This->action);
1144 IActionCollection_Release(actions);
1145 if (hr == S_OK)
1147 *task = &This->ITask_iface;
1148 InterlockedIncrement(&dll_ref);
1149 return S_OK;
1153 ITaskDefinition_Release(This->task);
1154 ITask_Release(&This->ITask_iface);
1155 return hr;