同步世界标准时间

  1 // TimeDlg.cpp : implementation file
  2 
  3 #include "stdafx.h"
  4 #include "Time.h"
  5 #include "TimeDlg.h"
  6 
  7 #ifdef _DEBUG
  8 #define new DEBUG_NEW
  9 #undef THIS_FILE
 10 static char THIS_FILE[] = __FILE__;
 11 #endif
 12 
 13 /////////////////////////////////////////////////////////////////////////////
 14 #include <winsock2.h>
 15 #pragma comment(lib, "wsock32")
 16 #define     WM_SOCKET_NOTIFY (WM_USER + 11) 
 17 
 18 char   m_szIPAddr[32]={0};
 19 SOCKET m_sock;
 20 ULONG  m_ulTime ;
 21 
 22 
 23 class CAboutDlg : public CDialog
 24 {
 25 public:
 26     CAboutDlg();
 27 
 28 // Dialog Data
 29     //{{AFX_DATA(CAboutDlg)
 30     enum { IDD = IDD_ABOUTBOX };
 31     //}}AFX_DATA
 32 
 33     // ClassWizard generated virtual function overrides
 34     //{{AFX_VIRTUAL(CAboutDlg)
 35     protected:
 36     virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
 37     //}}AFX_VIRTUAL
 38 
 39 // Implementation
 40 protected:
 41     //{{AFX_MSG(CAboutDlg)
 42     //}}AFX_MSG
 43     DECLARE_MESSAGE_MAP()
 44 };
 45 
 46 CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
 47 {
 48     //{{AFX_DATA_INIT(CAboutDlg)
 49     //}}AFX_DATA_INIT
 50 }
 51 
 52 void CAboutDlg::DoDataExchange(CDataExchange* pDX)
 53 {
 54     CDialog::DoDataExchange(pDX);
 55     //{{AFX_DATA_MAP(CAboutDlg)
 56     //}}AFX_DATA_MAP
 57 }
 58 
 59 BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
 60     //{{AFX_MSG_MAP(CAboutDlg)
 61         // No message handlers
 62     //}}AFX_MSG_MAP
 63 END_MESSAGE_MAP()
 64 
 65 /////////////////////////////////////////////////////////////////////////////
 66 // CTimeDlg dialog
 67 
 68 CTimeDlg::CTimeDlg(CWnd* pParent /*=NULL*/)
 69     : CDialog(CTimeDlg::IDD, pParent)
 70 {
 71     //{{AFX_DATA_INIT(CTimeDlg)
 72     //}}AFX_DATA_INIT
 73     // Note that LoadIcon does not require a subsequent DestroyIcon in Win32
 74     m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
 75 }
 76 
 77 void CTimeDlg::DoDataExchange(CDataExchange* pDX)
 78 {
 79     CDialog::DoDataExchange(pDX);
 80     //{{AFX_DATA_MAP(CTimeDlg)
 81     DDX_Control(pDX, IDC_TEXTOUT, m_edit);
 82     DDX_Control(pDX, IDC_LIST1, m_list);
 83     //}}AFX_DATA_MAP
 84 }
 85 
 86 BEGIN_MESSAGE_MAP(CTimeDlg, CDialog)
 87     //{{AFX_MSG_MAP(CTimeDlg)
 88     ON_WM_SYSCOMMAND()
 89     ON_WM_PAINT()
 90     ON_WM_QUERYDRAGICON()
 91     ON_MESSAGE(WM_SOCKET_NOTIFY,OnSocketNotify)
 92     ON_WM_TIMER()
 93     ON_LBN_DBLCLK(IDC_LIST1, OnDblclkList1)
 94     ON_WM_CTLCOLOR()
 95     ON_BN_CLICKED(IDC_BUTTON1, OnButton1)
 96     ON_NOTIFY(NM_DBLCLK, IDC_LIST1, OnDblclkList1)
 97     ON_WM_LBUTTONDOWN()
 98     //}}AFX_MSG_MAP
 99 END_MESSAGE_MAP()
