Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1106 lines
31 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // Job Scheduler Job Object Handler
  4. //
  5. // Microsoft Windows
  6. // Copyright (C) Microsoft Corporation, 1992 - 1996.
  7. //
  8. // File: jobex.cxx
  9. //
  10. // Contents: ITask interface methods
  11. //
  12. // Classes: CJob
  13. //
  14. // Interfaces: ITask
  15. //
  16. // History: 16-Oct-95 EricB created
  17. // 11-Nov-96 AnirudhS Fixed both GetRunTimes methods to return
  18. // the right success codes.
  19. // 20-Nov-01 ShBrown Switched to use standard NT build versioning
  20. //
  21. //-----------------------------------------------------------------------------
  22. #include "..\pch\headers.hxx"
  23. #pragma hdrstop
  24. #include "job.hxx"
  25. #include "defines.hxx"
  26. #include <ntverp.h>
  27. //
  28. // Increment the following if the job object file format is changed in an incompatible fashion.
  29. //
  30. #define JOB_OBJ_FORMAT_VERSION 1
  31. //+----------------------------------------------------------------------------
  32. //
  33. // Member: CJob::CJob
  34. //
  35. // Synopsis: constructor
  36. //
  37. //-----------------------------------------------------------------------------
  38. CJob::CJob(void) :
  39. m_wVersion(MAKEWORD(VER_PRODUCTMINORVERSION, VER_PRODUCTMAJORVERSION)),
  40. m_wFileObjVer(JOB_OBJ_FORMAT_VERSION),
  41. m_wTriggerOffset(0),
  42. m_wErrorRetryCount(0),
  43. m_wErrorRetryInterval(0),
  44. m_cRunningInstances(0),
  45. m_wIdleWait(SCH_DEFAULT_IDLE_TIME),
  46. m_wIdleDeadline(SCH_DEFAULT_IDLE_DEADLINE),
  47. m_dwPriority(NORMAL_PRIORITY_CLASS),
  48. m_dwMaxRunTime(MAX_RUN_TIME_DEFAULT),
  49. m_ExitCode(0),
  50. m_hrStatus(SCHED_S_TASK_NOT_SCHEDULED),
  51. m_rgFlags(JOB_I_FLAG_NO_RUN_PROP_CHANGE), // The task is not yet dirty
  52. m_rgTaskFlags(0),
  53. m_pwszApplicationName(NULL),
  54. m_pwszParameters(NULL),
  55. m_pwszWorkingDirectory(NULL),
  56. m_pwszCreator(NULL),
  57. m_pwszComment(NULL),
  58. m_cbTaskData(0),
  59. m_pbTaskData(NULL),
  60. m_cReserved(0),
  61. m_pbReserved(NULL),
  62. m_hrStartError(SCHED_S_TASK_HAS_NOT_RUN),
  63. m_pIJobTypeInfo(NULL),
  64. m_cReferences(1),
  65. #if !defined(_CHICAGO_)
  66. m_pAccountInfo(NULL),
  67. m_pbSignature(NULL),
  68. #endif // !defined(_CHICAGO_)
  69. m_ptszFileName(NULL),
  70. m_fFileCreated(FALSE)
  71. {
  72. //TRACE(CJob, CJob);
  73. UUID uuidNull = {0};
  74. m_uuidJob = uuidNull;
  75. SYSTEMTIME stNull = {0};
  76. m_stMostRecentRunTime = stNull;
  77. }
  78. //+----------------------------------------------------------------------------
  79. //
  80. // Member: CJob::~CJob
  81. //
  82. // Synopsis: destructor
  83. //
  84. //-----------------------------------------------------------------------------
  85. CJob::~CJob(void)
  86. {
  87. //TRACE(CJob, ~CJob);
  88. FreeProperties();
  89. if (m_pIJobTypeInfo != NULL)
  90. {
  91. m_pIJobTypeInfo->Release();
  92. }
  93. delete m_ptszFileName;
  94. #if !defined(_CHICAGO_)
  95. if (m_pAccountInfo != NULL)
  96. {
  97. ZERO_PASSWORD(m_pAccountInfo->pwszPassword); // NULL is handled.
  98. delete m_pAccountInfo->pwszAccount;
  99. delete m_pAccountInfo->pwszPassword;
  100. delete m_pAccountInfo;
  101. }
  102. #endif // !defined(_CHICAGO_)
  103. }
  104. //+----------------------------------------------------------------------------
  105. //
  106. // Member: CJob::ITask::GetRunTimes
  107. //
  108. // Synopsis: Return a list of run times for this job that fall between the
  109. // bracketing times inclusively.
  110. //
  111. // Arguments: [pstBegin] - the start of the bracketing period
  112. // [pstEnd] - the end of the bracketing period, may be NULL
  113. // [pCount] - On entry, points to the number of run times
  114. // to retrieve. This must be a number between 1
  115. // and TASK_MAX_RUN_TIMES. On exit, points to
  116. // the number of run times actually retrieved.
  117. // [rgstJobTimes] - the returned array of SYSTEMTIME structures
  118. //
  119. // Returns: S_OK: the requested number of run times are returned.
  120. // S_FALSE: fewer than the requested number of run times are
  121. // returned. (More precisely: the task has valid time-based
  122. // triggers, but the number of run times during the specified
  123. // time bracket is less than the number of run times requested.
  124. // (This includes the case of no event triggers and zero run
  125. // times during that time bracket.))
  126. // SCHED_S_EVENT_TRIGGER: no time-based triggers will cause the
  127. // task to run during the specified time bracket, but event
  128. // triggers may (note that event triggers have no set run
  129. // times). (In this case *pCount is set to 0)
  130. // SCHED_S_TASK_NO_VALID_TRIGGERS: the task is enabled but has no
  131. // valid triggers.
  132. // SCHED_S_TASK_DISABLED: the task is disabled.
  133. // E_INVALIDARG: the arguments are not valid.
  134. // E_OUTOFMEMORY: not enough memory is available.
  135. //
  136. // Notes: The job time list is callee allocated and caller freed. The
  137. // caller must use CoTaskMemFree to free this list.
  138. //-----------------------------------------------------------------------------
  139. STDMETHODIMP
  140. CJob::GetRunTimes(const LPSYSTEMTIME pstBegin, const LPSYSTEMTIME pstEnd,
  141. WORD * pCount, LPSYSTEMTIME * rgstJobTimes)
  142. {
  143. TRACE(CJob, GetRunTimes);
  144. HRESULT hr;
  145. WORD cLimit = *pCount;
  146. if (cLimit < 1 || cLimit > TASK_MAX_RUN_TIMES)
  147. {
  148. return E_INVALIDARG;
  149. }
  150. *rgstJobTimes = NULL;
  151. //
  152. // Get the list of run times.
  153. //
  154. CTimeRunList RunList;
  155. *pCount = 0; // Number of elements in RunList
  156. hr = GetRunTimesP(pstBegin, pstEnd, pCount, cLimit, &RunList, NULL);
  157. if (hr != S_OK)
  158. {
  159. *pCount = 0;
  160. return hr;
  161. }
  162. schAssert(*pCount <= cLimit);
  163. //
  164. // Convert the time list to an array of SYSTEMTIMEs.
  165. //
  166. #if DBG
  167. WORD cCountBefore = *pCount;
  168. #endif
  169. hr = RunList.MakeSysTimeArray(rgstJobTimes, pCount);
  170. if (SUCCEEDED(hr))
  171. {
  172. schAssert(*pCount == cCountBefore);
  173. hr = (*pCount < cLimit) ? S_FALSE : S_OK;
  174. }
  175. return hr;
  176. }
  177. //+----------------------------------------------------------------------------
  178. //
  179. // Member: CJob::GetRunTimesP, private
  180. //
  181. // Synopsis: Computes a set of run times for this job that fall between the
  182. // bracketing times inclusively, and adds them to the run list.
  183. //
  184. // Arguments: [pstBegin] - the start of the bracketing period
  185. // [pstEnd] - the end of the bracketing period, may be NULL
  186. // [pCount] - On both entry and exit, points to the number of
  187. // run times in the list.
  188. // [cLimit] - the maximum number of CRun objects that the list
  189. // may contain.
  190. // [pRunList] - the list of run time objects, can be
  191. // NULL if just checking to see if there will be
  192. // *any* runs. (Note: If it's NULL, duplicate run
  193. // times are not detected, so pCount may be over-
  194. // estimated on return.)
  195. // [ptszShortName] - the folder-relative job name.
  196. //
  197. // Returns: S_OK: Some (zero or more) runs have been added to the list.
  198. // SCHED_S_EVENT_TRIGGER: the job has an event trigger and none
  199. // of the other triggers had runs.
  200. // SCHED_S_TASK_NO_VALID_TRIGGERS: the triggers are disabled or
  201. // not set.
  202. // SCHED_S_TASK_DISABLED: the job is disabled.
  203. //
  204. // Notes: The job time list is callee allocated and caller freed. The
  205. // caller must use FreeList to free this list.
  206. //-----------------------------------------------------------------------------
  207. HRESULT
  208. CJob::GetRunTimesP(const SYSTEMTIME * pstBegin, const SYSTEMTIME * pstEnd,
  209. WORD * pCount, WORD cLimit, CTimeRunList * pRunList,
  210. LPTSTR ptszShortName)
  211. {
  212. HRESULT hr;
  213. schAssert(cLimit > 0); // If cLimit is 0, it's not clear what to return
  214. schAssert(cLimit <= TASK_MAX_RUN_TIMES);
  215. schAssert(*pCount <= cLimit);
  216. //
  217. // Test for conditions that would prevent a run time from being returned.
  218. //
  219. if (IsFlagSet(TASK_FLAG_DISABLED))
  220. {
  221. return SCHED_S_TASK_DISABLED;
  222. }
  223. WORD cTriggers = m_Triggers.GetCount();
  224. //
  225. // Don't need any of the internal job flags for run instance processing.
  226. // That bit space is used for run processing specific flags defined in
  227. // runobj.hxx.
  228. //
  229. DWORD rgFlags = GetUserFlags();
  230. BOOL fEventTriggerFound = FALSE;
  231. BOOL fTimeTriggerFound = FALSE;
  232. //
  233. // Loop over the triggers.
  234. //
  235. for (WORD i = 0; i < cTriggers; i++)
  236. {
  237. hr = ::GetTriggerRunTimes(m_Triggers[i],
  238. pstBegin,
  239. pstEnd,
  240. pCount,
  241. cLimit,
  242. pRunList,
  243. ptszShortName,
  244. rgFlags,
  245. m_dwMaxRunTime,
  246. m_wIdleWait,
  247. m_wIdleDeadline);
  248. if (FAILED(hr))
  249. {
  250. ERR_OUT("CJob::GetRunTimes, ::GetRunTimes", hr);
  251. return(hr);
  252. }
  253. if (hr == SCHED_S_EVENT_TRIGGER)
  254. {
  255. fEventTriggerFound = TRUE;
  256. }
  257. else if (hr == S_OK)
  258. {
  259. fTimeTriggerFound = TRUE;
  260. if (*pCount >= cLimit && pRunList == NULL)
  261. {
  262. //
  263. // Special case where all we want is to test *if* there are runs,
  264. // and don't need the run times. Otherwise, we examine all
  265. // triggers because they won't return run times in any particular
  266. // order.
  267. //
  268. break;
  269. }
  270. }
  271. }
  272. //
  273. // Summarize the results in the return code
  274. //
  275. if (fTimeTriggerFound)
  276. {
  277. if (*pCount == 0 && fEventTriggerFound)
  278. {
  279. hr = SCHED_S_EVENT_TRIGGER;
  280. // (BUGBUG Here, we are assuming that *pCount was 0 initially.
  281. // Maybe add this to the comments and assertions at the start
  282. // of this function. However, this might not be necessary if
  283. // *pCount is made a member of CRunList, as it should be.)
  284. }
  285. else
  286. {
  287. hr = S_OK;
  288. }
  289. }
  290. else if (fEventTriggerFound)
  291. {
  292. hr = SCHED_S_EVENT_TRIGGER;
  293. }
  294. else
  295. {
  296. hr = SCHED_S_TASK_NO_VALID_TRIGGERS;
  297. }
  298. return hr;
  299. }
  300. //+----------------------------------------------------------------------------
  301. //
  302. // Synopsis: Skips past the preceeding data and loads only the triggers
  303. //
  304. // Notes: This method will fail if not preceeded at some time during
  305. // the job object's lifetime by a call to LoadP.
  306. //
  307. //-----------------------------------------------------------------------------
  308. HRESULT
  309. CJob::LoadTriggers(void)
  310. {
  311. // CODEWORK Optimize this to use a single ReadFile, like LoadP().
  312. // Or, get rid of it altogether and just use LoadP, or an additional
  313. // flag to LoadP.
  314. //TRACE(CJob, LoadTriggers);
  315. if (m_ptszFileName == NULL || m_wTriggerOffset == 0)
  316. {
  317. return E_FAIL;
  318. }
  319. HRESULT hr;
  320. //
  321. // Open the file.
  322. //
  323. HANDLE hFile = CreateFile(m_ptszFileName, GENERIC_READ, FILE_SHARE_READ,
  324. NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN,
  325. NULL);
  326. if (hFile == INVALID_HANDLE_VALUE)
  327. {
  328. hr = HRESULT_FROM_WIN32(GetLastError());
  329. ERR_OUT("CJob::Load, file open", hr);
  330. return hr;
  331. }
  332. //
  333. // Move to the trigger data.
  334. //
  335. DWORD dwBytes;
  336. dwBytes = SetFilePointer(hFile, m_wTriggerOffset, NULL, FILE_BEGIN);
  337. if (dwBytes == 0xffffffff)
  338. {
  339. hr = HRESULT_FROM_WIN32(GetLastError());
  340. ERR_OUT("CJob::LoadTriggers, move to trigger data", hr);
  341. goto cleanup;
  342. }
  343. //
  344. // Load triggers.
  345. //
  346. hr = this->_LoadTriggers(hFile);
  347. cleanup:
  348. //
  349. // Close the file.
  350. //
  351. CloseHandle(hFile);
  352. return hr;
  353. }
  354. //+----------------------------------------------------------------------------
  355. //
  356. // Member: CJob::_LoadTriggersFromBuffer, private
  357. //
  358. // Synopsis:
  359. //
  360. // Arguments:
  361. //
  362. // Returns:
  363. //
  364. //-----------------------------------------------------------------------------
  365. HRESULT
  366. CJob::_LoadTriggersFromBuffer(CInputBuffer * pBuf)
  367. {
  368. HRESULT hr = S_OK;
  369. WORD cTriggers;
  370. // Read trigger count.
  371. //
  372. if (!pBuf->Read(&cTriggers, sizeof cTriggers))
  373. {
  374. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  375. CHECK_HRESULT(hr);
  376. return hr;
  377. }
  378. // Verify buffer contains that many triggers.
  379. //
  380. BYTE *pTriggers = pBuf->CurrentPosition(); // save current position
  381. if (!pBuf->Advance(cTriggers * sizeof TASK_TRIGGER))
  382. {
  383. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  384. CHECK_HRESULT(hr);
  385. return hr;
  386. }
  387. // Copy triggers into a properly aligned array.
  388. // CODEWORK: Align them in the original buffer instead of allocating
  389. // a separate one.
  390. //
  391. hr = m_Triggers.AllocAndCopy(cTriggers, pTriggers);
  392. if (FAILED(hr))
  393. {
  394. CHECK_HRESULT(hr);
  395. return hr;
  396. }
  397. if (cTriggers)
  398. {
  399. //
  400. // BUGBUG: temporary, remove the next time the job file format
  401. // is revised.
  402. //
  403. TASK_TRIGGER * ajt = m_Triggers.GetArray();
  404. for (WORD i = 0; i < cTriggers; i++)
  405. {
  406. ajt[i].Reserved1 = i;
  407. }
  408. //
  409. // end of temporary code.
  410. //
  411. this->SetFlag(JOB_I_FLAG_HAS_TRIGGERS);
  412. }
  413. else
  414. {
  415. //
  416. // No triggers - clear trigger flag.
  417. //
  418. this->ClearFlag(JOB_I_FLAG_HAS_TRIGGERS);
  419. }
  420. return S_OK;
  421. }
  422. //+----------------------------------------------------------------------------
  423. //
  424. // Member: CJob::_LoadTriggers, private
  425. //
  426. // Synopsis:
  427. //
  428. // Arguments: None.
  429. //
  430. // Returns:
  431. //
  432. // Notes: None.
  433. //
  434. //-----------------------------------------------------------------------------
  435. HRESULT
  436. CJob::_LoadTriggers(HANDLE hFile)
  437. {
  438. HRESULT hr = S_OK;
  439. DWORD dwRead;
  440. WORD cTriggers;
  441. // Read trigger count.
  442. //
  443. if (!ReadFile(hFile, &cTriggers, sizeof(cTriggers), &dwRead, NULL))
  444. {
  445. hr = HRESULT_FROM_WIN32(GetLastError());
  446. CHECK_HRESULT(hr);
  447. return(hr);
  448. }
  449. if (dwRead != sizeof(cTriggers))
  450. {
  451. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  452. CHECK_HRESULT(hr);
  453. return(hr);
  454. }
  455. // Free existing trigger array.
  456. //
  457. m_Triggers.FreeArray();
  458. // Get on with load.
  459. //
  460. if (cTriggers)
  461. {
  462. TASK_TRIGGER * ajt = (TASK_TRIGGER *)
  463. LocalAlloc(LMEM_FIXED, cTriggers * sizeof TASK_TRIGGER);
  464. if (ajt == NULL)
  465. {
  466. hr = HRESULT_FROM_WIN32(GetLastError());
  467. CHECK_HRESULT(hr);
  468. return hr;
  469. }
  470. if (!ReadFile(hFile, ajt, cTriggers * sizeof TASK_TRIGGER, &dwRead,
  471. NULL))
  472. {
  473. hr = HRESULT_FROM_WIN32(GetLastError());
  474. CHECK_HRESULT(hr);
  475. LocalFree(ajt);
  476. return hr;
  477. }
  478. if (dwRead != cTriggers * sizeof TASK_TRIGGER)
  479. {
  480. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  481. CHECK_HRESULT(hr);
  482. LocalFree(ajt);
  483. return hr;
  484. }
  485. for (WORD i = 0; i < cTriggers; i++)
  486. {
  487. //
  488. // BUGBUG: temporary, remove the next time the job file format
  489. // is revised.
  490. //
  491. ajt[i].Reserved1 = i;
  492. //
  493. // end of temporary code.
  494. //
  495. }
  496. m_Triggers.SetArray(cTriggers, ajt);
  497. this->SetFlag(JOB_I_FLAG_HAS_TRIGGERS);
  498. }
  499. else
  500. {
  501. //
  502. // No triggers - clear trigger flag.
  503. //
  504. this->ClearFlag(JOB_I_FLAG_HAS_TRIGGERS);
  505. }
  506. return(hr);
  507. }
  508. //+----------------------------------------------------------------------------
  509. //
  510. // Member: CJob::_SaveTriggers, private
  511. //
  512. // Synopsis:
  513. //
  514. // Arguments: None.
  515. //
  516. // Returns:
  517. //
  518. // Notes: None.
  519. //
  520. //-----------------------------------------------------------------------------
  521. HRESULT
  522. CJob::_SaveTriggers(HANDLE hFile)
  523. {
  524. HRESULT hr = S_OK;
  525. DWORD dwWritten;
  526. DWORD cTriggerDataSize;
  527. WORD cTriggers = m_Triggers.GetCount();
  528. // Write trigger count.
  529. //
  530. if (!WriteFile(hFile, &cTriggers, sizeof(cTriggers), &dwWritten, NULL))
  531. {
  532. hr = HRESULT_FROM_WIN32(GetLastError());
  533. CHECK_HRESULT(hr);
  534. return(hr);
  535. }
  536. if (dwWritten != sizeof(cTriggers))
  537. {
  538. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  539. CHECK_HRESULT(hr);
  540. return(hr);
  541. }
  542. // Write trigger data.
  543. //
  544. if (!WriteFile(hFile,
  545. m_Triggers.GetArray(),
  546. cTriggerDataSize = sizeof(TASK_TRIGGER) * cTriggers,
  547. &dwWritten,
  548. NULL))
  549. {
  550. hr = HRESULT_FROM_WIN32(GetLastError());
  551. CHECK_HRESULT(hr);
  552. return(hr);
  553. }
  554. if (dwWritten != cTriggerDataSize)
  555. {
  556. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  557. CHECK_HRESULT(hr);
  558. }
  559. return(hr);
  560. }
  561. //+----------------------------------------------------------------------------
  562. //
  563. // Member: CJob::SetTriggersDirty, protected
  564. //
  565. // Synopsis: Sets the triggers-dirty flag and clears the unchanged and
  566. // NetSchedule flags.
  567. //
  568. // Notes: IPersistFile::Save will call UpdateJobState if the trigger-
  569. // dirty flag is set. UpdateJobState updates the job's status
  570. // property.
  571. //-----------------------------------------------------------------------------
  572. void
  573. CJob::SetTriggersDirty(void)
  574. {
  575. //
  576. // The JOB_I_FLAG_TRIGGERS_DIRTY flag indicates the in-core object does
  577. // not match the persistent object. This flag is not saved persistently; it
  578. // is cleared on a Save.
  579. //
  580. SetFlag(JOB_I_FLAG_TRIGGERS_DIRTY);
  581. //
  582. // We set this flag here so that a rebuild will occur due to the possible
  583. // run time changes introduced by the trigger change.
  584. //
  585. SetFlag(JOB_I_FLAG_RUN_PROP_CHANGE);
  586. ClearFlag(JOB_I_FLAG_NO_RUN_PROP_CHANGE);
  587. }
  588. // Class members - *not* part of any interface.
  589. //
  590. //+----------------------------------------------------------------------------
  591. //
  592. // Member: CJob::SetTrigger, public
  593. //
  594. // Synopsis:
  595. //
  596. // Arguments: [] -
  597. //
  598. // Returns:
  599. //
  600. // Notes:
  601. //-----------------------------------------------------------------------------
  602. HRESULT
  603. CJob::SetTrigger(WORD iTrigger, PTASK_TRIGGER pTrigger)
  604. {
  605. TASK_TRIGGER * pjt = this->_GetTrigger(iTrigger);
  606. schAssert(pjt != NULL);
  607. if (pjt == NULL)
  608. {
  609. CHECK_HRESULT(E_FAIL);
  610. return(E_FAIL);
  611. }
  612. //
  613. // Check version. Do not modify triggers created by a later version.
  614. //
  615. // BUGBUG : This doesn't seem quite right.
  616. //
  617. if (pTrigger->cbTriggerSize != sizeof(TASK_TRIGGER))
  618. {
  619. CHECK_HRESULT(E_INVALIDARG);
  620. return(E_INVALIDARG);
  621. }
  622. //
  623. // Data validation.
  624. //
  625. if (pTrigger->wStartHour > JOB_MAX_HOUR ||
  626. pTrigger->wStartMinute > JOB_MAX_MINUTE)
  627. {
  628. return E_INVALIDARG;
  629. }
  630. if (!IsValidDate(pTrigger->wBeginMonth,
  631. pTrigger->wBeginDay,
  632. pTrigger->wBeginYear))
  633. {
  634. return E_INVALIDARG;
  635. }
  636. if (pTrigger->rgFlags & TASK_TRIGGER_FLAG_HAS_END_DATE &&
  637. !IsValidDate(pTrigger->wEndMonth,
  638. pTrigger->wEndDay,
  639. pTrigger->wEndYear))
  640. {
  641. return E_INVALIDARG;
  642. }
  643. //
  644. // If either MinutesDuration or MinutesInterval is nonzero, then
  645. // MinutesInterval must be less than MinutesDuration.
  646. //
  647. if ((pTrigger->MinutesDuration > 0 || pTrigger->MinutesInterval > 0) &&
  648. (pTrigger->MinutesInterval >= pTrigger->MinutesDuration))
  649. {
  650. return E_INVALIDARG;
  651. }
  652. //
  653. // Type consistency validation and value assignment.
  654. //
  655. switch (pTrigger->TriggerType)
  656. {
  657. case TASK_TIME_TRIGGER_DAILY:
  658. if (pTrigger->Type.Daily.DaysInterval == 0)
  659. {
  660. return E_INVALIDARG;
  661. }
  662. pjt->Type.Daily.DaysInterval = pTrigger->Type.Daily.DaysInterval;
  663. break;
  664. case TASK_TIME_TRIGGER_WEEKLY:
  665. if (pTrigger->Type.Weekly.WeeksInterval == 0 ||
  666. pTrigger->Type.Weekly.rgfDaysOfTheWeek == 0 ||
  667. pTrigger->Type.Weekly.rgfDaysOfTheWeek > JOB_RGFDOW_MAX)
  668. {
  669. return E_INVALIDARG;
  670. }
  671. pjt->Type.Weekly.WeeksInterval = pTrigger->Type.Weekly.WeeksInterval;
  672. pjt->Type.Weekly.rgfDaysOfTheWeek =
  673. pTrigger->Type.Weekly.rgfDaysOfTheWeek;
  674. break;
  675. case TASK_TIME_TRIGGER_MONTHLYDATE:
  676. if (!IsValidMonthlyDateTrigger(pTrigger))
  677. {
  678. return E_INVALIDARG;
  679. }
  680. pjt->Type.MonthlyDate.rgfDays = pTrigger->Type.MonthlyDate.rgfDays;
  681. pjt->Type.MonthlyDate.rgfMonths = pTrigger->Type.MonthlyDate.rgfMonths;
  682. break;
  683. case TASK_TIME_TRIGGER_MONTHLYDOW:
  684. if (pTrigger->Type.MonthlyDOW.wWhichWeek < TASK_FIRST_WEEK ||
  685. pTrigger->Type.MonthlyDOW.wWhichWeek > TASK_LAST_WEEK ||
  686. pTrigger->Type.MonthlyDOW.rgfDaysOfTheWeek == 0 ||
  687. pTrigger->Type.MonthlyDOW.rgfDaysOfTheWeek > JOB_RGFDOW_MAX ||
  688. pTrigger->Type.MonthlyDOW.rgfMonths == 0 ||
  689. pTrigger->Type.MonthlyDOW.rgfMonths > JOB_RGFMONTHS_MAX)
  690. {
  691. return E_INVALIDARG;
  692. }
  693. pjt->Type.MonthlyDOW.wWhichWeek = pTrigger->Type.MonthlyDOW.wWhichWeek;
  694. pjt->Type.MonthlyDOW.rgfDaysOfTheWeek =
  695. pTrigger->Type.MonthlyDOW.rgfDaysOfTheWeek;
  696. pjt->Type.MonthlyDOW.rgfMonths = pTrigger->Type.MonthlyDOW.rgfMonths;
  697. break;
  698. case TASK_TIME_TRIGGER_ONCE:
  699. case TASK_EVENT_TRIGGER_ON_IDLE:
  700. case TASK_EVENT_TRIGGER_AT_SYSTEMSTART:
  701. case TASK_EVENT_TRIGGER_AT_LOGON:
  702. // Not yet implemented:
  703. // case TASK_EVENT_TRIGGER_ON_APM_RESUME:
  704. //
  705. // No type-specific data for these.
  706. //
  707. break;
  708. default:
  709. return E_INVALIDARG;
  710. }
  711. pjt->TriggerType = pTrigger->TriggerType;
  712. pjt->cbTriggerSize = pTrigger->cbTriggerSize;
  713. pjt->wBeginYear = pTrigger->wBeginYear;
  714. pjt->wBeginMonth = pTrigger->wBeginMonth;
  715. pjt->wBeginDay = pTrigger->wBeginDay;
  716. pjt->wEndYear = pTrigger->wEndYear;
  717. pjt->wEndMonth = pTrigger->wEndMonth;
  718. pjt->wEndDay = pTrigger->wEndDay;
  719. pjt->wStartHour = pTrigger->wStartHour;
  720. pjt->wStartMinute = pTrigger->wStartMinute;
  721. pjt->MinutesDuration = pTrigger->MinutesDuration;
  722. pjt->MinutesInterval = pTrigger->MinutesInterval;
  723. //
  724. // The upper word of pjt->rgFlags is reserved, so set only the lower
  725. // word and retain the upper word values.
  726. //
  727. pjt->rgFlags &= JOB_INTERNAL_FLAG_MASK;
  728. pjt->rgFlags = pTrigger->rgFlags & ~JOB_INTERNAL_FLAG_MASK;
  729. //
  730. // This call explicitly set the trigger values, so clear the
  731. // JOB_TRIGGER_I_FLAG_NOT_SET bit.
  732. //
  733. pjt->rgFlags &= ~JOB_TRIGGER_I_FLAG_NOT_SET;
  734. this->SetTriggersDirty();
  735. //
  736. // If GetNextRunTime returned SCHED_S_TASK_NO_MORE_RUNS prior to this
  737. // call, then JOB_I_FLAG_NO_MORE_RUNS is set. Clear it and then call
  738. // UpdateJobState to bring the status current.
  739. //
  740. this->ClearFlag(JOB_I_FLAG_NO_MORE_RUNS);
  741. this->UpdateJobState(FALSE);
  742. return S_OK;
  743. }
  744. //+----------------------------------------------------------------------------
  745. //
  746. // Member: CJob::GetTrigger
  747. //
  748. // Synopsis:
  749. //
  750. // Arguments: [] -
  751. //
  752. // Returns: HRESULTS
  753. //
  754. // Notes:
  755. //
  756. //-----------------------------------------------------------------------------
  757. HRESULT
  758. CJob::GetTrigger(WORD iTrigger, PTASK_TRIGGER pTrigger)
  759. {
  760. TASK_TRIGGER * pjt = this->_GetTrigger(iTrigger);
  761. schAssert(pjt != NULL);
  762. if (pjt == NULL)
  763. {
  764. CHECK_HRESULT(E_FAIL);
  765. return(E_FAIL);
  766. }
  767. //
  768. // Do trigger type specific processing.
  769. //
  770. switch (pjt->TriggerType)
  771. {
  772. case TASK_TIME_TRIGGER_DAILY:
  773. pTrigger->Type.Daily.DaysInterval = pjt->Type.Daily.DaysInterval;
  774. break;
  775. case TASK_TIME_TRIGGER_WEEKLY:
  776. pTrigger->Type.Weekly.WeeksInterval = pjt->Type.Weekly.WeeksInterval;
  777. pTrigger->Type.Weekly.rgfDaysOfTheWeek =
  778. pjt->Type.Weekly.rgfDaysOfTheWeek;
  779. break;
  780. case TASK_TIME_TRIGGER_MONTHLYDATE:
  781. pTrigger->Type.MonthlyDate.rgfDays = pjt->Type.MonthlyDate.rgfDays;
  782. pTrigger->Type.MonthlyDate.rgfMonths = pjt->Type.MonthlyDate.rgfMonths;
  783. break;
  784. case TASK_TIME_TRIGGER_MONTHLYDOW:
  785. pTrigger->Type.MonthlyDOW.wWhichWeek = pjt->Type.MonthlyDOW.wWhichWeek;
  786. pTrigger->Type.MonthlyDOW.rgfDaysOfTheWeek =
  787. pjt->Type.MonthlyDOW.rgfDaysOfTheWeek;
  788. pTrigger->Type.MonthlyDOW.rgfMonths = pjt->Type.MonthlyDOW.rgfMonths;
  789. break;
  790. case TASK_TIME_TRIGGER_ONCE:
  791. case TASK_EVENT_TRIGGER_ON_IDLE:
  792. case TASK_EVENT_TRIGGER_AT_SYSTEMSTART:
  793. case TASK_EVENT_TRIGGER_AT_LOGON:
  794. // Not yet implemented:
  795. // case TASK_EVENT_TRIGGER_ON_APM_RESUME:
  796. //
  797. // No trigger-specific data.
  798. //
  799. break;
  800. default:
  801. //
  802. // In future revisions, different trigger types would be handled
  803. // here.
  804. //
  805. return E_INVALIDARG;
  806. }
  807. pTrigger->TriggerType = pjt->TriggerType;
  808. pTrigger->cbTriggerSize = pjt->cbTriggerSize;
  809. pTrigger->wBeginYear = pjt->wBeginYear;
  810. pTrigger->wBeginMonth = pjt->wBeginMonth;
  811. pTrigger->wBeginDay = pjt->wBeginDay;
  812. pTrigger->wEndYear = pjt->wEndYear;
  813. pTrigger->wEndMonth = pjt->wEndMonth;
  814. pTrigger->wEndDay = pjt->wEndDay;
  815. pTrigger->wStartHour = pjt->wStartHour;
  816. pTrigger->wStartMinute = pjt->wStartMinute;
  817. pTrigger->MinutesDuration = pjt->MinutesDuration;
  818. pTrigger->MinutesInterval = pjt->MinutesInterval;
  819. pTrigger->rgFlags = pjt->rgFlags;
  820. pTrigger->Reserved1 = 0;
  821. pTrigger->Reserved2 = pjt->Reserved2;
  822. pTrigger->wRandomMinutesInterval = pjt->wRandomMinutesInterval;
  823. //
  824. // If this trigger has not been set to non-default values, it will have
  825. // the flag bit JOB_TRIGGER_I_FLAG_NOT_SET set. Since this is an internal
  826. // value, replace it with TASK_TRIGGER_FLAG_DISABLED.
  827. //
  828. if (pTrigger->rgFlags & JOB_TRIGGER_I_FLAG_NOT_SET)
  829. {
  830. pTrigger->rgFlags &= ~JOB_INTERNAL_FLAG_MASK;
  831. pTrigger->rgFlags |= TASK_TRIGGER_FLAG_DISABLED;
  832. }
  833. else
  834. {
  835. pTrigger->rgFlags &= ~JOB_INTERNAL_FLAG_MASK;
  836. }
  837. //
  838. // Struct version check.
  839. //
  840. // In future revisions, different trigger structs would be handled
  841. // here.
  842. //
  843. //if (pTrigger->cbTriggerSize != sizeof(TASK_TRIGGER))
  844. //{
  845. // ;
  846. //}
  847. return S_OK;
  848. }
  849. //+----------------------------------------------------------------------------
  850. //
  851. // Member: CJob::SetErrorRetryCount, public
  852. //
  853. // Synopsis: Set the number of times the service should attempt to run a
  854. // job that is failing to start.
  855. //
  856. // Arguments: [wRetryCount] - zero, of course, means don't retry.
  857. //
  858. // Returns: HRESULTS
  859. //
  860. //-----------------------------------------------------------------------------
  861. HRESULT
  862. CJob::SetErrorRetryCount(WORD wRetryCount)
  863. {
  864. //TRACE(CJob, SetErrorRetryCount);
  865. m_wErrorRetryCount = wRetryCount;
  866. //
  867. // Not implemented yet
  868. //
  869. return E_NOTIMPL;
  870. }
  871. //+----------------------------------------------------------------------------
  872. //
  873. // Member: CJob::GetErrorRetryCount, public
  874. //
  875. // Synopsis: Get the number of times the service will attempt to run a
  876. // job that is failing to start.
  877. //
  878. // Arguments: [pwRetryCount] - the retry count.
  879. //
  880. // Returns: HRESULTS
  881. //
  882. //-----------------------------------------------------------------------------
  883. HRESULT
  884. CJob::GetErrorRetryCount(WORD * pwRetryCount)
  885. {
  886. //TRACE(CJob, GetErrorRetryCount);
  887. *pwRetryCount = m_wErrorRetryCount;
  888. //
  889. // Not implemented yet
  890. //
  891. return E_NOTIMPL;
  892. }
  893. //+----------------------------------------------------------------------------
  894. //
  895. // Member: CJob::SetIdleWait, public
  896. //
  897. // Synopsis: Set the time to wait until idle, in minutes. This is the
  898. // amount of time after the last user keyboard or mouse moverment
  899. // until the idle state will be entered for this task.
  900. //
  901. // Arguments: [wIdleMinutes] - the time to wait till idle in minutes.
  902. // [wDeadlineMinutes] - minutes to wait for [wIdleMinutes] of
  903. // idleness
  904. //
  905. // Returns: S_OK
  906. //
  907. // Notes: The task will wait for up to [wDeadlineMinutes] for an idle
  908. // period of [wIdleMinutes] to occur.
  909. //
  910. // If [wDeadlineMinutes] is 0, the task will not run unless the
  911. // computer has been idle for at least [wIdleMinutes] by the
  912. // task's start time.
  913. //
  914. //-----------------------------------------------------------------------------
  915. HRESULT
  916. CJob::SetIdleWait(WORD wIdleMinutes, WORD wDeadlineMinutes)
  917. {
  918. TRACE3(CJob, SetIdleWait);
  919. m_wIdleWait = wIdleMinutes;
  920. m_wIdleDeadline = wDeadlineMinutes;
  921. // Cause a wait list rebuild
  922. SetFlag(JOB_I_FLAG_PROPERTIES_DIRTY | JOB_I_FLAG_RUN_PROP_CHANGE);
  923. return S_OK;
  924. }
  925. //+----------------------------------------------------------------------------
  926. //
  927. // Member: CJob::GetIdleWait, public
  928. //
  929. // Synopsis: Get the idle time requirement and deadline, in minutes.
  930. //
  931. // Arguments: [pwMinutes] - the returned idle time.
  932. // [pwDeadline] - the returned idle deadline
  933. //
  934. // Returns: S_OK
  935. //
  936. //-----------------------------------------------------------------------------
  937. HRESULT
  938. CJob::GetIdleWait(WORD * pwMinutes, WORD * pwDeadline)
  939. {
  940. TRACE3(CJob, GetIdleWait);
  941. *pwMinutes = m_wIdleWait;
  942. *pwDeadline = m_wIdleDeadline;
  943. return S_OK;
  944. }
  945. //+----------------------------------------------------------------------------
  946. //
  947. // Member: CJob::SetErrorRetryInterval, public
  948. //
  949. // Synopsis: Set the interval, in minutes, between successive retries.
  950. //
  951. // Arguments: [wRetryInterval] - the retry interval.
  952. //
  953. // Returns: E_NOTIMPL
  954. //
  955. //-----------------------------------------------------------------------------
  956. HRESULT
  957. CJob::SetErrorRetryInterval(WORD wRetryInterval)
  958. {
  959. //TRACE(CJob, SetErrorRetryInterval);
  960. m_wErrorRetryInterval = wRetryInterval;
  961. //
  962. // Not implemented yet
  963. //
  964. return E_NOTIMPL;
  965. }
  966. //+----------------------------------------------------------------------------
  967. //
  968. // Member: CJob::GetErrorRetryInterval, public
  969. //
  970. // Synopsis: Get the interval, in minutes, between successive retries.
  971. //
  972. // Arguments: [pwRetryInterval] - the returned interval.
  973. //
  974. // Returns: E_NOTIMPL
  975. //
  976. //-----------------------------------------------------------------------------
  977. HRESULT
  978. CJob::GetErrorRetryInterval(WORD * pwRetryInterval)
  979. {
  980. //TRACE(CJob, GetErrorRetryInterval);
  981. *pwRetryInterval = m_wErrorRetryInterval;
  982. //
  983. // Not implemented yet
  984. //
  985. return E_NOTIMPL;
  986. }