본문 바로가기
Programming/Win_API

Windows 서비스 프로그램

by bbolmin 2014. 3. 22.




서비스를 동작시키기 위해서는 아래의 3가지 형태의 프로그램이 필요하다.



1. 서비스 프로그램

실제 작업을 처리하는 서비스 프로그램이다.



2. 서비스 설정 프로그램 

- 서비스의 목록을 레지스트리(HKEY_LOCAL_MACHINE\System\CurrentControlSet\Service)에 DB형태로 저장해서 관리하는데 서비스 프로그램을 설치 및 제거하는데 사용된다.



3. 서비스 제어 프로그램

서비스 프로그램은 백그라운드에서 동작하기 때문에 사용자가 제어할 수 없다. 따라서 서비스 제어 프로그램을 이용해서 서비스 프로그램을 제어(중지, 시작 등)한다.





[ 서비스 DB ]


 

[HKEY_LOCAL_MACHINE\System\CurrentControlSet\Service 레지스트리 (service.msc와 동일)]






1. 서비스 프로그램



[동작 Logic]


(Main_1) SCM에 서비스를 등록한다. - StartServiceCtrlDispatcher에서 Dispatcher Thread(서비스 함수)를 실행시킨다.

(ServiceMain_1) main에서 등록한 서비스 함수가 실행된다.

(ServiceMain_2) RegisterServiceCtrlHandler로 SCM에 핸들러를 등록한다.

(ServiceMain_3) 자신의 상태를 SCM에 전송한다.

(Handler) SCM에서 오는 제어는 핸들러 함수에서 처리한다.

(ServiceMain_4) 서비스에서 원하는 작업을 수행한다.

(Main_2) Dispatcher Thread(서비스 함수)가 모두 종료되면 StartServiceCtrlDispatcher가 리턴된다.





 = 서비스 프로그램 C++ 코드 기본 틀 =



#include "Windows.h"


SERVICE_STATUS_HANDLE g_hSrv;  
DWORD g_NowState;  
BOOL g_bPause;  
HANDLE Exit_Event;  

void ServiceMain1(DWORD argc, LPTSTR *argv);  
void ServiceHandler (DWORD fdwControl);
void SetStatus ( DWORD dwState, DWORD dwAccept);
 

// 메인 함수
int main(int argc, char* argv[])  
{  

	SERVICE_TABLE_ENTRY ste[] = 
	{  
		{L"TestService",(LPSERVICE_MAIN_FUNCTION)ServiceMain1},  
		{NULL, NULL}  
	};  

	//SCM에 서비스를 등록한다.
	StartServiceCtrlDispatcher(ste);  

	return 0;
}

// 서비스 메인함수
void ServiceMain1(DWORD argc, LPTSTR *argv)  
{  
	//SCM의 제어를 처리할 핸들러 등록한다.
	g_hSrv = RegisterServiceCtrlHandler(L"TestService", (LPHANDLER_FUNCTION)ServiceHandler);  

	if ( g_hSrv == 0) {  
		return ;  
	}  

	//SCM에 작업이 시작됨을 알린다.
	SetStatus(SERVICE_START_PENDING, 3);  

	// --- 필요한 초기화 작업 수행

	SetStatus (SERVICE_RUNNING, 3);  
	
	// --- 원하는 작업 수행


}

// 핸들러 함수
void ServiceHandler (DWORD fdwControl)   
{  
    if(fdwControl == g_NowState)  
        return ;  
  
    switch(fdwControl){  
      
        case SERVICE_CONTROL_PAUSE:  
            SetStatus (SERVICE_PAUSE_PENDING,0);  
            g_bPause=TRUE;  
            SetStatus (SERVICE_PAUSED, 3);  
            break;  
  
        case SERVICE_CONTROL_CONTINUE:  
            SetStatus (SERVICE_CONTINUE_PENDING,0);  
            g_bPause=FALSE;  
            SetStatus (SERVICE_RUNNING, 3);  
            break;  
  
        case SERVICE_CONTROL_STOP:  
            SetStatus (SERVICE_STOP_PENDING,0);  
            SetStatus (SERVICE_STOPPED,0);  
            break;  
      
        case SERVICE_CONTROL_INTERROGATE:  
        default:  
            SetStatus(g_NowState, 3);  
            break;  
          
    }  
  
}  

void SetStatus ( DWORD dwState, DWORD dwAccept)  
{  
    SERVICE_STATUS ss;  
    ss.dwServiceType = SERVICE_WIN32_OWN_PROCESS;  
    ss.dwCurrentState = dwState;  
    ss.dwControlsAccepted = dwAccept;  
    ss.dwWin32ExitCode = 0;  
    ss.dwServiceSpecificExitCode = 0;  
    ss.dwCheckPoint=0;  
    ss.dwWaitHint =0;  
  
    g_NowState = dwState;  
    SetServiceStatus (g_hSrv, &ss);  
} 









[REF] 


http://linkc.tistory.com/104

http://rhea.pe.kr/143

http://blog.naver.com/shin5341?Redirect=Log&logNo=80035810083