如何阻止我的应用程序收到某个"消息"?

use*_*662 27 .net vb.net multithreading messages windows-messages

找到了可能的解决方案!

我相信我找到了解决方案!我将继续测试,以确保它确实工作,但我很有希望:)我已经详细说明了如何在EDIT三个问题中找到解决方案!

对于任何希望了解我的问题背后的完整背景以及由于此问题的输入而尝试过的人,请参阅:http://pastebin.com/nTrEAkVj

随着我的研究和情况的进展,我将经常对此进行编辑(大多数工作日每天> 3次),所以如果您有兴趣或者对我的问题有一些信息或了解,请继续检查:)

快速背景:

我有这个应用程序我可以通过更改我的屏幕保护程序或锁定我的工作站崩溃,并且通常每当发送WM_WININICHANGE/WM_SETTINGSCHANGE消息时.

如果我可以通过更改我的屏幕保护程序来持续崩溃我的应用程序,那么这样做的一部分就是向我的应用程序发送某种消息(不一定是Windows消息,我的意思是最普遍意义上的消息),这反过来对我来说是灾难性的应用.因此,我试图找到一种方法来阻止导致我的问题被我的应用程序处理的任何消息.我知道这不是解决方案的最佳方式,所以你不需要告诉我.查看背景信息或询问为什么会困扰您(有充分理由).

我的问题:

有几件事情,任何有关的信息都可以帮助我解决我的问题,根据相关性进行标记(1是最相关的,3稍微有点帮助):

  1. 我试图使用Wndproc()过滤掉我的消息,如下所示:

    Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
        If CInt(m.Msg) <> CInt(26) then
            MyBase.WndProc(m)
        end if
    End Sub
    
    Run Code Online (Sandbox Code Playgroud)

    但是,根据Windspector,WM_WININICHANGE消息仍然被发送到我的应用程序(这是有道理的),但它也返回0 ...如果它正常工作不应该发生,它不应该返回什么,不应该吗?有关为什么这不符合我的预期以及如何使其工作的信息将非常有帮助!

  2. 我也尝试过使用messagefilters:

    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  << someone elses comment       
            Return m.Msg = 26
        End Function
    End Class
    
    Run Code Online (Sandbox Code Playgroud)

    然后添加到mybase.load处理方法:

    Application.AddMessageFilter(New MyMessageFilter())

    然而,它们似乎只是过滤某些消息,而像我这样的消息显然没有被捕获.有关是否绝对无法使用任何类型的过滤器来捕获WM_消息的信息,或者是否有其他方法可以使用消息过滤器来实现我的目标也是有帮助的.

  3. 在其他方式(除了这个带有message.msg = WM_WININICHANGE = 26的Windows消息)我可以更改我的屏幕保护程序向我的应用程序发送任何类型的消息吗?更改我的屏幕保护程序的另一种消息是否也可能是致命的?

如果有任何关于我的情况的其他信息可能有用,请告诉我,我会尽力去做!提前感谢您提供任何帮助:)

编辑:

看来,如果我只发送WM_CHANGESETTING消息,并使我的程序等待sendmessagetimeout的超时长度我发送消息,那么我的程序不会崩溃...看来RESPONSE是什么导致我的程序崩溃..有趣的 我绝对接近我的解决方案!我想更多的测试应该让我找出一种方法来确保我的程序不响应消息.

编辑二:

我今天发现了一些非常有希望的东西:我将wndproc函数定义为:

Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
    If CInt(m.Msg) <> CInt(26) Then
        MyBase.WndProc(m)
    Else
        MessageBox.Show("Get to work!", "Attention", MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1, MessageBoxOptions.ServiceNotification)
    End If
End Sub
Run Code Online (Sandbox Code Playgroud)

然后我尝试运行我的程序,然后使用以下命令发送WM_SETTINGCHANGE消息:

SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, IntPtr.Zero, IntPtr.Zero, _
             SendMessageTimeoutFlags.SMTO_ABORTIFHUNG, 5000, IntPtr.Zero)
Run Code Online (Sandbox Code Playgroud)

在我做的另一个节目中.那么你问的是什么?好吧,我试了好几次,每次弹出消息框(我为它选择的单词都是无关紧要的),然后我尝试等待不同的时间,然后按下确定,然后我会看到我的主要表单发生了什么.很多时候,没有什么不同,它仍然会崩溃.但偶尔,也许是1/5,该程序仍然会重新编码!然后,如果确实如此,我会尝试再次发送消息,然后再次,通常他们会在程序的同一次运行期间第二次失败,但偶尔再次,大约相当于另外1/5倍,程序不会再次崩溃.然后我试图将它崩溃两次.并且它没有时间,它几乎总是永远不会崩溃,无论我多少次尝试发送消息,无论我多久等待msgbox弹出.

我发现等待大约5秒似乎增加了我的几率:我触发消息的形式仍然是焦点(顶部栏会是蓝色的),在我按下冻结按钮后,然后msgbox会弹出,顶部也是蓝色(我认为是焦点),两者仍然"焦点"(至少蓝色哈哈).然后大约5秒钟后,原始形态将失去焦点,看到之后,我会尝试击中确定.

