본문으로 바로가기

Windows 서비스 프로그램

category Development/C# 2008. 8. 7. 11:32

C# 을 이용한 윈도우 서비스 프로그램 만들기

1. Visual Studio .NET 을 시작 한 후 C# 콘솔 애플리케이션을 하나 만들어 보도록 합니다 . 프로젝트 이름은 myFirstService 로 합니다 .

2. 프로젝트 안으로 들어오면 솔루션 탐색기의 Class1.cs 파일을 Application.cs 로 바꿉니다 . 이 파일은 이프로젝트의 Entry Point 이므로 직관적인 이름으로 바꾸도록 합니다 .

3. 솔루션 탐색기에서 마우스 우측 버튼을 눌러 속성창을 열어 [ 구성속성 ] --> [ 빌드 ] 에서 XML 문서 파일을 myFirstService.xml 로 바꾸도록 합니다 .

4. 닷넷 프레임워크에서는 윈도우 서비스를 구현 하기 위해 구현 해야 하는 System.ServiceProcess.ServiceBase 라는 베이스 클래스를 가집니다 . 이 클래스는 실제 서비스를 구현하고자 하는 클래스에서 상속을 받아 OnStart(), OnStop() 메소드를 재정의 (Override) 해야 합니다 . 이러한 메소드는 Service Control Manager 로부터 실제 호출 되므로 중요한 기능을 하는 함수 입니다 . OnStart 와 OnStop 메소드는 1 분에 한번씩 Service Control Manager 에게 해당 서비스가 살아 있는지 죽어 있는지에 대한 응답 (return control) 을 주어야 하므로 주의 해야 합니다 . 그러므로 이번 애플리케이션에서는 실제 서비스가 하는 일을 백그라운드 스레드를 이용하여 처리하도록 합니다 .

 

MyServiceBase.cs
using System; 
using System.Collections; 
using System.ComponentModel; 
using System.Data; 
using System.Diagnostics; 
using System.ServiceProcess; 
using System.Threading; 

namespace myFirstService 
{ 
    public class MyServiceBase : System.ServiceProcess.ServiceBase
    { 
        protected Thread m_thread; 
        protected ManualResetEvent m_shutdownEvent; 
        protected TimeSpan m_delay; 

        public MyServiceBase() 
        { 
            // create a new timespan object with a default of 10 seconds delay. 
            m_delay = new TimeSpan(0, 0, 0, 10, 0 ); 
        } 

        /// 
        /// Set things in motion so your service can do its work. 
        /// 
        protected override void OnStart(string[] args) 
        { 
            // create our threadstart object to wrap our delegate method 
            ThreadStart ts = new ThreadStart( this.ServiceMain ); 

            // create the manual reset event and set it to an initial state of unsignaled 
            m_shutdownEvent = new ManualResetEvent(false); 

            // create the worker thread 
            m_thread = new Thread( ts ); 

            // go ahead and start the worker thread 
            m_thread.Start(); 

            // call the base class so it has a chance to perform any work it needs to 
            base.OnStart( args ); 
        } 

        /// 
        /// Stop this service. 
        /// 
        protected override void OnStop() 
        { 
            // signal the event to shutdown 
            m_shutdownEvent.Set(); 

            // wait for the thread to stop giving it 10 seconds 
            m_thread.Join(10000); 

            // call the base class 
            base.OnStop(); 
        } 


        protected void ServiceMain() 
        { 
            bool bSignaled = false; 
            int nReturnCode = 0; 

            while( true ) 
            { 

                // wait for the event to be signaled or for the configured delay 
                bSignaled = m_shutdownEvent.WaitOne( m_delay, true ); 

                // if we were signaled to shutdow, exit the loop 
                if( bSignaled == true ) 

                break; 

                // let's do some work 
                nReturnCode = Execute(); 

            } 
        } 

        protected virtual int Execute() 
        { 
            return -1; 
        } 
    } 
} 

5. 이번에는 이전에 만든 MyServiceBase 를 상속하는 MyChildServiceBase.cs 클래스를 만들도록 합니다 .

MyChildServiceBase.cs
using System; 
using System.Collections; 
using System.ComponentModel; 
using System.Data; 
using System.Diagnostics; 
using System.ServiceProcess; 

namespace myFirstService 
{ 
    public class MyChildServiceBase : MyServiceBase 
    { 

        public MyChildServiceBase() 
        { 
            // TODO: Add any initialization after the InitComponent call 
        } 

