以前一直想自己写一个定时关机的程序,但一直没有实现,现在终于写好了
对于这样的一个功能,其实是很简单的。里面主要设计的技术就是怎样去写关机的代码段了。
因而我主要解析一下自动关机的具体实现。
对于这个功能的实现由四步实现:
1. 调用OpenProcessToken函数,实现设置关机进程的访问标识(access token)(MSDN解释:opens the access token associated with a process.)
该函数总共有三个参数,HANDLE ProcessHandle参数用于当前程序的实例句柄,可用函数GetCurrentHandle( )获取,DWORD DesiredAcess参数用于标识要获取的权限, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY分别表示可以实现或是屏蔽优先权和可以实现获取访问标识,PHANDLE TokenHandle用于获取获取访问标识后的句柄
2. 调用LookupPrivilegeValue函数,获取本地计算机唯一标识(LUID),并且获取关机权限.(MSDN解释:retrieves the locally unique identifier (LUID) used on a specified system to locally represent the specified privilege name.)
BOOL WINAPI LookupPrivilegeValue(LPCTSTR lpSystemName, LPCTSTR lpName PLUID lpLuid)第一个参数为要获取优先权的计算机名称,NULL值表示本地计算机,第二个参数为标识优先权的名称,可以是ID也可以为相应的字符串,如 SE_SHUTDOWN_NAME(或是"SeShutdownPrivilege")表示该进程具有关机的权限,或SE_SECURITY_NAME表示有管理审核和安全日志权限.第三个参数用于传进变量获取已标识计算机的LUID.
3. 调用AdjustTokenPrivileges函数,获取关机的权限.(MSDN解释: enables or disables privileges in the specified access token.)
BOOL WINAPI AdjustTokenPrivileges( HANDLE TokenHandle,BOOL DisableAllPrivileges, PTOKEN_PRIVILEGES NewState, DWORD BufferLength, PTOKEN_PRIVILEGES PreviousState, PDWORD ReturnLength);第一个参数为一个需要被修改的指针,并且它需要具有SE_PRIVILEGE_ENABLED权限,第二个参数true表示屏蔽所有权限,忽略NewState参数,若为false则用NewState参数设置当前参数,指向一个TOKEN_PRIVILEGES指针,BufferLength参数指示PreviousState参数的长度,如果PreviousState参数为NULL,则其为0,PreviousState参数指示前一TOKEN_PRIVILEGES指针, ReturnLength 参数应为NULL如果PreviousState参数为NULL
4. 调用ExitWindowsEx或是InitiateSystemShutdown函数实现最后的关机功能.
BOOL ExitWindowsEx(UINT uFlags,DWORD dwReserved);用于立即关机uFlags标识关机选项,EWX_POWEROFF为关机,EWX_REBOOT为重启,后一个参数被保留
BOOL WINAPI InitiateSystemShutdown(LPTSTR lpMachineName,LPTSTR lpMessage, DWORD dwTimeout, BOOL bForceAppsClosed, BOOL bRebootAfterShutdown);记录关机的原因,lpMachineName参数标识主机名,NULL为本机,或是网络中的一个主机名。lpMessage在关机对话框中显示信息,可以为NULL值,dwTimeout设置对话框的显示时间,即对话框出现后的关机剩余时间,bForceAppsClosed若要强制关机,则设置为TRUE,它强制关闭为保存的文件,否则设置为FALSE, bRebootAfterShutdownTRUE为重启,FALSE为关机
程序代码如下:
TOKEN_PRIVILEGES tkp;
HANDLE hToken;
if (!OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
{
MessageBox("OpenProcessToken failed!");
}
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)
{
MessageBox("AdjustTokenPrivileges enable failed!");
}
bool fResult =InitiateSystemShutdown(
NULL, // 要关的计算机用户名,可在局域网网中关掉对方的机器,NULL表示关本机
"定时关机已经启动,请做好保存工作!", // 显示的消息
10, // 关机所需的时间
TRUE,
FALSE); //设为TRUE为重起,设为FALSE为关机
if(!fResult)
{
MessageBox("InitiateSystemShutdown failed.");
}
tkp.Privileges[0].Attributes = 0;
AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,(PTOKEN_PRIVILEGES) NULL, 0);
if (GetLastError() != ERROR_SUCCESS)
{
MessageBox("AdjustTokenPrivileges disable failed.");
}
ExitWindowsEx(EWX_SHUTDOWN,0); //开始关机