Red de conocimiento informático - Conocimiento informático - Cómo escribir un programa de servicio de Windows

Cómo escribir un programa de servicio de Windows

Windows proporciona un conjunto de interfaces de programación de programas de servicio en segundo plano. Los usuarios deben seguir un determinado marco de programación al escribir programas de servicio en segundo plano; de lo contrario, el programa de servicio no podrá ejecutarse normalmente.

Los programas de servicio generalmente se escriben como aplicaciones de tipo consola. En términos generales, un programa que cumple con los requisitos de la interfaz del programa de gestión de control de servicios contiene las siguientes tres funciones:

1) Servicio principal. Función del programa (principal): Llame a la función del sistema StartServiceCtrlDispatcher para conectar el hilo principal del programa al programa de gestión de control de servicios.

Al igual que otros procesos, la función principal es la función de entrada del proceso de servicio. Cuando el Administrador de control de servicios (SCM) inicia el programa de servicio, comenzará la ejecución desde la función principal del programa de servicio. La inicialización de ServiceMain debe completarse en la función de punto de entrada. Para ser precisos, se inicializa una matriz de estructuras SERVICE_TABLE_ENTRY. Esta estructura registra los nombres de todos los servicios contenidos en el programa de servicio y las funciones de punto de entrada de los servicios. Luego llame a la interfaz StartServiceCtrlDispatcher.

El marco de funciones de la función principal es el siguiente:

int _tmain(int argc, _TCHAR* argv[])

{

// Tabla de funciones del punto de entrada del servicio

SERVICE_TABLE_ENTRY despachoTable[]=

{

{TEXT(SZSERVICENAME), (LPSERVICE_MAIN_FUNCTION)Service_Main},

{ NULL, NULL}

};

if((argcgt;1)amp;amp;((*argv[1]=='-') ||(argv [1]=="/")))

{

/*

El número de parámetros mayor que 1 significa instalar o eliminar el servicio. Esta operación la realiza el usuario

Por supuesto, también puedes escribir otro programa para implementar esta parte de la función

*/

if(_stricmp("instalar", argv[ 1] 1)==0)

{

installService();

}

else if(_stricmp("remove", argv[1] 1)==0)

{

removeService();

}

else if(_stricmp( "debug", argv[1] 1)==0)

{

bDebugServer=true;

debugService(argc, argv);

}

}

else

{

/ *

Si no coincide con lo anterior Cómo coinciden los parámetros, es posible que el administrador de control de servicios esté iniciando el programa.

Llame inmediatamente a la función StartServiceCtrlDispatcher

*/

g_logout.Logout("s\n", "enter StartServiceCtrlDispatcher...");

//Notificación service El administrador crea subprocesos de servicio para cada servicio

if(!StartServiceCtrlDispatcher(dispatchTable))

g_logout.Logout("s\n", "StartServiceCtrlDispatcher falló."); p>

else

g_logout.Logout("s\n", "StartServiceCtrlDispatcher OK.");

}

return 0;

p>

}

Después de que SCM inicia un programa de servicio, esperará a que el hilo principal del programa llame a StartServiceCtrlDispatcher. Si esa función no se llama en dos minutos, SCM considerará que hay un problema con el servicio y llamará a TerminateProcess para finalizar el proceso. Esto requiere que su hilo principal llame a StartServiceCtrlDispatcher lo más rápido posible.

2) Función de punto de entrada de servicio (ServiceMain): realiza tareas de inicialización de servicio y los procesos de servicio que ejecutan múltiples servicios al mismo tiempo tienen múltiples funciones de entrada de servicio.

En la función de entrada de servicio, la función de devolución de llamada de control de servicio debe registrarse inmediatamente. Luego llame a la función SetServiceStatus para notificar a SCM sobre el estado actual del servicio; de lo contrario, SCM considerará que el inicio del servicio falló.

El marco de la función ServiceMain es el siguiente:

void WINAPI Service_Main(DWORD dwArgc, LPTSTR *lpszArgv)

{

// Registrar control de servicio Función de manejo

sshStatusHandle=RegisterServiceCtrlHandler(TEXT(SZSERVICENAME), Service_Ctrl);

//Si el registro falla

if(!sshStatusHandle)

{

g_logout.Logout("s\n", "RegisterServiceCtrlHandler falló...");

return;

}

//Inicializa los miembros en la estructura SERVICE_STATUS

ssStatus.dwServiceType=SERVICE_WIN32_OWN_PROCESS; //Solo hay un servicio en el archivo ejecutable

ssStatus.dwServiceSpecificExitCode =0;

p>

ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP; //Permitir que SCP detenga el servicio

//Actualizar el estado del servicio

if(ReportStatusToSCMgr(SERVICE_START_PENDING , //Estado del servicio, El servicio aún se está inicializando

NO_ERROR,

3000)) //Tiempo de espera

SvcInit(dwArgc, lpszArgv); /Función de inicialización del servicio

else

g_logout.Logout("s\n", "ReportStatusToSCMgr SERVICE_START_PENDING falló...");

}

Función de inicialización del servicio SvcInit:

La forma en que está escrita esta función es más importante. Cree un evento de espera en la función y espere el evento. El hilo permanece en estado suspendido hasta que el servicio recibe una solicitud hasta que se recibe un mensaje de detención del servicio.

VOID SvcInit(DWORD dwArgc, LPTSTR *lpszArgv)

{

/*Crear evento*/

ghSvcStopEvent = CreateEvent(

NULL, // atributos de seguridad predeterminados

TRUE, // evento de reinicio manual

FALSE, // no señalado

NULL); // sin nombre

if (ghSvcStopEvent == NULL)

{

ReportSvcStatus( SERVICE_STOPPED, NO_ERROR, 0);

return ;

}

// Informar del estado de ejecución cuando se completa la inicialización.

ReportSvcStatus( SERVICE_RUNNING, NO_ERROR, 0);

/ / Ejecutar la creación del hilo de servicio aquí...

while(1)

{

// Esperar a que se active el evento de detención

WaitForSingleObject(ghSvcStopEvent, INFINITE);

ReportSvcStatus( SERVICE_STOPPED, NO_ERROR, 0

retorno

}

<); p>}

3) Función de controlador de servicio de control (Handler): a la que hace referencia el hilo de distribución de control cuando el programa de servicio recibe una solicitud de control. (Service_Ctrl aquí).

void WINAPI Service_Ctrl(DWORD dwCtrlCode)

{

//Procesamiento del código de solicitud de control

switch(dwCtrlCode)

{

//Primero actualice el estado del servicio a SERVICE_STOP_PENDING y luego detenga el servicio.

case SERVICE_CONTROL_STOP:

ReportStatusToSCMgr(SERVICE_STOP_PENDING, NO_ERROR, 500);

ServiceStop() //Implementado por un programa de servicio específico

/*ssStatus.dwCurrentState=SERVICE_STOPPED;*/

//Otras solicitudes de control...

predeterminado:

interrupción;

}

}

3. Notas

1) Para instalar el servicio, puede escribir un programa separado o puede incluirlo en el programa de servicio. Es relativamente simple. No lo presentaré aquí.

2) Es importante crear un evento de espera en la función de inicialización del servicio SvcInit. Este evento se activa después de que el servicio recibe el mensaje de detención del servicio.

3) Service_Main regresa inmediatamente después de esperar a que se active el evento y el proceso de servicio saldrá