系统定时关机,可以拖盘运行

本文介绍了一个使用C++实现的定时关机程序的设计与实现过程。该程序利用了ExitWindowsEx函数来执行关机操作,并通过Shell_NotifyIcon实现了程序最小化到系统托盘的功能。此外,还提供了定时关机和倒计时关机两种模式。

     写的一个定时关机程序,并可以拖盘运行。

     通过网上百度,我知道了ExitWindowsEx可以对电脑进行注销,关机,重启等操作,然后还需要让程序拖盘运行。于是我就写了一个通过定时和倒计时来对电脑开机进行控制。

用ExitWindowsEx函数如下:

 BOOL ExitWindowsEx(

  UINT uFlags, // 关闭参数

  DWORD dwReserved // 系统保留,一般取0

  );

 参数:uFlags

    指定关闭的类型。此参数必须有下列值的组合

         EWX_LOGOFF           关闭所有进程,然后注销用户。

       EWX_POWEROFF      关闭系统并关闭电源。该系统必须支持断电。(Win2000以上,

                                            进程必须有 SE_SHUTDOWN_NAME 特权。)

           EWX_REBOOT           关闭系统,然后重新启动系统。(条件同上)

           EWX_SHUTDOWN     关闭系统,安全地关闭电源。

                                        所有文件缓冲区已经刷新到磁盘上,所有正在运行的进程已经停止。

 参数:dwReserved

     保留,这参数被忽略。一般取0。

 而拖盘运行使用Shell_NotifyIcon函数,如下:

 BOOL Shell_NotifyIcon(

  DWORD dwMessage,

  PNOTIFYICONDATA lpdata

  );

dwMessage为输入参数,传递发送的消息,表明要执行的操作。可选的值如下

NIM_ADD       向托盘区域添加一个图标。此时第二个参数lpdata指向的NOTIFYICONDATA结构体中的hWnd和uID成员用来标示这个    图标,以便以后再次使用Shell_NotifyIcon对此图标操作

 

NIM_DELETE    删除托盘区域的一个图标。此时第二个参数lpdata指向的NOTIFYICONDATA结构体中的hWnd和uID成员用来标示需要被删除的这个图标

NIM_MODIFY

  修改托盘区域的一个图标。此时第二个参数lpdata指向的NOTIFYICONDATA结构体中的hWnd和uID成员用来标示需要被修改的这个图标。

NIM_SETFOCUS

  Version 5.0. 设置焦点。比如当用户操作托盘图标弹出菜单,而有按下ESC键将菜单消除后,程序应该使用此消息来将焦点设置到托盘图标上。

NIM_SETVERSION

  Version 5.0. 设置任务栏按照第二个参数lpdata指向的NOTIFYICONDATA结构体中的uVersion成员指定的版本号来工作。此消息可以允许用户设置是否使用基于Windows2000的version 5.0的风格。uVersion的缺省值为0,默认指明了使用原始Windows 95图标消息风格。具体这两者的区别请参考msdn中的Shell_NotifyIcon函数说明的Remarks。

 

lpdata为输入参数,是指向NOTIFYICONDATA结构体的指针,结构体内容用来配合第一个参数wMessage进行图标操作。

 

 

首先创建一个对话框的程序,取名为ClockToShutDown;

添加下图所示的各个控件

先说一下我的想法:1,2,3显视当前系统的年月日,时分秒。通过7,8单选按钮来选择是定时关机,还是倒计时关机。然后通过10,11,12来接收所需要定时或是倒计时的时间,如果是倒计时则将21,22可视并显视剩余时间,将定时选项的其他项变为不可见。18,19为取消当前设定的时间和启动当前所设置的时间(19与18重放的位置相同,18一开始不可视)。

 

先写出关机函数:

void CClockToShutDownDlg::ShowDown(void)

{

  HANDLE hToken;
  TOKEN_PRIVILEGES tkp;

      // Get a token for this process. 

  if (!OpenProcessToken(GetCurrentProcess(),
  TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
      return;

 

// Get the LUID for the shutdown privilege.

  LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME,
  &tkp.Privileges[0].Luid);

  tkp.PrivilegeCount = 1; // one privilege to set
  tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

 

 // Get the shutdown privilege for this process.

  AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,
  (PTOKEN_PRIVILEGES)NULL, 0);

  if (GetLastError() != ERROR_SUCCESS)
  return ;

  

// Shut down the system and force all applications to close.

  if (!ExitWindowsEx(EWX_SHUTDOWN | EWX_FORCE, 0))
  return ;

}

 

