728x90
728x170
▶ 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
그리드형(광고전용)
'C# > WinForm' 카테고리의 다른 글
[C#/WINFORM] 고품질 이미지 크기 변경하기 (0) | 2022.07.05 |
---|---|
[C#/WINFORM/.NET6] FontFamily 클래스 : GenericMonospace 정적 속성을 사용해 고정 폭 폰트 만들기 (0) | 2022.07.04 |
[C#/WINFORM/.NET6] Application 클래스 : ProductVersion 정적 속성을 사용해 프로그램 버전 구하기 (0) | 2022.06.21 |
[C#/WINFORM/.NET6] SoundPlayer 클래스 : PlaySync 메소드를 사용해 비프음 만들기 (0) | 2022.06.10 |
[C#/WINFORM] 저수준 키보드 후킹하기 (0) | 2022.05.25 |
[C#/WINFORM] 날짜 형식 버전 사용하기 (0) | 2022.05.25 |
[C#/WINFORM] MessageBox 클래스 : Show 정적 메소드를 사용해 최상위 메시지 박스 표시하기 (0) | 2022.05.14 |
[C#/WINFORM] Screen 클래스 : FromHandle 정적 메소드를 사용해 폼 최대화시 윈도우 작업표시줄 가리지 않기 (0) | 2022.05.13 |
[C#/WINFORM] UserControl 클래스 : 대용량 이미지 갤러리 사용하기 (0) | 2022.05.12 |
[C#/WINFORM/.NET5] ImageAttributes 클래스 : 투명 비트맵 구하기 (0) | 2022.05.04 |