2009. 9. 22. 15:31

Windows Service Program 제작을 위한 Skeleton 공유 (플러그인 이용)


UNIX/LINUX의 daemon 같은 개념의 프로그램이,
윈도우의 Service 프로그램 입니다.
이것들은 "시작 -> 실행"하여, "services.msc"를 실행하여 통해 조회가 가능합니다.

이러한 Windows Service Program은 보통의 WinMain(...)과는 약간 다르게 구현되어야 합니다.
즉, Windows Service controller와 통신을 지원해야 한다는 점이죠.

또한, serrvices.exe에 의해 실행되기 때문에, 그 디버깅 방법이 생각보단 까다롭습니다.
(뭐... _asm { INT 3; } 과 같이 강제 assert를 걸든지, windbg 등에 attach 하던지...)

그러한 것을 해결해 주고, 쉽게 Service Program을 제작할 수 있는 환경을 공유합니다.

필요한 component는 다음과 같습니다.

  • FFwSvc.exe ; 서비스에 등록될 Holder 프로그램. (파일명은 알아서 수정하세요)
  • FFwMon.plg ; FFwSvc.exe에서 LoadLibrary(...) 하는 플러그인 DLL. 프로그램의 Main을 담당.
  • FFwSvcInstaller.exe ; Service Controller Helper 프로그램. 등록/비등록/시작/종료를 명령함.

즉, 배포는 FFwSvc.exe + FFwMon.plg로 하면 되고, 디버깅 시에 FFwSvcInstaller.exe를 사용합니다.
그리고, 평상시의 개발은 FFwMon.plg만 구현하시면 됩니다.

여러분들이 구현해야 할 사항


  1. MYTRACELOG(...)
    OutputDebugString(...)을 사용을 하던지, 본인이 사용하는 로그 함수를 쓰세요.
    현재는 _tprintf로 #define 되어 있습니다.
  2. ...\FFwSvc\FFwSvcApp.cpp의 CFFwSvcApp::StartServiceDispatch(...) 수정
    SERVICE_TABLE_ENTRY pstArrSTE[] = {{TEXT("FFwSvc")...
    에서 FFwSvc를 본인의 Service Name으로 수정.
    Service Name은 Service의 시스템 고유 ID로 생각하면 되며,
    http://msdn.microsoft.com/en-us/library/ms686001(VS.85).aspx
    를 참고하시기 바랍니다.
  3. ...\FFwSvc\FFwSvcApp.cpp의 CFFwSvcApp::DoApp(VOID)(...) 수정
    GetProcAddress(hPlugIn, "FFwMon_PlugInMain");
    에 자신의 플러그인 (FFwMon.plg의 Export 함수 이름)을 기입합니다.
  4. 플러그인 모듈(FFwMon.plg)을 수정합니다.
    ..\Inc\FFwMon.h에 LPFN_FFwMon_PlugInMain를 3단계에서 제시한 함수명으로 변경합니다.
    ..\Inc\FFwMon.cpp에 있는 유일한 Export 함수에서, 3단계에서 제시한 함수명으로 변경합니다.
  5. DEAMON 함수를 제작합니다.
    ..\Inc\FFwMon.cpp에 DAEMON_JOB(...)을 제작합니다.
    단, hEventStop Event를 체크하셔야 합니다. DAEMON_JOB(...)에서 Thread를 하나 만들어,
    해당 Event에 Singnal이 체크되었을때 DAEMON_JOB(...)을 종료해야 합니다.
    UINT CheckTerminateSingnal(...) 
    {
       ...
       dwValue = ::WaitForSingleObject(hEventStop);
       if (WAIT_OBJECT_0 == dwValue)
       {
          pContext->m_bTerminate=TRUE;
          ...
          return 0;
       ...
     }
  6. 디버깅 툴인 ServiceInstaller를 수정합니다.
    ..\FFwSvcInstaller\FFwSvcInsallerDlg.cpp에서,
    ::OpenService(...) / ::CreateService(...)의 Service Name을 2단계에서 지정한 값을 변경합니다.
    ::CreateServie(...)의 Service Name to Display 값에 Service 설명을 기입합니다.
    (참고로, 서비스의 시작 유형등을 이곳에서 수정할 수 있습니다.)


테스트툴 사용방법


FFwSvcInstaller를 실행하면 위와 같습니다.
(비스타 이상에서는 FFwSvcInstaller를 관리자 권한으로 실행하셔야 합니다.)

크게 Run by service / Run by me로 되어 있는데,

Run by service는 services.msc를 통한 실행 효과를 줍니다.
즉, Install은 서비스 등록, UnInstall은 서비스 등록 해제, Start는 서비스 시작, Stop은 서비스 종료
를 의미합니다.
물론, Path에는 Service .exe의 Full Path를 넣으셔야 합니다.

Run by me는 FFwSvcInstaller에서 플러그인을 직접 실행합니다.
사실 Service controller에 의해 서비스 프로그램이 실행되면, 디버깅 하기가 무척 힘들어 집니다.
그렇기 때문에, 만들어진 것이 "Run by me"로, FFwSvcInstaller에서 플러그인을 직접 실행하여,
Attach하여 디버깅을 안해도 디버깅 가능하도록 했습니다.

'프로그래밍 > Let's Share it' 카테고리의 다른 글

CListCtrl의 내용을 프린터로 출력하기  (2) 2009.09.23
Thread Safe Memory Pool Templete 공유  (0) 2009.09.22
웹 크롤러(WebCrawler) 공유  (2) 2009.09.16
RC2 Maker  (0) 2009.09.16
Bitmap을 SetPixel로 그리기  (0) 2009.09.15