Windows服务之实现对服务的控制管理

来源:互联网 发布:淘宝客商城源码 编辑:程序博客网 时间:2024/05/16 11:05

http://blog.csdn.net/devourheavens/article/details/7335472

本文是Devour Heavens撰写整理的关于windows服务的知识,所有资料均来自于msdn官方文档,欢迎转载。但是为了尊重原作者的劳动,请注明出处!谢谢!

实现对服务的控制和管理

服务程序编写完成后,还需要服务管理程序才可以运行。一种方法是使用系统的服务管理工具,另一种方法是使用服务管理API自行编写一个服务管理程序。服务管理程序为系统新建服务,负责启动停止服务程序,并负责管理服务程序的属性等。

 1.1  创建、删除服务

服务程序编写完成后,还不能运行服务。必须首先向系统注册服务。创建和删除服务可以通过sc.exe 来操作。系统提供了相关API实现类似的功能。

1. 关键API

(1) OpenSCManager。

获取当前系统中所有的进程的PID。函数原型如下:

SC_HANDLE WINAPI OpenSCManager(

LPCTSTR lpMachineName,  

 LPCTSTR lpDatabaseName,

DWORD dwDesiredAccess

);

msdn官方文档对OpenSCManager函数参数的说明:

Parameters

lpMachineName [in, optional]

The name of the target computer. If the pointer is NULL or points to an empty string, the function connects to the service control manager on the local computer.

lpDatabaseName [in, optional]

The name of the service control manager database. This parameter should be set to SERVICES_ACTIVE_DATABASE. If it is NULL, the SERVICES_ACTIVE_DATABASE database is opened by default.

dwDesiredAccess [in]

The access to the service control manager. For a list of access rights, see Service Security and Access Rights.

Before granting the requested access rights, the system checks the access token of the calling process against the discretionary access-control list of the security descriptor associated with the service control manager.

The SC_MANAGER_CONNECT access right is implicitly specified by calling this function.

Return value

If the function succeeds, the return value is a handle to the specified service control manager database.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

The following error codes can be set by the SCM. Other error codes can be set by the registry functions that are called by the SCM. 

Return code

Description

ERROR_ACCESS_DENIED

The requested access was denied.

ERROR_DATABASE_DOES_NOT_EXIST

The specified database does not exist.

.参数

lpMachineName:输入参数,机器名,如果是本机则使用NULL。

lpDatabaseName:输入参数,SCM数据库名,设置为NULL或设置为SERVICES_ACTIVE_DATABASE,效果等同。

dwDesiredAccess:输入参数,需要的权限,可设置为SC_MANAGER_ALL_ACCESS 、SC_MANAGER_CREATE_SERVICE、C_MANAGER_CONNECT等。

.返回值

SC_HANDLE类型,SCM的句柄。

(2) CreateService。

SC_HANDLE WINAPI CreateService(

SC_HANDLE hSCManager,

LPCTSTR lpServiceName,

LPCTSTR lpDisplayName,

DWORD dwDesiredAccess,

DWORD dwServiceType,

DWORD dwStartType,

DWORD dwErrorControl,

LPCTSTR lpBinaryPathName,

LPCTSTR lpLoadOrderGroup,

LPDWORD lpdwTagId,

LPCTSTR lpDependencies,

LPCTSTR lpServiceStartName,

LPCTSTR lpPassword

);

CreateService函数的参数很多,但是设置方法很简单,直接从参数名就大体可以知道参数的意义。

详情参看msdn官方文档:http://msdn.microsoft.com/en-us/library/windows/desktop/ms682450(v=vs.85).aspx

 .返回值

SC_HANDLE类型,服务的句柄。

 

(3) OpenService。

打开服务,获取服务句柄,函数原型如下:

SC_HANDLE WINAPI OpenService(SC_HANDLE hSCManager,

LPCTSTR lpServiceName,

DWORD dwDesiredAccess

);

(4) DeleteService。

删除服务,以服务句柄为参数,函数原型如下:

BOOL WINAPI DeleteService(

SC_HANDLE hService

);

2. 实例创建服务

本实例使用CreateService函数创建服务,使用OpenSCManager API函数获取当前系统的PID。

VOID SvcInstall(LPSTR szPath,LPSTR szServiceName)

