첨부 실행 코드는 나눔고딕코딩 폰트를 사용합니다.
728x90
반응형
728x170

TestProject.zip
0.01MB

▶ MultimediaTimerDelegate.cs

namespace TestProject
{
    /// <summary>
    /// 멀티미디어 타이머 대리자
    /// </summary>
    /// <param name="id">ID</param>
    /// <param name="message">메시지</param>
    /// <param name="userContext">사용자 컨텍스트</param>
    /// <param name="reserved1">예약 1</param>
    /// <param name="reserved2">예약 2</param>
    public delegate void MultimediaTimerDelegate(uint id, uint message, ref uint userContext, uint reserved1, uint reserved2);
}

 

728x90

 

▶ MultimediaTimer.cs

using System;
using System.ComponentModel;
using System.Runtime.InteropServices;

namespace TestProject
{
    /// <summary>
    /// 멀티미디어 타이머
    /// </summary>
    public class MultimediaTimer : IDisposable
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Event
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 틱 이벤트 - Tick

        /// <summary>
        /// 틱 이벤트
        /// </summary>
        public event EventHandler Tick;

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Import
        ////////////////////////////////////////////////////////////////////////////////////////// Static
        //////////////////////////////////////////////////////////////////////////////// Private

        #region 타이머 이벤트 설정하기 - TimeSetEvent(delay, resolution, callback, userContext, eventType)

        /// <summary>
        /// 타이머 이벤트 설정하기
        /// </summary>
        /// <param name="delay">지연 시간 (단위 : ms)</param>
        /// <param name="resolution">해상도 (단위 : ms)</param>
        /// <param name="callback">콜백 함수</param>
        /// <param name="userContext">사용자 컨텍스트</param>
        /// <param name="eventType">이벤트 타입</param>
        /// <returns>타이머 ID</returns>
        /// <remarks>
        /// eventType : 0(1회성 이벤트), 1(정기 이벤트)
        /// </remarks>
        [DllImport("winmm", SetLastError = true, EntryPoint = "timeSetEvent")]
        private static extern uint TimeSetEvent(uint delay, uint resolution, MultimediaTimerDelegate callback, ref uint userContext, uint eventType);

        #endregion
        #region 타이머 이벤트 제거하기 - TimeKillEvent(timerID)

        /// <summary>
        /// 타이머 이벤트 제거하기
        /// </summary>
        /// <param name="timerID">타이머 ID</param>
        [DllImport("winmm", SetLastError = true, EntryPoint = "timeKillEvent")]
        private static extern void TimeKillEvent(uint timerID);

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region Field

        /// <summary>
        /// 리소스 해제 여부
        /// </summary>
        private bool disposed = false;

        /// <summary>
        /// 주기
        /// </summary>
        private int interval;
        
        /// <summary>
        /// 해상도 (단위 : ms)
        /// </summary>
        private int resolution;

        /// <summary>
        /// 타이머 ID
        /// </summary>
        private uint timerID; 

        /// <summary>
        /// 멀티미디어 타이머 대리자
        /// </summary>
        private readonly MultimediaTimerDelegate multimediaTimerDelegate;

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Property
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 주기 - Interval

        /// <summary>
        /// 주기
        /// </summary>
        public int Interval
        {
            get
            {
                return this.interval;
            }
            set
            {
                if(this.disposed)
                {
                    throw new ObjectDisposedException("MultimediaTimer");
                }

                if(value < 0)
                {
                    throw new ArgumentOutOfRangeException("Interval");
                }

                this.interval = value;

                if(Resolution > Interval)
                {
                    Resolution = value;
                }
            }
        }

        #endregion
        #region 해상도 - Resolution

        /// <summary>
        /// 해상도
        /// </summary>
        public int Resolution
        {
            get
            {
                return this.resolution;
            }
            set
            {
                if(this.disposed)
                {
                    throw new ObjectDisposedException("MultimediaTimer");
                }

                if(value < 0)
                {
                    throw new ArgumentOutOfRangeException("Resolution");
                }

                this.resolution = value;
            }
        }

        #endregion
        #region 실행 여부 - IsRunning

