写的一个定时关机程序,并可以拖盘运行。
通过网上百度,我知道了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;
}
本文介绍了一个使用C++实现的定时关机程序的设计与实现过程。该程序利用了ExitWindowsEx函数来执行关机操作,并通过Shell_NotifyIcon实现了程序最小化到系统托盘的功能。此外,还提供了定时关机和倒计时关机两种模式。
1130

被折叠的 条评论
为什么被折叠?