{

    SC_HANDLE schSCManager;

    SC_HANDLE schService; 

    if(!GetModuleFileName( NULL, szPath, MAX_PATH ) )

    {

        printf("Cannot install service (%d)\n", GetLastError());

        return;

    } 

    // Get a handle to the SCM database.  

    schSCManager = OpenSCManager(

        NULL,                    // local computer

        NULL,                    // ServicesActive database

        SC_MANAGER_ALL_ACCESS);  // full access rights 

    if (NULL ==schSCManager)

    {

        printf("OpenSCManager failed (%d)\n", GetLastError());

        return;

    } 

    // Create the service 

    schService = CreateService(

        schSCManager,              // SCM database

        szServiceName,                   // name of service

        szServiceName,                   // 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

        szPath,                    // path to service's binary

        NULL,                      // no load ordering group

        NULL,                      // no tag identifier

        NULL,                      // no dependencies

        NULL,                      // LocalSystem account

        NULL);                     // no password 

    if (schService ==NULL)

    {

        printf("CreateService failed (%d)\n", GetLastError());

        CloseServiceHandle(schSCManager);

        return;

    }

    else printf("Service installedsuccessfully\n");  

    CloseServiceHandle(schService);

    CloseServiceHandle(schSCManager);

}

 3. 实例删除服务

本实例演示如何删除服务。首先调用OpenService函数打开服务,获得服务句柄,然后调用API函数DeleteService删除服务。

VOID DeleteSvc(LPSTR szServiceName)

{

    SC_HANDLE schSCManager;

    SC_HANDLE schService;

    SERVICE_STATUS ssStatus;  

    // Get a handle to the SCM database. 

    schSCManager = OpenSCManager(

        NULL,                    // local computer

        NULL,                    // ServicesActive database

        SC_MANAGER_ALL_ACCESS);  // full access rights 

    if (NULL ==schSCManager)

    {

        printf("OpenSCManager failed (%d)\n", GetLastError());

        return;

    } 

    // Get a handle to the service. 

    schService = OpenService(

        schSCManager,       // SCM database

        szServiceName,          // name of service

        DELETE);            // need delete access 

    if (schService ==NULL)

    {

        printf("OpenService failed (%d)\n", GetLastError());

        CloseServiceHandle(schSCManager);

        return;

    } 

    // Delete the service. 

    if (!DeleteService(schService) )

    {

        printf("DeleteService failed (%d)\n", GetLastError());

    }

    else printf("Service deletedsuccessfully\n"); 

   CloseServiceHandle(schService);

    CloseServiceHandle(schSCManager);

}

1.2 启动、停止服务,向服务发送控制请求

 系统同样提供了相关的API来实现启动、停止服务,向服务发送控制请求等操作,服务的控制请求时服务控制服务的主要方法。在服务管理程序向服务程序发送了控制码后,服务注册的服务程序的控制处理函数就会被调用,并由其决定如何响应。

1.关键API

(1) StartService。

BOOL WINAPI StartService(

  __in      SC_HANDLE hService, 

 __in      DWORD dwNumServiceArgs, 

 __in_opt  LPCTSTR *lpServiceArgVectors

);

.参数

hService为服务句柄,后两个参数为服务主函数的参数,可以设置为NULL。

.返回值

返回值表示是否成功。下面是具体的返回值含义。

 

Return code

Description

ERROR_ACCESS_DENIED

The handle does not have the SERVICE_START access right.

ERROR_INVALID_HANDLE

The handle is invalid.

ERROR_PATH_NOT_FOUND

The service binary file could not be found.

ERROR_SERVICE_ALREADY_RUNNING

An instance of the service is already running.

ERROR_SERVICE_DATABASE_LOCKED

The database is locked.

ERROR_SERVICE_DEPENDENCY_DELETED

The service depends on a service that does not exist or has been marked for deletion.

ERROR_SERVICE_DEPENDENCY_FAIL

The service depends on another service that has failed to start.

ERROR_SERVICE_DISABLED

The service has been disabled.

ERROR_SERVICE_LOGON_FAILED

The service did not start due to a logon failure. This error occurs if the service is configured to run under an account that does not have the "Log on as a service" right.

ERROR_SERVICE_MARKED_FOR_DELETE

The service has been marked for deletion.

