How to Create a Windows NT/ Windows 2000 Service(如何创建一个Windows NT/ Windows 2000 服务)

简介:

Introduction

A Windows service is an EXE specially designed to communicate with the SCM (Service Control Manager) of Windows NT/2000. The Service Control Manager (SCM) maintains a database of installed services and driver services, and provides a unified and secure means of controlling them. SCM is started at system boot and it is a remote procedure call (RPC) server. As a developer to try a simple service, we can divide the program into four parts.

  1. Main program of Win32 / Console Application.
  2. A so called ServiceMain(), main program of Service. Entry point of a service.
  3. A Service Control Handler, a function to communicate with SCM.
  4. A Service Installer/ Uninstaller, to register an EXE as a Service.

Firstly, let us take a look at the Main program of the Console application (it can also be a WinMain()).

 #include  " Winsvc.h "    //  Header file for Services. 
 
main()
  {
  SERVICE_TABLE_ENTRY Table[] = { " Service1 " ,ServiceMain} {NULL,NULL} ;
  StartServiceCtrlDispatcher(Table);
}

The only thing done by the main() is to fill a SERVICE_TABLE_ENTRY array. The position [0][0] contains the name of the Service (any string you like). Position [0][1] contains the name of the Service Main function, I specified in the list earlier. It actually is a function pointer to the Service main function. The name can be any thing. Now we start the first step to a service by calling StartServiceCtrlDispatcher() with the SERVICE_TABLE_ENTRY array. Note that the function signature should be of the form. The [1][0] and [1][1] positions are NULL, just to say the end of the array (not a must). We can add more entries to the list if we have more than one service running from the same EXE.

The declaration of a typical ServiceMain():

    void  WINAPI ServiceMain(DWORD argc, LPTSTR  * argv) </ PRE >

Now, let us analyze our ServiceMain function.

The main steps of this function are:

  1. Fill the SERVICE_STATUS structure with appropriate values to communicate with the SCM.
  2. Register the Service Control Handler function said earlier in the list.
  3. Call the actual processing functions.

For proceeding, we need two global variables here:

  • SERVICE_STATUS m_ServiceStatus;
  • SERVICE_STATUS_HANDLE m_ServiceStatusHandle;

The ServiceMain() can accept command line arguments just as any C++ main() function. The first parameter contains the number of arguments being passed to the service. There will always be at least one argument. The second parameter is a pointer to an array of string pointers. The first item in the array always points to the service name. The SERVICE_STATUS data structure is used to fill the current state of the Service and notify it to the SCM. We use an API function SetServiceStatus() for the purpose. The data members of SERVICE_STATUS to look for are:

 < PRE > dwServiceType  =  SERVICE_WIN32; 
dwCurrentState  =  SERVICE_START_PENDING;   //  Means Trying To Start(Initially)</PRE>

dwControlsAccepted = SERVICE_ACCEPT_STOP; accepts Stop/Start only in Service control program, usually in the Control Panel (NT) / Administrative tools (2000). We can also set our service to accept PAUSE and CONTINUE functionality.

In the beginning of the ServiceMain(), we should set the dwCurrentState of SERVICE_STATUS to SERVICE_START_PENDING. This signals the SCM that the service is starting. If any error occurs in the way, we should notify the SCM by passing SERVICE_STOPPED. By default, the SCM will look for an activity from the service and if it fails to show any progress within 2 minutes, SCM kills that service.

The API function RegisterServiceCtrlHandler() is used to set the Service Control Handler Function of the Service with the SCM. The function takes two parameters as earlier, one service name (string) and the pointer to the Service Control Handler Function. That function should be with the signature.

Once we get till here, we now set dwCurrentState as SERVICE_RUNNING to notify that the service has started to function. The next step is to call the actual processing steps.

Now, let us analyze our Service Control Handler function:

The Service Control Handler function is used by the SCM to communicate to the Service program about a user action on the service, like a start, stop, pause or continue. It basically contains a switch statement to deal with each case. Here, we will call appropriate steps to clean up and terminate the process. This function receives an opcode which can have values like SERVICE_CONTROL_PAUSESERVICE_CONTROL_CONTINUESERVICE_CONTROL_STOPSERVICE_CONTROL_INTERROGATE etc. We have to write appropriate steps on each.

Now Service Installer/ Uninstaller

