一个定时关机的小程序

一:需求描述

最近经常在需要让计算机在特定时间关闭或者重启,所以写了这个程序。当然满足这一需求的方法很多,比如用计划任务等等,但是既然在学VC,就自己动手做一个吧。

二、解题思路

定时关机无非是设定一个关机时间,然后跟当前系统时间比较,取得这个差,然后设置一个定时器,到时间就执行相应的操作,比如shutdown、reboot、logoff等等。

三、详细过程

程序最终的画面如下:

第一步:利用Wizard生成一个对话框框架。然后按上图所示放置控件。其中“倒计时”的ID设为IDC_STATIC_NAME,“00:00:00”的ID设为IDC_STATIC_TIME(这两个在程序里要用),另外为日期、时间、ComboBox添加控件变量分别为m_Data1,m_Data2,m_ComboBox.ComboBox的样式为Drop list,即不接收输入。好了,下面就添加代码。

第二步:添加代码:

我要在按下“设定”按钮时,,把“设定”改为“重新设定”,让能设定的选项均不能再修改,除非再按一次这个按钮。所以要用一个bool型的变量记录按钮的状态,所以在对话框的头文件添加变量IsChanged,类型为bool.另外再添加3个变量m_Hour,m_Min,m_Sec,类型为int,一个long型的m_remain。好了,变量先添加这些,接下来要重载OnOK、OnCancel函数,直接用向导添加就行了;为按钮添加默认的点击处理函数;添加最小化到系统托盘的函数toTray(),消息映射 afx_msg LRESULT onShowTask(WPARAM wParam,LPARAM lParam);以及afx_msg void OnTimer(UINT_PTR nIDEvent);记得还要在对话框cpp文件中添加相应的内容,此处不说了。在对话框cpp中添加#define WM_SHOWTASK   WM_USER+1为自定义的消息。好了,现在就为函数写代码吧。

首先是在OnInitDialog()中添加 
 m_ComboBox.InsertString(0,_T("注销"));
 m_ComboBox.InsertString(1,_T("关闭计算机"));
 m_ComboBox.InsertString(2,_T("重新启动"));
 m_ComboBox.SetCurSel(1);
 // TODO: 在此添加额外的初始化代码
 IsChanged =true;

然后是OnOK函数中添加一行代码OnBnClickedButton1();

OnCancel函数中添加如下代码:

NOTIFYICONDATA nid1;
 nid1.hWnd = this->m_hWnd;
 nid1.uID = IDR_MAINFRAME;
 Shell_NotifyIcon(NIM_DELETE,&nid1);
 CDialog::OnCancel();

目的是把系统托盘中的图标移走。

OnTimer函数中添加如下代码

m_Hour = m_remain/3600;
 m_Min = (m_remain%3600)/60;
 m_Sec = (m_remain%3600)%60;
 CString m_time;
 if(m_Hour>=10)
  m_time.Format("%d:",m_Hour);
 else
  m_time.Format("0%d:",m_Hour);
 if(m_Min>=10)
  m_time.Format(m_time+"%d:",m_Min);
 else
  m_time.Format(m_time+"0%d:",m_Min);
 if(m_Sec>=10)
  m_time.Format(m_time+"%d",m_Sec);
 else
  m_time.Format(m_time+"0%d",m_Sec);
 SetDlgItemText(IDC_STATIC_TIME,m_time);
 if(m_remain<=60)
 {
  if(!IsTop)//只设定一次
  {
   CWnd::SetWindowPos(&wndTopMost,0,0,0,0,SWP_NOREDRAW|SWP_NOSIZE);
   IsTop = true;
  }
  MessageBeep(-1);
 }
 if(m_remain==0)
 {
  //shutdowncomputer adjust privalige
  HANDLE hToken;
  TOKEN_PRIVILEGES tkp;
  if(!OpenProcessToken(::GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,&hToken))
   return;
  LookupPrivilegeValue(NULL,SE_SHUTDOWN_NAME,&tkp.Privileges[0].Luid);
  tkp.PrivilegeCount = 1;
  tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  AdjustTokenPrivileges(hToken, false, &tkp, 0, (PTOKEN_PRIVILEGES)NULL, 0);
  if(GetLastError()!=ERROR_SUCCESS)
   return;
  switch(m_ComboBox.GetCurSel())
  {
  case 0://logoff
   ExitWindowsEx(EWX_LOGOFF|EWX_FORCE,0);
   break;
  case 1://shutdown
   ExitWindowsEx(EWX_SHUTDOWN | EWX_POWEROFF | EWX_FORCE, 0);
   break;
  default://reboot
   ExitWindowsEx(EWX_REBOOT | EWX_FORCE,0);
  }
  PostMessage(WM_QUIT);
 }
 m_remain -=1;

