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;
}