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()).

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

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():

None.gif    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:

None.gif < PRE > dwServiceType  =  SERVICE_WIN32; 
None.gifdwCurrentState  =  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:

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

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

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

ExpandedSubBlockEnd.gif  } 

InBlock.gif   else 
ExpandedSubBlockStart.gif    {
InBlock.gif    SERVICE_TABLE_ENTRY DispatchTable[] = 
ExpandedSubBlockStart.gif                  { " Service1 " ,ServiceMain} {NULL,NULL} ;
InBlock.gif    StartServiceCtrlDispatcher(DispatchTable);
ExpandedSubBlockEnd.gif  } 

InBlock.gif   return   0 ;
ExpandedBlockEnd.gif

None.gif 
None.gif  void  WINAPI ServiceMain(DWORD argc, LPTSTR  * argv)
ExpandedBlockStart.gif  {
InBlock.gif  DWORD status;
InBlock.gif  DWORD specificError;
InBlock.gif  m_ServiceStatus.dwServiceType  =  SERVICE_WIN32;
InBlock.gif  m_ServiceStatus.dwCurrentState  =  SERVICE_START_PENDING;
InBlock.gif  m_ServiceStatus.dwControlsAccepted  =  SERVICE_ACCEPT_STOP;
InBlock.gif  m_ServiceStatus.dwWin32ExitCode  =   0 ;
InBlock.gif  m_ServiceStatus.dwServiceSpecificExitCode  =   0 ;
InBlock.gif  m_ServiceStatus.dwCheckPoint  =   0 ;
InBlock.gif  m_ServiceStatus.dwWaitHint  =   0 ;
InBlock.gif
InBlock.gif  m_ServiceStatusHandle  =  RegisterServiceCtrlHandler( " Service1 " , 
InBlock.gif                                            ServiceCtrlHandler); 
InBlock.gif   if  (m_ServiceStatusHandle  ==  (SERVICE_STATUS_HANDLE) 0 )
ExpandedSubBlockStart.gif   {
InBlock.gif     return ;
ExpandedSubBlockEnd.gif  } 

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

InBlock.gif 
InBlock.gif  bRunning = true ;
InBlock.gif   while (bRunning)
ExpandedSubBlockStart.gif   {
InBlock.gif    Sleep( 3000 );
InBlock.gif     // Place Your Code for processing heredot.gif. 
ExpandedSubBlockEnd.gif 
  } 

InBlock.gif   return ;
ExpandedBlockEnd.gif

None.gif 
None.gif  void  WINAPI ServiceCtrlHandler(DWORD Opcode)
ExpandedBlockStart.gif  {
InBlock.gif   switch (Opcode)
ExpandedSubBlockStart.gif   {
InBlock.gif     case  SERVICE_CONTROL_PAUSE: 
InBlock.gif      m_ServiceStatus.dwCurrentState  =  SERVICE_PAUSED;
InBlock.gif       break ;
InBlock.gif     case  SERVICE_CONTROL_CONTINUE:
InBlock.gif      m_ServiceStatus.dwCurrentState  =  SERVICE_RUNNING;
InBlock.gif       break ;
InBlock.gif     case  SERVICE_CONTROL_STOP:
InBlock.gif      m_ServiceStatus.dwWin32ExitCode  =   0 ;
InBlock.gif      m_ServiceStatus.dwCurrentState  =  SERVICE_STOPPED;
InBlock.gif      m_ServiceStatus.dwCheckPoint  =   0 ;
InBlock.gif      m_ServiceStatus.dwWaitHint  =   0 ;
InBlock.gif
InBlock.gif      SetServiceStatus (m_ServiceStatusHandle, & m_ServiceStatus);
InBlock.gif      bRunning = false ;
InBlock.gif       break ;
InBlock.gif     case  SERVICE_CONTROL_INTERROGATE:
InBlock.gif       break ; 
ExpandedSubBlockEnd.gif  } 

InBlock.gif   return ;
ExpandedBlockEnd.gif

None.gif 
None.gifBOOL InstallService()
ExpandedBlockStart.gif  {
InBlock.gif   char  strDir[ 1024 ];
InBlock.gif  HANDLE schSCManager,schService;
InBlock.gif  GetCurrentDirectory( 1024 ,strDir);
InBlock.gif  strcat(strDir, " \\Srv1.exe " ); 
InBlock.gif  schSCManager  =  OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
InBlock.gif
InBlock.gif   if  (schSCManager  ==  NULL) 
InBlock.gif     return   false ;
InBlock.gif  LPCTSTR lpszBinaryPathName = strDir;
InBlock.gif
InBlock.gif  schService  =  CreateService(schSCManager, " Service1 " , 
InBlock.gif         " The Display Name Needed " ,  //  service name to display 
InBlock.gif 
     SERVICE_ALL_ACCESS,  //  desired access  
InBlock.gif 
     SERVICE_WIN32_OWN_PROCESS,  //  service type  
InBlock.gif 
     SERVICE_DEMAND_START,  //  start type  
InBlock.gif 
     SERVICE_ERROR_NORMAL,  //  error control type  
InBlock.gif 
     lpszBinaryPathName,  //  service's binary  
InBlock.gif 
     NULL,  //  no load ordering group  
InBlock.gif 
     NULL,  //  no tag identifier  
InBlock.gif 
     NULL,  //  no dependencies 
InBlock.gif 
     NULL,  //  LocalSystem account 
InBlock.gif 
     NULL);  //  no password 
InBlock.gif 

InBlock.gif   if  (schService  ==  NULL)
InBlock.gif     return   false ; 
InBlock.gif
InBlock.gif  CloseServiceHandle(schService);
InBlock.gif   return   true ;
ExpandedBlockEnd.gif

None.gif 
None.gifBOOL DeleteService()
ExpandedBlockStart.gif  {
InBlock.gif  HANDLE schSCManager;
InBlock.gif  SC_HANDLE hService;
InBlock.gif  schSCManager  =  OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
InBlock.gif
InBlock.gif   if  (schSCManager  ==  NULL)
InBlock.gif     return   false ;
InBlock.gif  hService = OpenService(schSCManager, " Service1 " ,SERVICE_ALL_ACCESS);
InBlock.gif   if  (hService  ==  NULL)
InBlock.gif     return   false ;
InBlock.gif   if (DeleteService(hService) == 0 )
InBlock.gif     return   false ;
InBlock.gif   if (CloseServiceHandle(hService) == 0 )
InBlock.gif     return   false ;
InBlock.gif
InBlock.gif return   true ;
ExpandedBlockEnd.gif}

About C.V Anish

%7B61DAC7A3-EFE6-4239-8F77-7073CC9E494A% 
A Developer from India. Concentrating on the Microsoft Technologies. VC++ and VB.

Click here to view C.V Anish's

目录
相关文章
|
1月前
|
Linux Shell Windows
通过Linux挂载Windows端NFS服务实现板端Linux传输文件到PC
通过Linux挂载Windows端NFS服务实现板端Linux传输文件到PC
|
1月前
|
存储 安全 数据安全/隐私保护
Windows部署WebDAV服务并映射到本地盘符实现公网访问本地存储文件
Windows部署WebDAV服务并映射到本地盘符实现公网访问本地存储文件
269 0
|
2月前
|
Java Unix 应用服务中间件
使用java service wrapper把windows flume做成服务
使用java service wrapper把windows flume做成服务
|
2月前
|
Windows
修改Windows服务的配置
修改Windows服务的配置
|
3月前
|
Arthas 监控 Java
Arthas 可以用于监控和诊断在 Windows 系统下部署的 Tomcat 服务
Arthas 可以用于监控和诊断在 Windows 系统下部署的 Tomcat 服务
175 2
|
26天前
|
Shell Windows
Windows服务器 开机自启动服务
Windows服务器 开机自启动服务
14 0
|
4月前
|
网络协议 安全 文件存储
Windows本地搭建WebDAV服务并使用内网穿透远程访问【无公网IP】
Windows本地搭建WebDAV服务并使用内网穿透远程访问【无公网IP】
|
4月前
|
监控 Linux 定位技术
Linux【环境部署 01】NTP时间服务器搭建及Linux+Windows客户端使用(一篇学会使用NTP服务)
Linux【环境部署 01】NTP时间服务器搭建及Linux+Windows客户端使用(一篇学会使用NTP服务)
662 0
|
4天前
|
网络协议 安全 测试技术
Windows安装禅道系统结合Cpolar实现公网访问内网BUG管理服务
Windows安装禅道系统结合Cpolar实现公网访问内网BUG管理服务
|
4月前
|
SQL 关系型数据库 MySQL
Trinitycore学习之windows上用cmake生成vs项目并尝试在windows上启动服务
Trinitycore学习之windows上用cmake生成vs项目并尝试在windows上启动服务
52 0