Написание функции ServiceMain

Функция SvcMain в следующем примере является функцией ServiceMain для примера службы. SvcMain имеет доступ к аргументам командной строки для службы так, как это делает функция main консольного приложения. Первый параметр содержит количество аргументов, передаваемых службе во втором параметре. Всегда будет иметься по крайней мере один аргумент. Второй параметр является указателем на массив строковых указателей. Первым элементом в массиве всегда является имя службы.

Функция SvcMain сначала вызывает функцию RegisterServiceCtrlHandler , чтобы зарегистрировать функцию SvcCtrlHandler в качестве функции Handler службы и начать инициализацию. RegisterServiceCtrlHandler должна быть первой функцией без изменения в ServiceMain , чтобы служба может использовать дескриптор состояния, возвращаемый этой функцией, для вызова SetServiceStatus с состоянием SERVICE_STOPPED в случае ошибки.

Затем функция SvcMain вызывает функцию ReportSvcStatus, чтобы указать, что ее начальное состояние SERVICE_START_PENDING. Пока служба находится в этом состоянии, никакие элементы управления не принимаются. Чтобы упростить логику службы, рекомендуется, чтобы служба не принимала какие-либо элементы управления во время выполнения ее инициализации.

Наконец, функция SvcMain вызывает функцию SvcInit, чтобы выполнить инициализацию службы и начать работу, выполняемую службой.

Пример функции инициализации SvcInit является очень простым примером. он не выполняет более сложные задачи инициализации, такие как создание дополнительных потоков. Он создает событие, которое обработчик управления службой может сообщить о том, что служба должна остановиться, а затем вызывает ReportSvcStatus, чтобы указать, что служба перешла в состояние SERVICE_RUNNING. На этом этапе служба завершила инициализацию и готова принять элементы управления. Для достижения оптимальной производительности системы приложение должно перейти в состояние выполнения в течение 25–100 миллисекунда.

Так как этот пример службы не выполняет никаких реальных задач, SvcInit просто ожидает передачи сигнала о событии остановки службы путем вызова функции WaitForSingleObject , вызывает ReportSvcStatus, чтобы указать, что служба перешла в состояние SERVICE_STOPPED, и возвращает значение . (Обратите внимание, что важно, чтобы функция возвращала, а не вызывала функцию ExitThread , так как возврат позволяет очистить память, выделенную для аргументов.) Дополнительные задачи очистки можно выполнять с помощью функции RegisterWaitForSingleObject вместо WaitForSingleObject. Поток, выполняющий функцию ServiceMain , завершает работу, но сама служба продолжает работать. Когда обработчик управления службой сообщает о событии, поток из пула потоков выполняет обратный вызов для выполнения дополнительной очистки, включая установку состояния SERVICE_STOPPED.

Обратите внимание, что в этом примере используется SvcReportEvent для записи событий ошибок в журнал событий. Исходный код для SvcReportEvent см. в разделе Svc.cpp. Пример функции обработчика элемента управления см. в разделе Написание функции обработчика элемента управления.

В этом примере используются следующие глобальные определения.

#define SVCNAME TEXT("SvcName")

SERVICE_STATUS          gSvcStatus; 
SERVICE_STATUS_HANDLE   gSvcStatusHandle; 
HANDLE                  ghSvcStopEvent = NULL;

Следующий пример фрагмента взят из полного примера службы.

//
// 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

Пример полной службы