⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dst.cpp

📁 Windows CE 6.0 Server 源码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft shared
// source or premium shared source license agreement under which you licensed
// this source code. If you did not accept the terms of the license agreement,
// you are not authorized to use this source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the SOURCE.RTF on your install media or the root of your tools installation.
// THE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
/*---------------------------------------------------------------------------*\
 *  module: dst.cpp
 *  purpose: DST support.  Need to handle the following 3 scenarios
 *          1)  DST turns on/off when system is running
 *          2)  DST turns on/off when system is suspended
 *          3)  DST turns on/off when system is powered off
 *
\*---------------------------------------------------------------------------*/

#include <windows.h>
#include <notify.h>
#include <service.h>

#include "../inc/timesvc.h"
#include "dst.h"
#include "dstrc.h"

//keep these consistant with names in public\wceshellfe\oak\ctlpnl\cplmain\regcpl.h
#define RK_CLOCK        TEXT("Software\\Microsoft\\Clock")
#define RV_INDST        TEXT("HomeDST")  //are we in DST?
#define RV_AUTODST      TEXT("AutoDST")  //do we auto-adjust DST?
#define RV_DSTUI        TEXT("ShowDSTUI")  //do we show a message at dst change?

#define DSTEVENT          _T("ShellDSTEvent")
#define DSTTZEVENT        _T("DSTTzChange")
#define DSTTIMEEVENT        _T("DSTTimeChange")

#define DSTNOTIFICATION   _T("\\\\.\\Notifications\\NamedEvents\\ShellDSTEvent")
#define DSTTIMEZONENOTIFICATION _T("\\\\.\\Notifications\\NamedEvents\\DSTTzChange")
#define DSTTIMENOTIFICATION _T("\\\\.\\Notifications\\NamedEvents\\DSTTimeChange")

#define NUMDSTEVENTS 4
#define SHUTDOWNEVENT 0
#define TZCHANGEEVENT 1
#define TIMECHANGEEVENT 2
#define DSTCHANGEEVENT 3 // This event must be last so WaitForMultipleObjects algorithm works (see DST_WaitForEvents)

#define MAX_DSTMSGLEN 256
#define MAX_DSTTITLELEN 64

// FILETIME (100-ns intervals) to minutes (10 x 1000 x 1000 x 60)
#define FILETIME_TO_MINUTES (10 * 1000 * 1000 * 60)


typedef int (*tMessageBoxW) (HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType);
typedef HWND (*tGetForegroundWindow) (VOID);

static DWORD g_dwTime = TIME_ZONE_ID_STANDARD;
static HINSTANCE g_hInst;
static HANDLE    g_hDSTThread;
static HANDLE    g_hDSTShutdownEvent;
static DWORD     g_dwDSTState;




// If the DSTCHANGEEVENT is fired within 1 minute on one of the DST boundaries
// (DST->STD or STD->DST) then always flip the system DST value on the system
// with a call to SetDaylightTime().  Otherwise assume that the event has fired
// because of a clock change (manual or SNTP server related) in which case we
// may or may not need to do this calculation.
#define DST_TIME_THRESHHOLD    (1 * FILETIME_TO_MINUTES)


