Windows高速定时器,多媒体定时器winmm.dll库的使用
1.贡献个Winform自定义控件,信用卡、银行卡输入控件;每4个字符分隔显示。其他UI框架可以参考。2.印章WinForm自定义控件封装,提供源码下载
3.Windows高速定时器,多媒体定时器winmm.dll库的使用
4.理解SynchronizationContext,如何在Winform里面跨线程访问UI控件5.C#winform程序关闭计算机的正确姿势6.WinForm触摸屏程序功能界面长时间不操作自动关闭回到主界面7.分享Winform datagridview 动态生成中文HeaderText8.Winform让扫描枪听话,防止在有焦点的地方就扫码输入的尴尬9.WinForm调用钉钉获取考勤结果10.C# Winform 实现Ajax效果自定义按钮11.C#Winform 自定义透明按钮和单窗体模块化实现12.C#Winform设计的通用标签设计器13.C#Winform使用mysql作为本地数据库14.C#winform自定义控件模拟设计时界面鼠标移动和调节大小、选中效果15.我在winform项目里使用“Windows I/O完成端口”的经验分享16.一次人脸识别ViewFaceCore使用的经验分享,看我把门店淘汰下来的POS机改成了人脸考勤机项目里面用到的这些看起来名字高大上的定时器测试下来也是非常不准。看了源码发现也是用System.Timers.Timer或者用的是Thread休眠的方式来实现的。100毫秒就不准了。直到一番搜索,发现利用多媒体定时器winmm.dll的MillisecondTimer是可用的。原文来自博客(dehai)Timer计时不准确的问题及解决方法”。代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 | public sealed class MillisecondTimer : IComponent, IDisposable { //***************************************************** 字 段 ******************************************************************* private static TimerCaps caps; private int interval; private bool isRunning; private int resolution; private TimerCallback timerCallback; private int timerID; //***************************************************** 属 性 ******************************************************************* /// <summary> /// /// </summary> public int Interval { get { return this .interval; } set { if ((value < caps.periodMin) || (value > caps.periodMax)) { throw new Exception( "超出计时范围!" ); } this .interval = value; } } /// <summary> /// /// </summary> public bool IsRunning { get { return this .isRunning; } } /// <summary> /// /// </summary> public ISite Site { set ; get ; } //***************************************************** 事 件 ******************************************************************* public event EventHandler Disposed; // 这个事件实现了IComponet接口 public event EventHandler Tick; //*************************************************** 构造函数和释构函数 ****************************************************************** static MillisecondTimer() { timeGetDevCaps( ref caps, Marshal.SizeOf(caps)); } public MillisecondTimer() { this .interval = caps.periodMin; // this .resolution = caps.periodMin; // this .isRunning = false ; this .timerCallback = new TimerCallback( this .TimerEventCallback); } public MillisecondTimer(IContainer container) : this () { container.Add( this ); } ~MillisecondTimer() { timeKillEvent( this .timerID); } //***************************************************** 方 法 ******************************************************************* /// <summary> /// /// </summary> public void Start() { if (!isRunning) { timerID = timeSetEvent( this .interval, this .resolution, this .timerCallback, 0, 1); // 间隔性地运行 if (timerID == 0) { throw new Exception( "无法启动计时器" ); } isRunning = true ; } } /// <summary> /// /// </summary> public void Stop() { if (isRunning) { timeKillEvent( this .timerID); isRunning = false ; } } /// <summary> /// 实现IDisposable接口 /// </summary> public void Dispose() { timeKillEvent( this .timerID); GC.SuppressFinalize( this ); Disposed?.Invoke( this , EventArgs.Empty); } //*************************************************** 内部函数 ****************************************************************** [DllImport( "winmm.dll" )] private static extern int timeSetEvent( int delay, int resolution, TimerCallback callback, int user, int mode); [DllImport( "winmm.dll" )] private static extern int timeKillEvent( int id); [DllImport( "winmm.dll" )] private static extern int timeGetDevCaps( ref TimerCaps caps, int sizeOfTimerCaps); private void TimerEventCallback( int id, int msg, int user, int param1, int param2) { Tick?.Invoke( this , null ); // 引发事件 } //*************************************************** 内部类型 ****************************************************************** private delegate void TimerCallback( int id, int msg, int user, int param1, int param2); // timeSetEvent所对应的回调函数的签名 /// <summary> /// 定时器的分辨率(resolution)。单位是ms,毫秒? /// </summary> [StructLayout(LayoutKind.Sequential)] private struct TimerCaps { public int periodMin; public int periodMax; } } } |
测试代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | class Program { static Dictionary< string , int > dtList = new Dictionary< string , int >(); static void Main( string [] args) { //var timer = new DoubleThreadTimer(100, 100); //timer.OnRunningCallback += Timer1_Tick; //timer.Start(); var timer1 = new MillisecondTimer(); timer1.Interval = 2; timer1.Tick += Timer1_Tick; timer1.Start(); Console.ReadLine(); } private static void Timer1_Tick( object sender, EventArgs e) { var dt = DateTime.Now; string dtStr = dt.ToString( "yyyyMMdd HHmmss" ); if (dtList.ContainsKey(dtStr)) { dtList[dtStr]++; if (dtList[dtStr] % 500 == 0) { Console.WriteLine(dtStr + "--->" + dtList[dtStr]); dtList.Remove(dtStr); } } else { if (dtList.Count > 1) { foreach ( var item in dtList) { Console.WriteLine(item.Key + "--->" + item.Value); } dtList.Clear(); } dtList.Add(dtStr, 1); } } } |
测试结论: 时间间隔设置为5毫秒,表现很稳定。2毫秒有时准。可靠性比.net的timer准好多倍啊
加上了些注释,并针对项目进行了封装:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | /// <summary> /// 用Windows多媒体定时器winmm.dll库封装的定时器 /// </summary> public class MillisecondTimer : ITimer, IDisposable { #region 定时器事件类型 const int TIME_ONESHOT = 0; const int TIME_PERIODIC = 1; #endregion private bool isRunning = false ; /// <summary> /// 定时器的分辨率(resolution)。单位是毫秒 /// </summary> [StructLayout(LayoutKind.Sequential)] private struct TimerCaps { public int periodMin; public int periodMax; } #region winmm.dll API声明 /// <summary> /// 设置一个媒体定时器(定时器事件类型常用的有2种,0:TIME_ONESHOT,1:TIME_PERIODIC) /// </summary> /// <param name="delay">以毫秒指定事件的周期。</param> /// <param name="resolution">以毫秒指定延时的精度,数值越小定时器事件分辨率越高。缺省值为1ms。</param> /// <param name="callback">指向一个回调函数。(委托实例)</param> /// <param name="user">存放用户提供的回调数据。</param> /// <param name="mode">指定定时器事件类型:0->TIME_ONESHOT:uDelay毫秒后只产生一次事件;1->TIME_PERIODIC :每隔delay毫秒周期性地产生事件。</param> /// <returns>定时器的ID,释放资源的时候需要</returns> [DllImport( "winmm.dll" )] private static extern int timeSetEvent( int delay, int resolution, TimerCallback callback, int user, int mode); /// <summary> /// 结束定时器,释放资源 /// </summary> /// <param name="id">设置定时器返回的ID</param> /// <returns></returns> [DllImport( "winmm.dll" )] private static extern int timeKillEvent( int id); /// <summary> /// 初始化结构体,TimerCaps{periodMin,periodMax} /// </summary> /// <param name="caps">TimerCaps</param> /// <param name="sizeOfTimerCaps">TimerCaps的长度</param> /// <returns></returns> [DllImport( "winmm.dll" )] private static extern int timeGetDevCaps( ref TimerCaps caps, int sizeOfTimerCaps); #endregion private delegate void TimerCallback( int id, int msg, int user, int param1, int param2); // timeSetEvent所对应的回调函数的签名 public event EES.Common.ManualTimer.TimerCallback OnRunningCallback; public event EES.Common.ManualTimer.TimerCallback OnStartedCallback; public event EES.Common.ManualTimer.TimerCallback OnStopedCallback; private TimerCallback m_TimerCallback; private int timerID; private TimerCaps caps = new TimerCaps(); public MillisecondTimer( int dueTime, int period) { timeGetDevCaps( ref caps, Marshal.SizeOf(caps)); caps.periodMin = period; caps.periodMax = dueTime; isRunning = false ; m_TimerCallback = new TimerCallback(TimerEventCallback); } /// <summary> /// 触发事件 /// </summary> /// <param name="id"></param> /// <param name="msg"></param> /// <param name="user"></param> /// <param name="param1"></param> /// <param name="param2"></param> private void TimerEventCallback( int id, int msg, int user, int param1, int param2) { OnRunningCallback?.Invoke( this , new EventArgs()); } /// <summary> /// 启动定时器,回调OnStartedCallback /// </summary> public void Start() { if (!isRunning) { timerID = timeSetEvent(caps.periodMin, caps.periodMin, m_TimerCallback, 0, TIME_PERIODIC); // 间隔性地运行 GC.KeepAlive(m_TimerCallback); if (timerID == 0) { throw new EESException( "无法启动计时器" ); } isRunning = true ; if (isRunning) OnStartedCallback?.Invoke( this , EventArgs.Empty); } } /// <summary> ///停止定时器 /// </summary> public void Stop() { if (isRunning) { timeKillEvent(timerID); isRunning = false ; OnStopedCallback?.Invoke( this , EventArgs.Empty); Dispose(); } } /// <summary> /// 获取定时器允许状态 /// </summary> /// <returns></returns> public bool IsRunning() { return isRunning; } /// <summary> /// Dispose /// </summary> public void Dispose() { if (!timerID.Equals(0)) timeKillEvent(timerID); GC.SuppressFinalize( this ); } } |
作者:数据酷软件
出处:https://www.cnblogs.com/datacool/p/datacool_2017timer.html
关于作者:20年编程从业经验,持续关注MES/ERP/POS/WMS/工业自动化
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明。
联系方式: qq:71008973;wx:6857740733
基于人脸识别的考勤系统 地址: https://gitee.com/afeng124/viewface_attendance_ext
自己开发安卓应用框架 地址: https://gitee.com/afeng124/android-app-frame
WPOS(warehouse+pos) 后台演示地址: http://47.239.106.75:8080/
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?