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
);
37 IPersistFile IPersistFile_iface
;
39 ITaskDefinition
*task
;
43 WORD idle_minutes
, deadline_minutes
;
44 DWORD priority
, maxRunTime
;
48 static inline TaskImpl
*impl_from_ITask(ITask
*iface
)
50 return CONTAINING_RECORD(iface
, TaskImpl
, ITask_iface
);
53 static inline TaskImpl
*impl_from_IPersistFile( IPersistFile
*iface
)
55 return CONTAINING_RECORD(iface
, TaskImpl
, IPersistFile_iface
);
58 static void TaskDestructor(TaskImpl
*This
)
62 IExecAction_Release(This
->action
);
63 ITaskDefinition_Release(This
->task
);
64 HeapFree(GetProcessHeap(), 0, This
->task_name
);
65 HeapFree(GetProcessHeap(), 0, This
->accountName
);
66 HeapFree(GetProcessHeap(), 0, This
);
67 InterlockedDecrement(&dll_ref
);
70 static HRESULT WINAPI
MSTASK_ITask_QueryInterface(
75 TaskImpl
* This
= impl_from_ITask(iface
);
77 TRACE("IID: %s\n", debugstr_guid(riid
));
78 if (ppvObject
== NULL
)
81 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
82 IsEqualGUID(riid
, &IID_ITask
))
84 *ppvObject
= &This
->ITask_iface
;
88 else if (IsEqualGUID(riid
, &IID_IPersistFile
))
90 *ppvObject
= &This
->IPersistFile_iface
;
95 WARN("Unknown interface: %s\n", debugstr_guid(riid
));
100 static ULONG WINAPI
MSTASK_ITask_AddRef(
103 TaskImpl
*This
= impl_from_ITask(iface
);
106 ref
= InterlockedIncrement(&This
->ref
);
110 static ULONG WINAPI
MSTASK_ITask_Release(
113 TaskImpl
* This
= impl_from_ITask(iface
);
116 ref
= InterlockedDecrement(&This
->ref
);
118 TaskDestructor(This
);
122 static HRESULT WINAPI
MSTASK_ITask_CreateTrigger(
125 ITaskTrigger
**ppTrigger
)
127 TRACE("(%p, %p, %p)\n", iface
, piNewTrigger
, ppTrigger
);
128 return TaskTriggerConstructor((LPVOID
*)ppTrigger
);
131 static HRESULT WINAPI
MSTASK_ITask_DeleteTrigger(
135 FIXME("(%p, %d): stub\n", iface
, iTrigger
);
139 static HRESULT WINAPI
MSTASK_ITask_GetTriggerCount(
143 FIXME("(%p, %p): stub\n", iface
, plCount
);
147 static HRESULT WINAPI
MSTASK_ITask_GetTrigger(
150 ITaskTrigger
**ppTrigger
)
152 FIXME("(%p, %d, %p): stub\n", iface
, iTrigger
, ppTrigger
);
156 static HRESULT WINAPI
MSTASK_ITask_GetTriggerString(
159 LPWSTR
*ppwszTrigger
)
161 FIXME("(%p, %d, %p): stub\n", iface
, iTrigger
, ppwszTrigger
);
165 static HRESULT WINAPI
MSTASK_ITask_GetRunTimes(
167 const LPSYSTEMTIME pstBegin
,
168 const LPSYSTEMTIME pstEnd
,
170 LPSYSTEMTIME
*rgstTaskTimes
)
172 FIXME("(%p, %p, %p, %p, %p): stub\n", iface
, pstBegin
, pstEnd
, pCount
,
177 static HRESULT WINAPI
MSTASK_ITask_GetNextRunTime(
179 SYSTEMTIME
*pstNextRun
)
181 FIXME("(%p, %p): stub\n", iface
, pstNextRun
);
185 static HRESULT WINAPI
MSTASK_ITask_SetIdleWait(
188 WORD wDeadlineMinutes
)
190 FIXME("(%p, %d, %d): stub\n", iface
, wIdleMinutes
, wDeadlineMinutes
);
194 static HRESULT WINAPI
MSTASK_ITask_GetIdleWait(ITask
*iface
, WORD
*idle_minutes
, WORD
*deadline_minutes
)
196 TaskImpl
*This
= impl_from_ITask(iface
);
198 TRACE("(%p, %p, %p): stub\n", iface
, idle_minutes
, deadline_minutes
);
200 *idle_minutes
= This
->idle_minutes
;
201 *deadline_minutes
= This
->deadline_minutes
;
205 static HRESULT WINAPI
MSTASK_ITask_Run(
208 FIXME("(%p): stub\n", iface
);
212 static HRESULT WINAPI
MSTASK_ITask_Terminate(
215 FIXME("(%p): stub\n", iface
);
219 static HRESULT WINAPI
MSTASK_ITask_EditWorkItem(
224 FIXME("(%p, %p, %d): stub\n", iface
, hParent
, dwReserved
);
228 static HRESULT WINAPI
MSTASK_ITask_GetMostRecentRunTime(
230 SYSTEMTIME
*pstLastRun
)
232 FIXME("(%p, %p): stub\n", iface
, pstLastRun
);
236 static HRESULT WINAPI
MSTASK_ITask_GetStatus(ITask
*iface
, HRESULT
*status
)
238 TaskImpl
*This
= impl_from_ITask(iface
);
240 TRACE("(%p, %p)\n", iface
, status
);
242 *status
= This
->status
;
246 static HRESULT WINAPI
MSTASK_ITask_GetExitCode(ITask
*iface
, DWORD
*exit_code
)
248 FIXME("(%p, %p): stub\n", iface
, exit_code
);
251 return SCHED_S_TASK_HAS_NOT_RUN
;
254 static HRESULT WINAPI
MSTASK_ITask_SetComment(ITask
*iface
, LPCWSTR comment
)
256 TaskImpl
*This
= impl_from_ITask(iface
);
257 IRegistrationInfo
*info
;
260 TRACE("(%p, %s)\n", iface
, debugstr_w(comment
));
262 if (!comment
|| !comment
[0])
265 hr
= ITaskDefinition_get_RegistrationInfo(This
->task
, &info
);
268 hr
= IRegistrationInfo_put_Description(info
, (BSTR
)comment
);
269 IRegistrationInfo_Release(info
);
274 static HRESULT WINAPI
MSTASK_ITask_GetComment(ITask
*iface
, LPWSTR
*comment
)
276 TaskImpl
*This
= impl_from_ITask(iface
);
277 IRegistrationInfo
*info
;
282 TRACE("(%p, %p)\n", iface
, comment
);
284 hr
= ITaskDefinition_get_RegistrationInfo(This
->task
, &info
);
285 if (hr
!= S_OK
) return hr
;
287 hr
= IRegistrationInfo_get_Description(info
, &description
);
290 len
= description
? lstrlenW(description
) + 1 : 1;
291 *comment
= CoTaskMemAlloc(len
* sizeof(WCHAR
));
297 lstrcpyW(*comment
, description
);
303 SysFreeString(description
);
306 IRegistrationInfo_Release(info
);
310 static HRESULT WINAPI
MSTASK_ITask_SetCreator(ITask
*iface
, LPCWSTR creator
)
312 TaskImpl
*This
= impl_from_ITask(iface
);
313 IRegistrationInfo
*info
;
316 TRACE("(%p, %s)\n", iface
, debugstr_w(creator
));
318 if (!creator
|| !creator
[0])
321 hr
= ITaskDefinition_get_RegistrationInfo(This
->task
, &info
);
324 hr
= IRegistrationInfo_put_Author(info
, (BSTR
)creator
);
325 IRegistrationInfo_Release(info
);
330 static HRESULT WINAPI
MSTASK_ITask_GetCreator(ITask
*iface
, LPWSTR
*creator
)
332 TaskImpl
*This
= impl_from_ITask(iface
);
333 IRegistrationInfo
*info
;
338 TRACE("(%p, %p)\n", iface
, creator
);
340 hr
= ITaskDefinition_get_RegistrationInfo(This
->task
, &info
);
341 if (hr
!= S_OK
) return hr
;
343 hr
= IRegistrationInfo_get_Author(info
, &author
);
346 len
= author
? lstrlenW(author
) + 1 : 1;
347 *creator
= CoTaskMemAlloc(len
* sizeof(WCHAR
));
353 lstrcpyW(*creator
, author
);
359 SysFreeString(author
);
362 IRegistrationInfo_Release(info
);
366 static HRESULT WINAPI
MSTASK_ITask_SetWorkItemData(
371 FIXME("(%p, %d, %p): stub\n", iface
, cBytes
, rgbData
);
375 static HRESULT WINAPI
MSTASK_ITask_GetWorkItemData(
380 FIXME("(%p, %p, %p): stub\n", iface
, pcBytes
, ppBytes
);
384 static HRESULT WINAPI
MSTASK_ITask_SetErrorRetryCount(
388 FIXME("(%p, %d): stub\n", iface
, wRetryCount
);
392 static HRESULT WINAPI
MSTASK_ITask_GetErrorRetryCount(ITask
*iface
, WORD
*count
)
394 TRACE("(%p, %p)\n", iface
, count
);
398 static HRESULT WINAPI
MSTASK_ITask_SetErrorRetryInterval(
402 FIXME("(%p, %d): stub\n", iface
, wRetryInterval
);
406 static HRESULT WINAPI
MSTASK_ITask_GetErrorRetryInterval(ITask
*iface
, WORD
*interval
)
408 TRACE("(%p, %p)\n", iface
, interval
);
412 static HRESULT WINAPI
MSTASK_ITask_SetFlags(
416 FIXME("(%p, 0x%08x): stub\n", iface
, dwFlags
);
420 static HRESULT WINAPI
MSTASK_ITask_GetFlags(ITask
*iface
, DWORD
*flags
)
422 FIXME("(%p, %p): stub\n", iface
, flags
);
427 static HRESULT WINAPI
MSTASK_ITask_SetAccountInformation(
429 LPCWSTR pwszAccountName
,
430 LPCWSTR pwszPassword
)
433 TaskImpl
*This
= impl_from_ITask(iface
);
434 LPWSTR tmp_account_name
;
436 TRACE("(%p, %s, %s): partial stub\n", iface
, debugstr_w(pwszAccountName
),
437 debugstr_w(pwszPassword
));
440 FIXME("Partial stub ignores passwords\n");
442 n
= (lstrlenW(pwszAccountName
) + 1);
443 tmp_account_name
= HeapAlloc(GetProcessHeap(), 0, n
* sizeof(WCHAR
));
444 if (!tmp_account_name
)
445 return E_OUTOFMEMORY
;
446 lstrcpyW(tmp_account_name
, pwszAccountName
);
447 HeapFree(GetProcessHeap(), 0, This
->accountName
);
448 This
->accountName
= tmp_account_name
;
452 static HRESULT WINAPI
MSTASK_ITask_GetAccountInformation(
454 LPWSTR
*ppwszAccountName
)
457 TaskImpl
*This
= impl_from_ITask(iface
);
459 TRACE("(%p, %p): partial stub\n", iface
, ppwszAccountName
);
461 /* This implements the WinXP behavior when accountName has not yet
462 * set. Win2K behaves differently, returning SCHED_E_CANNOT_OPEN_TASK */
463 if (!This
->accountName
)
464 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
);
466 n
= (lstrlenW(This
->accountName
) + 1);
467 *ppwszAccountName
= CoTaskMemAlloc(n
* sizeof(WCHAR
));
468 if (!*ppwszAccountName
)
469 return E_OUTOFMEMORY
;
470 lstrcpyW(*ppwszAccountName
, This
->accountName
);
474 static HRESULT WINAPI
MSTASK_ITask_SetApplicationName(ITask
*iface
, LPCWSTR appname
)
476 TaskImpl
*This
= impl_from_ITask(iface
);
479 TRACE("(%p, %s)\n", iface
, debugstr_w(appname
));
481 /* Empty application name */
482 if (!appname
|| !appname
[0])
483 return IExecAction_put_Path(This
->action
, NULL
);
485 /* Attempt to set pwszApplicationName to a path resolved application name */
486 len
= SearchPathW(NULL
, appname
, NULL
, 0, NULL
, NULL
);
492 tmp_name
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
494 return E_OUTOFMEMORY
;
495 len
= SearchPathW(NULL
, appname
, NULL
, len
, tmp_name
, NULL
);
497 hr
= IExecAction_put_Path(This
->action
, tmp_name
);
499 hr
= HRESULT_FROM_WIN32(GetLastError());
501 HeapFree(GetProcessHeap(), 0, tmp_name
);
505 /* If unable to path resolve name, simply set to appname */
506 return IExecAction_put_Path(This
->action
, (BSTR
)appname
);
509 static HRESULT WINAPI
MSTASK_ITask_GetApplicationName(ITask
*iface
, LPWSTR
*appname
)
511 TaskImpl
*This
= impl_from_ITask(iface
);
516 TRACE("(%p, %p)\n", iface
, appname
);
518 hr
= IExecAction_get_Path(This
->action
, &path
);
519 if (hr
!= S_OK
) return hr
;
521 len
= path
? lstrlenW(path
) + 1 : 1;
522 *appname
= CoTaskMemAlloc(len
* sizeof(WCHAR
));
528 lstrcpyW(*appname
, path
);
538 static HRESULT WINAPI
MSTASK_ITask_SetParameters(ITask
*iface
, LPCWSTR params
)
540 TaskImpl
*This
= impl_from_ITask(iface
);
542 TRACE("(%p, %s)\n", iface
, debugstr_w(params
));
544 /* Empty parameter list */
545 if (!params
|| !params
[0])
548 return IExecAction_put_Arguments(This
->action
, (BSTR
)params
);
551 static HRESULT WINAPI
MSTASK_ITask_GetParameters(ITask
*iface
, LPWSTR
*params
)
553 TaskImpl
*This
= impl_from_ITask(iface
);
558 TRACE("(%p, %p)\n", iface
, params
);
560 hr
= IExecAction_get_Arguments(This
->action
, &args
);
561 if (hr
!= S_OK
) return hr
;
563 len
= args
? lstrlenW(args
) + 1 : 1;
564 *params
= CoTaskMemAlloc(len
* sizeof(WCHAR
));
570 lstrcpyW(*params
, args
);
580 static HRESULT WINAPI
MSTASK_ITask_SetWorkingDirectory(ITask
* iface
, LPCWSTR workdir
)
582 TaskImpl
*This
= impl_from_ITask(iface
);
584 TRACE("(%p, %s)\n", iface
, debugstr_w(workdir
));
586 if (!workdir
|| !workdir
[0])
589 return IExecAction_put_WorkingDirectory(This
->action
, (BSTR
)workdir
);
592 static HRESULT WINAPI
MSTASK_ITask_GetWorkingDirectory(ITask
*iface
, LPWSTR
*workdir
)
594 TaskImpl
*This
= impl_from_ITask(iface
);
599 TRACE("(%p, %p)\n", iface
, workdir
);
601 hr
= IExecAction_get_WorkingDirectory(This
->action
, &dir
);
602 if (hr
!= S_OK
) return hr
;
604 len
= dir
? lstrlenW(dir
) + 1 : 1;
605 *workdir
= CoTaskMemAlloc(len
* sizeof(WCHAR
));
611 lstrcpyW(*workdir
, dir
);
621 static HRESULT WINAPI
MSTASK_ITask_SetPriority(
625 FIXME("(%p, 0x%08x): stub\n", iface
, dwPriority
);
629 static HRESULT WINAPI
MSTASK_ITask_GetPriority(ITask
*iface
, DWORD
*priority
)
631 TaskImpl
*This
= impl_from_ITask(iface
);
633 TRACE("(%p, %p)\n", iface
, priority
);
635 *priority
= This
->priority
;
639 static HRESULT WINAPI
MSTASK_ITask_SetTaskFlags(
643 FIXME("(%p, 0x%08x): stub\n", iface
, dwFlags
);
647 static HRESULT WINAPI
MSTASK_ITask_GetTaskFlags(ITask
*iface
, DWORD
*flags
)
649 FIXME("(%p, %p): stub\n", iface
, flags
);
654 static HRESULT WINAPI
MSTASK_ITask_SetMaxRunTime(
658 TaskImpl
*This
= impl_from_ITask(iface
);
660 TRACE("(%p, %d)\n", iface
, dwMaxRunTime
);
662 This
->maxRunTime
= dwMaxRunTime
;
666 static HRESULT WINAPI
MSTASK_ITask_GetMaxRunTime(
668 DWORD
*pdwMaxRunTime
)
670 TaskImpl
*This
= impl_from_ITask(iface
);
672 TRACE("(%p, %p)\n", iface
, pdwMaxRunTime
);
674 *pdwMaxRunTime
= This
->maxRunTime
;
678 static HRESULT WINAPI
MSTASK_IPersistFile_QueryInterface(
683 TaskImpl
*This
= impl_from_IPersistFile(iface
);
684 TRACE("(%p, %s, %p)\n", iface
, debugstr_guid(riid
), ppvObject
);
685 return ITask_QueryInterface(&This
->ITask_iface
, riid
, ppvObject
);
688 static ULONG WINAPI
MSTASK_IPersistFile_AddRef(
691 TaskImpl
*This
= impl_from_IPersistFile(iface
);
694 ref
= InterlockedIncrement(&This
->ref
);
698 static ULONG WINAPI
MSTASK_IPersistFile_Release(
701 TaskImpl
*This
= impl_from_IPersistFile(iface
);
704 ref
= InterlockedDecrement(&This
->ref
);
706 TaskDestructor(This
);
710 static HRESULT WINAPI
MSTASK_IPersistFile_GetClassID(IPersistFile
*iface
, CLSID
*clsid
)
712 TRACE("(%p, %p)\n", iface
, clsid
);
714 *clsid
= CLSID_CTask
;
718 static HRESULT WINAPI
MSTASK_IPersistFile_IsDirty(
721 FIXME("(%p): stub\n", iface
);
725 static HRESULT WINAPI
MSTASK_IPersistFile_Load(
727 LPCOLESTR pszFileName
,
730 FIXME("(%p, %p, 0x%08x): stub\n", iface
, pszFileName
, dwMode
);
734 static HRESULT WINAPI
MSTASK_IPersistFile_Save(
736 LPCOLESTR pszFileName
,
739 FIXME("(%p, %p, %d): stub\n", iface
, pszFileName
, fRemember
);
740 WARN("Returning S_OK but not writing to disk: %s %d\n",
741 debugstr_w(pszFileName
), fRemember
);
745 static HRESULT WINAPI
MSTASK_IPersistFile_SaveCompleted(
747 LPCOLESTR pszFileName
)
749 FIXME("(%p, %p): stub\n", iface
, pszFileName
);
753 static HRESULT WINAPI
MSTASK_IPersistFile_GetCurFile(
755 LPOLESTR
*ppszFileName
)
757 FIXME("(%p, %p): stub\n", iface
, ppszFileName
);
762 static const ITaskVtbl MSTASK_ITaskVtbl
=
764 MSTASK_ITask_QueryInterface
,
766 MSTASK_ITask_Release
,
767 MSTASK_ITask_CreateTrigger
,
768 MSTASK_ITask_DeleteTrigger
,
769 MSTASK_ITask_GetTriggerCount
,
770 MSTASK_ITask_GetTrigger
,
771 MSTASK_ITask_GetTriggerString
,
772 MSTASK_ITask_GetRunTimes
,
773 MSTASK_ITask_GetNextRunTime
,
774 MSTASK_ITask_SetIdleWait
,
775 MSTASK_ITask_GetIdleWait
,
777 MSTASK_ITask_Terminate
,
778 MSTASK_ITask_EditWorkItem
,
779 MSTASK_ITask_GetMostRecentRunTime
,
780 MSTASK_ITask_GetStatus
,
781 MSTASK_ITask_GetExitCode
,
782 MSTASK_ITask_SetComment
,
783 MSTASK_ITask_GetComment
,
784 MSTASK_ITask_SetCreator
,
785 MSTASK_ITask_GetCreator
,
786 MSTASK_ITask_SetWorkItemData
,
787 MSTASK_ITask_GetWorkItemData
,
788 MSTASK_ITask_SetErrorRetryCount
,
789 MSTASK_ITask_GetErrorRetryCount
,
790 MSTASK_ITask_SetErrorRetryInterval
,
791 MSTASK_ITask_GetErrorRetryInterval
,
792 MSTASK_ITask_SetFlags
,
793 MSTASK_ITask_GetFlags
,
794 MSTASK_ITask_SetAccountInformation
,
795 MSTASK_ITask_GetAccountInformation
,
796 MSTASK_ITask_SetApplicationName
,
797 MSTASK_ITask_GetApplicationName
,
798 MSTASK_ITask_SetParameters
,
799 MSTASK_ITask_GetParameters
,
800 MSTASK_ITask_SetWorkingDirectory
,
801 MSTASK_ITask_GetWorkingDirectory
,
802 MSTASK_ITask_SetPriority
,
803 MSTASK_ITask_GetPriority
,
804 MSTASK_ITask_SetTaskFlags
,
805 MSTASK_ITask_GetTaskFlags
,
806 MSTASK_ITask_SetMaxRunTime
,
807 MSTASK_ITask_GetMaxRunTime
810 static const IPersistFileVtbl MSTASK_IPersistFileVtbl
=
812 MSTASK_IPersistFile_QueryInterface
,
813 MSTASK_IPersistFile_AddRef
,
814 MSTASK_IPersistFile_Release
,
815 MSTASK_IPersistFile_GetClassID
,
816 MSTASK_IPersistFile_IsDirty
,
817 MSTASK_IPersistFile_Load
,
818 MSTASK_IPersistFile_Save
,
819 MSTASK_IPersistFile_SaveCompleted
,
820 MSTASK_IPersistFile_GetCurFile
823 HRESULT
TaskConstructor(ITaskService
*service
, const WCHAR
*task_name
, ITask
**task
)
826 ITaskDefinition
*taskdef
;
827 IActionCollection
*actions
;
830 TRACE("(%s, %p)\n", debugstr_w(task_name
), task
);
832 hr
= ITaskService_NewTask(service
, 0, &taskdef
);
833 if (hr
!= S_OK
) return hr
;
835 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(*This
));
838 ITaskDefinition_Release(taskdef
);
839 return E_OUTOFMEMORY
;
842 This
->ITask_iface
.lpVtbl
= &MSTASK_ITaskVtbl
;
843 This
->IPersistFile_iface
.lpVtbl
= &MSTASK_IPersistFileVtbl
;
845 This
->task
= taskdef
;
846 This
->task_name
= heap_strdupW(task_name
);
847 This
->status
= SCHED_S_TASK_NOT_SCHEDULED
;
848 This
->idle_minutes
= 10;
849 This
->deadline_minutes
= 60;
850 This
->priority
= NORMAL_PRIORITY_CLASS
;
851 This
->accountName
= NULL
;
853 /* Default time is 3 days = 259200000 ms */
854 This
->maxRunTime
= 259200000;
856 hr
= ITaskDefinition_get_Actions(This
->task
, &actions
);
859 hr
= IActionCollection_Create(actions
, TASK_ACTION_EXEC
, (IAction
**)&This
->action
);
860 IActionCollection_Release(actions
);
863 *task
= &This
->ITask_iface
;
864 InterlockedIncrement(&dll_ref
);
869 ITaskDefinition_Release(This
->task
);
870 ITask_Release(&This
->ITask_iface
);