实现了两点:1是显示剩余时间,2是时间到达后执行操作。

OnBnClickedButton1中添加如下代码

if(IsChanged)//设定关机
 {
  //取得设定时间
  SYSTEMTIME m_data,m_time,m_systime;
  __int64 m_Start,m_End;
  FILETIME m_filetime,m_sysfile;
  PULARGE_INTEGER m_inttime,m_sysint;
  GetSystemTime(&m_systime);
  m_systime.wHour +=8;
  m_Data1.GetTime(&m_data);
  m_Data2.GetTime(&m_time);
  m_data.wHour = m_time.wHour;
  m_data.wMinute = m_time.wMinute;
  m_data.wSecond = m_time.wSecond;
  m_data.wMilliseconds = m_time.wMilliseconds;
  SystemTimeToFileTime(&m_data,&m_filetime);
  SystemTimeToFileTime(&m_systime,&m_sysfile);
  m_inttime = (PULARGE_INTEGER)&m_filetime;
  m_sysint = (PULARGE_INTEGER)&m_sysfile;
  m_Start = *(__int64 *)m_sysint;
  m_End = *(__int64 *)m_inttime;
  if(m_Start>=m_End)
  {
   MessageBox(_T("不能小于当前时间!"),_T("时间设定出错"),MB_ICONERROR|MB_OK);
   return;
  } 
  m_remain =  (long)((m_End-m_Start)/10000/1000);

  CWnd::SetTimer(1,1000,0);
  SetDlgItemText(IDC_BUTTON1,_T("重新设定"));
  m_Data1.EnableWindow(false);
  m_Data2.EnableWindow(false);
  m_ComboBox.EnableWindow(false);
  IsChanged = false;
  switch(m_ComboBox.GetCurSel())
  {
  case 0:
    SetDlgItemText(IDC_STATIC_NAME,_T("注销倒计时:"));
    break;
  case 1:
    SetDlgItemText(IDC_STATIC_NAME,_T("关机倒计时:"));
    break;
  default:
    SetDlgItemText(IDC_STATIC_NAME,_T("重启倒计时:"));
  }
 }
 else//重新设定
 {
  IsChanged = true;
  m_Data1.EnableWindow();
  m_Data2.EnableWindow();
  m_ComboBox.EnableWindow();
  SetDlgItemText(IDC_BUTTON1,_T("设定"));
//  SYSTEMTIME m_time;
//  GetSystemTime(&m_time);
  m_Data1.SetTime();
  m_Data2.SetTime();
  CWnd::KillTimer(1);
 }

toTray中添加如下代码

NOTIFYICONDATA nid;
 nid.cbSize = (DWORD)sizeof(NOTIFYICONDATA);
 nid.hWnd = this->m_hWnd;
 nid.uID = IDR_MAINFRAME;
 nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
 nid.uCallbackMessage = WM_SHOWTASK;
 nid.hIcon = LoadIcon(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDR_MAINFRAME));
 strcpy(nid.szTip,"定时关机");
 Shell_NotifyIcon(NIM_ADD,&nid);
 ShowWindow(SW_HIDE);

主要是实现了最小化到系统托盘

LRESULT CautoshutdownDlg::onShowTask(WPARAM wParam,LPARAM lParam)
{
 if(wParam != IDR_MAINFRAME)
  return -1;
 switch(lParam)
 {
 case WM_RBUTTONUP:
  {
   LPPOINT lpoint = new tagPOINT;
   ::GetCursorPos(lpoint);
   CMenu menu;
   menu.CreatePopupMenu();
   menu.AppendMenu(MF_STRING,WM_DESTROY,"关闭");
   menu.TrackPopupMenu(TPM_LEFTALIGN,lpoint->x,lpoint->y,this);
   HMENU hmenu=menu.Detach();
   menu.DestroyMenu();
   delete lpoint;
  }
  break;
 case WM_LBUTTONUP:
  {
   this->ShowWindow(SW_SHOW);
  }
  break;
 }
 return 0;
}
这个就是相应的处理函数。

最后别忘了在OnSysCommand中添加 if(nID == SC_MINIMIZE)
 {

   toTray();


 }

好了,工作到次结束了。

需要说明的几点是:取得系统时间后要把它转化成FILETIME,然后化成ULARGEINTERG,最后转化成__int64之后才比较,然后/10000/1000换成秒。

你可能感兴趣的:(MFC编程,integer,token,wizard,button,delete,shell)