创建Windows系统服务
1创建Windows系统服务程序
参考博客:http://www.vckbase.com/index.php/wv/1193
1.1创建Win32空工程
右击解决方案->添加新建项目。
右击项目->添加新建项->添加C++文件。
#include <Windows.h>
#include <stdio.h>
#include <stdlib.h>
#define SLEEP_TIME 2000
#define LOGFILE "C:\\memstatus.txt"
#define MEM_NAME "MemoryStatus"
SERVICE_STATUS ServiceStatus;
SERVICE_STATUS_HANDLE hStatus;
void serviceMain(int agrc, char** argv);
void ControlHandler(DWORD request);
int InitService();
int WriteLog(char* str);
int InitService()
{
OutputDebugString("Monitoring started.");
int ret;
ret = WriteLog("Monitoring started.");
return ret;
}
void ControlHandler(DWORD request)
{
switch (request)
{
case SERVICE_CONTROL_STOP://same as shutdown
case SERVICE_CONTROL_SHUTDOWN:
WriteLog("stoped.");
ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
break;
default:
break;
}
SetServiceStatus(hStatus, &ServiceStatus);
}
void serviceMain(int agrc, char** argv)
{
int error = 0;
ServiceStatus.dwServiceType = SERVICE_WIN32;
ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP |
SERVICE_ACCEPT_SHUTDOWN;
ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwCheckPoint = 0;
ServiceStatus.dwWaitHint = 0;
hStatus = RegisterServiceCtrlHandler(MEM_NAME,
(LPHANDLER_FUNCTION)ControlHandler);
if (hStatus == (SERVICE_STATUS_HANDLE)0)
{
return; //failed register
}
error = InitService();
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
SetServiceStatus(hStatus, &ServiceStatus);
MEMORYSTATUS memory;
//const int iMaxTime = 5;
while(1)
{
if(ServiceStatus.dwCurrentState == SERVICE_RUNNING)
{
char buff[16];
GlobalMemoryStatus(&memory);
sprintf(buff, "%d", memory.dwAvailPhys);
OutputDebugString(buff);
int ret = WriteLog(buff);
if (ret)
{
ServiceStatus.dwWin32ExitCode = -1;
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
SetServiceStatus(hStatus, &ServiceStatus);
}
Sleep(SLEEP_TIME);
}
}
return;
}
int WriteLog(char* str)
{
FILE* log;
log = fopen(LOGFILE, "a+");
if (NULL == log)
{
return -1;
}
fprintf(log, "%s\n", str);
fclose(log);
return 0;
}
int main(int argc, char* argv[])
{
SERVICE_TABLE_ENTRY serTab[2];
serTab[0].lpServiceName = MEM_NAME;
serTab[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)serviceMain;
serTab[1].lpServiceName = NULL;
serTab[1].lpServiceProc = NULL;
StartServiceCtrlDispatcher(serTab);
//system("pause");
return 0;
}
1.2创建服务入口函数
该函数是服务的入口点。它运行在一个单独的线程当中,这个线程是由控制分派器创建的。ServiceMain 应该尽可能早为服务注册控制处理器。这要通过调用 RegisterServiceCtrlHadler 函数来实现。你要将两个参数传递给此函数:服务名和指向 ControlHandlerfunction 的指针。
它指示控制分派器调用 ControlHandler 函数处理 SCM 控制请求。注册完控制处理器之后,获得状态句柄(hStatus)。通过调用 SetServiceStatus 函数,用 hStatus 向 SCM 报告服务的状态。
dwServiceType:指示服务类型,创建 Win32 服务。赋值 SERVICE_WIN32;
dwCurrentState:指定服务的当前状态。因为服务的初始化在这里没有完成,所以这里的状态为 SERVICE_START_PENDING;
dwControlsAccepted:这个域通知 SCM 服务接受哪个域。本文例子是允许 STOP 和 SHUTDOWN 请求。处理控制请求将在第三步讨论;
dwWin32ExitCode 和 dwServiceSpecificExitCode:这两个域在你终止服务并报告退出细节时很有用。初始化服务时并不退出,因此,它们的值为 0;
dwCheckPoint 和 dwWaitHint:这两个域表示初始化某个服务进程时要30秒以上。本文例子服务的初始化过程很短,所以这两个域的值都为 0。
调用 SetServiceStatus 函数向 SCM 报告服务的状态时。要提供 hStatus 句柄和 ServiceStatus 结构。ServiceStatus 一个全局变量,所以你可以跨多个函数使用。
1.3创建服务消息Handler
ServiceMain 函数注册了控制处理器函数。控制处理器与处理各种 Windows 消息的窗口回调函数非常类似。它检查 SCM 发送了什么请求并采取相应行动。
每次你调用 SetServiceStatus 函数的时候,必须指定服务接收 STOP 和 SHUTDOWN 请求。Listing 2 示范了如何在 ControlHandler 函数中处理它们。
STOP 请求是 SCM 终止服务的时候发送的。例如,如果用户在“服务”控制面板中手动终止服务。SHUTDOWN 请求是关闭机器时,由 SCM 发送给所有运行中服务的请求。两种情况的处理方式相同:
写日志文件,监视停止;
向 SCM 报告 SERVICE_STOPPED 状态;
由于 ServiceStatus 结构对于整个程序而言为全局量,ServiceStatus 中的工作循环在当前状态改变或服务终止后停止。其它的控制请求如:PAUSE 和 CONTINUE 在本文的例子没有处理。
控制处理器函数必须报告服务状态,即便 SCM 每次发送控制请求的时候状态保持相同。因此,不管响应什么请求,都要调用 SetServiceStatus。
1.4安装配置服务
1.4.1创建服务
注意: binpath= 和路径之间的有个空格
创建成功后在注册表项在“HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\”中自动增加项[服务名]
1.4.2删除服务
1.5测试
win+R运行services.msc。
启动服务进行测试。
双击当前服务,也可以设为开机自动启动。
启动几秒,然后手动停止后,c盘下面memstatus.txt文件内容。
为了测试 MemoryStatus 服务在出错情况下的行为,可以将 memstatus.txt 文件设置成只读。这样一来,服务应该无法启动。
去掉只读属性,启动服务,在将文件设成只读。服务将停止执行,因为此时日志文件写入失败。如果你更新服务控制面板的内容(按F5),会发现服务状态是已经停止。修改文件属性后重新启动服务才能成功。
理解 Win32 服务的基本概念,使你能更好地用 C++ 来设计包装类。包装类隐藏了对底层 Win32 函数的调用并提供了一种舒适的通用接口。修改 MemoryStatus 程序代码,创建满足自己需要的服务!为了实现比本文例子所示范的更复杂的任务,你可以创建多线程的服务,将作业划分成几个工作者线程并从 ServiceMain 函数中监视它们的执行。