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.

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