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
;
47 static inline TaskImpl
*impl_from_ITask(ITask
*iface
)
49 return CONTAINING_RECORD(iface
, TaskImpl
, ITask_iface
);
52 static inline TaskImpl
*impl_from_IPersistFile( IPersistFile
*iface
)
54 return CONTAINING_RECORD(iface
, TaskImpl
, IPersistFile_iface
);
57 static void TaskDestructor(TaskImpl
*This
)
61 IExecAction_Release(This
->action
);
62 ITaskDefinition_Release(This
->task
);
63 HeapFree(GetProcessHeap(), 0, This
->task_name
);
64 HeapFree(GetProcessHeap(), 0, This
->accountName
);
65 HeapFree(GetProcessHeap(), 0, This
);
66 InterlockedDecrement(&dll_ref
);
69 static HRESULT WINAPI
MSTASK_ITask_QueryInterface(
74 TaskImpl
* This
= impl_from_ITask(iface
);
76 TRACE("IID: %s\n", debugstr_guid(riid
));
77 if (ppvObject
== NULL
)
80 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
81 IsEqualGUID(riid
, &IID_ITask
))
83 *ppvObject
= &This
->ITask_iface
;
87 else if (IsEqualGUID(riid
, &IID_IPersistFile
))
89 *ppvObject
= &This
->IPersistFile_iface
;
94 WARN("Unknown interface: %s\n", debugstr_guid(riid
));
99 static ULONG WINAPI
MSTASK_ITask_AddRef(
102 TaskImpl
*This
= impl_from_ITask(iface
);
105 ref
= InterlockedIncrement(&This
->ref
);
109 static ULONG WINAPI
MSTASK_ITask_Release(
112 TaskImpl
* This
= impl_from_ITask(iface
);
115 ref
= InterlockedDecrement(&This
->ref
);
117 TaskDestructor(This
);
121 static HRESULT WINAPI
MSTASK_ITask_CreateTrigger(
124 ITaskTrigger
**ppTrigger
)
126 TRACE("(%p, %p, %p)\n", iface
, piNewTrigger
, ppTrigger
);
127 return TaskTriggerConstructor((LPVOID
*)ppTrigger
);
130 static HRESULT WINAPI
MSTASK_ITask_DeleteTrigger(
134 FIXME("(%p, %d): stub\n", iface
, iTrigger
);
138 static HRESULT WINAPI
MSTASK_ITask_GetTriggerCount(
142 FIXME("(%p, %p): stub\n", iface
, plCount
);
146 static HRESULT WINAPI
MSTASK_ITask_GetTrigger(
149 ITaskTrigger
**ppTrigger
)
151 FIXME("(%p, %d, %p): stub\n", iface
, iTrigger
, ppTrigger
);
155 static HRESULT WINAPI
MSTASK_ITask_GetTriggerString(
158 LPWSTR
*ppwszTrigger
)
160 FIXME("(%p, %d, %p): stub\n", iface
, iTrigger
, ppwszTrigger
);
164 static HRESULT WINAPI
MSTASK_ITask_GetRunTimes(
166 const LPSYSTEMTIME pstBegin
,
167 const LPSYSTEMTIME pstEnd
,
169 LPSYSTEMTIME
*rgstTaskTimes
)
171 FIXME("(%p, %p, %p, %p, %p): stub\n", iface
, pstBegin
, pstEnd
, pCount
,
176 static HRESULT WINAPI
MSTASK_ITask_GetNextRunTime(
178 SYSTEMTIME
*pstNextRun
)
180 FIXME("(%p, %p): stub\n", iface
, pstNextRun
);
184 static HRESULT WINAPI
MSTASK_ITask_SetIdleWait(
187 WORD wDeadlineMinutes
)
189 FIXME("(%p, %d, %d): stub\n", iface
, wIdleMinutes
, wDeadlineMinutes
);
193 static HRESULT WINAPI
MSTASK_ITask_GetIdleWait(
196 WORD
*pwDeadlineMinutes
)
198 FIXME("(%p, %p, %p): stub\n", iface
, pwIdleMinutes
, pwDeadlineMinutes
);
202 static HRESULT WINAPI
MSTASK_ITask_Run(
205 FIXME("(%p): stub\n", iface
);
209 static HRESULT WINAPI
MSTASK_ITask_Terminate(
212 FIXME("(%p): stub\n", iface
);
216 static HRESULT WINAPI
MSTASK_ITask_EditWorkItem(
221 FIXME("(%p, %p, %d): stub\n", iface
, hParent
, dwReserved
);
225 static HRESULT WINAPI
MSTASK_ITask_GetMostRecentRunTime(
227 SYSTEMTIME
*pstLastRun
)
229 FIXME("(%p, %p): stub\n", iface
, pstLastRun
);
233 static HRESULT WINAPI
MSTASK_ITask_GetStatus(ITask
*iface
, HRESULT
*status
)
235 TaskImpl
*This
= impl_from_ITask(iface
);
237 TRACE("(%p, %p)\n", iface
, status
);
239 *status
= This
->status
;
243 static HRESULT WINAPI
MSTASK_ITask_GetExitCode(
247 FIXME("(%p, %p): stub\n", iface
, pdwExitCode
);
251 static HRESULT WINAPI
MSTASK_ITask_SetComment(ITask
*iface
, LPCWSTR comment
)
253 TaskImpl
*This
= impl_from_ITask(iface
);
254 IRegistrationInfo
*info
;
257 TRACE("(%p, %s)\n", iface
, debugstr_w(comment
));
259 if (!comment
|| !comment
[0])
262 hr
= ITaskDefinition_get_RegistrationInfo(This
->task
, &info
);
265 hr
= IRegistrationInfo_put_Description(info
, (BSTR
)comment
);
266 IRegistrationInfo_Release(info
);
271 static HRESULT WINAPI
MSTASK_ITask_GetComment(ITask
*iface
, LPWSTR
*comment
)
273 TaskImpl
*This
= impl_from_ITask(iface
);
274 IRegistrationInfo
*info
;
279 TRACE("(%p, %p)\n", iface
, comment
);
281 hr
= ITaskDefinition_get_RegistrationInfo(This
->task
, &info
);
282 if (hr
!= S_OK
) return hr
;
284 hr
= IRegistrationInfo_get_Description(info
, &description
);
287 len
= description
? lstrlenW(description
) + 1 : 1;
288 *comment
= CoTaskMemAlloc(len
* sizeof(WCHAR
));
294 lstrcpyW(*comment
, description
);
300 SysFreeString(description
);
303 IRegistrationInfo_Release(info
);
307 static HRESULT WINAPI
MSTASK_ITask_SetCreator(ITask
*iface
, LPCWSTR creator
)
309 TaskImpl
*This
= impl_from_ITask(iface
);
310 IRegistrationInfo
*info
;
313 TRACE("(%p, %s)\n", iface
, debugstr_w(creator
));
315 if (!creator
|| !creator
[0])
318 hr
= ITaskDefinition_get_RegistrationInfo(This
->task
, &info
);
321 hr
= IRegistrationInfo_put_Author(info
, (BSTR
)creator
);
322 IRegistrationInfo_Release(info
);
327 static HRESULT WINAPI
MSTASK_ITask_GetCreator(ITask
*iface
, LPWSTR
*creator
)
329 TaskImpl
*This
= impl_from_ITask(iface
);
330 IRegistrationInfo
*info
;
335 TRACE("(%p, %p)\n", iface
, creator
);
337 hr
= ITaskDefinition_get_RegistrationInfo(This
->task
, &info
);
338 if (hr
!= S_OK
) return hr
;
340 hr
= IRegistrationInfo_get_Author(info
, &author
);
343 len
= author
? lstrlenW(author
) + 1 : 1;
344 *creator
= CoTaskMemAlloc(len
* sizeof(WCHAR
));
350 lstrcpyW(*creator
, author
);
356 SysFreeString(author
);
359 IRegistrationInfo_Release(info
);
363 static HRESULT WINAPI
MSTASK_ITask_SetWorkItemData(
368 FIXME("(%p, %d, %p): stub\n", iface
, cBytes
, rgbData
);
372 static HRESULT WINAPI
MSTASK_ITask_GetWorkItemData(
377 FIXME("(%p, %p, %p): stub\n", iface
, pcBytes
, ppBytes
);
381 static HRESULT WINAPI
MSTASK_ITask_SetErrorRetryCount(
385 FIXME("(%p, %d): stub\n", iface
, wRetryCount
);
389 static HRESULT WINAPI
MSTASK_ITask_GetErrorRetryCount(ITask
*iface
, WORD
*count
)
391 TRACE("(%p, %p)\n", iface
, count
);
395 static HRESULT WINAPI
MSTASK_ITask_SetErrorRetryInterval(
399 FIXME("(%p, %d): stub\n", iface
, wRetryInterval
);
403 static HRESULT WINAPI
MSTASK_ITask_GetErrorRetryInterval(ITask
*iface
, WORD
*interval
)
405 TRACE("(%p, %p)\n", iface
, interval
);
409 static HRESULT WINAPI
MSTASK_ITask_SetFlags(
413 FIXME("(%p, 0x%08x): stub\n", iface
, dwFlags
);
417 static HRESULT WINAPI
MSTASK_ITask_GetFlags(ITask
*iface
, DWORD
*flags
)
419 FIXME("(%p, %p): stub\n", iface
, flags
);
424 static HRESULT WINAPI
MSTASK_ITask_SetAccountInformation(
426 LPCWSTR pwszAccountName
,
427 LPCWSTR pwszPassword
)
430 TaskImpl
*This
= impl_from_ITask(iface
);
431 LPWSTR tmp_account_name
;
433 TRACE("(%p, %s, %s): partial stub\n", iface
, debugstr_w(pwszAccountName
),
434 debugstr_w(pwszPassword
));
437 FIXME("Partial stub ignores passwords\n");
439 n
= (lstrlenW(pwszAccountName
) + 1);
440 tmp_account_name
= HeapAlloc(GetProcessHeap(), 0, n
* sizeof(WCHAR
));
441 if (!tmp_account_name
)
442 return E_OUTOFMEMORY
;
443 lstrcpyW(tmp_account_name
, pwszAccountName
);
444 HeapFree(GetProcessHeap(), 0, This
->accountName
);
445 This
->accountName
= tmp_account_name
;
449 static HRESULT WINAPI
MSTASK_ITask_GetAccountInformation(
451 LPWSTR
*ppwszAccountName
)
454 TaskImpl
*This
= impl_from_ITask(iface
);
456 TRACE("(%p, %p): partial stub\n", iface
, ppwszAccountName
);
458 /* This implements the WinXP behavior when accountName has not yet
459 * set. Win2K behaves differently, returning SCHED_E_CANNOT_OPEN_TASK */
460 if (!This
->accountName
)
461 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
);
463 n
= (lstrlenW(This
->accountName
) + 1);
464 *ppwszAccountName
= CoTaskMemAlloc(n
* sizeof(WCHAR
));
465 if (!*ppwszAccountName
)
466 return E_OUTOFMEMORY
;
467 lstrcpyW(*ppwszAccountName
, This
->accountName
);
471 static HRESULT WINAPI
MSTASK_ITask_SetApplicationName(ITask
*iface
, LPCWSTR appname
)
473 TaskImpl
*This
= impl_from_ITask(iface
);
476 TRACE("(%p, %s)\n", iface
, debugstr_w(appname
));
478 /* Empty application name */
479 if (!appname
|| !appname
[0])
480 return IExecAction_put_Path(This
->action
, NULL
);
482 /* Attempt to set pwszApplicationName to a path resolved application name */
483 len
= SearchPathW(NULL
, appname
, NULL
, 0, NULL
, NULL
);
489 tmp_name
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
491 return E_OUTOFMEMORY
;
492 len
= SearchPathW(NULL
, appname
, NULL
, len
, tmp_name
, NULL
);
494 hr
= IExecAction_put_Path(This
->action
, tmp_name
);
496 hr
= HRESULT_FROM_WIN32(GetLastError());
498 HeapFree(GetProcessHeap(), 0, tmp_name
);
502 /* If unable to path resolve name, simply set to appname */
503 return IExecAction_put_Path(This
->action
, (BSTR
)appname
);
506 static HRESULT WINAPI
MSTASK_ITask_GetApplicationName(ITask
*iface
, LPWSTR
*appname
)
508 TaskImpl
*This
= impl_from_ITask(iface
);
513 TRACE("(%p, %p)\n", iface
, appname
);
515 hr
= IExecAction_get_Path(This
->action
, &path
);
516 if (hr
!= S_OK
) return hr
;
518 len
= path
? lstrlenW(path
) + 1 : 1;
519 *appname
= CoTaskMemAlloc(len
* sizeof(WCHAR
));
525 lstrcpyW(*appname
, path
);
535 static HRESULT WINAPI
MSTASK_ITask_SetParameters(ITask
*iface
, LPCWSTR params
)
537 TaskImpl
*This
= impl_from_ITask(iface
);
539 TRACE("(%p, %s)\n", iface
, debugstr_w(params
));
541 /* Empty parameter list */
542 if (!params
|| !params
[0])
545 return IExecAction_put_Arguments(This
->action
, (BSTR
)params
);
548 static HRESULT WINAPI
MSTASK_ITask_GetParameters(ITask
*iface
, LPWSTR
*params
)
550 TaskImpl
*This
= impl_from_ITask(iface
);
555 TRACE("(%p, %p)\n", iface
, params
);
557 hr
= IExecAction_get_Arguments(This
->action
, &args
);
558 if (hr
!= S_OK
) return hr
;
560 len
= args
? lstrlenW(args
) + 1 : 1;
561 *params
= CoTaskMemAlloc(len
* sizeof(WCHAR
));
567 lstrcpyW(*params
, args
);
577 static HRESULT WINAPI
MSTASK_ITask_SetWorkingDirectory(ITask
* iface
, LPCWSTR workdir
)
579 TaskImpl
*This
= impl_from_ITask(iface
);
581 TRACE("(%p, %s)\n", iface
, debugstr_w(workdir
));
583 if (!workdir
|| !workdir
[0])
586 return IExecAction_put_WorkingDirectory(This
->action
, (BSTR
)workdir
);
589 static HRESULT WINAPI
MSTASK_ITask_GetWorkingDirectory(ITask
*iface
, LPWSTR
*workdir
)
591 TaskImpl
*This
= impl_from_ITask(iface
);
596 TRACE("(%p, %p)\n", iface
, workdir
);
598 hr
= IExecAction_get_WorkingDirectory(This
->action
, &dir
);
599 if (hr
!= S_OK
) return hr
;
601 len
= dir
? lstrlenW(dir
) + 1 : 1;
602 *workdir
= CoTaskMemAlloc(len
* sizeof(WCHAR
));
608 lstrcpyW(*workdir
, dir
);
618 static HRESULT WINAPI
MSTASK_ITask_SetPriority(
622 FIXME("(%p, 0x%08x): stub\n", iface
, dwPriority
);
626 static HRESULT WINAPI
MSTASK_ITask_GetPriority(
630 FIXME("(%p, %p): stub\n", iface
, pdwPriority
);
634 static HRESULT WINAPI
MSTASK_ITask_SetTaskFlags(
638 FIXME("(%p, 0x%08x): stub\n", iface
, dwFlags
);
642 static HRESULT WINAPI
MSTASK_ITask_GetTaskFlags(ITask
*iface
, DWORD
*flags
)
644 FIXME("(%p, %p): stub\n", iface
, flags
);
649 static HRESULT WINAPI
MSTASK_ITask_SetMaxRunTime(
653 TaskImpl
*This
= impl_from_ITask(iface
);
655 TRACE("(%p, %d)\n", iface
, dwMaxRunTime
);
657 This
->maxRunTime
= dwMaxRunTime
;
661 static HRESULT WINAPI
MSTASK_ITask_GetMaxRunTime(
663 DWORD
*pdwMaxRunTime
)
665 TaskImpl
*This
= impl_from_ITask(iface
);
667 TRACE("(%p, %p)\n", iface
, pdwMaxRunTime
);
669 *pdwMaxRunTime
= This
->maxRunTime
;
673 static HRESULT WINAPI
MSTASK_IPersistFile_QueryInterface(
678 TaskImpl
*This
= impl_from_IPersistFile(iface
);
679 TRACE("(%p, %s, %p)\n", iface
, debugstr_guid(riid
), ppvObject
);
680 return ITask_QueryInterface(&This
->ITask_iface
, riid
, ppvObject
);
683 static ULONG WINAPI
MSTASK_IPersistFile_AddRef(
686 TaskImpl
*This
= impl_from_IPersistFile(iface
);
689 ref
= InterlockedIncrement(&This
->ref
);
693 static ULONG WINAPI
MSTASK_IPersistFile_Release(
696 TaskImpl
*This
= impl_from_IPersistFile(iface
);
699 ref
= InterlockedDecrement(&This
->ref
);
701 TaskDestructor(This
);
705 static HRESULT WINAPI
MSTASK_IPersistFile_GetClassID(IPersistFile
*iface
, CLSID
*clsid
)
707 TRACE("(%p, %p)\n", iface
, clsid
);
709 *clsid
= CLSID_CTask
;
713 static HRESULT WINAPI
MSTASK_IPersistFile_IsDirty(
716 FIXME("(%p): stub\n", iface
);
720 static HRESULT WINAPI
MSTASK_IPersistFile_Load(
722 LPCOLESTR pszFileName
,
725 FIXME("(%p, %p, 0x%08x): stub\n", iface
, pszFileName
, dwMode
);
729 static HRESULT WINAPI
MSTASK_IPersistFile_Save(
731 LPCOLESTR pszFileName
,
734 FIXME("(%p, %p, %d): stub\n", iface
, pszFileName
, fRemember
);
735 WARN("Returning S_OK but not writing to disk: %s %d\n",
736 debugstr_w(pszFileName
), fRemember
);
740 static HRESULT WINAPI
MSTASK_IPersistFile_SaveCompleted(
742 LPCOLESTR pszFileName
)
744 FIXME("(%p, %p): stub\n", iface
, pszFileName
);
748 static HRESULT WINAPI
MSTASK_IPersistFile_GetCurFile(
750 LPOLESTR
*ppszFileName
)
752 FIXME("(%p, %p): stub\n", iface
, ppszFileName
);
757 static const ITaskVtbl MSTASK_ITaskVtbl
=
759 MSTASK_ITask_QueryInterface
,
761 MSTASK_ITask_Release
,
762 MSTASK_ITask_CreateTrigger
,
763 MSTASK_ITask_DeleteTrigger
,
764 MSTASK_ITask_GetTriggerCount
,
765 MSTASK_ITask_GetTrigger
,
766 MSTASK_ITask_GetTriggerString
,
767 MSTASK_ITask_GetRunTimes
,
768 MSTASK_ITask_GetNextRunTime
,
769 MSTASK_ITask_SetIdleWait
,
770 MSTASK_ITask_GetIdleWait
,
772 MSTASK_ITask_Terminate
,
773 MSTASK_ITask_EditWorkItem
,
774 MSTASK_ITask_GetMostRecentRunTime
,
775 MSTASK_ITask_GetStatus
,
776 MSTASK_ITask_GetExitCode
,
777 MSTASK_ITask_SetComment
,
778 MSTASK_ITask_GetComment
,
779 MSTASK_ITask_SetCreator
,
780 MSTASK_ITask_GetCreator
,
781 MSTASK_ITask_SetWorkItemData
,
782 MSTASK_ITask_GetWorkItemData
,
783 MSTASK_ITask_SetErrorRetryCount
,
784 MSTASK_ITask_GetErrorRetryCount
,
785 MSTASK_ITask_SetErrorRetryInterval
,
786 MSTASK_ITask_GetErrorRetryInterval
,
787 MSTASK_ITask_SetFlags
,
788 MSTASK_ITask_GetFlags
,
789 MSTASK_ITask_SetAccountInformation
,
790 MSTASK_ITask_GetAccountInformation
,
791 MSTASK_ITask_SetApplicationName
,
792 MSTASK_ITask_GetApplicationName
,
793 MSTASK_ITask_SetParameters
,
794 MSTASK_ITask_GetParameters
,
795 MSTASK_ITask_SetWorkingDirectory
,
796 MSTASK_ITask_GetWorkingDirectory
,
797 MSTASK_ITask_SetPriority
,
798 MSTASK_ITask_GetPriority
,
799 MSTASK_ITask_SetTaskFlags
,
800 MSTASK_ITask_GetTaskFlags
,
801 MSTASK_ITask_SetMaxRunTime
,
802 MSTASK_ITask_GetMaxRunTime
805 static const IPersistFileVtbl MSTASK_IPersistFileVtbl
=
807 MSTASK_IPersistFile_QueryInterface
,
808 MSTASK_IPersistFile_AddRef
,
809 MSTASK_IPersistFile_Release
,
810 MSTASK_IPersistFile_GetClassID
,
811 MSTASK_IPersistFile_IsDirty
,
812 MSTASK_IPersistFile_Load
,
813 MSTASK_IPersistFile_Save
,
814 MSTASK_IPersistFile_SaveCompleted
,
815 MSTASK_IPersistFile_GetCurFile
818 HRESULT
TaskConstructor(ITaskService
*service
, const WCHAR
*task_name
, ITask
**task
)
821 ITaskDefinition
*taskdef
;
822 IActionCollection
*actions
;
825 TRACE("(%s, %p)\n", debugstr_w(task_name
), task
);
827 hr
= ITaskService_NewTask(service
, 0, &taskdef
);
828 if (hr
!= S_OK
) return hr
;
830 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(*This
));
833 ITaskDefinition_Release(taskdef
);
834 return E_OUTOFMEMORY
;
837 This
->ITask_iface
.lpVtbl
= &MSTASK_ITaskVtbl
;
838 This
->IPersistFile_iface
.lpVtbl
= &MSTASK_IPersistFileVtbl
;
840 This
->task
= taskdef
;
841 This
->task_name
= heap_strdupW(task_name
);
842 This
->status
= SCHED_S_TASK_NOT_SCHEDULED
;
843 This
->accountName
= NULL
;
845 /* Default time is 3 days = 259200000 ms */
846 This
->maxRunTime
= 259200000;
848 hr
= ITaskDefinition_get_Actions(This
->task
, &actions
);
851 hr
= IActionCollection_Create(actions
, TASK_ACTION_EXEC
, (IAction
**)&This
->action
);
852 IActionCollection_Release(actions
);
855 *task
= &This
->ITask_iface
;
856 InterlockedIncrement(&dll_ref
);
861 ITaskDefinition_Release(This
->task
);
862 ITask_Release(&This
->ITask_iface
);