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

C 制作Windows service服务系列三--制作可控制界面的Windows服务 windows service 阅读详情

 本文是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函数可以列举依赖于一个特定服务的所有服务。

 

 

 

 

 

 

 

 

VC++6.0 Windows服务管理实战指南 本文还有配套的精品资源,点击获取 简介:VC++6.0是一款由Microsoft推出的经典C++编程工具,广泛用于Windows系统开发。本文章深入讲解了如何使用VC++6.0创建、控制和管理Windows服务。内容包括Windows服务概念、VC++6.0项目设置、服务控制接口实现、服务控制处理函数、服务启动/停止逻辑、安装/卸载服务的方法,以及服务控制API的使用。通过... 阅读详情

相关推荐

C#实现ServiceController类控制Windows服务的示例代码

ServiceController类是.NET Framework中用于与Windows服务进行交互的一个类。它允许开发者控制Windows服务的状态,包括启动、停止和重启服务,同时还能查询服务的状态和其它相关信息。这使得在.NET应用程序中实现服务管理功能成为可能,对于维护系统稳定运行和进行自动化运维有着极其重要的作用。在.NET Framework中,ServiceControllerStatus枚举定义了一系列服务可能的状态,这些状态包括但不限于:Stopped。

weixin_35706067的博客 1425

C/C++ Windows API——枚举服务

// EnumServiceDemo.cpp : 定义控制台应用程序的入口点。 //#include "stdafx.h" #include <Windows.h>int main() { /* 函数建立了一个到服务控制管理器的连接,并打开指定的数据库。 _Must_inspect_result_ WINADVAPI SC_HANDLE WINAPI OpenSCManage

司马懿的西山居 3963

windows api实现停止并禁用系统服务

输入一个服务名,调用该函数能够实现停止并禁用该服务

SC命令学习

SC命令学习一、SC命令是用来和NT服务控制器和服务进行通讯的命令行程序用法: sc [command] [service name] ...1.server:格式为//ServerName,若省略此项,则默认是本地2.command:命令 SC命令必须和其它命令结合使用。常用的有:query,qc,config,start,stop, pause,continue等3.service n

人生如棋 5946

易语言模块ProcessInfo.rar

易语言模块ProcessInfo.rar 易语言模块ProcessInfo.rar 易语言模块ProcessInfo.rar 易语言模块ProcessInfo.rar 易语言模块ProcessInfo.rar 易语言模块ProcessInfo.rar

从Google到LLVM:5种主流clang-format预设风格横向对比(含代码对比图)

本文横向对比了LLVM、Google、Chromium、Mozilla和WebKit五种主流的clang-format预设代码风格。通过同一段C++代码的格式化效果对比图,直观展示了它们在指针对齐、大括号换行、缩进等关键细节上的差异,并提供了基于团队背景与项目基因的选型决策指南。

weixin_28828243的博客 444

SC介绍和教程

写这个东西的目的在于让大家了解一下SC这个服务管理程序的使用,另一方面也是为了让大家更进一步的了解到NT,2000的服务的一些基础问题,如果有时 间,希望大家好好看看。再来结合起上一次如何打开termservice服务的那篇文章,在服务方面大家应该比较了解了。用这个东西就可以删除在别人机器 里留下的如ffsniffer, sksockerver这些东西,不用再担心,装上了删除不了。但是毕竟这个东西

心静思远 1520

YOLOv8损失函数升级:从CIoU到Wise-IoU v3的实战调优与避坑指南

本文详细介绍了如何将YOLOv8的损失函数从CIoU升级到Wise-IoU v3,以提升目标检测性能,特别是在小目标检测和样本不均衡场景下的表现。通过实战调优步骤和避坑指南,帮助开发者有效应用Wise-IoU v3的动态聚焦机制和单调性控制,显著提升模型精度和训练稳定性。

weixin_33737774的博客 590

SC命令详解

SC命令详解 SC命令是用来和NT服务控制器和服务进行通讯的命令行程序介绍SC,SC QC,and SC QUERY SC使用这样的语法: 1. SC [Servername] command Servicename [Optionname= Optionvalues] 2. SC [command] 这里使用第一种语法使用SC,使用第二种语法显示帮助。 下面介绍各种参数。 Servername 可选择:可以使用双斜线,如////myserver,也可以是////192.168.0.1来操作远程计算机。如果

永不放弃的地盘 4677

Cadence Virtuoso里搞定斩波运放AC仿真:PSS+PAC保姆级设置避坑指南

然而,当工程师们尝试在Cadence Virtuoso环境中对这种特殊结构进行AC特性分析时,往往会遇到传统AC仿真方法失效的困境——这正是PSS(Periodic Steady-State)与PAC(Periodic AC)仿真组合大显身手的场景。实际项目中我们常采用"先快后精"的两步法:先用快速设置确认大体趋势,再针对关键频段进行精细仿真。例如某次设计迭代中,将harmonics从10增加到20后,发现在1MHz处的相位裕度估算误差达15°,这解释了之前样机测试时的振荡问题。

weixin_33508411的博客 452

【数据库】银行/信贷业务测试工作中涉及的数据库表格

银行/信贷业务测试工作中涉及的数据库表格,金融信贷测试人必看!

孤之鹜的博客 1172

ReactOS服务控制管理器:Windows服务的开源实现

在现代操作系统中,服务(Service)是运行在后台的应用程序,它们通常没有用户界面,但为系统和其他应用程序提供关键功能。Windows服务控制管理器(Service Control Manager,SCM)是Windows操作系统的核心组件,负责管理所有系统服务的生命周期。ReactOS作为一个开源的Windows兼容操作系统,完整实现了SCM的功能,为开发者提供了深入了解Windows服务机制...