我目前正在考虑等待一点然后确认消息框有时会使我的程序不会崩溃,因为它会使消息超时,因此它不会返回.我不知道为什么返回的消息应该对我的程序实际执行的操作产生影响.这是澄清有用的领域:)

编辑三:

所以我在Winspector中查找了一下,我发现如果我等待WM_ERASEBKGND出现在我的桌面窗口(这是Winspector中标记为"sysListView32'FolderView'"的窗口)之后,在我的msgbox上点击"OK" ,那么程序不会崩溃,有趣!它通常需要接近sendmessagetimeout的Timeout才能显示WM_ERASEBKGND消息.这当然是从我自制的测试应用程序发送WM_SETTINGCHANGE消息后.

所以,在此之后我决定在Winspector周围看一下,因为我可以找到更多有用的队列吗?因为显然等待winspector显示消息被发送到我的桌面并不是我的程序的实际修复.我在程序进程中找到一些异常命名的窗口:一个名为".NET -BroadcastEventWindow.2.0.0.0.378734a.0",另一个名为"GDI + Hook Window Class'GDI + Window'",子窗口名为"IME"默认IME'".

我决定查看进入这些窗口的消息,看看他们是否收到任何可识别的消息,例如WM_SETTINGCHANGE或WM_ERASEBKGND.事实证明,他们不经常接收消息:GDI +在我看不到的时候没有收到任何消息,但.NET -BroadcastEventWindow收到了一些消息.当我点击我的应用程序窗口或其后的另一个窗口时,进入BroadcastEventWindow的那些主要只是WM_appactivate.

然后......我注意到.Net BroadcastEventWindow收到我的WM_CHANGESETTING消息!!!! 我看看其他消息显示的内容:不是很多,但我注意到当应用程序因为错误而崩溃时,有一条我无法识别的消息:WM_USER + 7194(0x201A).嗯,让我们看看那是什么.在我谷歌之后,我发现它似乎是一个应用程序/用户定义的消息,然后在另一个搜索与它相关的问题后,我注意到有人能够使用过滤器来过滤此消息并解决问题他们的(http://www.pcreview.co.uk/forums/handling-wm_user-messages-t1315625.html).至少对我来说值得一试吗?所以我重新添加我之前尝试过的过滤器,并更改要过滤的值.该应用程序没有崩溃!!!!!!!

接下来我尝试让我的工作站锁定,看看它是否仍然崩溃(因为之前只发送了单独的WM_CHANGESETTING消息).事实证明,它仍然崩溃了:(但是,我再次看看winspector的那个窗口,哦,哦,两个新的WM_USER消息:WM_USER + 7294(0x207E)和WM_USER + 7189(0x2015).所以我尝试过滤掉那些太......然后它也不会在工作站锁定时崩溃!!!:D

到目前为止,我注意到这对正常的应用程序使用没有任何不利影响!这是有道理的,因为我不认为任何用户定义的消息是故意参与我的程序.

我将把问题打开一段时间,直到我确定我的解决方案没有任何问题,并且效果很好.感谢那些给我一些建议的人,如何在调试的中间阶段继续:)

Han*_*ant 6

多年来我在各种问题中看到过这个问题.从来没有完全诊断出来,我只会告诉你我对它的了解.

此问题与SystemEvents类初始化的方式有关.它涉及到事故,因为这是触发切换到安全桌面时触发的事件的类.通过屏幕保护程序或通过锁定工作站(Windows + L键).Winforms控件通常对SystemEvents.DisplaySettingsChanged事件感兴趣,因为它们可能需要在更改主题或系统颜色时重绘自身.当系统切换桌面时,通常也会引发此事件.

一个核心问题是需要在UI线程上引发事件.SystemEvents需要准确猜出哪个线程实际上是UI线程.当在一个实际上不是UI线程的线程上创建在程序中创建的第一个窗口时,这会出错,否则通过将其COM单元设置为STA来伪装成一个.如果线程实际上继续运行,则在该线程上触发该事件.如果线程消失,并非罕见,那么当SynchronizationContext.Post()尝试封送调用并失败时,会引发异常.吞下异常,然后在任意线程池线程上引发事件.

无论哪种方式,事件都不会在正确的线程上引发,并且违反了任何UI组件的线程要求.这往往会被忽视,因为一些奇怪的原因,在桌面交换机上触发的同一事件往往会导致死锁或崩溃更频繁.

您需要仔细查看程序的初始化代码.到目前为止,最常见的错误是创建自己的启动画面.请务必使用.NET框架中的内置支持来实现这一点.


Oli*_*bes 4

实现您自己的消息过滤器

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
Run Code Online (Sandbox Code Playgroud)

当您的应用程序启动时添加此过滤器

Application.AddMessageFilter(New MyMessageFilter())
Run Code Online (Sandbox Code Playgroud)