Leaked source code of windows server 2003
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.

3485 lines
88 KiB

  1. //____________________________________________________________________________
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1995 - 1996.
  5. //
  6. // File: schedule.cxx
  7. //
  8. // Contents:
  9. //
  10. // Classes:
  11. //
  12. // Functions:
  13. //
  14. // Notes: For the first release of the scheduling agent, all security
  15. // operations are disabled under Win95, even Win95 to NT.
  16. //
  17. // History: 3/4/1996 RaviR Created
  18. // 11/16/00 DGrube removed Win4Assert(m_indexCbxTriggers >= 0);
  19. // since m_indexCbxTriggers is a DWORD (unsigned) causing
  20. // compiler errors.
  21. //
  22. //____________________________________________________________________________
  23. #include "..\pch\headers.hxx"
  24. #pragma hdrstop
  25. #include <mstask.h>
  26. #include <winuserp.h>
  27. #include "..\folderui\dbg.h"
  28. #include "..\folderui\macros.h"
  29. #include "..\folderui\jobicons.hxx"
  30. #include "..\folderui\util.hxx"
  31. #include "..\inc\resource.h"
  32. #include "..\inc\network.hxx"
  33. #include "..\inc\dll.hxx"
  34. #include "dlg.hxx"
  35. #include "rc.h"
  36. #include "defines.h"
  37. #include <mstask.h>
  38. #include "misc.hxx"
  39. #include "uiutil.hxx"
  40. #include "strings.hxx"
  41. #include "cdlist.hxx"
  42. #include "helpids.h"
  43. #include "iconhlpr.hxx"
  44. #include "schedui.hxx"
  45. #include "selmonth.hxx"
  46. #include "defines.hxx"
  47. #include <StrSafe.h>
  48. BOOL
  49. IsValidMonthlyDateTrigger(
  50. PTASK_TRIGGER pTrigger);
  51. typedef const unsigned char *LPCBYTE;
  52. //#undef DEB_TRACE
  53. //#define DEB_TRACE DEB_USER1
  54. //
  55. // (Control id, help id) list for context sensitivity help.
  56. //
  57. ULONG s_aSchedulePageHelpIds[] =
  58. {
  59. // Helpids for Schedule page controls (common to all triggers)
  60. idc_icon, Hidc_icon,
  61. cbx_trigger_type, Hcbx_trigger_type,
  62. dp_start_time, Hdp_start_time,
  63. cbx_triggers, Hcbx_triggers,
  64. txt_trigger, Htxt_trigger,
  65. btn_new, Hbtn_new,
  66. btn_delete, Hbtn_delete,
  67. btn_advanced, Hbtn_advanced,
  68. grp_schedule, Hgrp_schedule,
  69. chk_show_multiple_scheds, Hchk_show_multiple_scheds,
  70. // Helpids for Schedule page controls for DAILY trigger
  71. grp_daily, Hgrp_daily,
  72. daily_lbl_every, Hdaily_lbl_every,
  73. daily_txt_every, Hdaily_txt_every,
  74. daily_spin_every, Hdaily_spin_every,
  75. daily_lbl_days, Hdaily_lbl_days,
  76. // Helpids for Schedule page controls for WEEKLY trigger
  77. grp_weekly, Hgrp_weekly,
  78. weekly_lbl_every, Hweekly_lbl_every,
  79. weekly_txt_every, Hweekly_txt_every,
  80. weekly_spin_every, Hweekly_spin_every,
  81. weekly_lbl_weeks_on, Hweekly_lbl_weeks_on,
  82. chk_mon, Hchk_mon,
  83. chk_tue, Hchk_tue,
  84. chk_wed, Hchk_wed,
  85. chk_thu, Hchk_thu,
  86. chk_fri, Hchk_fri,
  87. chk_sat, Hchk_sat,
  88. chk_sun, Hchk_sun,
  89. // Helpids for Schedule page controls for MONTHLY trigger
  90. grp_monthly, Hgrp_monthly,
  91. md_rb, Hmd_rb,
  92. md_txt, Hmd_txt,
  93. md_spin, Hmd_spin,
  94. md_lbl, Hmd_lbl,
  95. dow_rb, Hdow_rb,
  96. dow_cbx_week, Hdow_cbx_week,
  97. dow_cbx_day, Hdow_cbx_day,
  98. dow_lbl, Hdow_lbl,
  99. btn_sel_months, Hbtn_sel_months,
  100. // Helpids for Schedule page controls for ONCE only trigger
  101. grp_once, Hgrp_once,
  102. once_lbl_run_on, Honce_lbl_run_on,
  103. once_dp_date, Honce_dp_date,
  104. // Helpids for Schedule page controls for WhenIdle trigger
  105. grp_idle, Hgrp_idle,
  106. sch_txt_idle_min, Hsch_txt_idle_min,
  107. idle_lbl_when, Hidle_lbl_when,
  108. sch_spin_idle_min, Hsch_spin_idle_min,
  109. idle_lbl_mins, Hidle_lbl_mins,
  110. 0,0
  111. };
  112. //
  113. // Local constants
  114. //
  115. // DEFAULT_TIME_FORMAT - what to use if there's a problem getting format
  116. // from system.
  117. //
  118. #define DEFAULT_TIME_FORMAT TEXT("hh:mm tt")
  119. //
  120. // extern
  121. //
  122. extern "C" TCHAR szMstaskHelp[];
  123. extern HINSTANCE g_hInstance;
  124. //+----------------------------------------------------------------------
  125. //
  126. // Class: CJobTrigger
  127. //
  128. // Purpose: TASK_TRIGGER structure encapsulated with double link node.
  129. //
  130. //----------------------------------------------------------------------
  131. class CJobTrigger : public CDLink
  132. {
  133. public:
  134. CJobTrigger(TASK_TRIGGER &jt) : m_jt(jt) {}
  135. virtual ~CJobTrigger() {}
  136. LPTSTR TriggerString(BOOL fPrependID, TCHAR tcBuff[], size_t bufSize);
  137. WORD GetTriggerID(void) { return (m_jt.Reserved1 & 0x7fff); }
  138. void SetTriggerID(WORD wID)
  139. { m_jt.Reserved1 = (m_jt.Reserved1 & 0x8000) | wID; }
  140. void DirtyTrigger() { m_jt.Reserved1 |= 0x8000; }
  141. BOOL IsTriggerDirty() { return (m_jt.Reserved1 & 0x8000) ? TRUE : FALSE; }
  142. CJobTrigger *Prev() { return (CJobTrigger*) CDLink::Prev(); }
  143. CJobTrigger *Next() { return (CJobTrigger*) CDLink::Next(); }
  144. TASK_TRIGGER m_jt;
  145. };
  146. //+----------------------------------------------------------------------
  147. //
  148. // Class: CJobTriggerList
  149. //
  150. // Purpose: A double linked list of CJobTriggers
  151. //
  152. //----------------------------------------------------------------------
  153. DECLARE_DOUBLE_LINK_LIST_CLASS(CJobTrigger)
  154. LPTSTR
  155. CJobTrigger::TriggerString(
  156. BOOL fPrependID,
  157. TCHAR tcBuff[],
  158. size_t bufSize)
  159. {
  160. LPWSTR pwsz = NULL;
  161. HRESULT hr = StringFromTrigger((const PTASK_TRIGGER)&m_jt, &pwsz, NULL);
  162. CHECK_HRESULT(hr);
  163. tcBuff[0] = TEXT('\0');
  164. if (SUCCEEDED(hr))
  165. {
  166. if (fPrependID == TRUE)
  167. {
  168. StringCchPrintf(tcBuff, bufSize, TEXT("%d. "), (this->GetTriggerID() + 1));
  169. }
  170. StringCchCat(tcBuff, bufSize, pwsz);
  171. CoTaskMemFree(pwsz);
  172. }
  173. return tcBuff;
  174. }
  175. //____________________________________________________________________________
  176. //____________________________________________________________________________
  177. //________________ ______________________________________
  178. //________________ class CSchedulePage ______________________________________
  179. //________________ ______________________________________
  180. //____________________________________________________________________________
  181. //____________________________________________________________________________
  182. class CSchedulePage : public CPropPage
  183. {
  184. public:
  185. CSchedulePage(ITask * pIJob,
  186. LPTSTR ptszTaskPath,
  187. BOOL fMultipleTriggers,
  188. BOOL fPersistChanges);
  189. ~CSchedulePage();
  190. private:
  191. enum
  192. {
  193. IDT_UPDATE_TRIGGER_STRING = 1
  194. };
  195. virtual LRESULT _OnInitDialog(LPARAM lParam);
  196. virtual LRESULT _OnCommand(int id, HWND hwndCtl, UINT codeNotify);
  197. virtual LRESULT _OnApply(void);
  198. virtual LRESULT _OnPSMQuerySibling(WPARAM wParam, LPARAM lParam);
  199. virtual LRESULT _OnDestroy(void);
  200. virtual LRESULT _OnTimer(UINT idTimer);
  201. virtual LRESULT _OnSpinDeltaPos(NM_UPDOWN * pnmud);
  202. virtual LRESULT _OnWinIniChange(WPARAM wParam, LPARAM lParam);
  203. virtual LRESULT _OnPSNSetActive(LPARAM lParam);
  204. virtual LRESULT _OnPSNKillActive(LPARAM lParam);
  205. virtual LRESULT _OnDateTimeChange(LPARAM lParam);
  206. virtual LRESULT _OnHelp(HANDLE hRequesting, UINT uiHelpCommand);
  207. void _ShowControls(int index, int nCmdShow);
  208. void _UpdateTriggerString(void);
  209. HRESULT _LoadTriggers(void);
  210. BOOL _LoadTriggerStrings(void);
  211. BOOL _InitPage(void);
  212. BOOL _RefreshPage(void);
  213. void _UpdateDailyControls(void);
  214. void _UpdateWeeklyControls(void);
  215. void _UpdateMonthlyControls(void);
  216. void _CheckMonthlyRadio(TASK_TRIGGER_TYPE TriggerType);
  217. void _UpdateOnceOnlyControls(void);
  218. void _UpdateIdleControls(void);
  219. WORD _GetDayFromRgfDays(DWORD rgfDays);
  220. int _GetTriggerTypeIndex(void);
  221. void _DisplayControls(int indexTrigger);
  222. void _EnableTimeTriggerSpecificCtrls(BOOL fEnable);
  223. void _SaveTriggerSettings(void);
  224. void _ShowTriggerStringDispCtrls(void);
  225. void _CreateTimerToUpdateTriggerStr(void);
  226. void _DeleteTimerToUpdateTriggerStr(void);
  227. void _ErrorDialog(int idsErr, LONG error = 0, UINT idsHelpHint = 0)
  228. { SchedUIErrorDialog(Hwnd(), idsErr, error, idsHelpHint); }
  229. BOOL _PerformSanityChkOnCurrTrigger(void);
  230. void _EnableApplyButton(void);
  231. void _DisableUI(void);
  232. ITask * m_pIJob;
  233. //
  234. // icon helper
  235. //
  236. CIconHelper * m_pIconHelper;
  237. //
  238. // The list of triggers
  239. //
  240. CJobTriggerList m_cjtList;
  241. //
  242. // The list of triggers deleted
  243. //
  244. CJobTriggerList m_cjtDeletedList;
  245. //
  246. // The trigger for which the schedule is being displayed currently
  247. //
  248. CJobTrigger * m_pcjtCurr;
  249. //
  250. // The count of triggers at load time
  251. //
  252. WORD m_cTriggersPrev;
  253. //
  254. // The id to be assigned to the next trigger, when the user pushes
  255. // the 'New' button for a multiple triggers schedule.
  256. //
  257. WORD m_wNextTriggerId;
  258. //
  259. // The current selection for the trigger type combo box.
  260. //
  261. int m_indexCbxTriggerType;
  262. //
  263. // The timer id of the timer used for trigger string update.
  264. //
  265. UINT_PTR m_idTimer;
  266. //
  267. // The current selection for the trigger strings combo box.
  268. //
  269. UINT m_indexCbxTriggers;
  270. //
  271. // Used by Set/KillActive
  272. //
  273. BOOL m_fShowingMultiSchedsOnKillActive;
  274. BOOL m_fShowMultiScheds;
  275. //
  276. // Should we save on Apply or OK.
  277. //
  278. BOOL m_fPersistChanges;
  279. //
  280. // Is this an AT job?
  281. //
  282. BOOL m_fNetScheduleJob;
  283. //
  284. // Time format string for use with Date picker control
  285. //
  286. TCHAR m_tszTimeFormat[MAX_DP_TIME_FORMAT];
  287. //
  288. // Selected months dialog
  289. //
  290. CSelectMonth _SelectMonths;
  291. //
  292. // If one of the trigger comboboxes is dropped down, contains the
  293. // index of the item selected when the user dropped down the list.
  294. // Otherwise, contains -1.
  295. //
  296. // CAUTION: The _OnTimer method looks at this variable to determine
  297. // whether it is safe to ask the trigger controls for their values
  298. // and update the trigger string and settings. If it has anything
  299. // other than -1, one of the comboboxes may not have a valid
  300. // selection.
  301. //
  302. static int s_iCbx;
  303. }; // class CSchedulePage
  304. //
  305. // CSchedulePage static. Although it's possible multiple instances
  306. // of the schedule page are running, only one can have the focus, therefore
  307. // only one can be using s_iCbx at a time.
  308. //
  309. int CSchedulePage::s_iCbx = -1;
  310. inline
  311. CSchedulePage::CSchedulePage(
  312. ITask * pIJob,
  313. LPTSTR ptszTaskPath,
  314. BOOL fMultipleTriggers,
  315. BOOL fPersistChanges)
  316. :
  317. m_pIJob(pIJob),
  318. m_pIconHelper(NULL),
  319. m_fShowMultiScheds(fMultipleTriggers),
  320. m_fPersistChanges(fPersistChanges),
  321. m_fNetScheduleJob(FALSE),
  322. m_cjtList(),
  323. m_cjtDeletedList(),
  324. m_pcjtCurr(NULL),
  325. m_cTriggersPrev(0),
  326. m_wNextTriggerId(0),
  327. m_indexCbxTriggerType(-1),
  328. m_indexCbxTriggers(0),
  329. m_idTimer(0),
  330. CPropPage(MAKEINTRESOURCE(schedule_page), ptszTaskPath)
  331. {
  332. TRACE(CSchedulePage, CSchedulePage);
  333. Win4Assert(m_pIJob != NULL);
  334. m_pIJob->AddRef();
  335. m_fShowingMultiSchedsOnKillActive = m_fShowMultiScheds;
  336. }
  337. inline
  338. CSchedulePage::~CSchedulePage()
  339. {
  340. TRACE(CSchedulePage, ~CSchedulePage);
  341. if (m_pIconHelper != NULL)
  342. {
  343. m_pIconHelper->Release();
  344. }
  345. if (m_pIJob != NULL)
  346. {
  347. m_pIJob->Release();
  348. }
  349. }
  350. LRESULT
  351. CSchedulePage::_OnHelp(
  352. HANDLE hRequesting,
  353. UINT uiHelpCommand)
  354. {
  355. WinHelp((HWND)hRequesting,
  356. szMstaskHelp,
  357. uiHelpCommand,
  358. (DWORD_PTR)(LPSTR)s_aSchedulePageHelpIds);
  359. return TRUE;
  360. }
  361. void
  362. CSchedulePage::_EnableApplyButton(void)
  363. {
  364. if (m_pcjtCurr)
  365. {
  366. m_pcjtCurr->DirtyTrigger();
  367. }
  368. CPropPage::_EnableApplyButton();
  369. }
  370. inline
  371. void
  372. CSchedulePage::_CreateTimerToUpdateTriggerStr(void)
  373. {
  374. if (m_idTimer == 0)
  375. {
  376. m_idTimer = SetTimer(Hwnd(), IDT_UPDATE_TRIGGER_STRING, 1500, NULL);
  377. DEBUG_OUT((DEB_USER12, "Created timer (%d)\n", m_idTimer));
  378. }
  379. }
  380. inline
  381. void
  382. CSchedulePage::_DeleteTimerToUpdateTriggerStr(void)
  383. {
  384. if (m_idTimer != 0)
  385. {
  386. KillTimer(Hwnd(), IDT_UPDATE_TRIGGER_STRING);
  387. m_idTimer = 0;
  388. }
  389. }
  390. void
  391. CSchedulePage::_EnableTimeTriggerSpecificCtrls(BOOL fEnable)
  392. {
  393. HWND hwnd;
  394. if (fEnable == TRUE)
  395. {
  396. if (hwnd = _hCtrl(dp_start_time)) DateTime_SetFormat(hwnd, m_tszTimeFormat);
  397. }
  398. else
  399. {
  400. if (hwnd = _hCtrl(dp_start_time)) DateTime_SetFormat(hwnd, tszBlank);
  401. }
  402. if (hwnd = _hCtrl(dp_start_time)) EnableWindow(hwnd, fEnable);
  403. if (hwnd = _hCtrl(btn_advanced)) EnableWindow(hwnd, fEnable);
  404. }
  405. int aCtrlsDaily[] = {
  406. grp_daily,
  407. daily_lbl_every, daily_txt_every, daily_spin_every,
  408. daily_lbl_days
  409. };
  410. int aCtrlsWeekly[] = {
  411. grp_weekly,
  412. weekly_lbl_every, weekly_txt_every, weekly_spin_every,
  413. weekly_lbl_weeks_on,
  414. chk_mon, chk_tue, chk_wed, chk_thu, chk_fri, chk_sat, chk_sun
  415. };
  416. int aCtrlsMonthly[] = {
  417. grp_monthly,
  418. md_rb, md_txt, md_spin, md_lbl, // md => monthly date
  419. dow_rb, dow_cbx_week, dow_cbx_day, dow_lbl, // dow => day of week
  420. btn_sel_months
  421. };
  422. int aCtrlsOnce[] = {
  423. grp_once,
  424. once_lbl_run_on, once_dp_date
  425. };
  426. int aCtrlsIdle[] = {
  427. grp_idle,
  428. idle_lbl_when,
  429. sch_txt_idle_min, sch_spin_idle_min,
  430. idle_lbl_mins
  431. };
  432. typedef struct _STriggerTypeData
  433. {
  434. int ids;
  435. int * pCtrls;
  436. int cCtrls;
  437. } STriggerTypeData;
  438. STriggerTypeData ttd[] = {
  439. {IDS_DAILY, aCtrlsDaily, ARRAYLEN(aCtrlsDaily)},
  440. {IDS_WEEKLY, aCtrlsWeekly, ARRAYLEN(aCtrlsWeekly)},
  441. {IDS_MONTHLY, aCtrlsMonthly, ARRAYLEN(aCtrlsMonthly)},
  442. {IDS_ONCE, aCtrlsOnce, ARRAYLEN(aCtrlsOnce)},
  443. {IDS_AT_STARTUP, NULL, 0},
  444. {IDS_AT_LOGON, NULL, 0},
  445. {IDS_WHEN_IDLE, aCtrlsIdle, ARRAYLEN(aCtrlsIdle)}
  446. };
  447. const int INDEX_DAILY = 0;
  448. const int INDEX_WEEKLY = 1;
  449. const int INDEX_MONTHLY = 2;
  450. const int INDEX_ONCE = 3;
  451. const int INDEX_STARTUP = 4;
  452. const int INDEX_LOGON = 5;
  453. const int INDEX_IDLE = 6;
  454. inline
  455. void
  456. CSchedulePage::_ShowControls(
  457. int index,
  458. int nCmdShow)
  459. {
  460. int cCtrls = ttd[index].cCtrls;
  461. for (int i=0; i < cCtrls; i++)
  462. {
  463. ShowWindow(GetDlgItem(Hwnd(), ttd[index].pCtrls[i]), nCmdShow);
  464. }
  465. }
  466. SWeekData g_aWeekData[] =
  467. {
  468. {IDS_FIRST, TASK_FIRST_WEEK},
  469. {IDS_SECOND, TASK_SECOND_WEEK},
  470. {IDS_THIRD, TASK_THIRD_WEEK},
  471. {IDS_FORTH, TASK_FOURTH_WEEK},
  472. {IDS_LAST, TASK_LAST_WEEK}
  473. };
  474. SDayData g_aDayData[] =
  475. {
  476. {chk_mon, IDS_MONDAY, TASK_MONDAY},
  477. {chk_tue, IDS_TUESDAY, TASK_TUESDAY},
  478. {chk_wed, IDS_WEDNESDAY, TASK_WEDNESDAY},
  479. {chk_thu, IDS_THURSDAY, TASK_THURSDAY},
  480. {chk_fri, IDS_FRIDAY, TASK_FRIDAY},
  481. {chk_sat, IDS_SATURDAY, TASK_SATURDAY},
  482. {chk_sun, IDS_SUNDAY, TASK_SUNDAY}
  483. };
  484. void
  485. CSchedulePage::_ShowTriggerStringDispCtrls(void)
  486. {
  487. TRACE(CSchedulePage, _ShowTriggerStringDispCtrls);
  488. HWND hwnd;
  489. if (m_fShowMultiScheds == TRUE)
  490. {
  491. if (hwnd = _hCtrl(txt_trigger)) ShowWindow(hwnd, SW_HIDE);
  492. if (hwnd = _hCtrl(idc_icon)) ShowWindow(hwnd, SW_HIDE);
  493. if (hwnd = _hCtrl(cbx_triggers)) ShowWindow(hwnd, SW_SHOWNA);
  494. if (hwnd = _hCtrl(btn_new)) ShowWindow(hwnd, SW_SHOWNA);
  495. if (hwnd = _hCtrl(btn_delete)) ShowWindow(hwnd, SW_SHOWNA);
  496. if (hwnd = _hCtrl(btn_new)) EnableWindow(hwnd, TRUE);
  497. // Handle the case where you open the page for the first time
  498. // and there is not a trigger on the job.
  499. if (hwnd = _hCtrl(btn_delete)) EnableWindow(hwnd, (m_pcjtCurr) ? TRUE : FALSE);
  500. }
  501. else
  502. {
  503. if (hwnd = _hCtrl(cbx_triggers)) ShowWindow(hwnd, SW_HIDE);
  504. if (hwnd = _hCtrl(btn_new)) ShowWindow(hwnd, SW_HIDE);
  505. if (hwnd = _hCtrl(btn_delete)) ShowWindow(hwnd, SW_HIDE);
  506. if (hwnd = _hCtrl(txt_trigger)) ShowWindow(hwnd, SW_SHOWNA);
  507. if (hwnd = _hCtrl(idc_icon)) ShowWindow(hwnd, SW_SHOWNA);
  508. if (hwnd = _hCtrl(btn_new)) EnableWindow(hwnd, FALSE);
  509. if (hwnd = _hCtrl(btn_delete)) EnableWindow(hwnd, FALSE);
  510. }
  511. }
  512. //+--------------------------------------------------------------------------
  513. //
  514. // Function: MoveControlGroup
  515. //
  516. // Synopsis: Move the controls with ids in [aidControls] left by
  517. // [xOffset] pixels.
  518. //
  519. // Arguments: [hdlg] - window handle of dialog containing controls
  520. // [aidControls] - array of ids of controls to move
  521. // [cControls] - number of elements in array
  522. // [xOffset] - distance, in pixels, to move controls left
  523. //
  524. // History: 08-01-1997 DavidMun Created
  525. //
  526. //---------------------------------------------------------------------------
  527. VOID
  528. MoveControlGroup(
  529. HWND hdlg,
  530. int aidControls[],
  531. ULONG cControls,
  532. long xOffset)
  533. {
  534. ULONG i;
  535. BOOL fOk;
  536. for (i = 0; i < cControls; i++)
  537. {
  538. HWND hwnd = GetDlgItem(hdlg, aidControls[i]);
  539. Win4Assert(hwnd);
  540. RECT rc;
  541. BOOL fOk = GetWindowRect(hwnd, &rc);
  542. Win4Assert(fOk);
  543. fOk = MapWindowPoints(NULL, hdlg, (LPPOINT) &rc, 2);
  544. Win4Assert(fOk);
  545. fOk = SetWindowPos(hwnd,
  546. NULL,
  547. rc.left - xOffset,
  548. rc.top,
  549. 0,
  550. 0,
  551. SWP_NOACTIVATE |
  552. SWP_NOCOPYBITS |
  553. SWP_NOOWNERZORDER |
  554. SWP_NOREDRAW |
  555. SWP_NOSENDCHANGING |
  556. SWP_NOSIZE |
  557. SWP_NOZORDER);
  558. Win4Assert(fOk);
  559. }
  560. }
  561. #define TRIGGER_OFFSET 250
  562. LRESULT
  563. CSchedulePage::_OnInitDialog(
  564. LPARAM lParam)
  565. {
  566. TRACE(CSchedulePage, _OnInitDialog);
  567. HRESULT hr = S_OK;
  568. do
  569. {
  570. //
  571. // Move the trigger settings for weekly, monthly, once, and idle over
  572. // to the left. Each is offset by a multiple of TRIGGER_OFFSET DLUs.
  573. // this is done because the dialog template maps out the various
  574. // control groups side-by-side to make editing easier
  575. // however, they must be moved into the dialog box so the user can see them!
  576. //
  577. /***************************
  578. This "should" work - but is having troubles on some localized builds
  579. we'll measure rather than calculate....
  580. RECT rc = { 0, 0, TRIGGER_OFFSET - 1, 1 };
  581. BOOL fOk = MapDialogRect(Hwnd(), &rc);
  582. Win4Assert(fOk);
  583. long xOffset = rc.right;
  584. MoveControlGroup(Hwnd(), aCtrlsWeekly, ARRAYLEN(aCtrlsWeekly), 1 * xOffset);
  585. MoveControlGroup(Hwnd(), aCtrlsMonthly, ARRAYLEN(aCtrlsMonthly), 2 * xOffset);
  586. MoveControlGroup(Hwnd(), aCtrlsOnce, ARRAYLEN(aCtrlsOnce), 3 * xOffset);
  587. MoveControlGroup(Hwnd(), aCtrlsIdle, ARRAYLEN(aCtrlsIdle), 4 * xOffset);
  588. **********************************/
  589. // determine coordinates of the 'default' groupbox (Daily)
  590. // then, for each of the control groups, calc the proper offset.
  591. // and move controls accordingly
  592. RECT defaultRect, controlRect;
  593. GetWindowRect(GetDlgItem(Hwnd(), grp_daily), &defaultRect);
  594. GetWindowRect(GetDlgItem(Hwnd(), grp_weekly), &controlRect);
  595. long xOffset = abs(controlRect.left - defaultRect.left);
  596. MoveControlGroup(Hwnd(), aCtrlsWeekly, ARRAYLEN(aCtrlsWeekly), xOffset);
  597. GetWindowRect(GetDlgItem(Hwnd(), grp_monthly), &controlRect);
  598. xOffset = abs(controlRect.left - defaultRect.left);
  599. MoveControlGroup(Hwnd(), aCtrlsMonthly, ARRAYLEN(aCtrlsMonthly), xOffset);
  600. GetWindowRect(GetDlgItem(Hwnd(), grp_once), &controlRect);
  601. xOffset = abs(controlRect.left - defaultRect.left);
  602. MoveControlGroup(Hwnd(), aCtrlsOnce, ARRAYLEN(aCtrlsOnce), xOffset);
  603. GetWindowRect(GetDlgItem(Hwnd(), grp_idle), &controlRect);
  604. xOffset = abs(controlRect.left - defaultRect.left);
  605. MoveControlGroup(Hwnd(), aCtrlsIdle, ARRAYLEN(aCtrlsIdle), xOffset);
  606. //
  607. // Initialize time format string m_tszTimeFormat
  608. //
  609. UpdateTimeFormat(m_tszTimeFormat, ARRAYLEN(m_tszTimeFormat));
  610. //
  611. // Get job flags
  612. //
  613. DWORD dwFlags;
  614. hr = m_pIJob->GetFlags(&dwFlags);
  615. m_fNetScheduleJob = dwFlags & JOB_I_FLAG_NET_SCHEDULE;
  616. //
  617. // See if the general page has already created the icon,
  618. // helper, if not create it here.
  619. //
  620. m_pIconHelper = (CIconHelper *)PropSheet_QuerySiblings(
  621. GetParent(Hwnd()), GET_ICON_HELPER, 0);
  622. if (m_pIconHelper == NULL)
  623. {
  624. m_pIconHelper = new CIconHelper();
  625. if (m_pIconHelper == NULL)
  626. {
  627. hr = E_OUTOFMEMORY;
  628. CHECK_HRESULT(hr);
  629. break;
  630. }
  631. //
  632. // Get the application name and set the application icon.
  633. //
  634. LPWSTR pwszAppName = NULL;
  635. hr = m_pIJob->GetApplicationName(&pwszAppName);
  636. CHECK_HRESULT(hr);
  637. BREAK_ON_FAIL(hr);
  638. m_pIconHelper->SetAppIcon(pwszAppName);
  639. CoTaskMemFree(pwszAppName);
  640. //
  641. // Compute the job icon
  642. //
  643. BOOL fEnabled = FALSE;
  644. if (this->IsTaskInTasksFolder())
  645. {
  646. fEnabled = (dwFlags & TASK_FLAG_DISABLED) ? FALSE : TRUE;
  647. }
  648. m_pIconHelper->SetJobIcon(fEnabled);
  649. }
  650. else
  651. {
  652. m_pIconHelper->AddRef();
  653. }
  654. hr = _LoadTriggers();
  655. CHECK_HRESULT(hr);
  656. BREAK_ON_FAIL(hr);
  657. _InitPage();
  658. _RefreshPage();
  659. m_fDirty = FALSE;
  660. } while (0);
  661. //
  662. // Disable all controls if this is an AT job
  663. // to prevent user from making changes
  664. //
  665. if (m_fNetScheduleJob)
  666. _DisableUI();
  667. if (FAILED(hr))
  668. {
  669. if (hr == E_OUTOFMEMORY)
  670. {
  671. _ErrorDialog(IERR_OUT_OF_MEMORY);
  672. }
  673. else
  674. {
  675. _ErrorDialog(IERR_SCHEDULE_PAGE_INIT, hr);
  676. }
  677. EnableWindow(Hwnd(), FALSE);
  678. return FALSE;
  679. }
  680. return TRUE;
  681. }
  682. //+--------------------------------------------------------------------------
  683. //
  684. // Member: CSchedulePage::_DisableUI
  685. //
  686. // Synopsis: Disable UI so the user can only view the settings
  687. //
  688. // History: 2001-11-13 ShBrown Created
  689. //
  690. //---------------------------------------------------------------------------
  691. void
  692. CSchedulePage::_DisableUI(void)
  693. {
  694. HWND hwnd;
  695. if (hwnd = _hCtrl(cbx_triggers)) EnableWindow(hwnd, FALSE);
  696. if (hwnd = _hCtrl(cbx_trigger_type)) EnableWindow(hwnd, FALSE);
  697. if (hwnd = _hCtrl(dp_start_time)) EnableWindow(hwnd, FALSE);
  698. if (hwnd = _hCtrl(daily_txt_every)) EnableWindow(hwnd, FALSE);
  699. if (hwnd = _hCtrl(daily_spin_every)) EnableWindow(hwnd, FALSE);
  700. if (hwnd = _hCtrl(weekly_txt_every)) EnableWindow(hwnd, FALSE);
  701. if (hwnd = _hCtrl(weekly_spin_every)) EnableWindow(hwnd, FALSE);
  702. if (hwnd = _hCtrl(chk_mon)) EnableWindow(hwnd, FALSE);
  703. if (hwnd = _hCtrl(chk_tue)) EnableWindow(hwnd, FALSE);
  704. if (hwnd = _hCtrl(chk_wed)) EnableWindow(hwnd, FALSE);
  705. if (hwnd = _hCtrl(chk_thu)) EnableWindow(hwnd, FALSE);
  706. if (hwnd = _hCtrl(chk_fri)) EnableWindow(hwnd, FALSE);
  707. if (hwnd = _hCtrl(chk_sat)) EnableWindow(hwnd, FALSE);
  708. if (hwnd = _hCtrl(chk_sun)) EnableWindow(hwnd, FALSE);
  709. if (hwnd = _hCtrl(md_rb)) EnableWindow(hwnd, FALSE);
  710. if (hwnd = _hCtrl(dow_rb)) EnableWindow(hwnd, FALSE);
  711. if (hwnd = _hCtrl(md_txt)) EnableWindow(hwnd, FALSE);
  712. if (hwnd = _hCtrl(md_spin)) EnableWindow(hwnd, FALSE);
  713. if (hwnd = _hCtrl(dow_cbx_week)) EnableWindow(hwnd, FALSE);
  714. if (hwnd = _hCtrl(dow_cbx_day)) EnableWindow(hwnd, FALSE);
  715. if (hwnd = _hCtrl(once_dp_date)) EnableWindow(hwnd, FALSE);
  716. if (hwnd = _hCtrl(sch_txt_idle_min)) EnableWindow(hwnd, FALSE);
  717. if (hwnd = _hCtrl(sch_spin_idle_min)) EnableWindow(hwnd, FALSE);
  718. if (hwnd = _hCtrl(chk_show_multiple_scheds)) EnableWindow(hwnd, FALSE);
  719. if (hwnd = _hCtrl(btn_new))
  720. {
  721. EnableWindow(hwnd, FALSE);
  722. ShowWindow(hwnd, SW_HIDE);
  723. }
  724. if (hwnd = _hCtrl(btn_delete))
  725. {
  726. EnableWindow(hwnd, FALSE);
  727. ShowWindow(hwnd, SW_HIDE);
  728. }
  729. if (hwnd = _hCtrl(btn_advanced))
  730. {
  731. EnableWindow(hwnd, FALSE);
  732. ShowWindow(hwnd, SW_HIDE);
  733. }
  734. if (hwnd = _hCtrl(btn_sel_months))
  735. {
  736. EnableWindow(hwnd, FALSE);
  737. ShowWindow(hwnd, SW_HIDE);
  738. }
  739. }
  740. #define GET_LOCALE_INFO(lcid) \
  741. { \
  742. cch = GetLocaleInfo(LOCALE_USER_DEFAULT, \
  743. (lcid), \
  744. tszScratch, \
  745. ARRAYLEN(tszScratch)); \
  746. if (!cch) \
  747. { \
  748. DEBUG_OUT_LASTERROR; \
  749. break; \
  750. } \
  751. }
  752. //+--------------------------------------------------------------------------
  753. //
  754. // Function: UpdateTimeFormat
  755. //
  756. // Synopsis: Construct a time format containing hour and minute for use
  757. // with the date picker control.
  758. //
  759. // Arguments: [tszTimeFormat] - buffer to fill with time format
  760. // [cchTimeFormat] - size in chars of buffer
  761. //
  762. // Modifies: *[tszTimeFormat]
  763. //
  764. // History: 11-18-1996 DavidMun Created
  765. //
  766. // Notes: This is called on initialization and for wininichange
  767. // processing.
  768. //
  769. //---------------------------------------------------------------------------
  770. void
  771. UpdateTimeFormat(
  772. LPTSTR tszTimeFormat,
  773. ULONG cchTimeFormat)
  774. {
  775. ULONG cch;
  776. TCHAR tszScratch[80];
  777. BOOL fAmPm = FALSE;
  778. BOOL fAmPmPrefixes = FALSE;
  779. BOOL fLeadingZero = FALSE;
  780. do
  781. {
  782. GET_LOCALE_INFO(LOCALE_ITIME);
  783. fAmPm = (*tszScratch == TEXT('0'));
  784. if (fAmPm)
  785. {
  786. GET_LOCALE_INFO(LOCALE_ITIMEMARKPOSN);
  787. fAmPmPrefixes = (*tszScratch == TEXT('1'));
  788. }
  789. GET_LOCALE_INFO(LOCALE_ITLZERO);
  790. fLeadingZero = (*tszScratch == TEXT('1'));
  791. GET_LOCALE_INFO(LOCALE_STIME);
  792. //
  793. // See if there's enough room in destination string
  794. //
  795. cch = 1 + // terminating nul
  796. 1 + // first hour digit specifier "h"
  797. 2 + // minutes specifier "mm"
  798. (fLeadingZero != 0) + // leading hour digit specifier "h"
  799. lstrlen(tszScratch) + // separator string
  800. (fAmPm ? 3 : 0); // space and "tt" for AM/PM
  801. if (cch > cchTimeFormat)
  802. {
  803. cch = 0; // signal error
  804. }
  805. } while (0);
  806. //
  807. // If there was a problem in getting locale info for building time string
  808. // just use the default and bail.
  809. //
  810. if (!cch)
  811. {
  812. StringCchCopy(tszTimeFormat, cchTimeFormat, DEFAULT_TIME_FORMAT);
  813. return;
  814. }
  815. //
  816. // Build a time string that has hours and minutes but no seconds.
  817. //
  818. tszTimeFormat[0] = TEXT('\0');
  819. if (fAmPm)
  820. {
  821. if (fAmPmPrefixes)
  822. {
  823. StringCchCopy(tszTimeFormat, cchTimeFormat, TEXT("tt "));
  824. }
  825. StringCchCat(tszTimeFormat, cchTimeFormat, TEXT("h"));
  826. if (fLeadingZero)
  827. {
  828. StringCchCat(tszTimeFormat, cchTimeFormat, TEXT("h"));
  829. }
  830. }
  831. else
  832. {
  833. StringCchCat(tszTimeFormat, cchTimeFormat, TEXT("H"));
  834. if (fLeadingZero)
  835. {
  836. StringCchCat(tszTimeFormat, cchTimeFormat, TEXT("H"));
  837. }
  838. }
  839. StringCchCat(tszTimeFormat, cchTimeFormat, tszScratch); // separator
  840. StringCchCat(tszTimeFormat, cchTimeFormat, TEXT("mm"));
  841. if (fAmPm && !fAmPmPrefixes)
  842. {
  843. StringCchCat(tszTimeFormat, cchTimeFormat, TEXT(" tt"));
  844. }
  845. }
  846. HRESULT
  847. CSchedulePage::_LoadTriggers(void)
  848. {
  849. TRACE(CSchedulePage, _LoadTriggers);
  850. HRESULT hr = S_OK;
  851. WORD cTriggers = 0;
  852. TASK_TRIGGER jtTemp;
  853. do
  854. {
  855. hr = m_pIJob->GetTriggerCount(&cTriggers);
  856. CHECK_HRESULT(hr);
  857. BREAK_ON_FAIL(hr);
  858. if (cTriggers == 0)
  859. {
  860. break;
  861. }
  862. m_wNextTriggerId = m_cTriggersPrev = cTriggers;
  863. ITaskTrigger * pIJobTrigger = NULL;
  864. for (WORD wTrigger = 0; wTrigger < cTriggers; wTrigger++)
  865. {
  866. hr = m_pIJob->GetTrigger(wTrigger, &pIJobTrigger);
  867. CHECK_HRESULT(hr);
  868. BREAK_ON_FAIL(hr);
  869. hr = pIJobTrigger->GetTrigger(&jtTemp);
  870. CHECK_HRESULT(hr);
  871. pIJobTrigger->Release();
  872. BREAK_ON_FAIL(hr);
  873. // Set the trigger id
  874. jtTemp.Reserved1 = wTrigger;
  875. //
  876. // Save it to the m_cjtList.
  877. //
  878. CJobTrigger * pcjt = new CJobTrigger(jtTemp);
  879. if (pcjt == NULL)
  880. {
  881. hr = E_OUTOFMEMORY;
  882. CHECK_HRESULT(hr);
  883. break;
  884. }
  885. m_cjtList.Add(pcjt);
  886. }
  887. BREAK_ON_FAIL(hr);
  888. m_pcjtCurr = m_cjtList.First();
  889. } while (0);
  890. return hr;
  891. }
  892. BOOL
  893. CSchedulePage::_LoadTriggerStrings(void)
  894. {
  895. TCHAR tcBuff[SCH_XBIGBUF_LEN];
  896. HWND hCombo = _hCtrl(cbx_triggers);
  897. if (!hCombo)
  898. {
  899. return FALSE;
  900. }
  901. int iNew;
  902. HWND hwnd;
  903. CJobTrigger * pcjt = m_cjtList.First();
  904. if (pcjt == NULL)
  905. {
  906. //
  907. // Job not scheduled
  908. //
  909. LoadString(g_hInstance, IDS_NO_TRIGGERS, tcBuff, ARRAYLEN(tcBuff));
  910. if (hwnd = _hCtrl(txt_trigger)) SetWindowText(hwnd, tcBuff);
  911. iNew = ComboBox_AddString(hCombo, tcBuff);
  912. if (iNew < 0)
  913. {
  914. return FALSE;
  915. }
  916. ComboBox_SetItemData(hCombo, iNew, 0);
  917. return TRUE;
  918. }
  919. for (; pcjt != NULL; pcjt = pcjt->Next())
  920. {
  921. pcjt->TriggerString(TRUE, tcBuff, SCH_XBIGBUF_LEN);
  922. if (pcjt == m_cjtList.First())
  923. {
  924. // For single schedule set the static text box used to display
  925. // the schedule string.
  926. if (hwnd = _hCtrl(txt_trigger)) SetWindowText(hwnd, tcBuff);
  927. m_pcjtCurr = pcjt;
  928. }
  929. iNew = ComboBox_AddString(hCombo, tcBuff);
  930. if (iNew < 0)
  931. {
  932. return FALSE;
  933. }
  934. ComboBox_SetItemData(hCombo, iNew, pcjt);
  935. }
  936. return TRUE;
  937. }
  938. BOOL
  939. CSchedulePage::_InitPage(void)
  940. {
  941. TRACE(CSchedulePage, _InitPage);
  942. TCHAR tcBuff[SCH_XBIGBUF_LEN];
  943. HWND hCombo;
  944. //
  945. // set multiple schedules chk box
  946. //
  947. if (m_fShowMultiScheds == TRUE)
  948. {
  949. CheckDlgButton(m_hPage, chk_show_multiple_scheds, BST_CHECKED);
  950. }
  951. else
  952. {
  953. CheckDlgButton(m_hPage, chk_show_multiple_scheds, BST_UNCHECKED);
  954. }
  955. ////////////////////////////////////////////////////////////////
  956. //
  957. // Init all the combo boxes
  958. //
  959. //
  960. // The triggers combo-box for multiple schedules
  961. //
  962. CJobTrigger * pcjt;
  963. int iNew, iTemp;
  964. //
  965. // The cbx_trigger_type
  966. //
  967. hCombo = GetDlgItem(Hwnd(), cbx_trigger_type);
  968. for (WORD w = 0; w < ARRAYLEN(ttd); w++)
  969. {
  970. LoadString(g_hInstance, ttd[w].ids, tcBuff, SCH_XBIGBUF_LEN);
  971. ComboBox_AddString(hCombo, tcBuff);
  972. }
  973. //
  974. // The triggers comb box for multiple schedules as well as
  975. // static text box for single schedule.
  976. //
  977. if (_LoadTriggerStrings() == FALSE)
  978. {
  979. return FALSE;
  980. }
  981. //
  982. // The combo-boxes in monthly control
  983. //
  984. hCombo = GetDlgItem(Hwnd(), dow_cbx_week);
  985. for (w = 0; w < ARRAYLEN(g_aWeekData); w++)
  986. {
  987. LoadString(g_hInstance, g_aWeekData[w].ids, tcBuff,
  988. SCH_XBIGBUF_LEN);
  989. ComboBox_AddString(hCombo, tcBuff);
  990. }
  991. hCombo = GetDlgItem(Hwnd(), dow_cbx_day);
  992. for (w = 0; w < ARRAYLEN(g_aDayData); w++)
  993. {
  994. LoadString(g_hInstance, g_aDayData[w].ids, tcBuff,
  995. SCH_XBIGBUF_LEN);
  996. ComboBox_AddString(hCombo, tcBuff);
  997. }
  998. ////////////////////////////////////////////////////////////////
  999. //
  1000. // Init all the spin controls
  1001. //
  1002. // daily_spin_every (1 to max), 1
  1003. Spin_SetRange(Hwnd(), daily_spin_every, 1, 9999);
  1004. Spin_SetPos(Hwnd(), daily_spin_every, 1);
  1005. SendDlgItemMessage(Hwnd(), daily_txt_every, EM_LIMITTEXT, 4, 0);
  1006. // weekly_spin_every (1 to max), 1
  1007. Spin_SetRange(Hwnd(), weekly_spin_every, 1, 9999);
  1008. Spin_SetPos(Hwnd(), weekly_spin_every, 1);
  1009. SendDlgItemMessage(Hwnd(), weekly_txt_every, EM_LIMITTEXT, 4, 0);
  1010. // md_spin (1 to 31), 1
  1011. Spin_SetRange(Hwnd(), md_spin, 1, 31);
  1012. Spin_SetPos(Hwnd(), md_spin, 1);
  1013. SendDlgItemMessage(Hwnd(), md_txt, EM_LIMITTEXT, 2, 0);
  1014. // sch_spin_idle_min (1 to max), 1
  1015. Spin_SetRange(Hwnd(), sch_spin_idle_min, 1, MAX_IDLE_MINUTES);
  1016. Spin_SetPos(Hwnd(), sch_spin_idle_min, 1);
  1017. SendDlgItemMessage(Hwnd(), sch_txt_idle_min, EM_LIMITTEXT, MAX_IDLE_DIGITS, 0);
  1018. ////////////////////////////////////////////////////////////////
  1019. //
  1020. // Hide all controls
  1021. //
  1022. _ShowControls(INDEX_DAILY, SW_HIDE);
  1023. _ShowControls(INDEX_WEEKLY, SW_HIDE);
  1024. _ShowControls(INDEX_MONTHLY, SW_HIDE);
  1025. _ShowControls(INDEX_ONCE, SW_HIDE);
  1026. _ShowControls(INDEX_IDLE, SW_HIDE);
  1027. return TRUE;
  1028. }
  1029. int
  1030. CSchedulePage::_GetTriggerTypeIndex(void)
  1031. {
  1032. switch (m_pcjtCurr->m_jt.TriggerType)
  1033. {
  1034. case TASK_TIME_TRIGGER_ONCE:
  1035. return INDEX_ONCE;
  1036. case TASK_TIME_TRIGGER_DAILY:
  1037. return INDEX_DAILY;
  1038. case TASK_TIME_TRIGGER_WEEKLY:
  1039. return INDEX_WEEKLY;
  1040. case TASK_TIME_TRIGGER_MONTHLYDATE:
  1041. case TASK_TIME_TRIGGER_MONTHLYDOW:
  1042. return INDEX_MONTHLY;
  1043. case TASK_EVENT_TRIGGER_ON_IDLE:
  1044. return INDEX_IDLE;
  1045. case TASK_EVENT_TRIGGER_AT_SYSTEMSTART:
  1046. return INDEX_STARTUP;
  1047. case TASK_EVENT_TRIGGER_AT_LOGON:
  1048. return INDEX_LOGON;
  1049. default:
  1050. Win4Assert(0 && "Unknown trigger type");
  1051. return -1;
  1052. }
  1053. }
  1054. BOOL
  1055. CSchedulePage::_RefreshPage(void)
  1056. {
  1057. TRACE(CSchedulePage, _RefreshPage);
  1058. //
  1059. // Special case if Job not scheduled.
  1060. //
  1061. HWND hwnd;
  1062. if (m_pcjtCurr == NULL)
  1063. {
  1064. if (hwnd = _hCtrl(cbx_trigger_type)) EnableWindow(hwnd, FALSE);
  1065. if (hwnd = _hCtrl(btn_delete)) EnableWindow(hwnd, FALSE);
  1066. _EnableTimeTriggerSpecificCtrls(FALSE);
  1067. _ShowTriggerStringDispCtrls();
  1068. // Force multiple schedules view
  1069. // and prevent disabling new trigger creation if #triggers == 0
  1070. m_fShowMultiScheds = TRUE;
  1071. if (hwnd = _hCtrl(cbx_triggers)) ComboBox_SetCurSel(hwnd, 0);
  1072. CheckDlgButton(m_hPage, chk_show_multiple_scheds, BST_CHECKED);
  1073. if (hwnd = _hCtrl(chk_show_multiple_scheds)) EnableWindow(hwnd, FALSE);
  1074. return TRUE;
  1075. }
  1076. //
  1077. // Disable the "show multiple schedules" checkbox if there
  1078. // is already more than one trigger on the task.
  1079. // This prevents users from hiding the fact that they might have
  1080. // additional triggers which they can't see.
  1081. //
  1082. if (m_cjtList.Count() != 1)
  1083. {
  1084. m_fShowMultiScheds = TRUE;
  1085. CheckDlgButton(m_hPage, chk_show_multiple_scheds, BST_CHECKED);
  1086. if (hwnd = _hCtrl(chk_show_multiple_scheds)) EnableWindow(hwnd, FALSE);
  1087. }
  1088. else
  1089. {
  1090. if (hwnd = _hCtrl(chk_show_multiple_scheds)) EnableWindow(hwnd, TRUE);
  1091. }
  1092. //
  1093. // Set the trigger type
  1094. //
  1095. int indexTrigger = _GetTriggerTypeIndex();
  1096. if (indexTrigger == -1)
  1097. {
  1098. return FALSE;
  1099. }
  1100. if (m_indexCbxTriggerType != -1 && m_indexCbxTriggerType != indexTrigger)
  1101. {
  1102. _ShowControls(m_indexCbxTriggerType, SW_HIDE);
  1103. }
  1104. m_indexCbxTriggerType = indexTrigger;
  1105. if (hwnd = _hCtrl(cbx_trigger_type)) ComboBox_SetCurSel(hwnd, indexTrigger);
  1106. //
  1107. // Set the schedule
  1108. //
  1109. BOOL fTimeTrigger = TRUE;
  1110. switch (m_pcjtCurr->m_jt.TriggerType)
  1111. {
  1112. case TASK_TIME_TRIGGER_DAILY:
  1113. _ShowControls(INDEX_DAILY, SW_SHOWNA);
  1114. _UpdateDailyControls();
  1115. break;
  1116. case TASK_TIME_TRIGGER_WEEKLY:
  1117. _ShowControls(INDEX_WEEKLY, SW_SHOWNA);
  1118. _UpdateWeeklyControls();
  1119. break;
  1120. case TASK_TIME_TRIGGER_MONTHLYDATE:
  1121. case TASK_TIME_TRIGGER_MONTHLYDOW:
  1122. _ShowControls(INDEX_MONTHLY, SW_SHOWNA);
  1123. _UpdateMonthlyControls();
  1124. break;
  1125. case TASK_TIME_TRIGGER_ONCE:
  1126. _ShowControls(INDEX_ONCE, SW_SHOWNA);
  1127. _UpdateOnceOnlyControls();
  1128. break;
  1129. case TASK_EVENT_TRIGGER_AT_SYSTEMSTART:
  1130. fTimeTrigger = FALSE;
  1131. ComboBox_SetCurSel(GetDlgItem(Hwnd(), cbx_trigger_type), INDEX_STARTUP);
  1132. break;
  1133. case TASK_EVENT_TRIGGER_AT_LOGON:
  1134. fTimeTrigger = FALSE;
  1135. ComboBox_SetCurSel(GetDlgItem(Hwnd(), cbx_trigger_type), INDEX_LOGON);
  1136. break;
  1137. case TASK_EVENT_TRIGGER_ON_IDLE:
  1138. fTimeTrigger = FALSE;
  1139. ComboBox_SetCurSel(GetDlgItem(Hwnd(), cbx_trigger_type), INDEX_IDLE);
  1140. _ShowControls(INDEX_IDLE, SW_SHOWNA);
  1141. _UpdateIdleControls();
  1142. break;
  1143. default:
  1144. Win4Assert(0 && "Unknown trigger type");
  1145. return FALSE;
  1146. }
  1147. _EnableTimeTriggerSpecificCtrls(fTimeTrigger);
  1148. if (fTimeTrigger == TRUE)
  1149. {
  1150. //
  1151. // Set start time
  1152. //
  1153. SYSTEMTIME st;
  1154. GetSystemTime(&st);
  1155. st.wHour = m_pcjtCurr->m_jt.wStartHour;
  1156. st.wMinute = m_pcjtCurr->m_jt.wStartMinute;
  1157. st.wSecond = 0;
  1158. hwnd = _hCtrl(dp_start_time);
  1159. if ((NULL == hwnd) || (DateTime_SetSystemtime(hwnd, GDT_VALID, &st) == FALSE))
  1160. {
  1161. DEBUG_OUT((DEB_USER1, "DateTime_SetSystemtime failed.\n"));
  1162. }
  1163. }
  1164. //
  1165. // Finally update the trigger string
  1166. //
  1167. _UpdateTriggerString();
  1168. _ShowTriggerStringDispCtrls();
  1169. return TRUE;
  1170. }
  1171. void
  1172. CSchedulePage::_UpdateDailyControls(void)
  1173. {
  1174. ComboBox_SetCurSel(GetDlgItem(Hwnd(), cbx_trigger_type), INDEX_DAILY);
  1175. Spin_SetPos(Hwnd(), daily_spin_every, m_pcjtCurr->m_jt.Type.Daily.DaysInterval);
  1176. }
  1177. void
  1178. CSchedulePage::_UpdateWeeklyControls(void)
  1179. {
  1180. ComboBox_SetCurSel(GetDlgItem(Hwnd(), cbx_trigger_type), INDEX_WEEKLY);
  1181. Spin_SetPos(Hwnd(), weekly_spin_every,
  1182. m_pcjtCurr->m_jt.Type.Weekly.WeeksInterval);
  1183. for (int i=0; i < 7; i++)
  1184. {
  1185. if (m_pcjtCurr->m_jt.Type.Weekly.rgfDaysOfTheWeek & g_aDayData[i].day)
  1186. {
  1187. CheckDlgButton(Hwnd(), g_aDayData[i].idCtrl, BST_CHECKED);
  1188. }
  1189. else
  1190. {
  1191. CheckDlgButton(Hwnd(), g_aDayData[i].idCtrl, BST_UNCHECKED);
  1192. }
  1193. }
  1194. }
  1195. WORD
  1196. CSchedulePage::_GetDayFromRgfDays(
  1197. DWORD rgfDays)
  1198. {
  1199. WORD wDay;
  1200. WORD wTemp;
  1201. BYTE bTemp;
  1202. if (LOWORD(rgfDays))
  1203. {
  1204. wTemp = LOWORD(rgfDays);
  1205. wDay = 0;
  1206. }
  1207. else
  1208. {
  1209. wTemp = HIWORD(rgfDays);
  1210. wDay = 16;
  1211. }
  1212. if (LOBYTE(wTemp))
  1213. {
  1214. bTemp = LOBYTE(wTemp);
  1215. }
  1216. else
  1217. {
  1218. bTemp = HIBYTE(wTemp);
  1219. wDay += 8;
  1220. }
  1221. if (bTemp & 0x01) return (wDay + 1);
  1222. if (bTemp & 0x02) return (wDay + 2);
  1223. if (bTemp & 0x04) return (wDay + 3);
  1224. if (bTemp & 0x08) return (wDay + 4);
  1225. if (bTemp & 0x10) return (wDay + 5);
  1226. if (bTemp & 0x20) return (wDay + 6);
  1227. if (bTemp & 0x40) return (wDay + 7);
  1228. if (bTemp & 0x80) return (wDay + 8);
  1229. return 0;
  1230. }
  1231. //+--------------------------------------------------------------------------
  1232. //
  1233. // Member: CSchedulePage::_CheckMonthlyRadio
  1234. //
  1235. // Synopsis: Set the state of the monthly radio buttons to match
  1236. // [TriggerType].
  1237. //
  1238. // Arguments: [TriggerType] - TASK_TIME_TRIGGER_MONTHLYDATE or
  1239. // TASK_TIME_TRIGGER_MONTHLYDOW.
  1240. //
  1241. // History: 07-20-1997 DavidMun Created
  1242. //
  1243. //---------------------------------------------------------------------------
  1244. void
  1245. CSchedulePage::_CheckMonthlyRadio(
  1246. TASK_TRIGGER_TYPE TriggerType)
  1247. {
  1248. if (TriggerType == TASK_TIME_TRIGGER_MONTHLYDATE)
  1249. {
  1250. CheckDlgButton(Hwnd(), md_rb, BST_CHECKED);
  1251. CheckDlgButton(Hwnd(), dow_rb, BST_UNCHECKED);
  1252. }
  1253. else
  1254. {
  1255. Win4Assert(TriggerType == TASK_TIME_TRIGGER_MONTHLYDOW);
  1256. CheckDlgButton(Hwnd(), md_rb, BST_UNCHECKED);
  1257. CheckDlgButton(Hwnd(), dow_rb, BST_CHECKED);
  1258. }
  1259. }
  1260. void
  1261. CSchedulePage::_UpdateMonthlyControls(void)
  1262. {
  1263. ComboBox_SetCurSel(GetDlgItem(Hwnd(), cbx_trigger_type), INDEX_MONTHLY);
  1264. WORD rgfMonths = 0;
  1265. HWND hwnd;
  1266. _CheckMonthlyRadio(m_pcjtCurr->m_jt.TriggerType);
  1267. if (m_pcjtCurr->m_jt.TriggerType == TASK_TIME_TRIGGER_MONTHLYDATE)
  1268. {
  1269. WORD wDay = _GetDayFromRgfDays(m_pcjtCurr->m_jt.Type.MonthlyDate.rgfDays);
  1270. Spin_SetPos(Hwnd(), md_spin, wDay);
  1271. rgfMonths = m_pcjtCurr->m_jt.Type.MonthlyDate.rgfMonths;
  1272. if (hwnd = _hCtrl(md_spin)) EnableWindow(hwnd, TRUE);
  1273. if (hwnd = _hCtrl(md_txt)) EnableWindow(hwnd, TRUE);
  1274. if (hwnd = _hCtrl(dow_cbx_week)) EnableWindow(hwnd, FALSE);
  1275. if (hwnd = _hCtrl(dow_cbx_day)) EnableWindow(hwnd, FALSE);
  1276. }
  1277. else // monthly day-of-week
  1278. {
  1279. for (int i=0; i < ARRAYLEN(g_aWeekData); i++)
  1280. {
  1281. if (g_aWeekData[i].week ==
  1282. m_pcjtCurr->m_jt.Type.MonthlyDOW.wWhichWeek)
  1283. {
  1284. break;
  1285. }
  1286. }
  1287. if (hwnd = _hCtrl(dow_cbx_week))
  1288. {
  1289. ComboBox_SetCurSel(hwnd, i);
  1290. EnableWindow(hwnd, TRUE);
  1291. }
  1292. WORD &wDayOfWeek = m_pcjtCurr->m_jt.Type.MonthlyDOW.rgfDaysOfTheWeek;
  1293. for (i=0; i < ARRAYLEN(g_aDayData); i++)
  1294. {
  1295. if (wDayOfWeek & g_aDayData[i].day)
  1296. {
  1297. break;
  1298. }
  1299. }
  1300. if (hwnd = _hCtrl(dow_cbx_day))
  1301. {
  1302. ComboBox_SetCurSel(hwnd, i);
  1303. EnableWindow(hwnd, TRUE);
  1304. }
  1305. rgfMonths = m_pcjtCurr->m_jt.Type.MonthlyDOW.rgfMonths;
  1306. if (hwnd = _hCtrl(md_txt)) EnableWindow(hwnd, FALSE);
  1307. if (hwnd = _hCtrl(md_spin)) EnableWindow(hwnd, FALSE);
  1308. }
  1309. }
  1310. void
  1311. CSchedulePage::_UpdateOnceOnlyControls(void)
  1312. {
  1313. ComboBox_SetCurSel(GetDlgItem(Hwnd(), cbx_trigger_type), INDEX_ONCE);
  1314. SYSTEMTIME st;
  1315. SecureZeroMemory(&st, sizeof st);
  1316. st.wYear = m_pcjtCurr->m_jt.wBeginYear;
  1317. st.wMonth = m_pcjtCurr->m_jt.wBeginMonth;
  1318. st.wDay = m_pcjtCurr->m_jt.wBeginDay;
  1319. HWND hwnd;
  1320. if (hwnd = _hCtrl(once_dp_date))
  1321. {
  1322. if (DateTime_SetSystemtime(hwnd, GDT_VALID, &st) == FALSE)
  1323. {
  1324. DEBUG_OUT((DEB_ERROR,
  1325. "DateTime_SetSystemtime err=%uL.\n",
  1326. GetLastError()));
  1327. }
  1328. }
  1329. }
  1330. void
  1331. CSchedulePage::_UpdateIdleControls(void)
  1332. {
  1333. WORD wIdleWait;
  1334. WORD wIdleDeadline;
  1335. m_pIJob->GetIdleWait(&wIdleWait, &wIdleDeadline);
  1336. if (wIdleWait > MAX_IDLE_MINUTES)
  1337. {
  1338. wIdleWait = MAX_IDLE_MINUTES;
  1339. }
  1340. Spin_SetPos(Hwnd(), sch_spin_idle_min, wIdleWait);
  1341. }
  1342. INT_PTR
  1343. AdvancedDialog(
  1344. HWND hParent,
  1345. PTASK_TRIGGER pjt);
  1346. LRESULT
  1347. CSchedulePage::_OnCommand(
  1348. int id,
  1349. HWND hwndCtl,
  1350. UINT codeNotify)
  1351. {
  1352. TRACE(CSchedulePage, _OnCommand);
  1353. HRESULT hr = S_OK;
  1354. CJobTrigger * pcjt = NULL;
  1355. BOOL fUpdateTriggerStr = TRUE;
  1356. SYSTEMTIME st;
  1357. HWND hCombo;
  1358. HWND hwnd;
  1359. switch (id)
  1360. {
  1361. case cbx_trigger_type:
  1362. fUpdateTriggerStr = FALSE;
  1363. if (codeNotify == CBN_DROPDOWN)
  1364. {
  1365. if (hwnd = _hCtrl(cbx_trigger_type))
  1366. {
  1367. s_iCbx = ComboBox_GetCurSel(hwnd);
  1368. }
  1369. }
  1370. else if (codeNotify == CBN_SELENDOK)
  1371. {
  1372. if (hwnd = _hCtrl(cbx_trigger_type))
  1373. {
  1374. int iCur = ComboBox_GetCurSel(hwnd);
  1375. if (iCur != s_iCbx)
  1376. {
  1377. _DisplayControls(iCur);
  1378. _EnableApplyButton();
  1379. fUpdateTriggerStr = TRUE;
  1380. }
  1381. }
  1382. s_iCbx = -1;
  1383. }
  1384. else if (codeNotify == CBN_SELENDCANCEL)
  1385. {
  1386. s_iCbx = -1;
  1387. }
  1388. break;
  1389. case btn_advanced:
  1390. {
  1391. _SaveTriggerSettings();
  1392. TASK_TRIGGER jt = m_pcjtCurr->m_jt;
  1393. if (AdvancedDialog(Hwnd(), &jt) == TRUE)
  1394. {
  1395. if (memcmp(&jt, &m_pcjtCurr->m_jt, sizeof(jt)) != 0)
  1396. {
  1397. m_pcjtCurr->m_jt = jt;
  1398. m_pcjtCurr->DirtyTrigger();
  1399. _EnableApplyButton();
  1400. }
  1401. else
  1402. {
  1403. fUpdateTriggerStr = FALSE;
  1404. }
  1405. }
  1406. break;
  1407. }
  1408. case btn_sel_months:
  1409. {
  1410. _SaveTriggerSettings();
  1411. TASK_TRIGGER jt = m_pcjtCurr->m_jt;
  1412. _SelectMonths.InitSelectionFromTrigger(&jt);
  1413. INT_PTR fOk = _SelectMonths.DoModal(select_month_dlg, Hwnd());
  1414. if (fOk)
  1415. {
  1416. _SelectMonths.UpdateTrigger(&jt);
  1417. if (memcmp(&jt, &m_pcjtCurr->m_jt, sizeof(jt)) != 0)
  1418. {
  1419. m_pcjtCurr->m_jt = jt;
  1420. m_pcjtCurr->DirtyTrigger();
  1421. _EnableApplyButton();
  1422. }
  1423. else
  1424. {
  1425. fUpdateTriggerStr = FALSE;
  1426. }
  1427. }
  1428. break;
  1429. }
  1430. // Daily controls - none to handle here
  1431. case daily_txt_every:
  1432. if (codeNotify == EN_CHANGE)
  1433. {
  1434. _EnableApplyButton();
  1435. }
  1436. break;
  1437. // Weekly controls
  1438. case weekly_txt_every:
  1439. if (codeNotify == EN_CHANGE)
  1440. {
  1441. _EnableApplyButton();
  1442. }
  1443. break;
  1444. case chk_mon: case chk_tue: case chk_wed: case chk_thu:
  1445. case chk_fri: case chk_sat: case chk_sun:
  1446. _EnableApplyButton();
  1447. break;
  1448. // Monthly controls
  1449. case md_txt:
  1450. if (codeNotify == EN_CHANGE)
  1451. {
  1452. _EnableApplyButton();
  1453. }
  1454. break;
  1455. case md_rb:
  1456. _CheckMonthlyRadio(TASK_TIME_TRIGGER_MONTHLYDATE);
  1457. Spin_Enable(Hwnd(), md_spin, 1);
  1458. if (hwnd = _hCtrl(dow_cbx_week)) EnableWindow(hwnd, FALSE);
  1459. if (hwnd = _hCtrl(dow_cbx_day)) EnableWindow(hwnd, FALSE);
  1460. _EnableApplyButton();
  1461. break;
  1462. case dow_rb:
  1463. _CheckMonthlyRadio(TASK_TIME_TRIGGER_MONTHLYDOW);
  1464. Spin_Disable(Hwnd(), md_spin);
  1465. if (hwnd = _hCtrl(dow_cbx_week))
  1466. {
  1467. EnableWindow(hwnd, TRUE);
  1468. ComboBox_SetCurSel(hwnd, 0);
  1469. }
  1470. if (hwnd = _hCtrl(dow_cbx_day))
  1471. {
  1472. EnableWindow(hwnd, TRUE);
  1473. ComboBox_SetCurSel(hwnd, 0);
  1474. }
  1475. _EnableApplyButton();
  1476. break;
  1477. case dow_cbx_week:
  1478. case dow_cbx_day:
  1479. fUpdateTriggerStr = FALSE;
  1480. if (codeNotify == CBN_DROPDOWN)
  1481. {
  1482. if (hwnd = _hCtrl(id)) s_iCbx = ComboBox_GetCurSel(hwnd);
  1483. }
  1484. else if (codeNotify == CBN_SELENDOK)
  1485. {
  1486. if (hwnd = _hCtrl(id))
  1487. {
  1488. int iCur = ComboBox_GetCurSel(hwnd);
  1489. if (iCur != s_iCbx)
  1490. {
  1491. _EnableApplyButton();
  1492. fUpdateTriggerStr = TRUE;
  1493. }
  1494. }
  1495. s_iCbx = -1;
  1496. }
  1497. else if (codeNotify == CBN_SELENDCANCEL)
  1498. {
  1499. s_iCbx = -1;
  1500. }
  1501. break;
  1502. // When Idle controls
  1503. case sch_txt_idle_min:
  1504. if (codeNotify == EN_CHANGE)
  1505. {
  1506. _EnableApplyButton();
  1507. }
  1508. break;
  1509. // Once only controls - none
  1510. // At startup controls - none
  1511. // At logon controls - none
  1512. // Controls for multiple triggers
  1513. case chk_show_multiple_scheds:
  1514. if (IsDlgButtonChecked(m_hPage, chk_show_multiple_scheds)
  1515. == BST_CHECKED)
  1516. {
  1517. m_fShowMultiScheds = TRUE;
  1518. }
  1519. else
  1520. {
  1521. m_fShowMultiScheds = FALSE;
  1522. }
  1523. _UpdateTriggerString();
  1524. _ShowTriggerStringDispCtrls();
  1525. break;
  1526. case btn_new:
  1527. {
  1528. if (hwnd = _hCtrl(btn_new)) SetFocus(hwnd);
  1529. hCombo = _hCtrl(cbx_triggers);
  1530. if (!hCombo)
  1531. {
  1532. break;
  1533. }
  1534. if (_PerformSanityChkOnCurrTrigger() == FALSE)
  1535. {
  1536. break;
  1537. }
  1538. if (m_pcjtCurr == NULL)
  1539. {
  1540. ComboBox_ResetContent(hCombo);
  1541. m_wNextTriggerId = 0;
  1542. }
  1543. else
  1544. {
  1545. //
  1546. // Save the current trigger
  1547. //
  1548. _SaveTriggerSettings();
  1549. }
  1550. //
  1551. // Create a new trigger, with default settings as:
  1552. // daily trigger starting at 6:00 AM
  1553. //
  1554. TASK_TRIGGER jtDefault;
  1555. GetSystemTime(&st);
  1556. SecureZeroMemory(&jtDefault, sizeof(jtDefault));
  1557. jtDefault.cbTriggerSize = sizeof(jtDefault);
  1558. jtDefault.wBeginYear = st.wYear;
  1559. jtDefault.wBeginMonth = st.wMonth;
  1560. jtDefault.wBeginDay = st.wDay;
  1561. jtDefault.wStartHour = 9; // 9 AM
  1562. jtDefault.TriggerType = TASK_TIME_TRIGGER_DAILY;
  1563. jtDefault.Type.Daily.DaysInterval = 1; // Every day
  1564. jtDefault.Reserved1 = m_wNextTriggerId;
  1565. jtDefault.Reserved2 = 0;
  1566. jtDefault.wRandomMinutesInterval = 0;
  1567. pcjt = m_cjtDeletedList.First();
  1568. if (pcjt != NULL)
  1569. {
  1570. m_cjtDeletedList.Remove(pcjt);
  1571. pcjt->m_jt = jtDefault;
  1572. }
  1573. else
  1574. {
  1575. pcjt = new CJobTrigger(jtDefault);
  1576. if (pcjt == NULL)
  1577. {
  1578. hr = E_OUTOFMEMORY;
  1579. CHECK_HRESULT(hr);
  1580. break;
  1581. }
  1582. }
  1583. pcjt->DirtyTrigger();
  1584. TCHAR tcBuff[SCH_XBIGBUF_LEN];
  1585. pcjt->TriggerString(TRUE, tcBuff, SCH_XBIGBUF_LEN);
  1586. int iNew = ComboBox_AddString(hCombo, tcBuff);
  1587. if (iNew < 0)
  1588. {
  1589. hr = E_OUTOFMEMORY;
  1590. CHECK_HRESULT(hr);
  1591. break;
  1592. }
  1593. ComboBox_SetItemData(hCombo, iNew, pcjt);
  1594. ComboBox_SetCurSel(hCombo, iNew);
  1595. m_indexCbxTriggers = iNew;
  1596. m_pcjtCurr = pcjt;
  1597. m_cjtList.Add(pcjt);
  1598. //
  1599. // Don't forget to increment m_wNextTriggerId
  1600. //
  1601. ++m_wNextTriggerId;
  1602. //
  1603. // Refresh the page for the new trigger
  1604. //
  1605. _RefreshPage();
  1606. //
  1607. // If count of triggers increased from 0 to 1 enable
  1608. // cbx_trigger_type & btn_delete.
  1609. //
  1610. if (m_cjtList.Count() == 1)
  1611. {
  1612. if (hwnd = _hCtrl(cbx_trigger_type)) EnableWindow(hwnd, TRUE);
  1613. if (hwnd = _hCtrl(btn_delete)) EnableWindow(hwnd, TRUE);
  1614. }
  1615. _EnableApplyButton();
  1616. break;
  1617. }
  1618. case btn_delete:
  1619. {
  1620. //
  1621. // Delete the current trigger.
  1622. //
  1623. //Win4Assert(m_cjtList.Count() > 1);
  1624. HWND hCombo = _hCtrl(cbx_triggers);
  1625. if (!hCombo)
  1626. {
  1627. break;
  1628. }
  1629. int iCur = ComboBox_GetCurSel(hCombo);
  1630. pcjt = (CJobTrigger *) ComboBox_GetItemData(hCombo, iCur);
  1631. ComboBox_DeleteString(hCombo, iCur);
  1632. m_cjtList.Remove(pcjt);
  1633. m_cjtDeletedList.Add(pcjt);
  1634. //
  1635. // Update the triggers combo box
  1636. //
  1637. if (iCur >= ComboBox_GetCount(hCombo))
  1638. {
  1639. --iCur;
  1640. }
  1641. if (iCur >= 0)
  1642. {
  1643. ComboBox_SetCurSel(hCombo, iCur);
  1644. m_indexCbxTriggers = iCur;
  1645. m_pcjtCurr = (CJobTrigger *) ComboBox_GetItemData(hCombo, iCur);
  1646. }
  1647. else
  1648. {
  1649. _ShowControls(m_indexCbxTriggerType, SW_HIDE);
  1650. _LoadTriggerStrings();
  1651. ComboBox_SetCurSel(hCombo, 0);
  1652. m_indexCbxTriggers = 0;
  1653. m_pcjtCurr = NULL;
  1654. fUpdateTriggerStr = FALSE;
  1655. }
  1656. //
  1657. // Refresh the page for the new trigger
  1658. //
  1659. _RefreshPage();
  1660. //
  1661. // If we have zero items, disable the delete button.
  1662. //
  1663. if (m_cjtList.Count() == 0)
  1664. {
  1665. if (hwnd = _hCtrl(btn_delete)) EnableWindow(hwnd, FALSE);
  1666. if (hwnd = _hCtrl(btn_new)) SetFocus(hwnd);
  1667. }
  1668. else
  1669. {
  1670. if (hwnd = _hCtrl(btn_delete)) SetFocus(hwnd);
  1671. }
  1672. _EnableApplyButton();
  1673. break;
  1674. }
  1675. case cbx_triggers:
  1676. if (codeNotify == CBN_SELENDOK)
  1677. {
  1678. if (hwnd = _hCtrl(cbx_triggers))
  1679. {
  1680. m_indexCbxTriggers = ComboBox_GetCurSel(hwnd);
  1681. m_pcjtCurr = (CJobTrigger *) ComboBox_GetItemData(hwnd, m_indexCbxTriggers);
  1682. _RefreshPage();
  1683. }
  1684. }
  1685. else
  1686. {
  1687. fUpdateTriggerStr = FALSE;
  1688. }
  1689. break;
  1690. default:
  1691. fUpdateTriggerStr = FALSE;
  1692. return FALSE;
  1693. }
  1694. if (fUpdateTriggerStr == TRUE)
  1695. {
  1696. _CreateTimerToUpdateTriggerStr();
  1697. }
  1698. if (FAILED(hr))
  1699. {
  1700. _ErrorDialog(IERR_OUT_OF_MEMORY);
  1701. }
  1702. return TRUE;
  1703. }
  1704. void
  1705. CSchedulePage::_DisplayControls(int indexTrigger)
  1706. {
  1707. TRACE(CSchedulePage, _DisplayControls);
  1708. if (indexTrigger == m_indexCbxTriggerType)
  1709. {
  1710. return;
  1711. }
  1712. _ShowControls(m_indexCbxTriggerType, SW_HIDE);
  1713. _ShowControls((m_indexCbxTriggerType = indexTrigger), SW_SHOWNA);
  1714. BOOL fEnableEventControls = TRUE;
  1715. UINT i;
  1716. HWND hwnd;
  1717. switch (indexTrigger)
  1718. {
  1719. case INDEX_DAILY:
  1720. Spin_SetPos(Hwnd(), daily_spin_every, 1);
  1721. break;
  1722. case INDEX_WEEKLY:
  1723. Spin_SetPos(Hwnd(), weekly_spin_every, 1);
  1724. CheckDlgButton(Hwnd(), g_aDayData[0].idCtrl, BST_CHECKED);
  1725. for (i = 1; i < ARRAYLEN(g_aDayData); i++)
  1726. {
  1727. CheckDlgButton(Hwnd(), g_aDayData[i].idCtrl, BST_UNCHECKED);
  1728. }
  1729. break;
  1730. case INDEX_MONTHLY:
  1731. {
  1732. _CheckMonthlyRadio(TASK_TIME_TRIGGER_MONTHLYDATE);
  1733. Spin_Enable(Hwnd(), md_spin, 1);
  1734. m_pcjtCurr->m_jt.Type.MonthlyDate.rgfMonths = ALL_MONTHS;
  1735. if (hwnd = _hCtrl(dow_cbx_week))
  1736. {
  1737. if( !EnableWindow(hwnd, FALSE) )
  1738. {
  1739. DEBUG_OUT((DEB_USER1, "EnableWindow(_hCtrl(dow_cbx_week), FALSE) failed.\n"));
  1740. }
  1741. }
  1742. if (hwnd = _hCtrl(dow_cbx_day))
  1743. {
  1744. if( !EnableWindow(hwnd, FALSE) )
  1745. {
  1746. DEBUG_OUT((DEB_USER1, "EnableWindow(_hCtrl(dow_cbx_day), FALSE) failed.\n"));
  1747. }
  1748. }
  1749. break;
  1750. }
  1751. case INDEX_ONCE:
  1752. {
  1753. SYSTEMTIME st;
  1754. GetLocalTime(&st);
  1755. if (hwnd = _hCtrl(once_dp_date))
  1756. {
  1757. if (DateTime_SetSystemtime(hwnd, GDT_VALID, &st) == FALSE)
  1758. {
  1759. DEBUG_OUT((DEB_USER1, "DateTime_SetSystemtime failed.\n"));
  1760. }
  1761. }
  1762. break;
  1763. }
  1764. case INDEX_IDLE:
  1765. {
  1766. WORD wIdleWait;
  1767. WORD wDummy;
  1768. HRESULT hr = m_pIJob->GetIdleWait(&wIdleWait, &wDummy);
  1769. if (FAILED(hr) || !wIdleWait)
  1770. {
  1771. wIdleWait = SCH_DEFAULT_IDLE_TIME;
  1772. }
  1773. else if (wIdleWait > MAX_IDLE_MINUTES)
  1774. {
  1775. wIdleWait = MAX_IDLE_MINUTES;
  1776. }
  1777. Spin_SetPos(Hwnd(), sch_spin_idle_min, wIdleWait);
  1778. fEnableEventControls = FALSE;
  1779. break;
  1780. }
  1781. case INDEX_STARTUP:
  1782. case INDEX_LOGON:
  1783. fEnableEventControls = FALSE;
  1784. break;
  1785. }
  1786. _EnableTimeTriggerSpecificCtrls(fEnableEventControls);
  1787. }
  1788. void
  1789. CSchedulePage::_SaveTriggerSettings(void)
  1790. {
  1791. TRACE(CSchedulePage, _SaveTriggerSettings);
  1792. if (m_pcjtCurr == 0)
  1793. {
  1794. // No triggers
  1795. return;
  1796. }
  1797. HWND hwnd = _hCtrl(cbx_trigger_type);
  1798. if (!hwnd)
  1799. {
  1800. return;
  1801. }
  1802. int idxTriggerType = ComboBox_GetCurSel(hwnd);
  1803. Win4Assert(idxTriggerType != CB_ERR);
  1804. int i;
  1805. // Get start time
  1806. SYSTEMTIME st;
  1807. if (hwnd = _hCtrl(dp_start_time))
  1808. {
  1809. if (DateTime_GetSystemtime(hwnd, &st) == GDT_VALID)
  1810. {
  1811. m_pcjtCurr->m_jt.wStartHour = st.wHour;
  1812. m_pcjtCurr->m_jt.wStartMinute = st.wMinute;
  1813. }
  1814. }
  1815. switch (idxTriggerType)
  1816. {
  1817. case INDEX_DAILY:
  1818. m_pcjtCurr->m_jt.TriggerType = TASK_TIME_TRIGGER_DAILY;
  1819. m_pcjtCurr->m_jt.Type.Daily.DaysInterval = (WORD)Spin_GetPos(Hwnd(),
  1820. daily_spin_every);
  1821. break;
  1822. case INDEX_WEEKLY:
  1823. m_pcjtCurr->m_jt.TriggerType = TASK_TIME_TRIGGER_WEEKLY;
  1824. m_pcjtCurr->m_jt.Type.Weekly.WeeksInterval = (WORD)Spin_GetPos(Hwnd(),
  1825. weekly_spin_every);
  1826. m_pcjtCurr->m_jt.Type.Weekly.rgfDaysOfTheWeek = 0;
  1827. for (i=0; i < ARRAYLEN(g_aDayData); i++)
  1828. {
  1829. if (IsDlgButtonChecked(Hwnd(), g_aDayData[i].idCtrl)
  1830. == BST_CHECKED)
  1831. {
  1832. m_pcjtCurr->m_jt.Type.Weekly.rgfDaysOfTheWeek |= g_aDayData[i].day;
  1833. }
  1834. }
  1835. break;
  1836. case INDEX_MONTHLY:
  1837. {
  1838. if (IsDlgButtonChecked(Hwnd(), md_rb) == BST_CHECKED)
  1839. {
  1840. m_pcjtCurr->m_jt.TriggerType = TASK_TIME_TRIGGER_MONTHLYDATE;
  1841. WORD wTemp = (WORD)Spin_GetPos(Hwnd(), md_spin);
  1842. m_pcjtCurr->m_jt.Type.MonthlyDate.rgfDays = (1 << (wTemp - 1));
  1843. }
  1844. else // monthly day-of-week
  1845. {
  1846. m_pcjtCurr->m_jt.TriggerType = TASK_TIME_TRIGGER_MONTHLYDOW;
  1847. if (hwnd = _hCtrl(dow_cbx_week))
  1848. {
  1849. i = ComboBox_GetCurSel(hwnd);
  1850. m_pcjtCurr->m_jt.Type.MonthlyDOW.wWhichWeek = (WORD)g_aWeekData[i].week;
  1851. }
  1852. if (hwnd = _hCtrl(dow_cbx_day))
  1853. {
  1854. i = ComboBox_GetCurSel(hwnd);
  1855. m_pcjtCurr->m_jt.Type.MonthlyDOW.rgfDaysOfTheWeek = (WORD)g_aDayData[i].day;
  1856. }
  1857. }
  1858. break;
  1859. }
  1860. case INDEX_ONCE:
  1861. m_pcjtCurr->m_jt.TriggerType = TASK_TIME_TRIGGER_ONCE;
  1862. if (hwnd = _hCtrl(once_dp_date))
  1863. {
  1864. if (DateTime_GetSystemtime(hwnd, &st) == GDT_VALID)
  1865. {
  1866. m_pcjtCurr->m_jt.wBeginYear = st.wYear;
  1867. m_pcjtCurr->m_jt.wBeginMonth = st.wMonth;
  1868. m_pcjtCurr->m_jt.wBeginDay = st.wDay;
  1869. }
  1870. }
  1871. break;
  1872. case INDEX_STARTUP:
  1873. m_pcjtCurr->m_jt.TriggerType = TASK_EVENT_TRIGGER_AT_SYSTEMSTART;
  1874. break;
  1875. case INDEX_LOGON:
  1876. m_pcjtCurr->m_jt.TriggerType = TASK_EVENT_TRIGGER_AT_LOGON;
  1877. break;
  1878. case INDEX_IDLE:
  1879. {
  1880. m_pcjtCurr->m_jt.TriggerType = TASK_EVENT_TRIGGER_ON_IDLE;
  1881. ULONG ulSpinPos = Spin_GetPos(Hwnd(), sch_spin_idle_min);
  1882. WORD wDummy;
  1883. WORD wIdleDeadline;
  1884. m_pIJob->GetIdleWait(&wDummy, &wIdleDeadline);
  1885. if (HIWORD(ulSpinPos))
  1886. {
  1887. m_pIJob->SetIdleWait(SCH_DEFAULT_IDLE_TIME, wIdleDeadline);
  1888. }
  1889. else
  1890. {
  1891. m_pIJob->SetIdleWait(LOWORD(ulSpinPos), wIdleDeadline);
  1892. }
  1893. break;
  1894. }
  1895. default:
  1896. Win4Assert(0 && "Unexpected");
  1897. }
  1898. }
  1899. LRESULT
  1900. CSchedulePage::_OnTimer(
  1901. UINT idTimer)
  1902. {
  1903. TRACE(CSchedulePage, _OnTimer);
  1904. //
  1905. // If this isn't the right timer, ignore it.
  1906. //
  1907. // If one of the comboboxes holding data needed to build the trigger is
  1908. // in the dropped-down state (and therefore may not have a valid
  1909. // selection), don't try to update the trigger. leave the timer
  1910. // running so we get another chance to update.
  1911. //
  1912. // Otherwise, save current trigger settings, update the string displayed
  1913. // at the top of the page, and get rid of the timer.
  1914. //
  1915. if (idTimer == IDT_UPDATE_TRIGGER_STRING && s_iCbx == -1)
  1916. {
  1917. _SaveTriggerSettings();
  1918. _UpdateTriggerString();
  1919. _DeleteTimerToUpdateTriggerStr();
  1920. }
  1921. else
  1922. {
  1923. DEBUG_OUT((DEB_IWARN,
  1924. "Ignoring timer message (%s)\n",
  1925. idTimer != IDT_UPDATE_TRIGGER_STRING ?
  1926. "foreign timer" :
  1927. "combobox down"));
  1928. }
  1929. return 0;
  1930. }
  1931. LRESULT
  1932. CSchedulePage::_OnPSNSetActive(
  1933. LPARAM lParam)
  1934. {
  1935. TRACE(CSchedulePage, _OnPSNSetActive);
  1936. m_fInInit = TRUE;
  1937. Win4Assert(s_iCbx == -1); // can't have a combo open yet
  1938. //
  1939. // Show application icon
  1940. //
  1941. SendDlgItemMessage(Hwnd(), idc_icon, STM_SETICON,
  1942. (WPARAM)m_pIconHelper->hiconJob, 0L);
  1943. //
  1944. // single or multiple scheds
  1945. //
  1946. if (m_fShowingMultiSchedsOnKillActive != m_fShowMultiScheds)
  1947. {
  1948. _ShowTriggerStringDispCtrls();
  1949. if (m_fShowMultiScheds == FALSE)
  1950. {
  1951. m_indexCbxTriggers = 0; // reset to zero
  1952. //
  1953. // Show the first trigger
  1954. //
  1955. HWND hwnd;
  1956. if (hwnd = _hCtrl(cbx_triggers))
  1957. {
  1958. m_pcjtCurr = (CJobTrigger *) ComboBox_GetItemData(hwnd, 0);
  1959. }
  1960. _RefreshPage();
  1961. }
  1962. else
  1963. {
  1964. _UpdateTriggerString();
  1965. }
  1966. }
  1967. else
  1968. {
  1969. _UpdateTriggerString();
  1970. }
  1971. //
  1972. // Make sure IdleWait is syncronized with Settings page changes.
  1973. //
  1974. _UpdateIdleControls();
  1975. //
  1976. // Create timer to update trigger
  1977. //
  1978. _CreateTimerToUpdateTriggerStr();
  1979. m_fInInit = FALSE;
  1980. return CPropPage::_OnPSNSetActive(lParam);
  1981. }
  1982. LRESULT
  1983. CSchedulePage::_OnPSNKillActive(
  1984. LPARAM lParam)
  1985. {
  1986. TRACE(CSchedulePage, _OnPSNKillActive);
  1987. if (_PerformSanityChkOnCurrTrigger() == FALSE)
  1988. {
  1989. // Returns TRUE to prevent the page from losing the activation
  1990. SetWindowLongPtr(m_hPage, DWLP_MSGRESULT, TRUE);
  1991. return TRUE;
  1992. }
  1993. m_fShowingMultiSchedsOnKillActive = m_fShowMultiScheds;
  1994. //
  1995. // Save the current trigger
  1996. //
  1997. _SaveTriggerSettings();
  1998. //
  1999. // Make sure Settings page is syncronized with IdleWait changes.
  2000. //
  2001. WORD wDummy;
  2002. WORD wIdleDeadline;
  2003. HRESULT hr = m_pIJob->GetIdleWait(&wDummy, &wIdleDeadline);
  2004. CHECK_HRESULT(hr);
  2005. ULONG ulSpinPos = Spin_GetPos(Hwnd(), sch_spin_idle_min);
  2006. if (HIWORD(ulSpinPos))
  2007. {
  2008. m_pIJob->SetIdleWait(SCH_DEFAULT_IDLE_TIME, wIdleDeadline);
  2009. }
  2010. else
  2011. {
  2012. m_pIJob->SetIdleWait(LOWORD(ulSpinPos), wIdleDeadline);
  2013. }
  2014. //
  2015. // kill timer here
  2016. //
  2017. _DeleteTimerToUpdateTriggerStr();
  2018. return CPropPage::_OnPSNKillActive(lParam);
  2019. }
  2020. LRESULT
  2021. CSchedulePage::_OnDateTimeChange(
  2022. LPARAM lParam)
  2023. {
  2024. TRACE(CSchedulePage, _OnDateTimeChange);
  2025. m_pcjtCurr->DirtyTrigger();
  2026. _EnableApplyButton();
  2027. _CreateTimerToUpdateTriggerStr();
  2028. return CPropPage::_OnDateTimeChange(lParam);
  2029. }
  2030. LRESULT
  2031. CSchedulePage::_OnSpinDeltaPos(
  2032. NM_UPDOWN * pnmud)
  2033. {
  2034. m_pcjtCurr->DirtyTrigger();
  2035. _CreateTimerToUpdateTriggerStr();
  2036. return CPropPage::_OnSpinDeltaPos(pnmud);
  2037. }
  2038. LRESULT
  2039. CSchedulePage::_OnWinIniChange(
  2040. WPARAM wParam,
  2041. LPARAM lParam)
  2042. {
  2043. TRACE(CSchedulePage, _OnWinIniChange);
  2044. UpdateTimeFormat(m_tszTimeFormat, ARRAYLEN(m_tszTimeFormat));
  2045. HWND hwnd;
  2046. if (hwnd = _hCtrl(dp_start_time)) DateTime_SetFormat(hwnd, m_tszTimeFormat);
  2047. if (hwnd = _hCtrl(once_dp_date)) DateTime_SetFormat(hwnd, NULL);
  2048. return 0;
  2049. }
  2050. void
  2051. CSchedulePage::_UpdateTriggerString(void)
  2052. {
  2053. TRACE(CSchedulePage, _UpdateTriggerString);
  2054. if (m_pcjtCurr == 0)
  2055. {
  2056. // No triggers
  2057. return;
  2058. }
  2059. TCHAR tcBuff[SCH_XBIGBUF_LEN];
  2060. m_pcjtCurr->TriggerString(m_fShowMultiScheds, tcBuff, SCH_XBIGBUF_LEN);
  2061. if (m_fShowMultiScheds == TRUE)
  2062. {
  2063. HWND hCombo = _hCtrl(cbx_triggers);
  2064. if (!hCombo)
  2065. {
  2066. return;
  2067. }
  2068. ComboBox_DeleteString(hCombo, m_indexCbxTriggers);
  2069. int iNew = ComboBox_InsertString(hCombo, m_indexCbxTriggers, tcBuff);
  2070. Win4Assert((UINT)iNew == m_indexCbxTriggers);
  2071. ComboBox_SetItemData(hCombo, iNew, m_pcjtCurr);
  2072. ComboBox_SetCurSel(hCombo, m_indexCbxTriggers);
  2073. }
  2074. else
  2075. {
  2076. // single trigger
  2077. SetDlgItemText(Hwnd(), txt_trigger, tcBuff);
  2078. }
  2079. }
  2080. LRESULT
  2081. CSchedulePage::_OnApply(void)
  2082. {
  2083. TRACE(CSchedulePage, _OnApply);
  2084. if (m_fDirty == FALSE)
  2085. {
  2086. return TRUE;
  2087. }
  2088. if (_PerformSanityChkOnCurrTrigger() == FALSE)
  2089. {
  2090. SetWindowLongPtr(Hwnd(), DWLP_MSGRESULT, FALSE);
  2091. return FALSE;
  2092. }
  2093. HRESULT hr = S_OK;
  2094. do
  2095. {
  2096. /////////////////////////////////////////////////////////////////////
  2097. //
  2098. // During the first pass do not delete triggers, since deleting
  2099. // triggers changes the trigger ids in the in memory job. So in
  2100. // the first pass:
  2101. // - save changes to existing triggers (if any)
  2102. // - set pcjtLastOriginal to the trigger with the largest ID of
  2103. // those originally loaded
  2104. // - add new triggers (if any)
  2105. //
  2106. WORD wTriggerID = 0;
  2107. ITaskTrigger * pIJobTrigger = NULL;
  2108. CJobTrigger * pcjtLastOriginal = NULL;
  2109. for (CJobTrigger *pcjt = m_cjtList.First();
  2110. pcjt != NULL;
  2111. pcjt = pcjt->Next())
  2112. {
  2113. wTriggerID = pcjt->GetTriggerID();
  2114. if (wTriggerID < m_cTriggersPrev)
  2115. {
  2116. pcjtLastOriginal = pcjt;
  2117. if (pcjt->IsTriggerDirty() == TRUE)
  2118. {
  2119. hr = m_pIJob->GetTrigger(wTriggerID, &pIJobTrigger);
  2120. CHECK_HRESULT(hr);
  2121. BREAK_ON_FAIL(hr);
  2122. }
  2123. else
  2124. {
  2125. pIJobTrigger = NULL;
  2126. }
  2127. }
  2128. else
  2129. {
  2130. WORD wTemp;
  2131. hr = m_pIJob->CreateTrigger(&wTemp, &pIJobTrigger);
  2132. CHECK_HRESULT(hr);
  2133. BREAK_ON_FAIL(hr);
  2134. }
  2135. if (pIJobTrigger != NULL)
  2136. {
  2137. hr = pIJobTrigger->SetTrigger(&pcjt->m_jt);
  2138. pIJobTrigger->Release();
  2139. CHECK_HRESULT(hr);
  2140. BREAK_ON_FAIL(hr);
  2141. }
  2142. }
  2143. BREAK_ON_FAIL(hr);
  2144. //
  2145. // Delete triggers in the decreasing order of Trigger ids, since
  2146. // the trigger ids in memory change.
  2147. //
  2148. if (m_cTriggersPrev && pcjtLastOriginal)
  2149. {
  2150. WORD wSequential = m_cTriggersPrev - 1;
  2151. pcjt = pcjtLastOriginal;
  2152. //
  2153. // There were some triggers originally && not all have been
  2154. // deleted.
  2155. //
  2156. // Go backwards sequentially through the original trigger IDs.
  2157. // Wherever we find a remaining trigger that is out of sync with
  2158. // wSequential, then the original trigger with ID wSequential must
  2159. // have been deleted in the UI, so we delete it on the job.
  2160. //
  2161. while (pcjt)
  2162. {
  2163. if (pcjt->GetTriggerID() < wSequential)
  2164. {
  2165. hr = m_pIJob->DeleteTrigger(wSequential);
  2166. CHECK_HRESULT(hr);
  2167. BREAK_ON_FAIL(hr);
  2168. }
  2169. else
  2170. {
  2171. pcjt = pcjt->Prev();
  2172. }
  2173. wSequential--;
  2174. }
  2175. //
  2176. // Special case deletions from the start of the list
  2177. //
  2178. wSequential = m_cjtList.First()->GetTriggerID();
  2179. while (wSequential > 0)
  2180. {
  2181. hr = m_pIJob->DeleteTrigger(--wSequential);
  2182. CHECK_HRESULT(hr);
  2183. BREAK_ON_FAIL(hr);
  2184. }
  2185. }
  2186. else if (m_cTriggersPrev)
  2187. {
  2188. WORD wSequential;
  2189. //
  2190. // All the original triggers were deleted in the ui.
  2191. //
  2192. for (wSequential = m_cTriggersPrev; wSequential; )
  2193. {
  2194. hr = m_pIJob->DeleteTrigger(--wSequential);
  2195. CHECK_HRESULT(hr);
  2196. BREAK_ON_FAIL(hr);
  2197. }
  2198. }
  2199. BREAK_ON_FAIL(hr);
  2200. //
  2201. // Re-number the trigger IDs, since this would have changed for
  2202. // the job.
  2203. //
  2204. // NOTE: This is was what we would have if we did a reload of
  2205. // the job.
  2206. //
  2207. m_wNextTriggerId = 0;
  2208. for (pcjt = m_cjtList.First();
  2209. pcjt != NULL;
  2210. pcjt = pcjt->Next())
  2211. {
  2212. pcjt->SetTriggerID(m_wNextTriggerId++);
  2213. }
  2214. m_cTriggersPrev = m_wNextTriggerId;
  2215. //
  2216. // Reload the trigger strings.
  2217. //
  2218. HWND hwnd;
  2219. if (hwnd = _hCtrl(cbx_triggers))
  2220. {
  2221. ComboBox_ResetContent(hwnd);
  2222. _LoadTriggerStrings();
  2223. if (m_fShowMultiScheds == TRUE)
  2224. {
  2225. ComboBox_SetCurSel(hwnd, m_indexCbxTriggers);
  2226. m_pcjtCurr = (CJobTrigger *) ComboBox_GetItemData(hwnd, m_indexCbxTriggers);
  2227. }
  2228. }
  2229. //
  2230. // reset dirty flag
  2231. //
  2232. m_fDirty = FALSE;
  2233. //
  2234. // If evrything went well see if the other pages are ready to
  2235. // save the job to storage.
  2236. //
  2237. if ((m_fPersistChanges == TRUE) &&
  2238. (PropSheet_QuerySiblings(GetParent(Hwnd()),
  2239. QUERY_READY_TO_BE_SAVED, 0))
  2240. == 0)
  2241. {
  2242. //
  2243. // Save the job file to storage.
  2244. //
  2245. // First, fetch general page task, application dirty status flags.
  2246. // Default to not dirty if the general page isn't present.
  2247. //
  2248. BOOL fTaskApplicationChange = FALSE;
  2249. PropSheet_QuerySiblings(GetParent(Hwnd()),
  2250. QUERY_TASK_APPLICATION_DIRTY_STATUS,
  2251. (LPARAM)&fTaskApplicationChange);
  2252. BOOL fTaskAccountChange = FALSE;
  2253. PropSheet_QuerySiblings(GetParent(Hwnd()),
  2254. QUERY_TASK_ACCOUNT_INFO_DIRTY_STATUS,
  2255. (LPARAM)&fTaskAccountChange);
  2256. BOOL fSuppressAccountInfoRequest = FALSE;
  2257. PropSheet_QuerySiblings(GetParent(Hwnd()),
  2258. QUERY_SUPPRESS_ACCOUNT_INFO_REQUEST_FLAG,
  2259. (LPARAM)&fSuppressAccountInfoRequest);
  2260. hr = JFSaveJob(Hwnd(),
  2261. m_pIJob,
  2262. this->GetPlatformId() == VER_PLATFORM_WIN32_NT &&
  2263. this->IsTaskInTasksFolder(),
  2264. fTaskAccountChange,
  2265. fTaskApplicationChange,
  2266. fSuppressAccountInfoRequest);
  2267. CHECK_HRESULT(hr);
  2268. BREAK_ON_FAIL(hr);
  2269. PropSheet_QuerySiblings(GetParent(Hwnd()),
  2270. RESET_TASK_APPLICATION_DIRTY_STATUS, 0);
  2271. PropSheet_QuerySiblings(GetParent(Hwnd()),
  2272. RESET_TASK_ACCOUNT_INFO_DIRTY_STATUS, 0);
  2273. PropSheet_QuerySiblings(GetParent(Hwnd()),
  2274. RESET_SUPPRESS_ACCOUNT_INFO_REQUEST_FLAG, 0);
  2275. //
  2276. // Instruct the general page to refresh account information.
  2277. //
  2278. PropSheet_QuerySiblings(GetParent(Hwnd()),
  2279. TASK_ACCOUNT_CHANGE_NOTIFY, 0);
  2280. }
  2281. } while (0);
  2282. if (FAILED(hr))
  2283. {
  2284. if (hr == E_OUTOFMEMORY)
  2285. {
  2286. _ErrorDialog(IERR_OUT_OF_MEMORY);
  2287. }
  2288. else if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
  2289. {
  2290. _ErrorDialog(IERR_FILE_NOT_FOUND);
  2291. }
  2292. else if (hr == HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED))
  2293. {
  2294. _ErrorDialog(IERR_ACCESS_DENIED);
  2295. }
  2296. else
  2297. {
  2298. _ErrorDialog(IERR_INTERNAL_ERROR, hr);
  2299. }
  2300. }
  2301. return TRUE;
  2302. }
  2303. LRESULT
  2304. CSchedulePage::_OnDestroy(void)
  2305. {
  2306. _DeleteTimerToUpdateTriggerStr();
  2307. return 0;
  2308. }
  2309. LRESULT
  2310. CSchedulePage::_OnPSMQuerySibling(
  2311. WPARAM wParam,
  2312. LPARAM lParam)
  2313. {
  2314. INT_PTR iRet = 0;
  2315. switch (wParam)
  2316. {
  2317. case QUERY_READY_TO_BE_SAVED:
  2318. iRet = (int)m_fDirty;
  2319. break;
  2320. case GET_ICON_HELPER:
  2321. iRet = (INT_PTR)m_pIconHelper;
  2322. break;
  2323. }
  2324. SetWindowLongPtr(Hwnd(), DWLP_MSGRESULT, iRet);
  2325. return iRet;
  2326. }
  2327. BOOL
  2328. CSchedulePage::_PerformSanityChkOnCurrTrigger(void)
  2329. {
  2330. if (m_pcjtCurr == 0)
  2331. {
  2332. // No triggers
  2333. return TRUE;
  2334. }
  2335. HWND hwnd = _hCtrl(cbx_trigger_type);
  2336. if (!hwnd)
  2337. {
  2338. return FALSE;
  2339. }
  2340. int iCur = ComboBox_GetCurSel(hwnd);
  2341. Win4Assert(iCur >= 0);
  2342. ULONG ul;
  2343. UINT i;
  2344. UINT idsErrStr = 0;
  2345. switch (iCur)
  2346. {
  2347. case INDEX_DAILY:
  2348. ul = GetDlgItemInt(Hwnd(), daily_txt_every, NULL, FALSE);
  2349. if (ul <= 0)
  2350. {
  2351. Spin_SetPos(Hwnd(), daily_spin_every, 1);
  2352. idsErrStr = IERR_INVALID_DAYILY_EVERY;
  2353. }
  2354. break;
  2355. case INDEX_WEEKLY:
  2356. ul = GetDlgItemInt(Hwnd(), weekly_txt_every, NULL, FALSE);
  2357. if (ul <= 0)
  2358. {
  2359. Spin_SetPos(Hwnd(), weekly_spin_every, 1);
  2360. idsErrStr = IERR_INVALID_WEEKLY_EVERY;
  2361. }
  2362. else
  2363. {
  2364. idsErrStr = IERR_INVALID_WEEKLY_TASK;
  2365. for (i=0; i < ARRAYLEN(g_aDayData); i++)
  2366. {
  2367. if (IsDlgButtonChecked(Hwnd(), g_aDayData[i].idCtrl)
  2368. == BST_CHECKED)
  2369. {
  2370. idsErrStr = 0;
  2371. break;
  2372. }
  2373. }
  2374. }
  2375. break;
  2376. case INDEX_MONTHLY:
  2377. if (IsDlgButtonChecked(Hwnd(), md_rb) == BST_CHECKED)
  2378. {
  2379. //
  2380. // It's a monthly date trigger. Get the spin control position.
  2381. // Complain if it's not a valid day number for any month, i.e.,
  2382. // if it's < 1 or > 31.
  2383. //
  2384. ul = GetDlgItemInt(Hwnd(), md_txt, NULL, FALSE);
  2385. if (ul <= 0)
  2386. {
  2387. Spin_SetPos(Hwnd(), md_spin, 1);
  2388. idsErrStr = IERR_MONTHLY_DATE_LT0;
  2389. break;
  2390. }
  2391. if (ul > 31)
  2392. {
  2393. Spin_SetPos(Hwnd(), md_spin, 31);
  2394. idsErrStr = IERR_MONTHLY_DATE_GT31;
  2395. break;
  2396. }
  2397. //
  2398. // Complain if the date specified does not fall within any of the
  2399. // months selected (e.g., Feb 31 is an error, Jan+Feb 31 is
  2400. // acceptable).
  2401. //
  2402. TASK_TRIGGER jt = m_pcjtCurr->m_jt;
  2403. jt.Type.MonthlyDate.rgfDays = (1 << (ul - 1));
  2404. if (!IsValidMonthlyDateTrigger(&jt))
  2405. {
  2406. idsErrStr = IERR_MONTHLY_DATE_INVALID;
  2407. break;
  2408. }
  2409. }
  2410. break;
  2411. default:
  2412. break;
  2413. }
  2414. if (idsErrStr != 0)
  2415. {
  2416. _ErrorDialog(idsErrStr);
  2417. return FALSE;
  2418. }
  2419. return TRUE;
  2420. }
  2421. //+--------------------------------------------------------------------------
  2422. //
  2423. // Function: SkipResourceTemplateArray
  2424. //
  2425. // Synopsis: Return a pointer to the first byte after the resource
  2426. // template array at [pbCur].
  2427. //
  2428. // Arguments: [pbCur] - points to resource template array to skip.
  2429. //
  2430. // Returns: [pbCur] + size of resource template array
  2431. //
  2432. // History: 08-01-1997 DavidMun Created
  2433. //
  2434. //---------------------------------------------------------------------------
  2435. LPCBYTE
  2436. SkipResourceTemplateArray(
  2437. LPCBYTE pbCur)
  2438. {
  2439. //
  2440. // Menu/class array is either 0x0000, 0xFFFF 0x????, or a null terminated
  2441. // Unicode string.
  2442. //
  2443. if (!*(USHORT *)pbCur)
  2444. {
  2445. pbCur += sizeof USHORT; // no menu
  2446. }
  2447. else if (*(USHORT *)pbCur == 0xFFFF)
  2448. {
  2449. pbCur += 2 * sizeof(USHORT);
  2450. }
  2451. else
  2452. {
  2453. pbCur += sizeof(WCHAR) * (1 + lstrlenW((LPCWSTR) pbCur));
  2454. }
  2455. return pbCur;
  2456. }
  2457. #define SCHEDULE_PAGE_WIDTH 253
  2458. HRESULT
  2459. GetSchedulePage(
  2460. ITask * pIJob,
  2461. LPTSTR ptszTaskPath,
  2462. BOOL fPersistChanges,
  2463. HPROPSHEETPAGE * phpage)
  2464. {
  2465. Win4Assert(pIJob != NULL);
  2466. Win4Assert(phpage != NULL);
  2467. //
  2468. // If there are no triggers show multiple trigger UI, so that
  2469. // the user can use 'New' push button to create a trigger.
  2470. //
  2471. HRESULT hr = S_OK;
  2472. LPTSTR ptszPathCopy;
  2473. do
  2474. {
  2475. //
  2476. // Get the job name.
  2477. //
  2478. if (ptszTaskPath != NULL)
  2479. {
  2480. //
  2481. // Create a copy.
  2482. //
  2483. ptszPathCopy = NewDupString(ptszTaskPath);
  2484. if (ptszPathCopy == NULL)
  2485. {
  2486. hr = E_OUTOFMEMORY;
  2487. CHECK_HRESULT(hr);
  2488. break;
  2489. }
  2490. }
  2491. else
  2492. {
  2493. //
  2494. // Obtain the job path from the interfaces.
  2495. //
  2496. hr = GetJobPath(pIJob, &ptszPathCopy);
  2497. }
  2498. BREAK_ON_FAIL(hr);
  2499. WORD cTriggers = 0;
  2500. hr = pIJob->GetTriggerCount(&cTriggers);
  2501. if (FAILED(hr))
  2502. {
  2503. delete ptszPathCopy;
  2504. CHECK_HRESULT(hr);
  2505. break;
  2506. }
  2507. // Show single trigger only if count of triggers == 1.
  2508. BOOL fShowMultipleTriggers = (cTriggers == 1) ? FALSE : TRUE;
  2509. CSchedulePage * pPage = new CSchedulePage(
  2510. pIJob,
  2511. ptszPathCopy,
  2512. fShowMultipleTriggers,
  2513. fPersistChanges);
  2514. if (pPage == NULL)
  2515. {
  2516. delete ptszPathCopy;
  2517. hr = E_OUTOFMEMORY;
  2518. CHECK_HRESULT(hr);
  2519. break;
  2520. }
  2521. //
  2522. // To make localization feasible, the trigger controls are specified
  2523. // in the dialog template as non overlapping. That is, each set of
  2524. // trigger controls has its own area on the dialog.
  2525. //
  2526. // Each set of controls is spaced out to the right.
  2527. //
  2528. // The following code loads the template, determines its size, makes
  2529. // a copy, then resizes the copy to normal propsheet page width and
  2530. // moves each set of trigger controls so that they all overlap.
  2531. //
  2532. // TODO - determine whether all this is still necessary.
  2533. // I removed the resizing code, and simply set the size in the dialog
  2534. // template.
  2535. // Now the contols are still spaced to the right, but are 'outside'
  2536. // the ostensible window.
  2537. HRSRC hrsDlg = FindResource(g_hInstance,
  2538. MAKEINTRESOURCE(schedule_page),
  2539. RT_DIALOG);
  2540. if (!hrsDlg)
  2541. {
  2542. DEBUG_OUT_LASTERROR;
  2543. hr = HRESULT_FROM_WIN32(GetLastError());
  2544. break;
  2545. }
  2546. //
  2547. // Per SDK: Both Windows 95 and Windows NT automatically free
  2548. // resources. You do not need to call the FreeResource function to
  2549. // free a resource loaded by using the LoadResource function.
  2550. //
  2551. HGLOBAL hglblDlg = LoadResource(g_hInstance, hrsDlg);
  2552. if (!hglblDlg)
  2553. {
  2554. DEBUG_OUT_LASTERROR;
  2555. hr = HRESULT_FROM_WIN32(GetLastError());
  2556. break;
  2557. }
  2558. //
  2559. // Per SDK: It is not necessary for Win32-based applications to
  2560. // unlock resources that were locked by the LockResource function.
  2561. //
  2562. LPVOID ptplDlg = (LPVOID) LockResource(hglblDlg);
  2563. if (!ptplDlg)
  2564. {
  2565. DEBUG_OUT_LASTERROR;
  2566. hr = HRESULT_FROM_WIN32(GetLastError());
  2567. break;
  2568. }
  2569. BOOL bDialogEx;
  2570. UINT uiStyle;
  2571. USHORT iditCount;
  2572. //
  2573. // Handle DIALOGEX style template
  2574. //
  2575. if(((LPDLGTEMPLATE2) ptplDlg)->wSignature == 0xffff)
  2576. {
  2577. bDialogEx = TRUE;
  2578. uiStyle = ((LPDLGTEMPLATE2) ptplDlg)->style;
  2579. iditCount = ((LPDLGTEMPLATE2) ptplDlg)->cDlgItems;
  2580. }
  2581. else
  2582. {
  2583. bDialogEx = FALSE;
  2584. uiStyle = ((LPDLGTEMPLATE) ptplDlg)->style;
  2585. iditCount = ((LPDLGTEMPLATE) ptplDlg)->cdit;
  2586. }
  2587. //
  2588. // ptplDlg is in read-only memory. Make a writeable copy.
  2589. //
  2590. // Sure wish we could do this:
  2591. //
  2592. // ULONG cbTemplate = GlobalSize(hglblDlg);
  2593. //
  2594. // but hglblDlg isn't on the global heap.
  2595. //
  2596. // So we're forced to grovel through the template and determine its
  2597. // size.
  2598. //
  2599. LPCBYTE pbCur = (LPCBYTE) ptplDlg;
  2600. USHORT i;
  2601. //
  2602. // Advance to dialog template menu array, then skip it and the class
  2603. // array.
  2604. //
  2605. pbCur += bDialogEx ? sizeof DLGTEMPLATE2 : sizeof DLGTEMPLATE;
  2606. pbCur = SkipResourceTemplateArray(pbCur);
  2607. pbCur = SkipResourceTemplateArray(pbCur);
  2608. //
  2609. // Skip title array, which is a null-terminated Unicode string.
  2610. //
  2611. pbCur += sizeof(WCHAR) * (1 + lstrlenW((LPCWSTR) pbCur));
  2612. //
  2613. // Skip font info, if it is specified.
  2614. //
  2615. if (uiStyle & DS_SETFONT)
  2616. {
  2617. pbCur += sizeof USHORT;
  2618. if (bDialogEx)
  2619. {
  2620. pbCur += sizeof USHORT;
  2621. pbCur += sizeof BYTE;
  2622. pbCur += sizeof BYTE;
  2623. }
  2624. pbCur += sizeof(WCHAR) * (1 + lstrlenW((LPCWSTR) pbCur));
  2625. }
  2626. //
  2627. // Now skip the DLGITEMTEMPLATE structures.
  2628. //
  2629. for (i = 0; i < iditCount; i++)
  2630. {
  2631. //
  2632. // The DLGITEMTEMPLATE structures must be DWORD aligned, but pbCur
  2633. // may be only WORD aligned. Advance it if necessary to skip a pad
  2634. // WORD.
  2635. //
  2636. if ((ULONG_PTR) pbCur & 3)
  2637. {
  2638. pbCur += 4 - ((ULONG_PTR) pbCur & 3);
  2639. }
  2640. // DEBUG_OUT((DEB_ITRACE, "control id %u\n", ((DLGITEMTEMPLATE*)pbCur)->id));
  2641. // Skip to the start of the variable length data
  2642. pbCur += bDialogEx ? sizeof DLGITEMTEMPLATE2 : sizeof DLGITEMTEMPLATE;
  2643. // Skip the class array
  2644. if (*(USHORT *)pbCur == 0xFFFF)
  2645. {
  2646. pbCur += 2 * sizeof(USHORT);
  2647. }
  2648. else
  2649. {
  2650. pbCur += sizeof(WCHAR) * (1 + lstrlenW((LPCWSTR) pbCur));
  2651. }
  2652. // Skip the title array
  2653. if (*(USHORT *)pbCur == 0xFFFF)
  2654. {
  2655. pbCur += 2 * sizeof(USHORT);
  2656. }
  2657. else
  2658. {
  2659. pbCur += sizeof(WCHAR) * (1 + lstrlenW((LPCWSTR) pbCur));
  2660. }
  2661. //
  2662. // Creation data. Contrary to SDK docs, it does not start on
  2663. // DWORD boundary.
  2664. //
  2665. if (*(USHORT *)pbCur)
  2666. {
  2667. pbCur += sizeof(USHORT) * (*(USHORT *)pbCur);
  2668. }
  2669. else
  2670. {
  2671. pbCur += sizeof(USHORT);
  2672. }
  2673. }
  2674. //
  2675. // pbCur now points just past the end of the entire dialog template.
  2676. // Now that its size is known, copy it.
  2677. //
  2678. ULONG cbTemplate = (ULONG)(pbCur - (LPCBYTE) ptplDlg);
  2679. LPVOID ptplDlgCopy = (LPVOID) new BYTE[cbTemplate];
  2680. if (!ptplDlgCopy)
  2681. {
  2682. hr = E_OUTOFMEMORY;
  2683. CHECK_HRESULT(hr);
  2684. break;
  2685. }
  2686. CopyMemory(ptplDlgCopy, ptplDlg, cbTemplate);
  2687. //
  2688. // Modify the PROPSHEETPAGE struct member to indicate that the page
  2689. // is created from an in-memory template. The base class dtor will
  2690. // see the PSP_DLGINDIRECT flag and do a delete on the pResource.
  2691. //
  2692. pPage->m_psp.dwFlags |= PSP_DLGINDIRECT;
  2693. pPage->m_psp.pResource = (LPDLGTEMPLATE) ptplDlgCopy;
  2694. HPROPSHEETPAGE hpage = CreatePropertySheetPage(&pPage->m_psp);
  2695. if (hpage == NULL)
  2696. {
  2697. delete pPage;
  2698. delete [] ptplDlgCopy;
  2699. hr = E_OUTOFMEMORY;
  2700. CHECK_HRESULT(hr);
  2701. break;
  2702. }
  2703. *phpage = hpage;
  2704. } while (0);
  2705. return hr;
  2706. }
  2707. HRESULT
  2708. AddSchedulePage(
  2709. PROPSHEETHEADER &psh,
  2710. ITask * pIJob)
  2711. {
  2712. HPROPSHEETPAGE hpage = NULL;
  2713. HRESULT hr = GetSchedulePage(pIJob, NULL, TRUE, &hpage);
  2714. if (SUCCEEDED(hr))
  2715. {
  2716. psh.phpage[psh.nPages++] = hpage;
  2717. }
  2718. return hr;
  2719. }
  2720. HRESULT
  2721. AddSchedulePage(
  2722. LPFNADDPROPSHEETPAGE lpfnAddPage,
  2723. LPARAM cookie,
  2724. ITask * pIJob)
  2725. {
  2726. HPROPSHEETPAGE hpage = NULL;
  2727. HRESULT hr = GetSchedulePage(pIJob, NULL, TRUE, &hpage);
  2728. if (SUCCEEDED(hr))
  2729. {
  2730. if (!lpfnAddPage(hpage, cookie))
  2731. {
  2732. DestroyPropertySheetPage(hpage);
  2733. hr = E_FAIL;
  2734. CHECK_HRESULT(hr);
  2735. }
  2736. }
  2737. return hr;
  2738. }