        /// <summary>
        /// 실행 여부
        /// </summary>
        public bool IsRunning
        {
            get
            {
                return this.timerID != 0;
            }
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - MultimediaTimer()

        /// <summary>
        /// 생성자
        /// </summary>
        public MultimediaTimer()
        {
            this.multimediaTimerDelegate = new MultimediaTimerDelegate(ProcessMultimediaTimer);

            Resolution = 5;
            Interval   = 10;
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Destructor

        #region 소멸자 - ~MultimediaTimer()

        /// <summary>
        /// 소멸자
        /// </summary>
        ~MultimediaTimer()
        {
            Dispose(false);
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 시작하기 - Start()

        /// <summary>
        /// 시작하기
        /// </summary>
        public void Start()
        {
            if(this.disposed)
            {
                throw new ObjectDisposedException("MultimediaTimer");
            }

            if(IsRunning)
            {
                return;
            }

            uint userContext = 0;

            this.timerID = TimeSetEvent((uint)Interval, (uint)Resolution, multimediaTimerDelegate, ref userContext, 1);

            if(this.timerID == 0)
            {
                int error = Marshal.GetLastWin32Error();

                throw new Win32Exception(error);
            }
        }

        #endregion
        #region 중단하기 - Stop()

        /// <summary>
        /// 중단하기
        /// </summary>
        public void Stop()
        {
            if(this.disposed)
            {
                throw new ObjectDisposedException("MultimediaTimer");
            }

            if(!IsRunning)
            {
                return;
            }

            StopInternal();
        }

        #endregion
        #region 리소스 해제하기 - Dispose()

        /// <summary>
        /// 리소스 해제하기
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
        }

        #endregion

        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region 멀티미디어 타이머 처리하기 - ProcessMultimediaTimer(id, message, userContext, reserved1, reserved2)

        /// <summary>
        /// 멀티미디어 타이머 처리하기
        /// </summary>
        /// <param name="id">ID</param>
        /// <param name="message">메시지</param>
        /// <param name="userContext">사용자 컨텍스트</param>
        /// <param name="reserved1">예약 1</param>
        /// <param name="reserved2">예약 2</param>
        private void ProcessMultimediaTimer(uint id, uint message, ref uint userContext, uint reserved1, uint reserved2)
        {
            Tick?.Invoke(this, EventArgs.Empty);
        }

        #endregion
        #region 중단하기 (내부용) - StopInternal()

        /// <summary>
        /// 중단하기 (내부용)
        /// </summary>
        private void StopInternal()
        {
            TimeKillEvent(this.timerID);

            this.timerID = 0;
        }

        #endregion
        #region 리소스 해제하기 - Dispose(disposing)

        /// <summary>
        /// 리소스 해제하기
        /// </summary>
        /// <param name="disposing">리소스 해제 여부</param>
        private void Dispose(bool disposing)
        {
            if(this.disposed)
            {
                return;
            }
        
            this.disposed = true;

            if(IsRunning)
            {
                StopInternal();
            }
        
            if(disposing)
            {
                Tick = null;

                GC.SuppressFinalize(this);
            }
        }

        #endregion
    }
}

 

300x250

 

▶ MainForm.cs

using System;
using System.Diagnostics;
using System.Windows.Forms;

namespace TestProject
{
    /// <summary>
    /// 메인 폼
    /// </summary>
    public partial class MainForm : Form
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region Field

        /// <summary>
        /// 스톱워치
        /// </summary>
        private Stopwatch stopwatch = new Stopwatch();

        /// <summary>
        /// 멀티미디어 타이머
        /// </summary>
        private MultimediaTimer multimediaTimer;

        /// <summary>
        /// 표시 타이머
        /// </summary>
        private Timer displayTimer;

        /// <summary>
        /// 현재 경과 시간 (단위 : 밀리초)
        /// </summary>
        private double currentElapsedTime;

        /// <summary>
        /// 이전 시간 (단위 : 밀리초)
        /// </summary>
        private double previousTime;

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - MainForm()

        /// <summary>
        /// 생성자
        /// </summary>
        public MainForm()
        {
            InitializeComponent();

            this.multimediaTimer = new MultimediaTimer();

            this.multimediaTimer.Interval   = 1;
            this.multimediaTimer.Resolution = 0;

            this.displayTimer = new Timer();

            this.displayTimer.Interval = 30;

            FormClosing               += Form_FormClosing;
            this.multimediaTimer.Tick += multimediaTimer_Tick;
            this.displayTimer.Tick    += displayTimer_Tick;

            this.multimediaTimer.Start();
            this.displayTimer.Start();

            this.stopwatch.Start();
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region 폼을 닫을 경우 처리하기 - Form_FormClosing(sender, e)

        /// <summary>
        /// 폼을 닫을 경우 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void Form_FormClosing(object sender, FormClosingEventArgs e)
        {
            this.displayTimer.Stop();
            this.multimediaTimer.Stop();
        }

        #endregion
        #region 멀티미디어 타이머 틱 처리하기 - multimediaTimer_Tick(sender, e)

        /// <summary>
        /// 멀티미디어 타이머 틱 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void multimediaTimer_Tick(object sender, EventArgs e)
        {
            this.currentElapsedTime = this.stopwatch.ElapsedMilliseconds - this.previousTime;

            Console.WriteLine($"멀티미디어 타이머 : [{DateTime.UtcNow:o}] {currentElapsedTime}");

            this.previousTime = this.stopwatch.ElapsedMilliseconds ;
        }

        #endregion
        #region 표시 타이머 틱 처리하기 - displayTimer_Tick(sender, e)

        /// <summary>
        /// 표시 타이머 틱 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void displayTimer_Tick(object sender, EventArgs e)
        {
            this.currentElaspesTimeValueLabel.Text = this.currentElapsedTime.ToString();
        }

        #endregion
    }
}
728x90
반응형
그리드형(광고전용)
Posted by icodebroker

댓글을 달아 주세요