ServiceMain 함수 작성

다음 예제의 SvcMain 함수는 예제 서비스에 대한 ServiceMain 함수입니다. SvcMain은 콘솔 애플리케이션의 기본 함수와 같은 방식으로 서비스에 대한 명령줄 인수에 액세스할 수 있습니다. 첫 번째 매개 변수에는 두 번째 매개 변수의 서비스에 전달되는 인수 수가 포함됩니다. 항상 하나 이상의 인수가 있습니다. 두 번째 매개 변수는 문자열 포인터 배열에 대한 포인터입니다. 배열의 첫 번째 항목은 항상 서비스 이름입니다.

SvcMain 함수는 먼저 RegisterServiceCtrlHandler 함수를 호출하여 SvcCtrlHandler 함수를 서비스의 처리기 함수로 등록하고 초기화를 시작합니다. RegisterServiceCtrlHandlerServiceMain에서 첫 번째 무연고 함수여야 하므로 서비스는 이 함수에서 반환된 상태 핸들을 사용하여 오류가 발생할 경우 SERVICE_STOPPED 상태로 SetServiceStatus를 호출할 수 있습니다.

다음으로 SvcMain 함수는 ReportSvcStatus 함수를 호출하여 초기 상태 SERVICE_START_PENDING 나타냅니다. 서비스가 이 상태에 있는 동안에는 컨트롤이 허용되지 않습니다. 서비스의 논리를 간소화하려면 초기화를 수행하는 동안 서비스에서 컨트롤을 허용하지 않는 것이 좋습니다.

마지막으로 SvcMain 함수는 SvcInit 함수를 호출하여 서비스별 초기화를 수행하고 서비스에서 수행할 작업을 시작합니다.

샘플 초기화 함수인 SvcInit는 매우 간단한 예입니다. 추가 스레드 만들기와 같은 더 복잡한 초기화 작업을 수행하지 않습니다. 서비스 제어 처리기가 서비스를 중지해야 함을 나타내는 신호를 표시한 다음 ReportSvcStatus를 호출하여 서비스가 SERVICE_RUNNING 상태로 들어갔음을 나타내는 이벤트를 만듭니다. 이 시점에서 서비스는 초기화를 완료했으며 컨트롤을 수락할 준비가 되었습니다. 최상의 시스템 성능을 위해 애플리케이션은 25-100밀리초 내에 실행 중 상태로 들어가야 합니다.

이 샘플 서비스는 실제 작업을 완료하지 않으므로 SvcInit는 WaitForSingleObject 함수를 호출하여 서비스 중지 이벤트가 신호를 받을 때까지 기다렸다가 ReportSvcStatus를 호출하여 서비스가 SERVICE_STOPPED 상태가 되었음을 나타내고 를 반환합니다. (반환하면 인수에 할당된 메모리를 정리할 수 있으므로 ExitThread 함수를 호출하는 대신 함수가 반환하는 것이 중요합니다.) WaitForSingleObject 대신 RegisterWaitForSingleObject 함수를 사용하여 추가 정리 작업을 수행할 수 있습니다. 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 함수

전체 서비스 샘플