|
|
//+----------------------------------------------------------------------------
//
// 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 "misc.hxx"
#include <ntverp.h>
#include <strsafe.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), m_pAccountInfo(NULL), m_pbSignature(NULL), 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 (m_pAccountInfo != NULL) { ZERO_PASSWORD(m_pAccountInfo->pwszPassword); // NULL is handled.
delete m_pAccountInfo->pwszAccount; delete m_pAccountInfo->pwszPassword; delete m_pAccountInfo; } }
//+----------------------------------------------------------------------------
//
// 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) { if (m_ptszFileName == NULL || m_wTriggerOffset == 0) { return E_FAIL; }
//
// Open the file.
//
HANDLE hFile = NULL; HRESULT hr = OpenFileWithRetry(m_ptszFileName, GENERIC_READ, FILE_SHARE_READ, &hFile); if (FAILED(hr)) { ERR_OUT("CJob::LoadTriggers, 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; }
|