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
;
66 TASK_TRIGGER
*trigger
;
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
)
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(
97 TaskImpl
* This
= impl_from_ITask(iface
);
99 TRACE("IID: %s\n", debugstr_guid(riid
));
100 if (ppvObject
== NULL
)
103 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
104 IsEqualGUID(riid
, &IID_ITask
))
106 *ppvObject
= &This
->ITask_iface
;
110 else if (IsEqualGUID(riid
, &IID_IPersistFile
))
112 *ppvObject
= &This
->IPersistFile_iface
;
117 WARN("Unknown interface: %s\n", debugstr_guid(riid
));
119 return E_NOINTERFACE
;
122 static ULONG WINAPI
MSTASK_ITask_AddRef(
125 TaskImpl
*This
= impl_from_ITask(iface
);
128 ref
= InterlockedIncrement(&This
->ref
);
132 static ULONG WINAPI
MSTASK_ITask_Release(
135 TaskImpl
* This
= impl_from_ITask(iface
);
138 ref
= InterlockedDecrement(&This
->ref
);
140 TaskDestructor(This
);
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
;
150 TRACE("(%p, %p, %p)\n", iface
, idx
, task_trigger
);
152 hr
= TaskTriggerConstructor((void **)task_trigger
);
153 if (hr
!= S_OK
) return hr
;
156 new_trigger
= heap_realloc(This
->trigger
, sizeof(This
->trigger
[0]) * (This
->trigger_count
+ 1));
158 new_trigger
= heap_alloc(sizeof(This
->trigger
[0]));
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
]);
169 *idx
= This
->trigger_count
++;
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
);
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
;
201 static HRESULT WINAPI
MSTASK_ITask_GetTrigger(
204 ITaskTrigger
**ppTrigger
)
206 FIXME("(%p, %d, %p): stub\n", iface
, iTrigger
, ppTrigger
);
210 static HRESULT WINAPI
MSTASK_ITask_GetTriggerString(
213 LPWSTR
*ppwszTrigger
)
215 FIXME("(%p, %d, %p): stub\n", iface
, iTrigger
, ppwszTrigger
);
219 static HRESULT WINAPI
MSTASK_ITask_GetRunTimes(
221 const LPSYSTEMTIME pstBegin
,
222 const LPSYSTEMTIME pstEnd
,
224 LPSYSTEMTIME
*rgstTaskTimes
)
226 FIXME("(%p, %p, %p, %p, %p): stub\n", iface
, pstBegin
, pstEnd
, pCount
,
231 static HRESULT WINAPI
MSTASK_ITask_GetNextRunTime(
233 SYSTEMTIME
*pstNextRun
)
235 FIXME("(%p, %p): stub\n", iface
, pstNextRun
);
239 static HRESULT WINAPI
MSTASK_ITask_SetIdleWait(
242 WORD wDeadlineMinutes
)
244 FIXME("(%p, %d, %d): stub\n", iface
, wIdleMinutes
, wDeadlineMinutes
);
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
;
259 static HRESULT WINAPI
MSTASK_ITask_Run(
262 FIXME("(%p): stub\n", iface
);
266 static HRESULT WINAPI
MSTASK_ITask_Terminate(
269 FIXME("(%p): stub\n", iface
);
273 static HRESULT WINAPI
MSTASK_ITask_EditWorkItem(
278 FIXME("(%p, %p, %d): stub\n", iface
, hParent
, dwReserved
);
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
;
300 static HRESULT WINAPI
MSTASK_ITask_GetExitCode(ITask
*iface
, DWORD
*exit_code
)
302 FIXME("(%p, %p): stub\n", iface
, exit_code
);
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
;
314 TRACE("(%p, %s)\n", iface
, debugstr_w(comment
));
316 if (!comment
|| !comment
[0])
319 hr
= ITaskDefinition_get_RegistrationInfo(This
->task
, &info
);
322 hr
= IRegistrationInfo_put_Description(info
, (BSTR
)comment
);
323 IRegistrationInfo_Release(info
);
328 static HRESULT WINAPI
MSTASK_ITask_GetComment(ITask
*iface
, LPWSTR
*comment
)
330 TaskImpl
*This
= impl_from_ITask(iface
);
331 IRegistrationInfo
*info
;
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
);
344 len
= description
? lstrlenW(description
) + 1 : 1;
345 *comment
= CoTaskMemAlloc(len
* sizeof(WCHAR
));
351 lstrcpyW(*comment
, description
);
357 SysFreeString(description
);
360 IRegistrationInfo_Release(info
);
364 static HRESULT WINAPI
MSTASK_ITask_SetCreator(ITask
*iface
, LPCWSTR creator
)
366 TaskImpl
*This
= impl_from_ITask(iface
);
367 IRegistrationInfo
*info
;
370 TRACE("(%p, %s)\n", iface
, debugstr_w(creator
));
372 if (!creator
|| !creator
[0])
375 hr
= ITaskDefinition_get_RegistrationInfo(This
->task
, &info
);
378 hr
= IRegistrationInfo_put_Author(info
, (BSTR
)creator
);
379 IRegistrationInfo_Release(info
);
384 static HRESULT WINAPI
MSTASK_ITask_GetCreator(ITask
*iface
, LPWSTR
*creator
)
386 TaskImpl
*This
= impl_from_ITask(iface
);
387 IRegistrationInfo
*info
;
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
);
400 len
= author
? lstrlenW(author
) + 1 : 1;
401 *creator
= CoTaskMemAlloc(len
* sizeof(WCHAR
));
407 lstrcpyW(*creator
, author
);
413 SysFreeString(author
);
416 IRegistrationInfo_Release(info
);
420 static HRESULT WINAPI
MSTASK_ITask_SetWorkItemData(
425 FIXME("(%p, %d, %p): stub\n", iface
, cBytes
, rgbData
);
429 static HRESULT WINAPI
MSTASK_ITask_GetWorkItemData(
434 FIXME("(%p, %p, %p): stub\n", iface
, pcBytes
, ppBytes
);
438 static HRESULT WINAPI
MSTASK_ITask_SetErrorRetryCount(
442 FIXME("(%p, %d): stub\n", iface
, wRetryCount
);
446 static HRESULT WINAPI
MSTASK_ITask_GetErrorRetryCount(ITask
*iface
, WORD
*count
)
448 TRACE("(%p, %p)\n", iface
, count
);
452 static HRESULT WINAPI
MSTASK_ITask_SetErrorRetryInterval(
456 FIXME("(%p, %d): stub\n", iface
, wRetryInterval
);
460 static HRESULT WINAPI
MSTASK_ITask_GetErrorRetryInterval(ITask
*iface
, WORD
*interval
)
462 TRACE("(%p, %p)\n", iface
, interval
);
466 static HRESULT WINAPI
MSTASK_ITask_SetFlags(
470 FIXME("(%p, 0x%08x): stub\n", iface
, dwFlags
);
474 static HRESULT WINAPI
MSTASK_ITask_GetFlags(ITask
*iface
, DWORD
*flags
)
476 FIXME("(%p, %p): stub\n", iface
, flags
);
481 static HRESULT WINAPI
MSTASK_ITask_SetAccountInformation(
483 LPCWSTR pwszAccountName
,
484 LPCWSTR pwszPassword
)
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
));
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
;
506 static HRESULT WINAPI
MSTASK_ITask_GetAccountInformation(
508 LPWSTR
*ppwszAccountName
)
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
);
528 static HRESULT WINAPI
MSTASK_ITask_SetApplicationName(ITask
*iface
, LPCWSTR appname
)
530 TaskImpl
*This
= impl_from_ITask(iface
);
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
);
546 tmp_name
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
548 return E_OUTOFMEMORY
;
549 len
= SearchPathW(NULL
, appname
, NULL
, len
, tmp_name
, NULL
);
551 hr
= IExecAction_put_Path(This
->action
, tmp_name
);
553 hr
= HRESULT_FROM_WIN32(GetLastError());
555 HeapFree(GetProcessHeap(), 0, tmp_name
);
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
);
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
));
582 lstrcpyW(*appname
, path
);
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])
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
);
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
));
624 lstrcpyW(*params
, args
);
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])
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
);
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
));
665 lstrcpyW(*workdir
, dir
);
675 static HRESULT WINAPI
MSTASK_ITask_SetPriority(
679 FIXME("(%p, 0x%08x): stub\n", iface
, dwPriority
);
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
;
693 static HRESULT WINAPI
MSTASK_ITask_SetTaskFlags(
697 FIXME("(%p, 0x%08x): stub\n", iface
, dwFlags
);
701 static HRESULT WINAPI
MSTASK_ITask_GetTaskFlags(ITask
*iface
, DWORD
*flags
)
703 FIXME("(%p, %p): stub\n", iface
, flags
);
708 static HRESULT WINAPI
MSTASK_ITask_SetMaxRunTime(
712 TaskImpl
*This
= impl_from_ITask(iface
);
714 TRACE("(%p, %d)\n", iface
, dwMaxRunTime
);
716 This
->maxRunTime
= dwMaxRunTime
;
720 static HRESULT WINAPI
MSTASK_ITask_GetMaxRunTime(
722 DWORD
*pdwMaxRunTime
)
724 TaskImpl
*This
= impl_from_ITask(iface
);
726 TRACE("(%p, %p)\n", iface
, pdwMaxRunTime
);
728 *pdwMaxRunTime
= This
->maxRunTime
;
732 static HRESULT WINAPI
MSTASK_IPersistFile_QueryInterface(
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(
745 TaskImpl
*This
= impl_from_IPersistFile(iface
);
748 ref
= InterlockedIncrement(&This
->ref
);
752 static ULONG WINAPI
MSTASK_IPersistFile_Release(
755 TaskImpl
*This
= impl_from_IPersistFile(iface
);
758 ref
= InterlockedDecrement(&This
->ref
);
760 TaskDestructor(This
);
764 static HRESULT WINAPI
MSTASK_IPersistFile_GetClassID(IPersistFile
*iface
, CLSID
*clsid
)
766 TRACE("(%p, %p)\n", iface
, clsid
);
768 *clsid
= CLSID_CTask
;
772 static HRESULT WINAPI
MSTASK_IPersistFile_IsDirty(
775 FIXME("(%p): stub\n", iface
);
779 static HRESULT WINAPI
MSTASK_IPersistFile_Load(
781 LPCOLESTR pszFileName
,
784 FIXME("(%p, %p, 0x%08x): stub\n", iface
, pszFileName
, dwMode
);
788 static BOOL
write_signature(HANDLE hfile
)
792 USHORT SignatureVersion
;
793 USHORT ClientVersion
;
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
)
811 } user
= { 8, { 0xff,0x0f,0x1d,0,0,0,0,0 } };
814 return WriteFile(hfile
, &user
, sizeof(user
), &size
, NULL
);
817 static BOOL
write_user_data(HANDLE hfile
, BYTE
*data
, WORD data_size
)
821 if (!WriteFile(hfile
, &data_size
, sizeof(data_size
), &size
, NULL
))
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;
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 */
845 hr
= ITask_CreateTrigger(task
, &idx
, &trigger
);
846 if (hr
!= S_OK
) return hr
;
847 ITaskTrigger_Release(trigger
);
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());
868 ITask_DeleteTrigger(task
, idx
);
873 static BOOL
write_unicode_string(HANDLE hfile
, const WCHAR
*str
)
878 count
= str
? (lstrlenW(str
) + 1) : 0;
879 if (!WriteFile(hfile
, &count
, sizeof(count
), &size
, NULL
))
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 };
893 WORD word
, user_data_size
= 0;
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
;
902 TRACE("(%p, %s, %d)\n", iface
, debugstr_w(task_name
), remember
);
904 disposition
= task_name
? CREATE_NEW
: OPEN_ALWAYS
;
908 task_name
= This
->task_name
;
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
, ¶ms
);
918 ITask_GetWorkingDirectory(task
, &workdir
);
919 ITask_GetWorkItemData(task
, &user_data_size
, &user_data
);
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 */
929 fixed
.trigger_offset
+= (lstrlenW(appname
) + 1) * sizeof(WCHAR
);
930 fixed
.trigger_offset
+= sizeof(USHORT
); /* Parameters */
932 fixed
.trigger_offset
+= (lstrlenW(params
) + 1) * sizeof(WCHAR
);
933 fixed
.trigger_offset
+= sizeof(USHORT
); /* Working Directory */
935 fixed
.trigger_offset
+= (lstrlenW(workdir
) + 1) * sizeof(WCHAR
);
936 fixed
.trigger_offset
+= sizeof(USHORT
); /* Author */
938 fixed
.trigger_offset
+= (lstrlenW(creator
) + 1) * sizeof(WCHAR
);
939 fixed
.trigger_offset
+= sizeof(USHORT
); /* 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
;
952 fixed
.status
= SCHED_S_TASK_HAS_NOT_RUN
;
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());
968 if (!WriteFile(hfile
, &word
, sizeof(word
), &size
, NULL
))
970 hr
= HRESULT_FROM_WIN32(GetLastError());
973 /* Application Name */
974 if (!write_unicode_string(hfile
, appname
))
976 hr
= HRESULT_FROM_WIN32(GetLastError());
980 if (!write_unicode_string(hfile
, params
))
982 hr
= HRESULT_FROM_WIN32(GetLastError());
985 /* Working Directory */
986 if (!write_unicode_string(hfile
, workdir
))
988 hr
= HRESULT_FROM_WIN32(GetLastError());
992 if (!write_unicode_string(hfile
, creator
))
994 hr
= HRESULT_FROM_WIN32(GetLastError());
998 if (!write_unicode_string(hfile
, comment
))
1000 hr
= HRESULT_FROM_WIN32(GetLastError());
1005 if (!write_user_data(hfile
, user_data
, user_data_size
))
1007 hr
= HRESULT_FROM_WIN32(GetLastError());
1012 if (!write_reserved_data(hfile
))
1014 hr
= HRESULT_FROM_WIN32(GetLastError());
1019 hr
= write_triggers(task
, hfile
);
1024 if (!write_signature(hfile
))
1026 hr
= HRESULT_FROM_WIN32(GetLastError());
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
);
1044 DeleteFileW(task_name
);
1047 HeapFree(GetProcessHeap(), 0, This
->task_name
);
1048 This
->task_name
= heap_strdupW(task_name
);
1053 static HRESULT WINAPI
MSTASK_IPersistFile_SaveCompleted(
1054 IPersistFile
* iface
,
1055 LPCOLESTR pszFileName
)
1057 FIXME("(%p, %p): stub\n", iface
, pszFileName
);
1061 static HRESULT WINAPI
MSTASK_IPersistFile_GetCurFile(
1062 IPersistFile
* iface
,
1063 LPOLESTR
*ppszFileName
)
1065 FIXME("(%p, %p): stub\n", iface
, ppszFileName
);
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
,
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 };
1135 WCHAR task_name
[MAX_PATH
];
1136 ITaskDefinition
*taskdef
;
1137 IActionCollection
*actions
;
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
));
1155 ITaskDefinition_Release(taskdef
);
1156 return E_OUTOFMEMORY
;
1159 This
->ITask_iface
.lpVtbl
= &MSTASK_ITaskVtbl
;
1160 This
->IPersistFile_iface
.lpVtbl
= &MSTASK_IPersistFileVtbl
;
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
);
1178 hr
= IActionCollection_Create(actions
, TASK_ACTION_EXEC
, (IAction
**)&This
->action
);
1179 IActionCollection_Release(actions
);
1182 *task
= &This
->ITask_iface
;
1183 InterlockedIncrement(&dll_ref
);
1188 ITaskDefinition_Release(This
->task
);
1189 ITask_Release(&This
->ITask_iface
);