创建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 函数中监视它们的执行。

posted @ 2022-03-12 22:05  xiaomodecnblogs  阅读(409)  评论(0编辑  收藏  举报