C#

C# MultiMediaTimer 1ms 간격의 타이머 (멀티미디어타이머)

sheepone 2022. 1. 6. 13:35
반응형

현재 타이머의 간격인 1ms와 출력창의 현재 시간과 옆의 간격 1ms

(1ms 이상의 간격으로 이벤트를 발생시키고 싶을때 사용하시면 좋습니다)

 

필요한 파라미터로는 Interval 과 Resolution이 있습니다.

Interval 은 최소 1ms로 타이머의 간격을 설정할 수 있고 Resolution은 작은값일수록 해상도가 높으며 0일때 최대의 해상도 입니다.

시스템의 부하를 줄이기 위해 Resolution을 최대한 큰값을 사용하라고 하네요.

 

내부적으로는 인터벌 설정시에 레졸루션이 더 크면 해당 인터벌의 값으로 레졸루션을 설정하게 되어 있습니다.

(인터벌만 설정해 주시면 될거 같네요)

 

멀티미디어 클래스

    public class MultimediaTimer : IDisposable
    {
        private bool disposed = false;
        private int interval, resolution;
        private UInt32 timerId; 

        // Hold the timer callback to prevent garbage collection.
        private readonly MultimediaTimerCallback Callback;

        public MultimediaTimer()
        {
            Callback = new MultimediaTimerCallback(TimerCallbackMethod);
            Resolution = 5;
            Interval = 10;
        }

        ~MultimediaTimer()
        {
            Dispose(false);
        }

        public int Interval
        {
            get
            {
                return interval;
            }
            set
            {
                CheckDisposed();

                if (value < 0)
                    throw new ArgumentOutOfRangeException("value");

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

        // Note minimum resolution is 0, meaning highest possible resolution.
        public int Resolution
        {
            get
            {
                return resolution;
            }
            set
            {
                CheckDisposed();

                if (value < 0)
                    throw new ArgumentOutOfRangeException("value");

                resolution = value;
            }
        }

        public bool IsRunning
        {
            get { return timerId != 0; }
        }

        public void Start()
        {
            CheckDisposed();

            if (IsRunning)
                throw new InvalidOperationException("Timer is already running");

            // Event type = 0, one off event
            // Event type = 1, periodic event
            UInt32 userCtx = 0;
            timerId = NativeMethods.TimeSetEvent((uint)Interval, (uint)Resolution, Callback, ref userCtx, 1);
            if (timerId == 0)
            {
                int error = Marshal.GetLastWin32Error();
                throw new Win32Exception(error);
            }
        }

        public void Stop()
        {
            CheckDisposed();

            if (!IsRunning)
                throw new InvalidOperationException("Timer has not been started");

            StopInternal();
        }

        private void StopInternal()
        {
            NativeMethods.TimeKillEvent(timerId);
            timerId = 0;
        }

        public event EventHandler Elapsed;

        public void Dispose()
        {
            Dispose(true);
        }

        private void TimerCallbackMethod(uint id, uint msg, ref uint userCtx, uint rsv1, uint rsv2)
        {
            var handler = Elapsed;
            if (handler != null)
            {
                handler(this, EventArgs.Empty);
            }
        }

        private void CheckDisposed()
        {
            if (disposed)
                throw new ObjectDisposedException("MultimediaTimer");
        }

        private void Dispose(bool disposing)
        {
            if (disposed)
                return;
        
            disposed = true;
            if (IsRunning)
            {
                StopInternal();
            }
        
            if (disposing)
            {
                Elapsed = null;
                GC.SuppressFinalize(this);
            }
        }
    }

    internal delegate void MultimediaTimerCallback(UInt32 id, UInt32 msg, ref UInt32 userCtx, UInt32 rsv1, UInt32 rsv2);

    internal static class NativeMethods
    {
        [DllImport("winmm.dll", SetLastError = true, EntryPoint = "timeSetEvent")]
        internal static extern UInt32 TimeSetEvent(UInt32 msDelay, UInt32 msResolution, MultimediaTimerCallback callback, ref UInt32 userCtx, UInt32 eventType);

        [DllImport("winmm.dll", SetLastError = true, EntryPoint = "timeKillEvent")]
        internal static extern void TimeKillEvent(UInt32 uTimerId);
    }

 

사용

using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace WindowsFormsApp9
{
    public partial class Form1 : Form
    {
        Stopwatch sw = new Stopwatch();
        static MultimediaTimer timer ;
        public Form1()
        {
            InitializeComponent();
            timer = new MultimediaTimer() { Interval = 1, Resolution = 0};
            timer.Elapsed += Handler;
            timer.Start();
            sw.Start();
        }

        double dNow ,dPre;
        public void Handler(object sender, EventArgs e)
        {
            dNow = sw.ElapsedMilliseconds - dPre ;
            Console.WriteLine($"MultimediaTimer Timer elapsed {DateTime.UtcNow:o} {dNow}");

            dPre = sw.ElapsedMilliseconds ;
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            label2.Text = dNow.ToString();
        }
        
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            timer.Stop();
        }        
    }
}

 

사용한 소스파일

WindowsFormsApp9.zip
0.63MB

반응형