3826 lines
98 KiB
C
3826 lines
98 KiB
C
/*++
|
|
|
|
Copyright (c) 1994-1998, Microsoft Corporation All rights reserved.
|
|
|
|
Module Name:
|
|
|
|
date.c
|
|
|
|
Abstract:
|
|
|
|
This module implements the textual representations of
|
|
Day Month Year : Hours Min Seconds for the Date/Time applet.
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
|
|
//
|
|
// Include Files.
|
|
//
|
|
|
|
#include "timedate.h"
|
|
#include <commctrl.h>
|
|
#include <prsht.h>
|
|
#include <regstr.h>
|
|
#include <imm.h>
|
|
#include "clock.h"
|
|
#include "mapctl.h"
|
|
#include "inettime.h"
|
|
#include "rc.h"
|
|
#include <help.h>
|
|
#include <shlwapi.h>
|
|
#include <windows.h>
|
|
#include <windowsx.h>
|
|
|
|
|
|
|
|
|
|
//
|
|
// Constant Declarations.
|
|
//
|
|
|
|
#define TZNAME_SIZE 128
|
|
#define TZDISPLAYZ 128
|
|
|
|
#define BIAS_ONE_HOUR (-60L)
|
|
|
|
#define ZONE_IMAGE_SCALE (356)
|
|
#define ZONE_BIAS_SCALE (-1440)
|
|
#define ZONE_IMAGE_LEFT (120)
|
|
#define ZONE_IMAGE_WIDTH (80)
|
|
|
|
#define BIAS_PLUS_12 (12L * BIAS_ONE_HOUR)
|
|
#define BIAS_MINUS_12 (- BIAS_PLUS_12)
|
|
|
|
#define TZ_HIT_NONE (0)
|
|
#define TZ_HIT_BASE (1)
|
|
#define TZ_HIT_PARTIAL (2)
|
|
#define TZ_HIT_EXACT (3)
|
|
|
|
|
|
|
|
|
|
//
|
|
// Global Variables.
|
|
//
|
|
|
|
TCHAR const szIntl[] = TEXT("intl");
|
|
|
|
//
|
|
// Default used if none could be found.
|
|
//
|
|
INTLSTRUCT IntlDef =
|
|
{
|
|
TEXT("Other Country"),
|
|
1, 0, 0, 0, 0, 2, 0, 1, 2, 1,
|
|
TEXT("AM"),
|
|
TEXT("PM"),
|
|
TEXT("$"),
|
|
TEXT(","),
|
|
TEXT("."),
|
|
TEXT("/"),
|
|
TEXT(":"),
|
|
TEXT(","),
|
|
TEXT("dddd, MMMM dd, yyyy"),
|
|
TEXT("M/d/yyyy"),
|
|
TEXT("USA"),
|
|
1, 0, 1, 0, 0x0409,
|
|
TEXT("hh:mm:ss tt"),
|
|
0, 1,
|
|
TEXT(","),
|
|
TEXT(".")
|
|
};
|
|
|
|
BOOL g_bFirstBoot = FALSE; // for first boot during setup
|
|
|
|
int g_Time[3]; // time the user currently has set
|
|
int g_LastTime[3]; // last displayed time - to stop flicker
|
|
|
|
short wDateTime[7]; // values for first 7 date/time items
|
|
short wPrevDateTime[7]; // only repaint fields if necessary
|
|
BOOL fDateDirty;
|
|
|
|
//
|
|
// Formatting strings for AM and PM
|
|
//
|
|
TCHAR sz1159[12];
|
|
TCHAR sz2359[12];
|
|
|
|
//
|
|
// Are we in 24 hour time. If not, is it AM or PM.
|
|
//
|
|
BOOL g_b24HR;
|
|
BOOL g_bPM;
|
|
|
|
//
|
|
// This flag indicates if the user has tried to change the time.
|
|
// If so, then we stop providing the system time and use the
|
|
// time that we store internally. We send the clock control our
|
|
// TimeProvider function.
|
|
//
|
|
WORD g_Modified = 0;
|
|
WORD g_WasModified = 0;
|
|
|
|
//
|
|
// Which of the HMS MDY have leading zeros.
|
|
//
|
|
BOOL g_bLZero[6] = {FALSE, TRUE, TRUE, FALSE, FALSE, FALSE};
|
|
|
|
//
|
|
// Ranges of HMS MDY
|
|
//
|
|
struct
|
|
{
|
|
int nMax;
|
|
int nMin;
|
|
} g_sDateInfo[] =
|
|
{
|
|
23, 0,
|
|
59, 0,
|
|
59, 0,
|
|
12, 1,
|
|
31, 1,
|
|
2099, 1980,
|
|
};
|
|
|
|
//
|
|
// Time Zone info globals.
|
|
//
|
|
int g_nTimeZones = 0;
|
|
TIME_ZONE_INFORMATION g_tziCurrent, *g_ptziCurrent = NULL;
|
|
|
|
//
|
|
// Registry location for Time Zone information.
|
|
//
|
|
#ifdef WINNT
|
|
TCHAR c_szTimeZones[] = TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones");
|
|
#else
|
|
TCHAR c_szTimeZones[] = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Time Zones");
|
|
#endif
|
|
|
|
//
|
|
// Time Zone data value keys.
|
|
//
|
|
TCHAR c_szTZDisplayName[] = TEXT("Display");
|
|
TCHAR c_szTZStandardName[] = TEXT("Std");
|
|
TCHAR c_szTZDaylightName[] = TEXT("Dlt");
|
|
TCHAR c_szTZI[] = TEXT("TZI");
|
|
TCHAR c_szTZMapInfo[] = TEXT("MapID");
|
|
|
|
//
|
|
// IME globals.
|
|
//
|
|
HIMC g_PrevIMCForDateField;
|
|
|
|
|
|
|
|
|
|
//
|
|
// Context Help Ids.
|
|
//
|
|
|
|
const DWORD aDateTimeHelpIds[] =
|
|
{
|
|
IDD_GROUPBOX1, IDH_DATETIME_DATE_GROUP,
|
|
IDD_GROUPBOX2, IDH_DATETIME_TIME,
|
|
DATETIME_CURTZ, IDH_DATETIME_CURRENT_TIME_ZONE,
|
|
DATETIME_CALENDAR, IDH_DATETIME_DATE,
|
|
DATETIME_CLOCK, IDH_DATETIME_TIME,
|
|
DATETIME_TBORDER, IDH_DATETIME_TIME,
|
|
DATETIME_HOUR, IDH_DATETIME_TIME,
|
|
DATETIME_TSEP1, IDH_DATETIME_TIME,
|
|
DATETIME_MINUTE, IDH_DATETIME_TIME,
|
|
DATETIME_TSEP2, IDH_DATETIME_TIME,
|
|
DATETIME_SECOND, IDH_DATETIME_TIME,
|
|
DATETIME_AMPM, IDH_DATETIME_TIME,
|
|
DATETIME_TARROW, IDH_DATETIME_TIME,
|
|
DATETIME_MONTHNAME, IDH_DATETIME_MONTH,
|
|
DATETIME_YEAR, IDH_DATETIME_YEAR,
|
|
DATETIME_YARROW, IDH_DATETIME_YEAR,
|
|
IDD_TIMEZONES, IDH_DATETIME_TIMEZONE,
|
|
// IDD_TIMEMAP, IDH_DATETIME_BITMAP,
|
|
IDD_TIMEMAP, NO_HELP,
|
|
IDD_AUTOMAGIC, IDH_DATETIME_DAYLIGHT_SAVE,
|
|
|
|
0, 0
|
|
};
|
|
|
|
|
|
|
|
|
|
//
|
|
// Typedef Declarations.
|
|
//
|
|
|
|
//
|
|
// Registry info goes in this structure.
|
|
//
|
|
typedef struct tagTZINFO
|
|
{
|
|
struct tagTZINFO *next;
|
|
TCHAR szDisplayName[TZDISPLAYZ];
|
|
TCHAR szStandardName[TZNAME_SIZE];
|
|
TCHAR szDaylightName[TZNAME_SIZE];
|
|
int ComboIndex;
|
|
int SeaIndex;
|
|
int LandIndex;
|
|
int MapLeft;
|
|
int MapWidth;
|
|
LONG Bias;
|
|
LONG StandardBias;
|
|
LONG DaylightBias;
|
|
SYSTEMTIME StandardDate;
|
|
SYSTEMTIME DaylightDate;
|
|
|
|
} TZINFO, *PTZINFO;
|
|
|
|
//
|
|
// State info for the time zone page.
|
|
//
|
|
typedef struct
|
|
{
|
|
PTZINFO zone;
|
|
BOOL initializing;
|
|
PTZINFO lookup[MAPCTL_MAX_INDICES];
|
|
|
|
} TZPAGE_STATE;
|
|
|
|
|
|
|
|
DWORD GetTextExtent(
|
|
HDC hdc,
|
|
LPCTSTR lpsz,
|
|
int cb);
|
|
|
|
|
|
#ifndef UNICODE
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// WideStrToStr
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
int WINAPI WideStrToStr(
|
|
LPSTR psz,
|
|
LPWSTR pwsz)
|
|
{
|
|
return WideCharToMultiByte(CP_ACP, 0, pwsz, -1, psz, MAX_PATH, NULL, NULL);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// StrToWideStr
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
int WINAPI StrToWideStr(
|
|
LPWSTR pwsz,
|
|
LPCSTR psz)
|
|
{
|
|
return MultiByteToWideChar(CP_ACP, 0, psz, -1, pwsz, MAX_PATH);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// AnsiWideStrCmpI
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
int AnsiWideStrCmpI(
|
|
LPCSTR pszAnsi,
|
|
WCHAR *pwszWide)
|
|
{
|
|
char szAnsi[64];
|
|
|
|
WideStrToStr(szAnsi, pwszWide);
|
|
return (lstrcmpi(pszAnsi, szAnsi));
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ParseDateElement
|
|
//
|
|
// Assumes that the character pointed to by pszElement is a
|
|
// 'M', 'd', or 'y', and checks if the string indicates a leading zero
|
|
// or century. The return value is a pointer to the next character,
|
|
// which should be a separator or NULL. A return value of NULL indicates
|
|
// an error.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
LPTSTR ParseDateElement(
|
|
LPTSTR pszElement,
|
|
BOOL *pbLZero)
|
|
{
|
|
//
|
|
// Check for valid character.
|
|
//
|
|
switch (*pszElement)
|
|
{
|
|
case ( TEXT('y') ) :
|
|
case ( TEXT('M') ) :
|
|
case ( TEXT('d') ) :
|
|
{
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
return (NULL);
|
|
}
|
|
}
|
|
|
|
++pszElement;
|
|
|
|
if (*pszElement != *(pszElement - 1))
|
|
{
|
|
*pbLZero = 0;
|
|
}
|
|
else
|
|
{
|
|
*pbLZero = 1;
|
|
|
|
if (*pszElement++ == TEXT('y'))
|
|
{
|
|
if (!(*pszElement == TEXT('y')))
|
|
{
|
|
*pbLZero = 0;
|
|
}
|
|
else
|
|
{
|
|
if (!(*++pszElement == TEXT('y')))
|
|
{
|
|
//
|
|
// Found 3 y's, invalid format.
|
|
//
|
|
return (NULL);
|
|
}
|
|
else
|
|
{
|
|
++pszElement;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return (pszElement);
|
|
}
|
|
|
|
|
|
int rgMoveTimeControls [] =
|
|
{
|
|
DATETIME_HOUR,
|
|
DATETIME_MINUTE,
|
|
DATETIME_SECOND,
|
|
DATETIME_TSEP1,
|
|
DATETIME_TSEP2
|
|
};
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// AdjustAMPMPosition
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
void AdjustAMPMPosition(HWND hwnd)
|
|
{
|
|
TCHAR szTimePrefix[5];
|
|
static BOOL fMoved = FALSE;
|
|
|
|
GetLocaleInfo(LOCALE_USER_DEFAULT,
|
|
LOCALE_ITIMEMARKPOSN,
|
|
szTimePrefix,
|
|
ARRAYSIZE(szTimePrefix));
|
|
|
|
if (!fMoved && szTimePrefix[0] == TEXT('1'))
|
|
{
|
|
RECT rLeftCtl, rAMPMCtl, rCurrCtl;
|
|
HWND hwndAMPM, hwndCurr;
|
|
int i, width;
|
|
POINT pt;
|
|
|
|
fMoved = TRUE;
|
|
|
|
//Get rect of left most control (hours)
|
|
GetWindowRect(GetDlgItem(hwnd, DATETIME_HOUR), &rLeftCtl);
|
|
|
|
//Get rect of AM PM control
|
|
hwndAMPM = GetDlgItem(hwnd, DATETIME_AMPM);
|
|
GetWindowRect(hwndAMPM, &rAMPMCtl);
|
|
width = rAMPMCtl.right - rAMPMCtl.left;
|
|
|
|
//Shift all controls right by the AM PM control width
|
|
for (i = 0; i < ARRAYSIZE(rgMoveTimeControls); i++)
|
|
{
|
|
hwndCurr = GetDlgItem(hwnd, rgMoveTimeControls[i]);
|
|
GetWindowRect(hwndCurr, &rCurrCtl);
|
|
pt.x = rCurrCtl.left;
|
|
pt.y = rCurrCtl.top;
|
|
ScreenToClient(hwnd, &pt);
|
|
|
|
MoveWindow(hwndCurr, pt.x + width,
|
|
pt.y,
|
|
rCurrCtl.right - rCurrCtl.left,
|
|
rCurrCtl.bottom - rCurrCtl.top,
|
|
TRUE);
|
|
}
|
|
|
|
//Move AM PM control left to where the hours were.
|
|
pt.x = rLeftCtl.left;
|
|
pt.y = rAMPMCtl.top;
|
|
ScreenToClient(hwnd, &pt);
|
|
MoveWindow(hwndAMPM, pt.x,
|
|
pt.y,
|
|
rAMPMCtl.right - rAMPMCtl.left,
|
|
rAMPMCtl.bottom - rAMPMCtl.top,
|
|
TRUE);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// MonthUpperBound
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
int _fastcall MonthUpperBound(
|
|
int nMonth,
|
|
int nYear)
|
|
{
|
|
switch (nMonth)
|
|
{
|
|
case ( 2 ) :
|
|
{
|
|
//
|
|
// A year is a leap year if it is divisible by 4 and is not
|
|
// a century year (multiple of 100) or if it is divisible by
|
|
// 400.
|
|
//
|
|
return ( ((nYear % 4 == 0) &&
|
|
((nYear % 100 != 0) || (nYear % 400 == 0))) ? 29 : 28 );
|
|
}
|
|
case ( 4 ) :
|
|
case ( 6 ) :
|
|
case ( 9 ) :
|
|
case ( 11 ) :
|
|
{
|
|
return (30);
|
|
}
|
|
}
|
|
|
|
return (31);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// IsAMPM
|
|
//
|
|
// True if PM.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL IsAMPM(
|
|
int iHour)
|
|
{
|
|
return ((iHour >= 12) ? 1 : 0);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// GetDateTime
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
void GetDateTime()
|
|
{
|
|
SYSTEMTIME SystemTime;
|
|
|
|
GetLocalTime(&SystemTime);
|
|
|
|
wDateTime[HOUR] = SystemTime.wHour;
|
|
wDateTime[MINUTE] = SystemTime.wMinute;
|
|
wDateTime[SECOND] = SystemTime.wSecond;
|
|
wDateTime[MONTH] = SystemTime.wMonth;
|
|
wDateTime[DAY] = SystemTime.wDay;
|
|
wDateTime[YEAR] = SystemTime.wYear;
|
|
wDateTime[WEEKDAY] = SystemTime.wDayOfWeek;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// GetTime
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
void GetTime()
|
|
{
|
|
SYSTEMTIME SystemTime;
|
|
|
|
GetLocalTime(&SystemTime);
|
|
|
|
wDateTime[HOUR] = SystemTime.wHour;
|
|
wDateTime[MINUTE] = SystemTime.wMinute;
|
|
wDateTime[SECOND] = SystemTime.wSecond;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// GetDate
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
void GetDate()
|
|
{
|
|
SYSTEMTIME SystemTime;
|
|
|
|
GetLocalTime(&SystemTime);
|
|
|
|
wDateTime[MONTH] = SystemTime.wMonth;
|
|
wDateTime[DAY] = SystemTime.wDay;
|
|
wDateTime[YEAR] = SystemTime.wYear;
|
|
wDateTime[WEEKDAY] = SystemTime.wDayOfWeek;
|
|
fDateDirty = FALSE;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// SetTime
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
void SetTime()
|
|
{
|
|
SYSTEMTIME SystemTime;
|
|
|
|
SystemTime.wHour = wDateTime[HOUR];
|
|
SystemTime.wMinute = wDateTime[MINUTE];
|
|
SystemTime.wSecond = wDateTime[SECOND];
|
|
|
|
SystemTime.wMilliseconds = 0;
|
|
|
|
SystemTime.wMonth = wDateTime[MONTH];
|
|
SystemTime.wDay = wDateTime[DAY];
|
|
SystemTime.wYear = wDateTime[YEAR];
|
|
|
|
SetLocalTime(&SystemTime);
|
|
SetLocalTime(&SystemTime);
|
|
fDateDirty = FALSE;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// SetDate
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
void SetDate()
|
|
{
|
|
SYSTEMTIME SystemTime;
|
|
|
|
SystemTime.wHour = wDateTime[HOUR];
|
|
SystemTime.wMinute = wDateTime[MINUTE];
|
|
SystemTime.wSecond = wDateTime[SECOND];
|
|
|
|
SystemTime.wMilliseconds = 0;
|
|
|
|
SystemTime.wMonth = wDateTime[MONTH];
|
|
SystemTime.wDay = wDateTime[DAY];
|
|
SystemTime.wYear = wDateTime[YEAR];
|
|
|
|
SetLocalTime(&SystemTime);
|
|
SetLocalTime(&SystemTime);
|
|
fDateDirty = FALSE;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// AdjustDelta
|
|
//
|
|
// Alters the variables in wDeltaDateTime, allowing a CANCEL button
|
|
// to perform its job by resetting the time as if it had never been
|
|
// touched. GetTime() & GetDate() should already have been called.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
void AdjustDelta(
|
|
HWND hDlg,
|
|
int nIndex)
|
|
{
|
|
int nDelta;
|
|
|
|
//
|
|
// We dont do time this way any more.
|
|
//
|
|
if (nIndex <= SECOND && nIndex >= HOUR)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Get position of the buddy from either the date or the time.
|
|
//
|
|
nDelta = (int)SendDlgItemMessage( hDlg,
|
|
nIndex <= SECOND
|
|
? DATETIME_TARROW
|
|
: DATETIME_YARROW,
|
|
UDM_GETPOS,
|
|
0,
|
|
0L );
|
|
|
|
if ((nIndex == YEAR) && !g_bLZero[YEAR])
|
|
{
|
|
//
|
|
// Years before 80 are 2080.
|
|
// Range is 1980...2079.
|
|
//
|
|
if (nDelta < 80)
|
|
{
|
|
nDelta += 2000;
|
|
}
|
|
else
|
|
{
|
|
nDelta += 1900;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If our current recording of the time/date is not what we have
|
|
// now, do deltas.
|
|
//
|
|
if (wDateTime[nIndex] != nDelta)
|
|
{
|
|
//
|
|
// Previous value is current user's settings.
|
|
//
|
|
wPrevDateTime[nIndex] = wDateTime[nIndex] = (WORD)nDelta;
|
|
fDateDirty = TRUE;
|
|
|
|
//
|
|
// If we are changing HMS, update the time.
|
|
//
|
|
if (nIndex <= SECOND)
|
|
{
|
|
nIndex = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// AdjustDeltaMonth
|
|
//
|
|
// Change the month part of wDateTime
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
extern int GetDaysOfTheMonth(int iMonth);
|
|
|
|
void AdjustDeltaMonth(
|
|
int iMonth)
|
|
{
|
|
GetTime();
|
|
|
|
if (wDateTime[MONTH] != iMonth)
|
|
{
|
|
//
|
|
// Make sure the current day is valid in the new month.
|
|
//
|
|
if (wDateTime[DAY] > (WORD)GetDaysOfTheMonth(iMonth))
|
|
{
|
|
wDateTime[DAY] = (WORD)GetDaysOfTheMonth(iMonth);
|
|
}
|
|
|
|
wPrevDateTime[MONTH] = wDateTime[MONTH] = (WORD)iMonth;
|
|
fDateDirty = TRUE;
|
|
|
|
g_sDateInfo[DAY].nMax = MonthUpperBound( wDateTime[MONTH],
|
|
wDateTime[YEAR] );
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ReadShortDate
|
|
//
|
|
// Verify that pszDate is one of MDY, DMY, or YMD.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
int ReadShortDate(
|
|
LPTSTR pszDate,
|
|
BOOL *pbMonth,
|
|
BOOL *pbDay,
|
|
BOOL *pbYear)
|
|
{
|
|
int i, nOrder;
|
|
BOOL *pbOrder[3];
|
|
TCHAR cHope[3];
|
|
|
|
//
|
|
// nOrder : 0 = MDY
|
|
// 1 = DMY
|
|
// 2 = YMD
|
|
//
|
|
switch (cHope[0] = *pszDate)
|
|
{
|
|
case ( TEXT('M') ) :
|
|
{
|
|
nOrder = 0;
|
|
pbOrder[0] = pbMonth;
|
|
break;
|
|
}
|
|
case ( TEXT('d') ) :
|
|
{
|
|
nOrder = 1;
|
|
pbOrder[0] = pbDay;
|
|
break;
|
|
}
|
|
case ( TEXT('y') ) :
|
|
{
|
|
nOrder = 2;
|
|
pbOrder[0] = pbYear;
|
|
break;
|
|
}
|
|
default :
|
|
{
|
|
return (FALSE);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Sets element 1.
|
|
//
|
|
if (nOrder) // 1 2
|
|
{
|
|
cHope[1] = TEXT('M');
|
|
pbOrder[1] = pbMonth;
|
|
}
|
|
else // 0
|
|
{
|
|
cHope[1] = TEXT('d');
|
|
pbOrder[1] = pbDay;
|
|
}
|
|
|
|
//
|
|
// Sets element 2.
|
|
//
|
|
if (nOrder == 2) // 2
|
|
{
|
|
cHope[2] = TEXT('d');
|
|
pbOrder[2] = pbDay;
|
|
}
|
|
else // 0 1
|
|
{
|
|
cHope[2] = TEXT('y');
|
|
pbOrder[2] = pbYear;
|
|
}
|
|
|
|
//
|
|
// Verifies that pszDate is of the form MDY DMY YMD.
|
|
//
|
|
for (i = 0; i < 3; i++, pszDate++)
|
|
{
|
|
if (*pszDate != cHope[i])
|
|
{
|
|
return (-1 - nOrder);
|
|
}
|
|
|
|
if (!(pszDate = ParseDateElement(pszDate, pbOrder[i])))
|
|
{
|
|
return (-1 - nOrder);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Success. Return MDY, DMY or YMD index.
|
|
//
|
|
return (nOrder);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// GetMaxCharWidth
|
|
//
|
|
// Determine the widest digit (safety against variable pitch fonts).
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
int GetMaxCharWidth(
|
|
HDC hDC)
|
|
{
|
|
UINT nNumWidth[10];
|
|
UINT i, nMaxNumWidth;
|
|
|
|
GetCharWidth32(hDC, TEXT('0'), TEXT('9'), nNumWidth);
|
|
|
|
for (nMaxNumWidth = 0, i = 0; i < 10; i++)
|
|
{
|
|
if (nNumWidth[i] > nMaxNumWidth)
|
|
{
|
|
nMaxNumWidth = nNumWidth[i];
|
|
}
|
|
}
|
|
|
|
return (nMaxNumWidth);
|
|
}
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// GetMaxSubstitutedCharWidth
|
|
//
|
|
// Determine the widest digit (safety against variable pitch fonts), but
|
|
// do it using strings so that if number substitution is on, we will get
|
|
// the width of the number based on what will actually be displayed
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
int GetMaxSubstitutedCharWidth(
|
|
HDC hDC)
|
|
{
|
|
char sz[2] = "0";
|
|
TCHAR szAMPM[12];
|
|
LONG i, nMaxNumWidth;
|
|
DWORD dwWidth;
|
|
SIZE size;
|
|
|
|
for (nMaxNumWidth = 0, i = 0; i < 10; (*sz)++, i++)
|
|
{
|
|
if (GetTextExtentPoint32A(hDC, sz, 1, &size) && size.cx > nMaxNumWidth)
|
|
nMaxNumWidth = size.cx;
|
|
|
|
}
|
|
|
|
if (nMaxNumWidth <= 8)
|
|
{
|
|
GetProfileString(szIntl, TEXT("s1159"), IntlDef.s1159, szAMPM, ARRAYSIZE(szAMPM));
|
|
dwWidth = LOWORD(GetTextExtent(hDC, szAMPM, lstrlen(szAMPM)));
|
|
if (dwWidth > 22)
|
|
nMaxNumWidth = 10;
|
|
GetProfileString(szIntl, TEXT("s2359"), IntlDef.s2359, szAMPM, ARRAYSIZE(szAMPM));
|
|
dwWidth = LOWORD(GetTextExtent(hDC, szAMPM, lstrlen(szAMPM)));
|
|
if (dwWidth > 22)
|
|
nMaxNumWidth = 10;
|
|
}
|
|
return (nMaxNumWidth);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ReflectAMPM
|
|
//
|
|
// Sets the global g_bPM and updates the control to display AM or PM.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
void ReflectAMPM(
|
|
HWND hDlg,
|
|
int nNum)
|
|
{
|
|
HWND hCtl = GetDlgItem(hDlg, DATETIME_AMPM);
|
|
|
|
ListBox_SetTopIndex(hCtl, g_bPM);
|
|
ListBox_SetCurSel(hCtl, (GetFocus() == hCtl) ? g_bPM : -1);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// GetTextExtent
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
#ifdef WIN32
|
|
DWORD GetTextExtent(
|
|
HDC hdc,
|
|
LPCTSTR lpsz,
|
|
int cb)
|
|
{
|
|
SIZE sz;
|
|
BOOL bSuccess = GetTextExtentPoint(hdc, lpsz, cb, &sz);
|
|
|
|
if ( !bSuccess )
|
|
{
|
|
ZeroMemory( &sz, sizeof(sz) );
|
|
}
|
|
|
|
return ( MAKELONG((WORD)sz.cx, (WORD)sz.cy) );
|
|
}
|
|
#endif
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// DateTimeInit
|
|
//
|
|
// Determine the widest digit (safety against variable pitch fonts).
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
void DateTimeInit(
|
|
HWND hDlg,
|
|
WORD nBaseID,
|
|
WORD nSepID,
|
|
LPTSTR pszSep,
|
|
int nMaxDigitWidth,
|
|
BOOL bDate)
|
|
{
|
|
HWND hAMPMList;
|
|
HWND hDay, hMonth, hYear; // also used as hHour, hMinute, & hSecond
|
|
HWND hOrder[5];
|
|
HDC hDC;
|
|
int nWidth, nHeight, X;
|
|
DWORD dwSepExt;
|
|
RECT Rect;
|
|
int i;
|
|
int nAMPMlength;
|
|
|
|
hMonth = GetDlgItem(hDlg, nBaseID);
|
|
hDay = GetDlgItem(hDlg, nBaseID + 1);
|
|
hYear = GetDlgItem(hDlg, nBaseID + 2);
|
|
hOrder[1] = GetDlgItem(hDlg, nSepID);
|
|
hOrder[3] = GetDlgItem(hDlg, nSepID + 1);
|
|
|
|
if (bDate)
|
|
{
|
|
i = GetProfileInt(szIntl, TEXT("iDate"), 0);
|
|
}
|
|
else
|
|
{
|
|
if (g_b24HR = (BOOL)GetProfileInt(szIntl, TEXT("iTime"), 0))
|
|
{
|
|
g_sDateInfo[HOUR].nMin = 0;
|
|
g_sDateInfo[HOUR].nMax = 23;
|
|
}
|
|
else
|
|
{
|
|
g_sDateInfo[HOUR].nMin = 1;
|
|
g_sDateInfo[HOUR].nMax = 12;
|
|
|
|
GetProfileString(szIntl, TEXT("s1159"), IntlDef.s1159, sz1159, ARRAYSIZE(sz1159));
|
|
GetProfileString(szIntl, TEXT("s2359"), IntlDef.s2359, sz2359, ARRAYSIZE(sz2359));
|
|
}
|
|
i = 0;
|
|
}
|
|
|
|
switch (i)
|
|
{
|
|
case ( 1 ) :
|
|
{
|
|
hOrder[0] = hDay;
|
|
hOrder[2] = hMonth;
|
|
hOrder[4] = hYear;
|
|
break;
|
|
}
|
|
case ( 2 ) :
|
|
{
|
|
hOrder[0] = hYear;
|
|
hOrder[2] = hMonth;
|
|
hOrder[4] = hDay;
|
|
break;
|
|
}
|
|
case ( 0 ) :
|
|
default :
|
|
{
|
|
hOrder[0] = hMonth;
|
|
hOrder[2] = hDay;
|
|
hOrder[4] = hYear;
|
|
break;
|
|
}
|
|
}
|
|
|
|
hDC = GetDC(hDlg);
|
|
|
|
if (!bDate)
|
|
{
|
|
dwSepExt = GetTextExtent(hDC, sz1159, lstrlen(sz1159));
|
|
nAMPMlength = LOWORD(GetTextExtent(hDC, sz2359, lstrlen(sz2359)));
|
|
if (nAMPMlength < (int)LOWORD(dwSepExt))
|
|
{
|
|
nAMPMlength = (int)LOWORD(dwSepExt);
|
|
}
|
|
}
|
|
|
|
dwSepExt = GetTextExtent(hDC, pszSep, lstrlen(pszSep));
|
|
ReleaseDC(hDlg, hDC);
|
|
|
|
GetWindowRect(hYear, (LPRECT)&Rect);
|
|
ScreenToClient(hDlg, (LPPOINT)&Rect.left);
|
|
ScreenToClient(hDlg, (LPPOINT)&Rect.right);
|
|
|
|
nHeight = Rect.bottom - Rect.top;
|
|
nWidth = Rect.top;
|
|
|
|
GetWindowRect( GetDlgItem( hDlg,
|
|
bDate ? DATETIME_CALENDAR : DATETIME_CLOCK ),
|
|
(LPRECT)&Rect );
|
|
ScreenToClient(hDlg, (LPPOINT)&Rect.left);
|
|
ScreenToClient(hDlg, (LPPOINT)&Rect.right);
|
|
|
|
Rect.top = nWidth;
|
|
X = (Rect.left + Rect.right - (6 * nMaxDigitWidth) - (2 * LOWORD(dwSepExt))) / 2;
|
|
|
|
if (bDate)
|
|
{
|
|
if (g_bLZero[YEAR])
|
|
{
|
|
X -= nMaxDigitWidth;
|
|
}
|
|
}
|
|
else if (!g_b24HR)
|
|
{
|
|
X -= nAMPMlength / 2;
|
|
}
|
|
|
|
for (i = 0; i < 5; i++)
|
|
{
|
|
nWidth = (i % 2) ? LOWORD(dwSepExt) : 2 * nMaxDigitWidth;
|
|
|
|
if ((hOrder[i] == hYear) && bDate && g_bLZero[YEAR])
|
|
{
|
|
nWidth *= 2;
|
|
}
|
|
|
|
//
|
|
// Allow for centering in edit control.
|
|
//
|
|
nWidth += 2;
|
|
|
|
// MoveWindow(hOrder[i], X, Rect.top, nWidth, nHeight, FALSE);
|
|
X += nWidth;
|
|
}
|
|
|
|
hAMPMList = GetDlgItem(hDlg, DATETIME_AMPM);
|
|
ListBox_ResetContent(hAMPMList);
|
|
|
|
if (!bDate && !g_b24HR)
|
|
{
|
|
ListBox_InsertString(hAMPMList, 0, sz1159);
|
|
ListBox_InsertString(hAMPMList, 1, sz2359);
|
|
}
|
|
|
|
EnableWindow(hAMPMList, !g_b24HR);
|
|
|
|
Edit_LimitText(hYear, (bDate && g_bLZero[YEAR]) ? 4 : 2);
|
|
Edit_LimitText(hMonth, 2);
|
|
Edit_LimitText(hDay, 2);
|
|
|
|
SetDlgItemText(hDlg, nSepID, pszSep);
|
|
SetDlgItemText(hDlg, nSepID + 1, pszSep);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// myitoa
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
void myitoa(
|
|
int intValue,
|
|
LPTSTR lpStr)
|
|
{
|
|
LPTSTR lpString;
|
|
TCHAR c;
|
|
|
|
//
|
|
// lpString points to 1st char.
|
|
//
|
|
lpString = lpStr;
|
|
|
|
do
|
|
{
|
|
*lpStr++ = (TCHAR)(intValue % 10 + TEXT('0'));
|
|
} while ((intValue /= 10) > 0);
|
|
|
|
//
|
|
// lpStr points to last char.
|
|
//
|
|
*lpStr-- = TEXT('\0');
|
|
|
|
//
|
|
// Now reverse the string.
|
|
//
|
|
while (lpString < lpStr)
|
|
{
|
|
c = *lpString;
|
|
*(lpString++) = *lpStr;
|
|
*(lpStr--) = c;
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// UpdateItem
|
|
//
|
|
// This displays the information in the control from the array
|
|
// of global values. Also selects the control. Also adds leading 0's
|
|
// as well as rounding years to 2 digits and 24 or AM/PM hours.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
void UpdateItem(
|
|
HWND hDlg,
|
|
int i)
|
|
{
|
|
TCHAR szNum[5];
|
|
int nNum = g_Modified ? wPrevDateTime[i] : wDateTime[i];
|
|
|
|
//
|
|
// Use internal time.
|
|
//
|
|
if (i <= SECOND && i >= HOUR)
|
|
{
|
|
nNum = g_Time[i];
|
|
|
|
//
|
|
// Do not paint un-necessarily.
|
|
//
|
|
if ((nNum == g_LastTime[i]) && (nNum >= 10))
|
|
{
|
|
return;
|
|
}
|
|
|
|
g_LastTime[i] = nNum;
|
|
|
|
if (i == HOUR)
|
|
{
|
|
if (IsAMPM(nNum))
|
|
{
|
|
g_bPM = TRUE;
|
|
}
|
|
ReflectAMPM(hDlg, nNum);
|
|
}
|
|
}
|
|
|
|
if (i == YEAR)
|
|
{
|
|
//
|
|
// Round the years to last 2 digits.
|
|
//
|
|
if (!g_bLZero[i])
|
|
{
|
|
nNum %= 100;
|
|
}
|
|
}
|
|
else if ((i == HOUR) && !g_b24HR)
|
|
{
|
|
//
|
|
// nNum came from our internal date time.
|
|
// Remove 12 hours if not 24hour.
|
|
//
|
|
if (g_bPM)
|
|
{
|
|
nNum %= 12;
|
|
}
|
|
|
|
//
|
|
// 00 hours is actually 12AM.
|
|
//
|
|
if (!nNum)
|
|
{
|
|
nNum = 12;
|
|
}
|
|
}
|
|
|
|
//
|
|
// See if we need leading zeros.
|
|
// We only deal with 2 character numbers MAX.
|
|
//
|
|
if ((nNum < 10) && (g_bLZero[i] || (i == YEAR)))
|
|
{
|
|
szNum[0] = TEXT('0');
|
|
szNum[1] = (TCHAR)(TEXT('0') + nNum);
|
|
szNum[2] = TEXT('\0');
|
|
}
|
|
else
|
|
{
|
|
myitoa(nNum, szNum);
|
|
}
|
|
|
|
//
|
|
// Reflect the value in the appropriate control.
|
|
//
|
|
SetDlgItemText(hDlg, DATETIME_HOUR + i, szNum);
|
|
|
|
//
|
|
// Select the field too.
|
|
//
|
|
SendDlgItemMessage(hDlg, DATETIME_HOUR + i, EM_SETSEL, 0, MAKELONG(0, 32767));
|
|
|
|
//
|
|
// If we changed year or month, then we may have altered the leap year
|
|
// state.
|
|
//
|
|
if (i == MONTH || i == YEAR)
|
|
{
|
|
g_sDateInfo[DAY].nMax = MonthUpperBound( wDateTime[MONTH],
|
|
wDateTime[YEAR] );
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// _ShowTZ
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
TCHAR c_szFirstBootTZ[] = TEXT("!!!First Boot!!!");
|
|
|
|
void _ShowTZ(
|
|
HWND hDlg)
|
|
{
|
|
HWND ctl = GetDlgItem(hDlg, DATETIME_CURTZ);
|
|
TIME_ZONE_INFORMATION info;
|
|
TCHAR final[64 + TZNAME_SIZE];
|
|
TCHAR name[TZNAME_SIZE];
|
|
DWORD TimeZoneId;
|
|
|
|
if (g_bFirstBoot)
|
|
{
|
|
ShowWindow(ctl, SW_HIDE);
|
|
}
|
|
else
|
|
{
|
|
TimeZoneId = GetTimeZoneInformation(&info);
|
|
#ifdef UNICODE
|
|
lstrcpy( name,
|
|
(TimeZoneId == TIME_ZONE_ID_STANDARD)
|
|
? info.StandardName
|
|
: info.DaylightName );
|
|
#else
|
|
WideStrToStr(name, (TimeZoneId == TIME_ZONE_ID_STANDARD)
|
|
? info.StandardName
|
|
: info.DaylightName );
|
|
#endif //UNICODE
|
|
|
|
//
|
|
// Display nothing if it is our special 1st boot marker.
|
|
//
|
|
if (*name && (lstrcmpi(name, c_szFirstBootTZ) != 0))
|
|
{
|
|
static TCHAR format[128] = TEXT("");
|
|
|
|
if (!*format)
|
|
{
|
|
GetWindowText( ctl,
|
|
format,
|
|
ARRAYSIZE(format) );
|
|
}
|
|
wsprintf(final, format, name);
|
|
}
|
|
else
|
|
{
|
|
*final = 0;
|
|
}
|
|
|
|
SetWindowText(ctl, final);
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// UnhookTime
|
|
//
|
|
// To stop the clock calling us back all the time (around exit).
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
void UnhookTimer(
|
|
HWND hDlg)
|
|
{
|
|
SendDlgItemMessage(hDlg, DATETIME_CLOCK, CLM_TIMEHWND, CLF_SETHWND, 0);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// TimeProvider
|
|
//
|
|
// Called by the clock to find out what time it is.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
void TimeProvider(
|
|
LPSYSTEMTIME lpSystemTime,
|
|
HWND hDlg)
|
|
{
|
|
short wTemp[7];
|
|
|
|
//
|
|
// If the user has modified the time, the clock should
|
|
// display the edit controls, otherwise its just the SystemTime.
|
|
//
|
|
if (g_Modified)
|
|
{
|
|
lpSystemTime->wHour = (WORD)g_Time[HOUR];
|
|
lpSystemTime->wMinute = (WORD)g_Time[MINUTE];
|
|
lpSystemTime->wSecond = (WORD)g_Time[SECOND];
|
|
}
|
|
else
|
|
{
|
|
#ifdef WIN32
|
|
GetLocalTime(lpSystemTime);
|
|
#else
|
|
GetTime();
|
|
if (wDateTime[HOUR] >= 0 && wDateTime[HOUR] <= 24)
|
|
{
|
|
lpSystemTime->wHour = wDateTime[HOUR];
|
|
}
|
|
lpSystemTime->wMinute = wDateTime[MINUTE];
|
|
lpSystemTime->wSecond = wDateTime[SECOND];
|
|
|
|
#endif
|
|
//
|
|
// Copy the time and display it for us too.
|
|
//
|
|
g_bPM = IsAMPM(lpSystemTime->wHour);
|
|
g_Time[HOUR] = lpSystemTime->wHour;
|
|
g_Time[MINUTE] = lpSystemTime->wMinute;
|
|
g_Time[SECOND] = lpSystemTime->wSecond;
|
|
|
|
//
|
|
// Check for date rollover.
|
|
//
|
|
if (!fDateDirty)
|
|
{
|
|
wTemp[DAY] = wDateTime[DAY];
|
|
wTemp[MONTH] = wDateTime[MONTH];
|
|
wTemp[YEAR] = wDateTime[YEAR];
|
|
|
|
GetDate();
|
|
|
|
if ((wDateTime[DAY] != wTemp[DAY]) ||
|
|
(wDateTime[MONTH] != wTemp[MONTH]) ||
|
|
(wDateTime[YEAR] != wTemp[YEAR]))
|
|
{
|
|
InvalidateRect(GetDlgItem(hDlg, DATETIME_CALENDAR), NULL, TRUE);
|
|
|
|
if (wDateTime[MONTH] != wTemp[MONTH])
|
|
{
|
|
ComboBox_SetCurSel( GetDlgItem(hDlg, DATETIME_MONTHNAME),
|
|
wDateTime[MONTH] - 1 );
|
|
}
|
|
|
|
if (wDateTime[YEAR] != wTemp[YEAR])
|
|
{
|
|
UpdateItem(hDlg, YEAR);
|
|
}
|
|
|
|
_ShowTZ(hDlg);
|
|
}
|
|
}
|
|
|
|
UpdateItem(hDlg, HOUR);
|
|
UpdateItem(hDlg, MINUTE);
|
|
UpdateItem(hDlg, SECOND);
|
|
ReflectAMPM(hDlg, g_Time[HOUR]);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// bSupportedCalendar
|
|
//
|
|
// Returns True if the current calendar is not Hijri nor Hebrew
|
|
//
|
|
// Otherwise it returns FALSE.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL bSupportedCalendar()
|
|
{
|
|
TCHAR tchCalendar[32];
|
|
CALTYPE defCalendar = CAL_GREGORIAN;
|
|
|
|
if (GetLocaleInfo(LOCALE_USER_DEFAULT,
|
|
LOCALE_ICALENDARTYPE,
|
|
tchCalendar,
|
|
ARRAYSIZE(tchCalendar)))
|
|
{
|
|
defCalendar = StrToInt(tchCalendar);
|
|
}
|
|
|
|
return (!(defCalendar == CAL_HIJRI || defCalendar == CAL_HEBREW));
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// InitDateTimeDlg
|
|
//
|
|
// Called to init the dialog.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
void InitDateTimeDlg(
|
|
HWND hDlg,
|
|
UINT message,
|
|
WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
int nMaxDigitWidth;
|
|
int i;
|
|
TCHAR szNum[5];
|
|
TCHAR szMonth[64];
|
|
TCHAR szShortDate[12];
|
|
HDC hDC;
|
|
HFONT hFont;
|
|
HWND hwndCB;
|
|
CALID calId;
|
|
static int nInc[] = { 1, 5, 5, 1, 1, 5 };
|
|
|
|
HWND hwndScroll;
|
|
UDACCEL udAccel[2];
|
|
HWND hwndTBorder;
|
|
|
|
HCURSOR oldcursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
|
|
|
|
LCID lcid = LOCALE_USER_DEFAULT;
|
|
|
|
InitCommonControls();
|
|
|
|
//
|
|
// Sets the Leading zero status of the 6 controls.
|
|
//
|
|
g_bLZero[HOUR] = g_bLZero[MONTH] = g_bLZero[DAY] = FALSE;
|
|
g_bLZero[MINUTE] = g_bLZero[SECOND] = g_bLZero[YEAR] = TRUE;
|
|
|
|
hDC = GetDC(hDlg);
|
|
|
|
if (hFont = (HFONT)SendMessage(hDlg, WM_GETFONT, 0, 0L))
|
|
{
|
|
hFont = SelectObject( hDC, hFont );
|
|
}
|
|
|
|
if (hFont)
|
|
{
|
|
SelectObject(hDC, hFont);
|
|
}
|
|
|
|
AdjustAMPMPosition(hDlg);
|
|
|
|
nMaxDigitWidth = GetMaxCharWidth(hDC);
|
|
ReleaseDC(hDlg, hDC);
|
|
|
|
g_bLZero[HOUR] = GetProfileInt(szIntl, TEXT("iTLZero"), 0);
|
|
//
|
|
// Initialize szShortDate in case GetProfileString fails.
|
|
//
|
|
lstrcpyn(szShortDate, IntlDef.sShortDate, ARRAYSIZE(szShortDate));
|
|
GetProfileString(szIntl, TEXT("sShortDate"), IntlDef.sShortDate, szShortDate, ARRAYSIZE(szShortDate));
|
|
ReadShortDate(szShortDate, g_bLZero + MONTH, g_bLZero + DAY, g_bLZero + YEAR);
|
|
|
|
g_bLZero[YEAR] = TRUE; //we always want the year to be 4 digits (this will be bad in late 9999)
|
|
|
|
//
|
|
// Setup the TIME stuff.
|
|
//
|
|
GetTime();
|
|
|
|
g_Time[HOUR] = wDateTime[HOUR];
|
|
g_Time[MINUTE] = wDateTime[MINUTE];
|
|
g_Time[SECOND] = wDateTime[SECOND];
|
|
|
|
GetProfileString(szIntl, TEXT("sTime"), IntlDef.sTime, szNum, 3);
|
|
DateTimeInit(hDlg, DATETIME_HOUR, DATETIME_TSEP1, szNum, nMaxDigitWidth, FALSE);
|
|
|
|
//
|
|
// Force all entries to be re-drawn,
|
|
//
|
|
g_LastTime[HOUR] = g_LastTime[MINUTE] = g_LastTime[SECOND] = -1;
|
|
UpdateItem(hDlg, HOUR);
|
|
UpdateItem(hDlg, MINUTE);
|
|
UpdateItem(hDlg, SECOND);
|
|
ReflectAMPM(hDlg, wDateTime[HOUR]);
|
|
|
|
//
|
|
// Setup the Date stuff.
|
|
//
|
|
GetDate();
|
|
|
|
g_sDateInfo[DAY].nMax = MonthUpperBound(wDateTime[MONTH], wDateTime[YEAR]);
|
|
|
|
if (!g_bLZero[YEAR])
|
|
{
|
|
wDateTime[YEAR] %= 100;
|
|
g_sDateInfo[YEAR].nMax = 99;
|
|
g_sDateInfo[YEAR].nMin = 0;
|
|
}
|
|
else
|
|
{
|
|
g_sDateInfo[YEAR].nMax = 2099;
|
|
g_sDateInfo[YEAR].nMin = 1980;
|
|
}
|
|
|
|
for (i = MONTH; i <= YEAR; i++)
|
|
{
|
|
wPrevDateTime[i] = -1;
|
|
}
|
|
|
|
//
|
|
// Get the month names. And select this month.
|
|
//
|
|
hwndCB = GetDlgItem(hDlg, DATETIME_MONTHNAME);
|
|
ComboBox_ResetContent(hwndCB);
|
|
//
|
|
// If the current calendar is Hijri or Hebrew then use the Gregorian one.
|
|
//
|
|
if (!bSupportedCalendar())
|
|
lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
|
|
|
|
GetLocaleInfo(lcid, LOCALE_ICALENDARTYPE, szMonth, ARRAYSIZE(szMonth));
|
|
calId = (CALID)StrToInt(szMonth);
|
|
|
|
for (i = 0; i < 12; i++)
|
|
{
|
|
#ifdef WINNT
|
|
GetCalendarInfo(lcid, calId, CAL_SMONTHNAME1 + i, szMonth, ARRAYSIZE(szMonth), NULL);
|
|
#else
|
|
GetLocaleInfo( LOCALE_USER_DEFAULT,
|
|
LOCALE_SMONTHNAME1 + i,
|
|
szMonth,
|
|
sizeof(szMonth) );
|
|
|
|
if (*szMonth && !IsDBCSLeadByte(*szMonth))
|
|
{
|
|
*szMonth = (TCHAR)CharUpper((LPTSTR)(DWORD)(TBYTE)*szMonth);
|
|
}
|
|
|
|
#endif
|
|
ComboBox_AddString(hwndCB, szMonth);
|
|
}
|
|
|
|
ComboBox_SetCurSel(hwndCB, wDateTime[MONTH] - 1);
|
|
|
|
//
|
|
// Set the default modifier for the Year Updown arrows.
|
|
//
|
|
wParam -= DATETIME_HOUR;
|
|
hwndScroll = GetDlgItem(hDlg, DATETIME_YARROW);
|
|
SendMessage( hwndScroll,
|
|
UDM_SETRANGE,
|
|
0,
|
|
MAKELPARAM(g_sDateInfo[YEAR].nMax, g_sDateInfo[YEAR].nMin) );
|
|
|
|
udAccel[0].nSec = 0;
|
|
udAccel[0].nInc = 1;
|
|
udAccel[1].nSec = 2;
|
|
udAccel[1].nInc = nInc[YEAR];
|
|
|
|
SendMessage(hwndScroll, UDM_SETACCEL, 2, (LPARAM)(LPUDACCEL)udAccel);
|
|
SendMessage(hwndScroll, UDM_SETBUDDY, (WPARAM)GetDlgItem(hDlg, DATETIME_YEAR), 0L);
|
|
|
|
//
|
|
// Set the default modifier for the time arrows.
|
|
// It should control the HOURS by default as per joelgros
|
|
//
|
|
hwndScroll = GetDlgItem(hDlg, DATETIME_TARROW);
|
|
SendMessage( hwndScroll,
|
|
UDM_SETRANGE,
|
|
0,
|
|
MAKELPARAM( g_sDateInfo[HOUR].nMax,
|
|
g_sDateInfo[HOUR].nMin) );
|
|
udAccel[0].nSec = 0;
|
|
udAccel[0].nInc = 1;
|
|
udAccel[1].nSec = 2;
|
|
udAccel[1].nInc = nInc[HOUR];
|
|
|
|
SendMessage( hwndScroll, UDM_SETACCEL, 2, (LPARAM)(LPUDACCEL)udAccel );
|
|
SendMessage( hwndScroll, UDM_SETBUDDY, (WPARAM)GetDlgItem(hDlg, DATETIME_HOUR), 0L );
|
|
|
|
//
|
|
// Make the 'well' for the digits appear.
|
|
//
|
|
hwndTBorder = GetDlgItem(hDlg, DATETIME_TBORDER);
|
|
SetWindowLong( hwndTBorder,
|
|
GWL_EXSTYLE,
|
|
GetWindowLong(hwndTBorder, GWL_EXSTYLE) | WS_EX_CLIENTEDGE );
|
|
|
|
//
|
|
// Display the border right now.
|
|
//
|
|
SetWindowPos( hwndTBorder,
|
|
NULL,
|
|
0, 0, 0, 0,
|
|
SWP_NOMOVE | SWP_NOSIZE | SWP_DRAWFRAME | SWP_SHOWWINDOW );
|
|
|
|
//
|
|
// Display month->year.
|
|
//
|
|
for (i = MONTH; i <= YEAR; i++)
|
|
{
|
|
if ((wDateTime[i] != wPrevDateTime[i]) &&
|
|
(GetFocus() != GetDlgItem(hDlg, DATETIME_HOUR + i)))
|
|
{
|
|
//
|
|
// Update previous date-time.
|
|
//
|
|
wPrevDateTime[i] = wDateTime[i];
|
|
|
|
if (i == YEAR)
|
|
{
|
|
UpdateItem(hDlg, i);
|
|
}
|
|
}
|
|
}
|
|
|
|
g_Modified = FALSE;
|
|
|
|
//
|
|
// Tell the clock that we have a time provider - must be done last.
|
|
//
|
|
SendDlgItemMessage( hDlg,
|
|
DATETIME_CLOCK,
|
|
CLM_TIMEHWND,
|
|
CLF_SETHWND,
|
|
(LPARAM)(LPINT)hDlg );
|
|
|
|
SetCursor(oldcursor);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CheckNum
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
LRESULT CheckNum(
|
|
HWND hDlg,
|
|
UINT nScrollID,
|
|
HWND hCtl)
|
|
{
|
|
static int cReenter = 0;
|
|
|
|
LRESULT lRet;
|
|
|
|
//
|
|
// If this is an illegal value, (but not blank), then kill the last char
|
|
// that was entered.
|
|
//
|
|
lRet = SendDlgItemMessage(hDlg, nScrollID, UDM_GETPOS, 0, 0L);
|
|
|
|
//
|
|
// Guard against re-entrance.
|
|
//
|
|
++cReenter;
|
|
|
|
if (cReenter <= 4)
|
|
{
|
|
SendMessage( hCtl,
|
|
HIWORD(lRet) && GetWindowTextLength(hCtl)
|
|
? EM_UNDO
|
|
: EM_EMPTYUNDOBUFFER,
|
|
0,
|
|
0L );
|
|
}
|
|
|
|
--cReenter;
|
|
|
|
return (lRet);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// DateTimeDlgProc
|
|
//
|
|
// Main dialog proc.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
INT_PTR CALLBACK DateTimeDlgProc(
|
|
HWND hDlg,
|
|
UINT uMsg,
|
|
WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
int i;
|
|
|
|
switch (uMsg)
|
|
{
|
|
case (WM_INITDIALOG):
|
|
{
|
|
AddInternetPageAsync(GetParent(hDlg), hDlg);
|
|
|
|
InitDateTimeDlg(hDlg, uMsg, wParam, lParam);
|
|
g_PrevIMCForDateField = ImmAssociateContext(GetDlgItem(hDlg, DATETIME_YEAR), 0);
|
|
break;
|
|
}
|
|
case ( WM_DESTROY ) :
|
|
{
|
|
if (g_PrevIMCForDateField)
|
|
{
|
|
ImmAssociateContext( GetDlgItem(hDlg, DATETIME_YEAR),
|
|
g_PrevIMCForDateField );
|
|
}
|
|
UnhookTimer(hDlg);
|
|
break;
|
|
}
|
|
#ifdef WIN32
|
|
case ( WM_CTLCOLORSTATIC ) :
|
|
#endif
|
|
case ( WM_CTLCOLOR ) :
|
|
{
|
|
//
|
|
// Set the background color of the time controls to the the
|
|
// color of the edit controls.
|
|
//
|
|
if ((GET_WM_CTLCOLOR_HWND(wParam, lParam, uMsg) ==
|
|
GetDlgItem(hDlg, DATETIME_TSEP1)) ||
|
|
(GET_WM_CTLCOLOR_HWND(wParam, lParam, uMsg) ==
|
|
GetDlgItem(hDlg, DATETIME_TSEP2)) ||
|
|
(GET_WM_CTLCOLOR_HWND(wParam, lParam, uMsg) ==
|
|
GetDlgItem(hDlg, DATETIME_TBORDER)))
|
|
{
|
|
#ifndef WIN32
|
|
//
|
|
// Make the statics the color of the edits.
|
|
//
|
|
lParam = GET_WM_CTLCOLOR_MPS(
|
|
GET_WM_CTLCOLOR_HDC(wParam, lParam, uMsg),
|
|
GET_WM_CTLCOLOR_HWND(wParam, lParam, uMsg),
|
|
CTLCOLOR_EDIT );
|
|
|
|
return ((INT_PTR)DefWindowProc(hDlg, uMsg, wParam, lParam));
|
|
#else
|
|
return ((INT_PTR)DefWindowProc(hDlg, WM_CTLCOLOREDIT, wParam, lParam));
|
|
#endif
|
|
}
|
|
return (0);
|
|
break;
|
|
}
|
|
case ( WM_NOTIFY ) :
|
|
{
|
|
//
|
|
// Property sheet handler stuff.
|
|
//
|
|
switch (((NMHDR *)lParam)->code)
|
|
{
|
|
case ( PSN_SETACTIVE ) :
|
|
{
|
|
_ShowTZ(hDlg);
|
|
break;
|
|
}
|
|
case ( PSN_RESET ) :
|
|
{
|
|
UnhookTimer(hDlg);
|
|
|
|
SetFocus(GetDlgItem(hDlg, (int)wParam));
|
|
|
|
GetDate();
|
|
GetTime();
|
|
break;
|
|
}
|
|
case ( PSN_APPLY ) :
|
|
{
|
|
wDateTime[MINUTE] = (WORD)g_Time[MINUTE];
|
|
wDateTime[SECOND] = (WORD)g_Time[SECOND];
|
|
|
|
if (g_b24HR)
|
|
{
|
|
wDateTime[HOUR] = (WORD)g_Time[HOUR];
|
|
}
|
|
else
|
|
{
|
|
wDateTime[HOUR] = g_Time[HOUR] % 12;
|
|
|
|
if (g_bPM)
|
|
{
|
|
wDateTime[HOUR] += 12;
|
|
}
|
|
}
|
|
|
|
g_WasModified = g_Modified;
|
|
SetTime();
|
|
|
|
g_LastTime[HOUR] = g_LastTime[MINUTE] = g_LastTime[SECOND] = -1;
|
|
|
|
for (i = MONTH; i <= YEAR; i++)
|
|
{
|
|
wPrevDateTime[i] = -1;
|
|
}
|
|
|
|
g_Modified = FALSE;
|
|
|
|
wPrevDateTime[HOUR] = wDateTime[HOUR];
|
|
wPrevDateTime[MINUTE] = wDateTime[MINUTE];
|
|
wPrevDateTime[SECOND] = wDateTime[SECOND];
|
|
wPrevDateTime[MONTH] = wDateTime[MONTH];
|
|
wPrevDateTime[DAY] = wDateTime[DAY];
|
|
wPrevDateTime[YEAR] = wDateTime[YEAR];
|
|
wPrevDateTime[WEEKDAY] = wDateTime[WEEKDAY];
|
|
|
|
//
|
|
// We handled it - no repaint.
|
|
//
|
|
return (TRUE);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case ( WM_VSCROLL ) :
|
|
{
|
|
switch (GET_WM_VSCROLL_CODE(wParam, lParam))
|
|
{
|
|
case ( SB_THUMBPOSITION ) :
|
|
{
|
|
SYSTEMTIME SystemTime;
|
|
HWND hBuddy = (HWND)SendMessage(
|
|
GET_WM_VSCROLL_HWND(wParam, lParam),
|
|
UDM_GETBUDDY,
|
|
0,
|
|
0L );
|
|
|
|
if (hBuddy == GetDlgItem(hDlg, DATETIME_HOUR))
|
|
{
|
|
g_Time[HOUR] = GET_WM_VSCROLL_POS(wParam, lParam);
|
|
}
|
|
else if (hBuddy == GetDlgItem(hDlg, DATETIME_MINUTE))
|
|
{
|
|
g_Time[MINUTE] = GET_WM_VSCROLL_POS(wParam, lParam);
|
|
}
|
|
else if (hBuddy == GetDlgItem(hDlg, DATETIME_SECOND))
|
|
{
|
|
g_Time[SECOND] = GET_WM_VSCROLL_POS(wParam, lParam);
|
|
}
|
|
// else if (hBuddy == GetDlgItem(hDlg, DATETIME_AMPM))
|
|
|
|
if (hBuddy != GetDlgItem(hDlg, DATETIME_YEAR))
|
|
g_Modified = TRUE;
|
|
|
|
//
|
|
// Light the apply now button.
|
|
//
|
|
PropSheet_Changed(GetParent(hDlg), hDlg);
|
|
|
|
//
|
|
// Force the clock to reflect this setting.
|
|
//
|
|
TimeProvider(&SystemTime, hDlg);
|
|
|
|
SendDlgItemMessage( hDlg,
|
|
DATETIME_CLOCK,
|
|
CLM_UPDATETIME,
|
|
CLF_SETTIME,
|
|
(LPARAM)(LPSYSTEMTIME)&SystemTime );
|
|
|
|
//
|
|
// Fall thru to update the year...
|
|
//
|
|
}
|
|
case ( SB_ENDSCROLL ) :
|
|
{
|
|
//
|
|
// If this is the year, have the calendar repaint.
|
|
//
|
|
if ((HWND)SendMessage( GET_WM_VSCROLL_HWND(wParam, lParam),
|
|
UDM_GETBUDDY,
|
|
0,
|
|
0L ) == GetDlgItem(hDlg, DATETIME_YEAR))
|
|
{
|
|
//
|
|
// Have it update the information.
|
|
//
|
|
GetTime();
|
|
AdjustDelta(hDlg, YEAR);
|
|
UpdateItem(hDlg, YEAR);
|
|
|
|
InvalidateRect( GetDlgItem(hDlg, DATETIME_CALENDAR),
|
|
NULL,
|
|
TRUE );
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case ( CLM_UPDATETIME ) :
|
|
{
|
|
//
|
|
// The clock updating/reflecting the time.
|
|
//
|
|
switch (wParam)
|
|
{
|
|
case ( CLF_SETTIME ) :
|
|
{
|
|
//
|
|
// Clock telling us what the time is.
|
|
//
|
|
g_Modified = TRUE;
|
|
g_Time[HOUR] = ((LPSYSTEMTIME)lParam)->wHour;
|
|
g_Time[MINUTE] = ((LPSYSTEMTIME)lParam)->wMinute;
|
|
g_Time[SECOND] = ((LPSYSTEMTIME)lParam)->wSecond;
|
|
g_bPM = IsAMPM(g_Time[HOUR]);
|
|
break;
|
|
}
|
|
case ( CLF_GETTIME ) :
|
|
{
|
|
//
|
|
// We tell the clock what time it is.
|
|
//
|
|
TimeProvider((LPSYSTEMTIME)lParam, hDlg);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case ( WM_COMMAND ) :
|
|
{
|
|
//
|
|
// Command processing.
|
|
//
|
|
switch (GET_WM_COMMAND_ID(wParam, lParam))
|
|
{
|
|
case ( DATETIME_AMPM ) :
|
|
{
|
|
//
|
|
// Deals with the AMPM control.
|
|
//
|
|
UDACCEL udAccel;
|
|
HWND hwndScroll = GetDlgItem(hDlg, DATETIME_TARROW);
|
|
HWND hwndThisCtl = GET_WM_COMMAND_HWND(wParam, lParam);
|
|
|
|
//
|
|
// We only care if we get/loose the focus.
|
|
//
|
|
switch (GET_WM_COMMAND_CMD(wParam, lParam))
|
|
{
|
|
case ( LBN_SETFOCUS ) :
|
|
{
|
|
//
|
|
// If we get the focus, then the UD control
|
|
// should deal with the AMPM.
|
|
//
|
|
// Select the visible entry.
|
|
//
|
|
ReflectAMPM(hDlg, wDateTime[HOUR]);
|
|
|
|
// if it has a buddy, remove it...
|
|
if ((HWND)SendMessage( hwndScroll,
|
|
UDM_GETBUDDY,
|
|
0,
|
|
0 ) != NULL)
|
|
{
|
|
SendMessage(hwndScroll, UDM_SETBUDDY, 0, 0);
|
|
}
|
|
|
|
//
|
|
// Tell the UD control how to manipulate AM/PM.
|
|
//
|
|
SendMessage( hwndScroll,
|
|
UDM_SETRANGE,
|
|
0,
|
|
MAKELPARAM(1, 0) );
|
|
udAccel.nSec = 0;
|
|
udAccel.nInc = 1;
|
|
SendMessage( hwndScroll,
|
|
UDM_SETACCEL,
|
|
1,
|
|
(LPARAM)(LPUDACCEL)&udAccel );
|
|
SendMessage( hwndScroll,
|
|
UDM_SETBUDDY,
|
|
(WPARAM)hwndThisCtl,
|
|
0 );
|
|
break;
|
|
}
|
|
case ( LBN_KILLFOCUS ) :
|
|
{
|
|
//
|
|
// When we loose focus, the g_bPM flag is updated.
|
|
//
|
|
// Remove selection from the AM/PM.
|
|
//
|
|
ListBox_SetCurSel(hwndThisCtl, -1);
|
|
|
|
if ((HWND)SendMessage( hwndScroll,
|
|
UDM_GETBUDDY,
|
|
0,
|
|
0 ) == hwndThisCtl)
|
|
{
|
|
SendMessage(hwndScroll, UDM_SETBUDDY, 0, 0);
|
|
}
|
|
|
|
break;
|
|
}
|
|
case ( LBN_SELCHANGE ) :
|
|
{
|
|
if ((g_Modified == FALSE) &&
|
|
(g_bPM == (BOOL)ListBox_GetTopIndex(hwndThisCtl)))
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Find the visible entry.
|
|
//
|
|
g_Modified = TRUE;
|
|
|
|
//
|
|
// Light the apply now button.
|
|
//
|
|
PropSheet_Changed(GetParent(hDlg), hDlg);
|
|
g_bPM = (BOOL)ListBox_GetTopIndex(hwndThisCtl);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case ( DATETIME_HOUR ) :
|
|
case ( DATETIME_MINUTE ) :
|
|
case ( DATETIME_SECOND ) :
|
|
{
|
|
switch (GET_WM_COMMAND_CMD(wParam, lParam))
|
|
{
|
|
case ( EN_CHANGE ) :
|
|
{
|
|
SYSTEMTIME SystemTime;
|
|
|
|
g_Modified = TRUE;
|
|
|
|
//
|
|
// Light the apply now button.
|
|
//
|
|
PropSheet_Changed(GetParent(hDlg), hDlg);
|
|
|
|
//
|
|
// Work out what the change was too.
|
|
//
|
|
g_Time[GET_WM_COMMAND_ID(wParam, lParam) -
|
|
DATETIME_HOUR] =
|
|
(int)SendDlgItemMessage( hDlg,
|
|
DATETIME_TARROW,
|
|
UDM_GETPOS,
|
|
0,
|
|
0 );
|
|
|
|
//
|
|
// Force the clock to reflect this setting.
|
|
//
|
|
TimeProvider(&SystemTime, hDlg);
|
|
SendDlgItemMessage( hDlg,
|
|
DATETIME_CLOCK,
|
|
CLM_UPDATETIME,
|
|
0,
|
|
(LPARAM)(LPSYSTEMTIME)&SystemTime );
|
|
break;
|
|
}
|
|
}
|
|
|
|
// fall thru...
|
|
}
|
|
case ( DATETIME_MONTH ) :
|
|
case ( DATETIME_YEAR ) :
|
|
case ( DATETIME_DAY ) :
|
|
{
|
|
switch (GET_WM_COMMAND_CMD(wParam, lParam))
|
|
{
|
|
case ( EN_CHANGE ) :
|
|
{
|
|
CheckNum( hDlg,
|
|
GET_WM_COMMAND_ID(wParam, lParam) <= DATETIME_SECOND
|
|
? DATETIME_TARROW
|
|
: DATETIME_YARROW,
|
|
GET_WM_COMMAND_HWND(wParam, lParam) );
|
|
|
|
// Changing the year may alter the number of days in February.
|
|
// Yes this is a hack, but this entire applet is a giant
|
|
// broken hack and I want to change it as little as possible.
|
|
if (GET_WM_COMMAND_ID(wParam, lParam) == DATETIME_YEAR && wDateTime[MONTH] == 2)
|
|
{
|
|
g_sDateInfo[DAY].nMax = MonthUpperBound( wDateTime[MONTH],
|
|
wDateTime[YEAR] );
|
|
if (wDateTime[DAY] > g_sDateInfo[DAY].nMax)
|
|
{
|
|
wDateTime[DAY] = (WORD)g_sDateInfo[DAY].nMax;
|
|
fDateDirty = TRUE;
|
|
}
|
|
InvalidateRect( GetDlgItem(hDlg, DATETIME_CALENDAR),
|
|
NULL,
|
|
TRUE );
|
|
}
|
|
break;
|
|
}
|
|
case ( EN_SETFOCUS ) :
|
|
{
|
|
UINT id = GET_WM_COMMAND_ID(wParam, lParam) - DATETIME_HOUR;
|
|
|
|
if (id <= SECOND)
|
|
{
|
|
UDACCEL udAccel[2];
|
|
static int nInc[] = { 1, 5, 5, 1, 1, 5 };
|
|
HWND hwndScroll = GetDlgItem(hDlg, DATETIME_TARROW);
|
|
|
|
// if it has a buddy, remove it...
|
|
if ((HWND)SendMessage( hwndScroll,
|
|
UDM_GETBUDDY,
|
|
0,
|
|
0 ) != NULL)
|
|
{
|
|
SendMessage(hwndScroll, UDM_SETBUDDY, 0, 0);
|
|
}
|
|
|
|
//
|
|
// now set the new one
|
|
//
|
|
SendMessage( hwndScroll,
|
|
UDM_SETRANGE,
|
|
0,
|
|
MAKELPARAM( g_sDateInfo[id].nMax,
|
|
g_sDateInfo[id].nMin) );
|
|
udAccel[0].nSec = 0;
|
|
udAccel[0].nInc = 1;
|
|
udAccel[1].nSec = 2;
|
|
udAccel[1].nInc = nInc[id];
|
|
SendMessage( hwndScroll,
|
|
UDM_SETACCEL,
|
|
2,
|
|
(LPARAM)(LPUDACCEL)udAccel );
|
|
|
|
//
|
|
// Set the UD to update this control.
|
|
//
|
|
SendMessage( hwndScroll,
|
|
UDM_SETBUDDY,
|
|
(WPARAM)GET_WM_COMMAND_HWND(wParam,
|
|
lParam),
|
|
0 );
|
|
}
|
|
break;
|
|
}
|
|
case ( EN_KILLFOCUS ) :
|
|
{
|
|
//
|
|
// Gets in range HMS MDY.
|
|
//
|
|
UINT id = GET_WM_COMMAND_ID(wParam, lParam) - DATETIME_HOUR;
|
|
|
|
AdjustDelta(hDlg, id);
|
|
UpdateItem(hDlg, id);
|
|
|
|
//
|
|
// If control is YEAR.
|
|
//
|
|
if (id == (DATETIME_YEAR - DATETIME_HOUR))
|
|
{
|
|
InvalidateRect( GetDlgItem(hDlg, DATETIME_CALENDAR),
|
|
NULL,
|
|
TRUE );
|
|
}
|
|
|
|
break;
|
|
}
|
|
default :
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case ( DATETIME_MONTHNAME ) :
|
|
{
|
|
if (GET_WM_COMMAND_CMD(wParam, lParam) == CBN_SELCHANGE)
|
|
{
|
|
int nIndex = 1 + (int)ComboBox_GetCurSel(
|
|
GetDlgItem( hDlg,
|
|
DATETIME_MONTHNAME ));
|
|
|
|
if (wDateTime[MONTH] != nIndex)
|
|
{
|
|
AdjustDeltaMonth(nIndex);
|
|
InvalidateRect( GetDlgItem(hDlg, DATETIME_CALENDAR),
|
|
NULL,
|
|
TRUE );
|
|
PropSheet_Changed(GetParent(hDlg), hDlg);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case ( DATETIME_CALENDAR ) :
|
|
{
|
|
//
|
|
// If the calendar sent us a change, we will assume
|
|
// that it is to allow the apply now to work.
|
|
//
|
|
PropSheet_Changed(GetParent(hDlg), hDlg);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case ( WM_WININICHANGE ) :
|
|
{
|
|
//
|
|
// Reinitialize if there is a time format change.
|
|
//
|
|
InitDateTimeDlg(hDlg, uMsg, wParam, lParam);
|
|
InvalidateRect(GetDlgItem(hDlg, DATETIME_CALENDAR), NULL, TRUE);
|
|
break;
|
|
}
|
|
case ( WM_TIMECHANGE ) :
|
|
{
|
|
//
|
|
// Forward time change messages to the clock control.
|
|
//
|
|
SendDlgItemMessage( hDlg,
|
|
DATETIME_CLOCK,
|
|
WM_TIMECHANGE,
|
|
wParam,
|
|
lParam );
|
|
|
|
break;
|
|
}
|
|
|
|
case ( WMUSER_ADDINTERNETTAB ) :
|
|
{
|
|
AddInternetTab(hDlg);
|
|
break;
|
|
}
|
|
|
|
case ( WM_HELP ) : // F1
|
|
{
|
|
WinHelp( (HWND)((LPHELPINFO)lParam)->hItemHandle,
|
|
NULL,
|
|
HELP_WM_HELP,
|
|
(DWORD_PTR)(LPTSTR)aDateTimeHelpIds );
|
|
break;
|
|
}
|
|
case ( WM_CONTEXTMENU ) : // right mouse click
|
|
{
|
|
WinHelp( (HWND)wParam,
|
|
NULL,
|
|
HELP_CONTEXTMENU,
|
|
(DWORD_PTR)(LPTSTR)aDateTimeHelpIds );
|
|
break;
|
|
}
|
|
default :
|
|
{
|
|
return (FALSE);
|
|
}
|
|
}
|
|
return (TRUE);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// SetZoneState
|
|
//
|
|
// Sets the display state of a time zone in the map control.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
void SetZoneState(
|
|
HWND map,
|
|
PTZINFO zone,
|
|
BOOL highlight)
|
|
{
|
|
if (zone)
|
|
{
|
|
if (zone->SeaIndex >= 0)
|
|
{
|
|
MapControlSetSeaRegionHighlight( map,
|
|
zone->SeaIndex,
|
|
highlight,
|
|
zone->MapLeft,
|
|
zone->MapWidth );
|
|
}
|
|
|
|
if (zone->LandIndex >= 0)
|
|
{
|
|
MapControlSetLandRegionHighlight( map,
|
|
zone->LandIndex,
|
|
highlight,
|
|
zone->MapLeft,
|
|
zone->MapWidth );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// SetZoneFamilyState
|
|
//
|
|
// Sets the display state of a time zone family in the map control.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
void SetZoneFamilyState(
|
|
HWND map,
|
|
PTZINFO family,
|
|
BOOL highlight)
|
|
{
|
|
if (family)
|
|
{
|
|
PTZINFO zone = family;
|
|
|
|
do
|
|
{
|
|
SetZoneState(map, zone, highlight);
|
|
zone = zone->next;
|
|
}
|
|
while(zone && (zone != family));
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ParseMapInfo
|
|
//
|
|
// Parses the color table information about the world bitmap we display.
|
|
//
|
|
// Expected format: "sea,land"
|
|
// where sea and land are color table indices or -1.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
void ParseMapInfo(
|
|
PTZINFO zone,
|
|
const TCHAR *text)
|
|
{
|
|
const TCHAR *p = text;
|
|
|
|
zone->SeaIndex = zone->LandIndex = -1;
|
|
|
|
if (*p)
|
|
{
|
|
if (*p != TEXT('-'))
|
|
{
|
|
zone->SeaIndex = 0;
|
|
|
|
while (*p && (*p != TEXT(',')))
|
|
{
|
|
zone->SeaIndex = (10 * zone->SeaIndex) + (*p - TEXT('0'));
|
|
p++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
do
|
|
{
|
|
p++;
|
|
} while (*p && (*p != TEXT(',')));
|
|
}
|
|
|
|
if (*p == TEXT(','))
|
|
{
|
|
p++;
|
|
}
|
|
|
|
if (*p)
|
|
{
|
|
if (*p != TEXT('-'))
|
|
{
|
|
zone->LandIndex = 0;
|
|
|
|
while (*p)
|
|
{
|
|
zone->LandIndex = (10 * zone->LandIndex) + (*p - TEXT('0'));
|
|
p++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ReadZoneData
|
|
//
|
|
// Reads the data for a time zone from the registry.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL ReadZoneData(
|
|
PTZINFO zone,
|
|
HKEY key,
|
|
LPCTSTR keyname)
|
|
{
|
|
TCHAR mapinfo[16];
|
|
DWORD len;
|
|
|
|
len = sizeof(zone->szDisplayName);
|
|
|
|
if (RegQueryValueEx( key,
|
|
c_szTZDisplayName,
|
|
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,
|
|
c_szTZStandardName,
|
|
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,
|
|
c_szTZDaylightName,
|
|
0,
|
|
NULL,
|
|
(LPBYTE)zone->szDaylightName,
|
|
&len ) != ERROR_SUCCESS)
|
|
{
|
|
return (FALSE);
|
|
}
|
|
|
|
len = sizeof(zone->Bias) +
|
|
sizeof(zone->StandardBias) +
|
|
sizeof(zone->DaylightBias) +
|
|
sizeof(zone->StandardDate) +
|
|
sizeof(zone->DaylightDate);
|
|
|
|
if (RegQueryValueEx( key,
|
|
c_szTZI,
|
|
0,
|
|
NULL,
|
|
(LPBYTE)&zone->Bias,
|
|
&len ) != ERROR_SUCCESS)
|
|
{
|
|
return (FALSE);
|
|
}
|
|
|
|
len = sizeof(mapinfo);
|
|
|
|
if (RegQueryValueEx( key,
|
|
c_szTZMapInfo,
|
|
0,
|
|
NULL,
|
|
(LPBYTE)mapinfo,
|
|
&len ) != ERROR_SUCCESS)
|
|
{
|
|
*mapinfo = TEXT('\0');
|
|
}
|
|
|
|
ParseMapInfo(zone, mapinfo);
|
|
|
|
//
|
|
// Generate phony MapLeft and MapRight until they show up in the
|
|
// registry.
|
|
//
|
|
zone->MapLeft = ((zone->Bias * ZONE_IMAGE_SCALE) / ZONE_BIAS_SCALE) +
|
|
ZONE_IMAGE_LEFT;
|
|
|
|
zone->MapWidth = ZONE_IMAGE_WIDTH;
|
|
|
|
return (TRUE);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// AddZoneToList
|
|
//
|
|
// Inserts a new time zone into a list, sorted by bias and then name.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
void AddZoneToList(
|
|
PTZINFO *list,
|
|
PTZINFO zone)
|
|
{
|
|
if (*list)
|
|
{
|
|
PTZINFO curr = NULL;
|
|
PTZINFO next = *list;
|
|
|
|
while (next && zone->Bias <= next->Bias)
|
|
{
|
|
if (zone->Bias == next->Bias)
|
|
{
|
|
if (CompareString( GetUserDefaultLCID(),
|
|
0,
|
|
zone->szDisplayName,
|
|
-1,
|
|
next->szDisplayName,
|
|
-1 ) == CSTR_LESS_THAN)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
curr = next;
|
|
next = curr->next;
|
|
}
|
|
|
|
zone->next = next;
|
|
|
|
if (curr)
|
|
{
|
|
curr->next = zone;
|
|
}
|
|
else
|
|
{
|
|
*list = zone;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*list = zone;
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FreeTimezoneList
|
|
//
|
|
// Frees all time zones in the passed list, setting the head to NULL.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
void FreeTimezoneList(
|
|
PTZINFO *list)
|
|
{
|
|
while (*list)
|
|
{
|
|
PTZINFO next = (*list)->next;
|
|
|
|
LocalFree((HANDLE)*list);
|
|
|
|
*list = next;
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ReadTimezones
|
|
//
|
|
// Reads the time zone information from the registry.
|
|
// Returns num read, -1 on failure.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
int ReadTimezones(
|
|
PTZINFO *list)
|
|
{
|
|
HKEY key = NULL;
|
|
int count = -1;
|
|
|
|
*list = NULL;
|
|
|
|
if (RegOpenKey( HKEY_LOCAL_MACHINE,
|
|
c_szTimeZones,
|
|
&key ) == ERROR_SUCCESS)
|
|
{
|
|
TCHAR 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))
|
|
{
|
|
zone = *list;
|
|
*list = NULL;
|
|
count = -1;
|
|
break;
|
|
}
|
|
|
|
zone->next = NULL;
|
|
|
|
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(list, zone);
|
|
zone = NULL;
|
|
count++;
|
|
}
|
|
|
|
RegCloseKey(subkey);
|
|
}
|
|
}
|
|
|
|
FreeTimezoneList(&zone);
|
|
RegCloseKey(key);
|
|
}
|
|
|
|
return (count);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// InitZoneMapping
|
|
//
|
|
// Initializes map and map lookup for a specific time zone.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
void InitZoneMapping(
|
|
PTZINFO *lookup,
|
|
PTZINFO list,
|
|
HWND map)
|
|
{
|
|
PTZINFO zone = list; // not needed but more readable
|
|
|
|
while (zone)
|
|
{
|
|
if (zone->SeaIndex >= 0)
|
|
{
|
|
lookup[zone->SeaIndex] = zone;
|
|
}
|
|
|
|
if (zone->LandIndex >= 0)
|
|
{
|
|
lookup[zone->LandIndex] = zone;
|
|
}
|
|
|
|
SetZoneState(map, zone, FALSE);
|
|
zone = zone->next;
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// BreakZonesIntoFamilies
|
|
//
|
|
// Breaks the passed list into many circular lists.
|
|
// Each list consists of all time zones with a particular bias.
|
|
// Assumes the passed list is sorted by bias.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
void BreakZonesIntoFamilies(
|
|
PTZINFO head)
|
|
{
|
|
PTZINFO subhead = NULL;
|
|
PTZINFO last = NULL;
|
|
PTZINFO zone = head;
|
|
|
|
while (zone)
|
|
{
|
|
subhead = zone;
|
|
|
|
do
|
|
{
|
|
last = zone;
|
|
zone = zone->next;
|
|
}
|
|
while (zone && (zone->Bias == subhead->Bias));
|
|
|
|
last->next = subhead;
|
|
}
|
|
|
|
//
|
|
// Merge -12 and +12 zones into a single group.
|
|
// Assumes populated registry and depends on sort order.
|
|
//
|
|
if ((subhead) &&
|
|
(subhead->Bias == BIAS_PLUS_12) &&
|
|
(head->Bias == BIAS_MINUS_12))
|
|
{
|
|
PTZINFO next = head;
|
|
|
|
do
|
|
{
|
|
zone = next;
|
|
next = zone->next;
|
|
}
|
|
while (next != head);
|
|
|
|
zone->next = subhead;
|
|
last->next = head;
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// InitTimezones
|
|
//
|
|
// Initializes time zone stuff, UI and otherwise.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL InitTimezones(
|
|
HWND page,
|
|
PTZINFO *lookup)
|
|
{
|
|
PTZINFO list = NULL;
|
|
|
|
if ((g_nTimeZones = ReadTimezones(&list)) >= 0)
|
|
{
|
|
HWND combo = GetDlgItem(page, IDD_TIMEZONES);
|
|
PTZINFO zone = list;
|
|
|
|
SetWindowRedraw(combo, FALSE);
|
|
|
|
while (zone)
|
|
{
|
|
int index = ComboBox_AddString(combo, zone->szDisplayName);
|
|
|
|
if (index < 0)
|
|
{
|
|
break;
|
|
}
|
|
zone->ComboIndex = index;
|
|
ComboBox_SetItemData(combo, index, (LPARAM)zone);
|
|
zone = zone->next;
|
|
}
|
|
|
|
SetWindowRedraw(combo, TRUE);
|
|
|
|
if (!zone)
|
|
{
|
|
InitZoneMapping(lookup, list, GetDlgItem(page, IDD_TIMEMAP));
|
|
BreakZonesIntoFamilies(list);
|
|
return (TRUE);
|
|
}
|
|
|
|
FreeTimezoneList(&list);
|
|
ComboBox_ResetContent(combo);
|
|
}
|
|
|
|
return (FALSE);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ChangeZone
|
|
//
|
|
// Updates the current zone, making sure new zone's family is highlighted.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
void ChangeZone(
|
|
HWND page,
|
|
TZPAGE_STATE *state,
|
|
PTZINFO zone)
|
|
{
|
|
if (zone || state->zone)
|
|
{
|
|
BOOL newfamily = (!zone || !state->zone ||
|
|
(zone->Bias != state->zone->Bias));
|
|
HWND map = GetDlgItem(page, IDD_TIMEMAP);
|
|
BOOL dayval = (zone && (zone->StandardDate.wMonth != 0));
|
|
|
|
if (newfamily && state->zone)
|
|
{
|
|
SetZoneFamilyState(map, state->zone, FALSE);
|
|
}
|
|
|
|
state->zone = zone;
|
|
|
|
if (newfamily && state->zone)
|
|
{
|
|
SetZoneFamilyState(map, state->zone, TRUE);
|
|
}
|
|
|
|
if (newfamily)
|
|
{
|
|
MapControlInvalidateDirtyRegions(map);
|
|
}
|
|
|
|
ShowWindow(GetDlgItem(page, IDD_AUTOMAGIC), (dayval != 0 ? SW_SHOW : SW_HIDE));
|
|
|
|
if (!state->initializing)
|
|
{
|
|
PropSheet_Changed(GetParent(page), page);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// HotTrackZone
|
|
//
|
|
// Updates the map highlighting and combo selection for a given map index.
|
|
// Expects to be called with dups.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
void HotTrackZone(
|
|
HWND page,
|
|
TZPAGE_STATE *state,
|
|
int index)
|
|
{
|
|
PTZINFO zone = state->lookup[index];
|
|
|
|
if (zone && (zone != state->zone))
|
|
{
|
|
ComboBox_SetCurSel( GetDlgItem(page, IDD_TIMEZONES),
|
|
(zone ? zone->ComboIndex : -1) );
|
|
ChangeZone(page, state, zone);
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CenterZone
|
|
//
|
|
// Updates the map highlighting and combo selection for a given map index.
|
|
// Expects to be called with dups.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
void CenterZone(
|
|
HWND page,
|
|
TZPAGE_STATE *state,
|
|
BOOL animate)
|
|
{
|
|
PTZINFO zone = state->zone;
|
|
|
|
if (zone)
|
|
{
|
|
HWND map = GetDlgItem(page, IDD_TIMEMAP);
|
|
|
|
MapControlRotateTo(map, zone->MapLeft + zone->MapWidth / 2, animate);
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// GetPTZ
|
|
//
|
|
// Returns the pointer for the iItem time zone.
|
|
// If iItem is -1 on entry, use the currently selected time zone.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
PTZINFO GetPTZ(
|
|
HWND hDlg,
|
|
int iItem)
|
|
{
|
|
HWND hCtl = GetDlgItem(hDlg, IDD_TIMEZONES);
|
|
|
|
if (iItem == -1)
|
|
{
|
|
iItem = (int)ComboBox_GetCurSel(hCtl);
|
|
}
|
|
|
|
if (iItem < 0)
|
|
{
|
|
return (NULL);
|
|
}
|
|
|
|
return ((PTZINFO)ComboBox_GetItemData(hCtl, iItem));
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// GetAllowLocalTimeChange
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
TCHAR c_szRegPathTZControl[] = REGSTR_PATH_TIMEZONE;
|
|
TCHAR c_szRegValDisableTZUpdate[] = REGSTR_VAL_TZNOAUTOTIME;
|
|
|
|
BOOL GetAllowLocalTimeChange()
|
|
{
|
|
//
|
|
// Assume allowed until we see a disallow flag.
|
|
//
|
|
BOOL result = TRUE;
|
|
HKEY key;
|
|
|
|
if (RegOpenKey( HKEY_LOCAL_MACHINE,
|
|
c_szRegPathTZControl,
|
|
&key ) == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// Assume no disallow flag until we see one.
|
|
//
|
|
DWORD value = 0;
|
|
long len = sizeof(value);
|
|
DWORD type;
|
|
|
|
if ((RegQueryValueEx( key,
|
|
c_szRegValDisableTZUpdate,
|
|
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);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// SetAllowLocalTimeChange
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
void SetAllowLocalTimeChange(
|
|
BOOL fAllow)
|
|
{
|
|
HKEY key = NULL;
|
|
|
|
if (fAllow)
|
|
{
|
|
//
|
|
// Remove the disallow flag from the registry if it exists.
|
|
//
|
|
if (RegOpenKey( HKEY_LOCAL_MACHINE,
|
|
c_szRegPathTZControl,
|
|
&key ) == ERROR_SUCCESS)
|
|
{
|
|
RegDeleteValue(key, c_szRegValDisableTZUpdate);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Add/set the nonzero disallow flag.
|
|
//
|
|
if (RegCreateKey( HKEY_LOCAL_MACHINE,
|
|
c_szRegPathTZControl,
|
|
&key ) == ERROR_SUCCESS)
|
|
{
|
|
DWORD value = 1;
|
|
|
|
RegSetValueEx( key,
|
|
(LPCTSTR)c_szRegValDisableTZUpdate,
|
|
0UL,
|
|
REG_DWORD,
|
|
(LPBYTE)&value,
|
|
sizeof(value) );
|
|
}
|
|
}
|
|
|
|
if (key)
|
|
{
|
|
RegCloseKey(key);
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// InitTimeZonePage
|
|
//
|
|
// This function initializes everything to do with the Time Zones.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL InitTimeZonePage(
|
|
HWND hDlg,
|
|
TZPAGE_STATE *state)
|
|
{
|
|
TIME_ZONE_INFORMATION tziCurrent;
|
|
DWORD dwTZID;
|
|
PTZINFO ptzi;
|
|
int j ,iCurrentTZ;
|
|
BOOL fForceSelection = FALSE;
|
|
TCHAR temp[TZNAME_SIZE];
|
|
TCHAR oldTzMapName[TZNAME_SIZE], newTzMapName[TZNAME_SIZE];
|
|
|
|
|
|
//
|
|
// Get the current time zone information.
|
|
//
|
|
dwTZID = GetTimeZoneInformation(&tziCurrent);
|
|
|
|
LoadString(g_hInst, IDS_ISRAELTIMEZONE, oldTzMapName, TZNAME_SIZE);
|
|
LoadString(g_hInst, IDS_JERUSALEMTIMEZONE, newTzMapName, TZNAME_SIZE);
|
|
|
|
// this is a hack for Win95 or WinNT 4 to Win98/Win2k migration. "Israel" became "Jerusalem"
|
|
#ifdef UNICODE
|
|
if (!lstrcmpi(oldTzMapName, tziCurrent.StandardName))
|
|
{
|
|
lstrcpy(tziCurrent.StandardName, newTzMapName);
|
|
fForceSelection = TRUE;
|
|
}
|
|
#else
|
|
if (!AnsiWideStrCmpI(oldTzMapName, tziCurrent.StandardName))
|
|
{
|
|
StrToWideStr(tziCurrent.StandardName, newTzMapName);
|
|
fForceSelection = TRUE;
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Check for bogus time zone info.
|
|
//
|
|
if (dwTZID != TIME_ZONE_ID_INVALID)
|
|
{
|
|
//
|
|
// Copy the name out so we can check for first boot.
|
|
//
|
|
#ifdef UNICODE
|
|
lstrcpy(temp, tziCurrent.StandardName);
|
|
#else
|
|
WideStrToStr(temp, tziCurrent.StandardName);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Treat bogus time zones like first boot.
|
|
//
|
|
lstrcpy(temp, c_szFirstBootTZ);
|
|
}
|
|
|
|
if (lstrcmpi(temp, c_szFirstBootTZ) == 0)
|
|
{
|
|
//
|
|
// The 'default' value of the time zone key specifies the
|
|
// default zone.
|
|
//
|
|
TCHAR szDefaultName[TZNAME_SIZE];
|
|
LONG len = sizeof(szDefaultName);
|
|
|
|
if (RegQueryValue( HKEY_LOCAL_MACHINE,
|
|
c_szTimeZones,
|
|
szDefaultName,
|
|
&len ) == ERROR_SUCCESS)
|
|
{
|
|
#ifdef UNICODE
|
|
lstrcpy(tziCurrent.StandardName, szDefaultName);
|
|
#else
|
|
StrToWideStr(tziCurrent.StandardName, szDefaultName);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
tziCurrent.StandardName[0] = 0;
|
|
}
|
|
|
|
//
|
|
// If we can't find it by name, use GMT.
|
|
//
|
|
tziCurrent.StandardBias = tziCurrent.DaylightBias = tziCurrent.Bias = 0;
|
|
|
|
//
|
|
// Force the user to make a valid choice before quitting.
|
|
//
|
|
fForceSelection = TRUE;
|
|
}
|
|
|
|
//
|
|
// Get the Time Zones from the registry.
|
|
//
|
|
InitTimezones(hDlg, state->lookup);
|
|
|
|
//
|
|
// Try to select the 'current' one or some equivalent.
|
|
//
|
|
|
|
//
|
|
// Start with an invalid index.
|
|
//
|
|
iCurrentTZ = g_nTimeZones;
|
|
|
|
//
|
|
// Try to find by name.
|
|
//
|
|
for (j = 0; j < g_nTimeZones; j++)
|
|
{
|
|
ptzi = GetPTZ(hDlg, j);
|
|
|
|
#ifdef UNICODE
|
|
if (!lstrcmpi(ptzi->szStandardName, tziCurrent.StandardName))
|
|
#else
|
|
if (!AnsiWideStrCmpI(ptzi->szStandardName, tziCurrent.StandardName))
|
|
#endif
|
|
{
|
|
iCurrentTZ = j;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If it hasn't been found yet, try to find a nearby zone using biases.
|
|
//
|
|
if (iCurrentTZ == g_nTimeZones)
|
|
{
|
|
int nBestHitCount = TZ_HIT_NONE;
|
|
|
|
for (j = 0; j < g_nTimeZones; j++)
|
|
{
|
|
ptzi = GetPTZ(hDlg, j);
|
|
|
|
if (ptzi->Bias == tziCurrent.Bias)
|
|
{
|
|
int nHitCount = TZ_HIT_BASE +
|
|
((ptzi->StandardBias == tziCurrent.StandardBias) +
|
|
(ptzi->DaylightBias == tziCurrent.DaylightBias));
|
|
|
|
if (nHitCount > nBestHitCount)
|
|
{
|
|
nBestHitCount = nHitCount;
|
|
iCurrentTZ = j;
|
|
|
|
if (nHitCount >= TZ_HIT_EXACT)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Still didn't find it?
|
|
//
|
|
if (iCurrentTZ == g_nTimeZones)
|
|
{
|
|
//
|
|
// Punt.
|
|
//
|
|
iCurrentTZ = 0;
|
|
|
|
fForceSelection = TRUE;
|
|
}
|
|
|
|
//
|
|
// Set up the dialog using this time zone's info.
|
|
//
|
|
|
|
//
|
|
// Always use our rules for the allow-daylight muck.
|
|
//
|
|
#ifndef WINNT
|
|
if ((ptzi = GetPTZ(hDlg, iCurrentTZ)) != NULL)
|
|
{
|
|
tziCurrent.StandardDate = ptzi->StandardDate;
|
|
tziCurrent.DaylightDate = ptzi->DaylightDate;
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// If wMonth is 0, then this Time Zone does not support DST.
|
|
//
|
|
if ((tziCurrent.StandardDate.wMonth == 0) ||
|
|
(tziCurrent.DaylightDate.wMonth == 0))
|
|
{
|
|
ShowWindow(GetDlgItem(hDlg, IDD_AUTOMAGIC), SW_HIDE);
|
|
}
|
|
|
|
//
|
|
// Always get "allow DLT" flag even if this zone is disabled.
|
|
//
|
|
CheckDlgButton(hDlg, IDD_AUTOMAGIC, GetAllowLocalTimeChange());
|
|
|
|
ComboBox_SetCurSel(GetDlgItem(hDlg, IDD_TIMEZONES), iCurrentTZ);
|
|
|
|
ChangeZone(hDlg, state, GetPTZ(hDlg, -1));
|
|
CenterZone(hDlg, state, FALSE);
|
|
|
|
if (fForceSelection || g_bFirstBoot)
|
|
{
|
|
PropSheet_Changed(GetParent(hDlg), hDlg);
|
|
PropSheet_CancelToClose(GetParent(hDlg));
|
|
}
|
|
|
|
return (TRUE);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// SetTheTimezone
|
|
//
|
|
// Apply the User's time zone selection.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
void SetTheTimezone(
|
|
BOOL bAutoMagicTimeChange,
|
|
BOOL bAutoMagicEnabled,
|
|
PTZINFO ptzi)
|
|
{
|
|
TIME_ZONE_INFORMATION tzi;
|
|
HCURSOR hCurOld;
|
|
|
|
if (!ptzi)
|
|
{
|
|
return;
|
|
}
|
|
|
|
tzi.Bias = ptzi->Bias;
|
|
|
|
#ifdef WINNT
|
|
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;
|
|
|
|
#ifdef UNICODE
|
|
lstrcpy(tzi.StandardName, ptzi->szStandardName);
|
|
lstrcpy(tzi.DaylightName, ptzi->szStandardName);
|
|
#else
|
|
StrToWideStr(tzi.StandardName, ptzi->szStandardName);
|
|
StrToWideStr(tzi.DaylightName, ptzi->szStandardName);
|
|
#endif
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
//
|
|
// Automatically adjust for Daylight Saving Time.
|
|
//
|
|
tzi.StandardBias = ptzi->StandardBias;
|
|
tzi.DaylightBias = ptzi->DaylightBias;
|
|
tzi.StandardDate = ptzi->StandardDate;
|
|
tzi.DaylightDate = ptzi->DaylightDate;
|
|
|
|
#ifdef UNICODE
|
|
lstrcpy(tzi.StandardName, ptzi->szStandardName);
|
|
lstrcpy(tzi.DaylightName, ptzi->szDaylightName);
|
|
#else
|
|
StrToWideStr(tzi.StandardName, ptzi->szStandardName);
|
|
StrToWideStr(tzi.DaylightName, ptzi->szDaylightName);
|
|
#endif
|
|
}
|
|
|
|
SetAllowLocalTimeChange(bAutoMagicTimeChange);
|
|
|
|
SetTimeZoneInformation(&tzi);
|
|
|
|
hCurOld = SetCursor(LoadCursor(NULL, IDC_WAIT));
|
|
|
|
SetCursor(hCurOld);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// TimeZoneDlgProc
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
INT_PTR CALLBACK TimeZoneDlgProc(
|
|
HWND hDlg,
|
|
UINT uMsg,
|
|
WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
TZPAGE_STATE *state = (TZPAGE_STATE *)GetWindowLongPtr(hDlg, DWLP_USER);
|
|
|
|
int i;
|
|
|
|
switch (uMsg)
|
|
{
|
|
case ( WM_INITDIALOG ) :
|
|
{
|
|
state = (TZPAGE_STATE *)LocalAlloc(LPTR, sizeof(TZPAGE_STATE));
|
|
|
|
SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR)state);
|
|
|
|
if (!state)
|
|
{
|
|
EndDialog(hDlg, -1);
|
|
break;
|
|
}
|
|
|
|
state->initializing = TRUE;
|
|
InitTimeZonePage(hDlg, state);
|
|
state->initializing = FALSE;
|
|
|
|
break;
|
|
}
|
|
case ( WM_DESTROY ) :
|
|
{
|
|
for (i = 0; i < g_nTimeZones; i++)
|
|
{
|
|
LocalFree((HLOCAL)GetPTZ(hDlg, i));
|
|
}
|
|
|
|
if (state)
|
|
{
|
|
LocalFree((HANDLE)state);
|
|
SetWindowLongPtr(hDlg, DWLP_USER, 0L);
|
|
}
|
|
break;
|
|
}
|
|
case ( WM_NOTIFY ) :
|
|
{
|
|
switch (((NMHDR *)lParam)->idFrom)
|
|
{
|
|
case ( 0 ) :
|
|
{
|
|
switch (((NMHDR *)lParam)->code)
|
|
{
|
|
case ( PSN_APPLY ) :
|
|
{
|
|
g_ptziCurrent = NULL;
|
|
|
|
//
|
|
// Find out which listbox item was selected.
|
|
//
|
|
SetTheTimezone(
|
|
IsDlgButtonChecked(hDlg, IDD_AUTOMAGIC),
|
|
IsWindowVisible(GetDlgItem(hDlg, IDD_AUTOMAGIC)),
|
|
GetPTZ(hDlg, -1) );
|
|
|
|
//
|
|
// if the user had modified the time as well as the timezone,
|
|
// then we should honor the time that they gave us since they
|
|
// explicitly said this was the time. If we don't then the
|
|
// time they entered will be offset by the timezone change
|
|
//
|
|
|
|
if (g_WasModified)
|
|
{
|
|
g_WasModified = FALSE;
|
|
SetTime();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case ( IDD_TIMEMAP ) :
|
|
{
|
|
NFYMAPEVENT *event = (NFYMAPEVENT *)lParam;
|
|
|
|
switch (event->hdr.code)
|
|
{
|
|
case ( MAPN_TOUCH ) :
|
|
{
|
|
HotTrackZone(hDlg, state, event->index);
|
|
break;
|
|
}
|
|
case ( MAPN_SELECT ) :
|
|
{
|
|
CenterZone(hDlg, state, TRUE);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case ( WM_COMMAND ) :
|
|
{
|
|
switch (GET_WM_COMMAND_ID(wParam, lParam))
|
|
{
|
|
case ( IDD_TIMEZONES ) : // combo box
|
|
{
|
|
if (GET_WM_COMMAND_CMD(wParam, lParam) == CBN_SELCHANGE)
|
|
{
|
|
ChangeZone(hDlg, state, GetPTZ(hDlg, -1));
|
|
CenterZone(hDlg, state, TRUE);
|
|
}
|
|
break;
|
|
}
|
|
case ( IDD_AUTOMAGIC ) : // check box
|
|
{
|
|
if (GET_WM_COMMAND_CMD(wParam, lParam) == BN_CLICKED)
|
|
{
|
|
PropSheet_Changed(GetParent(hDlg), hDlg);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case ( WM_HELP ) : // F1
|
|
{
|
|
WinHelp( (HWND)((LPHELPINFO)lParam)->hItemHandle,
|
|
NULL,
|
|
HELP_WM_HELP,
|
|
(DWORD_PTR)(LPTSTR)aDateTimeHelpIds );
|
|
break;
|
|
}
|
|
case ( WM_CONTEXTMENU ) : // right mouse click
|
|
{
|
|
WinHelp( (HWND)wParam,
|
|
NULL,
|
|
HELP_CONTEXTMENU,
|
|
(DWORD_PTR)(LPTSTR)aDateTimeHelpIds );
|
|
break;
|
|
}
|
|
default :
|
|
{
|
|
return (FALSE);
|
|
}
|
|
}
|
|
|
|
return (TRUE);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// GetClInt
|
|
//
|
|
// Steal an int from the command line.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
static int GetClInt(
|
|
const TCHAR *p)
|
|
{
|
|
BOOL neg = FALSE;
|
|
int v = 0;
|
|
|
|
//
|
|
// Skip spaces.
|
|
//
|
|
while (*p == TEXT(' '))
|
|
{
|
|
p++;
|
|
}
|
|
|
|
//
|
|
// See if it's negative.
|
|
//
|
|
if (*p == TEXT('-'))
|
|
{
|
|
//
|
|
// It's negative. Remember that it's negative and skip the
|
|
// '-' char.
|
|
//
|
|
neg = TRUE;
|
|
p++;
|
|
}
|
|
|
|
//
|
|
// Parse the absolute portion. Digits only.
|
|
//
|
|
while ((*p >= TEXT('0')) && (*p <= TEXT('9')))
|
|
{
|
|
//
|
|
// Accumulate the value.
|
|
//
|
|
v = v * 10 + *p++ - TEXT('0');
|
|
}
|
|
|
|
//
|
|
// Return the result.
|
|
//
|
|
return (neg ? -v : v);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// SelectZoneByName
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL SelectZoneByName(
|
|
LPCTSTR cmdline)
|
|
{
|
|
BOOL result = FALSE;
|
|
HKEY key = NULL;
|
|
|
|
while (*cmdline == TEXT(' '))
|
|
{
|
|
cmdline++;
|
|
}
|
|
|
|
if (!*cmdline)
|
|
{
|
|
return (FALSE);
|
|
}
|
|
|
|
if (RegOpenKey( HKEY_LOCAL_MACHINE,
|
|
c_szTimeZones,
|
|
&key ) == ERROR_SUCCESS)
|
|
{
|
|
TCHAR name[TZNAME_SIZE];
|
|
HKEY subkey = NULL;
|
|
TZINFO zone;
|
|
|
|
//
|
|
// User can pass key name.
|
|
//
|
|
if (RegOpenKey(key, cmdline, &subkey) == ERROR_SUCCESS)
|
|
{
|
|
if (ReadZoneData(&zone, subkey, cmdline))
|
|
{
|
|
result = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// User can also pass display name.
|
|
//
|
|
int i;
|
|
int CmdLen = lstrlen(cmdline);
|
|
|
|
for (i = 0;
|
|
RegEnumKey(key, i, name, TZNAME_SIZE) == ERROR_SUCCESS;
|
|
i++)
|
|
{
|
|
if (RegOpenKey(key, name, &subkey) == ERROR_SUCCESS)
|
|
{
|
|
LONG len = sizeof(zone.szDisplayName);
|
|
|
|
if ((RegQueryValueEx( subkey,
|
|
c_szTZDisplayName,
|
|
0,
|
|
NULL,
|
|
(LPBYTE)&zone.szDisplayName,
|
|
&len ) == ERROR_SUCCESS) &&
|
|
(CompareString( GetUserDefaultLCID(),
|
|
NORM_IGNORECASE | NORM_IGNOREKANATYPE |
|
|
NORM_IGNOREWIDTH | NORM_IGNORENONSPACE,
|
|
zone.szDisplayName,
|
|
(CmdLen < 15)
|
|
? -1
|
|
: min(lstrlen(zone.szDisplayName),
|
|
CmdLen),
|
|
cmdline,
|
|
-1 ) == CSTR_EQUAL))
|
|
{
|
|
if (ReadZoneData(&zone, subkey, name))
|
|
{
|
|
result = TRUE;
|
|
}
|
|
}
|
|
|
|
RegCloseKey(subkey);
|
|
}
|
|
|
|
if (result)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
RegCloseKey(key);
|
|
|
|
if (result)
|
|
{
|
|
SetTheTimezone(1, 1, &zone);
|
|
}
|
|
}
|
|
|
|
return (result);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// OpenDateTimePropertySheet
|
|
//
|
|
// Opens a DateTime property sheet.
|
|
// Set the page for the property sheet.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL OpenDateTimePropertySheet(
|
|
HWND hwnd,
|
|
LPCTSTR cmdline)
|
|
{
|
|
// Make this an array for multiple pages.
|
|
PROPSHEETPAGE apsp[3];
|
|
PROPSHEETHEADER psh;
|
|
HDC hDC;
|
|
HFONT hFont;
|
|
int wMaxDigitWidth;
|
|
BOOL fReturn;
|
|
HRESULT hrOle;
|
|
|
|
hDC = GetDC(hwnd);
|
|
|
|
wMaxDigitWidth = GetMaxSubstitutedCharWidth(hDC);
|
|
ReleaseDC(hwnd, hDC);
|
|
|
|
psh.nStartPage = (UINT)-1;
|
|
|
|
if (cmdline && *cmdline)
|
|
{
|
|
if (*cmdline == TEXT('/'))
|
|
{
|
|
BOOL fAutoSet = FALSE;
|
|
|
|
//
|
|
// Legend:
|
|
// zZ: first boot batch mode setup "/z pacific" etc
|
|
// fF: regular first boot
|
|
// mM: time zone change forced local time change message
|
|
//
|
|
switch (*++cmdline)
|
|
{
|
|
case ( TEXT('z') ) :
|
|
case ( TEXT('Z') ) :
|
|
{
|
|
fAutoSet = TRUE;
|
|
|
|
//
|
|
// Fall thru...
|
|
//
|
|
}
|
|
case ( TEXT('f') ) :
|
|
case ( TEXT('F') ) :
|
|
{
|
|
g_bFirstBoot = TRUE;
|
|
|
|
if (fAutoSet && SelectZoneByName(cmdline + 1))
|
|
{
|
|
return (TRUE);
|
|
}
|
|
|
|
//
|
|
// Start on time zone page.
|
|
//
|
|
psh.nStartPage = 1;
|
|
break;
|
|
}
|
|
case ( TEXT('m') ) :
|
|
case ( TEXT('M') ) :
|
|
{
|
|
MSGBOXPARAMS params =
|
|
{
|
|
sizeof(params),
|
|
hwnd,
|
|
g_hInst,
|
|
MAKEINTRESOURCE(IDS_WARNAUTOTIMECHANGE),
|
|
MAKEINTRESOURCE(IDS_WATC_CAPTION),
|
|
MB_OK | MB_USERICON,
|
|
MAKEINTRESOURCE(IDI_TIMEDATE),
|
|
0,
|
|
NULL,
|
|
0
|
|
};
|
|
|
|
MessageBoxIndirect(¶ms);
|
|
|
|
//
|
|
// Show time/date page for user to verify.
|
|
//
|
|
psh.nStartPage = 0;
|
|
|
|
break;
|
|
}
|
|
default :
|
|
{
|
|
//
|
|
// Fall out, maybe it's a number...
|
|
//
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (psh.nStartPage == (UINT)-1)
|
|
{
|
|
if (cmdline && (*cmdline >= TEXT('0')) && (*cmdline <= TEXT('9')))
|
|
{
|
|
psh.nStartPage = GetClInt(cmdline);
|
|
}
|
|
else
|
|
{
|
|
psh.nStartPage = 0;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Register our classes.
|
|
//
|
|
ClockInit(g_hInst);
|
|
CalendarInit(g_hInst);
|
|
RegisterMapControlStuff(g_hInst);
|
|
|
|
psh.dwSize = sizeof(psh);
|
|
if (g_bFirstBoot)
|
|
{
|
|
//
|
|
// Disable Apply button for first boot.
|
|
//
|
|
psh.dwFlags = PSH_PROPTITLE | PSH_PROPSHEETPAGE | PSH_NOAPPLYNOW;
|
|
}
|
|
else
|
|
{
|
|
psh.dwFlags = PSH_PROPTITLE | PSH_PROPSHEETPAGE;
|
|
}
|
|
psh.hwndParent = hwnd;
|
|
psh.hInstance = g_hInst;
|
|
psh.pszIcon = NULL;
|
|
|
|
//
|
|
// psh.nStartPage is set above.
|
|
//
|
|
psh.pszCaption = MAKEINTRESOURCE(IDS_TIMEDATE);
|
|
psh.nPages = 2;
|
|
psh.ppsp = apsp;
|
|
|
|
apsp[0].dwSize = sizeof(PROPSHEETPAGE);
|
|
apsp[0].dwFlags = PSP_DEFAULT;
|
|
apsp[0].hInstance = g_hInst;
|
|
apsp[0].pszTemplate = wMaxDigitWidth > 8 ? MAKEINTRESOURCE(DLG_DATETIMEWIDE) : MAKEINTRESOURCE(DLG_DATETIME);
|
|
apsp[0].pfnDlgProc = DateTimeDlgProc;
|
|
apsp[0].lParam = 0;
|
|
|
|
apsp[1].dwSize = sizeof(PROPSHEETPAGE);
|
|
apsp[1].dwFlags = PSP_DEFAULT;
|
|
apsp[1].hInstance = g_hInst;
|
|
apsp[1].pszTemplate = MAKEINTRESOURCE(DLG_TIMEZONE);
|
|
apsp[1].pfnDlgProc = TimeZoneDlgProc;
|
|
apsp[1].lParam = 0;
|
|
|
|
if (psh.nStartPage >= psh.nPages)
|
|
{
|
|
psh.nStartPage = 0;
|
|
}
|
|
|
|
// We use the HyperLink control and that requires OLE (for IAccessible)
|
|
hrOle = CoInitialize(0);
|
|
|
|
fReturn = (BOOL)PropertySheet(&psh);
|
|
if (SUCCEEDED(hrOle))
|
|
{
|
|
CoUninitialize();
|
|
}
|
|
|
|
return fReturn;
|
|
}
|