编写NT服务程序

来源:互联网 发布:act网络课程 编辑:程序博客网 时间:2024/05/17 23:03

     最近接触的工程是B/S、C/S结构的,跟之前做单机版的应用程序有很大的不同。后端很多功能都做成服务的形式。以前从来没有接触服务这个方面的东西,故趁此机会来学习一下如何制作Windows后台服务程序。

    看了公司的服务程序是如何做的,因为采用了第三库,库中提供了一个类来封装NTService功能,而我想知道的更彻底些,就在网上查看了一些资料,搭配着看了那个类的底层细节。总体感觉NTService程序并不难编写,关键要知道实现思路和与之相关的一些API。

简单来说,就是Windows系统有一个Service的数据库,把自己编写的服务加进去(安装),再利用Windows本身提供的控制机制来控制服务的启动暂停停止等,如果卸载就将服务从Service表中删除。具体的内容参考MSDN和网络资料,下面有几个相关链接:

http://blog.csdn.net/todototry/archive/2007/04/16/1566442.aspx

http://blog.csdn.net/todototry/archive/2007/04/16/1566443.aspx

http://blog.csdn.net/todototry/archive/2007/04/16/1566451.aspx

http://blog.csdn.net/todototry/archive/2007/04/16/1566455.aspx

http://www.vckbase.com/document/viewdoc/?id=1474

http://www.vckbase.com/document/viewdoc/?id=1447

http://blog.csdn.net/feijj2002_/archive/2007/08/05/1727228.aspx

 

 

为了加上印象,毕竟纸上得来终觉浅,就模仿一些代码写了个简单的NTService。

留个爪子印:

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <tchar.h>
#include <assert.h>

 

#define SZSERVICENAME "TNTService"
#define SZSERVICEDISPLAYNAME "TNTService_Desc"

 

void WINAPI TServiceMain(DWORD argc, LPTSTR * argv);
void InstallService();
void RemoveService();
void StartService();
void StopService();
void LogEvent(LPCTSTR pFormat, ...);
void Start();
void Stop();

//real service function
DWORD WINAPI RealService(LPVOID lpvThread);

 

SERVICE_STATUS servicestatus;
SERVICE_STATUS_HANDLE servicestatushandle;

 

int main(int argc, char * argv[])
{
 if(argc == 2)
 {
  if(::strcmp(argv[1]+1, "i")==0)//i = install
  {
   InstallService();
  }
  else if (::strcmp(argv[1]+1, "r")==0)//r = remove
  {
   RemoveService();
  }
  else if (::strcmp(argv[1]+1, "s")==0)//s = start
  {
   StartService();
  }
  else if (::strcmp(argv[1]+1, "k")==0)//k = kill
  {
   StopService();
  }
  
  return 0;
 }

 

 SERVICE_TABLE_ENTRY   service_table_entry[] =
 {
  { SZSERVICENAME, TServiceMain },
  { NULL, NULL }
 };

 ::StartServiceCtrlDispatcher(service_table_entry);

return 0;
}

 

void InstallService()
{
 SC_HANDLE handle = ::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
 assert(handle != NULL);
 char szFilename[256] = {'/0'};
 ::GetModuleFileName(NULL, szFilename, 255);
 SC_HANDLE hService = ::CreateService(handle,
          SZSERVICENAME,
          SZSERVICEDISPLAYNAME,
          SERVICE_ALL_ACCESS,
          SERVICE_WIN32_OWN_PROCESS,
          SERVICE_DEMAND_START,
          SERVICE_ERROR_IGNORE,
          szFilename,
          NULL,
          NULL,
          NULL,
          NULL,
          NULL);
 assert(hService != NULL);
 ::CloseServiceHandle(hService);
 ::CloseServiceHandle(handle);
}

 

void RemoveService()
{
 SC_HANDLE handle = ::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
 assert(handle != NULL);
 SC_HANDLE hService = OpenService(handle, SZSERVICENAME, SERVICE_ALL_ACCESS);
 assert(hService != NULL);
 DeleteService(hService);
}

 

void StartService()
{
 SC_HANDLE handle = ::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
 assert(handle != NULL);
 SC_HANDLE hService = OpenService(handle, SZSERVICENAME, SERVICE_ALL_ACCESS);
 assert(hService != NULL);
 StartService(hService, 0, NULL);
}

 

void StopService()
{
 SC_HANDLE handle = ::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
 assert(handle != NULL);
 SC_HANDLE hService = OpenService(handle, SZSERVICENAME, SERVICE_ALL_ACCESS);
 assert(hService != NULL);
 ControlService (hService, SERVICE_CONTROL_STOP, &servicestatus);
}

 

