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調用錯了。
原因應該是,在對所有窗口廣播息屏,這需要更長時間完成這個操作。這時點擊屏幕去觸發亮屏,系統的操作被打亂導致時序紊亂,現象就是屏會閃來閃去。
爲了驗證,我調用廣播息屏後,等待一段時間再去點擊屏幕,則不會出現閃屏。
所以,測試反饋問題是概率性事件,就是測試手法導致的。打開窗口少的情況下,息屏後手慢點可能就復現不了。
息屏操作不廣播,只需要通知當前應用窗口。以下是正確調用姿勢:
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 }