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     }

 

posted @ 2024-01-24 17:19  唐宋元明清2188  阅读(70)  评论(0编辑  收藏  举报