📄 dst.cpp
字号:
// returning from this function causes DST_Init to reset all of our events
// so we need to turn everything off
CeRunAppAtEvent(DSTTIMEZONENOTIFICATION, NOTIFICATION_EVENT_NONE);
CeRunAppAtEvent(DSTTIMENOTIFICATION, NOTIFICATION_EVENT_NONE);
CeRunAppAtTime(DSTNOTIFICATION, 0);
// and ditch the handles, except for shutdown event - keep that
for (int i = 1; i < NUMDSTEVENTS; i++)
{
if (NULL != DST_handles[i])
{
CloseHandle(DST_handles[i]);
DST_handles[i] = NULL;
}
}
switch (dwEvent - WAIT_OBJECT_0)
{
case SHUTDOWNEVENT :
DEBUGMSG(ZONE_INIT, (_T("[TIMESVC DST] Shutting down DST system\r\n")));
return FALSE;
case TZCHANGEEVENT :
case TIMECHANGEEVENT :
{
// need to redetermine whether we are in daylight or standard time
DEBUGMSG(ZONE_DST, (_T("[TIMESVC DST] Resetting DST event due to Time, Date, or TZ change\r\n")));
SetDaylightOrStandardTimeDST(NULL);
}
break;
case DSTCHANGEEVENT :
{
if (DST_Auto())
{
// stOld contains the current system time (NOT the one before the update)
// stNew contains new system time if we have to add or subtract 1 hour
// to process DST/STD time change.
SYSTEMTIME stOld, stNew;
LONGLONG llOld, llNew;
GetLocalTime(&stOld);
SystemTimeToFileTime(&stOld, (FILETIME *)&llOld);
/*
Check the time zone information. It's possible that this information has
changed since the GetTimeZoneInformation call in DST_SetEvent, and
this action needs to be based on the current timezone.
*/
TIME_ZONE_INFORMATION tzi = {0};
GetTimeZoneInformation(&tzi);
LONGLONG llStandard = 0, llDaylight = 0;
//fix up the date structs if necessary
if (0 == tzi.StandardDate.wYear)
DST_DetermineChangeDate(&tzi.StandardDate, TRUE);
if (0 == tzi.DaylightDate.wYear)
DST_DetermineChangeDate(&tzi.DaylightDate, TRUE);
//convert so we can do the math
VERIFY(SystemTimeToFileTime(&tzi.StandardDate, (FILETIME *)&llStandard));
VERIFY(SystemTimeToFileTime(&tzi.DaylightDate, (FILETIME *)&llDaylight));
if (((llOld-llDaylight >= 0) && (llOld-llDaylight < DST_TIME_THRESHHOLD)) ||
((llOld-llStandard >= 0) && (llOld-llStandard < DST_TIME_THRESHHOLD)))
{
// This indicates that it's less than 1 minute after the STD<->DST
// boundary. Always perform the flip after this conditional block.
}
else
{
// This indicates that we've had a DST event triggered without
// "naturally" crossing over the DST boundary. This can happen
// for instance if the original clock is set to 1/1/04 and the
// new time is set to 11/1/04. In this case, since TimeSVC had
// an event scheduled to go off sometime in 4/04 to handle this
// event, the event is handled presently.
// In this case, we *may* not need need to flip from DST<->STD.
// We may be in the same DST/Standard setting; i.e. on a system bootup
// where clock is default to 1/1/04, and new time is 11/1/04, in both cases
// we are in standard time and should not perform the calculations below.
// However, going from 1/1/04 to 6/1/04 will require a flip, since one is
// STD and other is DST
if ((llDaylight <= llStandard && llDaylight <= llOld && llOld <= llStandard)
|| (llDaylight > llStandard && (llDaylight <= llOld || llOld <= llStandard)))
{
// We are in day light time presently
if (TIME_ZONE_ID_DAYLIGHT == g_dwTime)
return TRUE; // no need to change
}
else {
// We are in standard time presently
if (TIME_ZONE_ID_STANDARD == g_dwTime)
return TRUE; // no need to change
}
}
/*
If we're going from Daylight to Standard, we need to move the
clock BACK by g_tzDSTBias (60 minutes usually). If we're going
from Standard to Daylight we need to move it forward even though
g_tzDSTBias is 0.
*/
if (TIME_ZONE_ID_DAYLIGHT == g_dwTime) // clock needs to go back - so we add (g_tzDSTBias is always negative)
{
llNew = llOld + (LONGLONG)((LONGLONG)tzi.DaylightBias * FILETIME_TO_MINUTES);
// now flip the time flag because we're just about to change
g_dwTime = TIME_ZONE_ID_STANDARD;
SetDaylightTime(FALSE);
}
else // clock needs to go forward - so we subtract (see above)
{
llNew = llOld - (LONGLONG)((LONGLONG)tzi.DaylightBias * FILETIME_TO_MINUTES);
// now flip the time flag because we're just about to change
g_dwTime = TIME_ZONE_ID_DAYLIGHT;
SetDaylightTime(TRUE);
}
FileTimeToSystemTime((FILETIME *)&llNew, &stNew);
DEBUGMSG(ZONE_DST, (L"[TIMESVC DST] TZ Change: Updating clock. Old Time =%d:%02d, New Time =%d:%02d\r\n",
stOld.wHour, stOld.wMinute, stNew.wHour, stNew.wMinute));
SetLocalTime(&stNew);
DST_ShowMessage ();
}
}
break;
default :
{
DEBUGMSG(ZONE_INIT, (_T("[TIMESVC DST] Shutting down DST system\r\n")));
return FALSE;
}
}
return TRUE;
}
/*++
Routine Description:
Determines if we should show a mesage for DST change
Arguments:
none
Return Value:
TRUE if we want to show a message
FALSE if we don't want to show a message
--*/
static BOOL DST_ShowMessage(void)
{
DWORD ret = 0;
HKEY hKey = NULL;
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, RK_CLOCK, 0, 0, &hKey))
{
DWORD dwSize = sizeof(DWORD);
RegQueryValueEx(hKey, RV_DSTUI, 0, NULL, (LPBYTE)&ret, &dwSize);
RegCloseKey(hKey);
}
#ifdef DEBUG
if (ret)
{
DEBUGMSG(ZONE_DST, ( _T("[TIMESVC DST] Show Message option for DST is on\r\n")));
}
else
{
DEBUGMSG(ZONE_DST, ( _T("[TIMESVC DST] Show Message option for DST is off\r\n")));
}
#endif //DEBUG
if (ret)
{
ret = FALSE;
TCHAR msg[MAX_DSTMSGLEN];
TCHAR title[MAX_DSTTITLELEN];
if (LoadString(g_hInst, IDS_DSTCHANGED, msg, MAX_DSTMSGLEN) &&
LoadString(g_hInst, IDS_DSTTIMEINFO, title, MAX_DSTTITLELEN))
{
HMODULE hCoreDll = LoadLibrary (L"coredll.dll");
if (hCoreDll)
{
tMessageBoxW pMessageBox = (tMessageBoxW)GetProcAddress(hCoreDll, L"MessageBoxW");
tGetForegroundWindow pGetForegroundWindow =(tGetForegroundWindow)GetProcAddress (hCoreDll, L"GetForegroundWindow");
if (pMessageBox && pGetForegroundWindow)
{
HANDLE hGweApiSetReady = OpenEvent(EVENT_ALL_ACCESS, FALSE, L"SYSTEM/GweApiSetReady");
if (hGweApiSetReady)
{
int fGweReady = (WAIT_OBJECT_0 == WaitForSingleObject (hGweApiSetReady, 30000));
CloseHandle (hGweApiSetReady);
if (fGweReady)
{
pMessageBox(pGetForegroundWindow(), msg, title, MB_OK);
ret = TRUE;
}
}
}
FreeLibrary (hCoreDll);
}
}
}
return (BOOL)ret;
}
// Determine first day of week [Sun-Sat] of the first day of the month.
WORD GetFirstWeekDayOfMonth(LPSYSTEMTIME pst) {
SYSTEMTIME st;
FILETIME ft;
memcpy(&st,pst,sizeof(st));
st.wDayOfWeek = 0;
st.wDay = 1;
// Convert to FILETIME and then back to SYSTEMTIME to get this information.
SystemTimeToFileTime(&st,&ft);
FileTimeToSystemTime(&ft,&st);
ASSERT((st.wDayOfWeek >= 0) && (st.wDayOfWeek <= 6));
return st.wDayOfWeek;
}
// Convert a SYSTEMITIME in the day-in-month format (ultimatly from
// TIME_ZONE_INFORMATION) into a real SYSTEMTIME that the system can process.
static BOOL DST_DetermineChangeDate(LPSYSTEMTIME pStTzChange, BOOL fThisYear)
{
LONGLONG llChangeDate = 0, llNow = 0;
SYSTEMTIME stAbsolute; // Conversion from pStTzChange
SYSTEMTIME stNow; // Current time
ASSERT((pStTzChange->wDay >= 1) && (pStTzChange->wDay <= 5));
memcpy(&stAbsolute,pStTzChange,sizeof(stAbsolute));
GetLocalTime(&stNow);
// build up the new structure
if (stAbsolute.wYear == 0) {
pStTzChange->wYear = stAbsolute.wYear = stNow.wYear;
}
// Day of week [Sun-Sat] the first day of week falls on
WORD wFirstDayInMonth = GetFirstWeekDayOfMonth(&stAbsolute);
// First day in month [1-7] that is on same day of week as timezone change
WORD wFirstDayTZChange;
// Determine the first date in this month that falls on the day of
// the week that the time zone change will happen on, eg
// first Monday in June 2006 would get wFirstDayTZChange=5.
if (wFirstDayInMonth > pStTzChange->wDayOfWeek)
wFirstDayTZChange = (1 + 7 -(wFirstDayInMonth - pStTzChange->wDayOfWeek));
else
wFirstDayTZChange = 1 + pStTzChange->wDayOfWeek - wFirstDayInMonth;
ASSERT((wFirstDayTZChange >= 1) && (wFirstDayTZChange <= 7));
stAbsolute.wDay = wFirstDayTZChange;
for (DWORD i = 1; i < pStTzChange->wDay; i++) {
FILETIME ftTemp;
// Increment the current week by one, and see if it's a legit date.
// SystemTimeToFileTime has all the logic to determine if the SystemTime
// is correct - if it's not in means we've "overshot" the intended date
// and need to pull back on. Consider for instance if the TZ Cutover
// was set to be 5th Thursday in July 2006. Eventually in this loop
// we would get to July 34th, which is bogus, so we'd need to pull
// back to July 27th.
stAbsolute.wDay += 7;
if (! SystemTimeToFileTime(&stAbsolute, &ftTemp)) {
// We overshot, pull back a week
stAbsolute.wDay -= 7;
break;
}
}
// Need to determine if the next occurrance of this date is THIS year or NEXT year
VERIFY(SystemTimeToFileTime(&stAbsolute, (FILETIME *)&llChangeDate));
VERIFY(SystemTimeToFileTime(&stNow, (FILETIME *)&llNow));
// In this case, the change-over date was calculated to be in the past.
// Sometimes this is what we want, othertimes (like when setting up an event
// to be fired in future) we need to re-perform this calculation so that we
// get a date in the future.
if (!fThisYear && (llChangeDate < llNow))
{
//need to redetermine the date for next year
pStTzChange->wYear++;
return DST_DetermineChangeDate(pStTzChange,TRUE);
}
memcpy(pStTzChange,&stAbsolute,sizeof(stAbsolute));
return TRUE;
}
/*++
Routine Description:
determines if the current locale supports DST based on
information in a TIME_ZONE_INFORMATION struct
Arguments:
pointer to a TIME_ZONE_INFORMATION struct
Return Value:
TRUE if the locale supports DST, FALSE otherwise
--*/
static BOOL LocaleSupportsDST(TIME_ZONE_INFORMATION *ptzi)
{
ASSERT(ptzi);
// If the month value is zero then this locale does not change for DST
// it should never be the case that we have a DST date but not a SDT date
ASSERT(((0 != ptzi->StandardDate.wMonth) && (0 != ptzi->DaylightDate.wMonth)) ||
((0 == ptzi->StandardDate.wMonth) && (0 == ptzi->DaylightDate.wMonth)));
if ((0 != ptzi->StandardDate.wMonth) && (0 != ptzi->DaylightDate.wMonth))
return TRUE;
else
return FALSE;
}
//
// Public interface section
//
int InitializeDST (HINSTANCE hInst) {
g_hInst = hInst;
g_hDSTShutdownEvent = CreateEvent (NULL, TRUE, TRUE, NULL);
return (g_hDSTShutdownEvent != NULL) ? ERROR_SUCCESS : ERROR_OUTOFMEMORY;
}
void DestroyDST (void) {
CloseHandle (g_hDSTShutdownEvent);
g_hDSTShutdownEvent = NULL;
g_hInst = NULL;
}
int RefreshDST (void) {
return ERROR_SUCCESS;
}
int StartDST (void) {
if (! g_hInst)
return ERROR_SERVICE_DOES_NOT_EXIST;
if (WaitForSingleObject (g_hDSTShutdownEvent, 0) == WAIT_TIMEOUT)
return ERROR_SERVICE_ALREADY_RUNNING;
ResetEvent (g_hDSTShutdownEvent);
g_hDSTThread = CreateThread (NULL, 0, DST_Init, NULL, 0, NULL);
if (g_hDSTThread == NULL) {
int iErr = GetLastError ();
SetEvent (g_hDSTShutdownEvent);
return iErr;
}
return ERROR_SUCCESS;
}
int StopDST (void) {
if (! g_hInst)
return ERROR_SERVICE_DOES_NOT_EXIST;
if (WaitForSingleObject (g_hDSTShutdownEvent, 0) == WAIT_OBJECT_0)
return ERROR_SERVICE_NOT_ACTIVE;
SetEvent (g_hDSTShutdownEvent);
WaitForSingleObject (g_hDSTThread, INFINITE);
CloseHandle (g_hDSTThread);
g_hDSTThread = NULL;
return ERROR_SUCCESS;
}
DWORD GetStateDST (void) {
if (! g_hInst)
return SERVICE_STATE_UNINITIALIZED;
if (WaitForSingleObject (g_hDSTShutdownEvent, 0) == WAIT_OBJECT_0)
return SERVICE_STATE_OFF;
return SERVICE_STATE_ON;
}
int ServiceControlDST (PBYTE pBufIn, DWORD dwLenIn, PBYTE pBufOut, DWORD dwLenOut, PDWORD pdwActualOut, int *pfProcessed) {
*pfProcessed = FALSE;
return ERROR_INVALID_PARAMETER;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -