윈도우즈 NT 플랫폼은
서비스라는
프로그램
형태를
지원한다. 이러한
서비스는
시스템
서비스라는
이름으로
불리며
윈도우즈
시스템이
시작하여
종료할
때까지
배후에서
실행되면서
유저
또는
시스템에
특정
서비스를
제공하는
프로그램이다. 이러한
시스템
서비스
프로그램은
운영체제의
일부로서
동작하기
때문에
작성시
큰
주의가
필요하다.
이
장에서는
윈도우즈
시스템
서비스
프로그래밍에
대해
알아보고
간단한
서비스
프로그램을
작성해
보고자
한다.
시스템
서비스
프로그램은
일반적으로
다음과
같은 3개의 export 된
함수를
가지게
된다.
첫번째
함수는 main() 함수로서
일반적인
콘솔
어플리케이션과
동일하다. 즉, 서비스
프로그램은
콘솔
어플리케이션
이기도
하다. Main()는 WinMain()
함수로도
대체
될
수
있다.
#include "Winsvc.h"
main()
{
SERVICE_TABLE_ENTRY Table[]={{"SampleService1",ServiceMain},
{NULL,NULL}};
StartServiceCtrlDispatcher(Table);
}
위의
예는
가장
간단한
예
일
뿐이다. 위의
예에서 main() 함수의
주
입무는
서비스
콘트롤
디스패치
핸들러를
실행시키는
것
뿐이다.
그러나
일반적인
서비스
프로그램은
자체적인
서비스
인스톨/언인스톨
루틴을
포함하고
있으며
명령라인에서
옵션을
통해
본
프로그램의
서비스를
제어한다.
이
예제에선 4개의
옵션을
지원하며
각각의
옵션은
다음과
같다.
-i : 서비스를
인스톨한다.
-d : 서비스를
종료하고
제거한다.
-start :
종료되어
있는
서비스를
시동시킨다.
-stop : 실행중인
서비스를
종료시킨다.
이러한
예가
들어간 main() 함수는
아래와
같으며
서비스를
핸들링
하기
위해
본인이
작성한 LXSVC 클래스를
호출하고
있다.
#include
<stdio.h>
#include
<wtypes.h>
#include
<winnt.h>
#include
<winsvc.h>
#include
<winuser.h>
#include
"DbgOut.h"
#include
"LxSvc.h"
#define ECHOSVC_NAME "Test Echo
Service"
#define ECHOSVC_DESC "Win32 API Cafe
example"
VOID WINAPI
ServiceMain(DWORD argc, LPTSTR *argv);
VOID WINAPI
ServiceCtrlHandler(DWORD dwControl);
bool g_isRunning
= false;
LXSVC *g_lxSvc =
NULL;
int main( int argc, char*
argv[] )
{
SERVICE_TABLE_ENTRY DispatchTable[] = { {
ECHOSVC_NAME, ServiceMain }, { 0, 0 } };
g_lxSvc = new LXSVC;
if ( argc
> 1 && !( stricmp(argv[1], "-i") ) )
{
if (
g_lxSvc->InstallService(NULL, ECHOSVC_NAME, ECHOSVC_DESC) )
{
g_lxSvc->StartService(NULL,
ECHOSVC_NAME);
}
}
if ( argc
> 1 && !( stricmp(argv[1], "-d" ) ) ) // Uninstall the
Service
{
g_lxSvc->UnistallService(NULL,
ECHOSVC_NAME);
}
if ( argc
> 1 && !( stricmp(argv[1], "-stop" ) ) ) // Stop the
Service
{
g_lxSvc->ControlService(NULL,
ECHOSVC_NAME, SERVICE_CONTROL_STOP);
}
if ( argc
> 1 && !( stricmp(argv[1], "-start" ) ) ) // Start the
Service
{
g_lxSvc->StartService(NULL,
ECHOSVC_NAME);
}
if ( argc
< 2 ) {
if (
!StartServiceCtrlDispatcher(DispatchTable) )
{
DbgOut("EchoServer :
StartServiceCtrlDispatcher error = %d\n", GetLastError() );
}
}
delete
g_lxSvc;
g_lxSvc = NULL;
return
0;
}
LXSVC 클래스의
멤버함수
이름은
지극히
직관적이기
때문에
이해하기
어렵지
않을
것이다. 서비스를
추가, 제거, 시작, 종료
등의
제어를
위해선
서비스
제어
관리자(Service Control Manager =
SCM)를
다루어야
한다. 자세한
내용은 LXSVC 클래스
내부의
함수를
보도록
하며
이
강좌에선
서비스를
등록하는
부분만
살펴
봄으로서 SCM 프로그래밍을
살짝만
맛보기로한다.
bool LXSVC::InstallService(LPTSTR
tszRemoteMachine, LPTSTR tszServiceName, LPTSTR tszDisplayName, LPTSTR
tszModulePathName)
{
DbgOut("LXSVC::InstallService\n");
bool bRet =
false;
if (
m_bWin9x ) {
} else
{
TCHAR
tszBuffer[255];
TCHAR
tszModulePath[MAX_PATH];
SC_HANDLE hSvcMgr =
OpenSCManager(tszRemoteMachine, NULL,
SC_MANAGER_ALL_ACCESS);
if (
hSvcMgr ) {
if (
tszModulePathName != NULL ) {
_tcscpy(tszModulePath,
tszModulePathName);
} else
{
GetModuleFileName(GetModuleHandle(NULL), tszModulePath,
MAX_PATH);
}
_tcscpy( tszBuffer, "\""
);
_tcscat( tszBuffer, tszModulePath
);
_tcscat( tszBuffer, "\""
);
SC_HANDLE hSvc = CreateService(hSvcMgr, tszServiceName, tszDisplayName,
SERVICE_ALL_ACCESS,
SERVICE_WIN32_OWN_PROCESS,
SERVICE_AUTO_START, SERVICE_ERROR_NORMAL,
tszBuffer,
NULL, NULL, NULL, NULL, NULL );
if (
hSvc ) {
bRet =
true;
CloseServiceHandle(hSvc);
}
else {
DbgOut("LXSVC::InstallService -
CreateService error = %d\n", GetLastError());
}
CloseServiceHandle(hSvcMgr);
} else
{
DbgOut("LXSVC::InstallService -
OpenSCManager error = %d\n", GetLastError() );
}
}
return
bRet;
}
위의
예에서InstallService()
멤버함수는
먼저
서비스
제어
관리자 SCM을
열고(OpenSCManager())
그
핸들을
사용하여
새로운
서비스를
생성(CreateService())하고
있다. 모든
서비스
제어
함수는
위와같이 SCM을
열고 SCM안의
서비스
핸들을
생성
또는
열은
후
그
핸들을
사용하여
제어하게
된다. 물론
모든
사용이
끝난
후는
서비스
핸들을
닫는다.
다음
강좌에서는
서비스의
다른 2 중요한
함수인
서비스의
메인
함수 (ServiceMain())
과
서비스
제어자(ServiceCtrlHandler())
에
대해
알아보기로
한다.
- Reference
'[ Windows Program ] > Windows API' 카테고리의 다른 글
멀티쓰레드 윈도우즈 소켓 프로그래밍 #4 – 멀티쓰레드 프로그래밍 (0) | 2011.03.08 |
---|---|
멀티쓰레드 윈도우즈 소켓 프로그래밍 #3 – 윈도우즈 서비스 프로그래밍 (0) | 2011.03.08 |
멀티쓰레드 윈도우즈 소켓 프로그래밍 #1 (0) | 2011.03.08 |
비동기소켓 서버구현 (0) | 2011.03.07 |
비동기 소켓 - WSAAsyncSelect (1) | 2011.03.07 |