A service program is an important class of programs on windows that do not interact with the user interface, but they are important to the system. Windows provides a special program for the Management Service program: The Service Control Manager, which basically deals with this program on the system's API for service control management. These API functions are described below through the operation of the service program
Get information on system services
In Windows systems there is a database dedicated to storing service information, and getting system service information is primarily done by looking in such a database. The main functions used are:
OpenSCManager: Open Database
SC_HANDLE WINAPI OpenSCManager( __in LPCTSTR lpMachineName, __in LPCTSTR lpDatabaseName, __in DWORD dwDesiredAccess);
This function is used primarily to connect the Service Control Manager on a specific computer and to open the database for the Service Control Manager.
The parameters of the function are:
Lpmachinename: Host Name
Lpdatabasename: Name of the service database in the host
dwDesiredAccess: What permissions to open the service program
The first two parameters can be null, if it is null, the second parameter is fetched from the registry, and the third parameter is the main incoming value as follows:
Sc_manager_all_access (0xf003f): Default has all permissions
Sc_manager_create_service (0x0002): Has permission to create a service
Sc_manager_connect (0x0001): the right to connect
Sc_manager_enumerate_service (0x0004) Enumerate the permissions of the information inside
The following is no longer one by one explained, please see the MSDN records for more information. In the program in order to facilitate the general use of sc_manager_all_access parameters
function if the call succeeds, it returns a handle to the Operation database, and subsequent operations on the service have this parameter as the first parameter.
EnumServicesStatus: Enumerating System Services
BOOL WINAPI EnumServicesStatus( __in SC_HANDLE hSCManager, __in DWORD dwServiceType, __in DWORD dwServiceState, __out LPENUM_SERVICE_STATUS lpServices, __in DWORD cbBufSize, __out LPDWORD pcbBytesNeeded, __out LPDWORD lpServicesReturned, __in_out LPDWORD lpResumeHandle);
Hscmanager: Service database handle
Dwservicetype: Enumerates the types of services, mainly: Service_driver (driver type Service), Service_win32 (Win32 type of service)
Dwservicestate: The service that represents which state is enumerated, mainly: service_active (service started), Service_inactive (service not started), Service_state_all (all services)
Lpservices: This parameter is primarily used as a buffer to return service information, type Enum_service_status primarily stores the service name, display name, and a service_status struct, which is prototyped as follows:
typedefstruct _SERVICE_STATUS{ //服务类型 DWORD dwControlsAccepted;//当前状态 DWORD dwServiceSpecificExitCode; DWORD dwCheckPoint; DWORD dwWaitHint;} SERVICE_STATUS, *LPSERVICE_STATUS;
Cbbufsize: Size of buffer
Pcbbytesneeded: Actual size of buffer required
Lpservicesreturned: Return value of the service
Lpresumehandle: Extra Handle
Each enum_service_status structure holds information about a service, but we don't know how many services we have in advance, so we don't know how much of a service information array to define, but Windows takes that into account. When the function call fails to return ERROR_MORE_DATA when using GetLastError, the supplied buffer is insufficient, this time the parameter pcbbytesneeded will return the correct size, so the use of this function will typically go through two calls for the first time lpservices = NULL, cbbufsize = 0, at this time the function is faulted and returns the actual size required, and then dynamically divided by the size of a memory buffer or provide an array, and pass in the actual size to obtain information about all services. A specific example is provided below:
Sc_handle schandle = OpenSCManager (null, NULL, sc_manager_all_access);if(NULL = = Schandle) {returnFALSE; } lpenum_service_status pservices = NULL; DWORD Dwbyteneed =0; DWORD Dwservicereturn =0; Lpdword lpresumehandle = NULL;//First call, set the buffer to null and set the buffer size to 0BOOL BRet =:: EnumServicesStatus (Schandle, Service_win32, Service_state_all, Pservices,0, &dwbyteneed, &dwservicereturn, Lpresumehandle);if(!bret) {//If the buffer size is insufficient if(Error_more_data = = GetLastError ()) {//Save the true size of the bufferDWORD dwrealneed = dwbyteneed;//Multiple allocation one is to save 0 of the end of the stringPservices = (lpenum_service_status)New Char[Dwrealneed +1]; ASSERT (NULL! = pservices); ZeroMemory (pservices, Dwrealneed +1); BRet =:: EnumServicesStatus (Schandle, Service_win32, Service_state_all, pservices, Dwrealneed +1, &dwbyteneed, &dwservicereturn, Lpresumehandle);//Through the above code can get information about the service} }
Gets the path, startup type, and dependencies of the service's main program
The above code can only get some information about the system service, such as the name of the service, the display name, and so on other information needs to call another API function to get
OpenService getting a handle to a specific service
SC_HANDLE WINAPI OpenService( __in //服务数据库的句柄 __in LPCTSTR lpServiceName,//服务的名称 __in DWORD dwDesiredAccess//以何种权限打开,为了方便一般填入SERVICE_ALL_ACCESS所有权限);
QueryServiceConfig Query system service Information
BOOL WINAPI QueryServiceConfig( __in SC_HANDLE hService, __out LPQUERY_SERVICE_CONFIG lpServiceConfig, __in DWORD cbBufSize, __out LPDWORD pcbBytesNeeded);
The second parameter of this function is a struct pointer, which defines the structure as follows:
typedefstruct _QUERY_SERVICE_CONFIG { DWORD dwServiceType; //服务类型 DWORD dwStartType; //启动类型 DWORD dwErrorControl;//错误码,服务执行出错时返回,操作系统根据这个错误码来做相应的处理 LPTSTR lpBinaryPathName;//主程序所在路径 LPTSTR lpLoadOrderGroup; DWORD dwTagId; //依赖项 LPTSTR lpServiceStartName; //显示名称} QUERY_SERVICE_CONFIG, *LPQUERY_SERVICE_CONFIG;
This function is called in the same way as EnumServicesStatus, and is also called by two times, the first time to obtain the required space size, this size is returned by the fourth parameter.
The following code shows how these two functions are called
///The first parameter is obtained through the OpenSCManager functionSc_handle H_scservice = OpenService (H_schandle, Psrvitem->strsrvname, service_all_access);if(NULL = = H_scservice) {Closeservicehandle (h_schandle);returnFALSE; } lpquery_service_config psrvconfig = NULL; DWORD dwbuffsize =0; DWORD Dwbuffneed =0; BOOL BRet = QueryServiceConfig (H_scservice, Psrvconfig, dwBuffSize, &dwbuffneed);if(!bret) {if(Error_insufficient_buffer = = GetLastError ()) {DWORD dwrealneed = dwbuffneed; Psrvconfig = (lpquery_service_config)New Char[Dwrealneed +1]; ASSERT (NULL! = psrvconfig); BRet = QueryServiceConfig (H_scservice, Psrvconfig, Dwrealneed, &dwbuffneed); } }
Get description of the service
Descriptive information is typically provided by a service developer to interpret information such as the role of the service program, which is recorded by the system and presented to the user when it is injected into the service. The main API function used to get system services is QUERYSERVICECONFIG2
BOOL WINAPI QueryServiceConfig2( __in SC_HANDLE hService, __in DWORD dwInfoLevel,//将获取何种信息在这我们需要填写SERVICE_CONFIG_DESCRIPTION表示获取描述信息 __out LPBYTE lpBuffer, __in DWORD cbBufSize, __out LPDWORD pcbBytesNeeded);
This function does not want to get the queryserviceconfig of the service at once, it specifies what information needs to be obtained according to the second parameter, and then returns to the buffer provided by the 3rd parameter, which is a pointer of type byte. The caller needs to type conversions based on the specific situation. The same function needs to be called two times.
BOOL BRet = QueryServiceConfig2 (H_scservice, Service_config_description, (LPBYTE) lpbyte, cbbufsize, &dwbuffneed);if(!bret) {if(Error_insufficient_buffer = = GetLastError ()) {DWORD dwrealneed = dwbuffneed;only one string pointer is saved in the//lpservice_description struct lpdescriptionLpbyte = (lpservice_description)New Char[Dwrealneed +1]; ASSERT (NULL! = lpbyte); BRet = QueryServiceConfig2 (H_scservice, Service_config_description, (LPBYTE) lpbyte, Dwrealneed, &dwbuffneed);if(!bret) {Delete[] lpbyte;Goto__error_ret; } psrvitem->strsrvdescrible = lpbyte->lpdescription;Delete[] lpbyte; Closeservicehandle (H_scservice); Closeservicehandle (H_schandle);returnTRUE; }}__error_ret:closeservicehandle (H_scservice); Closeservicehandle (H_schandle);returnFALSE;
Control of the service
Service Control main Control service start, pause, resume, stop and so on.
StartService Start Service
BOOL WINAPI StartService( __in SC_HANDLE hService, __in DWORD dwNumServiceArgs,//启动参数的个数 __in LPCTSTR* lpServiceArgVectors//参数列表指针);
This function is a bit like the main function, the main function can pass the command line arguments to the program, in order to implement the program and the user's interaction, here can also pass parameters, so that the service to complete a specific function, when the second argument is 0 o'clock the third parameter is NULL
ControlService Control Services
BOOL WINAPI ControlService( __in SC_HANDLE hService, __in DWORD dwControl,//新状态 __out LPSERVICE_STATUS lpServiceStatus//服务的原始状态);
This function is used to complete the service control except for startup, where the second parameter is the state of the service, and the parameters it can use are as follows:
Take value |
meaning |
Service_control_continue |
Continue running |
Service_control_pause |
Time out |
Service_control_stop |
Stop it |
The rest of the parts are not very common, so they are not listed here.
The following is a concrete example of how much of the code in this section is more judgmental because it takes into account the current state and whether the service supports this state.
Service_status ServiceStatus = {0};//Get the current statusBOOL BRet = QueryServiceStatus (H_scservice, &servicestatus); ASSERT (BRet);if(servicestatus.dwcurrentstate = = dwnewstatus) {Goto__return; }//If the current service is in the start and pause, but does not complete this action is not allowed to change the service state if(servicestatus.dwcurrentstate = = Service_continue_pending | | Service_pause_pending ==servicestatus.dwcurrentstate | | service_start_pending = = Servicestatus.dwcurrentstate | | service_stop_pending = = servicestatus.dwcurrentstate) {bRet = FALSE;Goto__return; }//If the service is in a paused state, only allow to continue running and stop if(service_paused = = servicestatus.dwcurrentstate) {if(service_control_continue = = Dwnewstatus | | Service_control_stop = = dwnewstatus) {BRet = ControlService (H_scservice, Dwnewstatus, &servicestatu s);Goto__return; }Else{bRet = FALSE;Goto__return; } }//If the service is running, run pause and stop if(service_running = = servicestatus.dwcurrentstate) {if(Service_control_pause = = Dwnewstatus | | Service_control_stop = = dwnewstatus) {BRet = ControlService (H_scservice, Dwnewstatus, &servicestatu s);Goto__return; }Else{bRet = FALSE;Goto__return; } }//If the service is in a stopped state, the operation is allowed to run if(service_stopped = = servicestatus.dwcurrentstate) {if(service_running = = dwnewstatus) {BRet = StartService (H_scservice,0, NULL);Goto__return; }Else{bRet = FALSE;Goto__return; }}__return:if(BRet) {piter->pnode->dwcurrentstatus = Dwnewstatus; } closeservicehandle (H_scservice); Closeservicehandle (H_schandle);returnBRet;
The state of the current service can be obtained using the EnumServicesStatus function, but this function is to get all the service programs recorded in the system, in which case we just need to get the state of a service, call this function always have overkill meaning, So the use of another function QueryServiceStatus, the main state of the service program are as follows:
Take value |
Status Description |
Service_running |
is started |
service_stopped |
Has stopped |
Service_paused |
Is paused |
Service_continue_pending |
is recovering |
Service_pause_pending |
is pausing |
Service_start_pending |
is starting |
Service_stop_pending |
is stopping |
The first few are completed, that is, the conversion from one state to the other, while the latter is in progress, between the two states
Get the controllable type of service
When controlling a service, consider not only the current state of the service program, but also whether it supports such a state, such as a service that does not support pausing and resuming operations
QueryServiceStatus status information for a query service
This function mainly passes a pointer to a service_status struct. This structure is defined as follows:
typedefstruct _SERVICE_STATUS { DWORD dwServiceType;//服务类型 //当前状态 DWORD dwControlsAccepted;//允许的操作 DWORD dwWin32ExitCode; DWORD dwServiceSpecificExitCode; DWORD dwCheckPoint; DWORD dwWaitHint;} SERVICE_STATUS, *LPSERVICE_STATUS;
Changing the startup type of a service
The startup type of the service mainly includes boot start, manual start, and prohibit startup. The function to change the startup type is mainly: Changeserviceconfig. The function prototypes are as follows:
BOOL WINAPI ChangeServiceConfig( __in SC_HANDLE hService, __in DWORD dwServiceType,//服务类型 __in DWORD dwStartType,//启动类型 __in DWORD dwErrorControl, __in LPCTSTR lpBinaryPathName,//服务的主程序路径 __in LPCTSTR lpLoadOrderGroup, __out LPDWORD lpdwTagId, __in LPCTSTR lpDependencies,//依赖项 __in LPCTSTR lpServiceStartName,//服务名称 __in LPCTSTR lpPassword,//服务密码,主要用于控制服务 __in LPCTSTR lpDisplayName//服务的显示名称);
The function passes all the new information of the service, if you want to change it, fill in the corresponding value, if you do not want to change the DWORD type of members to fill in service_no_change, for pointer type only need to fill in null.
Create a service
The creation service primarily uses the function CreateService, which is prototyped as follows:
Sc_handle WINAPI CreateService (__in sc_handle hscmanager, __in lpctstr lpservicename,//Service name__in LPCTSTR Lpdisplayname,//Display name__in DWORD dwDesiredAccess,//service permissions__in DWORD Dwservicetype,//Service type__in DWORD Dwstarttype,//service startup type__in DWORD Dwerrorcontrol, __in lpctstr lpbinarypathname,//Main program path__in LPCTSTR Lploadordergroup, __out lpdword lpdwtagid, __in lpctstr lpdependencies,//Dependencies__in LPCTSTR lpservicestartname, start name __in LPCTSTR Lppassword//Password); A service control manager that needs to fill in some information systems at startup to save this information, and to start the service based on some of them, some of which are required, such as the service name, which is used to uniquely identify a service, the path to the service that tells the Service Control Manager which program to start, and the dependencies, Passwords and so on can not be filled. The following is an example of the invocation of "' cppp sc_handle Hret =:: CreateService (H_scmanager, Lpservicename, Lpdisplayname, dwDesiredAccess, SERVIC E_win32_own_process, Dwstarttype, service_error_normal, lpbinarypathname, NULL, NULL, lpdependencies, LpServiceSta Rtname, Lppassword); <divclass="Se-preview-section-delimiter"></div>
Service_win32_own_process indicates that the service type is a service of the Win32 type with independent processes
Service_error_normal indicates that the error code returned by the service program is the system default error code
Delete Service
The function used by the Delete service is DeleteService, which is primarily passed to the handle of the service, which is returned by the function OpenService. It is also important to note that this function only works on services that have been stopped, so you need to stop the service before deleting it.
"'
Service_win32_own_process indicates that the service type is a service with a separate process for the Win32 type Service_error_normal indicates that the error code returned by the service program is the system default error code# # Delete ServiceThe function used by the Delete service is DeleteService, which is primarily passed to the handle of the service, which is returned by the function OpenService. It is also important to note that this function only works on services that have been stopped, so you need to stop the service before deleting it. "' CPPBOOLBRet =FALSE; DWORD Dwsrvacceptctrl = getsrvctrlaccept (piter->pnode->strsrvname);if(0= = (Dwsrvacceptctrl & service_accept_stop))//service cannot be deleted{Goto__return; }//Stop service, function Ctrlservice is the one I encapsulated before to control the service. BRet = Ctrlservice (Piter, service_control_stop);if(!bret) {Goto__return; } BRet =::D eleteservice (H_scservice);if(BRet) {DeleteItem (Piter->pnode); }__return:closeservicehandle (H_scservice); Closeservicehandle (H_scmanager);returnBRet;
Windows Service Management operations