How can I stop my application from receiving a certain “message”?

北战南征 提交于 2019-12-03 09:31:16
Hans Passant

I've seen this problem mentioned in various questions over the years. Never completely diagnosed it, I'll just tell you what I know about it.

This problem is related to the way the SystemEvents class gets initialized. It is involved in the mishap because that's the class that triggers the event that fires when you switch to the secure desktop. Either through the screen-saver or by locking the workstation (Windows + L key). Winforms controls are in general interested in the SystemEvents.DisplaySettingsChanged event because they might need to redraw themselves when the theme or the system colors were changed. This event is also commonly raised when the system switches desktops.

One core issue is that the events needs to be raised on the UI thread. SystemEvents needs to guess exactly what thread is actually the UI thread. This goes wrong when the very first window that is created in the program is created on a thread that is not actually the UI thread and otherwise masquerades as one by having its COM apartment set to STA. If the thread actually keeps running then the event is fired on that thread. If the thread is gone, not uncommon, then an exception is raised when the SynchronizationContext.Post() tries to marshal the call and fails. The exception is swallowed and the event is then raised on an arbitrary threadpool thread.

Either way, the event is not raised on the correct thread and that violates the threading requirements for any UI component. This tends to go unnoticed, for some strange reason the same event fired on the desktop switch tends to cause deadlock or crashes much more often.

You'll need to carefully review the initialization code of the program. By far the most common mistake is creating your own splash screen. Be sure to use the built-in support in the .NET framework to get that right.

Implement your own message filter with

Public Class MyMessageFilter
    Implements IMessageFilter

    Public Function PreFilterMessage(ByRef m As Message) As Boolean Implements IMessageFilter.PreFilterMessage
        ' Return true for messages that you want to stop
        Return m.Msg = MessageToDiscard
    End Function
End Class

Add this filter when your application starts with

Application.AddMessageFilter(New MyMessageFilter())
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!