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.

3756 lines
101 KiB

  1. /*++
  2. Copyright (c) 1994-1998, Microsoft Corporation All rights reserved.
  3. Module Name:
  4. date.c
  5. Abstract:
  6. This module implements the textual representations of
  7. Day Month Year : Hours Min Seconds for the Date/Time applet.
  8. Revision History:
  9. --*/
  10. //
  11. // Include Files.
  12. //
  13. #include "timedate.h"
  14. #include <commctrl.h>
  15. #include <prsht.h>
  16. #include <regstr.h>
  17. #include <imm.h>
  18. #include "clock.h"
  19. #include "mapctl.h"
  20. #include "inettime.h"
  21. #include "rc.h"
  22. #include <help.h>
  23. #include <windows.h>
  24. #include <windowsx.h>
  25. //
  26. // Constant Declarations.
  27. //
  28. #define TZNAME_SIZE 128
  29. #define TZDISPLAYZ 128
  30. #define BIAS_ONE_HOUR (-60L)
  31. #define ZONE_IMAGE_SCALE (356)
  32. #define ZONE_BIAS_SCALE (-1440)
  33. #define ZONE_IMAGE_LEFT (120)
  34. #define ZONE_IMAGE_WIDTH (80)
  35. #define BIAS_PLUS_12 (12L * BIAS_ONE_HOUR)
  36. #define BIAS_MINUS_12 (- BIAS_PLUS_12)
  37. #define TZ_HIT_NONE (0)
  38. #define TZ_HIT_BASE (1)
  39. #define TZ_HIT_PARTIAL (2)
  40. #define TZ_HIT_EXACT (3)
  41. //
  42. // Global Variables.
  43. //
  44. TCHAR const szIntl[] = TEXT("intl");
  45. //
  46. // Default used if none could be found.
  47. //
  48. INTLSTRUCT IntlDef =
  49. {
  50. TEXT("Other Country"),
  51. 1, 0, 0, 0, 0, 2, 0, 1, 2, 1,
  52. TEXT("AM"),
  53. TEXT("PM"),
  54. TEXT("$"),
  55. TEXT(","),
  56. TEXT("."),
  57. TEXT("/"),
  58. TEXT(":"),
  59. TEXT(","),
  60. TEXT("dddd, MMMM dd, yyyy"),
  61. TEXT("M/d/yyyy"),
  62. TEXT("USA"),
  63. 1, 0, 1, 0, 0x0409,
  64. TEXT("hh:mm:ss tt"),
  65. 0, 1,
  66. TEXT(","),
  67. TEXT(".")
  68. };
  69. BOOL g_bFirstBoot = FALSE; // for first boot during setup
  70. int g_Time[3]; // time the user currently has set
  71. int g_LastTime[3]; // last displayed time - to stop flicker
  72. short wDateTime[7]; // values for first 7 date/time items
  73. short wPrevDateTime[7]; // only repaint fields if necessary
  74. BOOL fDateDirty;
  75. //
  76. // Formatting strings for AM and PM
  77. //
  78. TCHAR sz1159[12];
  79. TCHAR sz2359[12];
  80. //
  81. // Are we in 24 hour time. If not, is it AM or PM.
  82. //
  83. BOOL g_b24HR;
  84. BOOL g_bPM;
  85. //
  86. // This flag indicates if the user has tried to change the time.
  87. // If so, then we stop providing the system time and use the
  88. // time that we store internally. We send the clock control our
  89. // TimeProvider function.
  90. //
  91. WORD g_Modified = 0;
  92. WORD g_WasModified = 0;
  93. //
  94. // Which of the HMS MDY have leading zeros.
  95. //
  96. BOOL g_bLZero[6] = {FALSE, TRUE, TRUE, FALSE, FALSE, FALSE};
  97. //
  98. // Ranges of HMS MDY
  99. //
  100. struct
  101. {
  102. int nMax;
  103. int nMin;
  104. } g_sDateInfo[] =
  105. {
  106. 23, 0,
  107. 59, 0,
  108. 59, 0,
  109. 12, 1,
  110. 31, 1,
  111. 2099, 1980,
  112. };
  113. //
  114. // Time Zone info globals.
  115. //
  116. int g_nTimeZones = 0;
  117. TIME_ZONE_INFORMATION g_tziCurrent, *g_ptziCurrent = NULL;
  118. //
  119. // Registry location for Time Zone information.
  120. //
  121. TCHAR c_szTimeZones[] = TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones");
  122. //
  123. // Time Zone data value keys.
  124. //
  125. TCHAR c_szTZDisplayName[] = TEXT("Display");
  126. TCHAR c_szTZStandardName[] = TEXT("Std");
  127. TCHAR c_szTZDaylightName[] = TEXT("Dlt");
  128. TCHAR c_szTZI[] = TEXT("TZI");
  129. TCHAR c_szTZMapInfo[] = TEXT("MapID");
  130. //
  131. // IME globals.
  132. //
  133. HIMC g_PrevIMCForDateField;
  134. //
  135. // Context Help Ids.
  136. //
  137. const DWORD aDateTimeHelpIds[] =
  138. {
  139. IDD_GROUPBOX1, IDH_DATETIME_DATE_GROUP,
  140. IDD_GROUPBOX2, IDH_DATETIME_TIME,
  141. DATETIME_CURTZ, IDH_DATETIME_CURRENT_TIME_ZONE,
  142. DATETIME_CALENDAR, IDH_DATETIME_DATE,
  143. DATETIME_CLOCK, IDH_DATETIME_TIME,
  144. DATETIME_TBORDER, IDH_DATETIME_TIME,
  145. DATETIME_HOUR, IDH_DATETIME_TIME,
  146. DATETIME_TSEP1, IDH_DATETIME_TIME,
  147. DATETIME_MINUTE, IDH_DATETIME_TIME,
  148. DATETIME_TSEP2, IDH_DATETIME_TIME,
  149. DATETIME_SECOND, IDH_DATETIME_TIME,
  150. DATETIME_AMPM, IDH_DATETIME_TIME,
  151. DATETIME_TARROW, IDH_DATETIME_TIME,
  152. DATETIME_MONTHNAME, IDH_DATETIME_MONTH,
  153. DATETIME_YEAR, IDH_DATETIME_YEAR,
  154. DATETIME_YARROW, IDH_DATETIME_YEAR,
  155. IDD_TIMEZONES, IDH_DATETIME_TIMEZONE,
  156. // IDD_TIMEMAP, IDH_DATETIME_BITMAP,
  157. IDD_TIMEMAP, NO_HELP,
  158. IDD_AUTOMAGIC, IDH_DATETIME_DAYLIGHT_SAVE,
  159. 0, 0
  160. };
  161. //
  162. // Typedef Declarations.
  163. //
  164. //
  165. // Registry info goes in this structure.
  166. //
  167. typedef struct tagTZINFO
  168. {
  169. struct tagTZINFO *next;
  170. TCHAR szDisplayName[TZDISPLAYZ];
  171. TCHAR szStandardName[TZNAME_SIZE];
  172. TCHAR szDaylightName[TZNAME_SIZE];
  173. int ComboIndex;
  174. int SeaIndex;
  175. int LandIndex;
  176. int MapLeft;
  177. int MapWidth;
  178. LONG Bias;
  179. LONG StandardBias;
  180. LONG DaylightBias;
  181. SYSTEMTIME StandardDate;
  182. SYSTEMTIME DaylightDate;
  183. } TZINFO, *PTZINFO;
  184. //
  185. // State info for the time zone page.
  186. //
  187. typedef struct
  188. {
  189. PTZINFO zone;
  190. BOOL initializing;
  191. PTZINFO lookup[MAPCTL_MAX_INDICES];
  192. } TZPAGE_STATE;
  193. DWORD GetTextExtent(
  194. HDC hdc,
  195. LPCTSTR lpsz,
  196. int cb);
  197. //
  198. //for TS time zone redirection
  199. //
  200. extern BOOL g_bShowOnlyTimeZone;
  201. ////////////////////////////////////////////////////////////////////////////
  202. //
  203. // ParseDateElement
  204. //
  205. // Assumes that the character pointed to by pszElement is a
  206. // 'M', 'd', or 'y', and checks if the string indicates a leading zero
  207. // or century. The return value is a pointer to the next character,
  208. // which should be a separator or NULL. A return value of NULL indicates
  209. // an error.
  210. //
  211. ////////////////////////////////////////////////////////////////////////////
  212. LPTSTR ParseDateElement(
  213. LPTSTR pszElement,
  214. BOOL *pbLZero)
  215. {
  216. //
  217. // Check for valid character.
  218. //
  219. switch (*pszElement)
  220. {
  221. case ( TEXT('y') ) :
  222. case ( TEXT('M') ) :
  223. case ( TEXT('d') ) :
  224. {
  225. break;
  226. }
  227. default:
  228. {
  229. return (NULL);
  230. }
  231. }
  232. ++pszElement;
  233. if (*pszElement != *(pszElement - 1))
  234. {
  235. *pbLZero = 0;
  236. }
  237. else
  238. {
  239. *pbLZero = 1;
  240. if (*pszElement++ == TEXT('y'))
  241. {
  242. if (!(*pszElement == TEXT('y')))
  243. {
  244. *pbLZero = 0;
  245. }
  246. else
  247. {
  248. if (!(*++pszElement == TEXT('y')))
  249. {
  250. //
  251. // Found 3 y's, invalid format.
  252. //
  253. return (NULL);
  254. }
  255. else
  256. {
  257. ++pszElement;
  258. }
  259. }
  260. }
  261. }
  262. return (pszElement);
  263. }
  264. int rgMoveTimeControls [] =
  265. {
  266. DATETIME_HOUR,
  267. DATETIME_MINUTE,
  268. DATETIME_SECOND,
  269. DATETIME_TSEP1,
  270. DATETIME_TSEP2
  271. };
  272. ////////////////////////////////////////////////////////////////////////////
  273. //
  274. // AdjustAMPMPosition
  275. //
  276. ////////////////////////////////////////////////////////////////////////////
  277. void AdjustAMPMPosition(HWND hwnd)
  278. {
  279. TCHAR szTimePrefix[5];
  280. static BOOL fMoved = FALSE;
  281. GetLocaleInfo(LOCALE_USER_DEFAULT,
  282. LOCALE_ITIMEMARKPOSN,
  283. szTimePrefix,
  284. ARRAYSIZE(szTimePrefix));
  285. if (!fMoved && szTimePrefix[0] == TEXT('1'))
  286. {
  287. RECT rLeftCtl, rAMPMCtl, rCurrCtl;
  288. HWND hwndAMPM, hwndCurr;
  289. int i, width;
  290. POINT pt;
  291. fMoved = TRUE;
  292. //Get rect of left most control (hours)
  293. GetWindowRect(GetDlgItem(hwnd, DATETIME_HOUR), &rLeftCtl);
  294. //Get rect of AM PM control
  295. hwndAMPM = GetDlgItem(hwnd, DATETIME_AMPM);
  296. GetWindowRect(hwndAMPM, &rAMPMCtl);
  297. width = rAMPMCtl.right - rAMPMCtl.left;
  298. //Shift all controls right by the AM PM control width
  299. for (i = 0; i < ARRAYSIZE(rgMoveTimeControls); i++)
  300. {
  301. hwndCurr = GetDlgItem(hwnd, rgMoveTimeControls[i]);
  302. GetWindowRect(hwndCurr, &rCurrCtl);
  303. pt.x = rCurrCtl.left;
  304. pt.y = rCurrCtl.top;
  305. ScreenToClient(hwnd, &pt);
  306. MoveWindow(hwndCurr, pt.x + width,
  307. pt.y,
  308. rCurrCtl.right - rCurrCtl.left,
  309. rCurrCtl.bottom - rCurrCtl.top,
  310. TRUE);
  311. }
  312. //Move AM PM control left to where the hours were.
  313. pt.x = rLeftCtl.left;
  314. pt.y = rAMPMCtl.top;
  315. ScreenToClient(hwnd, &pt);
  316. MoveWindow(hwndAMPM, pt.x,
  317. pt.y,
  318. rAMPMCtl.right - rAMPMCtl.left,
  319. rAMPMCtl.bottom - rAMPMCtl.top,
  320. TRUE);
  321. }
  322. }
  323. ////////////////////////////////////////////////////////////////////////////
  324. //
  325. // MonthUpperBound
  326. //
  327. ////////////////////////////////////////////////////////////////////////////
  328. int _fastcall MonthUpperBound(
  329. int nMonth,
  330. int nYear)
  331. {
  332. switch (nMonth)
  333. {
  334. case ( 2 ) :
  335. {
  336. //
  337. // A year is a leap year if it is divisible by 4 and is not
  338. // a century year (multiple of 100) or if it is divisible by
  339. // 400.
  340. //
  341. return ( ((nYear % 4 == 0) &&
  342. ((nYear % 100 != 0) || (nYear % 400 == 0))) ? 29 : 28 );
  343. }
  344. case ( 4 ) :
  345. case ( 6 ) :
  346. case ( 9 ) :
  347. case ( 11 ) :
  348. {
  349. return (30);
  350. }
  351. }
  352. return (31);
  353. }
  354. ////////////////////////////////////////////////////////////////////////////
  355. //
  356. // IsAMPM
  357. //
  358. // True if PM.
  359. //
  360. ////////////////////////////////////////////////////////////////////////////
  361. BOOL IsAMPM(
  362. int iHour)
  363. {
  364. return ((iHour >= 12) ? 1 : 0);
  365. }
  366. ////////////////////////////////////////////////////////////////////////////
  367. //
  368. // GetDateTime
  369. //
  370. ////////////////////////////////////////////////////////////////////////////
  371. void GetDateTime()
  372. {
  373. SYSTEMTIME SystemTime;
  374. GetLocalTime(&SystemTime);
  375. wDateTime[HOUR] = SystemTime.wHour;
  376. wDateTime[MINUTE] = SystemTime.wMinute;
  377. wDateTime[SECOND] = SystemTime.wSecond;
  378. wDateTime[MONTH] = SystemTime.wMonth;
  379. wDateTime[DAY] = SystemTime.wDay;
  380. wDateTime[YEAR] = SystemTime.wYear;
  381. wDateTime[WEEKDAY] = SystemTime.wDayOfWeek;
  382. }
  383. ////////////////////////////////////////////////////////////////////////////
  384. //
  385. // GetTime
  386. //
  387. ////////////////////////////////////////////////////////////////////////////
  388. void GetTime()
  389. {
  390. SYSTEMTIME SystemTime;
  391. GetLocalTime(&SystemTime);
  392. wDateTime[HOUR] = SystemTime.wHour;
  393. wDateTime[MINUTE] = SystemTime.wMinute;
  394. wDateTime[SECOND] = SystemTime.wSecond;
  395. }
  396. ////////////////////////////////////////////////////////////////////////////
  397. //
  398. // GetDate
  399. //
  400. ////////////////////////////////////////////////////////////////////////////
  401. void GetDate()
  402. {
  403. SYSTEMTIME SystemTime;
  404. GetLocalTime(&SystemTime);
  405. wDateTime[MONTH] = SystemTime.wMonth;
  406. wDateTime[DAY] = SystemTime.wDay;
  407. wDateTime[YEAR] = SystemTime.wYear;
  408. wDateTime[WEEKDAY] = SystemTime.wDayOfWeek;
  409. fDateDirty = FALSE;
  410. }
  411. ////////////////////////////////////////////////////////////////////////////
  412. //
  413. // SetTime
  414. //
  415. ////////////////////////////////////////////////////////////////////////////
  416. void SetTime()
  417. {
  418. SYSTEMTIME SystemTime;
  419. SystemTime.wHour = wDateTime[HOUR];
  420. SystemTime.wMinute = wDateTime[MINUTE];
  421. SystemTime.wSecond = wDateTime[SECOND];
  422. SystemTime.wMilliseconds = 0;
  423. SystemTime.wMonth = wDateTime[MONTH];
  424. SystemTime.wDay = wDateTime[DAY];
  425. SystemTime.wYear = wDateTime[YEAR];
  426. SetLocalTime(&SystemTime);
  427. SetLocalTime(&SystemTime);
  428. fDateDirty = FALSE;
  429. }
  430. ////////////////////////////////////////////////////////////////////////////
  431. //
  432. // SetDate
  433. //
  434. ////////////////////////////////////////////////////////////////////////////
  435. void SetDate()
  436. {
  437. SYSTEMTIME SystemTime;
  438. SystemTime.wHour = wDateTime[HOUR];
  439. SystemTime.wMinute = wDateTime[MINUTE];
  440. SystemTime.wSecond = wDateTime[SECOND];
  441. SystemTime.wMilliseconds = 0;
  442. SystemTime.wMonth = wDateTime[MONTH];
  443. SystemTime.wDay = wDateTime[DAY];
  444. SystemTime.wYear = wDateTime[YEAR];
  445. SetLocalTime(&SystemTime);
  446. SetLocalTime(&SystemTime);
  447. fDateDirty = FALSE;
  448. }
  449. ////////////////////////////////////////////////////////////////////////////
  450. //
  451. // AdjustDelta
  452. //
  453. // Alters the variables in wDeltaDateTime, allowing a CANCEL button
  454. // to perform its job by resetting the time as if it had never been
  455. // touched. GetTime() & GetDate() should already have been called.
  456. //
  457. ////////////////////////////////////////////////////////////////////////////
  458. void AdjustDelta(
  459. HWND hDlg,
  460. int nIndex)
  461. {
  462. int nDelta;
  463. //
  464. // We dont do time this way any more.
  465. //
  466. if (nIndex <= SECOND && nIndex >= HOUR)
  467. {
  468. return;
  469. }
  470. //
  471. // Get position of the buddy from either the date or the time.
  472. //
  473. nDelta = (int)SendDlgItemMessage( hDlg,
  474. nIndex <= SECOND
  475. ? DATETIME_TARROW
  476. : DATETIME_YARROW,
  477. UDM_GETPOS,
  478. 0,
  479. 0L );
  480. if ((nIndex == YEAR) && !g_bLZero[YEAR])
  481. {
  482. //
  483. // Years before 80 are 2080.
  484. // Range is 1980...2079.
  485. //
  486. if (nDelta < 80)
  487. {
  488. nDelta += 2000;
  489. }
  490. else
  491. {
  492. nDelta += 1900;
  493. }
  494. }
  495. //
  496. // If our current recording of the time/date is not what we have
  497. // now, do deltas.
  498. //
  499. if (wDateTime[nIndex] != nDelta)
  500. {
  501. //
  502. // Previous value is current user's settings.
  503. //
  504. wPrevDateTime[nIndex] = wDateTime[nIndex] = (WORD)nDelta;
  505. fDateDirty = TRUE;
  506. //
  507. // If we are changing HMS, update the time.
  508. //
  509. if (nIndex <= SECOND)
  510. {
  511. nIndex = 0;
  512. }
  513. }
  514. }
  515. ////////////////////////////////////////////////////////////////////////////
  516. //
  517. // AdjustDeltaMonth
  518. //
  519. // Change the month part of wDateTime
  520. //
  521. ////////////////////////////////////////////////////////////////////////////
  522. extern int GetDaysOfTheMonth(int iMonth);
  523. void AdjustDeltaMonth(
  524. int iMonth)
  525. {
  526. GetTime();
  527. if (wDateTime[MONTH] != iMonth)
  528. {
  529. //
  530. // Make sure the current day is valid in the new month.
  531. //
  532. if (wDateTime[DAY] > (WORD)GetDaysOfTheMonth(iMonth))
  533. {
  534. wDateTime[DAY] = (WORD)GetDaysOfTheMonth(iMonth);
  535. }
  536. wPrevDateTime[MONTH] = wDateTime[MONTH] = (WORD)iMonth;
  537. fDateDirty = TRUE;
  538. g_sDateInfo[DAY].nMax = MonthUpperBound( wDateTime[MONTH],
  539. wDateTime[YEAR] );
  540. }
  541. }
  542. ////////////////////////////////////////////////////////////////////////////
  543. //
  544. // ReadShortDate
  545. //
  546. // Verify that pszDate is one of MDY, DMY, or YMD.
  547. //
  548. ////////////////////////////////////////////////////////////////////////////
  549. int ReadShortDate(
  550. LPTSTR pszDate,
  551. BOOL *pbMonth,
  552. BOOL *pbDay,
  553. BOOL *pbYear)
  554. {
  555. int i, nOrder;
  556. BOOL *pbOrder[3];
  557. TCHAR cHope[3];
  558. //
  559. // nOrder : 0 = MDY
  560. // 1 = DMY
  561. // 2 = YMD
  562. //
  563. switch (cHope[0] = *pszDate)
  564. {
  565. case ( TEXT('M') ) :
  566. {
  567. nOrder = 0;
  568. pbOrder[0] = pbMonth;
  569. break;
  570. }
  571. case ( TEXT('d') ) :
  572. {
  573. nOrder = 1;
  574. pbOrder[0] = pbDay;
  575. break;
  576. }
  577. case ( TEXT('y') ) :
  578. {
  579. nOrder = 2;
  580. pbOrder[0] = pbYear;
  581. break;
  582. }
  583. default :
  584. {
  585. return (FALSE);
  586. }
  587. }
  588. //
  589. // Sets element 1.
  590. //
  591. if (nOrder) // 1 2
  592. {
  593. cHope[1] = TEXT('M');
  594. pbOrder[1] = pbMonth;
  595. }
  596. else // 0
  597. {
  598. cHope[1] = TEXT('d');
  599. pbOrder[1] = pbDay;
  600. }
  601. //
  602. // Sets element 2.
  603. //
  604. if (nOrder == 2) // 2
  605. {
  606. cHope[2] = TEXT('d');
  607. pbOrder[2] = pbDay;
  608. }
  609. else // 0 1
  610. {
  611. cHope[2] = TEXT('y');
  612. pbOrder[2] = pbYear;
  613. }
  614. //
  615. // Verifies that pszDate is of the form MDY DMY YMD.
  616. //
  617. for (i = 0; i < 3; i++, pszDate++)
  618. {
  619. if (*pszDate != cHope[i])
  620. {
  621. return (-1 - nOrder);
  622. }
  623. if (!(pszDate = ParseDateElement(pszDate, pbOrder[i])))
  624. {
  625. return (-1 - nOrder);
  626. }
  627. }
  628. //
  629. // Success. Return MDY, DMY or YMD index.
  630. //
  631. return (nOrder);
  632. }
  633. ////////////////////////////////////////////////////////////////////////////
  634. //
  635. // GetMaxCharWidth
  636. //
  637. // Determine the widest digit (safety against variable pitch fonts).
  638. //
  639. ////////////////////////////////////////////////////////////////////////////
  640. int GetMaxCharWidth(
  641. HDC hDC)
  642. {
  643. UINT nNumWidth[10];
  644. UINT i, nMaxNumWidth;
  645. GetCharWidth32(hDC, TEXT('0'), TEXT('9'), nNumWidth);
  646. for (nMaxNumWidth = 0, i = 0; i < 10; i++)
  647. {
  648. if (nNumWidth[i] > nMaxNumWidth)
  649. {
  650. nMaxNumWidth = nNumWidth[i];
  651. }
  652. }
  653. return (nMaxNumWidth);
  654. }
  655. ////////////////////////////////////////////////////////////////////////////
  656. //
  657. // GetMaxSubstitutedCharWidth
  658. //
  659. // Determine the widest digit (safety against variable pitch fonts), but
  660. // do it using strings so that if number substitution is on, we will get
  661. // the width of the number based on what will actually be displayed
  662. //
  663. ////////////////////////////////////////////////////////////////////////////
  664. int GetMaxSubstitutedCharWidth(
  665. HDC hDC)
  666. {
  667. char sz[2] = "0";
  668. TCHAR szAMPM[12];
  669. LONG i, nMaxNumWidth;
  670. DWORD dwWidth;
  671. SIZE size;
  672. for (nMaxNumWidth = 0, i = 0; i < 10; (*sz)++, i++)
  673. {
  674. if (GetTextExtentPoint32A(hDC, sz, 1, &size) && size.cx > nMaxNumWidth)
  675. nMaxNumWidth = size.cx;
  676. }
  677. if (nMaxNumWidth <= 8)
  678. {
  679. GetProfileString(szIntl, TEXT("s1159"), IntlDef.s1159, szAMPM, ARRAYSIZE(szAMPM));
  680. dwWidth = LOWORD(GetTextExtent(hDC, szAMPM, lstrlen(szAMPM)));
  681. if (dwWidth > 22)
  682. {
  683. nMaxNumWidth = 10;
  684. }
  685. GetProfileString(szIntl, TEXT("s2359"), IntlDef.s2359, szAMPM, ARRAYSIZE(szAMPM));
  686. dwWidth = LOWORD(GetTextExtent(hDC, szAMPM, lstrlen(szAMPM)));
  687. if (dwWidth > 22)
  688. {
  689. nMaxNumWidth = 10;
  690. }
  691. }
  692. return (nMaxNumWidth);
  693. }
  694. ////////////////////////////////////////////////////////////////////////////
  695. //
  696. // ReflectAMPM
  697. //
  698. // Sets the global g_bPM and updates the control to display AM or PM.
  699. //
  700. ////////////////////////////////////////////////////////////////////////////
  701. void ReflectAMPM(
  702. HWND hDlg,
  703. int nNum)
  704. {
  705. HWND hCtl = GetDlgItem(hDlg, DATETIME_AMPM);
  706. ListBox_SetTopIndex(hCtl, g_bPM);
  707. ListBox_SetCurSel(hCtl, (GetFocus() == hCtl) ? g_bPM : -1);
  708. }
  709. ////////////////////////////////////////////////////////////////////////////
  710. //
  711. // GetTextExtent
  712. //
  713. ////////////////////////////////////////////////////////////////////////////
  714. #ifdef WIN32
  715. DWORD GetTextExtent(
  716. HDC hdc,
  717. LPCTSTR lpsz,
  718. int cb)
  719. {
  720. SIZE sz;
  721. BOOL bSuccess = GetTextExtentPoint(hdc, lpsz, cb, &sz);
  722. if ( !bSuccess )
  723. {
  724. ZeroMemory( &sz, sizeof(sz) );
  725. }
  726. return ( MAKELONG((WORD)sz.cx, (WORD)sz.cy) );
  727. }
  728. #endif
  729. ////////////////////////////////////////////////////////////////////////////
  730. //
  731. // DateTimeInit
  732. //
  733. // Determine the widest digit (safety against variable pitch fonts).
  734. //
  735. ////////////////////////////////////////////////////////////////////////////
  736. void DateTimeInit(
  737. HWND hDlg,
  738. WORD nBaseID,
  739. WORD nSepID,
  740. LPTSTR pszSep,
  741. int nMaxDigitWidth,
  742. BOOL bDate)
  743. {
  744. HWND hAMPMList;
  745. HWND hDay, hMonth, hYear; // also used as hHour, hMinute, & hSecond
  746. HWND hOrder[5];
  747. HDC hDC;
  748. int nWidth, nHeight, X;
  749. DWORD dwSepExt;
  750. RECT Rect;
  751. int i;
  752. int nAMPMlength;
  753. hMonth = GetDlgItem(hDlg, nBaseID);
  754. hDay = GetDlgItem(hDlg, nBaseID + 1);
  755. hYear = GetDlgItem(hDlg, nBaseID + 2);
  756. hOrder[1] = GetDlgItem(hDlg, nSepID);
  757. hOrder[3] = GetDlgItem(hDlg, nSepID + 1);
  758. if (bDate)
  759. {
  760. i = GetProfileInt(szIntl, TEXT("iDate"), 0);
  761. }
  762. else
  763. {
  764. if (g_b24HR = ( 0 != GetProfileInt(szIntl, TEXT("iTime"), 0) ))
  765. {
  766. g_sDateInfo[HOUR].nMin = 0;
  767. g_sDateInfo[HOUR].nMax = 23;
  768. }
  769. else
  770. {
  771. g_sDateInfo[HOUR].nMin = 1;
  772. g_sDateInfo[HOUR].nMax = 12;
  773. GetProfileString(szIntl, TEXT("s1159"), IntlDef.s1159, sz1159, ARRAYSIZE(sz1159));
  774. GetProfileString(szIntl, TEXT("s2359"), IntlDef.s2359, sz2359, ARRAYSIZE(sz2359));
  775. }
  776. i = 0;
  777. }
  778. switch (i)
  779. {
  780. case ( 1 ) :
  781. {
  782. hOrder[0] = hDay;
  783. hOrder[2] = hMonth;
  784. hOrder[4] = hYear;
  785. break;
  786. }
  787. case ( 2 ) :
  788. {
  789. hOrder[0] = hYear;
  790. hOrder[2] = hMonth;
  791. hOrder[4] = hDay;
  792. break;
  793. }
  794. case ( 0 ) :
  795. default :
  796. {
  797. hOrder[0] = hMonth;
  798. hOrder[2] = hDay;
  799. hOrder[4] = hYear;
  800. break;
  801. }
  802. }
  803. hDC = GetDC(hDlg);
  804. if (!bDate)
  805. {
  806. dwSepExt = GetTextExtent(hDC, sz1159, lstrlen(sz1159));
  807. nAMPMlength = LOWORD(GetTextExtent(hDC, sz2359, lstrlen(sz2359)));
  808. if (nAMPMlength < (int)LOWORD(dwSepExt))
  809. {
  810. nAMPMlength = (int)LOWORD(dwSepExt);
  811. }
  812. }
  813. dwSepExt = GetTextExtent(hDC, pszSep, lstrlen(pszSep));
  814. ReleaseDC(hDlg, hDC);
  815. GetWindowRect(hYear, (LPRECT)&Rect);
  816. ScreenToClient(hDlg, (LPPOINT)&Rect.left);
  817. ScreenToClient(hDlg, (LPPOINT)&Rect.right);
  818. nHeight = Rect.bottom - Rect.top;
  819. nWidth = Rect.top;
  820. GetWindowRect( GetDlgItem( hDlg,
  821. bDate ? DATETIME_CALENDAR : DATETIME_CLOCK ),
  822. (LPRECT)&Rect );
  823. ScreenToClient(hDlg, (LPPOINT)&Rect.left);
  824. ScreenToClient(hDlg, (LPPOINT)&Rect.right);
  825. Rect.top = nWidth;
  826. X = (Rect.left + Rect.right - (6 * nMaxDigitWidth) - (2 * LOWORD(dwSepExt))) / 2;
  827. if (bDate)
  828. {
  829. if (g_bLZero[YEAR])
  830. {
  831. X -= nMaxDigitWidth;
  832. }
  833. }
  834. else if (!g_b24HR)
  835. {
  836. X -= nAMPMlength / 2;
  837. }
  838. for (i = 0; i < 5; i++)
  839. {
  840. nWidth = (i % 2) ? LOWORD(dwSepExt) : 2 * nMaxDigitWidth;
  841. if ((hOrder[i] == hYear) && bDate && g_bLZero[YEAR])
  842. {
  843. nWidth *= 2;
  844. }
  845. //
  846. // Allow for centering in edit control.
  847. //
  848. nWidth += 2;
  849. // MoveWindow(hOrder[i], X, Rect.top, nWidth, nHeight, FALSE);
  850. X += nWidth;
  851. }
  852. hAMPMList = GetDlgItem(hDlg, DATETIME_AMPM);
  853. ListBox_ResetContent(hAMPMList);
  854. if (!bDate && !g_b24HR)
  855. {
  856. ListBox_InsertString(hAMPMList, 0, sz1159);
  857. ListBox_InsertString(hAMPMList, 1, sz2359);
  858. }
  859. EnableWindow(hAMPMList, !g_b24HR);
  860. Edit_LimitText(hYear, (bDate && g_bLZero[YEAR]) ? 4 : 2);
  861. Edit_LimitText(hMonth, 2);
  862. Edit_LimitText(hDay, 2);
  863. SetDlgItemText(hDlg, nSepID, pszSep);
  864. SetDlgItemText(hDlg, nSepID + 1, pszSep);
  865. }
  866. ////////////////////////////////////////////////////////////////////////////
  867. //
  868. // myitoa
  869. //
  870. ////////////////////////////////////////////////////////////////////////////
  871. void myitoa(
  872. int intValue,
  873. LPTSTR lpStr)
  874. {
  875. LPTSTR lpString;
  876. TCHAR c;
  877. //
  878. // lpString points to 1st char.
  879. //
  880. lpString = lpStr;
  881. do
  882. {
  883. *lpStr++ = (TCHAR)(intValue % 10 + TEXT('0'));
  884. } while ((intValue /= 10) > 0);
  885. //
  886. // lpStr points to last char.
  887. //
  888. *lpStr-- = TEXT('\0');
  889. //
  890. // Now reverse the string.
  891. //
  892. while (lpString < lpStr)
  893. {
  894. c = *lpString;
  895. *(lpString++) = *lpStr;
  896. *(lpStr--) = c;
  897. }
  898. }
  899. ////////////////////////////////////////////////////////////////////////////
  900. //
  901. // UpdateItem
  902. //
  903. // This displays the information in the control from the array
  904. // of global values. Also selects the control. Also adds leading 0's
  905. // as well as rounding years to 2 digits and 24 or AM/PM hours.
  906. //
  907. ////////////////////////////////////////////////////////////////////////////
  908. void UpdateItem(
  909. HWND hDlg,
  910. int i)
  911. {
  912. TCHAR szNum[5];
  913. int nNum = g_Modified ? wPrevDateTime[i] : wDateTime[i];
  914. //
  915. // Use internal time.
  916. //
  917. if (i <= SECOND && i >= HOUR)
  918. {
  919. nNum = g_Time[i];
  920. //
  921. // Do not paint un-necessarily.
  922. //
  923. if ((nNum == g_LastTime[i]) && (nNum >= 10))
  924. {
  925. return;
  926. }
  927. g_LastTime[i] = nNum;
  928. if (i == HOUR)
  929. {
  930. if (IsAMPM(nNum))
  931. {
  932. g_bPM = TRUE;
  933. }
  934. ReflectAMPM(hDlg, nNum);
  935. }
  936. }
  937. if (i == YEAR)
  938. {
  939. //
  940. // Round the years to last 2 digits.
  941. //
  942. if (!g_bLZero[i])
  943. {
  944. nNum %= 100;
  945. }
  946. }
  947. else if ((i == HOUR) && !g_b24HR)
  948. {
  949. //
  950. // nNum came from our internal date time.
  951. // Remove 12 hours if not 24hour.
  952. //
  953. if (g_bPM)
  954. {
  955. nNum %= 12;
  956. }
  957. //
  958. // 00 hours is actually 12AM.
  959. //
  960. if (!nNum)
  961. {
  962. nNum = 12;
  963. }
  964. }
  965. //
  966. // See if we need leading zeros.
  967. // We only deal with 2 character numbers MAX.
  968. //
  969. if ((nNum < 10) && (g_bLZero[i] || (i == YEAR)))
  970. {
  971. szNum[0] = TEXT('0');
  972. szNum[1] = (TCHAR)(TEXT('0') + nNum);
  973. szNum[2] = TEXT('\0');
  974. }
  975. else
  976. {
  977. myitoa(nNum, szNum);
  978. }
  979. //
  980. // Reflect the value in the appropriate control.
  981. //
  982. SetDlgItemText(hDlg, DATETIME_HOUR + i, szNum);
  983. //
  984. // Select the field too.
  985. //
  986. SendDlgItemMessage(hDlg, DATETIME_HOUR + i, EM_SETSEL, 0, MAKELONG(0, 32767));
  987. //
  988. // If we changed year or month, then we may have altered the leap year
  989. // state.
  990. //
  991. if (i == MONTH || i == YEAR)
  992. {
  993. g_sDateInfo[DAY].nMax = MonthUpperBound( wDateTime[MONTH],
  994. wDateTime[YEAR] );
  995. }
  996. }
  997. ////////////////////////////////////////////////////////////////////////////
  998. //
  999. // _ShowTZ
  1000. //
  1001. ////////////////////////////////////////////////////////////////////////////
  1002. TCHAR c_szFirstBootTZ[] = TEXT("!!!First Boot!!!");
  1003. void _ShowTZ(
  1004. HWND hDlg)
  1005. {
  1006. HWND ctl = GetDlgItem(hDlg, DATETIME_CURTZ);
  1007. TIME_ZONE_INFORMATION info;
  1008. TCHAR final[64 + TZNAME_SIZE];
  1009. TCHAR name[TZNAME_SIZE];
  1010. DWORD TimeZoneId;
  1011. if (g_bFirstBoot)
  1012. {
  1013. ShowWindow(ctl, SW_HIDE);
  1014. }
  1015. else
  1016. {
  1017. TimeZoneId = GetTimeZoneInformation(&info);
  1018. if ( TimeZoneId == TIME_ZONE_ID_STANDARD )
  1019. {
  1020. StringCchCopy( name, ARRAYSIZE(name), info.StandardName );
  1021. }
  1022. else
  1023. {
  1024. StringCchCopy( name, ARRAYSIZE(name), info.DaylightName );
  1025. }
  1026. //
  1027. // Display nothing if it is our special 1st boot marker.
  1028. //
  1029. if (*name && (lstrcmpi(name, c_szFirstBootTZ) != 0))
  1030. {
  1031. static TCHAR format[128] = TEXT("");
  1032. if (!*format)
  1033. {
  1034. GetWindowText( ctl, format, ARRAYSIZE(format) );
  1035. }
  1036. StringCchPrintf( final, ARRAYSIZE(final), format, name );
  1037. }
  1038. else
  1039. {
  1040. *final = 0;
  1041. }
  1042. SetWindowText(ctl, final);
  1043. }
  1044. }
  1045. ////////////////////////////////////////////////////////////////////////////
  1046. //
  1047. // UnhookTime
  1048. //
  1049. // To stop the clock calling us back all the time (around exit).
  1050. //
  1051. ////////////////////////////////////////////////////////////////////////////
  1052. void UnhookTimer(
  1053. HWND hDlg)
  1054. {
  1055. SendDlgItemMessage(hDlg, DATETIME_CLOCK, CLM_TIMEHWND, CLF_SETHWND, 0);
  1056. }
  1057. ////////////////////////////////////////////////////////////////////////////
  1058. //
  1059. // TimeProvider
  1060. //
  1061. // Called by the clock to find out what time it is.
  1062. //
  1063. ////////////////////////////////////////////////////////////////////////////
  1064. void TimeProvider(
  1065. LPSYSTEMTIME lpSystemTime,
  1066. HWND hDlg)
  1067. {
  1068. short wTemp[7];
  1069. //
  1070. // If the user has modified the time, the clock should
  1071. // display the edit controls, otherwise its just the SystemTime.
  1072. //
  1073. if (g_Modified)
  1074. {
  1075. lpSystemTime->wHour = (WORD)g_Time[HOUR];
  1076. lpSystemTime->wMinute = (WORD)g_Time[MINUTE];
  1077. lpSystemTime->wSecond = (WORD)g_Time[SECOND];
  1078. }
  1079. else
  1080. {
  1081. #ifdef WIN32
  1082. GetLocalTime(lpSystemTime);
  1083. #else
  1084. GetTime();
  1085. if (wDateTime[HOUR] >= 0 && wDateTime[HOUR] <= 24)
  1086. {
  1087. lpSystemTime->wHour = wDateTime[HOUR];
  1088. }
  1089. lpSystemTime->wMinute = wDateTime[MINUTE];
  1090. lpSystemTime->wSecond = wDateTime[SECOND];
  1091. #endif
  1092. //
  1093. // Copy the time and display it for us too.
  1094. //
  1095. g_bPM = IsAMPM(lpSystemTime->wHour);
  1096. g_Time[HOUR] = lpSystemTime->wHour;
  1097. g_Time[MINUTE] = lpSystemTime->wMinute;
  1098. g_Time[SECOND] = lpSystemTime->wSecond;
  1099. //
  1100. // Check for date rollover.
  1101. //
  1102. if (!fDateDirty)
  1103. {
  1104. wTemp[DAY] = wDateTime[DAY];
  1105. wTemp[MONTH] = wDateTime[MONTH];
  1106. wTemp[YEAR] = wDateTime[YEAR];
  1107. GetDate();
  1108. if ((wDateTime[DAY] != wTemp[DAY]) ||
  1109. (wDateTime[MONTH] != wTemp[MONTH]) ||
  1110. (wDateTime[YEAR] != wTemp[YEAR]))
  1111. {
  1112. InvalidateRect(GetDlgItem(hDlg, DATETIME_CALENDAR), NULL, TRUE);
  1113. if (wDateTime[MONTH] != wTemp[MONTH])
  1114. {
  1115. ComboBox_SetCurSel( GetDlgItem(hDlg, DATETIME_MONTHNAME),
  1116. wDateTime[MONTH] - 1 );
  1117. }
  1118. if (wDateTime[YEAR] != wTemp[YEAR])
  1119. {
  1120. UpdateItem(hDlg, YEAR);
  1121. }
  1122. _ShowTZ(hDlg);
  1123. }
  1124. }
  1125. UpdateItem(hDlg, HOUR);
  1126. UpdateItem(hDlg, MINUTE);
  1127. UpdateItem(hDlg, SECOND);
  1128. ReflectAMPM(hDlg, g_Time[HOUR]);
  1129. }
  1130. }
  1131. ////////////////////////////////////////////////////////////////////////////
  1132. //
  1133. // bSupportedCalendar
  1134. //
  1135. // Returns True if the current calendar is not Hijri nor Hebrew
  1136. //
  1137. // Otherwise it returns FALSE.
  1138. //
  1139. ////////////////////////////////////////////////////////////////////////////
  1140. BOOL bSupportedCalendar()
  1141. {
  1142. TCHAR tchCalendar[32];
  1143. CALTYPE defCalendar = CAL_GREGORIAN;
  1144. if (GetLocaleInfo(LOCALE_USER_DEFAULT,
  1145. LOCALE_ICALENDARTYPE,
  1146. tchCalendar,
  1147. ARRAYSIZE(tchCalendar)))
  1148. {
  1149. defCalendar = StrToInt(tchCalendar);
  1150. }
  1151. return (!(defCalendar == CAL_HIJRI || defCalendar == CAL_HEBREW));
  1152. }
  1153. ////////////////////////////////////////////////////////////////////////////
  1154. //
  1155. // InitDateTimeDlg
  1156. //
  1157. // Called to init the dialog.
  1158. //
  1159. ////////////////////////////////////////////////////////////////////////////
  1160. void InitDateTimeDlg(
  1161. HWND hDlg,
  1162. UINT message,
  1163. WPARAM wParam,
  1164. LPARAM lParam)
  1165. {
  1166. int nMaxDigitWidth;
  1167. int i;
  1168. TCHAR szNum[5];
  1169. TCHAR szMonth[64];
  1170. TCHAR szShortDate[12];
  1171. HDC hDC;
  1172. HFONT hFont;
  1173. HWND hwndCB;
  1174. CALID calId;
  1175. static int nInc[] = { 1, 5, 5, 1, 1, 5 };
  1176. HWND hwndScroll;
  1177. UDACCEL udAccel[2];
  1178. HWND hwndTBorder;
  1179. HCURSOR oldcursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
  1180. LCID lcid = LOCALE_USER_DEFAULT;
  1181. InitCommonControls();
  1182. //
  1183. // Sets the Leading zero status of the 6 controls.
  1184. //
  1185. g_bLZero[HOUR] = g_bLZero[MONTH] = g_bLZero[DAY] = FALSE;
  1186. g_bLZero[MINUTE] = g_bLZero[SECOND] = g_bLZero[YEAR] = TRUE;
  1187. hDC = GetDC(hDlg);
  1188. if (hFont = (HFONT)SendMessage(hDlg, WM_GETFONT, 0, 0L))
  1189. {
  1190. hFont = SelectObject( hDC, hFont );
  1191. }
  1192. if (hFont)
  1193. {
  1194. SelectObject(hDC, hFont);
  1195. }
  1196. AdjustAMPMPosition(hDlg);
  1197. nMaxDigitWidth = GetMaxCharWidth(hDC);
  1198. ReleaseDC(hDlg, hDC);
  1199. g_bLZero[HOUR] = GetProfileInt(szIntl, TEXT("iTLZero"), 0);
  1200. //
  1201. // Initialize szShortDate in case GetProfileString fails.
  1202. //
  1203. StringCchCopy( szShortDate, ARRAYSIZE(szShortDate), IntlDef.sShortDate );
  1204. GetProfileString(szIntl, TEXT("sShortDate"), IntlDef.sShortDate, szShortDate, ARRAYSIZE(szShortDate));
  1205. ReadShortDate(szShortDate, g_bLZero + MONTH, g_bLZero + DAY, g_bLZero + YEAR);
  1206. g_bLZero[YEAR] = TRUE; //we always want the year to be 4 digits (this will be bad in late 9999)
  1207. //
  1208. // Setup the TIME stuff.
  1209. //
  1210. GetTime();
  1211. g_Time[HOUR] = wDateTime[HOUR];
  1212. g_Time[MINUTE] = wDateTime[MINUTE];
  1213. g_Time[SECOND] = wDateTime[SECOND];
  1214. GetProfileString(szIntl, TEXT("sTime"), IntlDef.sTime, szNum, 3);
  1215. DateTimeInit(hDlg, DATETIME_HOUR, DATETIME_TSEP1, szNum, nMaxDigitWidth, FALSE);
  1216. //
  1217. // Force all entries to be re-drawn,
  1218. //
  1219. g_LastTime[HOUR] = g_LastTime[MINUTE] = g_LastTime[SECOND] = -1;
  1220. UpdateItem(hDlg, HOUR);
  1221. UpdateItem(hDlg, MINUTE);
  1222. UpdateItem(hDlg, SECOND);
  1223. ReflectAMPM(hDlg, wDateTime[HOUR]);
  1224. //
  1225. // Setup the Date stuff.
  1226. //
  1227. GetDate();
  1228. g_sDateInfo[DAY].nMax = MonthUpperBound(wDateTime[MONTH], wDateTime[YEAR]);
  1229. if (!g_bLZero[YEAR])
  1230. {
  1231. wDateTime[YEAR] %= 100;
  1232. g_sDateInfo[YEAR].nMax = 99;
  1233. g_sDateInfo[YEAR].nMin = 0;
  1234. }
  1235. else
  1236. {
  1237. g_sDateInfo[YEAR].nMax = 2099;
  1238. g_sDateInfo[YEAR].nMin = 1980;
  1239. }
  1240. for (i = MONTH; i <= YEAR; i++)
  1241. {
  1242. wPrevDateTime[i] = -1;
  1243. }
  1244. //
  1245. // Get the month names. And select this month.
  1246. //
  1247. hwndCB = GetDlgItem(hDlg, DATETIME_MONTHNAME);
  1248. ComboBox_ResetContent(hwndCB);
  1249. //
  1250. // If the current calendar is Hijri or Hebrew then use the Gregorian one.
  1251. //
  1252. if (!bSupportedCalendar())
  1253. lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
  1254. GetLocaleInfo(lcid, LOCALE_ICALENDARTYPE, szMonth, ARRAYSIZE(szMonth));
  1255. calId = (CALID)StrToInt(szMonth);
  1256. for (i = 0; i < 12; i++)
  1257. {
  1258. GetCalendarInfo(lcid, calId, CAL_SMONTHNAME1 + i, szMonth, ARRAYSIZE(szMonth), NULL);
  1259. ComboBox_AddString(hwndCB, szMonth);
  1260. }
  1261. ComboBox_SetCurSel(hwndCB, wDateTime[MONTH] - 1);
  1262. //
  1263. // Set the default modifier for the Year Updown arrows.
  1264. //
  1265. wParam -= DATETIME_HOUR;
  1266. hwndScroll = GetDlgItem(hDlg, DATETIME_YARROW);
  1267. SendMessage( hwndScroll,
  1268. UDM_SETRANGE,
  1269. 0,
  1270. MAKELPARAM(g_sDateInfo[YEAR].nMax, g_sDateInfo[YEAR].nMin) );
  1271. udAccel[0].nSec = 0;
  1272. udAccel[0].nInc = 1;
  1273. udAccel[1].nSec = 2;
  1274. udAccel[1].nInc = nInc[YEAR];
  1275. SendMessage(hwndScroll, UDM_SETACCEL, 2, (LPARAM)(LPUDACCEL)udAccel);
  1276. SendMessage(hwndScroll, UDM_SETBUDDY, (WPARAM)GetDlgItem(hDlg, DATETIME_YEAR), 0L);
  1277. //
  1278. // Set the default modifier for the time arrows.
  1279. // It should control the HOURS by default as per joelgros
  1280. //
  1281. hwndScroll = GetDlgItem(hDlg, DATETIME_TARROW);
  1282. SendMessage( hwndScroll,
  1283. UDM_SETRANGE,
  1284. 0,
  1285. MAKELPARAM( g_sDateInfo[HOUR].nMax,
  1286. g_sDateInfo[HOUR].nMin) );
  1287. udAccel[0].nSec = 0;
  1288. udAccel[0].nInc = 1;
  1289. udAccel[1].nSec = 2;
  1290. udAccel[1].nInc = nInc[HOUR];
  1291. SendMessage( hwndScroll, UDM_SETACCEL, 2, (LPARAM)(LPUDACCEL)udAccel );
  1292. SendMessage( hwndScroll, UDM_SETBUDDY, (WPARAM)GetDlgItem(hDlg, DATETIME_HOUR), 0L );
  1293. //
  1294. // Make the 'well' for the digits appear.
  1295. //
  1296. hwndTBorder = GetDlgItem(hDlg, DATETIME_TBORDER);
  1297. SetWindowLong( hwndTBorder,
  1298. GWL_EXSTYLE,
  1299. GetWindowLong(hwndTBorder, GWL_EXSTYLE) | WS_EX_CLIENTEDGE );
  1300. //
  1301. // Display the border right now.
  1302. //
  1303. SetWindowPos( hwndTBorder,
  1304. NULL,
  1305. 0, 0, 0, 0,
  1306. SWP_NOMOVE | SWP_NOSIZE | SWP_DRAWFRAME | SWP_SHOWWINDOW );
  1307. //
  1308. // Display month->year.
  1309. //
  1310. for (i = MONTH; i <= YEAR; i++)
  1311. {
  1312. if ((wDateTime[i] != wPrevDateTime[i]) &&
  1313. (GetFocus() != GetDlgItem(hDlg, DATETIME_HOUR + i)))
  1314. {
  1315. //
  1316. // Update previous date-time.
  1317. //
  1318. wPrevDateTime[i] = wDateTime[i];
  1319. if (i == YEAR)
  1320. {
  1321. UpdateItem(hDlg, i);
  1322. }
  1323. }
  1324. }
  1325. g_Modified = FALSE;
  1326. //
  1327. // Tell the clock that we have a time provider - must be done last.
  1328. //
  1329. SendDlgItemMessage( hDlg,
  1330. DATETIME_CLOCK,
  1331. CLM_TIMEHWND,
  1332. CLF_SETHWND,
  1333. (LPARAM)(LPINT)hDlg );
  1334. SetCursor(oldcursor);
  1335. }
  1336. ////////////////////////////////////////////////////////////////////////////
  1337. //
  1338. // CheckNum
  1339. //
  1340. ////////////////////////////////////////////////////////////////////////////
  1341. LRESULT CheckNum(
  1342. HWND hDlg,
  1343. UINT nScrollID,
  1344. HWND hCtl)
  1345. {
  1346. static int cReenter = 0;
  1347. LRESULT lRet;
  1348. //
  1349. // If this is an illegal value, (but not blank), then kill the last char
  1350. // that was entered.
  1351. //
  1352. lRet = SendDlgItemMessage(hDlg, nScrollID, UDM_GETPOS, 0, 0L);
  1353. //
  1354. // Guard against re-entrance.
  1355. //
  1356. ++cReenter;
  1357. if (cReenter <= 4)
  1358. {
  1359. SendMessage( hCtl,
  1360. HIWORD(lRet) && GetWindowTextLength(hCtl)
  1361. ? EM_UNDO
  1362. : EM_EMPTYUNDOBUFFER,
  1363. 0,
  1364. 0L );
  1365. }
  1366. --cReenter;
  1367. return (lRet);
  1368. }
  1369. ////////////////////////////////////////////////////////////////////////////
  1370. //
  1371. // DateTimeDlgProc
  1372. //
  1373. // Main dialog proc.
  1374. //
  1375. ////////////////////////////////////////////////////////////////////////////
  1376. INT_PTR CALLBACK DateTimeDlgProc(
  1377. HWND hDlg,
  1378. UINT uMsg,
  1379. WPARAM wParam,
  1380. LPARAM lParam)
  1381. {
  1382. int i;
  1383. switch (uMsg)
  1384. {
  1385. case (WM_INITDIALOG):
  1386. {
  1387. AddInternetPageAsync(GetParent(hDlg), hDlg);
  1388. InitDateTimeDlg(hDlg, uMsg, wParam, lParam);
  1389. g_PrevIMCForDateField = ImmAssociateContext(GetDlgItem(hDlg, DATETIME_YEAR), 0);
  1390. break;
  1391. }
  1392. case ( WM_DESTROY ) :
  1393. {
  1394. if (g_PrevIMCForDateField)
  1395. {
  1396. ImmAssociateContext( GetDlgItem(hDlg, DATETIME_YEAR),
  1397. g_PrevIMCForDateField );
  1398. }
  1399. UnhookTimer(hDlg);
  1400. break;
  1401. }
  1402. #ifdef WIN32
  1403. case ( WM_CTLCOLORSTATIC ) :
  1404. #endif
  1405. case ( WM_CTLCOLOR ) :
  1406. {
  1407. //
  1408. // Set the background color of the time controls to the the
  1409. // color of the edit controls.
  1410. //
  1411. if ((GET_WM_CTLCOLOR_HWND(wParam, lParam, uMsg) ==
  1412. GetDlgItem(hDlg, DATETIME_TSEP1)) ||
  1413. (GET_WM_CTLCOLOR_HWND(wParam, lParam, uMsg) ==
  1414. GetDlgItem(hDlg, DATETIME_TSEP2)) ||
  1415. (GET_WM_CTLCOLOR_HWND(wParam, lParam, uMsg) ==
  1416. GetDlgItem(hDlg, DATETIME_TBORDER)))
  1417. {
  1418. #ifndef WIN32
  1419. //
  1420. // Make the statics the color of the edits.
  1421. //
  1422. lParam = GET_WM_CTLCOLOR_MPS(
  1423. GET_WM_CTLCOLOR_HDC(wParam, lParam, uMsg),
  1424. GET_WM_CTLCOLOR_HWND(wParam, lParam, uMsg),
  1425. CTLCOLOR_EDIT );
  1426. return ((INT_PTR)DefWindowProc(hDlg, uMsg, wParam, lParam));
  1427. #else
  1428. return ((INT_PTR)DefWindowProc(hDlg, WM_CTLCOLOREDIT, wParam, lParam));
  1429. #endif
  1430. }
  1431. return (0);
  1432. break;
  1433. }
  1434. case ( WM_NOTIFY ) :
  1435. {
  1436. //
  1437. // Property sheet handler stuff.
  1438. //
  1439. switch (((NMHDR *)lParam)->code)
  1440. {
  1441. case ( PSN_SETACTIVE ) :
  1442. {
  1443. _ShowTZ(hDlg);
  1444. break;
  1445. }
  1446. case ( PSN_RESET ) :
  1447. {
  1448. UnhookTimer(hDlg);
  1449. SetFocus(GetDlgItem(hDlg, (int)wParam));
  1450. GetDate();
  1451. GetTime();
  1452. break;
  1453. }
  1454. case ( PSN_APPLY ) :
  1455. {
  1456. wDateTime[MINUTE] = (WORD)g_Time[MINUTE];
  1457. wDateTime[SECOND] = (WORD)g_Time[SECOND];
  1458. if (g_b24HR)
  1459. {
  1460. wDateTime[HOUR] = (WORD)g_Time[HOUR];
  1461. }
  1462. else
  1463. {
  1464. wDateTime[HOUR] = g_Time[HOUR] % 12;
  1465. if (g_bPM)
  1466. {
  1467. wDateTime[HOUR] += 12;
  1468. }
  1469. }
  1470. g_WasModified = g_Modified;
  1471. SetTime();
  1472. g_LastTime[HOUR] = g_LastTime[MINUTE] = g_LastTime[SECOND] = -1;
  1473. for (i = MONTH; i <= YEAR; i++)
  1474. {
  1475. wPrevDateTime[i] = -1;
  1476. }
  1477. g_Modified = FALSE;
  1478. wPrevDateTime[HOUR] = wDateTime[HOUR];
  1479. wPrevDateTime[MINUTE] = wDateTime[MINUTE];
  1480. wPrevDateTime[SECOND] = wDateTime[SECOND];
  1481. wPrevDateTime[MONTH] = wDateTime[MONTH];
  1482. wPrevDateTime[DAY] = wDateTime[DAY];
  1483. wPrevDateTime[YEAR] = wDateTime[YEAR];
  1484. wPrevDateTime[WEEKDAY] = wDateTime[WEEKDAY];
  1485. //
  1486. // We handled it - no repaint.
  1487. //
  1488. return (TRUE);
  1489. }
  1490. }
  1491. break;
  1492. }
  1493. case ( WM_VSCROLL ) :
  1494. {
  1495. switch (GET_WM_VSCROLL_CODE(wParam, lParam))
  1496. {
  1497. case ( SB_THUMBPOSITION ) :
  1498. {
  1499. SYSTEMTIME SystemTime;
  1500. HWND hBuddy = (HWND)SendMessage(
  1501. GET_WM_VSCROLL_HWND(wParam, lParam),
  1502. UDM_GETBUDDY,
  1503. 0,
  1504. 0L );
  1505. if (hBuddy == GetDlgItem(hDlg, DATETIME_HOUR))
  1506. {
  1507. g_Time[HOUR] = GET_WM_VSCROLL_POS(wParam, lParam);
  1508. }
  1509. else if (hBuddy == GetDlgItem(hDlg, DATETIME_MINUTE))
  1510. {
  1511. g_Time[MINUTE] = GET_WM_VSCROLL_POS(wParam, lParam);
  1512. }
  1513. else if (hBuddy == GetDlgItem(hDlg, DATETIME_SECOND))
  1514. {
  1515. g_Time[SECOND] = GET_WM_VSCROLL_POS(wParam, lParam);
  1516. }
  1517. // else if (hBuddy == GetDlgItem(hDlg, DATETIME_AMPM))
  1518. if (hBuddy != GetDlgItem(hDlg, DATETIME_YEAR))
  1519. g_Modified = TRUE;
  1520. //
  1521. // Light the apply now button.
  1522. //
  1523. PropSheet_Changed(GetParent(hDlg), hDlg);
  1524. //
  1525. // Force the clock to reflect this setting.
  1526. //
  1527. TimeProvider(&SystemTime, hDlg);
  1528. SendDlgItemMessage( hDlg,
  1529. DATETIME_CLOCK,
  1530. CLM_UPDATETIME,
  1531. CLF_SETTIME,
  1532. (LPARAM)(LPSYSTEMTIME)&SystemTime );
  1533. //
  1534. // Fall thru to update the year...
  1535. //
  1536. }
  1537. case ( SB_ENDSCROLL ) :
  1538. {
  1539. //
  1540. // If this is the year, have the calendar repaint.
  1541. //
  1542. if ((HWND)SendMessage( GET_WM_VSCROLL_HWND(wParam, lParam),
  1543. UDM_GETBUDDY,
  1544. 0,
  1545. 0L ) == GetDlgItem(hDlg, DATETIME_YEAR))
  1546. {
  1547. //
  1548. // Have it update the information.
  1549. //
  1550. GetTime();
  1551. AdjustDelta(hDlg, YEAR);
  1552. UpdateItem(hDlg, YEAR);
  1553. InvalidateRect( GetDlgItem(hDlg, DATETIME_CALENDAR),
  1554. NULL,
  1555. TRUE );
  1556. }
  1557. break;
  1558. }
  1559. }
  1560. break;
  1561. }
  1562. case ( CLM_UPDATETIME ) :
  1563. {
  1564. //
  1565. // The clock updating/reflecting the time.
  1566. //
  1567. switch (wParam)
  1568. {
  1569. case ( CLF_SETTIME ) :
  1570. {
  1571. //
  1572. // Clock telling us what the time is.
  1573. //
  1574. g_Modified = TRUE;
  1575. g_Time[HOUR] = ((LPSYSTEMTIME)lParam)->wHour;
  1576. g_Time[MINUTE] = ((LPSYSTEMTIME)lParam)->wMinute;
  1577. g_Time[SECOND] = ((LPSYSTEMTIME)lParam)->wSecond;
  1578. g_bPM = IsAMPM(g_Time[HOUR]);
  1579. break;
  1580. }
  1581. case ( CLF_GETTIME ) :
  1582. {
  1583. //
  1584. // We tell the clock what time it is.
  1585. //
  1586. TimeProvider((LPSYSTEMTIME)lParam, hDlg);
  1587. break;
  1588. }
  1589. }
  1590. break;
  1591. }
  1592. case ( WM_COMMAND ) :
  1593. {
  1594. //
  1595. // Command processing.
  1596. //
  1597. switch (GET_WM_COMMAND_ID(wParam, lParam))
  1598. {
  1599. case ( DATETIME_AMPM ) :
  1600. {
  1601. //
  1602. // Deals with the AMPM control.
  1603. //
  1604. UDACCEL udAccel;
  1605. HWND hwndScroll = GetDlgItem(hDlg, DATETIME_TARROW);
  1606. HWND hwndThisCtl = GET_WM_COMMAND_HWND(wParam, lParam);
  1607. //
  1608. // We only care if we get/loose the focus.
  1609. //
  1610. switch (GET_WM_COMMAND_CMD(wParam, lParam))
  1611. {
  1612. case ( LBN_SETFOCUS ) :
  1613. {
  1614. //
  1615. // If we get the focus, then the UD control
  1616. // should deal with the AMPM.
  1617. //
  1618. // Select the visible entry.
  1619. //
  1620. ReflectAMPM(hDlg, wDateTime[HOUR]);
  1621. // if it has a buddy, remove it...
  1622. if ((HWND)SendMessage( hwndScroll,
  1623. UDM_GETBUDDY,
  1624. 0,
  1625. 0 ) != NULL)
  1626. {
  1627. SendMessage(hwndScroll, UDM_SETBUDDY, 0, 0);
  1628. }
  1629. //
  1630. // Tell the UD control how to manipulate AM/PM.
  1631. //
  1632. SendMessage( hwndScroll,
  1633. UDM_SETRANGE,
  1634. 0,
  1635. MAKELPARAM(1, 0) );
  1636. udAccel.nSec = 0;
  1637. udAccel.nInc = 1;
  1638. SendMessage( hwndScroll,
  1639. UDM_SETACCEL,
  1640. 1,
  1641. (LPARAM)(LPUDACCEL)&udAccel );
  1642. SendMessage( hwndScroll,
  1643. UDM_SETBUDDY,
  1644. (WPARAM)hwndThisCtl,
  1645. 0 );
  1646. break;
  1647. }
  1648. case ( LBN_KILLFOCUS ) :
  1649. {
  1650. //
  1651. // When we loose focus, the g_bPM flag is updated.
  1652. //
  1653. // Remove selection from the AM/PM.
  1654. //
  1655. ListBox_SetCurSel(hwndThisCtl, -1);
  1656. if ((HWND)SendMessage( hwndScroll,
  1657. UDM_GETBUDDY,
  1658. 0,
  1659. 0 ) == hwndThisCtl)
  1660. {
  1661. SendMessage(hwndScroll, UDM_SETBUDDY, 0, 0);
  1662. }
  1663. break;
  1664. }
  1665. case ( LBN_SELCHANGE ) :
  1666. {
  1667. if ((g_Modified == FALSE) &&
  1668. (g_bPM == (BOOL)ListBox_GetTopIndex(hwndThisCtl)))
  1669. {
  1670. break;
  1671. }
  1672. //
  1673. // Find the visible entry.
  1674. //
  1675. g_Modified = TRUE;
  1676. //
  1677. // Light the apply now button.
  1678. //
  1679. PropSheet_Changed(GetParent(hDlg), hDlg);
  1680. g_bPM = (BOOL)ListBox_GetTopIndex(hwndThisCtl);
  1681. break;
  1682. }
  1683. }
  1684. break;
  1685. }
  1686. case ( DATETIME_HOUR ) :
  1687. case ( DATETIME_MINUTE ) :
  1688. case ( DATETIME_SECOND ) :
  1689. {
  1690. switch (GET_WM_COMMAND_CMD(wParam, lParam))
  1691. {
  1692. case ( EN_CHANGE ) :
  1693. {
  1694. SYSTEMTIME SystemTime;
  1695. g_Modified = TRUE;
  1696. //
  1697. // Light the apply now button.
  1698. //
  1699. PropSheet_Changed(GetParent(hDlg), hDlg);
  1700. //
  1701. // Work out what the change was too.
  1702. //
  1703. g_Time[GET_WM_COMMAND_ID(wParam, lParam) -
  1704. DATETIME_HOUR] =
  1705. (int)SendDlgItemMessage( hDlg,
  1706. DATETIME_TARROW,
  1707. UDM_GETPOS,
  1708. 0,
  1709. 0 );
  1710. //
  1711. // Force the clock to reflect this setting.
  1712. //
  1713. TimeProvider(&SystemTime, hDlg);
  1714. SendDlgItemMessage( hDlg,
  1715. DATETIME_CLOCK,
  1716. CLM_UPDATETIME,
  1717. 0,
  1718. (LPARAM)(LPSYSTEMTIME)&SystemTime );
  1719. break;
  1720. }
  1721. }
  1722. // fall thru...
  1723. }
  1724. case ( DATETIME_MONTH ) :
  1725. case ( DATETIME_YEAR ) :
  1726. case ( DATETIME_DAY ) :
  1727. {
  1728. switch (GET_WM_COMMAND_CMD(wParam, lParam))
  1729. {
  1730. case ( EN_CHANGE ) :
  1731. {
  1732. CheckNum( hDlg,
  1733. GET_WM_COMMAND_ID(wParam, lParam) <= DATETIME_SECOND
  1734. ? DATETIME_TARROW
  1735. : DATETIME_YARROW,
  1736. GET_WM_COMMAND_HWND(wParam, lParam) );
  1737. // Changing the year may alter the number of days in February.
  1738. // Yes this is a hack, but this entire applet is a giant
  1739. // broken hack and I want to change it as little as possible.
  1740. if (GET_WM_COMMAND_ID(wParam, lParam) == DATETIME_YEAR && wDateTime[MONTH] == 2)
  1741. {
  1742. g_sDateInfo[DAY].nMax = MonthUpperBound( wDateTime[MONTH],
  1743. wDateTime[YEAR] );
  1744. if (wDateTime[DAY] > g_sDateInfo[DAY].nMax)
  1745. {
  1746. wDateTime[DAY] = (WORD)g_sDateInfo[DAY].nMax;
  1747. fDateDirty = TRUE;
  1748. }
  1749. InvalidateRect( GetDlgItem(hDlg, DATETIME_CALENDAR),
  1750. NULL,
  1751. TRUE );
  1752. }
  1753. break;
  1754. }
  1755. case ( EN_SETFOCUS ) :
  1756. {
  1757. UINT id = GET_WM_COMMAND_ID(wParam, lParam) - DATETIME_HOUR;
  1758. if (id <= SECOND)
  1759. {
  1760. UDACCEL udAccel[2];
  1761. static int nInc[] = { 1, 5, 5, 1, 1, 5 };
  1762. HWND hwndScroll = GetDlgItem(hDlg, DATETIME_TARROW);
  1763. // if it has a buddy, remove it...
  1764. if ((HWND)SendMessage( hwndScroll,
  1765. UDM_GETBUDDY,
  1766. 0,
  1767. 0 ) != NULL)
  1768. {
  1769. SendMessage(hwndScroll, UDM_SETBUDDY, 0, 0);
  1770. }
  1771. //
  1772. // now set the new one
  1773. //
  1774. SendMessage( hwndScroll,
  1775. UDM_SETRANGE,
  1776. 0,
  1777. MAKELPARAM( g_sDateInfo[id].nMax,
  1778. g_sDateInfo[id].nMin) );
  1779. udAccel[0].nSec = 0;
  1780. udAccel[0].nInc = 1;
  1781. udAccel[1].nSec = 2;
  1782. udAccel[1].nInc = nInc[id];
  1783. SendMessage( hwndScroll,
  1784. UDM_SETACCEL,
  1785. 2,
  1786. (LPARAM)(LPUDACCEL)udAccel );
  1787. //
  1788. // Set the UD to update this control.
  1789. //
  1790. SendMessage( hwndScroll,
  1791. UDM_SETBUDDY,
  1792. (WPARAM)GET_WM_COMMAND_HWND(wParam,
  1793. lParam),
  1794. 0 );
  1795. }
  1796. break;
  1797. }
  1798. case ( EN_KILLFOCUS ) :
  1799. {
  1800. //
  1801. // Gets in range HMS MDY.
  1802. //
  1803. UINT id = GET_WM_COMMAND_ID(wParam, lParam) - DATETIME_HOUR;
  1804. AdjustDelta(hDlg, id);
  1805. UpdateItem(hDlg, id);
  1806. //
  1807. // If control is YEAR.
  1808. //
  1809. if (id == (DATETIME_YEAR - DATETIME_HOUR))
  1810. {
  1811. InvalidateRect( GetDlgItem(hDlg, DATETIME_CALENDAR),
  1812. NULL,
  1813. TRUE );
  1814. }
  1815. break;
  1816. }
  1817. default :
  1818. {
  1819. break;
  1820. }
  1821. }
  1822. break;
  1823. }
  1824. case ( DATETIME_MONTHNAME ) :
  1825. {
  1826. if (GET_WM_COMMAND_CMD(wParam, lParam) == CBN_SELCHANGE)
  1827. {
  1828. int nIndex = 1 + (int)ComboBox_GetCurSel(
  1829. GetDlgItem( hDlg,
  1830. DATETIME_MONTHNAME ));
  1831. if (wDateTime[MONTH] != nIndex)
  1832. {
  1833. AdjustDeltaMonth(nIndex);
  1834. InvalidateRect( GetDlgItem(hDlg, DATETIME_CALENDAR),
  1835. NULL,
  1836. TRUE );
  1837. PropSheet_Changed(GetParent(hDlg), hDlg);
  1838. }
  1839. }
  1840. break;
  1841. }
  1842. case ( DATETIME_CALENDAR ) :
  1843. {
  1844. //
  1845. // If the calendar sent us a change, we will assume
  1846. // that it is to allow the apply now to work.
  1847. //
  1848. PropSheet_Changed(GetParent(hDlg), hDlg);
  1849. break;
  1850. }
  1851. }
  1852. break;
  1853. }
  1854. case ( WM_WININICHANGE ) :
  1855. {
  1856. //
  1857. // Reinitialize if there is a time format change.
  1858. //
  1859. InitDateTimeDlg(hDlg, uMsg, wParam, lParam);
  1860. InvalidateRect(GetDlgItem(hDlg, DATETIME_CALENDAR), NULL, TRUE);
  1861. break;
  1862. }
  1863. case ( WM_TIMECHANGE ) :
  1864. {
  1865. //
  1866. // Forward time change messages to the clock control.
  1867. //
  1868. SendDlgItemMessage( hDlg,
  1869. DATETIME_CLOCK,
  1870. WM_TIMECHANGE,
  1871. wParam,
  1872. lParam );
  1873. break;
  1874. }
  1875. case ( WMUSER_ADDINTERNETTAB ) :
  1876. {
  1877. AddInternetTab(hDlg);
  1878. break;
  1879. }
  1880. case ( WM_HELP ) : // F1
  1881. {
  1882. WinHelp( (HWND)((LPHELPINFO)lParam)->hItemHandle,
  1883. NULL,
  1884. HELP_WM_HELP,
  1885. (DWORD_PTR)(LPTSTR)aDateTimeHelpIds );
  1886. break;
  1887. }
  1888. case ( WM_CONTEXTMENU ) : // right mouse click
  1889. {
  1890. WinHelp( (HWND)wParam,
  1891. NULL,
  1892. HELP_CONTEXTMENU,
  1893. (DWORD_PTR)(LPTSTR)aDateTimeHelpIds );
  1894. break;
  1895. }
  1896. default :
  1897. {
  1898. return (FALSE);
  1899. }
  1900. }
  1901. return (TRUE);
  1902. }
  1903. ////////////////////////////////////////////////////////////////////////////
  1904. //
  1905. // SetZoneState
  1906. //
  1907. // Sets the display state of a time zone in the map control.
  1908. //
  1909. ////////////////////////////////////////////////////////////////////////////
  1910. void SetZoneState(
  1911. HWND map,
  1912. PTZINFO zone,
  1913. BOOL highlight)
  1914. {
  1915. if (zone)
  1916. {
  1917. if (zone->SeaIndex >= 0)
  1918. {
  1919. MapControlSetSeaRegionHighlight( map,
  1920. zone->SeaIndex,
  1921. highlight,
  1922. zone->MapLeft,
  1923. zone->MapWidth );
  1924. }
  1925. if (zone->LandIndex >= 0)
  1926. {
  1927. MapControlSetLandRegionHighlight( map,
  1928. zone->LandIndex,
  1929. highlight,
  1930. zone->MapLeft,
  1931. zone->MapWidth );
  1932. }
  1933. }
  1934. }
  1935. ////////////////////////////////////////////////////////////////////////////
  1936. //
  1937. // SetZoneFamilyState
  1938. //
  1939. // Sets the display state of a time zone family in the map control.
  1940. //
  1941. ////////////////////////////////////////////////////////////////////////////
  1942. void SetZoneFamilyState(
  1943. HWND map,
  1944. PTZINFO family,
  1945. BOOL highlight)
  1946. {
  1947. if (family)
  1948. {
  1949. PTZINFO zone = family;
  1950. do
  1951. {
  1952. SetZoneState(map, zone, highlight);
  1953. zone = zone->next;
  1954. }
  1955. while(zone && (zone != family));
  1956. }
  1957. }
  1958. ////////////////////////////////////////////////////////////////////////////
  1959. //
  1960. // ParseMapInfo
  1961. //
  1962. // Parses the color table information about the world bitmap we display.
  1963. //
  1964. // Expected format: "sea,land"
  1965. // where sea and land are color table indices or -1.
  1966. //
  1967. ////////////////////////////////////////////////////////////////////////////
  1968. void ParseMapInfo(
  1969. PTZINFO zone,
  1970. const TCHAR *text)
  1971. {
  1972. const TCHAR *p = text;
  1973. zone->SeaIndex = zone->LandIndex = -1;
  1974. if (*p)
  1975. {
  1976. if (*p != TEXT('-'))
  1977. {
  1978. zone->SeaIndex = 0;
  1979. while (*p && (*p != TEXT(',')))
  1980. {
  1981. zone->SeaIndex = (10 * zone->SeaIndex) + (*p - TEXT('0'));
  1982. p++;
  1983. }
  1984. }
  1985. else
  1986. {
  1987. do
  1988. {
  1989. p++;
  1990. } while (*p && (*p != TEXT(',')));
  1991. }
  1992. if (*p == TEXT(','))
  1993. {
  1994. p++;
  1995. }
  1996. if (*p)
  1997. {
  1998. if (*p != TEXT('-'))
  1999. {
  2000. zone->LandIndex = 0;
  2001. while (*p)
  2002. {
  2003. zone->LandIndex = (10 * zone->LandIndex) + (*p - TEXT('0'));
  2004. p++;
  2005. }
  2006. }
  2007. }
  2008. }
  2009. }
  2010. ////////////////////////////////////////////////////////////////////////////
  2011. //
  2012. // ReadZoneData
  2013. //
  2014. // Reads the data for a time zone from the registry.
  2015. //
  2016. ////////////////////////////////////////////////////////////////////////////
  2017. BOOL ReadZoneData(
  2018. PTZINFO zone,
  2019. HKEY key,
  2020. LPCTSTR keyname)
  2021. {
  2022. TCHAR mapinfo[16];
  2023. DWORD len;
  2024. DWORD lenRet;
  2025. lenRet = sizeof(zone->szDisplayName);
  2026. if (RegQueryValueEx( key,
  2027. c_szTZDisplayName,
  2028. 0,
  2029. NULL,
  2030. (LPBYTE)zone->szDisplayName,
  2031. &lenRet ) != ERROR_SUCCESS)
  2032. {
  2033. return (FALSE);
  2034. }
  2035. else
  2036. {
  2037. zone->szDisplayName[ ARRAYSIZE(zone->szDisplayName) - 1 ] = L'\0'; // make sure it is terminated
  2038. }
  2039. //
  2040. // Under NT, the keyname is the "Standard" name. Values stored
  2041. // under the keyname contain the other strings and binary info
  2042. // related to the time zone. Every time zone must have a standard
  2043. // name, therefore, we save registry space by using the Standard
  2044. // name as the subkey name under the "Time Zones" key.
  2045. //
  2046. lenRet = sizeof(zone->szStandardName);
  2047. if (RegQueryValueEx( key,
  2048. c_szTZStandardName,
  2049. 0,
  2050. NULL,
  2051. (LPBYTE)zone->szStandardName,
  2052. &lenRet ) != ERROR_SUCCESS)
  2053. {
  2054. //
  2055. // Use keyname if can't get StandardName value.
  2056. //
  2057. StringCchCopy( zone->szStandardName, ARRAYSIZE(zone->szStandardName), keyname );
  2058. }
  2059. else
  2060. {
  2061. zone->szStandardName[ ARRAYSIZE(zone->szStandardName) - 1 ] = L'\0'; // make sure it is terminated
  2062. }
  2063. lenRet = sizeof(zone->szDaylightName);
  2064. if (RegQueryValueEx( key,
  2065. c_szTZDaylightName,
  2066. 0,
  2067. NULL,
  2068. (LPBYTE)zone->szDaylightName,
  2069. &lenRet ) != ERROR_SUCCESS)
  2070. {
  2071. return (FALSE);
  2072. }
  2073. else
  2074. {
  2075. zone->szDaylightName[ ARRAYSIZE(zone->szDaylightName) - 1 ] = L'\0'; // make sure it is terminated
  2076. }
  2077. lenRet = len = sizeof(zone->Bias)
  2078. + sizeof(zone->StandardBias)
  2079. + sizeof(zone->DaylightBias)
  2080. + sizeof(zone->StandardDate)
  2081. + sizeof(zone->DaylightDate);
  2082. if (RegQueryValueEx( key,
  2083. c_szTZI,
  2084. 0,
  2085. NULL,
  2086. (LPBYTE)&zone->Bias,
  2087. &lenRet ) != ERROR_SUCCESS
  2088. || lenRet != len )
  2089. {
  2090. return (FALSE);
  2091. }
  2092. len = sizeof(mapinfo);
  2093. if (RegQueryValueEx( key,
  2094. c_szTZMapInfo,
  2095. 0,
  2096. NULL,
  2097. (LPBYTE)mapinfo,
  2098. &len ) != ERROR_SUCCESS)
  2099. {
  2100. mapinfo[0] = TEXT('\0');
  2101. }
  2102. else
  2103. {
  2104. mapinfo[ARRAYSIZE(mapinfo) - 1 ] = L'\0';
  2105. }
  2106. ParseMapInfo(zone, mapinfo);
  2107. //
  2108. // Generate phony MapLeft and MapRight until they show up in the
  2109. // registry.
  2110. //
  2111. zone->MapLeft = ((zone->Bias * ZONE_IMAGE_SCALE) / ZONE_BIAS_SCALE) +
  2112. ZONE_IMAGE_LEFT;
  2113. zone->MapWidth = ZONE_IMAGE_WIDTH;
  2114. return (TRUE);
  2115. }
  2116. ////////////////////////////////////////////////////////////////////////////
  2117. //
  2118. // AddZoneToList
  2119. //
  2120. // Inserts a new time zone into a list, sorted by bias and then name.
  2121. //
  2122. ////////////////////////////////////////////////////////////////////////////
  2123. void AddZoneToList(
  2124. PTZINFO *list,
  2125. PTZINFO zone)
  2126. {
  2127. if (*list)
  2128. {
  2129. PTZINFO curr = NULL;
  2130. PTZINFO next = *list;
  2131. while (next && zone->Bias <= next->Bias)
  2132. {
  2133. if (zone->Bias == next->Bias)
  2134. {
  2135. if (CompareString( GetUserDefaultLCID(),
  2136. 0,
  2137. zone->szDisplayName,
  2138. -1,
  2139. next->szDisplayName,
  2140. -1 ) == CSTR_LESS_THAN)
  2141. {
  2142. break;
  2143. }
  2144. }
  2145. curr = next;
  2146. next = curr->next;
  2147. }
  2148. zone->next = next;
  2149. if (curr)
  2150. {
  2151. curr->next = zone;
  2152. }
  2153. else
  2154. {
  2155. *list = zone;
  2156. }
  2157. }
  2158. else
  2159. {
  2160. *list = zone;
  2161. }
  2162. }
  2163. ////////////////////////////////////////////////////////////////////////////
  2164. //
  2165. // FreeTimezoneList
  2166. //
  2167. // Frees all time zones in the passed list, setting the head to NULL.
  2168. //
  2169. ////////////////////////////////////////////////////////////////////////////
  2170. void FreeTimezoneList(
  2171. PTZINFO *list)
  2172. {
  2173. while (*list)
  2174. {
  2175. PTZINFO next = (*list)->next;
  2176. LocalFree((HANDLE)*list);
  2177. *list = next;
  2178. }
  2179. }
  2180. ////////////////////////////////////////////////////////////////////////////
  2181. //
  2182. // ReadTimezones
  2183. //
  2184. // Reads the time zone information from the registry.
  2185. // Returns num read, -1 on failure.
  2186. //
  2187. ////////////////////////////////////////////////////////////////////////////
  2188. int ReadTimezones(
  2189. PTZINFO *list)
  2190. {
  2191. HKEY key = NULL;
  2192. int count = -1;
  2193. *list = NULL;
  2194. if (RegOpenKey( HKEY_LOCAL_MACHINE,
  2195. c_szTimeZones,
  2196. &key ) == ERROR_SUCCESS)
  2197. {
  2198. TCHAR name[TZNAME_SIZE];
  2199. PTZINFO zone = NULL;
  2200. int i;
  2201. count = 0;
  2202. for (i = 0;
  2203. RegEnumKey(key, i, name, TZNAME_SIZE) == ERROR_SUCCESS;
  2204. i++)
  2205. {
  2206. HKEY subkey = NULL;
  2207. if (!zone &&
  2208. ((zone = (PTZINFO)LocalAlloc(LPTR, sizeof(TZINFO))) == NULL))
  2209. {
  2210. zone = *list;
  2211. *list = NULL;
  2212. count = -1;
  2213. break;
  2214. }
  2215. zone->next = NULL;
  2216. if (RegOpenKey(key, name, &subkey) == ERROR_SUCCESS)
  2217. {
  2218. //
  2219. // Each sub key name under the Time Zones key is the
  2220. // "Standard" name for the Time Zone.
  2221. //
  2222. StringCchCopy( zone->szStandardName, ARRAYSIZE(zone->szStandardName), name );
  2223. if (ReadZoneData(zone, subkey, name))
  2224. {
  2225. AddZoneToList(list, zone);
  2226. zone = NULL;
  2227. count++;
  2228. }
  2229. RegCloseKey(subkey);
  2230. }
  2231. }
  2232. FreeTimezoneList(&zone);
  2233. RegCloseKey(key);
  2234. }
  2235. return (count);
  2236. }
  2237. ////////////////////////////////////////////////////////////////////////////
  2238. //
  2239. // InitZoneMapping
  2240. //
  2241. // Initializes map and map lookup for a specific time zone.
  2242. //
  2243. ////////////////////////////////////////////////////////////////////////////
  2244. void InitZoneMapping(
  2245. PTZINFO *lookup,
  2246. PTZINFO list,
  2247. HWND map)
  2248. {
  2249. PTZINFO zone = list; // not needed but more readable
  2250. while (zone)
  2251. {
  2252. if (zone->SeaIndex >= 0)
  2253. {
  2254. lookup[zone->SeaIndex] = zone;
  2255. }
  2256. if (zone->LandIndex >= 0)
  2257. {
  2258. lookup[zone->LandIndex] = zone;
  2259. }
  2260. SetZoneState(map, zone, FALSE);
  2261. zone = zone->next;
  2262. }
  2263. }
  2264. ////////////////////////////////////////////////////////////////////////////
  2265. //
  2266. // BreakZonesIntoFamilies
  2267. //
  2268. // Breaks the passed list into many circular lists.
  2269. // Each list consists of all time zones with a particular bias.
  2270. // Assumes the passed list is sorted by bias.
  2271. //
  2272. ////////////////////////////////////////////////////////////////////////////
  2273. void BreakZonesIntoFamilies(
  2274. PTZINFO head)
  2275. {
  2276. PTZINFO subhead = NULL;
  2277. PTZINFO last = NULL;
  2278. PTZINFO zone = head;
  2279. while (zone)
  2280. {
  2281. subhead = zone;
  2282. do
  2283. {
  2284. last = zone;
  2285. zone = zone->next;
  2286. }
  2287. while (zone && (zone->Bias == subhead->Bias));
  2288. last->next = subhead;
  2289. }
  2290. //
  2291. // Merge -12 and +12 zones into a single group.
  2292. // Assumes populated registry and depends on sort order.
  2293. //
  2294. if ((subhead) &&
  2295. (subhead->Bias == BIAS_PLUS_12) &&
  2296. (head->Bias == BIAS_MINUS_12))
  2297. {
  2298. PTZINFO next = head;
  2299. do
  2300. {
  2301. zone = next;
  2302. next = zone->next;
  2303. }
  2304. while (next != head);
  2305. zone->next = subhead;
  2306. last->next = head;
  2307. }
  2308. }
  2309. ////////////////////////////////////////////////////////////////////////////
  2310. //
  2311. // InitTimezones
  2312. //
  2313. // Initializes time zone stuff, UI and otherwise.
  2314. //
  2315. ////////////////////////////////////////////////////////////////////////////
  2316. BOOL InitTimezones(
  2317. HWND page,
  2318. PTZINFO *lookup)
  2319. {
  2320. PTZINFO list = NULL;
  2321. if ((g_nTimeZones = ReadTimezones(&list)) >= 0)
  2322. {
  2323. HWND combo = GetDlgItem(page, IDD_TIMEZONES);
  2324. PTZINFO zone = list;
  2325. SetWindowRedraw(combo, FALSE);
  2326. while (zone)
  2327. {
  2328. int index = ComboBox_AddString(combo, zone->szDisplayName);
  2329. if (index < 0)
  2330. {
  2331. break;
  2332. }
  2333. zone->ComboIndex = index;
  2334. ComboBox_SetItemData(combo, index, (LPARAM)zone);
  2335. zone = zone->next;
  2336. }
  2337. SetWindowRedraw(combo, TRUE);
  2338. if (!zone)
  2339. {
  2340. InitZoneMapping(lookup, list, GetDlgItem(page, IDD_TIMEMAP));
  2341. BreakZonesIntoFamilies(list);
  2342. return (TRUE);
  2343. }
  2344. FreeTimezoneList(&list);
  2345. ComboBox_ResetContent(combo);
  2346. }
  2347. return (FALSE);
  2348. }
  2349. ////////////////////////////////////////////////////////////////////////////
  2350. //
  2351. // ChangeZone
  2352. //
  2353. // Updates the current zone, making sure new zone's family is highlighted.
  2354. //
  2355. ////////////////////////////////////////////////////////////////////////////
  2356. void ChangeZone(
  2357. HWND page,
  2358. TZPAGE_STATE *state,
  2359. PTZINFO zone)
  2360. {
  2361. if (zone || state->zone)
  2362. {
  2363. BOOL newfamily = (!zone || !state->zone ||
  2364. (zone->Bias != state->zone->Bias));
  2365. HWND map = GetDlgItem(page, IDD_TIMEMAP);
  2366. BOOL dayval = (zone && (zone->StandardDate.wMonth != 0));
  2367. if (newfamily && state->zone)
  2368. {
  2369. SetZoneFamilyState(map, state->zone, FALSE);
  2370. }
  2371. state->zone = zone;
  2372. if (newfamily && state->zone)
  2373. {
  2374. SetZoneFamilyState(map, state->zone, TRUE);
  2375. }
  2376. if (newfamily)
  2377. {
  2378. MapControlInvalidateDirtyRegions(map);
  2379. }
  2380. ShowWindow(GetDlgItem(page, IDD_AUTOMAGIC), (dayval != 0 ? SW_SHOW : SW_HIDE));
  2381. if (!state->initializing)
  2382. {
  2383. PropSheet_Changed(GetParent(page), page);
  2384. }
  2385. }
  2386. }
  2387. ////////////////////////////////////////////////////////////////////////////
  2388. //
  2389. // HotTrackZone
  2390. //
  2391. // Updates the map highlighting and combo selection for a given map index.
  2392. // Expects to be called with dups.
  2393. //
  2394. ////////////////////////////////////////////////////////////////////////////
  2395. void HotTrackZone(
  2396. HWND page,
  2397. TZPAGE_STATE *state,
  2398. int index)
  2399. {
  2400. PTZINFO zone = state->lookup[index];
  2401. if (zone && (zone != state->zone))
  2402. {
  2403. ComboBox_SetCurSel( GetDlgItem(page, IDD_TIMEZONES),
  2404. (zone ? zone->ComboIndex : -1) );
  2405. ChangeZone(page, state, zone);
  2406. }
  2407. }
  2408. ////////////////////////////////////////////////////////////////////////////
  2409. //
  2410. // CenterZone
  2411. //
  2412. // Updates the map highlighting and combo selection for a given map index.
  2413. // Expects to be called with dups.
  2414. //
  2415. ////////////////////////////////////////////////////////////////////////////
  2416. void CenterZone(
  2417. HWND page,
  2418. TZPAGE_STATE *state,
  2419. BOOL animate)
  2420. {
  2421. PTZINFO zone = state->zone;
  2422. if (zone)
  2423. {
  2424. HWND map = GetDlgItem(page, IDD_TIMEMAP);
  2425. MapControlRotateTo(map, zone->MapLeft + zone->MapWidth / 2, animate);
  2426. }
  2427. }
  2428. ////////////////////////////////////////////////////////////////////////////
  2429. //
  2430. // GetPTZ
  2431. //
  2432. // Returns the pointer for the iItem time zone.
  2433. // If iItem is -1 on entry, use the currently selected time zone.
  2434. //
  2435. ////////////////////////////////////////////////////////////////////////////
  2436. PTZINFO GetPTZ(
  2437. HWND hDlg,
  2438. int iItem)
  2439. {
  2440. HWND hCtl = GetDlgItem(hDlg, IDD_TIMEZONES);
  2441. if (iItem == -1)
  2442. {
  2443. iItem = (int)ComboBox_GetCurSel(hCtl);
  2444. }
  2445. if (iItem < 0)
  2446. {
  2447. return (NULL);
  2448. }
  2449. return ((PTZINFO)ComboBox_GetItemData(hCtl, iItem));
  2450. }
  2451. ////////////////////////////////////////////////////////////////////////////
  2452. //
  2453. // GetAllowLocalTimeChange
  2454. //
  2455. ////////////////////////////////////////////////////////////////////////////
  2456. TCHAR c_szRegPathTZControl[] = REGSTR_PATH_TIMEZONE;
  2457. TCHAR c_szRegValDisableTZUpdate[] = REGSTR_VAL_TZNOAUTOTIME;
  2458. BOOL GetAllowLocalTimeChange()
  2459. {
  2460. //
  2461. // Assume allowed until we see a disallow flag.
  2462. //
  2463. BOOL result = TRUE;
  2464. HKEY key;
  2465. if (RegOpenKey( HKEY_LOCAL_MACHINE,
  2466. c_szRegPathTZControl,
  2467. &key ) == ERROR_SUCCESS)
  2468. {
  2469. //
  2470. // Assume no disallow flag until we see one.
  2471. //
  2472. DWORD value = 0;
  2473. long len = sizeof(value);
  2474. DWORD type;
  2475. if ((RegQueryValueEx( key,
  2476. c_szRegValDisableTZUpdate,
  2477. NULL,
  2478. &type,
  2479. (LPBYTE)&value,
  2480. &len ) == ERROR_SUCCESS) &&
  2481. ((type == REG_DWORD) || (type == REG_BINARY)) &&
  2482. (len == sizeof(value)) && value)
  2483. {
  2484. //
  2485. // Okay, we have a nonzero value, it is either:
  2486. //
  2487. // 1) 0xFFFFFFFF
  2488. // this is set in an inf file for first boot to prevent
  2489. // the base from performing any cutovers during setup.
  2490. //
  2491. // 2) some other value
  2492. // this signifies that the user actualy disabled cutovers
  2493. // *return that local time changes are disabled
  2494. //
  2495. if (value != 0xFFFFFFFF)
  2496. {
  2497. result = FALSE;
  2498. }
  2499. }
  2500. RegCloseKey(key);
  2501. }
  2502. return (result);
  2503. }
  2504. ////////////////////////////////////////////////////////////////////////////
  2505. //
  2506. // SetAllowLocalTimeChange
  2507. //
  2508. ////////////////////////////////////////////////////////////////////////////
  2509. void SetAllowLocalTimeChange(
  2510. BOOL fAllow)
  2511. {
  2512. HKEY key = NULL;
  2513. if (fAllow)
  2514. {
  2515. //
  2516. // Remove the disallow flag from the registry if it exists.
  2517. //
  2518. if (RegOpenKey( HKEY_LOCAL_MACHINE,
  2519. c_szRegPathTZControl,
  2520. &key ) == ERROR_SUCCESS)
  2521. {
  2522. RegDeleteValue(key, c_szRegValDisableTZUpdate);
  2523. }
  2524. }
  2525. else
  2526. {
  2527. //
  2528. // Add/set the nonzero disallow flag.
  2529. //
  2530. if (RegCreateKey( HKEY_LOCAL_MACHINE,
  2531. c_szRegPathTZControl,
  2532. &key ) == ERROR_SUCCESS)
  2533. {
  2534. DWORD value = 1;
  2535. RegSetValueEx( key,
  2536. (LPCTSTR)c_szRegValDisableTZUpdate,
  2537. 0UL,
  2538. REG_DWORD,
  2539. (LPBYTE)&value,
  2540. sizeof(value) );
  2541. }
  2542. }
  2543. if (key)
  2544. {
  2545. RegCloseKey(key);
  2546. }
  2547. }
  2548. ////////////////////////////////////////////////////////////////////////////
  2549. //
  2550. // InitTimeZonePage
  2551. //
  2552. // This function initializes everything to do with the Time Zones.
  2553. //
  2554. ////////////////////////////////////////////////////////////////////////////
  2555. BOOL InitTimeZonePage(
  2556. HWND hDlg,
  2557. TZPAGE_STATE *state)
  2558. {
  2559. TIME_ZONE_INFORMATION tziCurrent;
  2560. DWORD dwTZID;
  2561. PTZINFO ptzi;
  2562. int j ,iCurrentTZ;
  2563. BOOL fForceSelection = FALSE;
  2564. TCHAR temp[TZNAME_SIZE];
  2565. TCHAR oldTzMapName[TZNAME_SIZE], newTzMapName[TZNAME_SIZE];
  2566. //
  2567. // Get the current time zone information.
  2568. //
  2569. dwTZID = GetTimeZoneInformation(&tziCurrent);
  2570. LoadString(g_hInst, IDS_ISRAELTIMEZONE, oldTzMapName, TZNAME_SIZE);
  2571. LoadString(g_hInst, IDS_JERUSALEMTIMEZONE, newTzMapName, TZNAME_SIZE);
  2572. // this is a hack for Win95 or WinNT 4 to Win98/Win2k migration. "Israel" became "Jerusalem"
  2573. if (!lstrcmpi(oldTzMapName, tziCurrent.StandardName))
  2574. {
  2575. StringCchCopy( tziCurrent.StandardName, ARRAYSIZE(tziCurrent.StandardName), newTzMapName );
  2576. fForceSelection = TRUE;
  2577. }
  2578. //
  2579. // Check for bogus time zone info.
  2580. //
  2581. if (dwTZID != TIME_ZONE_ID_INVALID)
  2582. {
  2583. //
  2584. // Copy the name out so we can check for first boot.
  2585. //
  2586. StringCchCopy( temp, ARRAYSIZE(temp), tziCurrent.StandardName );
  2587. }
  2588. else
  2589. {
  2590. //
  2591. // Treat bogus time zones like first boot.
  2592. //
  2593. StringCchCopy( temp, ARRAYSIZE(temp), c_szFirstBootTZ );
  2594. }
  2595. if (lstrcmpi(temp, c_szFirstBootTZ) == 0)
  2596. {
  2597. //
  2598. // The 'default' value of the time zone key specifies the
  2599. // default zone.
  2600. //
  2601. TCHAR szDefaultName[TZNAME_SIZE];
  2602. LONG len = sizeof(szDefaultName);
  2603. if (RegQueryValue( HKEY_LOCAL_MACHINE,
  2604. c_szTimeZones,
  2605. szDefaultName,
  2606. &len ) == ERROR_SUCCESS)
  2607. {
  2608. StringCchCopy( tziCurrent.StandardName, ARRAYSIZE(tziCurrent.StandardName), szDefaultName );
  2609. }
  2610. else
  2611. {
  2612. tziCurrent.StandardName[0] = L'\0';
  2613. }
  2614. //
  2615. // If we can't find it by name, use GMT.
  2616. //
  2617. tziCurrent.StandardBias = tziCurrent.DaylightBias = tziCurrent.Bias = 0;
  2618. //
  2619. // Force the user to make a valid choice before quitting.
  2620. //
  2621. fForceSelection = TRUE;
  2622. }
  2623. //
  2624. // Get the Time Zones from the registry.
  2625. //
  2626. InitTimezones(hDlg, state->lookup);
  2627. //
  2628. // Try to select the 'current' one or some equivalent.
  2629. //
  2630. //
  2631. // Start with an invalid index.
  2632. //
  2633. iCurrentTZ = g_nTimeZones;
  2634. //
  2635. // Try to find by name.
  2636. //
  2637. for (j = 0; j < g_nTimeZones; j++)
  2638. {
  2639. ptzi = GetPTZ(hDlg, j);
  2640. if (!lstrcmpi(ptzi->szStandardName, tziCurrent.StandardName))
  2641. {
  2642. iCurrentTZ = j;
  2643. break;
  2644. }
  2645. }
  2646. //
  2647. // If it hasn't been found yet, try to find a nearby zone using biases.
  2648. //
  2649. if (iCurrentTZ == g_nTimeZones)
  2650. {
  2651. int nBestHitCount = TZ_HIT_NONE;
  2652. for (j = 0; j < g_nTimeZones; j++)
  2653. {
  2654. ptzi = GetPTZ(hDlg, j);
  2655. if (ptzi->Bias == tziCurrent.Bias)
  2656. {
  2657. int nHitCount = TZ_HIT_BASE +
  2658. ((ptzi->StandardBias == tziCurrent.StandardBias) +
  2659. (ptzi->DaylightBias == tziCurrent.DaylightBias));
  2660. if (nHitCount > nBestHitCount)
  2661. {
  2662. nBestHitCount = nHitCount;
  2663. iCurrentTZ = j;
  2664. if (nHitCount >= TZ_HIT_EXACT)
  2665. {
  2666. break;
  2667. }
  2668. }
  2669. }
  2670. }
  2671. }
  2672. //
  2673. // Still didn't find it?
  2674. //
  2675. if (iCurrentTZ == g_nTimeZones)
  2676. {
  2677. //
  2678. // Punt.
  2679. //
  2680. iCurrentTZ = 0;
  2681. fForceSelection = TRUE;
  2682. }
  2683. //
  2684. // Set up the dialog using this time zone's info.
  2685. //
  2686. //
  2687. // If wMonth is 0, then this Time Zone does not support DST.
  2688. //
  2689. if ((tziCurrent.StandardDate.wMonth == 0) ||
  2690. (tziCurrent.DaylightDate.wMonth == 0))
  2691. {
  2692. ShowWindow(GetDlgItem(hDlg, IDD_AUTOMAGIC), SW_HIDE);
  2693. }
  2694. //
  2695. // Always get "allow DLT" flag even if this zone is disabled.
  2696. //
  2697. CheckDlgButton(hDlg, IDD_AUTOMAGIC, GetAllowLocalTimeChange());
  2698. ComboBox_SetCurSel(GetDlgItem(hDlg, IDD_TIMEZONES), iCurrentTZ);
  2699. ChangeZone(hDlg, state, GetPTZ(hDlg, -1));
  2700. CenterZone(hDlg, state, FALSE);
  2701. if (fForceSelection || g_bFirstBoot)
  2702. {
  2703. PropSheet_Changed(GetParent(hDlg), hDlg);
  2704. PropSheet_CancelToClose(GetParent(hDlg));
  2705. }
  2706. return (TRUE);
  2707. }
  2708. ////////////////////////////////////////////////////////////////////////////
  2709. //
  2710. // SetTheTimezone
  2711. //
  2712. // Apply the User's time zone selection.
  2713. //
  2714. ////////////////////////////////////////////////////////////////////////////
  2715. void SetTheTimezone(
  2716. BOOL bAutoMagicTimeChange,
  2717. BOOL bAutoMagicEnabled,
  2718. PTZINFO ptzi)
  2719. {
  2720. TIME_ZONE_INFORMATION tzi;
  2721. HCURSOR hCurOld;
  2722. if (!ptzi)
  2723. {
  2724. return;
  2725. }
  2726. tzi.Bias = ptzi->Bias;
  2727. if ((bAutoMagicTimeChange == 0) ||
  2728. (ptzi->StandardDate.wMonth == 0))
  2729. {
  2730. //
  2731. // Standard Only.
  2732. //
  2733. tzi.StandardBias = ptzi->StandardBias;
  2734. tzi.DaylightBias = ptzi->StandardBias;
  2735. tzi.StandardDate = ptzi->StandardDate;
  2736. tzi.DaylightDate = ptzi->StandardDate;
  2737. StringCchCopy( tzi.StandardName, ARRAYSIZE(tzi.StandardName), ptzi->szStandardName );
  2738. StringCchCopy( tzi.DaylightName, ARRAYSIZE(tzi.DaylightName), ptzi->szStandardName );
  2739. }
  2740. else
  2741. {
  2742. //
  2743. // Automatically adjust for Daylight Saving Time.
  2744. //
  2745. tzi.StandardBias = ptzi->StandardBias;
  2746. tzi.DaylightBias = ptzi->DaylightBias;
  2747. tzi.StandardDate = ptzi->StandardDate;
  2748. tzi.DaylightDate = ptzi->DaylightDate;
  2749. StringCchCopy( tzi.StandardName, ARRAYSIZE(tzi.StandardName), ptzi->szStandardName );
  2750. StringCchCopy( tzi.DaylightName, ARRAYSIZE(tzi.DaylightName), ptzi->szDaylightName );
  2751. }
  2752. SetAllowLocalTimeChange(bAutoMagicTimeChange);
  2753. SetTimeZoneInformation(&tzi);
  2754. hCurOld = SetCursor(LoadCursor(NULL, IDC_WAIT));
  2755. SetCursor(hCurOld);
  2756. }
  2757. ////////////////////////////////////////////////////////////////////////////
  2758. //
  2759. // TimeZoneDlgProc
  2760. //
  2761. ////////////////////////////////////////////////////////////////////////////
  2762. INT_PTR CALLBACK TimeZoneDlgProc(
  2763. HWND hDlg,
  2764. UINT uMsg,
  2765. WPARAM wParam,
  2766. LPARAM lParam)
  2767. {
  2768. TZPAGE_STATE *state = (TZPAGE_STATE *)GetWindowLongPtr(hDlg, DWLP_USER);
  2769. int i;
  2770. switch (uMsg)
  2771. {
  2772. case ( WM_INITDIALOG ) :
  2773. {
  2774. state = (TZPAGE_STATE *)LocalAlloc(LPTR, sizeof(TZPAGE_STATE));
  2775. SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR)state);
  2776. if (!state)
  2777. {
  2778. EndDialog(hDlg, -1);
  2779. break;
  2780. }
  2781. state->initializing = TRUE;
  2782. InitTimeZonePage(hDlg, state);
  2783. state->initializing = FALSE;
  2784. break;
  2785. }
  2786. case ( WM_DESTROY ) :
  2787. {
  2788. for (i = 0; i < g_nTimeZones; i++)
  2789. {
  2790. LocalFree((HLOCAL)GetPTZ(hDlg, i));
  2791. }
  2792. if (state)
  2793. {
  2794. LocalFree((HANDLE)state);
  2795. SetWindowLongPtr(hDlg, DWLP_USER, 0L);
  2796. }
  2797. break;
  2798. }
  2799. case ( WM_NOTIFY ) :
  2800. {
  2801. switch (((NMHDR *)lParam)->idFrom)
  2802. {
  2803. case ( 0 ) :
  2804. {
  2805. switch (((NMHDR *)lParam)->code)
  2806. {
  2807. case ( PSN_APPLY ) :
  2808. {
  2809. g_ptziCurrent = NULL;
  2810. //
  2811. // Find out which listbox item was selected.
  2812. //
  2813. SetTheTimezone(
  2814. IsDlgButtonChecked(hDlg, IDD_AUTOMAGIC),
  2815. IsWindowVisible(GetDlgItem(hDlg, IDD_AUTOMAGIC)),
  2816. GetPTZ(hDlg, -1) );
  2817. //
  2818. // if the user had modified the time as well as the timezone,
  2819. // then we should honor the time that they gave us since they
  2820. // explicitly said this was the time. If we don't then the
  2821. // time they entered will be offset by the timezone change
  2822. //
  2823. if (g_WasModified)
  2824. {
  2825. g_WasModified = FALSE;
  2826. SetTime();
  2827. }
  2828. break;
  2829. }
  2830. }
  2831. break;
  2832. }
  2833. case ( IDD_TIMEMAP ) :
  2834. {
  2835. NFYMAPEVENT *event = (NFYMAPEVENT *)lParam;
  2836. switch (event->hdr.code)
  2837. {
  2838. case ( MAPN_TOUCH ) :
  2839. {
  2840. HotTrackZone(hDlg, state, event->index);
  2841. break;
  2842. }
  2843. case ( MAPN_SELECT ) :
  2844. {
  2845. CenterZone(hDlg, state, TRUE);
  2846. break;
  2847. }
  2848. }
  2849. break;
  2850. }
  2851. }
  2852. break;
  2853. }
  2854. case ( WM_COMMAND ) :
  2855. {
  2856. switch (GET_WM_COMMAND_ID(wParam, lParam))
  2857. {
  2858. case ( IDD_TIMEZONES ) : // combo box
  2859. {
  2860. if (GET_WM_COMMAND_CMD(wParam, lParam) == CBN_SELCHANGE)
  2861. {
  2862. ChangeZone(hDlg, state, GetPTZ(hDlg, -1));
  2863. CenterZone(hDlg, state, TRUE);
  2864. }
  2865. break;
  2866. }
  2867. case ( IDD_AUTOMAGIC ) : // check box
  2868. {
  2869. if (GET_WM_COMMAND_CMD(wParam, lParam) == BN_CLICKED)
  2870. {
  2871. PropSheet_Changed(GetParent(hDlg), hDlg);
  2872. }
  2873. break;
  2874. }
  2875. }
  2876. break;
  2877. }
  2878. case ( WM_HELP ) : // F1
  2879. {
  2880. WinHelp( (HWND)((LPHELPINFO)lParam)->hItemHandle,
  2881. NULL,
  2882. HELP_WM_HELP,
  2883. (DWORD_PTR)(LPTSTR)aDateTimeHelpIds );
  2884. break;
  2885. }
  2886. case ( WM_CONTEXTMENU ) : // right mouse click
  2887. {
  2888. WinHelp( (HWND)wParam,
  2889. NULL,
  2890. HELP_CONTEXTMENU,
  2891. (DWORD_PTR)(LPTSTR)aDateTimeHelpIds );
  2892. break;
  2893. }
  2894. default :
  2895. {
  2896. return (FALSE);
  2897. }
  2898. }
  2899. return (TRUE);
  2900. }
  2901. ////////////////////////////////////////////////////////////////////////////
  2902. //
  2903. // GetClInt
  2904. //
  2905. // Steal an int from the command line.
  2906. //
  2907. ////////////////////////////////////////////////////////////////////////////
  2908. static int GetClInt(
  2909. const TCHAR *p)
  2910. {
  2911. BOOL neg = FALSE;
  2912. int v = 0;
  2913. //
  2914. // Skip spaces.
  2915. //
  2916. while (*p == TEXT(' '))
  2917. {
  2918. p++;
  2919. }
  2920. //
  2921. // See if it's negative.
  2922. //
  2923. if (*p == TEXT('-'))
  2924. {
  2925. //
  2926. // It's negative. Remember that it's negative and skip the
  2927. // '-' char.
  2928. //
  2929. neg = TRUE;
  2930. p++;
  2931. }
  2932. //
  2933. // Parse the absolute portion. Digits only.
  2934. //
  2935. while ((*p >= TEXT('0')) && (*p <= TEXT('9')))
  2936. {
  2937. //
  2938. // Accumulate the value.
  2939. //
  2940. v = v * 10 + *p++ - TEXT('0');
  2941. }
  2942. //
  2943. // Return the result.
  2944. //
  2945. return (neg ? -v : v);
  2946. }
  2947. ////////////////////////////////////////////////////////////////////////////
  2948. //
  2949. // SelectZoneByName
  2950. //
  2951. ////////////////////////////////////////////////////////////////////////////
  2952. BOOL SelectZoneByName(
  2953. LPCTSTR cmdline)
  2954. {
  2955. BOOL result = FALSE;
  2956. HKEY key = NULL;
  2957. while (*cmdline == TEXT(' '))
  2958. {
  2959. cmdline++;
  2960. }
  2961. if (!*cmdline)
  2962. {
  2963. return (FALSE);
  2964. }
  2965. if (RegOpenKey( HKEY_LOCAL_MACHINE,
  2966. c_szTimeZones,
  2967. &key ) == ERROR_SUCCESS)
  2968. {
  2969. TCHAR name[TZNAME_SIZE];
  2970. HKEY subkey = NULL;
  2971. TZINFO zone;
  2972. //
  2973. // User can pass key name.
  2974. //
  2975. if (RegOpenKey(key, cmdline, &subkey) == ERROR_SUCCESS)
  2976. {
  2977. if (ReadZoneData(&zone, subkey, cmdline))
  2978. {
  2979. result = TRUE;
  2980. }
  2981. }
  2982. else
  2983. {
  2984. //
  2985. // User can also pass display name.
  2986. //
  2987. int i;
  2988. int CmdLen = lstrlen(cmdline);
  2989. for (i = 0;
  2990. RegEnumKey(key, i, name, TZNAME_SIZE) == ERROR_SUCCESS;
  2991. i++)
  2992. {
  2993. if (RegOpenKey(key, name, &subkey) == ERROR_SUCCESS)
  2994. {
  2995. LONG len = sizeof(zone.szDisplayName);
  2996. LRESULT lr = RegQueryValueEx( subkey
  2997. , c_szTZDisplayName
  2998. , 0
  2999. , NULL
  3000. , (LPBYTE) &zone.szDisplayName
  3001. , &len
  3002. );
  3003. if ( ERROR_SUCCESS == lr )
  3004. {
  3005. zone.szDisplayName[ ARRAYSIZE(zone.szDisplayName) - 1 ] = L'\0'; // make sure it is terminated.
  3006. if ( CompareString( GetUserDefaultLCID()
  3007. , NORM_IGNORECASE | NORM_IGNOREKANATYPE
  3008. | NORM_IGNOREWIDTH | NORM_IGNORENONSPACE
  3009. , zone.szDisplayName
  3010. , (CmdLen < 15) ? -1 : min(lstrlen(zone.szDisplayName), CmdLen)
  3011. , cmdline
  3012. , -1
  3013. ) == CSTR_EQUAL)
  3014. {
  3015. if (ReadZoneData(&zone, subkey, name))
  3016. {
  3017. result = TRUE;
  3018. }
  3019. }
  3020. }
  3021. RegCloseKey(subkey);
  3022. }
  3023. if (result)
  3024. {
  3025. break;
  3026. }
  3027. }
  3028. }
  3029. RegCloseKey(key);
  3030. if (result)
  3031. {
  3032. SetTheTimezone(1, 1, &zone);
  3033. }
  3034. }
  3035. return (result);
  3036. }
  3037. ////////////////////////////////////////////////////////////////////////////
  3038. //
  3039. // OpenDateTimePropertySheet
  3040. //
  3041. // Opens a DateTime property sheet.
  3042. // Set the page for the property sheet.
  3043. //
  3044. ////////////////////////////////////////////////////////////////////////////
  3045. BOOL OpenDateTimePropertySheet(
  3046. HWND hwnd,
  3047. LPCTSTR cmdline)
  3048. {
  3049. // Make this an array for multiple pages.
  3050. PROPSHEETPAGE apsp[3];
  3051. PROPSHEETHEADER psh;
  3052. HDC hDC;
  3053. HFONT hFont;
  3054. int wMaxDigitWidth;
  3055. BOOL fReturn;
  3056. HRESULT hrOle;
  3057. hDC = GetDC(hwnd);
  3058. wMaxDigitWidth = GetMaxSubstitutedCharWidth(hDC);
  3059. ReleaseDC(hwnd, hDC);
  3060. psh.nStartPage = (UINT)-1;
  3061. if (cmdline && *cmdline)
  3062. {
  3063. if (*cmdline == TEXT('/'))
  3064. {
  3065. BOOL fAutoSet = FALSE;
  3066. //
  3067. // Legend:
  3068. // zZ: first boot batch mode setup "/z pacific" etc
  3069. // fF: regular first boot
  3070. // mM: time zone change forced local time change message
  3071. //
  3072. switch (*++cmdline)
  3073. {
  3074. case ( TEXT('z') ) :
  3075. case ( TEXT('Z') ) :
  3076. {
  3077. fAutoSet = TRUE;
  3078. //
  3079. // Fall thru...
  3080. //
  3081. }
  3082. case ( TEXT('f') ) :
  3083. case ( TEXT('F') ) :
  3084. {
  3085. g_bFirstBoot = TRUE;
  3086. if (fAutoSet && SelectZoneByName(cmdline + 1))
  3087. {
  3088. return (TRUE);
  3089. }
  3090. //
  3091. // Start on time zone page.
  3092. //
  3093. psh.nStartPage = 1;
  3094. break;
  3095. }
  3096. case ( TEXT('m') ) :
  3097. case ( TEXT('M') ) :
  3098. {
  3099. MSGBOXPARAMS params =
  3100. {
  3101. sizeof(params),
  3102. hwnd,
  3103. g_hInst,
  3104. MAKEINTRESOURCE(IDS_WARNAUTOTIMECHANGE),
  3105. MAKEINTRESOURCE(IDS_WATC_CAPTION),
  3106. MB_OK | MB_USERICON,
  3107. MAKEINTRESOURCE(IDI_TIMEDATE),
  3108. 0,
  3109. NULL,
  3110. 0
  3111. };
  3112. MessageBoxIndirect(&params);
  3113. //
  3114. // Show time/date page for user to verify.
  3115. //
  3116. psh.nStartPage = 0;
  3117. break;
  3118. }
  3119. default :
  3120. {
  3121. //
  3122. // Fall out, maybe it's a number...
  3123. //
  3124. break;
  3125. }
  3126. }
  3127. }
  3128. }
  3129. if (psh.nStartPage == (UINT)-1)
  3130. {
  3131. if (cmdline && (*cmdline >= TEXT('0')) && (*cmdline <= TEXT('9')))
  3132. {
  3133. psh.nStartPage = GetClInt(cmdline);
  3134. }
  3135. else
  3136. {
  3137. psh.nStartPage = 0;
  3138. }
  3139. }
  3140. //
  3141. // Register our classes.
  3142. //
  3143. ClockInit(g_hInst);
  3144. CalendarInit(g_hInst);
  3145. RegisterMapControlStuff(g_hInst);
  3146. psh.dwSize = sizeof(psh);
  3147. if (g_bFirstBoot)
  3148. {
  3149. //
  3150. // Disable Apply button for first boot.
  3151. //
  3152. psh.dwFlags = PSH_PROPTITLE | PSH_PROPSHEETPAGE | PSH_NOAPPLYNOW;
  3153. }
  3154. else
  3155. {
  3156. psh.dwFlags = PSH_PROPTITLE | PSH_PROPSHEETPAGE;
  3157. }
  3158. psh.hwndParent = hwnd;
  3159. psh.hInstance = g_hInst;
  3160. psh.pszIcon = NULL;
  3161. //
  3162. // psh.nStartPage is set above.
  3163. //
  3164. if(g_bShowOnlyTimeZone)
  3165. {
  3166. psh.pszCaption = MAKEINTRESOURCE(IDS_TIMEDATE);
  3167. psh.nPages = 1;
  3168. psh.ppsp = apsp;
  3169. apsp[0].dwSize = sizeof(PROPSHEETPAGE);
  3170. apsp[0].dwFlags = PSP_DEFAULT;
  3171. apsp[0].hInstance = g_hInst;
  3172. apsp[0].pszTemplate = MAKEINTRESOURCE(DLG_TIMEZONE);
  3173. apsp[0].pfnDlgProc = TimeZoneDlgProc;
  3174. apsp[0].lParam = 0;
  3175. }
  3176. else
  3177. {
  3178. psh.pszCaption = MAKEINTRESOURCE(IDS_TIMEDATE);
  3179. psh.nPages = 2;
  3180. psh.ppsp = apsp;
  3181. apsp[0].dwSize = sizeof(PROPSHEETPAGE);
  3182. apsp[0].dwFlags = PSP_DEFAULT;
  3183. apsp[0].hInstance = g_hInst;
  3184. apsp[0].pszTemplate = wMaxDigitWidth > 8 ? MAKEINTRESOURCE(DLG_DATETIMEWIDE) : MAKEINTRESOURCE(DLG_DATETIME);
  3185. apsp[0].pfnDlgProc = DateTimeDlgProc;
  3186. apsp[0].lParam = 0;
  3187. apsp[1].dwSize = sizeof(PROPSHEETPAGE);
  3188. apsp[1].dwFlags = PSP_DEFAULT;
  3189. apsp[1].hInstance = g_hInst;
  3190. apsp[1].pszTemplate = MAKEINTRESOURCE(DLG_TIMEZONE);
  3191. apsp[1].pfnDlgProc = TimeZoneDlgProc;
  3192. apsp[1].lParam = 0;
  3193. }
  3194. if (psh.nStartPage >= psh.nPages)
  3195. {
  3196. psh.nStartPage = 0;
  3197. }
  3198. // We use the HyperLink control and that requires OLE (for IAccessible)
  3199. hrOle = CoInitialize(0);
  3200. fReturn = (BOOL)PropertySheet(&psh);
  3201. if (SUCCEEDED(hrOle))
  3202. {
  3203. CoUninitialize();
  3204. }
  3205. return fReturn;
  3206. }