|
|
/*++
Copyright (c) 1997 Microsoft Corporation
Module Name:
datetime.cpp
Abstract:
This file implements the date & time page.
Environment:
WIN32 User Mode
Author:
Wesley Witt (wesw) 1-Dec-1997
--*/
#include "ntoc.h"
#pragma hdrstop
#define MYDEBUG 0
#define TIMER_ID 1
#define OPEN_TLEN 450 /* < half second */
#define TZNAME_SIZE 128
#define TZDISPLAYZ 128
#define REGKEY_TIMEZONES L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones"
#define REGVAL_TZ_DISPLAY L"Display"
#define REGVAL_TZ_STD L"Std"
#define REGVAL_TZ_DAYLIGHT L"Dlt"
#define REGVAL_TZ_TZI L"TZI"
#define REGVAL_TZ_INDEX L"Index"
#define REGVAL_TZ_INDEXMAP L"IndexMapping"
#define REGKEY_TIMEZONE_INFO L"System\\CurrentControlSet\\Control\\TimeZoneInformation"
#define REGVAL_TZNOAUTOTIME L"DisableAutoDaylightTimeSet"
typedef struct tagTZINFO { LIST_ENTRY ListEntry; WCHAR szDisplayName[TZDISPLAYZ]; WCHAR szStandardName[TZNAME_SIZE]; WCHAR szDaylightName[TZNAME_SIZE]; int ReferenceIndex; LONG Bias; LONG StandardBias; LONG DaylightBias; SYSTEMTIME StandardDate; SYSTEMTIME DaylightDate;
} TZINFO, *PTZINFO;
LIST_ENTRY ZoneList; SYSTEMTIME SelectedTime; SYSTEMTIME SelectedDate; BOOL ChangeTime; BOOL ChangeDate; PTZINFO CurrZone; BOOL AllowAutoDST; INT gUnattenedTimeZone = -1; BOOL DateTimeBadUnattend;
HWND ghWnd; // global copy of the handle to the wizard page. This
// is required by DateTimeCommitChanges during an
// unattended installation.
BOOL ReadZoneData( PTZINFO zone, HKEY key, LPCWSTR keyname ) { WCHAR mapinfo[16]; DWORD len;
len = sizeof(zone->szDisplayName);
if (RegQueryValueEx( key, REGVAL_TZ_DISPLAY, 0, NULL, (LPBYTE)zone->szDisplayName, &len ) != ERROR_SUCCESS) { return (FALSE); }
//
// Under NT, the keyname is the "Standard" name. Values stored
// under the keyname contain the other strings and binary info
// related to the time zone. Every time zone must have a standard
// name, therefore, we save registry space by using the Standard
// name as the subkey name under the "Time Zones" key.
//
len = sizeof(zone->szStandardName);
if (RegQueryValueEx( key, REGVAL_TZ_STD, 0, NULL, (LPBYTE)zone->szStandardName, &len ) != ERROR_SUCCESS) { //
// Use keyname if can't get StandardName value.
//
lstrcpyn( zone->szStandardName, keyname, sizeof(zone->szStandardName) ); }
len = sizeof(zone->szDaylightName);
if (RegQueryValueEx( key, REGVAL_TZ_DAYLIGHT, 0, NULL, (LPBYTE)zone->szDaylightName, &len ) != ERROR_SUCCESS) { return (FALSE); }
len = sizeof(zone->ReferenceIndex);
if (RegQueryValueEx( key, REGVAL_TZ_INDEX, 0, NULL, (LPBYTE)&zone->ReferenceIndex, &len ) != ERROR_SUCCESS) { return (FALSE); }
len = sizeof(zone->Bias) + sizeof(zone->StandardBias) + sizeof(zone->DaylightBias) + sizeof(zone->StandardDate) + sizeof(zone->DaylightDate);
if (RegQueryValueEx( key, REGVAL_TZ_TZI, 0, NULL, (LPBYTE)&zone->Bias, &len ) != ERROR_SUCCESS) { return (FALSE); }
return (TRUE); }
#if MYDEBUG
void PrintZones( void ) { PLIST_ENTRY NextZone; PTZINFO zone; NextZone = ZoneList.Flink; if (NextZone) { DebugPrint(( L"----------------- time zone list -------------------------------------\n" )); while (NextZone != &ZoneList) { zone = CONTAINING_RECORD( NextZone, TZINFO, ListEntry ); NextZone = zone->ListEntry.Flink; DebugPrint(( L"%03d %s", zone->ReferenceIndex, zone->szDisplayName )); } } } #endif
void AddZoneToList( PTZINFO zone ) { PLIST_ENTRY NextZone; PTZINFO ThisZone;
if (IsListEmpty( &ZoneList )) { InsertHeadList( &ZoneList, &zone->ListEntry ); return; }
NextZone = ZoneList.Flink; while (NextZone != &ZoneList) { ThisZone = CONTAINING_RECORD( NextZone, TZINFO, ListEntry ); NextZone = ThisZone->ListEntry.Flink; if (ThisZone->ReferenceIndex > zone->ReferenceIndex) { InsertTailList( &ThisZone->ListEntry, &zone->ListEntry ); return; } } InsertTailList( &ZoneList, &zone->ListEntry ); }
int BuildTimeZoneList( void ) { HKEY key = NULL; int count = -1;
InitializeListHead( &ZoneList );
if (RegOpenKey( HKEY_LOCAL_MACHINE, REGKEY_TIMEZONES, &key ) == ERROR_SUCCESS) { WCHAR name[TZNAME_SIZE]; PTZINFO zone = NULL; int i;
count = 0;
for (i = 0; RegEnumKey( key, i, name, TZNAME_SIZE ) == ERROR_SUCCESS; i++) { HKEY subkey = NULL;
if (!zone && ((zone = (PTZINFO)LocalAlloc(LPTR, sizeof(TZINFO))) == NULL)) { break; }
if (RegOpenKey(key, name, &subkey) == ERROR_SUCCESS) { //
// Each sub key name under the Time Zones key is the
// "Standard" name for the Time Zone.
//
lstrcpyn(zone->szStandardName, name, TZNAME_SIZE);
if (ReadZoneData(zone, subkey, name)) { AddZoneToList(zone); zone = NULL; count++; }
RegCloseKey(subkey); } }
RegCloseKey(key); }
return count; }
void DateTimeInit( void ) { DWORD d;
BuildTimeZoneList();
#if MYDEBUG
PrintZones(); #endif
if ((SetupInitComponent.SetupData.OperationFlags & SETUPOP_BATCH) == 0) { return; }
HINF InfHandle = SetupInitComponent.HelperRoutines.GetInfHandle( INFINDEX_UNATTENDED, SetupInitComponent.HelperRoutines.OcManagerContext ); if (InfHandle == NULL) { DateTimeBadUnattend = TRUE; return; }
INFCONTEXT InfLine;
if (!SetupFindFirstLine(InfHandle, L"GuiUnattended", L"TimeZone", &InfLine )) {
DateTimeBadUnattend = TRUE;
return; }
if (SetupGetIntField( &InfLine, 1, (PINT)&d )) { gUnattenedTimeZone = (INT) d; } else { DateTimeBadUnattend = TRUE; } }
void SetAllowLocalTimeChange( BOOL fAllow ) { HKEY key = NULL;
if (fAllow) { //
// Remove the disallow flag from the registry if it exists.
//
if (RegOpenKey( HKEY_LOCAL_MACHINE, REGKEY_TIMEZONE_INFO, &key ) == ERROR_SUCCESS) { RegDeleteValue(key, REGVAL_TZNOAUTOTIME); } } else { //
// Add/set the nonzero disallow flag.
//
if (RegCreateKey( HKEY_LOCAL_MACHINE, REGKEY_TIMEZONE_INFO, &key ) == ERROR_SUCCESS) { DWORD value = 1;
RegSetValueEx( key, REGVAL_TZNOAUTOTIME, 0, REG_DWORD, (LPBYTE)&value, sizeof(value) ); } }
if (key) { RegCloseKey(key); } }
BOOL GetAllowLocalTimeChange( void ) { //
// Assume allowed until we see a disallow flag.
//
BOOL result = TRUE; HKEY key;
if (RegOpenKey( HKEY_LOCAL_MACHINE, REGKEY_TIMEZONE_INFO, &key ) == ERROR_SUCCESS) { //
// Assume no disallow flag until we see one.
//
DWORD value = 0; DWORD len = sizeof(value); DWORD type;
if ((RegQueryValueEx( key, REGVAL_TZNOAUTOTIME, NULL, &type, (LPBYTE)&value, &len ) == ERROR_SUCCESS) && ((type == REG_DWORD) || (type == REG_BINARY)) && (len == sizeof(value)) && value) { //
// Okay, we have a nonzero value, it is either:
//
// 1) 0xFFFFFFFF
// this is set in an inf file for first boot to prevent
// the base from performing any cutovers during setup.
//
// 2) some other value
// this signifies that the user actualy disabled cutovers
// *return that local time changes are disabled
//
if (value != 0xFFFFFFFF) { result = FALSE; } }
RegCloseKey(key); }
return (result); }
void SetTheTimezone( BOOL bAutoMagicTimeChange, PTZINFO ptzi ) { TIME_ZONE_INFORMATION tzi; HCURSOR hCurOld;
if (!ptzi) { return; }
tzi.Bias = ptzi->Bias;
tzi.StandardName[0] = 0; lstrcpyn(tzi.StandardName, ptzi->szStandardName, sizeof(tzi.StandardName)/sizeof(tzi.StandardName[0])); tzi.StandardName[sizeof(tzi.StandardName)/sizeof(tzi.StandardName[0])-1] = 0;
tzi.DaylightName[0] = 0;
if ((bAutoMagicTimeChange == 0) || (ptzi->StandardDate.wMonth == 0)) { //
// Standard Only.
//
tzi.StandardBias = ptzi->StandardBias; tzi.DaylightBias = ptzi->StandardBias; tzi.StandardDate = ptzi->StandardDate; tzi.DaylightDate = ptzi->StandardDate; lstrcpyn(tzi.DaylightName, ptzi->szStandardName, sizeof(tzi.DaylightName)/sizeof(tzi.DaylightName[0])); } else { //
// Automatically adjust for Daylight Saving Time.
//
tzi.StandardBias = ptzi->StandardBias; tzi.DaylightBias = ptzi->DaylightBias; tzi.StandardDate = ptzi->StandardDate; tzi.DaylightDate = ptzi->DaylightDate; lstrcpyn(tzi.DaylightName, ptzi->szDaylightName, sizeof(tzi.DaylightName)/sizeof(tzi.DaylightName[0])); } tzi.DaylightName[sizeof(tzi.DaylightName)/sizeof(tzi.DaylightName[0])-1] = 0;
SetAllowLocalTimeChange( bAutoMagicTimeChange ); SetTimeZoneInformation( &tzi ); }
void DateTimeApplyChanges( void ) { SYSTEMTIME SysTime;
if (SetupInitComponent.SetupData.OperationFlags & SETUPOP_NTUPGRADE) { return; }
// Note that in the unattended case we will never have ChangeTime set
// as the page never is used except for the timezone stuff. There is
// no support to set date/time via unattend.
if (ChangeTime) { SysTime.wHour = SelectedTime.wHour; SysTime.wMinute = SelectedTime.wMinute; SysTime.wSecond = SelectedTime.wSecond; SysTime.wMilliseconds = SelectedTime.wMilliseconds; } else { GetLocalTime( &SysTime ); }
// If this is an unattended setup the PSN_WIZNEXT never arrived so it is
// necessary to check the state of ICD_DAYTIME which was set by DateTimeOnInitDialog().
if ((SetupInitComponent.SetupData.OperationFlags & SETUPOP_BATCH) && gUnattenedTimeZone != -1) { // This is unattended.
AllowAutoDST = IsDlgButtonChecked( ghWnd, IDC_DAYLIGHT ) != 0; } else { // This is NOT UNATTENDED. SelectedDate was initialized when PSN_WIZNEXT
// was processed.
SysTime.wYear = SelectedDate.wYear; SysTime.wMonth = SelectedDate.wMonth; SysTime.wDayOfWeek = SelectedDate.wDayOfWeek; SysTime.wDay = SelectedDate.wDay; }
// Function SetLocalTime uses Time Zone information so it is IMPERATIVE that
// SetTheTimezone get called before SetLocalTime.
SetTheTimezone( AllowAutoDST, CurrZone );
SetLocalTime( &SysTime );
}
void DateTimeCommitChanges( void ) { return; }
/////////////////////////////////////////////////////////////////////////////
//++
//
// GetTimeZoneReferenceIndexFromRegistry
//
// Routine Description:
// This funecion extracts the Time Zone reference index from information that
// is stored in the registry.
//
// Arguments:
// None
//
// Return Value:
// The Time Zone reference index. If no valid reference index is deduced
// this function will return zero.
//
// Note:
// The logic performed by the following function was originally implemented in
// DateTimeOnInitDialog.
//
//--
/////////////////////////////////////////////////////////////////////////////
int GetTimeZoneReferenceIndexFromRegistry( void ) { int xReferenceIndex;
HKEY hKey;
// Attempt to open the Time Zones registry key.
if ( RegOpenKey( HKEY_LOCAL_MACHINE, REGKEY_TIMEZONES, &hKey ) == ERROR_SUCCESS ) { // The following call to RegQueryValueEx retrieves the size, in bytes, of
// the IndexMapping registry value, in parameter "index".
int xIndexMapSize;
if ( RegQueryValueEx( hKey, REGVAL_TZ_INDEXMAP, 0, NULL, NULL, (LPDWORD) &xIndexMapSize ) == ERROR_SUCCESS ) { // Allocate memory for the IndexMap registry value.
LPWSTR wszIndexMap;
wszIndexMap = (LPWSTR) LocalAlloc( LPTR, xIndexMapSize );
// Was a buffer allocated successfully?
if ( wszIndexMap != (LPWSTR) NULL ) { // This call to RegQueryValueEx retrieves the IndexMap value into
// the buffer, wszIndexMap.
if ( RegQueryValueEx( hKey, REGVAL_TZ_INDEXMAP, 0, NULL, (LPBYTE) wszIndexMap, (LPDWORD) &xIndexMapSize ) == ERROR_SUCCESS ) { // Get the language identifier.
WCHAR wszLangStr[32];
if ( GetLocaleInfo( LOCALE_USER_DEFAULT, LOCALE_ILANGUAGE, wszLangStr, sizeof( wszLangStr )/sizeof( WCHAR ) ) > 0 ) { LPWSTR lang = wszLangStr;
LPWSTR map = wszIndexMap;
while ( *lang == L'0' ) lang++;
while ( *map ) { if ( _wcsicmp( lang, map ) == 0 ) { while ( *map ) map++;
map++;
xReferenceIndex = _wtol( map );
break; }
while ( *map ) map++;
map++;
while ( *map ) map++;
map++; } // end of while loop
} // language identifier obtained?
} // IndexMapping reg value queried?
LocalFree( wszIndexMap ); } // memory allocated for ImageMap reg value retrieval?
else { xReferenceIndex = 0; } // memory allocated for ImageMap reg value retrieval?
} // Size of ImageMap obtained?
else { xReferenceIndex = 0; } // Size of ImageMap obtained?
RegCloseKey( hKey ); } // TimeZones reg key opened?
else { xReferenceIndex = 0; } // TimeZones reg key opened?
return ( xReferenceIndex ); }
BOOL DateTimeOnInitDialog( IN HWND hwnd, IN HWND hwndFocus, IN LPARAM lParam ) { PLIST_ENTRY NextZone; PTZINFO zone; HWND combo; WCHAR LangStr[32]; int DesiredZone = 0; int index; HKEY hKey; LPWSTR IndexMap;
ghWnd = hwnd; // initialize the global copy of the handle to the
// wizard page. ghWnd is used by DateTimeCommitChanges()
// during unattended setup.
SetTimer( hwnd, TIMER_ID, OPEN_TLEN, 0 );
if ( (SetupInitComponent.SetupData.OperationFlags & SETUPOP_BATCH) && gUnattenedTimeZone != -1 ) { //
// We've got an unattended time zone value
//
// If everything were perfect DesiredZone will exactly match the ReferenceIndex
// member of one of the TZINFO structures in ZoneList. Note that ZoneList was
// built by BuildTimeZoneList.
DesiredZone = gUnattenedTimeZone; } else { //
// Base the default zone on the locale
//
// Extract the reference index for the desired time zone from the registry.
DesiredZone = GetTimeZoneReferenceIndexFromRegistry(); } // Time zone specified in unattended setup answer file?
#if MYDEBUG
DebugPrint(( L"DesiredZone = %03d", DesiredZone )); #endif
combo = GetDlgItem( hwnd, IDC_TIMEZONE );
SetWindowRedraw( combo, FALSE );
PTZINFO pTimeZoneInfo = (PTZINFO) NULL;
// Note that ZoneList was built by BuildTimeZoneList.
NextZone = ZoneList.Flink;
if ( NextZone ) { // Add time zones to the combo box.
while ( NextZone != &ZoneList ) { zone = CONTAINING_RECORD( NextZone, TZINFO, ListEntry ); NextZone = zone->ListEntry.Flink;
index = ComboBox_AddString( combo, zone->szDisplayName );
#if MYDEBUG
DebugPrint(( L"%03d,%03d %s", index, zone->ReferenceIndex, zone->szDisplayName )); #endif
if ( index < 0 ) { break; }
ComboBox_SetItemData( combo, index, (LPARAM)zone );
if ( DesiredZone == zone->ReferenceIndex ) { pTimeZoneInfo = zone; #if MYDEBUG
DebugPrint(( L" Found DesiredZone" )); #endif
} } // end of while loop
}
// Was a time zone that matched DesiredZone identified?
if ( pTimeZoneInfo != (PTZINFO) NULL ) { // Set the GLOBAL Time Zone Info structure pointer.
CurrZone = pTimeZoneInfo; } else { // The fact that pTimeZoneInfo remained unchanged from its' initialized state
// means that DesiredZone is not meaningfull.
// Was DesiredZone obtained from the unattended setup answer file?
if ( gUnattenedTimeZone != -1 ) { // DesiredZone was obtained from the answer file. Since it is not meaningfull,
// attempt to deduce it from registry information. Deducing DesiredZone from
// information in the registry is the default action for ATTENDED setup.
DesiredZone = GetTimeZoneReferenceIndexFromRegistry(); } // Was DesiredZone obtained from the answer file?
// Is DesiredZone meaningfull now?
if ( DesiredZone != 0 ) { // Scan the list of Time Zones for one that matches DesiredZone.
NextZone = ZoneList.Flink;
if ( NextZone ) { while ( NextZone != &ZoneList ) { zone = CONTAINING_RECORD( NextZone, TZINFO, ListEntry );
NextZone = zone->ListEntry.Flink;
#if MYDEBUG
DebugPrint(( L"%03d,%03d %s", index, zone->ReferenceIndex, zone->szDisplayName )); #endif
if ( DesiredZone == zone->ReferenceIndex ) { pTimeZoneInfo = zone; } } // end of while loop
} // Is NextZone legal?
} // Is DesiredZone meaningfull now?
// Was a time zone that matched DesiredZone identified?
Assert( pTimeZoneInfo != (PTZINFO) NULL );
if ( pTimeZoneInfo != (PTZINFO) NULL ) { // Set the GLOBAL Time Zone Info structure pointer.
CurrZone = pTimeZoneInfo; } else { // Use the first Time Zone in the list as a default.
CurrZone = CONTAINING_RECORD( ZoneList.Flink, TZINFO, ListEntry ); #if MYDEBUG
DebugPrint(( L"Couldn't find default timzone" )); #endif
} // Was a time zone that matched DesiredZone identified?
} // Was a time zone that matched DesiredZone identified?
index = ComboBox_FindString( combo, 0, CurrZone->szDisplayName ); if ( index == CB_ERR ) { index = 0; }
ComboBox_SetCurSel( combo, index );
EnableWindow( GetDlgItem( hwnd, IDC_DAYLIGHT ), CurrZone->StandardDate.wMonth != 0 ); CheckDlgButton( hwnd, IDC_DAYLIGHT, GetAllowLocalTimeChange() );
SetWindowRedraw(combo, TRUE);
return FALSE; }
BOOL DateTimeOnCommand( IN HWND hwnd, IN DWORD NotifyCode, IN DWORD ControlId, IN HWND hwndControl ) { if (NotifyCode == CBN_SELCHANGE && ControlId == IDC_TIMEZONE) { CurrZone = (PTZINFO) ComboBox_GetItemData( hwndControl, ComboBox_GetCurSel( hwndControl ) ); EnableWindow( GetDlgItem( hwnd, IDC_DAYLIGHT ), CurrZone->StandardDate.wMonth != 0 ); if (CurrZone->StandardDate.wMonth != 0) { CheckDlgButton( hwnd, IDC_DAYLIGHT, TRUE ); } else { CheckDlgButton( hwnd, IDC_DAYLIGHT, FALSE ); } return FALSE; }
return TRUE; }
BOOL DateTimeOnNotify( IN HWND hwnd, IN WPARAM ControlId, IN LPNMHDR pnmh ) { switch( pnmh->code ) { case PSN_SETACTIVE: if (SetupInitComponent.SetupData.OperationFlags & SETUPOP_NTUPGRADE) { SetWindowLongPtr( hwnd, DWLP_MSGRESULT, -1 ); return TRUE; }
if ((SetupInitComponent.SetupData.OperationFlags & SETUPOP_BATCH) && DateTimeBadUnattend) { // No unattend value for time date in the unattend case.
// make sure the wizard is shown.
// note: When we get out here, only the next button is enabled.
SetupInitComponent.HelperRoutines.ShowHideWizardPage( SetupInitComponent.HelperRoutines.OcManagerContext, TRUE); return FALSE; }
if ((SetupInitComponent.SetupData.OperationFlags & SETUPOP_BATCH) && gUnattenedTimeZone != -1) { //
// we're in unattend mode
//
DateTimeApplyChanges(); SetWindowLongPtr( hwnd, DWLP_MSGRESULT, -1 ); return TRUE; }
// If we get here the user needs has click next or back.
// Make sure the wizard page is showing.
// For Whistler GUI mode we try to hide wizard pages and show a background
// billboard if there is only a progress bar.
//
SetupInitComponent.HelperRoutines.ShowHideWizardPage( SetupInitComponent.HelperRoutines.OcManagerContext, TRUE);
PropSheet_SetWizButtons(GetParent(hwnd), PSWIZB_BACK | PSWIZB_NEXT);
break;
case DTN_DATETIMECHANGE: if (ControlId == IDC_TIME_PICKER) { KillTimer( hwnd, TIMER_ID ); ChangeTime = TRUE; } else if (ControlId == IDC_DATE_PICKER) { ChangeDate = TRUE; } break;
case PSN_WIZNEXT: SendDlgItemMessage( hwnd, IDC_TIME_PICKER, DTM_GETSYSTEMTIME, 0, (LPARAM)&SelectedTime ); SendDlgItemMessage( hwnd, IDC_DATE_PICKER, DTM_GETSYSTEMTIME, 0, (LPARAM)&SelectedDate ); AllowAutoDST = IsDlgButtonChecked( hwnd, IDC_DAYLIGHT ) != 0; DateTimeApplyChanges(); break; }
return FALSE; }
BOOL DateTimeOnTimer( IN HWND hwnd ) { SYSTEMTIME CurrTime; GetLocalTime( &CurrTime ); SendDlgItemMessage( hwnd, IDC_TIME_PICKER, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&CurrTime ); return FALSE; }
INT_PTR CALLBACK DateTimeDlgProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam ) {
CommonWizardProc( hwnd, message, wParam, lParam, WizPageDateTime );
switch( message ) { case WM_INITDIALOG: return DateTimeOnInitDialog( hwnd, (HWND)wParam, lParam );
case WM_COMMAND: return DateTimeOnCommand( hwnd, HIWORD(wParam), LOWORD(wParam), (HWND)lParam );
case WM_TIMER: return DateTimeOnTimer( hwnd );
case WM_NOTIFY: return DateTimeOnNotify( hwnd, wParam, (LPNMHDR) lParam ); }
return FALSE; }
|