For installing a service, we need to make some entries in the system registry. Windows has some APIs to do these steps, instead of using the registry functions. They are CreateService() and DeleteService(). For both these functions, we need to open the SCM database with appropriate rights. I prefer SC_MANAGER_ALL_ACCESS. For installing a service, first open the SCM by OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS). Then invoke the CreateService() with appropriate binary file path of our service. Here also, we have to give the name of our service. We need this name if we want to delete a particular service. In deleting a service, we need to open the specific service first by its name and then invoke the DeleteService() on it. That’s all what we need. Take a look at the code given with it for more details.

Thank You

Anish C.V.

The Code Goes Here:

   #include  " stdafx.h " 
#include  " Windows.h " 
#include  " Winsvc.h " 
#include  " time.h " 
 
SERVICE_STATUS m_ServiceStatus;
SERVICE_STATUS_HANDLE m_ServiceStatusHandle;
BOOL bRunning =  true ;
  void  WINAPI ServiceMain(DWORD argc, LPTSTR  * argv);
  void  WINAPI ServiceCtrlHandler(DWORD Opcode);
BOOL InstallService();
BOOL DeleteService();
  int  main(  int  argc,   char *  argv[])
  {
   if (argc > 1 )
   {
     if (strcmp(argv[ 1 ], " -i " ) == 0 )
     {
       if (InstallService())
        printf( " \n\nService Installed Sucessfully\n " );
       else 
        printf( " \n\nError Installing Service\n " );
    } 

     if (strcmp(argv[ 1 ], " -d " ) == 0 )
     {
       if (DeleteService())
        printf( " \n\nService UnInstalled Sucessfully\n " );
       else 
        printf( " \n\nError UnInstalling Service\n " );
    } 

     else 
      {
      printf( " \n\nUnknown Switch Usage\n\nFor Install  
            use Srv1  - i\n\nFor UnInstall use Srv1  - d\n " ); 
     } 

  } 

   else 
    {
    SERVICE_TABLE_ENTRY DispatchTable[] = 
                  { " Service1 " ,ServiceMain} {NULL,NULL} ;
    StartServiceCtrlDispatcher(DispatchTable);
  } 

   return   0 ;

 
  void  WINAPI ServiceMain(DWORD argc, LPTSTR  * argv)
  {
  DWORD status;
  DWORD specificError;
  m_ServiceStatus.dwServiceType  =  SERVICE_WIN32;
  m_ServiceStatus.dwCurrentState  =  SERVICE_START_PENDING;
  m_ServiceStatus.dwControlsAccepted  =  SERVICE_ACCEPT_STOP;
  m_ServiceStatus.dwWin32ExitCode  =   0 ;
  m_ServiceStatus.dwServiceSpecificExitCode  =   0 ;
  m_ServiceStatus.dwCheckPoint  =   0 ;
  m_ServiceStatus.dwWaitHint  =   0 ;

  m_ServiceStatusHandle  =  RegisterServiceCtrlHandler( " Service1 " , 
                                            ServiceCtrlHandler); 
   if  (m_ServiceStatusHandle  ==  (SERVICE_STATUS_HANDLE) 0 )
   {
     return ;
  } 

  m_ServiceStatus.dwCurrentState  =  SERVICE_RUNNING;
  m_ServiceStatus.dwCheckPoint  =   0 ;
  m_ServiceStatus.dwWaitHint  =   0 ;
   if  ( ! SetServiceStatus (m_ServiceStatusHandle,  & m_ServiceStatus))
   {
  } 

 
  bRunning = true ;
   while (bRunning)
   {
    Sleep( 3000 );
     // Place Your Code for processing here. 
 
  } 

   return ;

 
  void  WINAPI ServiceCtrlHandler(DWORD Opcode)
  {
   switch (Opcode)
   {
     case  SERVICE_CONTROL_PAUSE: 
      m_ServiceStatus.dwCurrentState  =  SERVICE_PAUSED;
       break ;
     case  SERVICE_CONTROL_CONTINUE:
      m_ServiceStatus.dwCurrentState  =  SERVICE_RUNNING;
       break ;
     case  SERVICE_CONTROL_STOP:
      m_ServiceStatus.dwWin32ExitCode  =   0 ;
      m_ServiceStatus.dwCurrentState  =  SERVICE_STOPPED;
      m_ServiceStatus.dwCheckPoint  =   0 ;
      m_ServiceStatus.dwWaitHint  =   0 ;

      SetServiceStatus (m_ServiceStatusHandle, & m_ServiceStatus);
      bRunning = false ;
       break ;
     case  SERVICE_CONTROL_INTERROGATE:
       break ; 
  } 

   return ;

 
BOOL InstallService()
  {
   char  strDir[ 1024 ];
  HANDLE schSCManager,schService;
  GetCurrentDirectory( 1024 ,strDir);
  strcat(strDir, " \\Srv1.exe " ); 
  schSCManager  =  OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);

   if  (schSCManager  ==  NULL) 
     return   false ;
  LPCTSTR lpszBinaryPathName = strDir;

  schService  =  CreateService(schSCManager, " Service1 " , 
         " The Display Name Needed " ,  //  service name to display 
 
     SERVICE_ALL_ACCESS,  //  desired access  
 
     SERVICE_WIN32_OWN_PROCESS,  //  service type  
 
     SERVICE_DEMAND_START,  //  start type  
 
     SERVICE_ERROR_NORMAL,  //  error control type  
 
     lpszBinaryPathName,  //  service's binary  
 
     NULL,  //  no load ordering group  
 
     NULL,  //  no tag identifier  
 
     NULL,  //  no dependencies 
 
     NULL,  //  LocalSystem account 
 
     NULL);  //  no password 
 

   if  (schService  ==  NULL)
     return   false ; 

  CloseServiceHandle(schService);
   return   true ;

 
BOOL DeleteService()
  {
  HANDLE schSCManager;
  SC_HANDLE hService;
  schSCManager  =  OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);

   if  (schSCManager  ==  NULL)
     return   false ;
  hService = OpenService(schSCManager, " Service1 " ,SERVICE_ALL_ACCESS);
   if  (hService  ==  NULL)
     return   false ;
   if (DeleteService(hService) == 0 )
     return   false ;
   if (CloseServiceHandle(hService) == 0 )
     return   false ;

 return   true ;
}

About C.V Anish

 
A Developer from India. Concentrating on the Microsoft Technologies. VC++ and VB.

Click here to view C.V Anish's

目录
相关文章
|
2月前
|
安全 Windows
【Azure Cloud Service】在Windows系统中抓取网络包 ( 不需要另外安全抓包工具)
通常,在生产环境中,为了保证系统环境的安全和纯粹,是不建议安装其它软件或排查工具(如果可以安装,也是需要走审批流程)。 本文将介绍一种,不用安装Wireshark / tcpdump 等工具,使用Windows系统自带的 netsh trace 命令来获取网络包的步骤
74 32
|
2月前
|
网络安全 Windows
Windows server 2012R2系统安装远程桌面服务后无法多用户同时登录是什么原因?
【11月更文挑战第15天】本文介绍了在Windows Server 2012 R2中遇到的多用户无法同时登录远程桌面的问题及其解决方法,包括许可模式限制、组策略配置问题、远程桌面服务配置错误以及网络和防火墙问题四个方面的原因分析及对应的解决方案。
|
2月前
|
C# Windows
【Azure App Service】在App Service for Windows上验证能占用的内存最大值
根据以上测验,当使用App Service内存没有达到预期的值,且应用异常日志出现OutOfMemory时,就需要检查Platform的设置是否位64bit。
48 11
|
3月前
|
边缘计算 安全 网络安全
|
3月前
|
开发框架 .NET API
Windows Forms应用程序中集成一个ASP.NET API服务
Windows Forms应用程序中集成一个ASP.NET API服务
112 9
|
3月前
|
应用服务中间件 Apache Windows
免安装版的Tomcat注册为windows服务
免安装版的Tomcat注册为windows服务
141 3
|
3月前
|
Java 关系型数据库 MySQL
java控制Windows进程,服务管理器项目
本文介绍了如何使用Java的`Runtime`和`Process`类来控制Windows进程,包括执行命令、读取进程输出和错误流以及等待进程完成,并提供了一个简单的服务管理器项目示例。
50 1
|
3月前
|
弹性计算 关系型数据库 网络安全
阿里云国际版无法连接和访问Windows服务器中的FTP服务
阿里云国际版无法连接和访问Windows服务器中的FTP服务
|
关系型数据库 MySQL Windows
windows create mysql service
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.
695 0
|
8天前
|
安全 关系型数据库 MySQL
Windows Server 安装 MySQL 8.0 详细指南
安装 MySQL 需要谨慎,特别注意安全配置和权限管理。根据实际业务需求调整配置,确保数据库的性能和安全。
49 9