//
//	Private DST code
//
/*++

    
Routine Description:
    Determines whether the current date and time is in daylight
    or standard time, and notifies the kernel.

    Kernel doesn't currently update this in all cases
    Manually take care of it to be safe and ensure that subsequent calls 
    to GetTimeZoneInformation return the correct value

    pNewSystemTime may be NULL to retrieve current system time, or may
    indicate time we're about to change to on clock update
    
Arguments:
    none
    
Return Value:
    current timezone value (same as return values for GetTimeZoneInformation
    
--*/
void  SetDaylightOrStandardTimeDST(SYSTEMTIME *pNewSystemTime)
{
    TIME_ZONE_INFORMATION tzi;
    DWORD dwTZ = GetTimeZoneInformation(&tzi);
   
    // If the system supports DST verify that the kernel returned the correct
    // value, otherwise make sure the kerel has us in SDT
    if (LocaleSupportsDST(&tzi))
    {
        // All times are in UTC time, not local time.  We need to convert to UTC
        // to avoid the case where after we roll-back the clock from 2AM->1AM, then
        // setting a local time of 1:05AM we couldn't tell whether we're in DST or STD.
        // We can compute this exactly by comparing against the UTC.
        SYSTEMTIME curTime;        
        LONGLONG  llStandard = 0, llDaylight = 0, llNow = 0;

        if (pNewSystemTime)
            memcpy(&curTime,pNewSystemTime,sizeof(SYSTEMTIME));
        else
            GetSystemTime(&curTime);

        //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));
        VERIFY(SystemTimeToFileTime(&curTime, (FILETIME *)&llNow));

        // TIME_ZONE_INFORMATION values need to be converted to UTC.  We convert
        // llStandard using the DaylightBias because llStandard is the time in
        // DST local clock where the DST->STD conversion is performed.
        llStandard = llStandard + (((ULONGLONG)(tzi.Bias+tzi.DaylightBias))*FILETIME_TO_MINUTES);
        llDaylight = llDaylight + (((ULONGLONG)(tzi.Bias))*FILETIME_TO_MINUTES);

        //the greater difference determines which zone we are in   
        if (DST_Auto() && ((llDaylight <= llStandard && llDaylight <= llNow && llNow <= llStandard) 
                        || (llDaylight > llStandard && (llDaylight <= llNow || llNow <= llStandard))))
        {
            DEBUGMSG(ZONE_DST, (_T("[TIMESVC DST]  Notifying kernel that we are in Daylight time.  GetTimeZoneInformation currently thinks we are in %s time.\r\n"), 
                     TIME_ZONE_ID_DAYLIGHT  == dwTZ ? _T("Daylight") : _T("Standard")));
            SetDaylightTime(TRUE);
            g_dwTime = TIME_ZONE_ID_DAYLIGHT;           
        }        
        else
        {
            DEBUGMSG(ZONE_DST, (_T("[TIMESVC DST]  Notifying kernel that we are in Standard time.  GetTimeZoneInformation currently thinks we are in %s time.\r\n"), 
                     TIME_ZONE_ID_DAYLIGHT  == dwTZ ? _T("Daylight") : _T("Standard")));
            SetDaylightTime(FALSE);
            g_dwTime = TIME_ZONE_ID_STANDARD;            
        }
    }
    else
    {
        ASSERT(TIME_ZONE_ID_STANDARD == dwTZ);
        if (TIME_ZONE_ID_STANDARD != dwTZ) {
            SetDaylightTime(FALSE);
        }
        g_dwTime = TIME_ZONE_ID_STANDARD;
    }
}


/*++
Routine Description:
    'main' function for DST.  Called from shell init, and re-entered from DST_WaitForEvent.
    
Arguments:
    none
    
Return Value:
    none
    
--*/
static DWORD WINAPI DST_Init(LPVOID lpUnused)
{
    DEBUGMSG(ZONE_INIT, (_T("[TIMESVC DST] System Started...\r\n")));

    // Clean up any existing events in the notification database
    CeRunAppAtEvent(DSTTIMEZONENOTIFICATION, NOTIFICATION_EVENT_NONE);
    CeRunAppAtEvent(DSTTIMENOTIFICATION, NOTIFICATION_EVENT_NONE);
    CeRunAppAtTime(DSTNOTIFICATION, 0);

    //need to know from the start if we are in standard or daylight time
    SetDaylightOrStandardTimeDST(NULL);
    for (;;)
    {
        HANDLE hDSTEvents[NUMDSTEVENTS];
        hDSTEvents[SHUTDOWNEVENT] = g_hDSTShutdownEvent;
        hDSTEvents[TZCHANGEEVENT] = DST_SetTimezoneChangeEvent();
        hDSTEvents[TIMECHANGEEVENT] = DST_SetTimeChangeEvent();
        hDSTEvents[DSTCHANGEEVENT] = DST_SetDSTEvent(); // This can be NULL if we are in a non-DST timezone

        if (NULL == hDSTEvents[TZCHANGEEVENT])
        {
            DEBUGCHK( _T("DST:  Failed to set TZ change Event"));
            break;
        }
        if (NULL == hDSTEvents[TIMECHANGEEVENT])
        {
            DEBUGCHK( _T("DST:  Failed to set Time change Event"));
            break;
        }

        if (! DST_WaitForEvents(hDSTEvents))
            break;
    } 

    DEBUGMSG(ZONE_INIT, (_T("[TIMESVC DST] Thread exited...\r\n")));
    return 0;
}    


/*++
Routine Description:
    Determines if we should auto-adjust for DST
    
Arguments:
    none
    
Return Value:
    TRUE if we want to auto adjust
    FALSE if we don't want to auto adjust
    
--*/
static BOOL  DST_Auto(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_AUTODST, 0, NULL, (LPBYTE)&ret, &dwSize);
        RegCloseKey(hKey);
    }
#ifdef DEBUG
    if (ret)
    {
        DEBUGMSG(ZONE_DST, ( _T("[TIMESVC DST]  Auto change for DST is on\r\n")));
    } 
    else
    {
        DEBUGMSG(ZONE_DST, ( _T("[TIMESVC DST]  Auto change for DST is off\r\n")));
    }