ERROR_SERVICE_NO_THREAD

A thread could not be created for the service.

ERROR_SERVICE_REQUEST_TIMEOUT

The process for the service was started, but it did not call StartServiceCtrlDispatcher or the thread that called StartServiceCtrlDispatcher may be blocked in a control handler function.

 

(2)ControlService。

向服务发送控制请求码。并获取服务状态。

BOOL WINAPI ControlService( 

 __in   SC_HANDLE hService, 

 __in   DWORD dwControl, 

 __out  LPSERVICE_STATUS lpServiceStatus

);

.参数hService为服务句柄,dwCount为控制码,lpServiceStatus为返回的服务状态。

如果需要停止服务,需要使用ControlService向服务发送SERVICE_CONTROL_STOP控制码。

2.实例启动服务

本实例使用StartService启动服务。代码中使用QueryServiceStatusEx API 函数,获取服务的当前状态。

VOID  StartSvc(LPSTR szSvcName)

{

   SERVICE_STATUS_PROCESS ssStatus;

   DWORD dwOldCheckPoint;

   DWORD dwStartTickCount;

   DWORD dwWaitTime;

   DWORD dwBytesNeeded; 

   // Get a handle to the SCM database.  

   schSCManager = OpenSCManager(

       NULL,                    // localcomputer

       NULL,                    //servicesActive database

       SC_MANAGER_ALL_ACCESS);  // fullaccess rights  

   if (NULL == schSCManager)

    {

       printf("OpenSCManager failed (%d)\n", GetLastError());

       return;

    } 

   // Get a handle to the service. 

   schService = OpenService(

       schSCManager,         // SCMdatabase

       szSvcName,            // name ofservice

       SERVICE_ALL_ACCESS);  // fullaccess  

   if (schService == NULL)

    {

       printf("OpenService failed (%d)\n", GetLastError());

       CloseServiceHandle(schSCManager);

       return;

   }     

   // Check the status in case the service is not stopped.  

   if (!QueryServiceStatusEx(

           schService,                     //handle to service

           SC_STATUS_PROCESS_INFO,         //information level

           (LPBYTE) &ssStatus,            // address of structure

           sizeof(SERVICE_STATUS_PROCESS), // size of structure

           &dwBytesNeeded ) )             // size needed if buffer is too small

    {

       printf("QueryServiceStatusEx failed (%d)\n", GetLastError());

       CloseServiceHandle(schService);

       CloseServiceHandle(schSCManager);

       return;

    } 

   // Check if the service is already running. It would be possible

   // to stop the service here, but for simplicity this example justreturns.  

   if(ssStatus.dwCurrentState != SERVICE_STOPPED &&ssStatus.dwCurrentState != SERVICE_STOP_PENDING)

    {

       printf("Cannot start the service because it is alreadyrunning\n");

       CloseServiceHandle(schService);

       CloseServiceHandle(schSCManager);

       return;

    } 

   // Save the tick count and initial checkpoint. 

    dwStartTickCount = GetTickCount();

   dwOldCheckPoint = ssStatus.dwCheckPoint; 

   // Wait for the service to stop before attempting to start it. 

   while (ssStatus.dwCurrentState == SERVICE_STOP_PENDING)

    {

       // Do not wait longer than the wait hint. A good interval is

       // one-tenth of the wait hint but not less than 1 second 

       // and not more than 10 seconds.  

       dwWaitTime = ssStatus.dwWaitHint / 10; 

       if( dwWaitTime < 1000 )

           dwWaitTime = 1000;

       else if ( dwWaitTime > 10000 )

           dwWaitTime = 10000; 

       Sleep( dwWaitTime ); 

       // Check the status until the service is no longer stop pending.  

       if (!QueryServiceStatusEx(

               schService,                     // handle to service

                SC_STATUS_PROCESS_INFO,         // information level

                (LPBYTE) &ssStatus,             // address of structure

                sizeof(SERVICE_STATUS_PROCESS),// size of structure

                &dwBytesNeeded ) )              // size needed if buffer is toosmall

       {

           printf("QueryServiceStatusEx failed (%d)\n", GetLastError());

           CloseServiceHandle(schService);

           CloseServiceHandle(schSCManager);

           return;

       } 

       if ( ssStatus.dwCheckPoint > dwOldCheckPoint )

       {

           // Continue to wait and check. 

           dwStartTickCount = GetTickCount();

           dwOldCheckPoint = ssStatus.dwCheckPoint;

       }

       else

       {

           if(GetTickCount()-dwStartTickCount > ssStatus.dwWaitHint)

           {

                printf("Timeout waitingfor service to stop\n");

                CloseServiceHandle(schService);

               CloseServiceHandle(schSCManager);

                return;

           }

       }

    } 

   // Attempt to start the service. 

   if (!StartService(

           schService,  // handle to service

           0,           // number ofarguments

           NULL) )      // no arguments

    {

       printf("StartService failed (%d)\n", GetLastError());

       CloseServiceHandle(schService);

       CloseServiceHandle(schSCManager);

       return;

    }

   else printf("Service start pending...\n");  

   // Check the status until the service is no longer start pending.  

   if (!QueryServiceStatusEx(

           schService,                     //handle to service

           SC_STATUS_PROCESS_INFO,         //info level

           (LPBYTE) &ssStatus,            // address of structure

           sizeof(SERVICE_STATUS_PROCESS), // size of structure

           &dwBytesNeeded ) )             // if buffer too small

    {

       printf("QueryServiceStatusEx failed (%d)\n", GetLastError());

       CloseServiceHandle(schService);

       CloseServiceHandle(schSCManager);

       return;

    } 

   // Save the tick count and initial checkpoint. 

   dwStartTickCount = GetTickCount();

   dwOldCheckPoint = ssStatus.dwCheckPoint; 

   while (ssStatus.dwCurrentState == SERVICE_START_PENDING)

    {

       // Do not wait longer than the wait hint. A good interval is

       // one-tenth the wait hint, but no less than 1 second and no

       // more than 10 seconds.  

       dwWaitTime = ssStatus.dwWaitHint / 10; 

       if( dwWaitTime < 1000 )

           dwWaitTime = 1000;

       else if ( dwWaitTime > 10000 )

           dwWaitTime = 10000; 

       Sleep( dwWaitTime ); 

       // Check the status again.  

       if (!QueryServiceStatusEx(

           schService,             // handleto service

           SC_STATUS_PROCESS_INFO, // info level

           (LPBYTE) &ssStatus,            // address of structure

           sizeof(SERVICE_STATUS_PROCESS), // size of structure

           &dwBytesNeeded ) )             // if buffer too small

       {

           printf("QueryServiceStatusEx failed (%d)\n", GetLastError());

           break;

       } 

       if ( ssStatus.dwCheckPoint > dwOldCheckPoint )

       {

           // Continue to wait and check.

 

           dwStartTickCount = GetTickCount();

           dwOldCheckPoint = ssStatus.dwCheckPoint;

       }

       else

       {

           if(GetTickCount()-dwStartTickCount > ssStatus.dwWaitHint)

           {

                // No progress made within thewait hint.

                break;

           }

       }

    }

 

   // Determine whether the service is running. 

   if (ssStatus.dwCurrentState == SERVICE_RUNNING)

    {

       printf("Service started successfully.\n");

    }

   else

    {

       printf("Service not started. \n");

       printf("  Current State:%d\n", ssStatus.dwCurrentState);

       printf("  Exit Code:%d\n", ssStatus.dwWin32ExitCode);

       printf("  Check Point:%d\n", ssStatus.dwCheckPoint);

       printf("  Wait Hint:%d\n", ssStatus.dwWaitHint);

    } 

   CloseServiceHandle(schService);

   CloseServiceHandle(schSCManager);

3.实例向服务发送控制请求

ControlSvcService函数实现了对服务的控制。先根据用户输入的控制码,设置存取权限,然后调用OpenService API打开服务,之后调用ControlService服务向服务发送控制码。

BOOL ControlSvcService(DWORD fdwControl)

{

         SERVICE_STATUSssStatus;

         DWORDfdwAccess;

         DWORDdwStartTickCount, dwWaitTime; 

         //Access

         switch(fdwControl)

         {

         caseSERVICE_CONTROL_STOP:

                   fdwAccess= SERVICE_STOP;

                   break;

         caseSERVICE_CONTROL_PAUSE:

         caseSERVICE_CONTROL_CONTINUE:

                  fdwAccess = SERVICE_PAUSE_CONTINUE;

                   break;

         caseSERVICE_CONTROL_INTERROGATE:

                   fdwAccess= SERVICE_INTERROGATE;

                   break;

         default:

                   fdwAccess= SERVICE_INTERROGATE;

         } 

         //打开服务

         schService= OpenService(

                   schSCManager,        // SCManager 句柄

                   szServiceName,                 // 服务名

                   fdwAccess);          // 存取权限

         if(schService == NULL)

         {

                   printf("OpenServicefailed (%d)\n", GetLastError());

                   returnFALSE;

         } 

         //发送控制码

         if(! ControlService(

                   schService,   // 服务的句柄

                   fdwControl,   // 控制码

                   &ssStatus))  // 状态

         {

                   printf("ControlServicefailed (%d)\n", GetLastError());

                   returnFALSE;

         } 

         //显示状态

         printf("\nStatusof Sample_Srv: \n");

         printf("  Service Type: 0x%x\n",ssStatus.dwServiceType);

         printf("  Current State: 0x%x\n",ssStatus.dwCurrentState);

         printf("  Controls Accepted: 0x%x\n",

                   ssStatus.dwControlsAccepted);

         printf("  Exit Code: %d\n",ssStatus.dwWin32ExitCode);

         printf("  Service Specific Exit Code: %d\n",

                   ssStatus.dwServiceSpecificExitCode);

         printf("  Check Point: %d\n",ssStatus.dwCheckPoint);

         printf("  Wait Hint: %d\n", ssStatus.dwWaitHint); 

         returnTRUE;

}

3.实例停止服务运行

 

VOID  DoStopSvc(LPSTR szSvcName )

{

   SERVICE_STATUS_PROCESS ssp;

   DWORD dwStartTime = GetTickCount();

   DWORD dwBytesNeeded;

   DWORD dwTimeout = 30000; // 30-second time-out

   DWORD dwWaitTime; 

   // Get a handle to the SCM database.  

   schSCManager = OpenSCManager(

       NULL,                    // localcomputer

       NULL,                    //ServicesActive database

       SC_MANAGER_ALL_ACCESS);  // fullaccess rights 

   if (NULL == schSCManager)

    {

       printf("OpenSCManager failed (%d)\n", GetLastError());

       return;

    } 

   // Get a handle to the service. 

   schService = OpenService(

       schSCManager,         // SCMdatabase

       szSvcName,            // name ofservice

       SERVICE_STOP |

       SERVICE_QUERY_STATUS |

       SERVICE_ENUMERATE_DEPENDENTS);   

   if (schService == NULL)

    {

       printf("OpenService failed (%d)\n", GetLastError());

       CloseServiceHandle(schSCManager);

       return;

   }     

   // Make sure the service is not already stopped. 

   if ( !QueryServiceStatusEx(

           schService,

           SC_STATUS_PROCESS_INFO,

            (LPBYTE)&ssp,

           sizeof(SERVICE_STATUS_PROCESS),

           &dwBytesNeeded ) )

    {

       printf("QueryServiceStatusEx failed (%d)\n", GetLastError());

       goto stop_cleanup;

    } 

   if ( ssp.dwCurrentState == SERVICE_STOPPED )

    {

       printf("Service is already stopped.\n");

       goto stop_cleanup;

    } 

   // If a stop is pending, wait for it. 

   while ( ssp.dwCurrentState == SERVICE_STOP_PENDING )

    {

       printf("Service stop pending...\n");

 

       // Do not wait longer than the wait hint. A good interval is

       // one-tenth of the wait hint but not less than 1 second 

       // and not more than 10 seconds.  

       dwWaitTime = ssp.dwWaitHint / 10; 

       if( dwWaitTime < 1000 )

           dwWaitTime = 1000;

       else if ( dwWaitTime > 10000 )

           dwWaitTime = 10000; 

       Sleep( dwWaitTime ); 

       if ( !QueryServiceStatusEx(

                 schService,

                 SC_STATUS_PROCESS_INFO,

                 (LPBYTE)&ssp,

                sizeof(SERVICE_STATUS_PROCESS),

                 &dwBytesNeeded ) )

       {

           printf("QueryServiceStatusEx failed (%d)\n", GetLastError());

           goto stop_cleanup;

       } 

       if ( ssp.dwCurrentState == SERVICE_STOPPED )

       {

           printf("Service stopped successfully.\n");

           goto stop_cleanup;

       } 

       if ( GetTickCount() - dwStartTime > dwTimeout )

       {

            printf("Service stop timedout.\n");

           goto stop_cleanup;

       }

    } 

   // If the service is running, dependencies must be stopped first. 

   StopDependentServices(schService); 

   // Send a stop code to the service. 

   if ( !ControlService(

           schService,

           SERVICE_CONTROL_STOP,

           (LPSERVICE_STATUS) &ssp ) )

    {

       printf( "ControlService failed (%d)\n", GetLastError() );

       goto stop_cleanup;

    } 

   // Wait for the service to stop. 

   while ( ssp.dwCurrentState != SERVICE_STOPPED )

    {

       Sleep( ssp.dwWaitHint );

       if ( !QueryServiceStatusEx(

                schService,

                SC_STATUS_PROCESS_INFO,

                (LPBYTE)&ssp,

               sizeof(SERVICE_STATUS_PROCESS),

                &dwBytesNeeded ) )

       {

           printf( "QueryServiceStatusEx failed (%d)\n", GetLastError());

           goto stop_cleanup;

       } 

       if ( ssp.dwCurrentState == SERVICE_STOPPED )

           break; 

       if ( GetTickCount() - dwStartTime > dwTimeout )

       {

           printf( "Wait timed out\n" );

           goto stop_cleanup;

       }

    }

   printf("Service stopped successfully\n"); 

stop_cleanup:

   CloseServiceHandle(schService);

   CloseServiceHandle(schSCManager);

BOOL  StopDependentServices(SC_HANDLE schService)

{

   DWORD i;

   DWORD dwBytesNeeded;

   DWORD dwCount; 

   LPENUM_SERVICE_STATUS  lpDependencies = NULL;

   ENUM_SERVICE_STATUS     ess;

   SC_HANDLE               hDepService;

   SERVICE_STATUS_PROCESS  ssp; 

   DWORD dwStartTime = GetTickCount();

   DWORD dwTimeout = 30000; // 30-second time-out 

   // Pass a zero-length buffer to get the required buffer size.

   if ( EnumDependentServices( schService, SERVICE_ACTIVE,

        lpDependencies, 0, &dwBytesNeeded, &dwCount ) )

    {

        // If the Enum call succeeds, then there are no dependent

        // services, so do nothing.

        return TRUE;

    }

   else

    {

       if ( GetLastError() != ERROR_MORE_DATA )

           return FALSE; // Unexpected error

 

       // Allocate a buffer for the dependencies.

       lpDependencies = (LPENUM_SERVICE_STATUS) HeapAlloc(

           GetProcessHeap(), HEAP_ZERO_MEMORY, dwBytesNeeded ); 

       if ( !lpDependencies )

           return FALSE; 

       __try {

           // Enumerate the dependencies.

           if ( !EnumDependentServices( schService, SERVICE_ACTIVE,

                lpDependencies, dwBytesNeeded,&dwBytesNeeded,

                &dwCount ) )

           return FALSE; 

           for ( i = 0; i < dwCount; i++ )

           {

                ess = *(lpDependencies + i);

                // Open the service.

                hDepService = OpenService(schSCManager,

                   ess.lpServiceName,

                   SERVICE_STOP |SERVICE_QUERY_STATUS ); 

                if ( !hDepService )

                   return FALSE; 

                __try {

                   // Send a stop code.

                    if ( !ControlService(hDepService,

                           SERVICE_CONTROL_STOP,

                            (LPSERVICE_STATUS)&ssp ) )

                    return FALSE; 

                    // Wait for the service tostop.

                    while ( ssp.dwCurrentState!= SERVICE_STOPPED )

                    {

                        Sleep( ssp.dwWaitHint);

                        if (!QueryServiceStatusEx(

                                hDepService,

                               SC_STATUS_PROCESS_INFO,

                               (LPBYTE)&ssp,

                               sizeof(SERVICE_STATUS_PROCESS),

                               &dwBytesNeeded ) )

                        return FALSE; 

                        if ( ssp.dwCurrentState== SERVICE_STOPPED )

                            break; 

                        if ( GetTickCount() -dwStartTime > dwTimeout )

                            return FALSE;

                    }

                }

                __finally

                {

                    // Always release theservice handle.

                    CloseServiceHandle(hDepService );

                }

           }

       }

       __finally

       {

           // Always free theenumeration buffer.

           HeapFree( GetProcessHeap(), 0, lpDependencies );

       }

    }

   return TRUE;

1.3 管理服务状态、配置服务、服务的依赖关系

1.管理服务状态

服务状态信息是了解服务运行情况的关键。一是服务管理程序再对服务进行操作时需要判断服务状态,二是服务程序本身也需要根据服务状态来决定相关操作。管理服务状态涉及QueryServiceStatusEx和SetServiceStatus等API函数,以及SERVICE_STATUS和SERVICE_STATUS_PROCESS结构体。

(1)QueryServiceStatus。

获取服务运行状态,函数原型如下 :

BOOL WINAPI QueryServiceStatus( 

__in   SC_HANDLE hService, 

__out  LPSERVICE_STATUS lpServiceStatus

);

参数hService是服务句柄,lpServiceStatus指向保存服务状态信息的SERVICE_STATUS结构的指针变量,返回值表示是否成功。

(2)SetServiceStatus。

设置服务运行状态,函数原型如下:

BOOL WINAPI SetServiceStatus( 

 __in  SERVICE_STATUS_HANDLE hServiceStatus,

  __in  LPSERVICE_STATUS lpServiceStatus

);

参数与返回值意义与QueryServiceStatusEx类似。

(3)SERVICE_STATUS结构。

typedef struct _SERVICE_STATUS {

 DWORD dwServiceType; 

 DWORD dwCurrentState; 

 DWORD dwControlsAccepted; 

 DWORD dwWin32ExitCode; 

 DWORD dwServiceSpecificExitCode;

 DWORD dwCheckPoint; 

 DWORD dwWaitHint;

} SERVICE_STATUS, *LPSERVICE_STATUS;

结构的dwCurrentState表示服务状态,其值可能是SERVICE_CONTINUE_PENDING,SERVICE_PAUSE_PENDING,SERVICE_PAUSED,SERVICE_RUNNING,SERVICE_START_PENDING,SERVICE_STOP_PENDING,SERVICE_STOPPED。

(4)QueryServiceStatusEx。

与QueryServiceStatus不同,除了可以获得服务信息外,还可以获得服务进程的有关信息,如PID等。

BOOL WINAPI QueryServiceStatusEx( 

 __in       SC_HANDLE hService, 

 __in       SC_STATUS_TYPE InfoLevel,

 __out_opt  LPBYTE lpBuffer,

 __in       DWORD cbBufSize, 

 __out      LPDWORD pcbBytesNeeded

);

如果参数InfoLevel设置为SC_STATUS_PROCESS_INFO常量,则lpBuffer应为指向SERVICE_STATUS_PROCESS结构体变量的指针,cbBufSize为lpBuffer指向缓冲区的大小,pcbBytesNeeded返回需要的缓冲区大小。

(5)SERVICE_STATUS_PROCESS。

typedefstruct _SERVICE_STATUS_PROCESS {

  DWORD dwServiceType;

  DWORD dwCurrentState;

  DWORD dwControlsAccepted;

  DWORD dwWin32ExitCode;

  DWORD dwServiceSpecificExitCode;

  DWORD dwCheckPoint;

  DWORD dwWaitHint;

  DWORD dwProcessId;

  DWORD dwServiceFlags;

}SERVICE_STATUS_PROCESS, *LPSERVICE_STATUS_PROCESS;

2.配置服务

在创建服务后,仍然可以修改服务的属性,比如可执行程序的路径等。获取和设置服务配置使用API函数QueryServiceConfig、QueryServiceConfig2、ChangeServiceConfig、ChangeServiceConfig2和结构体QUERY_SERVICE_CONFIG。

3.服务的依赖关系

服务与服务之间所存在的依赖关系是指一个服务的运行需要其他服务的支持,一个服务也可以是其他服务的依赖,可以通过服务属性参看服务的依存关系。
EnumDependentServices API函数可以列举依赖于一个特定服务的所有服务。

 

阅读全文
0 0