        /// 
        /// Set things in motion so your service can do its work. 
        /// 
        protected override void OnStart(string[] args) 

        { 
            // TODO: Add code here to start your service. 
            base.OnStart( args ); 
        } 

        /// 
        /// Stop this service. 
        /// 
        protected override void OnStop() 
        { 
            // TODO: Add code here to perform any tear-down necessary to stop your service.
            base.OnStop(); 
        } 
    } 
} 


6. 이전에는 실제 AdminService 를 수행 하는 MyAdminService.cs 를 만듭니다 .

MyAdminService.cs
using System; 
using System.Collections; 
using System.ComponentModel; 
using System.Data; 
using System.Diagnostics; 
using System.ServiceProcess; 

namespace myFirstService 
{ 

    public class MyAdminService : MyServiceBase 
    { 

        public MyAdminService() 
        { 
            this.ServiceName = "MyAdminSvc"; 
        } 

        /// 
        /// Set things in motion so your service can do its work. 
        /// 
        protected override void OnStart(string[] args) 
        { 
            base.OnStart( args ); 
        } 

        /// 
        /// Stop this service. 
        /// 
        protected override void OnStop() 
        { 
            base.OnStop(); 
        } 

        protected override int Execute() 
        { 
            // for right now we'll just log a message in the Application message log to- let us know that.
            // our service is working 
            System.Diagnostics.EventLog.WriteEntry("MyAdminSvc", ServiceName + "::Execute()"); 
            return 0; 
        } 
    } 
} 


7. 지금까지 하나의 서비스를 만들어 보았으며 이제는 Application.cs 파일의 메인 메소드를 수정 하여 실제 서비스가 기동 되도록 하겠습니다 . ( 전체 Application.cs 파일은 아래와 같습니다 )

Application.cs
using System; 
using System.ServiceProcess; 

namespace myFirstService 
{ 

    /// 
    /// Summary description for Class1. 
    /// 
    class Application 
    { 
        /// 
        /// The main entry point for the application. 
        /// 
        [STAThread] 
        static void Main (string[] args) 
        { 
            // we'll go ahead and create an array so that we can add the different- services that 
            // we'll create over time. 
            ServiceBase[] servicesToRun; 

            // to create a new instance of a new service, just add it to the list of- services 
            // specified in the ServiceBase array constructor. 
            servicesToRun = new ServiceBase[] { new MyAdminService() }; 

            // now run all the service that we have created. This doesn't actually- cause the services 
            // to run but it registers the services with the Service Control Manager so- that it can 
            // when you start the service the SCM will call the OnStart method of the- service. 
            ServiceBase.Run( servicesToRun ); 
        } 
    } 
} 

8. 아래에서 추가될 인스톨러 (Installer) 는 제어판의 서비스에 등록 할 때 필요한 파일 입니다 .

MyInstaller.cs
using System; 
using System.Collections; 
using System.ComponentModel; 
using System.Configuration.Install; 
using System.ServiceProcess; 

namespace myFirstService 
{ 
	/// 
	/// Summary description for SpadesInstaller. 
	/// 
	[RunInstaller(true)] 
	public class MyInstaller : System.Configuration.Install.Installer 
	{ 
    		public MyInstaller() 
	{ 
	ServiceProcessInstaller process = new ServiceProcessInstaller(); 

	process.Account = ServiceAccount.LocalSystem; 

	ServiceInstaller serviceAdmin = new ServiceInstaller(); 

	serviceAdmin.StartType = ServiceStartMode.Manual; 
	serviceAdmin.ServiceName = "MyAdminSvc"; 
	serviceAdmin.DisplayName = "My Administration Service"; 

	// Microsoft didn't add the ability to add a description for the services we- are going to install 
	// To work around this we'll have to add the information directly to the registry-but I'll leave 
	// this exercise for later. 
	// now just add the installers that we created to our parents container, the- documentation 
	// states that there is not any order that you need to worry about here but- I'll still 
	// go ahead and add them in the order that makes sense. 

	Installers.Add( process ); 
	Installers.Add( serviceAdmin ); 
} 
참고 : http://msdn.microsoft.com/ko-kr/library/zt39148a(VS.80).aspx

'Development > C#' 카테고리의 다른 글

제네릭이란 무엇인가?  (0) 2008.11.17
DataGridView 내용 엑셀에 붙이기  (0) 2008.10.30
MySQL 연동  (0) 2008.10.30
아스키코드표  (0) 2008.10.30
DataGridView Tip  (0) 2008.08.05