#endif //DEBUG

    return (BOOL)ret;
}



/*++

    
Routine Description:
    Sets Event to be notified when timezone changes
    
Arguments:
    none
    
Return Value:
    HANDLE to timezone event
    
--*/
static HANDLE DST_SetTimezoneChangeEvent(void)
{
    HANDLE hTZEvent = CreateEvent(NULL, FALSE, FALSE, DSTTZEVENT);
    if (hTZEvent)
    {
        if (!CeRunAppAtEvent(DSTTIMEZONENOTIFICATION,
                             NOTIFICATION_EVENT_TZ_CHANGE))
        {
            CloseHandle(hTZEvent);
            hTZEvent = NULL;
        }
    }
    return hTZEvent;
}

/*++

    
Routine Description:
    Sets Event to be notified when time changes
    
Arguments:
    none
    
Return Value:
    HANDLE to timezone event
    
--*/
static HANDLE DST_SetTimeChangeEvent(void)
{
    HANDLE hTimeEvent = CreateEvent(NULL, FALSE, FALSE, DSTTIMEEVENT);
    if (hTimeEvent)
    {
        if (!CeRunAppAtEvent(DSTTIMENOTIFICATION,
                             NOTIFICATION_EVENT_TIME_CHANGE))
        {
            CloseHandle(hTimeEvent);
            hTimeEvent = NULL;
        }
    }
    return hTimeEvent;
}


/*++
Routine Description:
    Sets the DST Event 
    
Arguments:
    none
    
Return Value:
    Handle to event to be triggered when daylight time turns on (or off)
    
--*/
static HANDLE DST_SetDSTEvent (void)
{
    HANDLE hEvent = NULL;
    BOOL bEvent = FALSE;
    TIME_ZONE_INFORMATION tzi = {0};
    SYSTEMTIME curTime, notificationTime;
    LONGLONG llNow = 0, llNotification = 0;

    DWORD dwTZ = GetTimeZoneInformation(&tzi);

    // Only create the event if the locale supports DST
    if (!LocaleSupportsDST(&tzi))
        return NULL;

    switch (g_dwTime)
    {
        case TIME_ZONE_ID_DAYLIGHT :
            DEBUGMSG(ZONE_DST, ( _T("[TIMESVC DST]  Currently in Daylight Time\r\n")));
            notificationTime = tzi.StandardDate;
        break;

        case TIME_ZONE_ID_STANDARD :
            DEBUGMSG(ZONE_DST, ( _T("[TIMESVC DST]  Currently in Standard Time\r\n")));
            notificationTime = tzi.DaylightDate;
        break;

        default :
            DEBUGMSG(ZONE_DST, (_T("[TIMESVC DST]  Unknown TimeZone\r\n")));
            ASSERT(TIME_ZONE_ID_UNKNOWN == dwTZ);    //otherwise GetTZInfo is busted
            return NULL;
    }

    if (0 == notificationTime.wYear) //no specific date set - do the math
        DST_DetermineChangeDate(&notificationTime);

    //only set events that are in the future
    VERIFY(SystemTimeToFileTime(&notificationTime, (FILETIME *)&llNotification));
    GetLocalTime(&curTime);
    VERIFY(SystemTimeToFileTime(&curTime, (FILETIME *)&llNow));
    if (llNotification > llNow)
    {
        hEvent = CreateEvent(NULL, FALSE, FALSE, DSTEVENT);
        if (hEvent != INVALID_HANDLE_VALUE)
        {
            if (!CeRunAppAtTime(DSTNOTIFICATION, &notificationTime))
            {
               CloseHandle(hEvent);
               hEvent = NULL;
            }
        }

        DEBUGMSG(ZONE_DST, (_T("[TIMESVC DST]  Set TimeChange Event for %d/%d/%02d at %d:%02d\r\n"), 
                 notificationTime.wMonth, notificationTime.wDay, notificationTime.wYear,
                 notificationTime.wHour, notificationTime.wMinute));
    }

    return hEvent;
}


/*++
Routine Description:
    waits for DST event to be signaled, and optionally re-sets the
    time as appropriate.
    
Arguments:
    hEvent - handle to DST event
    
Return Value:
    none
    
--*/
static int DST_WaitForEvents(LPHANDLE DST_handles)
{
    // The last event can be NULL if we so check before we give the number of handles
    DWORD dwEvent = WaitForMultipleObjects(DST_handles[NUMDSTEVENTS-1] ? NUMDSTEVENTS : NUMDSTEVENTS-1,
                                           DST_handles, FALSE, INFINITE);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -