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
29 #include "mstask_private.h"
30 #include "wine/debug.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(mstask
);
36 USHORT product_version
;
39 USHORT name_size_offset
;
40 USHORT trigger_offset
;
41 USHORT error_retry_count
;
42 USHORT error_retry_interval
;
50 SYSTEMTIME last_runtime
;
56 IPersistFile IPersistFile_iface
;
58 ITaskDefinition
*task
;
62 WORD idle_minutes
, deadline_minutes
;
63 DWORD priority
, maxRunTime
;
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
)
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(
94 TaskImpl
* This
= impl_from_ITask(iface
);
96 TRACE("IID: %s\n", debugstr_guid(riid
));
97 if (ppvObject
== NULL
)
100 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
101 IsEqualGUID(riid
, &IID_ITask
))
103 *ppvObject
= &This
->ITask_iface
;
107 else if (IsEqualGUID(riid
, &IID_IPersistFile
))
109 *ppvObject
= &This
->IPersistFile_iface
;
114 WARN("Unknown interface: %s\n", debugstr_guid(riid
));
116 return E_NOINTERFACE
;
119 static ULONG WINAPI
MSTASK_ITask_AddRef(
122 TaskImpl
*This
= impl_from_ITask(iface
);
125 ref
= InterlockedIncrement(&This
->ref
);
129 static ULONG WINAPI
MSTASK_ITask_Release(
132 TaskImpl
* This
= impl_from_ITask(iface
);
135 ref
= InterlockedDecrement(&This
->ref
);
137 TaskDestructor(This
);
141 static HRESULT WINAPI
MSTASK_ITask_CreateTrigger(
144 ITaskTrigger
**ppTrigger
)
146 TRACE("(%p, %p, %p)\n", iface
, piNewTrigger
, ppTrigger
);
147 return TaskTriggerConstructor((LPVOID
*)ppTrigger
);
150 static HRESULT WINAPI
MSTASK_ITask_DeleteTrigger(
154 FIXME("(%p, %d): stub\n", iface
, iTrigger
);
158 static HRESULT WINAPI
MSTASK_ITask_GetTriggerCount(
162 FIXME("(%p, %p): stub\n", iface
, plCount
);
166 static HRESULT WINAPI
MSTASK_ITask_GetTrigger(
169 ITaskTrigger
**ppTrigger
)
171 FIXME("(%p, %d, %p): stub\n", iface
, iTrigger
, ppTrigger
);
175 static HRESULT WINAPI
MSTASK_ITask_GetTriggerString(
178 LPWSTR
*ppwszTrigger
)
180 FIXME("(%p, %d, %p): stub\n", iface
, iTrigger
, ppwszTrigger
);
184 static HRESULT WINAPI
MSTASK_ITask_GetRunTimes(
186 const LPSYSTEMTIME pstBegin
,
187 const LPSYSTEMTIME pstEnd
,
189 LPSYSTEMTIME
*rgstTaskTimes
)
191 FIXME("(%p, %p, %p, %p, %p): stub\n", iface
, pstBegin
, pstEnd
, pCount
,
196 static HRESULT WINAPI
MSTASK_ITask_GetNextRunTime(
198 SYSTEMTIME
*pstNextRun
)
200 FIXME("(%p, %p): stub\n", iface
, pstNextRun
);
204 static HRESULT WINAPI
MSTASK_ITask_SetIdleWait(
207 WORD wDeadlineMinutes
)
209 FIXME("(%p, %d, %d): stub\n", iface
, wIdleMinutes
, wDeadlineMinutes
);
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
;
224 static HRESULT WINAPI
MSTASK_ITask_Run(
227 FIXME("(%p): stub\n", iface
);
231 static HRESULT WINAPI
MSTASK_ITask_Terminate(
234 FIXME("(%p): stub\n", iface
);
238 static HRESULT WINAPI
MSTASK_ITask_EditWorkItem(
243 FIXME("(%p, %p, %d): stub\n", iface
, hParent
, dwReserved
);
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
;
265 static HRESULT WINAPI
MSTASK_ITask_GetExitCode(ITask
*iface
, DWORD
*exit_code
)
267 FIXME("(%p, %p): stub\n", iface
, exit_code
);
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
;
279 TRACE("(%p, %s)\n", iface
, debugstr_w(comment
));
281 if (!comment
|| !comment
[0])
284 hr
= ITaskDefinition_get_RegistrationInfo(This
->task
, &info
);
287 hr
= IRegistrationInfo_put_Description(info
, (BSTR
)comment
);
288 IRegistrationInfo_Release(info
);
293 static HRESULT WINAPI
MSTASK_ITask_GetComment(ITask
*iface
, LPWSTR
*comment
)
295 TaskImpl
*This
= impl_from_ITask(iface
);
296 IRegistrationInfo
*info
;
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
);
309 len
= description
? lstrlenW(description
) + 1 : 1;
310 *comment
= CoTaskMemAlloc(len
* sizeof(WCHAR
));
316 lstrcpyW(*comment
, description
);
322 SysFreeString(description
);
325 IRegistrationInfo_Release(info
);
329 static HRESULT WINAPI
MSTASK_ITask_SetCreator(ITask
*iface
, LPCWSTR creator
)
331 TaskImpl
*This
= impl_from_ITask(iface
);
332 IRegistrationInfo
*info
;
335 TRACE("(%p, %s)\n", iface
, debugstr_w(creator
));
337 if (!creator
|| !creator
[0])
340 hr
= ITaskDefinition_get_RegistrationInfo(This
->task
, &info
);
343 hr
= IRegistrationInfo_put_Author(info
, (BSTR
)creator
);
344 IRegistrationInfo_Release(info
);
349 static HRESULT WINAPI
MSTASK_ITask_GetCreator(ITask
*iface
, LPWSTR
*creator
)
351 TaskImpl
*This
= impl_from_ITask(iface
);
352 IRegistrationInfo
*info
;
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
);
365 len
= author
? lstrlenW(author
) + 1 : 1;
366 *creator
= CoTaskMemAlloc(len
* sizeof(WCHAR
));
372 lstrcpyW(*creator
, author
);
378 SysFreeString(author
);
381 IRegistrationInfo_Release(info
);
385 static HRESULT WINAPI
MSTASK_ITask_SetWorkItemData(
390 FIXME("(%p, %d, %p): stub\n", iface
, cBytes
, rgbData
);
394 static HRESULT WINAPI
MSTASK_ITask_GetWorkItemData(
399 FIXME("(%p, %p, %p): stub\n", iface
, pcBytes
, ppBytes
);
403 static HRESULT WINAPI
MSTASK_ITask_SetErrorRetryCount(
407 FIXME("(%p, %d): stub\n", iface
, wRetryCount
);
411 static HRESULT WINAPI
MSTASK_ITask_GetErrorRetryCount(ITask
*iface
, WORD
*count
)
413 TRACE("(%p, %p)\n", iface
, count
);
417 static HRESULT WINAPI
MSTASK_ITask_SetErrorRetryInterval(
421 FIXME("(%p, %d): stub\n", iface
, wRetryInterval
);
425 static HRESULT WINAPI
MSTASK_ITask_GetErrorRetryInterval(ITask
*iface
, WORD
*interval
)
427 TRACE("(%p, %p)\n", iface
, interval
);
431 static HRESULT WINAPI
MSTASK_ITask_SetFlags(
435 FIXME("(%p, 0x%08x): stub\n", iface
, dwFlags
);
439 static HRESULT WINAPI
MSTASK_ITask_GetFlags(ITask
*iface
, DWORD
*flags
)
441 FIXME("(%p, %p): stub\n", iface
, flags
);
446 static HRESULT WINAPI
MSTASK_ITask_SetAccountInformation(
448 LPCWSTR pwszAccountName
,
449 LPCWSTR pwszPassword
)
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
));
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
;
471 static HRESULT WINAPI
MSTASK_ITask_GetAccountInformation(
473 LPWSTR
*ppwszAccountName
)
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
);
493 static HRESULT WINAPI
MSTASK_ITask_SetApplicationName(ITask
*iface
, LPCWSTR appname
)
495 TaskImpl
*This
= impl_from_ITask(iface
);
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
);
511 tmp_name
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
513 return E_OUTOFMEMORY
;
514 len
= SearchPathW(NULL
, appname
, NULL
, len
, tmp_name
, NULL
);
516 hr
= IExecAction_put_Path(This
->action
, tmp_name
);
518 hr
= HRESULT_FROM_WIN32(GetLastError());
520 HeapFree(GetProcessHeap(), 0, tmp_name
);
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
);
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
));
547 lstrcpyW(*appname
, path
);
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])
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
);
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
));
589 lstrcpyW(*params
, args
);
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])
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
);
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
));
630 lstrcpyW(*workdir
, dir
);
640 static HRESULT WINAPI
MSTASK_ITask_SetPriority(
644 FIXME("(%p, 0x%08x): stub\n", iface
, dwPriority
);
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
;
658 static HRESULT WINAPI
MSTASK_ITask_SetTaskFlags(
662 FIXME("(%p, 0x%08x): stub\n", iface
, dwFlags
);
666 static HRESULT WINAPI
MSTASK_ITask_GetTaskFlags(ITask
*iface
, DWORD
*flags
)
668 FIXME("(%p, %p): stub\n", iface
, flags
);
673 static HRESULT WINAPI
MSTASK_ITask_SetMaxRunTime(
677 TaskImpl
*This
= impl_from_ITask(iface
);
679 TRACE("(%p, %d)\n", iface
, dwMaxRunTime
);
681 This
->maxRunTime
= dwMaxRunTime
;
685 static HRESULT WINAPI
MSTASK_ITask_GetMaxRunTime(
687 DWORD
*pdwMaxRunTime
)
689 TaskImpl
*This
= impl_from_ITask(iface
);
691 TRACE("(%p, %p)\n", iface
, pdwMaxRunTime
);
693 *pdwMaxRunTime
= This
->maxRunTime
;
697 static HRESULT WINAPI
MSTASK_IPersistFile_QueryInterface(
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(
710 TaskImpl
*This
= impl_from_IPersistFile(iface
);
713 ref
= InterlockedIncrement(&This
->ref
);
717 static ULONG WINAPI
MSTASK_IPersistFile_Release(
720 TaskImpl
*This
= impl_from_IPersistFile(iface
);
723 ref
= InterlockedDecrement(&This
->ref
);
725 TaskDestructor(This
);
729 static HRESULT WINAPI
MSTASK_IPersistFile_GetClassID(IPersistFile
*iface
, CLSID
*clsid
)
731 TRACE("(%p, %p)\n", iface
, clsid
);
733 *clsid
= CLSID_CTask
;
737 static HRESULT WINAPI
MSTASK_IPersistFile_IsDirty(
740 FIXME("(%p): stub\n", iface
);
744 static HRESULT WINAPI
MSTASK_IPersistFile_Load(
746 LPCOLESTR pszFileName
,
749 FIXME("(%p, %p, 0x%08x): stub\n", iface
, pszFileName
, dwMode
);
753 static BOOL
write_signature(HANDLE hfile
)
757 USHORT SignatureVersion
;
758 USHORT ClientVersion
;
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
)
776 } user
= { 8, { 0xff,0x0f,0x1d,0,0,0,0,0 } };
779 return WriteFile(hfile
, &user
, sizeof(user
), &size
, NULL
);
782 static BOOL
write_user_data(HANDLE hfile
, BYTE
*data
, WORD data_size
)
786 if (!WriteFile(hfile
, &data_size
, sizeof(data_size
), &size
, NULL
))
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;
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 */
810 hr
= ITask_CreateTrigger(task
, &idx
, &trigger
);
811 if (hr
!= S_OK
) return hr
;
812 ITaskTrigger_Release(trigger
);
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());
833 ITask_DeleteTrigger(task
, idx
);
838 static BOOL
write_unicode_string(HANDLE hfile
, const WCHAR
*str
)
843 count
= str
? (lstrlenW(str
) + 1) : 0;
844 if (!WriteFile(hfile
, &count
, sizeof(count
), &size
, NULL
))
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 };
858 WORD word
, user_data_size
= 0;
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
;
867 TRACE("(%p, %s, %d)\n", iface
, debugstr_w(task_name
), remember
);
869 disposition
= task_name
? CREATE_NEW
: OPEN_ALWAYS
;
873 task_name
= This
->task_name
;
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
, ¶ms
);
883 ITask_GetWorkingDirectory(task
, &workdir
);
884 ITask_GetWorkItemData(task
, &user_data_size
, &user_data
);
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 */
894 fixed
.trigger_offset
+= (lstrlenW(appname
) + 1) * sizeof(WCHAR
);
895 fixed
.trigger_offset
+= sizeof(USHORT
); /* Parameters */
897 fixed
.trigger_offset
+= (lstrlenW(params
) + 1) * sizeof(WCHAR
);
898 fixed
.trigger_offset
+= sizeof(USHORT
); /* Working Directory */
900 fixed
.trigger_offset
+= (lstrlenW(workdir
) + 1) * sizeof(WCHAR
);
901 fixed
.trigger_offset
+= sizeof(USHORT
); /* Author */
903 fixed
.trigger_offset
+= (lstrlenW(creator
) + 1) * sizeof(WCHAR
);
904 fixed
.trigger_offset
+= sizeof(USHORT
); /* 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
;
917 fixed
.status
= SCHED_S_TASK_HAS_NOT_RUN
;
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());
933 if (!WriteFile(hfile
, &word
, sizeof(word
), &size
, NULL
))
935 hr
= HRESULT_FROM_WIN32(GetLastError());
938 /* Application Name */
939 if (!write_unicode_string(hfile
, appname
))
941 hr
= HRESULT_FROM_WIN32(GetLastError());
945 if (!write_unicode_string(hfile
, params
))
947 hr
= HRESULT_FROM_WIN32(GetLastError());
950 /* Working Directory */
951 if (!write_unicode_string(hfile
, workdir
))
953 hr
= HRESULT_FROM_WIN32(GetLastError());
957 if (!write_unicode_string(hfile
, creator
))
959 hr
= HRESULT_FROM_WIN32(GetLastError());
963 if (!write_unicode_string(hfile
, comment
))
965 hr
= HRESULT_FROM_WIN32(GetLastError());
970 if (!write_user_data(hfile
, user_data
, user_data_size
))
972 hr
= HRESULT_FROM_WIN32(GetLastError());
977 if (!write_reserved_data(hfile
))
979 hr
= HRESULT_FROM_WIN32(GetLastError());
984 if (!write_triggers(hfile
, task
))
986 hr
= HRESULT_FROM_WIN32(GetLastError());
991 if (!write_signature(hfile
))
993 hr
= HRESULT_FROM_WIN32(GetLastError());
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
);
1011 DeleteFileW(task_name
);
1014 HeapFree(GetProcessHeap(), 0, This
->task_name
);
1015 This
->task_name
= heap_strdupW(task_name
);
1020 static HRESULT WINAPI
MSTASK_IPersistFile_SaveCompleted(
1021 IPersistFile
* iface
,
1022 LPCOLESTR pszFileName
)
1024 FIXME("(%p, %p): stub\n", iface
, pszFileName
);
1028 static HRESULT WINAPI
MSTASK_IPersistFile_GetCurFile(
1029 IPersistFile
* iface
,
1030 LPOLESTR
*ppszFileName
)
1032 FIXME("(%p, %p): stub\n", iface
, ppszFileName
);
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
,
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 };
1102 WCHAR task_name
[MAX_PATH
];
1103 ITaskDefinition
*taskdef
;
1104 IActionCollection
*actions
;
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
));
1122 ITaskDefinition_Release(taskdef
);
1123 return E_OUTOFMEMORY
;
1126 This
->ITask_iface
.lpVtbl
= &MSTASK_ITaskVtbl
;
1127 This
->IPersistFile_iface
.lpVtbl
= &MSTASK_IPersistFileVtbl
;
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
);
1143 hr
= IActionCollection_Create(actions
, TASK_ACTION_EXEC
, (IAction
**)&This
->action
);
1144 IActionCollection_Release(actions
);
1147 *task
= &This
->ITask_iface
;
1148 InterlockedIncrement(&dll_ref
);
1153 ITaskDefinition_Release(This
->task
);
1154 ITask_Release(&This
->ITask_iface
);