Skriva en funktion för ServiceMain
Funktionen SvcMain i följande exempel är funktionen ServiceMain för exempeltjänsten. SvcMain har åtkomst till kommandoradsargumenten för tjänsten på det sätt som huvudsakliga funktion i ett konsolprogram gör. Den första parametern innehåller antalet argument som skickas till tjänsten i den andra parametern. Det kommer alltid att finnas minst ett argument. Den andra parametern är en pekare till en matris med strängpekare. Det första objektet i matrisen är alltid tjänstnamnet.
Funktionen SvcMain anropar först funktionen RegisterServiceCtrlHandler för att registrera funktionen SvcCtrlHandler som tjänstens Handler-funktion och påbörja initieringen. RegisterServiceCtrlHandler bör vara den första icke-felande funktionen i ServiceMain så att tjänsten kan använda statushandtaget som returneras av den här funktionen för att anropa SetServiceStatus med SERVICE_STOPPED state om ett fel inträffar.
Sedan anropar funktionen SvcMain funktionen ReportSvcStatus för att ange att dess ursprungliga status är SERVICE_START_PENDING. När tjänsten är i det här tillståndet accepteras inga kontroller. För att förenkla tjänstens logik rekommenderar vi att tjänsten inte accepterar några kontroller medan den utför sin initiering.
Slutligen anropar funktionen SvcMain funktionen SvcInit för att utföra den tjänstspecifika initieringen och påbörja arbetet som ska utföras av tjänsten.
Exempelinitieringsfunktionen SvcInit är ett mycket enkelt exempel. den utför inte mer komplexa initieringsuppgifter, till exempel att skapa ytterligare trådar. Den skapar en händelse som tjänstkontrollhanteraren kan signalera för att indikera att tjänsten ska stoppas och anropar sedan ReportSvcStatus för att indikera att tjänsten har angett SERVICE_RUNNING tillstånd. Tjänsten har nu slutfört initieringen och är redo att acceptera kontroller. För bästa systemprestanda bör programmet ange körningstillståndet inom 25–100 millisekunder.
Eftersom den här exempeltjänsten inte utför några verkliga uppgifter väntar SvcInit bara på att tjänststoppshändelsen ska signaleras genom att anropa funktionen WaitForSingleObject, anropar ReportSvcStatus för att indikera att tjänsten har angett SERVICE_STOPPED tillstånd och returnerar. (Observera att det är viktigt att funktionen returnerar i stället för att anropa funktionen ExitThread eftersom det går att rensa det minne som allokerats för argumenten genom att returnera.) Du kan utföra ytterligare rensningsuppgifter med hjälp av funktionen RegisterWaitForSingleObject i stället för WaitForSingleObject. Tråden som kör funktionen ServiceMain avslutas, men själva tjänsten fortsätter att köras. När tjänstkontrollhanteraren signalerar händelsen kör en tråd från trådpoolen din callback-funktion för att utföra ytterligare rensning, inklusive att ange status till SERVICE_STOPPED.
Observera att det här exemplet använder SvcReportEvent för att skriva felhändelser till händelseloggen. Källkoden för SvcReportEvent finns i Svc.cpp. Ett exempel på en kontrollhanterarfunktion finns i Skriva en kontrollhanterarfunktion.
Följande globala definitioner används i det här exemplet.
#define SVCNAME TEXT("SvcName")
SERVICE_STATUS gSvcStatus;
SERVICE_STATUS_HANDLE gSvcStatusHandle;
HANDLE ghSvcStopEvent = NULL;
Följande exempelfragment tas från det fullständiga tjänstexemplet.
//
// Purpose:
// Entry point for the service
//
// Parameters:
// dwArgc - Number of arguments in the lpszArgv array
// lpszArgv - Array of strings. The first string is the name of
// the service and subsequent strings are passed by the process
// that called the StartService function to start the service.
//
// Return value:
// None.
//
VOID WINAPI SvcMain( DWORD dwArgc, LPTSTR *lpszArgv )
{
// Register the handler function for the service
gSvcStatusHandle = RegisterServiceCtrlHandler(
SVCNAME,
SvcCtrlHandler);
if( !gSvcStatusHandle )
{
SvcReportEvent(TEXT("RegisterServiceCtrlHandler"));
return;
}
// These SERVICE_STATUS members remain as set here
gSvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
gSvcStatus.dwServiceSpecificExitCode = 0;
// Report initial status to the SCM
ReportSvcStatus( SERVICE_START_PENDING, NO_ERROR, 3000 );
// Perform service-specific initialization and work.
SvcInit( dwArgc, lpszArgv );
}
//
// Purpose:
// The service code
//
// Parameters:
// dwArgc - Number of arguments in the lpszArgv array
// lpszArgv - Array of strings. The first string is the name of
// the service and subsequent strings are passed by the process
// that called the StartService function to start the service.
//
// Return value:
// None
//
VOID SvcInit( DWORD dwArgc, LPTSTR *lpszArgv)
{
// TO_DO: Declare and set any required variables.
// Be sure to periodically call ReportSvcStatus() with
// SERVICE_START_PENDING. If initialization fails, call
// ReportSvcStatus with SERVICE_STOPPED.
// Create an event. The control handler function, SvcCtrlHandler,
// signals this event when it receives the stop control code.
ghSvcStopEvent = CreateEvent(
NULL, // default security attributes
TRUE, // manual reset event
FALSE, // not signaled
NULL); // no name
if ( ghSvcStopEvent == NULL)
{
ReportSvcStatus( SERVICE_STOPPED, NO_ERROR, 0 );
return;
}
// Report running status when initialization is complete.
ReportSvcStatus( SERVICE_RUNNING, NO_ERROR, 0 );
// TO_DO: Perform work until service stops.
while(1)
{
// Check whether to stop the service.
WaitForSingleObject(ghSvcStopEvent, INFINITE);
ReportSvcStatus( SERVICE_STOPPED, NO_ERROR, 0 );
return;
}
}
//
// Purpose:
// Sets the current service status and reports it to the SCM.
//
// Parameters:
// dwCurrentState - The current state (see SERVICE_STATUS)
// dwWin32ExitCode - The system error code
// dwWaitHint - Estimated time for pending operation,
// in milliseconds
//
// Return value:
// None
//
VOID ReportSvcStatus( DWORD dwCurrentState,
DWORD dwWin32ExitCode,
DWORD dwWaitHint)
{
static DWORD dwCheckPoint = 1;
// Fill in the SERVICE_STATUS structure.
gSvcStatus.dwCurrentState = dwCurrentState;
gSvcStatus.dwWin32ExitCode = dwWin32ExitCode;
gSvcStatus.dwWaitHint = dwWaitHint;
if (dwCurrentState == SERVICE_START_PENDING)
gSvcStatus.dwControlsAccepted = 0;
else gSvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
if ( (dwCurrentState == SERVICE_RUNNING) ||
(dwCurrentState == SERVICE_STOPPED) )
gSvcStatus.dwCheckPoint = 0;
else gSvcStatus.dwCheckPoint = dwCheckPoint++;
// Report the status of the service to the SCM.
SetServiceStatus( gSvcStatusHandle, &gSvcStatus );
}
Relaterade ämnen