分类: WINDOWS
2010-11-13 15:08:58
最近在写一个程序,用来实现每隔一段时间上传数据功能。为了使小程序一直跟随操作系统启动运行而运行,听建议说最好写成一个服务,设置开机启动服务就可以达到上述效果了。
在网上淘换了个VC程序代码,里面有详细的注释。代码如下:
#include
#include
#include
#include
char *SERVICE_NAME = "BeepService"; // 定义服务的名称
HANDLE terminateEvent = NULL; // 定义用于控制ServiceMain执行的事件句柄
SERVICE_STATUS_HANDLE serviceStatusHandle; // 定义与SCM通讯的服务状态句柄
int beepDelay = 20000; // 定义间隔时间
BOOL pauseService = FALSE; // 定义服务暂停的标志
BOOL runningService = FALSE; // 定义服务运行的标志
HANDLE threadHandle = 0; // 定义实现服务功能的线程句柄
VOID SendStatusToSCM (DWORD dwCurrentState,DWORD dwWin32ExitCode,
DWORD dwServiceSpecificExitCode,DWORD dwCheckPoint,DWORD dwWaitHint)
{
SERVICE_STATUS serviceStatus;
serviceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; //设置服务运行在其自身的进程中
serviceStatus.dwCurrentState = dwCurrentState; //设置服务的当前状态
// 如果服务正在启动,则不接收和处理控制通知事件,否则接收所有的控制通知事件
if (dwCurrentState == SERVICE_START_PENDING)
serviceStatus.dwControlsAccepted = 0;
else
serviceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP|SERVICE_ACCEPT_PAUSE_CONTINUE |SERVICE_ACCEPT_SHUTDOWN;
/* 如果服务具有特定的出错代码,则设置serviceStatus 的dwWin32ExitCode属性为
ERROR_SERVICE_SPECIFIC_ERROR,并设置serviceStatus的dwServiceSpecificExitCode属性
为特定出错代码,以显示特定的错误信息*/
if (dwServiceSpecificExitCode == 0)
{
serviceStatus.dwWin32ExitCode = dwWin32ExitCode;
serviceStatus.dwServiceSpecificExitCode =0;
}
else
{
serviceStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
serviceStatus.dwServiceSpecificExitCode =dwServiceSpecificExitCode; //设置服务的特定出错代码
}
serviceStatus.dwCheckPoint = dwCheckPoint; //设置服务在启动、关闭和运行操作中反映操作进度的值
serviceStatus.dwWaitHint = dwWaitHint; //设置服务在执行启动、关闭和运行操作时将持续的时间值
SetServiceStatus (serviceStatusHandle, &serviceStatus); //更新SCM中服务的状态信息
}
DWORD ServiceThread(LPDWORD param)
{ //使用Sleep函数将while控制流程挂起,然后在指定的毫秒数后自动唤醒
while (1)
{
//服务功能程序接口位置
Sleep(beepDelay); //将该线程挂起beepDelay中指定的毫秒数
}
return 0;
}
VOID Handler (DWORD controlCode)
{
switch(controlCode)
{ // 处理停止服务事件
case SERVICE_CONTROL_STOP:
//通知SCM服务即将停止
SendStatusToSCM(SERVICE_STOP_PENDING,NO_ERROR, 0, 1, 5000);
runningService=FALSE; //设置服务运行的标志
SetEvent(terminateEvent); //设置终止事件句柄为活动状态,从而使ServiceMain函数得以继续执行
return;
// 处理暂停服务事件
case SERVICE_CONTROL_PAUSE:
if (runningService && !pauseService)
{
// 通知SCM服务即将暂停
SendStatusToSCM( SERVICE_PAUSE_PENDING,NO_ERROR, 0, 1, 1000);
pauseService = TRUE; //设置服务暂停的标志
SuspendThread(threadHandle); //挂起新服务的线程
SendStatusToSCM(SERVICE_PAUSED, NO_ERROR, 0, 0, 0); //通知SCM服务暂停
}
break;
// 处理继续服务事件
case SERVICE_CONTROL_CONTINUE:
if (runningService && pauseService)
{
// 通知SCM服务即将继续
SendStatusToSCM( SERVICE_CONTINUE_PENDING,NO_ERROR, 0, 1, 1000);
pauseService=FALSE; //设置服务暂停的标志
ResumeThread(threadHandle); //继续新服务的线程
SendStatusToSCM(SERVICE_RUNNING, NO_ERROR, 0, 0, 0); //通知SCM服务继续
}
break;
// 处理更新服务当前状态事件
case SERVICE_CONTROL_INTERROGATE:
break;
// 处理关闭系统事件
case SERVICE_CONTROL_SHUTDOWN:
return;
}
}
VOID ServiceMain(DWORD argc, LPTSTR *argv)
{ //调用RegisterServiceCtrlHandler函数获得服务状态句柄,并注册生成服务控制处理函数
serviceStatusHandle =RegisterServiceCtrlHandler(SERVICE_NAME, (LPHANDLER_FUNCTION)Handler);
//通知SCM服务即将启动,并设置启动操作的进度值为1,以及估计完成的时间值为5秒
SendStatusToSCM(SERVICE_START_PENDING,NO_ERROR, 0, 1, 5000);
// 创建terminateEvent事件句柄,以控制ServiceMain程序的执行
terminateEvent = CreateEvent (0, TRUE, FALSE, 0);
// 通知SCM服务即将启动,并设置启动操作的进度值为2,以及估计完成的时间值为1秒
SendStatusToSCM(SERVICE_START_PENDING,NO_ERROR, 0, 2, 1000);
// 获取启动参数,即蜂鸣的间隔时间值
if (argc == 2)
{
int temp = atoi(argv[1]);
//如果间隔值小于1秒,则使用缺省的间隔值
if (temp < 1000)
beepDelay = DEFAULT_BEEP_DELAY;
else
beepDelay = temp;
}
// 创建服务线程
DWORD id;
//创建服务所在的线程,ServiceThread是线程函数的起始地址,id用于获得线程的ID号
threadHandle = CreateThread(0, 0, (LPTHREAD_START_ROUTINE) ServiceThread,0, 0, &id);
runningService = TRUE; // 设置服务运行的标志
// 通知SCM服务开始运行
SendStatusToSCM(SERVICE_RUNNING,NO_ERROR, 0, 0, 0);
// 监视terminateEvent 事件句柄的状态,如果处于活动状态,程序继续执行,否则阻止程序继续执行
WaitForSingleObject (terminateEvent, INFINITE);
// 如果terminateEvent 事件句柄处于活动状态,则关闭相关句柄,终止ServiceMain函数
CloseHandle(terminateEvent); //关闭terminateEvent事件句柄
SendStatusToSCM(SERVICE_STOPPED, 0,0, 0, 0); // 显示出错信息error,并通知SCM服务停止
CloseHandle(threadHandle); //关闭threadHandle线程句柄
}
VOID main(VOID)
{
//填充SERVICE_TABLE_ENTRY结构,供StartServiceCtrlDispatcher函数调用
SERVICE_TABLE_ENTRY serviceTable[] = {{ SERVICE_NAME,(LPSERVICE_MAIN_FUNCTION)
ServiceMain},{ NULL, NULL }};
BOOL success;
//通过将新服务的ServiceMain函数的指针传递给SCM,实现新服务在SCM中的注册
success = StartServiceCtrlDispatcher(serviceTable);
if (!success)
ExitProcess(GetLastError()); //结束进程的执行
}
将程序编译成Myservices.exe文件,把他放在c盘,在DOS命令符下输入 sc create Myservices binpath= c:\Myservices.exe(Myservices 是服务的名字)。创建服务成功之后了,在运行里输入services.msc,打开服务,在里面找到Myservices 服务,启动它。OVER。删除服务命令:在DOS命令符下输入 sc delete 服务的名字。