windows-nt/Source/XPSP1/NT/admin/services/sched/job/jobex.cxx
2020-09-26 16:20:57 +08:00

1107 lines
31 KiB
C++

//+----------------------------------------------------------------------------
//
// Job Scheduler Job Object Handler
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1996.
//
// File: jobex.cxx
//
// Contents: ITask interface methods
//
// Classes: CJob
//
// Interfaces: ITask
//
// History: 16-Oct-95 EricB created
// 11-Nov-96 AnirudhS Fixed both GetRunTimes methods to return
// the right success codes.
// 20-Nov-01 ShBrown Switched to use standard NT build versioning
//
//-----------------------------------------------------------------------------
#include "..\pch\headers.hxx"
#pragma hdrstop
#include "job.hxx"
#include "defines.hxx"
#include <ntverp.h>
//
// Increment the following if the job object file format is changed in an incompatible fashion.
//
#define JOB_OBJ_FORMAT_VERSION 1
//+----------------------------------------------------------------------------
//
// Member: CJob::CJob
//
// Synopsis: constructor
//
//-----------------------------------------------------------------------------
CJob::CJob(void) :
m_wVersion(MAKEWORD(VER_PRODUCTMINORVERSION, VER_PRODUCTMAJORVERSION)),
m_wFileObjVer(JOB_OBJ_FORMAT_VERSION),
m_wTriggerOffset(0),
m_wErrorRetryCount(0),
m_wErrorRetryInterval(0),
m_cRunningInstances(0),
m_wIdleWait(SCH_DEFAULT_IDLE_TIME),
m_wIdleDeadline(SCH_DEFAULT_IDLE_DEADLINE),
m_dwPriority(NORMAL_PRIORITY_CLASS),
m_dwMaxRunTime(MAX_RUN_TIME_DEFAULT),
m_ExitCode(0),
m_hrStatus(SCHED_S_TASK_NOT_SCHEDULED),
m_rgFlags(JOB_I_FLAG_NO_RUN_PROP_CHANGE), // The task is not yet dirty
m_rgTaskFlags(0),
m_pwszApplicationName(NULL),
m_pwszParameters(NULL),
m_pwszWorkingDirectory(NULL),
m_pwszCreator(NULL),
m_pwszComment(NULL),
m_cbTaskData(0),
m_pbTaskData(NULL),
m_cReserved(0),
m_pbReserved(NULL),
m_hrStartError(SCHED_S_TASK_HAS_NOT_RUN),
m_pIJobTypeInfo(NULL),
m_cReferences(1),
#if !defined(_CHICAGO_)
m_pAccountInfo(NULL),
m_pbSignature(NULL),
#endif // !defined(_CHICAGO_)
m_ptszFileName(NULL),
m_fFileCreated(FALSE)
{
//TRACE(CJob, CJob);
UUID uuidNull = {0};
m_uuidJob = uuidNull;
SYSTEMTIME stNull = {0};
m_stMostRecentRunTime = stNull;
}
//+----------------------------------------------------------------------------
//
// Member: CJob::~CJob
//
// Synopsis: destructor
//
//-----------------------------------------------------------------------------
CJob::~CJob(void)
{
//TRACE(CJob, ~CJob);
FreeProperties();
if (m_pIJobTypeInfo != NULL)
{
m_pIJobTypeInfo->Release();
}
delete m_ptszFileName;
#if !defined(_CHICAGO_)
if (m_pAccountInfo != NULL)
{
ZERO_PASSWORD(m_pAccountInfo->pwszPassword); // NULL is handled.
delete m_pAccountInfo->pwszAccount;
delete m_pAccountInfo->pwszPassword;
delete m_pAccountInfo;
}
#endif // !defined(_CHICAGO_)
}
//+----------------------------------------------------------------------------
//
// Member: CJob::ITask::GetRunTimes
//
// Synopsis: Return a list of run times for this job that fall between the
// bracketing times inclusively.
//
// Arguments: [pstBegin] - the start of the bracketing period
// [pstEnd] - the end of the bracketing period, may be NULL
// [pCount] - On entry, points to the number of run times
// to retrieve. This must be a number between 1
// and TASK_MAX_RUN_TIMES. On exit, points to
// the number of run times actually retrieved.
// [rgstJobTimes] - the returned array of SYSTEMTIME structures
//
// Returns: S_OK: the requested number of run times are returned.
// S_FALSE: fewer than the requested number of run times are
// returned. (More precisely: the task has valid time-based
// triggers, but the number of run times during the specified
// time bracket is less than the number of run times requested.
// (This includes the case of no event triggers and zero run
// times during that time bracket.))
// SCHED_S_EVENT_TRIGGER: no time-based triggers will cause the
// task to run during the specified time bracket, but event
// triggers may (note that event triggers have no set run
// times). (In this case *pCount is set to 0)
// SCHED_S_TASK_NO_VALID_TRIGGERS: the task is enabled but has no
// valid triggers.
// SCHED_S_TASK_DISABLED: the task is disabled.
// E_INVALIDARG: the arguments are not valid.
// E_OUTOFMEMORY: not enough memory is available.
//
// Notes: The job time list is callee allocated and caller freed. The
// caller must use CoTaskMemFree to free this list.
//-----------------------------------------------------------------------------
STDMETHODIMP
CJob::GetRunTimes(const LPSYSTEMTIME pstBegin, const LPSYSTEMTIME pstEnd,
WORD * pCount, LPSYSTEMTIME * rgstJobTimes)
{
TRACE(CJob, GetRunTimes);
HRESULT hr;
WORD cLimit = *pCount;
if (cLimit < 1 || cLimit > TASK_MAX_RUN_TIMES)
{
return E_INVALIDARG;
}
*rgstJobTimes = NULL;
//
// Get the list of run times.
//
CTimeRunList RunList;
*pCount = 0; // Number of elements in RunList
hr = GetRunTimesP(pstBegin, pstEnd, pCount, cLimit, &RunList, NULL);
if (hr != S_OK)
{
*pCount = 0;
return hr;
}
schAssert(*pCount <= cLimit);
//
// Convert the time list to an array of SYSTEMTIMEs.
//
#if DBG
WORD cCountBefore = *pCount;
#endif
hr = RunList.MakeSysTimeArray(rgstJobTimes, pCount);
if (SUCCEEDED(hr))
{
schAssert(*pCount == cCountBefore);
hr = (*pCount < cLimit) ? S_FALSE : S_OK;
}
return hr;
}
//+----------------------------------------------------------------------------
//
// Member: CJob::GetRunTimesP, private
//
// Synopsis: Computes a set of run times for this job that fall between the
// bracketing times inclusively, and adds them to the run list.
//
// Arguments: [pstBegin] - the start of the bracketing period
// [pstEnd] - the end of the bracketing period, may be NULL
// [pCount] - On both entry and exit, points to the number of
// run times in the list.
// [cLimit] - the maximum number of CRun objects that the list
// may contain.
// [pRunList] - the list of run time objects, can be
// NULL if just checking to see if there will be
// *any* runs. (Note: If it's NULL, duplicate run
// times are not detected, so pCount may be over-
// estimated on return.)
// [ptszShortName] - the folder-relative job name.
//
// Returns: S_OK: Some (zero or more) runs have been added to the list.
// SCHED_S_EVENT_TRIGGER: the job has an event trigger and none
// of the other triggers had runs.
// SCHED_S_TASK_NO_VALID_TRIGGERS: the triggers are disabled or
// not set.
// SCHED_S_TASK_DISABLED: the job is disabled.
//
// Notes: The job time list is callee allocated and caller freed. The
// caller must use FreeList to free this list.
//-----------------------------------------------------------------------------
HRESULT
CJob::GetRunTimesP(const SYSTEMTIME * pstBegin, const SYSTEMTIME * pstEnd,
WORD * pCount, WORD cLimit, CTimeRunList * pRunList,
LPTSTR ptszShortName)
{
HRESULT hr;
schAssert(cLimit > 0); // If cLimit is 0, it's not clear what to return
schAssert(cLimit <= TASK_MAX_RUN_TIMES);
schAssert(*pCount <= cLimit);
//
// Test for conditions that would prevent a run time from being returned.
//
if (IsFlagSet(TASK_FLAG_DISABLED))
{
return SCHED_S_TASK_DISABLED;
}
WORD cTriggers = m_Triggers.GetCount();
//
// Don't need any of the internal job flags for run instance processing.
// That bit space is used for run processing specific flags defined in
// runobj.hxx.
//
DWORD rgFlags = GetUserFlags();
BOOL fEventTriggerFound = FALSE;
BOOL fTimeTriggerFound = FALSE;
//
// Loop over the triggers.
//
for (WORD i = 0; i < cTriggers; i++)
{
hr = ::GetTriggerRunTimes(m_Triggers[i],
pstBegin,
pstEnd,
pCount,
cLimit,
pRunList,
ptszShortName,
rgFlags,
m_dwMaxRunTime,
m_wIdleWait,
m_wIdleDeadline);
if (FAILED(hr))
{
ERR_OUT("CJob::GetRunTimes, ::GetRunTimes", hr);
return(hr);
}
if (hr == SCHED_S_EVENT_TRIGGER)
{
fEventTriggerFound = TRUE;
}
else if (hr == S_OK)
{
fTimeTriggerFound = TRUE;
if (*pCount >= cLimit && pRunList == NULL)
{
//
// Special case where all we want is to test *if* there are runs,
// and don't need the run times. Otherwise, we examine all
// triggers because they won't return run times in any particular
// order.
//
break;
}
}
}
//
// Summarize the results in the return code
//
if (fTimeTriggerFound)
{
if (*pCount == 0 && fEventTriggerFound)
{
hr = SCHED_S_EVENT_TRIGGER;
// (BUGBUG Here, we are assuming that *pCount was 0 initially.
// Maybe add this to the comments and assertions at the start
// of this function. However, this might not be necessary if
// *pCount is made a member of CRunList, as it should be.)
}
else
{
hr = S_OK;
}
}
else if (fEventTriggerFound)
{
hr = SCHED_S_EVENT_TRIGGER;
}
else
{
hr = SCHED_S_TASK_NO_VALID_TRIGGERS;
}
return hr;
}
//+----------------------------------------------------------------------------
//
// Synopsis: Skips past the preceeding data and loads only the triggers
//
// Notes: This method will fail if not preceeded at some time during
// the job object's lifetime by a call to LoadP.
//
//-----------------------------------------------------------------------------
HRESULT
CJob::LoadTriggers(void)
{
// CODEWORK Optimize this to use a single ReadFile, like LoadP().
// Or, get rid of it altogether and just use LoadP, or an additional
// flag to LoadP.
//TRACE(CJob, LoadTriggers);
if (m_ptszFileName == NULL || m_wTriggerOffset == 0)
{
return E_FAIL;
}
HRESULT hr;
//
// Open the file.
//
HANDLE hFile = CreateFile(m_ptszFileName, GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN,
NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
hr = HRESULT_FROM_WIN32(GetLastError());
ERR_OUT("CJob::Load, file open", hr);
return hr;
}
//
// Move to the trigger data.
//
DWORD dwBytes;
dwBytes = SetFilePointer(hFile, m_wTriggerOffset, NULL, FILE_BEGIN);
if (dwBytes == 0xffffffff)
{
hr = HRESULT_FROM_WIN32(GetLastError());
ERR_OUT("CJob::LoadTriggers, move to trigger data", hr);
goto cleanup;
}
//
// Load triggers.
//
hr = this->_LoadTriggers(hFile);
cleanup:
//
// Close the file.
//
CloseHandle(hFile);
return hr;
}
//+----------------------------------------------------------------------------
//
// Member: CJob::_LoadTriggersFromBuffer, private
//
// Synopsis:
//
// Arguments:
//
// Returns:
//
//-----------------------------------------------------------------------------
HRESULT
CJob::_LoadTriggersFromBuffer(CInputBuffer * pBuf)
{
HRESULT hr = S_OK;
WORD cTriggers;
// Read trigger count.
//
if (!pBuf->Read(&cTriggers, sizeof cTriggers))
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
CHECK_HRESULT(hr);
return hr;
}
// Verify buffer contains that many triggers.
//
BYTE *pTriggers = pBuf->CurrentPosition(); // save current position
if (!pBuf->Advance(cTriggers * sizeof TASK_TRIGGER))
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
CHECK_HRESULT(hr);
return hr;
}
// Copy triggers into a properly aligned array.
// CODEWORK: Align them in the original buffer instead of allocating
// a separate one.
//
hr = m_Triggers.AllocAndCopy(cTriggers, pTriggers);
if (FAILED(hr))
{
CHECK_HRESULT(hr);
return hr;
}
if (cTriggers)
{
//
// BUGBUG: temporary, remove the next time the job file format
// is revised.
//
TASK_TRIGGER * ajt = m_Triggers.GetArray();
for (WORD i = 0; i < cTriggers; i++)
{
ajt[i].Reserved1 = i;
}
//
// end of temporary code.
//
this->SetFlag(JOB_I_FLAG_HAS_TRIGGERS);
}
else
{
//
// No triggers - clear trigger flag.
//
this->ClearFlag(JOB_I_FLAG_HAS_TRIGGERS);
}
return S_OK;
}
//+----------------------------------------------------------------------------
//
// Member: CJob::_LoadTriggers, private
//
// Synopsis:
//
// Arguments: None.
//
// Returns:
//
// Notes: None.
//
//-----------------------------------------------------------------------------
HRESULT
CJob::_LoadTriggers(HANDLE hFile)
{
HRESULT hr = S_OK;
DWORD dwRead;
WORD cTriggers;
// Read trigger count.
//
if (!ReadFile(hFile, &cTriggers, sizeof(cTriggers), &dwRead, NULL))
{
hr = HRESULT_FROM_WIN32(GetLastError());
CHECK_HRESULT(hr);
return(hr);
}
if (dwRead != sizeof(cTriggers))
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
CHECK_HRESULT(hr);
return(hr);
}
// Free existing trigger array.
//
m_Triggers.FreeArray();
// Get on with load.
//
if (cTriggers)
{
TASK_TRIGGER * ajt = (TASK_TRIGGER *)
LocalAlloc(LMEM_FIXED, cTriggers * sizeof TASK_TRIGGER);
if (ajt == NULL)
{
hr = HRESULT_FROM_WIN32(GetLastError());
CHECK_HRESULT(hr);
return hr;
}
if (!ReadFile(hFile, ajt, cTriggers * sizeof TASK_TRIGGER, &dwRead,
NULL))
{
hr = HRESULT_FROM_WIN32(GetLastError());
CHECK_HRESULT(hr);
LocalFree(ajt);
return hr;
}
if (dwRead != cTriggers * sizeof TASK_TRIGGER)
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
CHECK_HRESULT(hr);
LocalFree(ajt);
return hr;
}
for (WORD i = 0; i < cTriggers; i++)
{
//
// BUGBUG: temporary, remove the next time the job file format
// is revised.
//
ajt[i].Reserved1 = i;
//
// end of temporary code.
//
}
m_Triggers.SetArray(cTriggers, ajt);
this->SetFlag(JOB_I_FLAG_HAS_TRIGGERS);
}
else
{
//
// No triggers - clear trigger flag.
//
this->ClearFlag(JOB_I_FLAG_HAS_TRIGGERS);
}
return(hr);
}
//+----------------------------------------------------------------------------
//
// Member: CJob::_SaveTriggers, private
//
// Synopsis:
//
// Arguments: None.
//
// Returns:
//
// Notes: None.
//
//-----------------------------------------------------------------------------
HRESULT
CJob::_SaveTriggers(HANDLE hFile)
{
HRESULT hr = S_OK;
DWORD dwWritten;
DWORD cTriggerDataSize;
WORD cTriggers = m_Triggers.GetCount();
// Write trigger count.
//
if (!WriteFile(hFile, &cTriggers, sizeof(cTriggers), &dwWritten, NULL))
{
hr = HRESULT_FROM_WIN32(GetLastError());
CHECK_HRESULT(hr);
return(hr);
}
if (dwWritten != sizeof(cTriggers))
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
CHECK_HRESULT(hr);
return(hr);
}
// Write trigger data.
//
if (!WriteFile(hFile,
m_Triggers.GetArray(),
cTriggerDataSize = sizeof(TASK_TRIGGER) * cTriggers,
&dwWritten,
NULL))
{
hr = HRESULT_FROM_WIN32(GetLastError());
CHECK_HRESULT(hr);
return(hr);
}
if (dwWritten != cTriggerDataSize)
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
CHECK_HRESULT(hr);
}
return(hr);
}
//+----------------------------------------------------------------------------
//
// Member: CJob::SetTriggersDirty, protected
//
// Synopsis: Sets the triggers-dirty flag and clears the unchanged and
// NetSchedule flags.
//
// Notes: IPersistFile::Save will call UpdateJobState if the trigger-
// dirty flag is set. UpdateJobState updates the job's status
// property.
//-----------------------------------------------------------------------------
void
CJob::SetTriggersDirty(void)
{
//
// The JOB_I_FLAG_TRIGGERS_DIRTY flag indicates the in-core object does
// not match the persistent object. This flag is not saved persistently; it
// is cleared on a Save.
//
SetFlag(JOB_I_FLAG_TRIGGERS_DIRTY);
//
// We set this flag here so that a rebuild will occur due to the possible
// run time changes introduced by the trigger change.
//
SetFlag(JOB_I_FLAG_RUN_PROP_CHANGE);
ClearFlag(JOB_I_FLAG_NO_RUN_PROP_CHANGE);
}
// Class members - *not* part of any interface.
//
//+----------------------------------------------------------------------------
//
// Member: CJob::SetTrigger, public
//
// Synopsis:
//
// Arguments: [] -
//
// Returns:
//
// Notes:
//-----------------------------------------------------------------------------
HRESULT
CJob::SetTrigger(WORD iTrigger, PTASK_TRIGGER pTrigger)
{
TASK_TRIGGER * pjt = this->_GetTrigger(iTrigger);
schAssert(pjt != NULL);
if (pjt == NULL)
{
CHECK_HRESULT(E_FAIL);
return(E_FAIL);
}
//
// Check version. Do not modify triggers created by a later version.
//
// BUGBUG : This doesn't seem quite right.
//
if (pTrigger->cbTriggerSize != sizeof(TASK_TRIGGER))
{
CHECK_HRESULT(E_INVALIDARG);
return(E_INVALIDARG);
}
//
// Data validation.
//
if (pTrigger->wStartHour > JOB_MAX_HOUR ||
pTrigger->wStartMinute > JOB_MAX_MINUTE)
{
return E_INVALIDARG;
}
if (!IsValidDate(pTrigger->wBeginMonth,
pTrigger->wBeginDay,
pTrigger->wBeginYear))
{
return E_INVALIDARG;
}
if (pTrigger->rgFlags & TASK_TRIGGER_FLAG_HAS_END_DATE &&
!IsValidDate(pTrigger->wEndMonth,
pTrigger->wEndDay,
pTrigger->wEndYear))
{
return E_INVALIDARG;
}
//
// If either MinutesDuration or MinutesInterval is nonzero, then
// MinutesInterval must be less than MinutesDuration.
//
if ((pTrigger->MinutesDuration > 0 || pTrigger->MinutesInterval > 0) &&
(pTrigger->MinutesInterval >= pTrigger->MinutesDuration))
{
return E_INVALIDARG;
}
//
// Type consistency validation and value assignment.
//
switch (pTrigger->TriggerType)
{
case TASK_TIME_TRIGGER_DAILY:
if (pTrigger->Type.Daily.DaysInterval == 0)
{
return E_INVALIDARG;
}
pjt->Type.Daily.DaysInterval = pTrigger->Type.Daily.DaysInterval;
break;
case TASK_TIME_TRIGGER_WEEKLY:
if (pTrigger->Type.Weekly.WeeksInterval == 0 ||
pTrigger->Type.Weekly.rgfDaysOfTheWeek == 0 ||
pTrigger->Type.Weekly.rgfDaysOfTheWeek > JOB_RGFDOW_MAX)
{
return E_INVALIDARG;
}
pjt->Type.Weekly.WeeksInterval = pTrigger->Type.Weekly.WeeksInterval;
pjt->Type.Weekly.rgfDaysOfTheWeek =
pTrigger->Type.Weekly.rgfDaysOfTheWeek;
break;
case TASK_TIME_TRIGGER_MONTHLYDATE:
if (!IsValidMonthlyDateTrigger(pTrigger))
{
return E_INVALIDARG;
}
pjt->Type.MonthlyDate.rgfDays = pTrigger->Type.MonthlyDate.rgfDays;
pjt->Type.MonthlyDate.rgfMonths = pTrigger->Type.MonthlyDate.rgfMonths;
break;
case TASK_TIME_TRIGGER_MONTHLYDOW:
if (pTrigger->Type.MonthlyDOW.wWhichWeek < TASK_FIRST_WEEK ||
pTrigger->Type.MonthlyDOW.wWhichWeek > TASK_LAST_WEEK ||
pTrigger->Type.MonthlyDOW.rgfDaysOfTheWeek == 0 ||
pTrigger->Type.MonthlyDOW.rgfDaysOfTheWeek > JOB_RGFDOW_MAX ||
pTrigger->Type.MonthlyDOW.rgfMonths == 0 ||
pTrigger->Type.MonthlyDOW.rgfMonths > JOB_RGFMONTHS_MAX)
{
return E_INVALIDARG;
}
pjt->Type.MonthlyDOW.wWhichWeek = pTrigger->Type.MonthlyDOW.wWhichWeek;
pjt->Type.MonthlyDOW.rgfDaysOfTheWeek =
pTrigger->Type.MonthlyDOW.rgfDaysOfTheWeek;
pjt->Type.MonthlyDOW.rgfMonths = pTrigger->Type.MonthlyDOW.rgfMonths;
break;
case TASK_TIME_TRIGGER_ONCE:
case TASK_EVENT_TRIGGER_ON_IDLE:
case TASK_EVENT_TRIGGER_AT_SYSTEMSTART:
case TASK_EVENT_TRIGGER_AT_LOGON:
// Not yet implemented:
// case TASK_EVENT_TRIGGER_ON_APM_RESUME:
//
// No type-specific data for these.
//
break;
default:
return E_INVALIDARG;
}
pjt->TriggerType = pTrigger->TriggerType;
pjt->cbTriggerSize = pTrigger->cbTriggerSize;
pjt->wBeginYear = pTrigger->wBeginYear;
pjt->wBeginMonth = pTrigger->wBeginMonth;
pjt->wBeginDay = pTrigger->wBeginDay;
pjt->wEndYear = pTrigger->wEndYear;
pjt->wEndMonth = pTrigger->wEndMonth;
pjt->wEndDay = pTrigger->wEndDay;
pjt->wStartHour = pTrigger->wStartHour;
pjt->wStartMinute = pTrigger->wStartMinute;
pjt->MinutesDuration = pTrigger->MinutesDuration;
pjt->MinutesInterval = pTrigger->MinutesInterval;
//
// The upper word of pjt->rgFlags is reserved, so set only the lower
// word and retain the upper word values.
//
pjt->rgFlags &= JOB_INTERNAL_FLAG_MASK;
pjt->rgFlags = pTrigger->rgFlags & ~JOB_INTERNAL_FLAG_MASK;
//
// This call explicitly set the trigger values, so clear the
// JOB_TRIGGER_I_FLAG_NOT_SET bit.
//
pjt->rgFlags &= ~JOB_TRIGGER_I_FLAG_NOT_SET;
this->SetTriggersDirty();
//
// If GetNextRunTime returned SCHED_S_TASK_NO_MORE_RUNS prior to this
// call, then JOB_I_FLAG_NO_MORE_RUNS is set. Clear it and then call
// UpdateJobState to bring the status current.
//
this->ClearFlag(JOB_I_FLAG_NO_MORE_RUNS);
this->UpdateJobState(FALSE);
return S_OK;
}
//+----------------------------------------------------------------------------
//
// Member: CJob::GetTrigger
//
// Synopsis:
//
// Arguments: [] -
//
// Returns: HRESULTS
//
// Notes:
//
//-----------------------------------------------------------------------------
HRESULT
CJob::GetTrigger(WORD iTrigger, PTASK_TRIGGER pTrigger)
{
TASK_TRIGGER * pjt = this->_GetTrigger(iTrigger);
schAssert(pjt != NULL);
if (pjt == NULL)
{
CHECK_HRESULT(E_FAIL);
return(E_FAIL);
}
//
// Do trigger type specific processing.
//
switch (pjt->TriggerType)
{
case TASK_TIME_TRIGGER_DAILY:
pTrigger->Type.Daily.DaysInterval = pjt->Type.Daily.DaysInterval;
break;
case TASK_TIME_TRIGGER_WEEKLY:
pTrigger->Type.Weekly.WeeksInterval = pjt->Type.Weekly.WeeksInterval;
pTrigger->Type.Weekly.rgfDaysOfTheWeek =
pjt->Type.Weekly.rgfDaysOfTheWeek;
break;
case TASK_TIME_TRIGGER_MONTHLYDATE:
pTrigger->Type.MonthlyDate.rgfDays = pjt->Type.MonthlyDate.rgfDays;
pTrigger->Type.MonthlyDate.rgfMonths = pjt->Type.MonthlyDate.rgfMonths;
break;
case TASK_TIME_TRIGGER_MONTHLYDOW:
pTrigger->Type.MonthlyDOW.wWhichWeek = pjt->Type.MonthlyDOW.wWhichWeek;
pTrigger->Type.MonthlyDOW.rgfDaysOfTheWeek =
pjt->Type.MonthlyDOW.rgfDaysOfTheWeek;
pTrigger->Type.MonthlyDOW.rgfMonths = pjt->Type.MonthlyDOW.rgfMonths;
break;
case TASK_TIME_TRIGGER_ONCE:
case TASK_EVENT_TRIGGER_ON_IDLE:
case TASK_EVENT_TRIGGER_AT_SYSTEMSTART:
case TASK_EVENT_TRIGGER_AT_LOGON:
// Not yet implemented:
// case TASK_EVENT_TRIGGER_ON_APM_RESUME:
//
// No trigger-specific data.
//
break;
default:
//
// In future revisions, different trigger types would be handled
// here.
//
return E_INVALIDARG;
}
pTrigger->TriggerType = pjt->TriggerType;
pTrigger->cbTriggerSize = pjt->cbTriggerSize;
pTrigger->wBeginYear = pjt->wBeginYear;
pTrigger->wBeginMonth = pjt->wBeginMonth;
pTrigger->wBeginDay = pjt->wBeginDay;
pTrigger->wEndYear = pjt->wEndYear;
pTrigger->wEndMonth = pjt->wEndMonth;
pTrigger->wEndDay = pjt->wEndDay;
pTrigger->wStartHour = pjt->wStartHour;
pTrigger->wStartMinute = pjt->wStartMinute;
pTrigger->MinutesDuration = pjt->MinutesDuration;
pTrigger->MinutesInterval = pjt->MinutesInterval;
pTrigger->rgFlags = pjt->rgFlags;
pTrigger->Reserved1 = 0;
pTrigger->Reserved2 = pjt->Reserved2;
pTrigger->wRandomMinutesInterval = pjt->wRandomMinutesInterval;
//
// If this trigger has not been set to non-default values, it will have
// the flag bit JOB_TRIGGER_I_FLAG_NOT_SET set. Since this is an internal
// value, replace it with TASK_TRIGGER_FLAG_DISABLED.
//
if (pTrigger->rgFlags & JOB_TRIGGER_I_FLAG_NOT_SET)
{
pTrigger->rgFlags &= ~JOB_INTERNAL_FLAG_MASK;
pTrigger->rgFlags |= TASK_TRIGGER_FLAG_DISABLED;
}
else
{
pTrigger->rgFlags &= ~JOB_INTERNAL_FLAG_MASK;
}
//
// Struct version check.
//
// In future revisions, different trigger structs would be handled
// here.
//
//if (pTrigger->cbTriggerSize != sizeof(TASK_TRIGGER))
//{
// ;
//}
return S_OK;
}
//+----------------------------------------------------------------------------
//
// Member: CJob::SetErrorRetryCount, public
//
// Synopsis: Set the number of times the service should attempt to run a
// job that is failing to start.
//
// Arguments: [wRetryCount] - zero, of course, means don't retry.
//
// Returns: HRESULTS
//
//-----------------------------------------------------------------------------
HRESULT
CJob::SetErrorRetryCount(WORD wRetryCount)
{
//TRACE(CJob, SetErrorRetryCount);
m_wErrorRetryCount = wRetryCount;
//
// Not implemented yet
//
return E_NOTIMPL;
}
//+----------------------------------------------------------------------------
//
// Member: CJob::GetErrorRetryCount, public
//
// Synopsis: Get the number of times the service will attempt to run a
// job that is failing to start.
//
// Arguments: [pwRetryCount] - the retry count.
//
// Returns: HRESULTS
//
//-----------------------------------------------------------------------------
HRESULT
CJob::GetErrorRetryCount(WORD * pwRetryCount)
{
//TRACE(CJob, GetErrorRetryCount);
*pwRetryCount = m_wErrorRetryCount;
//
// Not implemented yet
//
return E_NOTIMPL;
}
//+----------------------------------------------------------------------------
//
// Member: CJob::SetIdleWait, public
//
// Synopsis: Set the time to wait until idle, in minutes. This is the
// amount of time after the last user keyboard or mouse moverment
// until the idle state will be entered for this task.
//
// Arguments: [wIdleMinutes] - the time to wait till idle in minutes.
// [wDeadlineMinutes] - minutes to wait for [wIdleMinutes] of
// idleness
//
// Returns: S_OK
//
// Notes: The task will wait for up to [wDeadlineMinutes] for an idle
// period of [wIdleMinutes] to occur.
//
// If [wDeadlineMinutes] is 0, the task will not run unless the
// computer has been idle for at least [wIdleMinutes] by the
// task's start time.
//
//-----------------------------------------------------------------------------
HRESULT
CJob::SetIdleWait(WORD wIdleMinutes, WORD wDeadlineMinutes)
{
TRACE3(CJob, SetIdleWait);
m_wIdleWait = wIdleMinutes;
m_wIdleDeadline = wDeadlineMinutes;
// Cause a wait list rebuild
SetFlag(JOB_I_FLAG_PROPERTIES_DIRTY | JOB_I_FLAG_RUN_PROP_CHANGE);
return S_OK;
}
//+----------------------------------------------------------------------------
//
// Member: CJob::GetIdleWait, public
//
// Synopsis: Get the idle time requirement and deadline, in minutes.
//
// Arguments: [pwMinutes] - the returned idle time.
// [pwDeadline] - the returned idle deadline
//
// Returns: S_OK
//
//-----------------------------------------------------------------------------
HRESULT
CJob::GetIdleWait(WORD * pwMinutes, WORD * pwDeadline)
{
TRACE3(CJob, GetIdleWait);
*pwMinutes = m_wIdleWait;
*pwDeadline = m_wIdleDeadline;
return S_OK;
}
//+----------------------------------------------------------------------------
//
// Member: CJob::SetErrorRetryInterval, public
//
// Synopsis: Set the interval, in minutes, between successive retries.
//
// Arguments: [wRetryInterval] - the retry interval.
//
// Returns: E_NOTIMPL
//
//-----------------------------------------------------------------------------
HRESULT
CJob::SetErrorRetryInterval(WORD wRetryInterval)
{
//TRACE(CJob, SetErrorRetryInterval);
m_wErrorRetryInterval = wRetryInterval;
//
// Not implemented yet
//
return E_NOTIMPL;
}
//+----------------------------------------------------------------------------
//
// Member: CJob::GetErrorRetryInterval, public
//
// Synopsis: Get the interval, in minutes, between successive retries.
//
// Arguments: [pwRetryInterval] - the returned interval.
//
// Returns: E_NOTIMPL
//
//-----------------------------------------------------------------------------
HRESULT
CJob::GetErrorRetryInterval(WORD * pwRetryInterval)
{
//TRACE(CJob, GetErrorRetryInterval);
*pwRetryInterval = m_wErrorRetryInterval;
//
// Not implemented yet
//
return E_NOTIMPL;
}