MMTimer.cs 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Runtime.InteropServices;
  5. using System.Text;
  6. using System.Threading.Tasks;
  7. namespace MECF.Framework.Common.Utilities
  8. {
  9. /// <summary>
  10. /// 定时器分辨率:毫秒
  11. /// </summary>
  12. struct TimerCaps
  13. {
  14. /// <summary>最小周期</summary>
  15. public int periodMin;
  16. /// <summary>最大周期</summary>
  17. public int periodMax;
  18. }
  19. /// <summary>
  20. /// 高精度定时器
  21. /// </summary>
  22. public class MMTimer
  23. {
  24. static MMTimer()
  25. {
  26. TimeGetDevCaps(ref _caps, Marshal.SizeOf(_caps));
  27. }
  28. public MMTimer()
  29. {
  30. Running = false;
  31. _interval = _caps.periodMin;
  32. _resolution = _caps.periodMin;
  33. _callback = new TimerCallback(TimerEventCallback);
  34. }
  35. ~MMTimer()
  36. {
  37. TimeKillEvent(_id);
  38. }
  39. /// <summary>
  40. /// 系统定时器回调
  41. /// </summary>
  42. /// <param name="id">定时器编号</param>
  43. /// <param name="msg">预留,不使用</param>
  44. /// <param name="user">用户实例数据</param>
  45. /// <param name="param1">预留,不使用</param>
  46. /// <param name="param2">预留,不使用</param>
  47. private delegate void TimerCallback(int id, int msg, int user, int param1, int param2);
  48. #region 动态库接口
  49. /// <summary>
  50. /// 查询设备支持的定时器分辨率
  51. /// </summary>
  52. /// <param name="ptc">定时器分辨率结构体指针</param>
  53. /// <param name="cbtc">定时器分辨率结构体大小</param>
  54. /// <returns></returns>
  55. [DllImport("winmm.dll", EntryPoint = "timeGetDevCaps")]
  56. private static extern TimerError TimeGetDevCaps(ref TimerCaps ptc, int cbtc);
  57. /// <summary>
  58. /// 绑定定时器事件
  59. /// </summary>
  60. /// <param name="delay">延时:毫秒</param>
  61. /// <param name="resolution">分辨率</param>
  62. /// <param name="callback">回调接口</param>
  63. /// <param name="user">用户提供的回调数据</param>
  64. /// <param name="eventType"></param>
  65. [DllImport("winmm.dll", EntryPoint = "timeSetEvent")]
  66. private static extern int TimeSetEvent(int delay, int resolution, TimerCallback callback, int user, int eventType);
  67. /// <summary>
  68. /// 终止定时器
  69. /// </summary>
  70. /// <param name="id">定时器编号</param>
  71. [DllImport("winmm.dll", EntryPoint = "timeKillEvent")]
  72. private static extern TimerError TimeKillEvent(int id);
  73. #endregion
  74. #region 属性
  75. /// <summary>时间间隔:毫秒</summary>
  76. public int Interval
  77. {
  78. get { return _interval; }
  79. set
  80. {
  81. if (value < _caps.periodMin || value > _caps.periodMax)
  82. throw new Exception("无效的计时间隔");
  83. _interval = value;
  84. }
  85. }
  86. public bool Running { get; private set; }
  87. #endregion
  88. #region 事件
  89. public event Action Ticked;
  90. #endregion
  91. #region 公开方法
  92. public void Start()
  93. {
  94. if (!Running)
  95. {
  96. _id = TimeSetEvent(_interval, _resolution, _callback, 0,
  97. (int)EventType01.TIME_PERIODIC | (int)EventType02.TIME_KILL_SYNCHRONOUS);
  98. if (_id == 0) throw new Exception("启动定时器失败");
  99. Running = true;
  100. }
  101. }
  102. public void Stop()
  103. {
  104. if (Running)
  105. {
  106. TimeKillEvent(_id);
  107. Running = false;
  108. }
  109. }
  110. #endregion
  111. #region 内部方法
  112. private void TimerEventCallback(int id, int msg, int user, int param1, int param2)
  113. {
  114. try
  115. {
  116. Ticked?.Invoke();
  117. }
  118. catch
  119. {
  120. throw;
  121. }
  122. }
  123. #endregion
  124. #region 字段
  125. // 系统定时器分辨率
  126. private static TimerCaps _caps;
  127. // 定时器间隔
  128. private int _interval;
  129. // 定时器分辨率
  130. private int _resolution;
  131. // 定时器回调
  132. private TimerCallback _callback;
  133. // 定时器编号
  134. private int _id;
  135. #endregion
  136. }
  137. public enum TimerError
  138. {
  139. /// <summary>没有错误</summary>
  140. MMSYSERR_NOERROR = 0,
  141. /// <summary>常规错误码</summary>
  142. MMSYSERR_ERROR = 1,
  143. /// <summary>ptc 为空,或 cbtc 无效,或其他错误</summary>
  144. TIMERR_NOCANDO = 97,
  145. /// <summary>无效参数</summary>
  146. MMSYSERR_INVALPARAM = 11,
  147. }
  148. public enum EventType01
  149. {
  150. /// <summary>单次执行</summary>
  151. TIME_ONESHOT = 0x0000,
  152. /// <summary>循环执行</summary>
  153. TIME_PERIODIC = 0x0001,
  154. }
  155. public enum EventType02
  156. {
  157. /// <summary>定时器到期时,调用回调方法。这是默认值</summary>
  158. TIME_CALLBACK_FUNCTION = 0x0000,
  159. /// <summary>定时器到期时,调用 setEvent</summary>
  160. TIME_CALLBACK_EVENT_SET = 0x0010,
  161. /// <summary>定时器到期时,调用 PulseEvent</summary>
  162. TIME_CALLBACK_EVENT_PULSE = 0x0020,
  163. /// <summary>防止在调用 timeKillEvent 函数之后发生事件</summary>
  164. TIME_KILL_SYNCHRONOUS = 0x0100,
  165. }
  166. }