gitblog_00268的博客 633

Halcon实战:5个工业质检案例教你玩转机器视觉(附完整代码)

本文通过5个工业质检实战案例,详细拆解了如何运用Halcon视觉软件库解决精密测量、包装检测、字符识别、透明物缺陷检测及深度学习质检等复杂问题。每个案例均提供完整代码与核心思路,旨在帮助工程师掌握从问题分析到方案落地的系统方法论,提升机器视觉项目的实战能力与鲁棒性。

nut55的博客 261

Windows Service服务程序的原理及实现(1)实现对服务的控制和管理

上一篇文章《Windows Service服务程序(0)服务主函数 & 控制处理函数》对Windows服务开发做了初步讲解。服务编写完成后,还需要服务管理程序才可以运行。一种方式是上篇文章中介绍的使用系统服务管理工具,如sc.exe等;另一种方式是使用Windows服务管理API自行编写服务管理程序。

机器学习 1万+

uniapp - 详细实现移动端公众号 H5 网页授权登录流程及示例代码,申请测试公众号全流程及本地调试无需部署上线服务器就能直接调起微信登陆授权页面,手机移动端h5公众号页面利用微登录拿到用户数据!

uni-app,微信公众号,h5网页,uniapp网页端,手机端H5公众号页面,微信网页登陆,uniApp详细实现公众号的登录,微信授权第三方网站登录,流程及逻辑详细教程,OAuth2.0,公众号网页授权,微信网页授权通过code换取网页授权,redirect_url,参数错误,解决,报错,无法调起,如何申请测试公众号,微信公众平台测试号的申请与使用,获取用户openid手机号昵称头像,利用测试号实现本地调试微信登录授权,本地无法调试怎么办,测试公众号,在开发环境下怎么测试,用项目本地ip地址,微信公众号平

🏆 前端领域优质创作者 5063

Python李峋同款跳动的爱心(完整代码)

Python语言实现李峋同款可写字版跳动的爱心的完整代码。

AIGC 4万+

实现Windows服务并安装,控制

转自:http://blog.youkuaiyun.com/yincheng01/article/details/7079574 我们进行Windows编程的时候,经常涉及到Windows服务编程,针对Windows服务我们该怎么编程呢, 我们先来实现一个Windows服务并实现之,请见注释代码分析。 view plainprint? /* 头文件 */

踏雪无痕 1621

通过Power Platform自定义D365 CE 业务需求 - 4. 使用Power Automate

Power Automate构建块Power Automate中的连接器流的类型和用途流中的动态值和表达式使用变量、循环和条件在Power Automate中处理审批业务场景、用例和实现Power Virtual Agent的概念Power Virtual Agent的构建块配置Power Virtual Agent示例在公共网站/门户中部署Power Virtual Agent业务场景、用例和实现。

Martin-Mei的博客 560

怎样用sc命令运行服务器,windows中的sc控制服务命令

SC的语法SC [Servername] command Servicename [Optionname= Optionvalues]Servername 远程服务器名称,可选,使用双斜线如\\192.168.1.223来操作远程计算机。在本地操作省略该参数Command:SC命令的具体操作命令,可以使用以下命令:config:改变一个服务的配置如sc config Servicename sta...

weixin_32645721的博客 2519

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

WINDOWS服务开发

1.查看系统日志:控制面板\所有控制面板项\管理工具\计算机管理 2.windows服务的实现: 资料:msdn->system service->services. http://msdn.microsoft.com/en-us/library/windows/desktop/ms685141(v=vs.85).aspx demo:http://msdn.microsoft.com/en-

狂奔之林的博客 854

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

用Vc6写Windows 服务

 // ServiceTest.cpp : Defines the entry point for the console application.//#include "stdafx.h"#include #ifdef _DEBUG#define new DEBUG_NEW#undef THIS_FILEstatic char THIS_FILE[] = __FILE__;#en

731

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

vnc远程控制教程,vnc远程控制时如何实现vnc服务器批量管理教程

在日常工作过程中,肯定有很多程序员小伙伴们会有vnc远程控制的需求吧,小编也一样.那大家了解如何实现vnc远程控制吗?又对远程控制之后如何实现服务器批量管理了解多少呢?接下来,我将会对vnc远程控制如何实现服务器批量管理作一个简单介绍。 首先,我使用的是IIS7服务器管理工具。作为IIS7服务器管理工具,它可以对vnc站点进行管理,方便快捷。除此之外,最大的特点就是能够对vnc站点进行服务器批量管理,远程监控等。 对于服务器集成管理器来说,它最大的优点就是能批量管理windows和linux系统服务器,

weixin_49271180的博客 416

IPMITool Windows版下载说明:Windows下的服务器管理利器

IPMITool Windows版下载说明:Windows下的服务器管理利器 【下载地址】IPMIToolWindows版下载说明 这是一款专为Windows平台设计的IPMITool工具,功能与Linux版本一致,是服务器管理领域不可或缺的利器。通过IPMI(智能平台管理接口),管理员可以远程监控和管理服务器的物理状态...

gitblog_06741的博客 776

控制台程序转化为windows服务

首先我们创建一个控制台应用程序WriteLog,然后添加windows服务LogService 新增的windows服务切换到代码视图,我这边用log4net进行的日志的记录 OnStart方式是服务启动后执行的,OnStop是服务停止后执行的方法。 切换到设计页面,右击添加安装程序 修改serviceInstaller1的属性 St...

weixin_30266829的博客 770
上一篇: windows服务
下一篇: STL::array之数组容器
devourHeavens
博客等级 码龄15年 3粉丝 5原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值