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.

954 lines
25 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. datetime.cpp
  5. Abstract:
  6. This file implements the date & time page.
  7. Environment:
  8. WIN32 User Mode
  9. Author:
  10. Wesley Witt (wesw) 1-Dec-1997
  11. --*/
  12. #include "ntoc.h"
  13. #pragma hdrstop
  14. #define MYDEBUG 0
  15. #define TIMER_ID 1
  16. #define OPEN_TLEN 450 /* < half second */
  17. #define TZNAME_SIZE 128
  18. #define TZDISPLAYZ 128
  19. #define REGKEY_TIMEZONES L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones"
  20. #define REGVAL_TZ_DISPLAY L"Display"
  21. #define REGVAL_TZ_STD L"Std"
  22. #define REGVAL_TZ_DAYLIGHT L"Dlt"
  23. #define REGVAL_TZ_TZI L"TZI"
  24. #define REGVAL_TZ_INDEX L"Index"
  25. #define REGVAL_TZ_INDEXMAP L"IndexMapping"
  26. #define REGKEY_TIMEZONE_INFO L"System\\CurrentControlSet\\Control\\TimeZoneInformation"
  27. #define REGVAL_TZNOAUTOTIME L"DisableAutoDaylightTimeSet"
  28. typedef struct tagTZINFO
  29. {
  30. LIST_ENTRY ListEntry;
  31. WCHAR szDisplayName[TZDISPLAYZ];
  32. WCHAR szStandardName[TZNAME_SIZE];
  33. WCHAR szDaylightName[TZNAME_SIZE];
  34. int ReferenceIndex;
  35. LONG Bias;
  36. LONG StandardBias;
  37. LONG DaylightBias;
  38. SYSTEMTIME StandardDate;
  39. SYSTEMTIME DaylightDate;
  40. } TZINFO, *PTZINFO;
  41. LIST_ENTRY ZoneList;
  42. SYSTEMTIME SelectedTime;
  43. SYSTEMTIME SelectedDate;
  44. BOOL ChangeTime;
  45. BOOL ChangeDate;
  46. PTZINFO CurrZone;
  47. BOOL AllowAutoDST;
  48. INT gUnattenedTimeZone = -1;
  49. BOOL DateTimeBadUnattend;
  50. HWND ghWnd; // global copy of the handle to the wizard page. This
  51. // is required by DateTimeCommitChanges during an
  52. // unattended installation.
  53. BOOL
  54. ReadZoneData(
  55. PTZINFO zone,
  56. HKEY key,
  57. LPCWSTR keyname
  58. )
  59. {
  60. WCHAR mapinfo[16];
  61. DWORD len;
  62. len = sizeof(zone->szDisplayName);
  63. if (RegQueryValueEx( key,
  64. REGVAL_TZ_DISPLAY,
  65. 0,
  66. NULL,
  67. (LPBYTE)zone->szDisplayName,
  68. &len ) != ERROR_SUCCESS)
  69. {
  70. return (FALSE);
  71. }
  72. //
  73. // Under NT, the keyname is the "Standard" name. Values stored
  74. // under the keyname contain the other strings and binary info
  75. // related to the time zone. Every time zone must have a standard
  76. // name, therefore, we save registry space by using the Standard
  77. // name as the subkey name under the "Time Zones" key.
  78. //
  79. len = sizeof(zone->szStandardName);
  80. if (RegQueryValueEx( key,
  81. REGVAL_TZ_STD,
  82. 0,
  83. NULL,
  84. (LPBYTE)zone->szStandardName,
  85. &len ) != ERROR_SUCCESS)
  86. {
  87. //
  88. // Use keyname if can't get StandardName value.
  89. //
  90. lstrcpyn( zone->szStandardName,
  91. keyname,
  92. sizeof(zone->szStandardName) );
  93. }
  94. len = sizeof(zone->szDaylightName);
  95. if (RegQueryValueEx( key,
  96. REGVAL_TZ_DAYLIGHT,
  97. 0,
  98. NULL,
  99. (LPBYTE)zone->szDaylightName,
  100. &len ) != ERROR_SUCCESS)
  101. {
  102. return (FALSE);
  103. }
  104. len = sizeof(zone->ReferenceIndex);
  105. if (RegQueryValueEx( key,
  106. REGVAL_TZ_INDEX,
  107. 0,
  108. NULL,
  109. (LPBYTE)&zone->ReferenceIndex,
  110. &len ) != ERROR_SUCCESS)
  111. {
  112. return (FALSE);
  113. }
  114. len = sizeof(zone->Bias) +
  115. sizeof(zone->StandardBias) +
  116. sizeof(zone->DaylightBias) +
  117. sizeof(zone->StandardDate) +
  118. sizeof(zone->DaylightDate);
  119. if (RegQueryValueEx( key,
  120. REGVAL_TZ_TZI,
  121. 0,
  122. NULL,
  123. (LPBYTE)&zone->Bias,
  124. &len ) != ERROR_SUCCESS)
  125. {
  126. return (FALSE);
  127. }
  128. return (TRUE);
  129. }
  130. #if MYDEBUG
  131. void
  132. PrintZones(
  133. void
  134. )
  135. {
  136. PLIST_ENTRY NextZone;
  137. PTZINFO zone;
  138. NextZone = ZoneList.Flink;
  139. if (NextZone) {
  140. DebugPrint(( L"----------------- time zone list -------------------------------------\n" ));
  141. while (NextZone != &ZoneList) {
  142. zone = CONTAINING_RECORD( NextZone, TZINFO, ListEntry );
  143. NextZone = zone->ListEntry.Flink;
  144. DebugPrint(( L"%03d %s", zone->ReferenceIndex, zone->szDisplayName ));
  145. }
  146. }
  147. }
  148. #endif
  149. void
  150. AddZoneToList(
  151. PTZINFO zone
  152. )
  153. {
  154. PLIST_ENTRY NextZone;
  155. PTZINFO ThisZone;
  156. if (IsListEmpty( &ZoneList )) {
  157. InsertHeadList( &ZoneList, &zone->ListEntry );
  158. return;
  159. }
  160. NextZone = ZoneList.Flink;
  161. while (NextZone != &ZoneList)
  162. {
  163. ThisZone = CONTAINING_RECORD( NextZone, TZINFO, ListEntry );
  164. NextZone = ThisZone->ListEntry.Flink;
  165. if (ThisZone->ReferenceIndex > zone->ReferenceIndex) {
  166. InsertTailList( &ThisZone->ListEntry, &zone->ListEntry );
  167. return;
  168. }
  169. }
  170. InsertTailList( &ZoneList, &zone->ListEntry );
  171. }
  172. int
  173. BuildTimeZoneList(
  174. void
  175. )
  176. {
  177. HKEY key = NULL;
  178. int count = -1;
  179. InitializeListHead( &ZoneList );
  180. if (RegOpenKey( HKEY_LOCAL_MACHINE, REGKEY_TIMEZONES, &key ) == ERROR_SUCCESS)
  181. {
  182. WCHAR name[TZNAME_SIZE];
  183. PTZINFO zone = NULL;
  184. int i;
  185. count = 0;
  186. for (i = 0; RegEnumKey( key, i, name, TZNAME_SIZE ) == ERROR_SUCCESS; i++)
  187. {
  188. HKEY subkey = NULL;
  189. if (!zone &&
  190. ((zone = (PTZINFO)LocalAlloc(LPTR, sizeof(TZINFO))) == NULL))
  191. {
  192. break;
  193. }
  194. if (RegOpenKey(key, name, &subkey) == ERROR_SUCCESS)
  195. {
  196. //
  197. // Each sub key name under the Time Zones key is the
  198. // "Standard" name for the Time Zone.
  199. //
  200. lstrcpyn(zone->szStandardName, name, TZNAME_SIZE);
  201. if (ReadZoneData(zone, subkey, name))
  202. {
  203. AddZoneToList(zone);
  204. zone = NULL;
  205. count++;
  206. }
  207. RegCloseKey(subkey);
  208. }
  209. }
  210. RegCloseKey(key);
  211. }
  212. return count;
  213. }
  214. void
  215. DateTimeInit(
  216. void
  217. )
  218. {
  219. DWORD d;
  220. BuildTimeZoneList();
  221. #if MYDEBUG
  222. PrintZones();
  223. #endif
  224. if ((SetupInitComponent.SetupData.OperationFlags & SETUPOP_BATCH) == 0) {
  225. return;
  226. }
  227. HINF InfHandle = SetupInitComponent.HelperRoutines.GetInfHandle(
  228. INFINDEX_UNATTENDED,
  229. SetupInitComponent.HelperRoutines.OcManagerContext
  230. );
  231. if (InfHandle == NULL) {
  232. DateTimeBadUnattend = TRUE;
  233. return;
  234. }
  235. INFCONTEXT InfLine;
  236. if (!SetupFindFirstLine(InfHandle, L"GuiUnattended", L"TimeZone", &InfLine )) {
  237. DateTimeBadUnattend = TRUE;
  238. return;
  239. }
  240. if (SetupGetIntField( &InfLine, 1, (PINT)&d )) {
  241. gUnattenedTimeZone = (INT) d;
  242. } else {
  243. DateTimeBadUnattend = TRUE;
  244. }
  245. }
  246. void
  247. SetAllowLocalTimeChange(
  248. BOOL fAllow
  249. )
  250. {
  251. HKEY key = NULL;
  252. if (fAllow)
  253. {
  254. //
  255. // Remove the disallow flag from the registry if it exists.
  256. //
  257. if (RegOpenKey( HKEY_LOCAL_MACHINE, REGKEY_TIMEZONE_INFO, &key ) == ERROR_SUCCESS)
  258. {
  259. RegDeleteValue(key, REGVAL_TZNOAUTOTIME);
  260. }
  261. }
  262. else
  263. {
  264. //
  265. // Add/set the nonzero disallow flag.
  266. //
  267. if (RegCreateKey( HKEY_LOCAL_MACHINE, REGKEY_TIMEZONE_INFO, &key ) == ERROR_SUCCESS)
  268. {
  269. DWORD value = 1;
  270. RegSetValueEx( key,
  271. REGVAL_TZNOAUTOTIME,
  272. 0,
  273. REG_DWORD,
  274. (LPBYTE)&value,
  275. sizeof(value) );
  276. }
  277. }
  278. if (key)
  279. {
  280. RegCloseKey(key);
  281. }
  282. }
  283. BOOL
  284. GetAllowLocalTimeChange(
  285. void
  286. )
  287. {
  288. //
  289. // Assume allowed until we see a disallow flag.
  290. //
  291. BOOL result = TRUE;
  292. HKEY key;
  293. if (RegOpenKey( HKEY_LOCAL_MACHINE, REGKEY_TIMEZONE_INFO, &key ) == ERROR_SUCCESS)
  294. {
  295. //
  296. // Assume no disallow flag until we see one.
  297. //
  298. DWORD value = 0;
  299. DWORD len = sizeof(value);
  300. DWORD type;
  301. if ((RegQueryValueEx( key,
  302. REGVAL_TZNOAUTOTIME,
  303. NULL,
  304. &type,
  305. (LPBYTE)&value,
  306. &len ) == ERROR_SUCCESS) &&
  307. ((type == REG_DWORD) || (type == REG_BINARY)) &&
  308. (len == sizeof(value)) && value)
  309. {
  310. //
  311. // Okay, we have a nonzero value, it is either:
  312. //
  313. // 1) 0xFFFFFFFF
  314. // this is set in an inf file for first boot to prevent
  315. // the base from performing any cutovers during setup.
  316. //
  317. // 2) some other value
  318. // this signifies that the user actualy disabled cutovers
  319. // *return that local time changes are disabled
  320. //
  321. if (value != 0xFFFFFFFF)
  322. {
  323. result = FALSE;
  324. }
  325. }
  326. RegCloseKey(key);
  327. }
  328. return (result);
  329. }
  330. void
  331. SetTheTimezone(
  332. BOOL bAutoMagicTimeChange,
  333. PTZINFO ptzi
  334. )
  335. {
  336. TIME_ZONE_INFORMATION tzi;
  337. HCURSOR hCurOld;
  338. if (!ptzi)
  339. {
  340. return;
  341. }
  342. tzi.Bias = ptzi->Bias;
  343. tzi.StandardName[0] = 0;
  344. lstrcpyn(tzi.StandardName, ptzi->szStandardName, sizeof(tzi.StandardName)/sizeof(tzi.StandardName[0]));
  345. tzi.StandardName[sizeof(tzi.StandardName)/sizeof(tzi.StandardName[0])-1] = 0;
  346. tzi.DaylightName[0] = 0;
  347. if ((bAutoMagicTimeChange == 0) || (ptzi->StandardDate.wMonth == 0))
  348. {
  349. //
  350. // Standard Only.
  351. //
  352. tzi.StandardBias = ptzi->StandardBias;
  353. tzi.DaylightBias = ptzi->StandardBias;
  354. tzi.StandardDate = ptzi->StandardDate;
  355. tzi.DaylightDate = ptzi->StandardDate;
  356. lstrcpyn(tzi.DaylightName, ptzi->szStandardName, sizeof(tzi.DaylightName)/sizeof(tzi.DaylightName[0]));
  357. }
  358. else
  359. {
  360. //
  361. // Automatically adjust for Daylight Saving Time.
  362. //
  363. tzi.StandardBias = ptzi->StandardBias;
  364. tzi.DaylightBias = ptzi->DaylightBias;
  365. tzi.StandardDate = ptzi->StandardDate;
  366. tzi.DaylightDate = ptzi->DaylightDate;
  367. lstrcpyn(tzi.DaylightName, ptzi->szDaylightName, sizeof(tzi.DaylightName)/sizeof(tzi.DaylightName[0]));
  368. }
  369. tzi.DaylightName[sizeof(tzi.DaylightName)/sizeof(tzi.DaylightName[0])-1] = 0;
  370. SetAllowLocalTimeChange( bAutoMagicTimeChange );
  371. SetTimeZoneInformation( &tzi );
  372. }
  373. void
  374. DateTimeApplyChanges(
  375. void
  376. )
  377. {
  378. SYSTEMTIME SysTime;
  379. if (SetupInitComponent.SetupData.OperationFlags & SETUPOP_NTUPGRADE) {
  380. return;
  381. }
  382. // Note that in the unattended case we will never have ChangeTime set
  383. // as the page never is used except for the timezone stuff. There is
  384. // no support to set date/time via unattend.
  385. if (ChangeTime) {
  386. SysTime.wHour = SelectedTime.wHour;
  387. SysTime.wMinute = SelectedTime.wMinute;
  388. SysTime.wSecond = SelectedTime.wSecond;
  389. SysTime.wMilliseconds = SelectedTime.wMilliseconds;
  390. } else {
  391. GetLocalTime( &SysTime );
  392. }
  393. // If this is an unattended setup the PSN_WIZNEXT never arrived so it is
  394. // necessary to check the state of ICD_DAYTIME which was set by DateTimeOnInitDialog().
  395. if ((SetupInitComponent.SetupData.OperationFlags & SETUPOP_BATCH) && gUnattenedTimeZone != -1) {
  396. // This is unattended.
  397. AllowAutoDST = IsDlgButtonChecked( ghWnd, IDC_DAYLIGHT ) != 0;
  398. }
  399. else
  400. {
  401. // This is NOT UNATTENDED. SelectedDate was initialized when PSN_WIZNEXT
  402. // was processed.
  403. SysTime.wYear = SelectedDate.wYear;
  404. SysTime.wMonth = SelectedDate.wMonth;
  405. SysTime.wDayOfWeek = SelectedDate.wDayOfWeek;
  406. SysTime.wDay = SelectedDate.wDay;
  407. }
  408. // Function SetLocalTime uses Time Zone information so it is IMPERATIVE that
  409. // SetTheTimezone get called before SetLocalTime.
  410. SetTheTimezone( AllowAutoDST, CurrZone );
  411. SetLocalTime( &SysTime );
  412. }
  413. void
  414. DateTimeCommitChanges(
  415. void
  416. )
  417. {
  418. return;
  419. }
  420. /////////////////////////////////////////////////////////////////////////////
  421. //++
  422. //
  423. // GetTimeZoneReferenceIndexFromRegistry
  424. //
  425. // Routine Description:
  426. // This funecion extracts the Time Zone reference index from information that
  427. // is stored in the registry.
  428. //
  429. // Arguments:
  430. // None
  431. //
  432. // Return Value:
  433. // The Time Zone reference index. If no valid reference index is deduced
  434. // this function will return zero.
  435. //
  436. // Note:
  437. // The logic performed by the following function was originally implemented in
  438. // DateTimeOnInitDialog.
  439. //
  440. //--
  441. /////////////////////////////////////////////////////////////////////////////
  442. int GetTimeZoneReferenceIndexFromRegistry( void )
  443. {
  444. int xReferenceIndex;
  445. HKEY hKey;
  446. // Attempt to open the Time Zones registry key.
  447. if ( RegOpenKey( HKEY_LOCAL_MACHINE, REGKEY_TIMEZONES, &hKey ) == ERROR_SUCCESS )
  448. {
  449. // The following call to RegQueryValueEx retrieves the size, in bytes, of
  450. // the IndexMapping registry value, in parameter "index".
  451. int xIndexMapSize;
  452. if ( RegQueryValueEx( hKey, REGVAL_TZ_INDEXMAP, 0, NULL, NULL,
  453. (LPDWORD) &xIndexMapSize ) == ERROR_SUCCESS )
  454. {
  455. // Allocate memory for the IndexMap registry value.
  456. LPWSTR wszIndexMap;
  457. wszIndexMap = (LPWSTR) LocalAlloc( LPTR, xIndexMapSize );
  458. // Was a buffer allocated successfully?
  459. if ( wszIndexMap != (LPWSTR) NULL )
  460. {
  461. // This call to RegQueryValueEx retrieves the IndexMap value into
  462. // the buffer, wszIndexMap.
  463. if ( RegQueryValueEx( hKey, REGVAL_TZ_INDEXMAP, 0, NULL,
  464. (LPBYTE) wszIndexMap,
  465. (LPDWORD) &xIndexMapSize ) == ERROR_SUCCESS )
  466. {
  467. // Get the language identifier.
  468. WCHAR wszLangStr[32];
  469. if ( GetLocaleInfo( LOCALE_USER_DEFAULT,
  470. LOCALE_ILANGUAGE, wszLangStr,
  471. sizeof( wszLangStr )/sizeof( WCHAR ) ) > 0 )
  472. {
  473. LPWSTR lang = wszLangStr;
  474. LPWSTR map = wszIndexMap;
  475. while ( *lang == L'0' ) lang++;
  476. while ( *map )
  477. {
  478. if ( _wcsicmp( lang, map ) == 0 )
  479. {
  480. while ( *map ) map++;
  481. map++;
  482. xReferenceIndex = _wtol( map );
  483. break;
  484. }
  485. while ( *map ) map++;
  486. map++;
  487. while ( *map ) map++;
  488. map++;
  489. } // end of while loop
  490. } // language identifier obtained?
  491. } // IndexMapping reg value queried?
  492. LocalFree( wszIndexMap );
  493. } // memory allocated for ImageMap reg value retrieval?
  494. else
  495. {
  496. xReferenceIndex = 0;
  497. } // memory allocated for ImageMap reg value retrieval?
  498. } // Size of ImageMap obtained?
  499. else
  500. {
  501. xReferenceIndex = 0;
  502. } // Size of ImageMap obtained?
  503. RegCloseKey( hKey );
  504. } // TimeZones reg key opened?
  505. else
  506. {
  507. xReferenceIndex = 0;
  508. } // TimeZones reg key opened?
  509. return ( xReferenceIndex );
  510. }
  511. BOOL
  512. DateTimeOnInitDialog(
  513. IN HWND hwnd,
  514. IN HWND hwndFocus,
  515. IN LPARAM lParam
  516. )
  517. {
  518. PLIST_ENTRY NextZone;
  519. PTZINFO zone;
  520. HWND combo;
  521. WCHAR LangStr[32];
  522. int DesiredZone = 0;
  523. int index;
  524. HKEY hKey;
  525. LPWSTR IndexMap;
  526. ghWnd = hwnd; // initialize the global copy of the handle to the
  527. // wizard page. ghWnd is used by DateTimeCommitChanges()
  528. // during unattended setup.
  529. SetTimer( hwnd, TIMER_ID, OPEN_TLEN, 0 );
  530. if ( (SetupInitComponent.SetupData.OperationFlags & SETUPOP_BATCH) && gUnattenedTimeZone != -1 )
  531. {
  532. //
  533. // We've got an unattended time zone value
  534. //
  535. // If everything were perfect DesiredZone will exactly match the ReferenceIndex
  536. // member of one of the TZINFO structures in ZoneList. Note that ZoneList was
  537. // built by BuildTimeZoneList.
  538. DesiredZone = gUnattenedTimeZone;
  539. }
  540. else
  541. {
  542. //
  543. // Base the default zone on the locale
  544. //
  545. // Extract the reference index for the desired time zone from the registry.
  546. DesiredZone = GetTimeZoneReferenceIndexFromRegistry();
  547. } // Time zone specified in unattended setup answer file?
  548. #if MYDEBUG
  549. DebugPrint(( L"DesiredZone = %03d", DesiredZone ));
  550. #endif
  551. combo = GetDlgItem( hwnd, IDC_TIMEZONE );
  552. SetWindowRedraw( combo, FALSE );
  553. PTZINFO pTimeZoneInfo = (PTZINFO) NULL;
  554. // Note that ZoneList was built by BuildTimeZoneList.
  555. NextZone = ZoneList.Flink;
  556. if ( NextZone )
  557. {
  558. // Add time zones to the combo box.
  559. while ( NextZone != &ZoneList )
  560. {
  561. zone = CONTAINING_RECORD( NextZone, TZINFO, ListEntry );
  562. NextZone = zone->ListEntry.Flink;
  563. index = ComboBox_AddString( combo, zone->szDisplayName );
  564. #if MYDEBUG
  565. DebugPrint(( L"%03d,%03d %s", index, zone->ReferenceIndex, zone->szDisplayName ));
  566. #endif
  567. if ( index < 0 )
  568. {
  569. break;
  570. }
  571. ComboBox_SetItemData( combo, index, (LPARAM)zone );
  572. if ( DesiredZone == zone->ReferenceIndex )
  573. {
  574. pTimeZoneInfo = zone;
  575. #if MYDEBUG
  576. DebugPrint(( L" Found DesiredZone" ));
  577. #endif
  578. }
  579. } // end of while loop
  580. }
  581. // Was a time zone that matched DesiredZone identified?
  582. if ( pTimeZoneInfo != (PTZINFO) NULL )
  583. {
  584. // Set the GLOBAL Time Zone Info structure pointer.
  585. CurrZone = pTimeZoneInfo;
  586. }
  587. else
  588. {
  589. // The fact that pTimeZoneInfo remained unchanged from its' initialized state
  590. // means that DesiredZone is not meaningfull.
  591. // Was DesiredZone obtained from the unattended setup answer file?
  592. if ( gUnattenedTimeZone != -1 )
  593. {
  594. // DesiredZone was obtained from the answer file. Since it is not meaningfull,
  595. // attempt to deduce it from registry information. Deducing DesiredZone from
  596. // information in the registry is the default action for ATTENDED setup.
  597. DesiredZone = GetTimeZoneReferenceIndexFromRegistry();
  598. } // Was DesiredZone obtained from the answer file?
  599. // Is DesiredZone meaningfull now?
  600. if ( DesiredZone != 0 )
  601. {
  602. // Scan the list of Time Zones for one that matches DesiredZone.
  603. NextZone = ZoneList.Flink;
  604. if ( NextZone )
  605. {
  606. while ( NextZone != &ZoneList )
  607. {
  608. zone = CONTAINING_RECORD( NextZone, TZINFO, ListEntry );
  609. NextZone = zone->ListEntry.Flink;
  610. #if MYDEBUG
  611. DebugPrint(( L"%03d,%03d %s", index, zone->ReferenceIndex, zone->szDisplayName ));
  612. #endif
  613. if ( DesiredZone == zone->ReferenceIndex )
  614. {
  615. pTimeZoneInfo = zone;
  616. }
  617. } // end of while loop
  618. } // Is NextZone legal?
  619. } // Is DesiredZone meaningfull now?
  620. // Was a time zone that matched DesiredZone identified?
  621. Assert( pTimeZoneInfo != (PTZINFO) NULL );
  622. if ( pTimeZoneInfo != (PTZINFO) NULL )
  623. {
  624. // Set the GLOBAL Time Zone Info structure pointer.
  625. CurrZone = pTimeZoneInfo;
  626. }
  627. else
  628. {
  629. // Use the first Time Zone in the list as a default.
  630. CurrZone = CONTAINING_RECORD( ZoneList.Flink, TZINFO, ListEntry );
  631. #if MYDEBUG
  632. DebugPrint(( L"Couldn't find default timzone" ));
  633. #endif
  634. } // Was a time zone that matched DesiredZone identified?
  635. } // Was a time zone that matched DesiredZone identified?
  636. index = ComboBox_FindString( combo, 0, CurrZone->szDisplayName );
  637. if ( index == CB_ERR )
  638. {
  639. index = 0;
  640. }
  641. ComboBox_SetCurSel( combo, index );
  642. EnableWindow( GetDlgItem( hwnd, IDC_DAYLIGHT ), CurrZone->StandardDate.wMonth != 0 );
  643. CheckDlgButton( hwnd, IDC_DAYLIGHT, GetAllowLocalTimeChange() );
  644. SetWindowRedraw(combo, TRUE);
  645. return FALSE;
  646. }
  647. BOOL
  648. DateTimeOnCommand(
  649. IN HWND hwnd,
  650. IN DWORD NotifyCode,
  651. IN DWORD ControlId,
  652. IN HWND hwndControl
  653. )
  654. {
  655. if (NotifyCode == CBN_SELCHANGE && ControlId == IDC_TIMEZONE) {
  656. CurrZone = (PTZINFO) ComboBox_GetItemData( hwndControl, ComboBox_GetCurSel( hwndControl ) );
  657. EnableWindow( GetDlgItem( hwnd, IDC_DAYLIGHT ), CurrZone->StandardDate.wMonth != 0 );
  658. if (CurrZone->StandardDate.wMonth != 0) {
  659. CheckDlgButton( hwnd, IDC_DAYLIGHT, TRUE );
  660. } else {
  661. CheckDlgButton( hwnd, IDC_DAYLIGHT, FALSE );
  662. }
  663. return FALSE;
  664. }
  665. return TRUE;
  666. }
  667. BOOL
  668. DateTimeOnNotify(
  669. IN HWND hwnd,
  670. IN WPARAM ControlId,
  671. IN LPNMHDR pnmh
  672. )
  673. {
  674. switch( pnmh->code ) {
  675. case PSN_SETACTIVE:
  676. if (SetupInitComponent.SetupData.OperationFlags & SETUPOP_NTUPGRADE) {
  677. SetWindowLongPtr( hwnd, DWLP_MSGRESULT, -1 );
  678. return TRUE;
  679. }
  680. if ((SetupInitComponent.SetupData.OperationFlags & SETUPOP_BATCH) && DateTimeBadUnattend) {
  681. // No unattend value for time date in the unattend case.
  682. // make sure the wizard is shown.
  683. // note: When we get out here, only the next button is enabled.
  684. SetupInitComponent.HelperRoutines.ShowHideWizardPage(
  685. SetupInitComponent.HelperRoutines.OcManagerContext,
  686. TRUE);
  687. return FALSE;
  688. }
  689. if ((SetupInitComponent.SetupData.OperationFlags & SETUPOP_BATCH) && gUnattenedTimeZone != -1) {
  690. //
  691. // we're in unattend mode
  692. //
  693. DateTimeApplyChanges();
  694. SetWindowLongPtr( hwnd, DWLP_MSGRESULT, -1 );
  695. return TRUE;
  696. }
  697. // If we get here the user needs has click next or back.
  698. // Make sure the wizard page is showing.
  699. // For Whistler GUI mode we try to hide wizard pages and show a background
  700. // billboard if there is only a progress bar.
  701. //
  702. SetupInitComponent.HelperRoutines.ShowHideWizardPage(
  703. SetupInitComponent.HelperRoutines.OcManagerContext,
  704. TRUE);
  705. PropSheet_SetWizButtons(GetParent(hwnd), PSWIZB_BACK | PSWIZB_NEXT);
  706. break;
  707. case DTN_DATETIMECHANGE:
  708. if (ControlId == IDC_TIME_PICKER) {
  709. KillTimer( hwnd, TIMER_ID );
  710. ChangeTime = TRUE;
  711. } else if (ControlId == IDC_DATE_PICKER) {
  712. ChangeDate = TRUE;
  713. }
  714. break;
  715. case PSN_WIZNEXT:
  716. SendDlgItemMessage( hwnd, IDC_TIME_PICKER, DTM_GETSYSTEMTIME, 0, (LPARAM)&SelectedTime );
  717. SendDlgItemMessage( hwnd, IDC_DATE_PICKER, DTM_GETSYSTEMTIME, 0, (LPARAM)&SelectedDate );
  718. AllowAutoDST = IsDlgButtonChecked( hwnd, IDC_DAYLIGHT ) != 0;
  719. DateTimeApplyChanges();
  720. break;
  721. }
  722. return FALSE;
  723. }
  724. BOOL
  725. DateTimeOnTimer(
  726. IN HWND hwnd
  727. )
  728. {
  729. SYSTEMTIME CurrTime;
  730. GetLocalTime( &CurrTime );
  731. SendDlgItemMessage( hwnd, IDC_TIME_PICKER, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&CurrTime );
  732. return FALSE;
  733. }
  734. INT_PTR CALLBACK
  735. DateTimeDlgProc(
  736. HWND hwnd,
  737. UINT message,
  738. WPARAM wParam,
  739. LPARAM lParam
  740. )
  741. {
  742. CommonWizardProc( hwnd, message, wParam, lParam, WizPageDateTime );
  743. switch( message ) {
  744. case WM_INITDIALOG:
  745. return DateTimeOnInitDialog( hwnd, (HWND)wParam, lParam );
  746. case WM_COMMAND:
  747. return DateTimeOnCommand( hwnd, HIWORD(wParam), LOWORD(wParam), (HWND)lParam );
  748. case WM_TIMER:
  749. return DateTimeOnTimer( hwnd );
  750. case WM_NOTIFY:
  751. return DateTimeOnNotify( hwnd, wParam, (LPNMHDR) lParam );
  752. }
  753. return FALSE;
  754. }