About Service Design Preliminary (MSDN Election Translation)

zhaozj2021-02-16  42

The following is that I learned a service note in these days, share it, just let the friends who want to write a service together (of course, this translation is very bad, don't joke):

· A service program includes three parts

The first part is the control module, mainly communicating with the service management program, performs the installation and deletion of the service program.

The second module is the main module, that is, the work to do during the running process, should be a loop (if the cycle is exited, do you need to notify the operating system?).

The third module is a service management program control processing module, mainly processing service boot, service stop and other events. And notify the current state of the service management program.

Understanding process

• How to install a service program and how to delete a service program.

· How to deal with the system's start-up service and stop service

· The main module running in the service program should be placed there? And how to organize?

MSDN selection content

Service Control Manager is referred to as SCM (or SCMGR), is a remote call when the system is started

· Maintaining a database that has been installed service program (List)

• Start Service or Drive SERVICES when the system is started or when needed.

· Enumerally, have installed service and service drivers

· Get ​​the status information of the service and service driver in the run

· Send control requirements for the service in the run

· Lock (or release) Service database.

The main function

The Service program is usually written as a console program, and the main function will be the entry of the console program to obtain a predetermined parameter from the registry.

When the SCM launches the service program, it will wait to call the StartServiceCtrLDispatcher function

Service_win32_oen_process type Service will call StartServiceCtrlDispatcher from its main thread. You can perform some initialization operations within the servicemain function, after the service starts.

The StartServiceCtrldispatcher function has a service_table_entry as a parameter, which specifies the service name and entry point.

If the StartServiceCtrldispatcher function call is successful, the calling thread will not return before the service process ends.

· When the new service starts, create a new thread and call the corresponding entry point.

· Call the appropriate processing function to process the Service control requirements

The servicemain function

The ServiceMain function is the entry point of the service.

When the service control program requires a new service run. SCM starts service and sends a startup request to control the transmitter, then create a new thread to run the serviceMain function of the service.

Servicemain function needs to perform a task:

REGISTERSERVICECTRLHANDLEREX is called immediately to register a handler (Handlerex) to process the service's control requirements. The return value is a Handle that informs the SCM's service status processing.

Perform an initialization unit, if the execution time of the initialization code is less than 1 second or very short, it can be executed in the ServiceMain.

If the initialization time is too long, it is best to call the setServiceStatus function, specifying the status is Service_Start_pending (in the startup), it is best to make the SETSERVICESTATUS report now, which is better to perform DEBUG. When the initialization is completed, the setServiceStatus is called and specifies the service_running indicated state.

Execute the service task, or return (if there is no task)

If an error occurs during initialization or run, you should call SetServiceStatus and specify service_stop_pending (stop). After completing the work work, then specify the current state service_stopped, remember to specify the value of members dwservicespecifiitcode and dwWN32exitcode in the service_status structure to specify the type of error.

The Control Handler Function

Each Service has a control processing ("Handlerex) function, which is controlled to call when the service process gets control requirements from the Service control program, so this function is executed in the thread of Control Dispatcher.

When the handler is called, the Service must call the setServiceStatus function to report the current state to the SCM, regardless of whether the current state changes.

The Service Control Program can use the ControlService function to send control requirements, all service must accept and process service_control_interrogate (control inquiry), you can open or disable access to other control code, using setServiceStatus to complete. If you want to receive Service_Control_DeviceEvent (Control Event Drive) code, you must call the RegisterDeviceNotification function, and Service can also handle other user-defined code.

The control processing function must return within 30 seconds, otherwise the SCM will return an error. If Service needs to do more work to process, then it is best to create a new thread, and if you want to handle the requirements of the stop service, you can create another one. Threads are processed, then call setServiceStatus setting service_stop_pending to return.

When the user closes the operating system, all control processing processes receive the service_control_shutdown control signal due to the called setServiceStatus, which will be queued in order to inform the signal according to the sequence of installation, according to the default, each service can have approximately 20 Second's clearing time is completed before the system is closed, you can set the WaitTokillServentimeout key value of the registry to change the system waiting for the service to close, the key value is set below.

HKEY_LOCAL_MACHINE / SYSTEM / CURRENTCONTROLSET / CONTROL

How to write the main function of the service program

Servcie's main function calls the StartServiceCtrLDispatcher function to connect to the SCM and start controlling the transmitter thread, the thread starts and waiting for the arrival of the request (of course, it is filtered), this function will not return, until there is an error or All services in the process are completed. The SCM will send a control request to tell the shutdown thread to return from the StartServiceCtrldispatcher function, and then the process is turned off. The following example is a case where only one service is included in a service process. (Omitted ...)

SERVICE_STATUS MyServiceStatus; SERVICE_STATUS_HANDLE MyServiceStatusHandle; VOID MyServiceStart (DWORD argc, LPTSTR * argv); VOID MyServiceCtrlHandler (DWORD opcode); DWORD MyServiceInitialization (DWORD argc, LPTSTR * argv, DWORD * specificError); void main () {SERVICE_TABLE_ENTRY DispatchTable [] = { { "MyService", MyServiceStart}, {NULL, NULL}}; if {SvcDebugOut ( "[mY_SERVICE] StartServiceCtrlDispatcher error =% d / n", GetLastError ()) (StartServiceCtrlDispatcher (DispatchTable)!);}} VOID SvcDebugOut (LPSTR String, dword status) {char buffer [1024]; if (strlish <1000) {sprintf (buffer, string, status); OutputDebugstringA (Buffer);}}

If your service program supports multiple services, the main function will be slightly different, and more service names will be added to the Dispatch Table to be monitored by the Dispatcher thread.

How to write servicemain functions

The following example inside the MyServiceStart function is the entry of the service, MyServiceStart uses the command line parameters, as the main function of the console program. The first parameter contains a total of several parameters being transferred to the service. Therefore, there is always at least one parameter, the second parameter is an array of pointers, pointing to the string pointer. The first item in array must be the name of the service.

MyServiceStart filled first SERVICE_STATUS structure containing a control code can be accepted, although this Service can accept SERVICE_CONTROL_PAUSE (pause) and SERVICE_CONTROL_CONTINUE (continue) and was told to suspend makes no sense, SERVICE_ACCEPT_PAUSE_CONTINUE sign contains only for illustrative purposes. If you are suspended in your service, it is meaningless, then don't support it.

The MyServiceStart function then calls the RegisterServiceCtrlHandler function to register myService as a service function and start the initialization work. The following initialization examples MyServiceInitialization is only used to explain that there is no actual initialization code, and create any thread. If your initialization code may be very long, then your code is best to call SetServiceStatus to send the progress information of the waiting information and initialization. When the initialization is complete, the example will call setSerCviceStatus to set service_running and continue its work. If the error is wrong during initialization, the MyServiceStart reports service_stopped back.

Because this example does not complete what real task, MyServiceStart is simple to return to the caller. In any case, your service should use this thread to complete what you want to design. If your service does not need to run something (just operating the RPC request), the servicemain function should return to the caller. This is much better than calling exitthread, because we have to give the opportunity to call the program to clean the site, and apply for memory and arrays.

If you want to output debug information, you can call SVCDeBugout. The source code of this function has been given in "How to write the main function of the servcie program".

Service_status myServiceStatus;

Service_status_handle myServiceStatushandle;

Void MyServiceStart (DWORD ARGC, LPTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTS

{

DWORD status;

DWORD Specificerror;

MyServiceStatus.dwServiceType = service_win32;

MyServiceStatus.dwcurrentState = service_start_pend;

MyServiceStatus.dwcontrolsaccepted = service_accept_stop |

Service_accept_pause_continue;

MyServiceStatus.dwwin32exitcode = 0;

MyServiceStatus.dwservicespecifiXitcode = 0;

MyServiceStatus.dwcheckpoint = 0;

MyServiceStatus.dwwaithint = 0;

MyServiceStatusHandle = RegisterServiceCtrlHandler

"MyService",

MyServiceCtrlHandler;

IF (myServiceStatusHandle == (Service_Status_Handle) 0)

{

SvcDebugout ("[my_service] registerServiceCtrlHandler Failed% D / N", getLastError ());

Return;

}

// Initialization Code Goes Here.

Status = MyServiceInitialization (Argc, Argv, & SpeciFicError);

// Handle Error Condition

IF (status! = no_error)

{

MyServiceStatus.dwcurrentState = service_stopped; myServiceStatus.dwcheckpoint = 0;

MyServiceStatus.dwwaithint = 0;

MyServiceStatus.dwwin32exitcode = status;

MyServiceStatus.dwserviceSpecificeXitcode = SpecificError;

SetServiceStatus (MyServiceStatusHandle, & myServiceStatus);

Return;

}

// Initialization Complete - Report Running Status.

MyServiceStatus.dwcurrentState = service_running;

MyServiceStatus.dwcheckpoint = 0;

MyServiceStatus.dwwaithint = 0;

IF (! setServiceStatus (MyServiceStatushandle, & myServiceStatus))

{

Status = getLastError ();

SVCDebugout ("[My_Service] setServiceStatus Error% LD / N", STATUS);

}

// this is where the service does its work.

Svcdebugout ("[my_service] returnning the main trread / n", 0);

Return;

}

// stub initialization function.

DWORD MyServiceInitialization (DWORD ARGC, LPTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTS "

{

Argv;

Argc;

SpecificError;

Return (0);

}

How to write control processing functions

In the following example, MyServiceCtrlHandler is a process of processing, which is called by the Dispatcher thread, which handles the current Service State to update the current service status. Each time the handler receives the control signal, it will process and return status, regardless of whether the service is still disposed of control information.

A paused control signal is received. MyServiceCtrlHandler Simple Setup The dwcurrentState in Service_Status is in the service_paused. Similarly, if continued information is received, set service_running. So, this example is not a good example for processing pauses and continues. In fact, if your service declares that it does not support pause and continues, the SCM does not send this information to the handler.

Service_status myServiceStatus;

Service_status_handle myServiceStatushandle;

Void MyServiceCtrlHandler (DWORD OPCODE)

{

DWORD status;

Switch (opcode)

{

Case service_control_pause:

// do whatever it takes to pause here.

MyServiceStatus.dwcurrentState = service_paused;

Case Service_Control_Continue:

// do whatever it takes to payue here.

MyServiceStatus.dwcurrentState = service_running;

Break;

Case Service_Control_Stop:

// do wherever it takes to stop here.

MyServiceStatus.dwwin32exitcode = 0;

MyServiceStatus.dwcurrentState = service_stopped;

MyServiceStatus.dwcheckpoint = 0;

MyServiceStatus.dwwaithint = 0;

IF (! setServiceStatus (MyServiceStatushandle, & myServiceStatus))

{

Status = getLastError ();

SVCDebugout ("[My_Service] setServiceStatus Error% LD / N", STATUS);

}

SVCDebugout ("[my_service] leaving myService / n", 0); return;

Case Service_Control_Interrogate:

// Fall Through To Send Current Status.

Break;

DEFAULT:

SVCDebugout ("[my_service] unrecognized opcode% ld / n", opcode);

}

// Send Current Status.

IF (! setServiceStatus (MyServiceStatushandle, & myServiceStatus))

{

Status = getLastError ();

SVCDebugout ("[My_Service] setServiceStatus Error% LD / N", STATUS);

}

Return;

}

After completing, if I wrote what can be referred to the service program example, I will get here and use the right to reference.

转载请注明原文地址:https://www.9cbs.com/read-24598.html

New Post(0)