서비스를 설치 하고, 제거 할 수 있으며 서비스를 시작하면 1초마다 윈도우즈 기본 에러메시지.. 띵~ 이 나옵니다.
서비스를 일시 중지 시키면 동작이 멈추고, 재시작하면 다시 띵~ 이러한 구조로 흘러갑니다.
간단하게 util.h 와 util.cpp 를 만들어서 구조와 크게 상관없는 함수들을 모아놓았습니다.
#include "util.h"
#pragma comment(lib, "Advapi32.lib")
const char* S_NAME = "TEST";
const char* S_DISP = "TEST Service";
const char* S_DESC = "TEST Service Description";
// 서비스를 제어하기 위한 핸들을 저장하고 있어야한다.
SERVICE_STATUS_HANDLE srvhd = 0;
// 서비스의 상태를 저장하는 플래그
DWORD srvst = SERVICE_STOPPED;
int main(int argc, char** argv)
{
// 실행파일의 경로를 구한다.
char S_BINARY[MAX_PATH] = {0};
::GetModuleFileName(NULL, S_BINARY, MAX_PATH);
// 인자가 2개이고, 두번째 인자가 'i' 이면 인스톨
if(argc == 2 && argv[1][0] == 'i')
{
ServiceInstall();
return 0;
}
// 인자가 2개이고, 두번째 인자가 'u' 이면 언인스톨
else if(argc == 2 && argv[1][0] == 'u')
{
ServiceUninstall();
return 0;
}
SERVICE_TABLE_ENTRY STE[] =
{
{(char*)S_NAME, (LPSERVICE_MAIN_FUNCTION)_tmain_service},
{NULL,NULL}
};
// 서비스 메인 함수를 등록한다.
if(StartServiceCtrlDispatcher(STE) == FALSE)
return -1;
return 0;
}
VOID _tmain_service(INT ARGC, LPSTR* ARGV)
{
srvhd = RegisterServiceCtrlHandlerEx(S_NAME, _tmain_service_handler, NULL);
if (srvhd == NULL)
return;
// 정상적으로 서비스가 시작되었다.
// 서비스의 기본적인 작업이 끝나고 메인 루프로 들어가기 전에 꼭 상태를
// 런닝 상태로 만들어주어야 한다.
// 이걸 처리해놓지 않으면, 서비스 관리자에서 정상적으로 시작된건을 인지하지 못한다.
SET_SERVICE_STATE(srvhd, SERVICE_RUNNING);
// 무한 루프를 돌면서 띵띵~ 소리를 낸다.
while(GET_SERVICE_STATE() != SERVICE_STOPPED)
{
// 일시 중지 상태일 때는 그냥 별동작 없이 대기를 반복한다.
if(GET_SERVICE_STATE() == SERVICE_PAUSED)
{
Sleep(1000);
continue;
}
::MessageBeep(0xFFFFFFFF);
Sleep(1000);
}
return;
}
DWORD WINAPI _tmain_service_handler(DWORD fdwControl, DWORD dwEventType, LPVOID lpEventData, LPVOID lpContext)
{
// 서비스라 좋은점이 있네, 시스템에서 발생하는 잡다구리한 이벤트들을 별로 힘들이지 않고
// 이곳에서 받아다가 처리할 수 있다.
switch (fdwControl)
{
case SERVICE_CONTROL_PAUSE:
SET_SERVICE_STATE(srvhd, SERVICE_PAUSE_PENDING,0);
// 서비스를 일시 중지 시킨다.
SET_SERVICE_STATE(srvhd, SERVICE_PAUSED);
break;
case SERVICE_CONTROL_CONTINUE:
SET_SERVICE_STATE(srvhd, SERVICE_CONTINUE_PENDING,0);
// 일시 중지 시킨 서비스를 재개한다.
SET_SERVICE_STATE(srvhd, SERVICE_RUNNING);
break;
case SERVICE_CONTROL_STOP:
SET_SERVICE_STATE(srvhd, SERVICE_STOP_PENDING, 0);
// 서비스를 멈춘다 (즉, 종료와 같은 의미)
SET_SERVICE_STATE(srvhd, SERVICE_STOPPED);
break;
default:
break;
}
return NO_ERROR;
}
// 아래 파일은 샘플 프로젝트입니다.
다음에는 개인용 피씨나, 서버 피씨에 어떤 사용자가 접속하고, 종료했는지 터미널 서버로 들어왔다면
어떤 IP주소로 접속했는지 등등등.. '내컴퓨터 누가 건드렸어..' 서비스를 만들어 보도록 하겠습니다.
출처: https://crowback.tistory.com/184?category=86281 [까막's 블로그:티스토리]