void WINAPI ServiceCtrlHandler(DWORD dwControl)
{
 switch (dwControl)
 {
  //下面虽然添加了暂停、继续等请求的处理代码,但没有实际作用
  //这是为什么呢?到了下面的TServiceMain函数里面就明白了...

 case SERVICE_CONTROL_PAUSE:
  servicestatus.dwCurrentState = SERVICE_PAUSE_PENDING;
  // TODO: add code to set dwCheckPoint & dwWaitHint
  // This value need to try a lot to confirm
  // ...
  ::SetServiceStatus(servicestatushandle, &servicestatus);
  // TODO: add code to pause the service
  // not called in this service
  // ...
  servicestatus.dwCurrentState = SERVICE_PAUSED;
  // TODO: add code to set dwCheckPoint & dwWaitHint to 0
  break;

 case SERVICE_CONTROL_CONTINUE:
  servicestatus.dwCurrentState = SERVICE_CONTINUE_PENDING;
  // TODO: add code to set dwCheckPoint & dwWaitHint
  ::SetServiceStatus(servicestatushandle, &servicestatus);
  // TODO: add code to unpause the service
  // not called in this service
  // ...
  servicestatus.dwCurrentState = SERVICE_RUNNING;
  // TODO: add code to set dwCheckPoint & dwWaitHint to 0
  break;

 case SERVICE_CONTROL_STOP:
  servicestatus.dwCurrentState = SERVICE_STOP_PENDING;
  // TODO: add code to set dwCheckPoint & dwWaitHint
  ::SetServiceStatus(servicestatushandle, &servicestatus);
  // TODO: add code to stop the service
  Stop();
  servicestatus.dwCurrentState = SERVICE_STOPPED;
  // TODO: add code to set dwCheckPoint & dwWaitHint to 0
  break;

 case SERVICE_CONTROL_SHUTDOWN:
  // TODO: add code for system shutdown
  // as quick as possible
  break;

 case SERVICE_CONTROL_INTERROGATE:
  // TODO: add code to set the service status
  // ...
  servicestatus.dwCurrentState = SERVICE_RUNNING;
  break;
 }
 ::SetServiceStatus(servicestatushandle, &servicestatus);
}

 

void WINAPI TServiceMain(DWORD argc, LPTSTR * argv)
{
 servicestatus.dwServiceType = SERVICE_WIN32;
 servicestatus.dwCurrentState = SERVICE_START_PENDING;
 servicestatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;//必须为STOP才能接受外部命令
 servicestatus.dwWin32ExitCode = 0;
 servicestatus.dwServiceSpecificExitCode = 0;
 servicestatus.dwCheckPoint = 0;
 servicestatus.dwWaitHint = 0;

 servicestatushandle =
  ::RegisterServiceCtrlHandler(SZSERVICENAME, ServiceCtrlHandler);
 if (servicestatushandle == (SERVICE_STATUS_HANDLE)0)
 {
  return;
 }

 bool bInitialized = false;
 Start();

 bInitialized = true;

 servicestatus.dwCheckPoint = 0;
 servicestatus.dwWaitHint = 0;
 servicestatus.dwCurrentState = SERVICE_RUNNING;

 ::SetServiceStatus(servicestatushandle, &servicestatus);


 //创建服务线程   服务完成的功能在这里调用
 HANDLE hThread = CreateThread(NULL, 0, RealService, NULL, 0, NULL);
 assert(hThread != NULL);
 CloseHandle(hThread);

 return;
}


void Start()
{
 LogEvent("Service Starting...");
}

 

void LogEvent(LPCTSTR pFormat, ...)
{
 TCHAR chMsg[256];
 HANDLE hEventSource;
 LPTSTR lpszStrings[1];
 va_list pArg;

 va_start(pArg, pFormat);
 _vstprintf(chMsg, pFormat, pArg);
 va_end(pArg);

 lpszStrings[0] = chMsg;

 if (1)
 {
  // Get a handle to use with ReportEvent().
  hEventSource = RegisterEventSource(NULL, SZSERVICENAME);
  if (hEventSource != NULL)
  {
   // Write to event log.
   ReportEvent(hEventSource, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, (LPCTSTR*) &lpszStrings[0], NULL);
   DeregisterEventSource(hEventSource);
  }
 }
 else
 {
  // As we are not running as a service, just write the error to the console.
  _putts(chMsg);
 }
}

 

void Stop()
{
 LogEvent("Service Stoped.");

 

DWORD WINAPI RealService(LPVOID lpvThread)
{
 //实现实际功能的地方
 return 1;
}