首先,對於長篇文章感到抱歉。Screen.AllScreens錯誤併發布WM_DISPLAYCHANGE,到一個單獨的WinForm應用程序
關於如何限制WM_DISPLAYCHANGE消息的發佈範圍的任何建議?
場景:
Screen.AllScreens
返回一個客戶端上檢測到的所有顯示器座標和分辨率的陣列。如果應用程序在工作站被鎖定時啓動(在應用程序重啓過程中),Screen.AllScreens
僅返回一個元素,詳細說明單個屏幕,其中所有多個監視器的尺寸爲一個。
隨後,在這種情況下,當用戶解鎖工作站並開始使用應用程序時,正在使用的Infragistics控件(UltraWinDock)不允許拖動主屏幕之外的浮動窗口,因爲Screen.AllScreens
屬性未返回系統的真實監視器配置。 Infragistics控件實際上看起來是Screen.PrimaryScreen.Bounds
,但Screen.PrimaryScreen
屬性又調用緩存的Screen.AllScreens
數組,該數組返回一個巨大的主屏幕!
當應用程序正常啓動(工作站解鎖)時,控件功能正常。
的唯一手段,我可以看到Screen.AllScreens
被複位,並且可以被刷新是經由SystemEvents.DisplayChanging
事件被升高, 在該點處內部字段被設置爲空。 (Screen.AllScreens
掛鉤此事件。)Screen.AllScreens
將在下次調用它時重新填充。
從我所能確定的情況來看,SystemEvents.DisplayChanging
事件可以通過WM_DISPLAYCHANGE
WMI消息產生。
由我已設法解決方法的裝置是通過調用:
[DllImport("user32.dll")]
public static extern int GetSystemMetrics(int nIndex);
與SM_CMONITORS的參數表示在系統上顯示的數目。無論工作站是否鎖定,這似乎總是返回實際顯示的監視器數量。
我然後評估Screen.AllScreens
陣列的長度是否小於GetSystemMetrics(SM_CMONITORS)
結果,如果它是,我掛鉤到 SystemEvents.SessionSwitch
靜態事件,並檢查SessionSwitchEventArgs.Reason
屬性,對於SessionUnlock
的值。 當工作站被解鎖時,接收到此事件和條件滿足,所以我使用P/Invoke方法
[DllImport("user32.dll")]
public static extern bool PostMessage(IntPtr hWnd, uint wMsg, UIntPtr wParam, IntPtr lParam);
具有以下ARGS發佈消息:
PostMessage(HWND_BROADCAST, WM_DISPLAYCHANGE,UIntPtr.Zero,IntPtr.Zero)
這工作非常漂亮並達到預期的效果!Screen.AllScreens
已重置且Infragistics控件正常工作。
它在我看來像一個難以理解的錯誤,Screen.AllScreens
在鎖定的工作站上啓動應用程序時不會重新評估,然後解鎖。
一個罕見的問題,我承認,但仍然是一個問題。
對於WM_DISPLAYCHANGE消息,wParam和lParam被描述爲:
的wParam
- 顯示器的新的圖像的深度,在每個像素的位數。
lParam的
低位字指定屏幕的水平分辨率。
高位字指定屏幕的垂直分辨率。
我送在這些爭論空IntPtr.Zero
,因爲我不知道什麼實際值在發送消息的時間。
我的問題在於,我在整個系統上用空參數廣播WM_DISPLAYCHANGE
消息,並且可能有正在運行的進程正在運行,它會消耗WM_DISPLAYMESSAGE
並利用這些參數。我希望如果發送空論據,任何消費者都會忽略這些論點,但這是一個非常危險的假設。
有沒有辦法將消息發送或發佈到有問題的應用程序,並消除影響其他進程的風險?
我曾嘗試以下無濟於事:
PostMessage(IntPtr.Zero, WM_DISPLAYCHANGE, UIntPtr.Zero, IntPtr.Zero)
PostMessage(this.Handle, WM_DISPLAYCHANGE, UIntPtr.Zero, IntPtr.Zero)
PostThreadMessage(AppDomain.GetCurrentThreadId(), WM_DISPLAYCHANGE, UIntPtr.Zero, IntPtr.Zero)
SendMessage(this.Handle, WM_DISPLAYCHANGE, UIntPtr.Zero, IntPtr.Zero)
注:
- 我沒有用的P/Invoke或WMI大量經驗。
- 目標框架是.Net 3.5。
- 我還沒有看到廣播PostMessage的
WM_DISPLAYCHANGE
方法的任何副作用。 - 我已經下載了Infragistics的源代碼,並確定問題出現在他們的代碼中,並且認爲重新編譯該控件以集成修補程序,但決定不這樣做。我已通知Infragistics該問題,但不能等待修復,並且不要特別將其視爲Infragistics問題,因爲這是造成該問題的
Screen.AllScreens
。 - 應用程序一夜之間重新啓動是必要的,無法更改爲等待用戶在早上登錄。
- 我創建了一個測試應用程序,用於鎖定用戶的工作站,重新啓動自身(應用程序,而不是工作站),並在應用程序鎖定時評估
Screen.AllScreens
屬性,然後在發送WM_DISPLAYCHANGE
方法後評估另一個快照。我想添加一個屏幕截圖,但不允許我是一個新的StackOverflow用戶!
Infragistics再次表示,該公司是一家重要的錯誤工廠。解決你真正的問題,轉儲他們。如果你不想在他們的支持渠道尋求幫助。 –
是的,我同意,但不幸的是使用控件的決定是從我手中,並且支持渠道將花費太長時間,雖然我已經跟他們記錄它。我簡單地(!)需要知道如何使用P/Invoke來PostMessage到特定的應用程序。 – pandrew