自从儿子上周从上海回来后,天天泡在电脑上。我很担心他的视力,不过秋老虎这么厉害,除了晚上能够带他到操场活动外,白天也只能闷在空调屋里活动啦,不让他玩也过于不近人情。“堵不如疏”,就打算给他装个定时开关机软件,免得我不在家的时候他不知节制地消耗视力。儿子有一定的电脑软件安装基础,网上所找到的定时开关机软件都不符合要求。于是,就自己写了一个简单的程序。
程序功能:自启动服务模式运行。开机40分钟后,强制关机,并把当前时刻记录到lastTime.dat中;每次开机前读取系统时间,与lastTime.dat中的时间进行比较,若小于10分钟,则强制关机。
为防止儿子发现服务并卸载该软件,电脑采用EWF方式进行文件保护,并且屏蔽了任务管理器和控制面板中的服务项目。
程序源码如下:
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <windows.h>
#define WINNT 0x11
#define WIN9X 0x12
#define EXITWINDOWS_FAILED 0x13
#define EXITWINDOWS_SUCESS 0x14
#define ADJUST_TOCKEN_SUCESS 0x15
#define ADJUST_TOCKEN_FAILED 0x15
#define ADJUST_PRIVILEGE_FAILED 0x16
#define OPENING_PROCESS_TOKEN_FAILED 0x100
UINT m_nVersionType;
BOOL AdjustProcessTokenPrivilege()
{
HANDLE hToken;
TOKEN_PRIVILEGES tkp;
if (!OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
{
return OPENING_PROCESS_TOKEN_FAILED;
}
if(!LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME,&tkp.Privileges[0].Luid))
{
return ADJUST_PRIVILEGE_FAILED;
}
tkp.PrivilegeCount = 1;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,(PTOKEN_PRIVILEGES)NULL, 0);
if (GetLastError() != ERROR_SUCCESS)
{
return ADJUST_TOCKEN_FAILED;
}
return ADJUST_TOCKEN_SUCESS;
}
BOOL ExitWindowsExt(UINT nFlag, DWORD dwType)
{
int iRetval(0);
switch(m_nVersionType)
{
case WINNT:
{
if((iRetval=AdjustProcessTokenPrivilege()) == ADJUST_TOCKEN_SUCESS)
{
return ExitWindowsEx(nFlag, dwType);
}
else
{
return iRetval;
}
break;
}
case WIN9X:
{
return ExitWindowsEx(nFlag, dwType);
break;
}
}
return FALSE;
}
void CheckAndShutDown()
{
int hour = 0;
int minute = 0;
time_t timer = time(NULL);
struct tm *tb = localtime(&timer);
// 开机检测是否与上次关机时间在10分钟之内,如果是,则继续关机
FILE *fr = fopen("D://lastTime.dat", "r");
if(fr)
{
fscanf(fr, "%d%d", &hour, &minute);
fclose(fr);
}
int diff = (tb->tm_hour - hour) * 60 + (tb->tm_min - minute);
if(abs(diff) < 10)
{
ExitWindowsExt(EWX_POWEROFF|EWX_FORCE, 0);
}
Sleep(40 * 60 * 1000); // 40分钟自动关机一次
// 在关机前记录当前时间
timer = time(NULL);
tb = localtime(&timer);
FILE *fw = fopen("D://lastTime.dat", "w");
if(fw)
{
fprintf(fw, "%d %d", tb->tm_hour, tb->tm_min);
fclose(fw);
}
// ForcePoweroff
ExitWindowsExt(EWX_POWEROFF|EWX_FORCE, 0);
}
// Declare several global variables to share
// their values across multiple functions of your program.
SERVICE_STATUS ServiceStatus;
SERVICE_STATUS_HANDLE hStatus;
// Make the forward definitions of functions prototypes.
//
void ServiceMain(int argc, char** argv);
void ControlHandler(DWORD request);
// Control Handler
void ControlHandler(DWORD request)
{
switch(request)
{
case SERVICE_CONTROL_STOP:
OutputDebugString("Monitoring stopped.");
ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
SetServiceStatus (hStatus, &ServiceStatus);
return;
case SERVICE_CONTROL_SHUTDOWN:
OutputDebugString("Monitoring stopped.");
ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
SetServiceStatus (hStatus, &ServiceStatus);
return;
default:
break;
}
// Report current status
SetServiceStatus (hStatus, &ServiceStatus);
return;
}
void ServiceMain(int argc, char** argv)
{
ServiceStatus.dwServiceType = SERVICE_WIN32;
ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwServiceSpecificExitCode = 0;
ServiceStatus.dwCheckPoint = 0;
ServiceStatus.dwWaitHint = 0;
hStatus = RegisterServiceCtrlHandler("AutoOff", (LPHANDLER_FUNCTION)ControlHandler);
if (hStatus == (SERVICE_STATUS_HANDLE)0)
{
// Registering Control Handler failed
return;
}
// We report the running status to SCM.
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
SetServiceStatus (hStatus, &ServiceStatus);
CheckAndShutDown();
return;
}
int main(int argc, char **argv)
{
OSVERSIONINFO m_osvi;
m_osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
BOOL bval = GetVersionEx(&m_osvi);
if(m_osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)
{
m_nVersionType = WINNT;
}
else if(m_osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
{
m_nVersionType = WIN9X;
}
#ifdef SERVICE
SERVICE_TABLE_ENTRY ServiceTable[2];
ServiceTable[0].lpServiceName = "AutoOff";
ServiceTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain;
ServiceTable[1].lpServiceName = NULL;
ServiceTable[1].lpServiceProc = NULL;
// Start the control dispatcher thread for our service
StartServiceCtrlDispatcher(ServiceTable);
#else
CheckAndShutDown();
#endif
return 0;
}
CheckAndShutDown()是主执行程序。
AdjustProcessTokenPrivilege()和ExitWindowsExt()是用于设置强制关机权限的,参考http://www.host01.com/article/software/cc/20060917233139326.htm 。
ServiceMain()和ControlHandler()是服务程序函数,参考http://www.vckbase.com/document/viewdoc/?id=1474 。