100 
101 /////////////////////////////////////////////////////////////////////////////
102 // CTimeDlg message handlers
103 
104 BOOL CTimeDlg::OnInitDialog()
105 {
106     CDialog::OnInitDialog();
107 
108     // Add "About..." menu item to system menu.
109 
110     // IDM_ABOUTBOX must be in the system command range.
111     ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
112     ASSERT(IDM_ABOUTBOX < 0xF000);
113 
114     CMenu* pSysMenu = GetSystemMenu(FALSE);
115     if (pSysMenu != NULL)
116     {
117         CString strAboutMenu;
118         strAboutMenu.LoadString(IDS_ABOUTBOX);
119         if (!strAboutMenu.IsEmpty())
120         {
121             pSysMenu->AppendMenu(MF_SEPARATOR);
122             pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
123         }
124     }
125 
126     // Set the icon for this dialog.  The framework does this automatically
127     //  when the application's main window is not a dialog
128     SetIcon(m_hIcon, TRUE);            // Set big icon
129     SetIcon(m_hIcon, FALSE);        // Set small icon
130     
131 
132     SetDlgItemText(IDC_TEXTOUT,"\r\n\r\n\r\n\r\n\t请选择右侧时间服务器\r\n\r\n\t然后鼠标单击校准时间\r\n\r\n\r\n");
133 
134 
135     m_list.SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);
136     m_list.InsertColumn(0,"时间服务器域名",LVCFMT_LEFT,150);
137     m_list.InsertColumn(1,"IP地址",LVCFMT_CENTER,120);
138 /*
139     m_list.InsertItem(0,"time-a.nist.gov");
140     m_list.InsertItem(1,"time-b.nist.gov");
141     m_list.InsertItem(2,"time-a.timefreq.bldrdoc.gov");
142     m_list.InsertItem(3,"time-b.timefreq.bldrdoc");
143     m_list.InsertItem(4,"time-c.timefreq.bldrdoc.gov");
144     m_list.InsertItem(5,"utcnist.colorado.edu");
145     m_list.InsertItem(6,"time.nist.gov");
146     m_list.InsertItem(7,"time-nw.nist.gov");
147     m_list.InsertItem(8,"nist1.datum.com");
148     m_list.InsertItem(9,"nist1-dc.glassey.com");
149     m_list.InsertItem(10,"nist1-ny.glassey.com");
150     m_list.InsertItem(11,"nist1-sj.glassey.com");
151     m_list.InsertItem(12,"nist1.aol-ca.truetime.com");
152     m_list.InsertItem(13,"nist1.aol-va.truetime.com");
153     m_list.SetItemText(0,1,"129.6.15.28");
154     m_list.SetItemText(1,1,"129.6.15.29");
155     m_list.SetItemText(2,1,"132.163.4.101");
156     m_list.SetItemText(3,1,"132.163.4.102");
157     m_list.SetItemText(4,1,"132.163.4.103");
158     m_list.SetItemText(5,1,"128.138.140.44");
159     m_list.SetItemText(6,1,"192.43.244.18");
160     m_list.SetItemText(7,1,"131.107.1.10");
161     m_list.SetItemText(8,1,"66.243.43.21");
162     m_list.SetItemText(9,1,"216.200.93.8");
163     m_list.SetItemText(10,1,"208.184.49.9");
164     m_list.SetItemText(11,1,"207.126.98.204");
165     m_list.SetItemText(12,1,"207.200.81.113");
166     m_list.SetItemText(13,1,"205.188.185.33");
167 */
168     m_list.InsertItem(0,"time-a.timefreq.bldrdoc.gov");
169     m_list.InsertItem(1,"time-c.timefreq.bldrdoc.gov");
170     m_list.SetItemText(0,1,"132.163.4.101");
171     m_list.SetItemText(1,1,"132.163.4.103");
172     
173 
174     return TRUE;  // return TRUE  unless you set the focus to a control
175 }
176 
177 void CTimeDlg::OnSysCommand(UINT nID, LPARAM lParam)
178 {
179     if ((nID & 0xFFF0) == IDM_ABOUTBOX)
180     {
181         CAboutDlg dlgAbout;
182         dlgAbout.DoModal();
183     }
184     else
185     {
186         CDialog::OnSysCommand(nID, lParam);
187     }
188 }
189 
190 // If you add a minimize button to your dialog, you will need the code below
191 //  to draw the icon.  For MFC applications using the document/view model,
192 //  this is automatically done for you by the framework.
193 
194 void CTimeDlg::OnPaint() 
195 {
196     if (IsIconic())
197     {
198         CPaintDC dc(this); // device context for painting
199 
200         SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
201 
202         // Center icon in client rectangle
203         int cxIcon = GetSystemMetrics(SM_CXICON);
204         int cyIcon = GetSystemMetrics(SM_CYICON);
205         CRect rect;
206         GetClientRect(&rect);
207         int x = (rect.Width() - cxIcon + 1) / 2;
208         int y = (rect.Height() - cyIcon + 1) / 2;
209 
210         // Draw the icon
211         dc.DrawIcon(x, y, m_hIcon);
212     }
213     else
214     {
215         CDialog::OnPaint();
216     }
217 }
218 
219 // The system calls this to obtain the cursor to display while the user drags
220 //  the minimized window.
221 HCURSOR CTimeDlg::OnQueryDragIcon()
222 {
223     return (HCURSOR) m_hIcon;
224 }
225 
226 void CTimeDlg::OnOK()
227 {        
228     POSITION pos = m_list.GetFirstSelectedItemPosition();
229     if(pos)
230     {
231         int nItem = m_list.GetNextSelectedItem(pos);
232         strcpy(m_szIPAddr,m_list.GetItemText(nItem,1) );
233     }    //从列表框中获取所选择的时间服务器的IP地址
234 
235     CString str;  str=m_szIPAddr;  //判断是否选择了IP地址
236     if(str.IsEmpty())
237     {
238         MessageBox("请选择时间服务器!","时间校正",MB_ICONEXCLAMATION);
239         return;
240     }    
241 
242     SetDlgItemText(IDC_TEXTOUT,"");    
243     
244     WSADATA WSAData;
245     ::WSAStartup (MAKEWORD(2,0), &WSAData);        // Call "WSAStartup"显示szDescription字串,并简要提供了一些版本资讯。MAKEWORD(2,0)将第一个参数设定为0x0200(表示2.0版本)
246     EditPrintf ("\r\nStarted up %hs\r\n\r\n", WSAData.szDescription);
247 
248     /*  第一个参数AF_INET是一个位址种类,表示此处是某种Internet位址。
249         第二个参数表示资料以资料流的形式传回,而不是以资料封包的形式传回
250         (我们需要的资料只有4个位元组长,而资料封包适用于较大的资料块)。
251         最后一个参数是一个协定,我们指定使用的Internet协定是TCP。它是RFC-868所定义的两个协定之一。
252         socket函数的传回值储存在SOCKET型态的变数中,以便后面的Socket函数的调用。  */
253     m_sock = ::socket (AF_INET, SOCK_STREAM, IPPROTO_TCP) ;    
254     if (m_sock == INVALID_SOCKET)
255     {
256         EditPrintf ( "Socket 创建失败! #%i\r\n\r\n", ::WSAGetLastError ()) ;
257         ::WSACleanup () ;
258         return  ;
259     }
260     EditPrintf ("Socket %i  已经成功创建!\r\n\r\n", m_sock) ;
261     
262     /*  Call "WSAAsyncSelect" 
263         WSAAsynchSelect是另一个Windows特有的Socket函数。此函数用于避免因Internet回应过慢而造成应用程序当住。
264         在WinSock文件中,有些函数与「阻碍性(blocking)」有关。也就是说,它们不能保证立即把控制项权传回给程序。
265         WSAAsyncSelect函数强制阻碍性的函数转为非阻碍性的,即在函数执行完之前把控制项传回给程序。
266         函数的结果以讯息的形式报告给应用程序。WSAAsyncSelect函数让应用程序指定讯息和接收讯息的视窗的数值。
267         使用程序定义的一个讯息,该讯息称为WM_SOCKET_NOTIFY,最后一个参数来指定讯息发送的条件,
268         特别在连结和接收资料时(FD_CONNECT | FD_READ)   */
269     if (SOCKET_ERROR== ::WSAAsyncSelect(m_sock,GetSafeHwnd(),WM_SOCKET_NOTIFY,FD_CONNECT|FD_READ))
270     {
271         EditPrintf ("WSAAsyncSelect 错误: #%i.\r\n\r\n",::WSAGetLastError ());
272         ::closesocket (m_sock);
273         ::WSACleanup ();
274         return;
275     }
276     
277     /*  Call "connect" with IP address and time-server port
278         将sin_port设定为埠号,这里是时间协定的埠号,RFC-868显示为37。
279         但不要像我最初时那样,将此栏位设为37。当大多数数字通过Internet时,
280         结构的这个埠号栏位必须是「big endian」的,即最高的位元组排第一个。
281         Intel微处理器是little endian。幸运的是,htons(「host-to-network short」)函数使位元组翻转
282         用inet_addr函数将储存在m_szIPAddr字串中的伺服器位址转化为无正负号长整数   */
283     static struct sockaddr_in sa ;
284     sa.sin_family           = AF_INET ;    //#define AF_INET   2   (internetwork: UDP, TCP, etc.)
285     sa.sin_port             = ::htons (IPPORT_TIMESERVER) ;   //#define IPPORT_TIMESERVER    37
286     sa.sin_addr.S_un.S_addr = ::inet_addr (m_szIPAddr) ;
287     ::connect(m_sock, (SOCKADDR*) &sa, sizeof(sa)) ;
288 
289     
290     /*  connect函数通常已经会阻碍著后面程序的执行,这是因为连结成功以前需要花些时间。
291         然而,由于调用了WSAAsyncSelect,所以connect不会等待连结,事实上,它会立即传回SOCKET_ERROR的值。
292         并不是出现了错误,这只是表示现在还没有连线成功而已。NETTIME也不会检查这个传回值,只是调用::WSAGetLastError而已。
293         如果::WSAGetLastError传回WSAEWOULDBLOCK(即函数的执行通常要受阻,但这里并没有受阻),那就一切都还很正常。 */ 
294     if (WSAEWOULDBLOCK != ::WSAGetLastError ())
295     {
296         EditPrintf ("连接错误: #%i.\r\n\r\n", ::WSAGetLastError ()) ;
297         ::closesocket (m_sock) ;
298         ::WSACleanup () ;
299         return;
300     }
301     EditPrintf ( "正在连接: %hs...", m_szIPAddr) ;
302     
303     /*  连结最终完成时,主对话框由WM_SOCKET_NOTIFY消息-NETTIME在WSAAsyncSelect函数中指定的程序自订讯息所通知。
304         lParam的低字组等于FD_CONNECT,高字组表示错误。这时的错误可能是程序不能连结到指定的伺服器。
305         NETTIME还列出了其他伺服器,供您选择,让您可以试试其他的伺服器。
306         如果一切顺利,那么NETTIME将调用recv(「receive:接收」)函数来读取资料.
307         设定了一个计时器,只是在程序视窗中显示句点,以指示程序正在执行。*/
308     SetTimer (1, 1000, NULL);
309 
310 
311 }
312 
313 
314 void CTimeDlg::OnSocketNotify(WPARAM wp,LPARAM lp)
315 {     
316     WORD wEvent = WSAGETSELECTEVENT (lp) ;        // ie, LOWORD
317     WORD wError = WSAGETSELECTERROR (lp) ;        // ie, HIWORD
318     
319     //处理WSAAsyncSelect中指定得两种事件  FD_CONNECT | FD_READ
320     
321     switch (wEvent)   
322     {
323     case FD_CONNECT:
324         EditPrintf ("\r\n");
325         
326         if (wError)
327         {
328             EditPrintf ( "连接错误: #%i.", wError);
329              return ;
330         }
331         EditPrintf ( "已成功连接到时间服务器: %hs.\r\n\r\n", m_szIPAddr) ;
332         
333         /*  调用recv(「receive:接收」)函数来读取资料.
334             该调用将产生WM_SOCKET_NOTIFY讯息,这时带有FD_READ的事件代码。产生一个WSAEWOULDBLOCK错误以表示函数通常受阻,
335             但这时没有受阻。理论上来说(当然这不大可能),函数至少能传回资料的一部分,然后透过再次调用以获得其余的32个位元组值。
336             (char *) &m_ulTime, 4意味著,用4个位元组来储存m_ulTime变数
337             最后一个参数MSG_PEEK表示只是读此资料,并不将其从输入伫列中删除WM_SOCKET_NOTIFY讯息 */
338         ::recv (m_sock, (char *) &m_ulTime, 4, MSG_PEEK);
339         EditPrintf ( "正在接受数据,请稍候...");
340         return ;
341         
342     case FD_READ:
343         KillTimer (1);
344         EditPrintf ( "\r\n");
345         
346         if (wError)
347         {
348             EditPrintf ( "FD_READ 错误! #%i.", wError);
349              return ;
350         }
351 
352         /*  获得其余的32个位元值,这时最后的参数是0,用于从伫列中删除WM_SOCKET_NOTIFY讯息。
353             接收的32位元的m_ulTime值是从1990年1月1日开始的0:00 UTC秒数
354             但最高顺序的位元组是第一个位元组,因此该值必须通过ntohl(「network-to-host long」)函数处理来调整位元组顺序,
355             以便Intel微处理器能够处理。然后调用ChangeSystemTime函数。 */        
356         ::recv(m_sock, (char *) &m_ulTime, 4, 0) ;
357         m_ulTime = ::ntohl (m_ulTime) ;
358         EditPrintf ( "接受的时间为从1900年1月1日起 %u 秒 \r\n", m_ulTime) ;
359         
360         //改变系统时间        
361         this->ChangeSystemTime() ;     
362     }
363 }
364 void CTimeDlg::ChangeSystemTime()
365 {
366      FILETIME      ftNew ;     
367      SYSTEMTIME    stOld, stNew ;     
368      ::GetLocalTime (&stOld) ;   //首先取得目前的本地时间
369 
370      stNew.wYear         = 1900 ;
371      stNew.wMonth        = 1 ;
372      stNew.wDay          = 1 ;
373      stNew.wHour         = 0 ;
374      stNew.wMinute       = 0 ;
375      stNew.wSecond       = 0 ;
376      stNew.wMilliseconds = 0 ;
377      ::SystemTimeToFileTime (&stNew, &ftNew);
378 
379      /*  将SYSTEMTIME结构设定为1900年1月1日午夜(0时)。
380          并将这个SYSTEMTIME结构传递给SystemTimeToFileTime,将此结构转化为FILETIME结构。
381          FILETIME实际上只是由两个32位元的DWORD一起组成64位元的整数,
382          用来表示从1601年1月1日至今间隔为100奈秒(nanosecond)的间隔数。 */     
383 
384      LARGE_INTEGER li ;            //64位大整数
385      li = * (LARGE_INTEGER *) &ftNew;
386      li.QuadPart += (LONGLONG) 10000000 * m_ulTime; 
387      ftNew = * (FILETIME *) &li;
388      ::FileTimeToSystemTime (&ftNew, &stNew);
389 
390      if (::SetSystemTime (&stNew))    //调用SetSystemTime来设定时间
391      {
392          ::GetLocalTime (&stNew);
393           this->FormatUpdatedTime (&stOld, &stNew);   //最初的本地时间和新的本地时间一起传递给FormatUpdatedTime 这个函数用::GetTimeFormat函数和::GetDateFormat函数将时间转化为ASCII字串。
394      }
395      else
396           EditPrintf ("不能设置新的日期和时间!");
397 }
398 
399 void CTimeDlg::FormatUpdatedTime(SYSTEMTIME *pstOld, SYSTEMTIME *pstNew)
400 {
401      TCHAR szDateOld [64], szTimeOld [64], szDateNew [64], szTimeNew [64] ;
402 
403      ::GetDateFormat (LOCALE_USER_DEFAULT, LOCALE_NOUSEROVERRIDE | DATE_SHORTDATE,
404                       pstOld, NULL, szDateOld, sizeof (szDateOld)) ;
405      
406      ::GetTimeFormat (LOCALE_USER_DEFAULT, LOCALE_NOUSEROVERRIDE |TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT,
407                       pstOld, NULL, szTimeOld, sizeof (szTimeOld)) ;
408 
409      ::GetDateFormat (LOCALE_USER_DEFAULT, LOCALE_NOUSEROVERRIDE | DATE_SHORTDATE,
410                       pstNew, NULL, szDateNew, sizeof (szDateNew)) ;
411      
412      ::GetTimeFormat (LOCALE_USER_DEFAULT, LOCALE_NOUSEROVERRIDE |TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT,
413                       pstNew, NULL, szTimeNew, sizeof (szTimeNew)) ;
414 
415      EditPrintf ( "\r\n系统的日期和时间已成功更改:"
416                  "\r\n以前\t%s, %s.%03i \r\n现在\t%s, %s.%03i.", 
417 
418                  szDateOld, szTimeOld, pstOld->wMilliseconds,
419                  szDateNew, szTimeNew, pstNew->wMilliseconds) ;
420 } 
421 
422 void CTimeDlg::EditPrintf(TCHAR *szFormat,...)
423 {
424      TCHAR   szBuffer [1024];
425      va_list pArgList;  //typedef char *  va_list;
426 
427      va_start (pArgList, szFormat);  
428      ::wvsprintf (szBuffer, szFormat, pArgList); 
429      va_end (pArgList);
430 
431      m_edit.SetSel(-1,-1);  //将插入光标放于最后
432      m_edit.ReplaceSel(szBuffer);
433      m_edit.ScrollWindow(0,0);  //滚动到插入点
434 }
435 
436 void CTimeDlg::OnTimer(UINT nIDEvent) 
437 {
438     EditPrintf(".");    
439 
440     CDialog::OnTimer(nIDEvent);
441 }
442 
443 void CTimeDlg::OnCancel() 
444 {
445     ::closesocket (m_sock);
446     m_sock = 0 ;
447     ::WSACleanup () ;    
448     KillTimer (1) ;
449     
450     CDialog::OnCancel();
451 }
452 
453 void CTimeDlg::OnDblclkList1() 
454 {
455     POSITION pos = m_list.GetFirstSelectedItemPosition();
456     if(pos)
457     {
458         int nItem = m_list.GetNextSelectedItem(pos);
459         CString str;
460         str.Format("时间服务器%s",m_list.GetItemText(nItem,1));
461         MessageBox(str,"校正时间",MB_ICONINFORMATION);
462     } 
463 }
464 
465 HBRUSH CTimeDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) 
466 {
467     HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
468     
469     if (pWnd->GetDlgCtrlID() == IDC_TEXTOUT)
470     {
471     //    pDC->SetBkColor(RGB(156,174,189));
472         pDC->SetTextColor(RGB(0,0,255));
473     //    return (HBRUSH)CreateSolidBrush(RGB(156,174,189));
474     }    
475     
476 
477     return hbr;
478 }
479 
480 void CTimeDlg::OnButton1() 
481 {
482 
483     CAboutDlg dlg;
484     dlg.DoModal();
485 }
486 
487 
488 
489 
490 void CTimeDlg::OnLButtonDown(UINT nFlags, CPoint point) 
491 {
492     SendMessage(WM_NCLBUTTONDOWN,HTCAPTION,0);    
493 
494     CDialog::OnLButtonDown(nFlags, point);
495 }
496 
497 BOOL CTimeDlg::PreTranslateMessage(MSG* pMsg) 
498 {
499     if(pMsg -> message == WM_KEYDOWN)
500     {
501         if(pMsg -> wParam == VK_ESCAPE)
502             return TRUE;
503         if(pMsg -> wParam == VK_RETURN)
504             return TRUE;
505     }
506  
507      return CDialog::PreTranslateMessage(pMsg);
508 }
同步世界标准时间 转载

 

posted @ 2013-01-05 17:06  syrchina  阅读(286)  评论(0编辑  收藏  举报