C# 息屏操作出现闪屏
windows大屏使用场景,关闭显示器是一个常用操作。
操作系统提供了相应的API,应用层调用:
1 //广播消息,所有顶级窗体都会接收 2 private static readonly IntPtr HWND_BROADCAST = new IntPtr(0xffff); 3 //系统消息 4 private const uint WM_SYSCOMMAND = 0x112; 5 //关闭显示器的系统命令 6 private const int SC_MONITORPOWER = 0xF170; 7 //2为PowerOff, 1为省电状态,-1为开机 8 private const int MonitorPowerOff = 2; 9 // 定义Win32 API中的SendMessage函数 10 [DllImport("user32.dll",CharSet = CharSet.Auto)] 11 private static extern IntPtr SendMessage(IntPtr hWnd, uint hMsg, int wParam, int lParam); 12 private void SendMessage_OnClick(object sender, RoutedEventArgs e) 13 { 14 SendMessage(HWND_BROADCAST, WM_SYSCOMMAND, SC_MONITORPOWER, MonitorPowerOff); 15 }
以上是息屏的实现。但经测试验证,上面方案有较大概率导致整机时序信号反复拉高拉低、出现长时间的闪屏。
经过反复尝试,发现是API调用错了。
原因应该是上面调用句柄参数HWND_BROADCAST,这是对所有窗口广播息屏,这需要更长时间完成这个操作。这时点击屏幕去触发亮屏,系统的操作被打乱导致时序紊乱,现象就是屏会闪来闪去。
为了验证,我调用广播息屏后,等待一段时间再去点击屏幕,则不会出现闪屏。
所以,测试反馈问题是概率性事件,就是测试手法导致的。打开窗口少的情况下,息屏后手慢点可能就复现不了。
息屏操作不广播,只需要通知当前应用窗口。以下是正确调用姿势:
1 private void SendMessage_OnClick(object sender, RoutedEventArgs e) 2 { 3 var interopHelper = new WindowInteropHelper(this); 4 SendMessage(interopHelper.Handle, WM_SYSCOMMAND, SC_MONITORPOWER, MonitorPowerOff); 5 }
作者:唐宋元明清2188
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须在文章页面给出原文连接,否则保留追究法律责任的权利。