윈도우 서비스는 운영 체제의 부팅부터 종료까지 백그라운드에서 동작할 수 있는 응용 프로그램입니다. 이전 포스팅에서 간단하게 윈도우 서비스 애플리케이션을 만들고 서비스 제어 관리자를 통해 서비스를 제어해보았습니다. 이번 포스팅에서는 실행 부터 종료까지 간단하게 윈도우 서비스 동작 과정에 대해서 알아보겠습니다.
윈도우 서비스 동작 과정
- 서비스 프로세스가 시작되고
main
함수에서StartServiceCtrlDispatcher
를 호출 StartServiceCtrlDispatcher
가 서비스 제어 관리자와 연결되고, 서비스의ServiceMain
함수가 호출됨ServiceMain
에서 서비스가 해야 할 작업을 수행하며,SetServiceStatus
로 상태를 계속 서비스 제어 관리자에 보고- 서비스 제어 관리자에서 발생하는 제어 요청을
ServiceCtrlHandler
를 통해 처리 - 서비스가 종료될 때
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
);
마치며
간단하게 윈도우 서비스 동작 과정에 대해서 알아보았습니다. 이제 위 내용을 기반으로 하여 윈도우 서비스의 예시로 런처 서비스를 만들어 윈도우 부팅 시 메모장을 실행하는 서비스를 만들어보겠습니다.
# 관련 포스트
# 참고 자료