接下来是启动定时后的处理:

 void CClockToShowDownDlg::OnBnClickedBtnQy()  //启动按钮id为IDC_BTN_QY

{

  UpdateData() ;//更新各控件的关联数据

  CString str;
 GetDlgItemText(IDC_EDIT_HOUR,str) ;//获得时间输入框的内容
 if(!wcscmp(_T(""),str.GetBuffer()))  //若时分秒均为空则要提示
 {
  str.ReleaseBuffer() ;
  GetDlgItemText(IDC_EDIT_MINUTE,str) ;
  if(!wcscmp(_T(""),str.GetBuffer()))
  {
   str.ReleaseBuffer();
   GetDlgItemText(IDC_EDIT_SECOND,str) ;
   if(!wcscmp(_T(""),str.GetBuffer()))
   {
    str.ReleaseBuffer();
    MessageBox(_T("您没有设定任何时间"));
    return ;
   }
  }
  
 }
 m_nHour = GetDlgItemInt(IDC_EDIT_HOUR) ;//将时分秒输入框的数据读出,就算用户不符合规范也可以,只要有一项不为空
 m_nHour = m_nHour%24 ;                            //当某一项输入为空时GetDlgItemInt读出的是0

 m_nMinute = GetDlgItemInt(IDC_EDIT_MINUTE) ;
 m_nMinute = m_nMinute%60 ;

 m_nSecond = GetDlgItemInt(IDC_EDIT_SECOND) ;
 m_nSecond = m_nSecond % 60;
  

 if(!(m_nHour || m_nMinute || m_nSecond))//若是定时,可以定为0点,
 {
       
  if(m_bDJS.GetCheck())//但倒计时不能是0秒,m_bDJS 是单选项的控件变量
  {
       MessageBox(_T("您设的倒计时为0/r/n请不要如此设置/r/n要想直接关机请点击关机按钮!")) ;
         return ;
  }
  
 }
 
 if(m_bDJS.GetCheck())//做判断,如果倒计时则将21,22可视并显视剩余时间,将定时选项的其他项变为不可见
 {                                    //反之,则取相反即可
        ShowOrHide(1) ;//ShowOrHide,参数1,则显示21,22,隐藏其他项。

 }
 else
 { 
       ShowOrHide(0);
 }
 

((CButton*)GetDlgItem(IDC_CHECK_DS))->ShowWindow(SW_HIDE) ;//一旦开始就让两个单选按钮隐藏不可用
    ((CButton*)GetDlgItem(IDC_CHECK_DJS))->ShowWindow(SW_HIDE);


     GetDlgItem(IDC_BTN_QY)->ShowWindow(SW_HIDE) ;//启用按钮和取消按钮互斥存在
     GetDlgItem(IDC_BTN_QX)->ShowWindow(SW_SHOW) ;
 
  m_bFlag = m_bDS.GetCheck() ;//m_bFlag是布尔变量,用来判断是定时还是倒计时。

  SetTimer(TIME_TO_END,999,NULL) ;//开始定数器计时TIME_TO_END=2,是定义的一个宏

}     

 

接下来主要对定时进行处理,捕获WM_TIMER后函数处理如下:

