Knowledge Base Nr: 00172 tasksched.cpp - http://www.swe-kaiser.de
Downloads:
WIN32: Taskscheduler verwalten (task einfügen, löschen, auflisten)
#include "afxwin.h"
#include <mstask.h>
class CSchedulerSupport
{
public:
CSchedulerSupport(const char* lpszUser, const char* lpszPassword);
virtual ~CSchedulerSupport();
enum ETaskFrequency
{
freqUnset = 0, // for debugging - used in asserts
freqFirst = 0, // for debugging
freqOnce,
freqDaily,
freqWeekly,
freqMonthly,
freqLast = freqMonthly // for debugging
};
static int DeleteTask(const char* lpszTaskName);
static int GetTaskList(CStringArray* arTaskList);
int CreateTask(const char* lpszTaskName, SYSTEMTIME timeStart, SYSTEMTIME timeEnd
, CString strProgramPath, CString strComment = ""
, CString strParameters = "", CString strStartingDir = ""
, ETaskFrequency eFreq = freqOnce, bool bFailIfExists = false);
//timestringformat: "%d.%d.%d %d:%d:%d", nDay, nMonth, nYear, nHour, nMin, nSec
int CreateTask(const char* lpszTaskName, const char* lpszTimeStart, const char* lpszTimeEnd
, CString strProgramPath, CString strComment = ""
, CString strParameters = "", CString strStartingDir = ""
, ETaskFrequency eFreq = freqOnce, bool bFailIfExists = false);
protected:
int SaveTask(const char* lpszTaskName, bool bFailIfExists = false); // save the task to the scheduler
...
};
///////////////////////////////
#pragma comment(lib, "mstask.lib")
#define DDS_CST_EVERYMONTH \
TASK_JANUARY | TASK_FEBRUARY | TASK_MARCH | \
TASK_APRIL | TASK_MAY | TASK_JUNE | \
TASK_JULY | TASK_AUGUST | TASK_SEPTEMBER | \
TASK_OCTOBER | TASK_NOVEMBER | TASK_DECEMBER
int CSchedulerSupport::SaveTask(const char* lpszTaskName, bool bFailIfExists)
{
HRESULT hr;
ITaskScheduler* pISched = NULL;
IUnknown* pIUnk = NULL;
IPersistFile* pIFile = NULL;
ITask* pITask = NULL;
ITaskTrigger* pITaskTrig = NULL;
IScheduledWorkItem* pISchedWItem = NULL;
TASK_TRIGGER rTrigger;
DWORD dwTaskFlags;
WORD wTrigNumber;
USES_CONVERSION;
ASSERT ( AfxIsValidString ( lpszTaskName ));
// Validate parameters and member data. The program path can't be empty,
// but the other strings may be.
if ( 0 == m_timeStart.wYear ||
NULL == lpszTaskName ||
0 == lstrlen ( lpszTaskName ) ||
m_strProgramPath.GetLength() < 1 )
{
return E_FAIL;
}
// Get an interface to the scheduler.
hr = ::CoCreateInstance (
CLSID_CTaskScheduler,
NULL,
CLSCTX_INPROC_SERVER,
IID_ITaskScheduler,
(void **) &pISched );
if ( FAILED(hr) )
{
#ifdef _DEBUG
TRACE1("CSchedulerSupport::SaveTask() - failed to create a task scheduler interface. Return = 0x%08X\n",
(DWORD) hr );
// Check if the error was "class not registered". If so, you don't
// have the scheduler installed. I display a nice long message in
// the debug window, which hopefully explains what's up. :)
if ( REGDB_E_CLASSNOTREG == hr )
{
TRACE0(" The error was REGDB_E_CLASSNOTREG, meaning you don't have the scheduler installed.\n"
_T(" If you are running 95 or NT 4 with IE 4, you must install the task scheduler from the\n")
_T(" IE components install page on MS's web site or the IE CD.\n")
_T(" If you're on 98, NT 5, or 95/NT 4 with IE 5, then something's wrong with your install\n")
_T(" because the scheduler should always be installed.\n")
_T(" Note that this class does *NOT* work with the \"AT\" service, which is the default\n")
_T(" scheduler on NT 4 and earlier.\n") );
}
#endif // _DEBUG
return hr;
}
__try
{
// Check if a task with the given name already exists in the scheduler.
// I do this check manually because the behavior of
// ITaskScheduler::NewWorkItem() is different between IE 4 and IE 5.
// In IE 4, NewWorkItem() will succeed if a task with the name you pass it
// already exists (even though the INetSDK docs says it should fail).
// In IE 5, NewWorkItem() has been fixed to match the docs.
// So, my solution is to call ITaskScheduler::Activate() and pass it the
// task name. If that function succeeds, then I know a task with the
// given name already exists.
// (Note to MS: This _really_ ought to be mentioned in the KB!!)
hr = pISched->Activate ( T2COLE ( lpszTaskName ), IID_ITask, &pIUnk );
if ( SUCCEEDED(hr) )
{
// A task with the given name already exists. Check bFailIfExists
// to see what we should do.
pIUnk->Release(); // We don't need this interface.
pIUnk = NULL;
if ( bFailIfExists )
{
TRACE0("CSchedulerSupport::SaveTask() - A task with the given name already exists; failing.\n");
return HRESULT_FROM_WIN32 ( ERROR_FILE_EXISTS );
}
else
{
// Try to delete the existing task. If the delete succeeds, then
// we proceed. Otherwise, we'll bail out with an error.
TRACE0("CSchedulerSupport::SaveTask() - A task with the given name already exists; deleting it.\n");
hr = CSchedulerSupport::DeleteTask ( lpszTaskName );
if ( FAILED(hr) )
{
TRACE1("CSchedulerSupport::SaveTask() - couldn't delete existing task! Bailing out. Return = 0x%08X\n",
(DWORD) hr );
return hr;
}
}
}
// Create a new task.
hr = pISched->NewWorkItem ( T2COLE ( lpszTaskName ), CLSID_CTask,
IID_ITask, &pIUnk );
if ( FAILED(hr) )
{
TRACE1("CSchedulerSupport::SaveTask() - couldn't create a new work item. Return = 0x%08X\n",
(DWORD) hr );
return hr;
}
// We now have an IUnknown pointer. This is queried for an ITask
// pointer on the work item we just added.
hr = pIUnk->QueryInterface ( IID_ITask, (void **) &pITask );
if ( FAILED(hr) )
{
TRACE1("CSchedulerSupport::SaveTask() - QI() on IUnknown failed to get an ITask. Return = 0x%08X\n",
(DWORD) hr );
return hr;
}
// Clean up the IUnknown, as we are done with it.
pIUnk->Release();
pIUnk = NULL;
// Set the program name.
hr = pITask->SetApplicationName ( T2COLE( (LPCTSTR) m_strProgramPath ));
if ( FAILED(hr) )
{
TRACE1("CSchedulerSupport::SaveTask() - failed to set application. Return = 0x%08X\n",
(DWORD) hr );
return hr;
}
// Set the app's parameters.
if ( m_strParameters.GetLength() > 0 )
{
hr = pITask->SetParameters ( T2COLE( (LPCTSTR) m_strParameters ));
if ( FAILED(hr) )
{
TRACE1("CSchedulerSupport::SaveTask() - failed to set parameters. Return = 0x%08X\n",
(DWORD) hr );
return hr;
}
}
// Set the starting directory.
if ( m_strStartingDir.GetLength() > 0 )
{
hr = pITask->SetWorkingDirectory ( T2COLE( (LPCTSTR) m_strStartingDir ));
if ( FAILED(hr) )
{
TRACE1("CSchedulerSupport::SaveTask() - failed to set starting directory. Return = 0x%08X\n",
(DWORD) hr );
return hr;
}
}
// Set the job comment.
if ( m_strComment.GetLength() > 0 )
{
hr = pITask->SetComment ( T2COLE( (LPCTSTR) m_strComment ));
if ( FAILED (hr) )
{
TRACE1("CSchedulerSupport::SaveTask() - failed to set task comment. Return = 0x%08X\n",
(DWORD) hr );
return hr;
}
}
// Set the flags on the task object
// The two flags below are the default for events created via the task
// scheduler UI.
// Note that I _don't_ set TASK_FLAG_DELETE_WHEN_DONE. Setting this flag
// is bad if you have the "Notify me of missed tasks" option on in the
// scheduler. If this flag is set and the event is missed, the scheduler
// nukes the event without notifying you . How mean.
dwTaskFlags = TASK_FLAG_DONT_START_IF_ON_BATTERIES |
TASK_FLAG_KILL_IF_GOING_ON_BATTERIES;
// On NT, set the interactive flag so the user can see it.
if ( !( GetVersion() & 0x80000000 ) )
{
dwTaskFlags |= TASK_FLAG_INTERACTIVE;
}
hr = pITask->SetFlags ( dwTaskFlags );
if ( FAILED (hr) )
{
TRACE1("CSchedulerSupport::SaveTask() - failed to set task flags. Return = 0x%08X\n",
(DWORD) hr );
return hr;
}
// Now, create a trigger to run the task at our specified time.
hr = pITask->CreateTrigger ( &wTrigNumber, &pITaskTrig );
if ( FAILED (hr) )
{
TRACE1("CSchedulerSupport::SaveTask() - failed to create a task trigger. Return = 0x%08X\n",
(DWORD) hr );
return hr;
}
// Now, fill in the trigger as necessary. Note that the seconds field of
// m_timeStart is not used since the scheduler only stores the hour
// and minute of the starting time.
ZeroMemory ( &rTrigger, sizeof (TASK_TRIGGER) );
rTrigger.cbTriggerSize = sizeof (TASK_TRIGGER);
rTrigger.wBeginYear = m_timeStart.wYear;
rTrigger.wBeginMonth = m_timeStart.wMonth;
rTrigger.wBeginDay = m_timeStart.wDay;
rTrigger.wStartHour = m_timeStart.wHour;
rTrigger.wStartMinute = m_timeStart.wMinute;
if ( 0 != m_timeEnd.wYear )
{
rTrigger.rgFlags = TASK_TRIGGER_FLAG_HAS_END_DATE;
rTrigger.wEndYear = m_timeEnd.wYear;
rTrigger.wEndMonth = m_timeEnd.wMonth;
rTrigger.wEndDay = m_timeEnd.wDay;
}
switch ( m_eFreq )
{
case freqOnce:
rTrigger.TriggerType = TASK_TIME_TRIGGER_ONCE;
break;
case freqDaily:
rTrigger.TriggerType = TASK_TIME_TRIGGER_DAILY;
// Repeat every day.
rTrigger.Type.Daily.DaysInterval = 1;
break;
case freqWeekly:
rTrigger.TriggerType = TASK_TIME_TRIGGER_WEEKLY;
rTrigger.Type.Weekly.rgfDaysOfTheWeek =
GetDayOfWeekFlag ( m_timeStart );
// Repeat every week.
rTrigger.Type.Weekly.WeeksInterval = 1;
break;
case freqMonthly:
rTrigger.TriggerType = TASK_TIME_TRIGGER_MONTHLYDATE;
rTrigger.Type.MonthlyDate.rgfDays = 1 << ( m_timeStart.wDay - 1 );
rTrigger.Type.MonthlyDate.rgfMonths = DDS_CST_EVERYMONTH;
break;
default:
ASSERT(FALSE);
return -1; //DEFAULT_UNREACHABLE;
}
// Add this trigger to the task using ITaskTrigger::SetTrigger
hr = pITaskTrig->SetTrigger ( &rTrigger );
if ( FAILED(hr) )
{
TRACE1("CSchedulerSupport::SaveTask() - failed to add trigger to the task. Return = 0x%08X\n",
(DWORD) hr );
return hr;
}
//user account
hr = pITask->QueryInterface ( IID_IScheduledWorkItem, (void **) &pISchedWItem );
if ( FAILED (hr) )
{
TRACE1("CSchedulerSupport::SaveTask() - failed to get an IScheduledWorkItem interface on the task. Return = 0x%08X\n",
(DWORD) hr );
return hr;
}
//ACHTUNG: username/password als parameter übergeben!
hr = pISchedWItem->SetAccountInformation (T2COLE( (LPCTSTR)m_strUser), T2COLE( (LPCTSTR)m_strPassword));
//default account: ist nicht interaktiv!
//hr = pISchedWItem->SetAccountInformation (T2COLE( (LPCTSTR)""), T2COLE( (LPCTSTR)NULL));
if ( FAILED(hr) )
{
TRACE1("CSchedulerSupport::SaveTask() - error SetAccountInformation. Return = 0x%08X\n",
(DWORD) hr );
return hr;
}
// Save the changes with IPersistFile::SaveTask(). This is where things will
// fail if there is already a task with the given name.
hr = pITask->QueryInterface ( IID_IPersistFile, (void **) &pIFile );
if ( FAILED (hr) )
{
TRACE1("CSchedulerSupport::SaveTask() - failed to get an IPersistFile interface on the task. Return = 0x%08X\n",
(DWORD) hr );
return hr;
}
hr = pIFile->Save ( NULL, FALSE );
if ( FAILED(hr) )
{
TRACE1("CSchedulerSupport::SaveTask() - error saving task. Return = 0x%08X\n",
(DWORD) hr );
return hr;
}
} // end __try
__finally
{
// Clean up all the interfaces.
if ( pIFile != NULL )
pIFile->Release();
if ( pITaskTrig != NULL )
pITaskTrig->Release();
if ( pITask != NULL )
pITask->Release();
if ( pISched != NULL )
pISched->Release();
if ( pISchedWItem != NULL )
pISchedWItem->Release();
} // end __finally
return hr;
}
int CSchedulerSupport::DeleteTask(const char* lpszTaskName)
{
HRESULT hr;
ITaskScheduler* pISched = NULL;
USES_CONVERSION;
ASSERT ( AfxIsValidString ( lpszTaskName ));
if ( 0 == lstrlen ( lpszTaskName ) )
{
return E_FAIL;
}
// Get an interface to the scheduler.
hr = ::CoCreateInstance (
CLSID_CTaskScheduler,
NULL,
CLSCTX_INPROC_SERVER,
IID_ITaskScheduler,
(void **) &pISched );
if ( FAILED(hr) )
{
#ifdef _DEBUG
TRACE1("CSchedulerSupport::DeleteTask() - failed to create a task scheduler interface. Return = 0x%08X\n",
(DWORD) hr );
// Check if the error was "class not registered". If so, you don't
// have the scheduler installed. I display a nice long message in
// the debug window, which hopefully explains what's up. :)
if ( REGDB_E_CLASSNOTREG == hr )
{
TRACE0(" The error was REGDB_E_CLASSNOTREG, meaning you don't have the scheduler installed.\n"
_T(" If you are running 95 or NT 4 with IE 4, you must install the task scheduler from the\n")
_T(" IE components install page on MS's web site or the IE CD.\n")
_T(" If you're on 98, NT 5, or 95/NT 4 with IE 5, then something's wrong with your install\n")
_T(" because the scheduler should always be installed.\n")
_T(" Note that this class does *NOT* work with the \"AT\" service, which is the default\n")
_T(" scheduler on NT 4 and earlier.\n") );
}
#endif // _DEBUG
return hr;
}
hr = pISched->Delete ( T2COLE ( lpszTaskName ));
if ( FAILED(hr) )
{
TRACE1("CSchedulerSupport::DeleteTask() - failed to delete task. Return = 0x%08X\n",
(DWORD) hr );
}
pISched->Release();
return hr;
}
int CSchedulerSupport::GetTaskList(CStringArray* arTaskList)
{
arTaskList->RemoveAll();
HRESULT hr = ERROR_SUCCESS;
ITaskScheduler *pITS;
hr = CoCreateInstance(CLSID_CTaskScheduler,
NULL,
CLSCTX_INPROC_SERVER,
IID_ITaskScheduler,
(void **) &pITS);
if (FAILED(hr))
{
ASSERT(FALSE);
return hr;
}
IEnumWorkItems *pIEnum;
hr = pITS->Enum(&pIEnum);
if (FAILED(hr))
{
ASSERT(FALSE);
return hr;
}
const TASKS_TO_RETRIEVE = 5;
CString str;
LPWSTR *lpwszNames;
DWORD dwFetchedTasks = 0;
while (SUCCEEDED(pIEnum->Next(TASKS_TO_RETRIEVE,
&lpwszNames,
&dwFetchedTasks))
&& (dwFetchedTasks != 0))
{
while (dwFetchedTasks)
{
CString strTask(lpwszNames[--dwFetchedTasks]);
str = strTask;
CoTaskMemFree(lpwszNames[dwFetchedTasks]);
////////////
ITask *pITask;
hr = pITS->Activate(strTask.AllocSysString(),
IID_ITask,
(IUnknown**) &pITask);
if (FAILED(hr))
{
continue;
}
LPWSTR ppwszComment;
hr = pITask->GetComment(&ppwszComment);
pITask->Release();
if (FAILED(hr))
{
continue;
}
str += "\t";
str += ppwszComment;
CoTaskMemFree(ppwszComment);
///////////
arTaskList->Add(str);
}
CoTaskMemFree(lpwszNames);
}
pITS->Release();
pIEnum->Release();
return 0;
}