콘텐츠로 건너뛰기

[윈도우 서비스] 02. 윈도우 서비스 동작 과정

윈도우 서비스는 운영 체제의 부팅부터 종료까지 백그라운드에서 동작할 수 있는 응용 프로그램입니다. 이전 포스팅에서 간단하게 윈도우 서비스 애플리케이션을 만들고 서비스 제어 관리자를 통해 서비스를 제어해보았습니다. 이번 포스팅에서는 실행 부터 종료까지 간단하게 윈도우 서비스 동작 과정에 대해서 알아보겠습니다.

윈도우 서비스 동작 과정

  1. 서비스 프로세스가 시작되고 main 함수에서 StartServiceCtrlDispatcher를 호출
  2. StartServiceCtrlDispatcher가 서비스 제어 관리자와 연결되고, 서비스의 ServiceMain 함수가 호출됨
  3. ServiceMain에서 서비스가 해야 할 작업을 수행하며, SetServiceStatus로 상태를 계속 서비스 제어 관리자에 보고
  4. 서비스 제어 관리자에서 발생하는 제어 요청을 ServiceCtrlHandler를 통해 처리
  5. 서비스가 종료될 때 SetServiceStatus를 통해 최종 상태를 보고하고 서비스 종료

이와 같은 흐름으로 동작하며, 서비스 상태 및 제어는 모두 서비스 제어 관리자와 통신하여 관리합니다.

1. 서비스 메인 함수

Windows 서비스는 콘솔 애플리케이션과 달리 서비스 시작 시 메인 함수(통상 main 또는 wmain)가 아니라 서비스 전용 함수가 호출됩니다. 일반적으로 ServiceMain 이름으로 함수를 생성합니다.

void WINAPI ServiceMain(DWORD argc, LPTSTR* argv);

이 함수는 서비스 제어 관리자에 의해 호출되며, 서비스의 실제 작업을 처리합니다.

2. StartServiceCtrlDispatcher 함수

서비스가 시작될 때 가장 먼저 호출해야 할 함수는 StartServiceCtrlDispatcher입니다. 이 함수는 서비스와 서비스 제어 관리자 간의 통신을 설정하며, 서비스 메인 함수를 지정합니다.

BOOL WINAPI StartServiceCtrlDispatcher(
  const SERVICE_TABLE_ENTRY* lpServiceTable
);

SERVICE_TABLE_ENTRY

서비스 이름과 ServiceMain 함수를 지정할 수 있는 구조체입니다. SERVICE_TABLE_ENTRY 구조체 배열을 StartServiceCtrlDispatcher 함수에 넘기면 서비스가 시작되고, 구조체의 ServiceMain 함수를 실행합니다.

int _tmain(int argc, TCHAR* argv[]) 
{
    SERVICE_TABLE_ENTRY ServiceTable[] = 
    {
        {TEXT("StudioYS Service"), (LPSERVICE_MAIN_FUNCTION) ServiceMain},
        {NULL, NULL}
    };

    // Start the control dispatcher
    if (!StartServiceCtrlDispatcher(ServiceTable)) 
    {
        // Handle error
    }
}

StartServiceCtrlDispatcher는 서비스 프로세스의 시작점이 되는 함수로, 이 함수가 호출되어야 비로소 서비스 제어 관리자와 연결되어 서비스 상태를 관리할 수 있습니다.

3. ServiceMain 함수

이 함수 내에서 서비스가 해야 할 작업을 정의합니다. 일반적으로 서비스의 상태를 나타내는 구조체(SERVICE_STATUS_HANDLE)를 사용하고, SetServiceStatus 함수를 통해 상태를 SCM에 보고합니다. 또한 서비스가 언제 중지되거나 일시 중지되는지와 같은 이벤트를 처리할 수 있도록 서비스 제어 핸들러를 등록합니다.

void WINAPI ServiceMain(DWORD argc, LPTSTR* argv) 
{
    // 1. 서비스 상태 등록
    SERVICE_STATUS_HANDLE hServiceStatus = RegisterServiceCtrlHandler(
        SERVICE_NAME,
        ServiceCtrlHandler
    );

    if (hServiceStatus == NULL) 
    {
        // Error handling
        return;
    }

    // 2. 서비스 상태 보고
    SERVICE_STATUS serviceStatus;
    serviceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
    serviceStatus.dwCurrentState = SERVICE_START_PENDING;
    serviceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE;
    // ...

    SetServiceStatus(hServiceStatus, &serviceStatus);

    // 3. 서비스 동작 수행
    // To Do Something
}

4. 서비스 제어 핸들러

ServiceCtrlHandler는 서비스 제어 관리자가 서비스에 전달하는 제어 요청을 처리합니다. 예를 들어, 서비스 중지, 일시 중지, 계속 등을 처리하는 함수입니다.

void WINAPI ServiceCtrlHandler(DWORD dwCtrl) 
{
    switch (dwCtrl) {
        case SERVICE_CONTROL_STOP:
            // 서비스 중지 처리
            break;
        case SERVICE_CONTROL_PAUSE:
            // 서비스 일시 중지 처리
            break;
        case SERVICE_CONTROL_CONTINUE:
            // 서비스 재개 처리
            break;
        default:
            break;
    }
}

5. 서비스 상태 보고

서비스는 SetServiceStatus를 사용하여 서비스 제어 관리자에 현재 상태를 보고합니다. 서비스가 시작 중, 실행 중, 일시 중지, 중지 등 다양한 상태를 서비스 제어 관리자에 알림으로써 적절한 처리를 할 수 있도록 합니다.

BOOL SetServiceStatus(
  SERVICE_STATUS_HANDLE hServiceStatus,
  LPSERVICE_STATUS lpServiceStatus
);

마치며

간단하게 윈도우 서비스 동작 과정에 대해서 알아보았습니다. 이제 위 내용을 기반으로 하여 윈도우 서비스의 예시로 런처 서비스를 만들어 윈도우 부팅 시 메모장을 실행하는 서비스를 만들어보겠습니다.

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

목차 보기