void CClockToShutDown::OnTimer(UINT_PTR nIDEvent)//TIME_FIRST=1,是定义的一个宏,用来显示当前时间
{                                                                   
 
 if(nIDEvent == TIME_FIRST)
 {
   SYSTEMTIME time ;//系统时间结构体
   GetLocalTime(&time) ;//获取本地时间
   CString str ;

  //分别对时间进行格式化输出
   str.Format(_T("%d年%d月%d日"),time.wYear,time.wMonth, time.wDay) ;
   SetDlgItemText(IDC_CLOCK_YMD,str) ;

  

   str.Format(_T("%d时%d分%d秒"),time.wHour,time.wMinute,time.wSecond) ;
   SetDlgItemText(IDC_CLOCK_HMS,str) ;

 

   switch(time.wDayOfWeek)
   {
   case 0:
    str.Format(_T("星期天")) ;
    break;
   case 1:
    str.Format(_T("星期一")) ;
    break;
   case 2:
    str.Format(_T("星期二")) ;
   case 3:
    str.Format(_T("星期三")) ;
    break;   
   case 4:
    str.Format(_T("星期四")) ;
    break;
   case 5:
    str.Format(_T("星期五")) ;
    break;
   case 6:
    str.Format(_T("星期六")) ;
    break;
   }
   SetDlgItemText(IDC_CLOCK_WEEK,str) ;
 }

 else if(nIDEvent == TIME_TO_END)//对定时器TIME_TO_END进行处理
 {
       if(!m_bFlag)//如果是0,则表示是倒计时
    { 
   if(m_nSecond>0)//如果秒数大于0,则每秒自次1,若小于0秒,则对分数进行判断
   {
     m_nSecond--;
   }
     else
     {
     if(m_nMinute> 0)  //若分数大于0,则每当秒数为零时自减1,并将秒数设为59.若小于零则对小时数进行判断
     {
    m_nMinute -- ;
    m_nSecond = 59 ;
     }
     else
     {
    if(m_nHour>0)//如果小时数大于0,则每当分钟数为0时自减1,并将分数,秒数均设为59.如果小时数也等于0,则定时到,关机。
    {
       m_nHour--;
       m_nMinute = 59 ;
       m_nSecond = 59 ;
    }
    else
    {
                     ShutDown();
    }
     }
      }
    
      CString str ;//若定时没到,则对剩余时间进行显视
      str.Format(_T("%d:%d:%d"),m_nHour,m_nMinute,m_nSecond) ;
      SetDlgItemText(IDC_EDIT_DJSXS,str) ;
    }
    else//如果为定时
    {
       SYSTEMTIME time ;//直接让当前时间与本地时间比较,相等则定时时间到了。
       GetLocalTime(&time) ;
    if(time.wHour == m_nHour)
    {
     if(time.wMinute == m_nMinute)
     {
      if(time.wSecond == m_nSecond)
      {
                     ShutDown();
      }
     }
    }
    }

 

 }

 CDialog::OnTimer(nIDEvent);
}

 

 主要功能已经完成,接下来是让程序拖盘运行,并且有右键菜单。

定义一个消息WM_TUOPAN,并使其消息映射,函数为OnTuopan。用来响应消息。

BOOL CLockToShutDown::TrayMessage(HWND hWnd, DWORD dwMessage, HICON hIcon, LPCWSTR pszTip)
{
    BOOL bReturn;
    NOTIFYICONDATA NofityData;
    NofityData.cbSize = sizeof(NOTIFYICONDATA);
    NofityData.hWnd = hWnd;
    NofityData.uID = IDR_MAINFRAME;
    NofityData.uFlags = NIF_MESSAGE|NIF_ICON|NIF_TIP;
    NofityData.uCallbackMessage = WM_MY_TRAY_NOTIFICATION;
    NofityData.hIcon = hIcon;
    lstrcpyn(NofityData.szTip, pszTip, sizeof(NofityData.szTip));
    bReturn = Shell_NotifyIcon(dwMessage, &NofityData);
    if (hIcon)
        DestroyIcon(hIcon);
    return bReturn;
}

响应托盘按钮单击事件,便可使程序拖盘运行:

void CClockToShutDown::OnBnClickedBtnTp()
{
    TrayMessage(m_hWnd, NIM_ADD, NULL, _T("我的托盘"));
    TrayMessage(m_hWnd, NIM_MODIFY, m_hIcon, _T("我的托盘"));
    ShowWindow(SW_HIDE);
}

分别响应拖盘时的左键双击,和右键单击:

LRESULT CClockToShutDown::OnTuopan(WPARAM wParam ,LPARAM lParam)
{
 CMenu menu ;
 menu.LoadMenu(IDR_MENU1) ;//IDR_MENU1为自己建立的菜单(可以自己去写菜单项的响应,如退出,关机,退出托盘等等)
 CMenu* pPopup = menu.GetSubMenu(0);
    LPPOINT lpoint = new tagPOINT 

 ::GetCursorPos(lpoint) ;;//获取当前鼠标位置
 switch (lParam )
 {
 case WM_RBUTTONUP: //如果是右键消息,则弹出菜单
  pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, lpoint->x, lpoint->y,this);
       
  SetForegroundWindow(); //该函数使鼠标点击别的地方时菜单消失

  break;
 case WM_LBUTTONDBLCLK://如果是鼠标左键双击消息,退出拖盘,则返回主界面。
  ShowWindow(SW_SHOW);
  TrayMessage(m_hWnd, NIM_DELETE, NULL, _T(""));  
 }
 return 0;  
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值