Delen via


Een ServiceMain-functie schrijven

De functie SvcMain in het volgende voorbeeld is de functie ServiceMain voor de voorbeeldservice. SvcMain heeft toegang tot de opdrachtregelargumenten voor de service op de manier waarop de belangrijkste functie van een consoletoepassing dat doet. De eerste parameter bevat het aantal argumenten dat wordt doorgegeven aan de service in de tweede parameter. Er zal altijd ten minste één argument zijn. De tweede parameter is een aanwijzer naar een matrix met tekenreeksaanwijzers. Het eerste item in de matrix is altijd de servicenaam.

Met de functie SvcMain wordt eerst de RegisterServiceCtrlHandler-functie aangeroepen om de functie SvcCtrlHandler te registreren als de Handler--functie van de service en begint met initialisatie. RegisterServiceCtrlHandler- moet de eerste niet-failerende functie in ServiceMain zijn, zodat de service de statusgreep die door deze functie wordt geretourneerd, kan gebruiken om SetServiceStatus- aan te roepen met de status SERVICE_STOPPED als er een fout optreedt.

Vervolgens roept de functie SvcMain de functie ReportSvcStatus aan om aan te geven dat de initiële status "SERVICE_START_PENDING" is. Hoewel de service deze status heeft, worden er geen besturingselementen geaccepteerd. Om de logica van de service te vereenvoudigen, wordt aanbevolen dat de service geen besturingselementen accepteert terwijl deze de initialisatie uitvoert.

Ten slotte roept de functie SvcMain de SvcInit-functie aan om de servicespecifieke initialisatie uit te voeren en te beginnen met het werk dat door de service moet worden uitgevoerd.

De voorbeeldinitialisatiefunctie, SvcInit, is een zeer eenvoudig voorbeeld; het voert geen complexere initialisatietaken uit, zoals het maken van extra threads. Er wordt een gebeurtenis gemaakt die de handler voor servicebeheer kan signaleren om aan te geven dat de service moet stoppen en roept Vervolgens ReportSvcStatus aan om aan te geven dat de service de status SERVICE_RUNNING heeft ingevoerd. Op dit punt is de initialisatie van de service voltooid en kunnen besturingselementen worden geaccepteerd. Voor de beste systeemprestaties moet uw toepassing de uitvoeringsstatus binnen 25-100 milliseconden invoeren.

Omdat deze voorbeeldservice geen echte taken uitvoert, wacht SvcInit gewoon totdat de servicestopgebeurtenis wordt gesignaleerd door de functie WaitForSingleObject aan te roepen, meldt ReportSvcStatus aan om aan te geven dat de service de status SERVICE_STOPPED heeft ingevoerd en wordt geretourneerd. (Houd er rekening mee dat het belangrijk is dat de functie retourneert in plaats van de exitthread-functie aan te roepen, omdat retournering het geheugen dat is toegewezen voor de argumenten, mogelijk maakt opschonen.) U kunt extra opschoningstaken uitvoeren met behulp van de functie RegisterWaitForSingleObject in plaats van WaitForSingleObject. De thread waarop de ServiceMain-functie wordt uitgevoerd, wordt beëindigd, maar de service zelf blijft actief. Wanneer de handler voor servicebeheer de gebeurtenis aangeeft, voert een thread uit de threadgroep uw callback uit om de extra opschoning uit te voeren, inclusief het instellen van de status op SERVICE_STOPPED.

In dit voorbeeld wordt SvcReportEvent gebruikt om foutgebeurtenissen naar het gebeurtenislogboek te schrijven. Zie Svc.cppvoor de broncode voor SvcReportEvent. Zie Een besturingshandlerfunctie schrijvenvoor een voorbeeld van een besturingshandlerfunctie.

In dit voorbeeld worden de volgende globale definities gebruikt.

#define SVCNAME TEXT("SvcName")

SERVICE_STATUS          gSvcStatus; 
SERVICE_STATUS_HANDLE   gSvcStatusHandle; 
HANDLE                  ghSvcStopEvent = NULL;

Het volgende voorbeeldfragment is afkomstig uit het volledige servicevoorbeeld.

//
// 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 );
}

Service ServiceMain-functie

het volledige servicevoorbeeld