Поделиться через


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

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

Функция SvcMain сначала вызывает функцию RegisterServiceCtrlHandler , чтобы зарегистрировать функцию SvcCtrlHandler в качестве функции обработчика для службы и начать инициализацию. 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. См. пример функции обработчика элементов управления в Writing a Control Handler Function.

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

#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

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