如何停止我的应用程序接收某些“消息"? [英] How can I stop my application from receiving a certain "message"?

查看:118
本文介绍了如何停止我的应用程序接收某些“消息"?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

发现了可能的解决方案!

我相信我已经找到了解决方案!我将继续测试以确保它确实可以正常工作,但我很希望:)我已经详细说明了如何在问题的编辑三点"中找到解决方案!

I believe I have found a solution! I will be continuing testing to make sure it DOES in fact work, but I'm hopeful :) I have detailed how I found the solution in EDIT THREE of the question!

对于希望了解我的问题背后的全部背景以及我从该问题的输入中得到的尝试的人,请参见: http://pastebin.com/nTrEAkVj

For anyone wishing to know the full background behind my problem and what I have kind of tried as a result of input from this question, see this: http://pastebin.com/nTrEAkVj

随着研究的进展,我将经常进行编辑(大多数工作日每天进行3次),因此请继续检查是否对我的问题感兴趣或有一定的信息或知识:)

I will be editing this frequently (>3 times a day most weekdays) as I progress my research and situation, so keep checking back if you are interested or have some information or knowledge of my issue :)

快速背景:

我制作的这个应用程序可能会因更换屏幕保护程序或锁定工作站而崩溃,并且通常在向其发送WM_WININICHANGE/WM_SETTINGSCHANGE消息时会崩溃.

I have this app I have made that can be crashed by changing my screen saver or locking my work station, and in general whenever a WM_WININICHANGE/WM_SETTINGSCHANGE message is sent to it.

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

If I can consistently crash my app by changing my screensaver, then SOME part of doing that is sending my app SOME kind of message (not necessarily a windows message, I mean message in the most general sense), which in turn is catastrophic to my application. Due to this, I am trying to find a way to block whatever message is causing my problem from being processed by my application. I am aware this isn't the best way to go about a solution, so you don't need to tell me. Look at the background info or ask why if that bothers you (there is a good reason).

我的问题:

关于相关信息,有几件事可以帮助我解决我的问题(按照相关性标记(1最相关,3不太有用))

there are several things that any information about would help me solve my problem, labelled according to relevance (1 being most relevant, 3 slightly less helpful):

  1. 我正在尝试使用Wndproc()过滤出我的消息,如下所示:

  1. I am trying to use Wndproc() to filter out my message like this:

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

但是,根据Windspector的说法,WM_WININICHANGE消息仍在发送到我的应用程序中(这很有道理),但是它也返回了0.如果它工作正常,就不应该发生这种情况,应该不退还什么,不是吗?有关为何此功能无法按我预期的方式工作以及如何使其起作用的信息将非常有帮助!

However, according to Windspector, the WM_WININICHANGE message is still being sent to my app (this makes sense), BUT it is also being returned with 0... this shouldn't be happening if it was working properly, it shouldn't return anything, shouldn't it? Information regarding why this isn't working as I expected and how to make it work would be extremely helpful!

我也尝试过使用消息过滤器:

I have also tried using 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

,然后添加到我的mybase.load处理方法中:

and then adding to my mybase.load handling method:

Application.AddMessageFilter(New MyMessageFilter())

Application.AddMessageFilter(New MyMessageFilter())

但是,它们似乎仅过滤某些邮件,而诸如我的邮件之类的邮件显然没有被这些邮件捕获.有关是否绝对不可能使用任何类型的过滤器来捕获WM_消息,或者是否有其他方法可以使用消息过滤器来实现我的目标的信息,也将有所帮助.

however they appear to only filter certain messages, and messages such as mine are not caught in these apparently. information about if it is definately impossible to use any kind of filter to catch a WM_ message or if there are possibly other ways to use message filters to accomplish my goal would also be helpful.

还可以通过其他方式(除了我发现的一条带有message.msg = WM_WININICHANGE = 26的Windows消息)以外的其他方式来更改屏幕保护程序,以向我的应用程序发送任何消息吗?更改我的屏幕保护程序的另一种消息是否也可能致命?

in what OTHER ways (apart from this one windows message with message.msg = WM_WININICHANGE = 26 that I found) could me changing my screensaver send ANY kind of message to my application? is it possible that another kind of message from changing my screen saver is also fatal?

让我知道关于我的处境是否还有其他有用的信息,我将竭尽所能!预先感谢您提供的任何帮助:)

Let me know if there is ANY other information regarding my situation that may be useful, and I will do my best to get it! Thank you in advance for any help you can give :)

如果我仅发送WM_CHANGESETTING消息,并且让我的程序在发送消息的sendmessagetimeout的超时时间内等待,则出现该消息,则我的程序不会崩溃...似乎RESPONSE是导致崩溃的原因程序...有趣.我绝对接近我的解决方案!我认为应该再进行一些测试,以便让我找出一种方法来确保我的程序不响应该消息.

It appears if I ONLY send the WM_CHANGESETTING message, and make my program wait over the timeout length of the sendmessagetimeout I sent the message with, then my program doesn't crash... it appears the RESPONSE is what is crashing my program... interesting. I am definitely close to my solution! I'm thinking a little more testing should allow me to figure out a method to make sure my program does not respond to the message.

编辑两次:

今天我发现了一些非常有希望的东西:我完全像这样定义了wndproc函数:

I discovered something VERY promising today: I defined my wndproc function exactly like this:

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

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

And then I tried running my program, and then sending a WM_SETTINGCHANGE message using:

SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, IntPtr.Zero, IntPtr.Zero, _
             SendMessageTimeoutFlags.SMTO_ABORTIFHUNG, 5000, IntPtr.Zero)

在我制作的另一个程序中.那你问发生了什么事?好吧,我尝试了几次,每次弹出消息框时(我为其选择的单词都是微不足道的),然后我尝试等待不同的时间,然后再按OK,然后我会看到我的主表单发生了什么.很多时候,没有什么不同,它仍然会崩溃.但是偶尔,也许是1/5次,该程序仍会重新启动!然后,如果这样,我将尝试再次发送消息,然后再次发送,通常,它们将在程序的相同运行期间第二次失败,但偶尔会再次失败,大约是看起来的1/5倍,程序不会再次崩溃.然后我尝试两次使其崩溃.而且没有时间,无论我尝试发送该消息多少次,也不管msgbox弹出后我等待了多长时间,几乎永远都不会崩溃.

in another program I made. So what happened you ask? well I tried this several times, and every time the messagebox would pop up (the words I chose for it are insignificant), then I tried waiting different amounts of time before pressing ok, and then I would see what happened to my main form. Well a lot of the time, nothing was different, it would still crash. But occasionally, maybe 1/5 times, the program would still be respoding after! Then if it did, I would try sending the message again, and then again, usually they would fail the second time during the same run of the program, BUT occasionally again, about another 1/5 times it seemed, the program wouldn't crash AGAIN. And then the times I tried to crash it twice. and it didn't either time, it would almost always then never crash no matter how many times I tried sending the message and regardless of how long I waited after the msgbox popped up.

我发现等待大约5秒似乎增加了我的几率:触发冻结消息后,我按下冻结按钮后的窗体仍会保持焦点(顶部栏为蓝色),然后弹出msgbox向上,顶部也为蓝色(我认为是焦点),但它们两个都仍处于焦点"(至少是蓝色哈哈).然后大约5秒钟后,原始表单将失去焦点,看到该表单后,我将尝试单击确定".

I found waiting about 5 seconds seemed to increase my odds: my form that I trigger the message with would still be in focus (top bar would be blue), right after I pressed the freeze button, and then the msgbox would pop up, with the top also blue (in focus I assume), both of them still "in focus" (at least blue haha). Then after about 5 seconds the original form would lose focus, and after seeing that, I would try hitting ok.

我目前在想,等待一会儿再确认消息框有时会使我的程序不崩溃,因为它使消息超时,因此它不返回.我不知道为什么消息返回或不应该影响程序实际执行的操作.这是需要澄清的地方:)

I am currently thinking that this waiting a bit and then acknowledging the message box is sometimes enabling my program to not crash because it is timing out the message so it does not return. I do NOT know why the message returning or not should have an effect on what my program actually does though. This is the area where clarification would be helpful :)

编辑三遍:

所以我在Winspector中寻找了更多内容,我发现如果在单击确定"之前,等待WM_ERASEBKGND在我的桌面窗口(在Winspector中标记为"sysListView32'FolderView'"的窗口)中显示在我的msgbox上,程序将不会崩溃,有趣的是! sendmessagetimeout的超时通常接近WM_ERASEBKGND消息的超时时间.当然,这是从我的自制测试应用发送了WM_SETTINGCHANGE消息之后.

so I am looking in Winspector a bit more, and I find that if I wait for WM_ERASEBKGND to show up in my desktop window (which is the window labelled as "sysListView32 'FolderView'" in Winspector) before hitting "OK" on my msgbox, then the program will not crash, interesting! It usually takes close to the Timeout for the sendmessagetimeout for the WM_ERASEBKGND message to show up. this is of course after sending the WM_SETTINGCHANGE message from my homemade testing app.

因此,在此之后,我决定对Winspector进行更多研究,因为也许可以找到更多有用的队列?因为显然等待winspector显示一条消息已发送到我的桌面对我的程序根本不是真正的解决方法.我在程序过程中发现了几个异常命名的窗口:一个名为".NET -BroadcastEventWindow.2.0.0.0.378734a.0",另一个名为"GDI +挂钩窗口类'GDI + Window'",其子窗口名为"IME"默认的IME'".

So, after this I decide to look a bit more around Winspector, because maybe there are even more useful queues I can find? Since obviously waiting for winspector to show a message is sent to my desktop isn't an actual fix at all for my program. I find a few unusually named windows under my program process: one is named ".NET -BroadcastEventWindow.2.0.0.0.378734a.0" and another is named "GDI+ Hook Window Class 'GDI+ Window'" with a subwindow called "IME 'Default IME'".

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

I decide to look at the messages going to these windows to see if they are receiving any recognizable messages, such as WM_SETTINGCHANGE or WM_ERASEBKGND. Turns out, they do not recieve messages often: GDI+ didn't receive any messages while I watched I don't think, but .NET -BroadcastEventWindow received a few. The ones going to the BroadcastEventWindow were mostly only WM_appactivate when I clicked my application window or another window after it.

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

BUT THEN... I notice .Net BroadcastEventWindow receives my WM_CHANGESETTING message!!!! I look at what other messages show up: not a lot, but I notice when the app crashes because of the bug, there is a message I don't recognize: WM_USER+7194 (0x201A). Hm, lets see what that is. After I google it, I figure out it appears to be an application/user defined message, and then after another search about problems related to it, I notice that someone is able to use a filter to filter this message out and fix a problem of theirs (http://www.pcreview.co.uk/forums/handling-wm_user-messages-t1315625.html). It's worth a try for me at least right? so I re-add the filter I had tried previously, and change the values to be filtered. The app didn't crash!!!!!!!

接下来,我尝试让我的工作站锁定以查看是否仍然将其崩溃(因为以前仅是向其发送了单独的WM_CHANGESETTING消息).原来,它仍然确实崩溃了:(但是,我再次在winspector中查看该窗口,哦,呵呵,两条新的WM_USER消息:WM_USER + 7294(0x207E)和WM_USER + 7189(0x2015).所以我尝试过滤掉它们也...也不会在工作站锁定时崩溃!:D

Next I try by letting my workstation lock to see if that still crashes it (because previously was only with sending it the lone WM_CHANGESETTING message). turns out, it still did crash :( BUT, I take another look in winspector for that window, and oh huh, two NEW WM_USER messages: WM_USER+7294(0x207E) and WM_USER+7189(0x2015). So I try filtering those out too... and then it doesn't crash on workstation locking either!!! :D

到目前为止,我还没有注意到这对常规应用程序的使用也没有不利影响!这很有意义,因为我认为程序中没有故意包含任何用户定义的消息.

So far I have noticed no adverse affects of this on regular app use too! which makes sense, since I don't think any user defined messages are purposefully involved in my program.

在确定我的解决方案没有问题并且效果很好之前,我将把问题悬而未决.多亏了在我的调试中间阶段给我一些建议的人:)

I will be leaving the question open a bit longer until I make sure there is nothing wrong with my solution and it works well. Thanks to those of you who gave me a little bit of advice with how to proceed at the middle stages of my debugging :)

推荐答案

这些年来,我在各种问题中都提到了这个问题.永远不会完全诊断出来,我只会告诉你我对此有什么了解.

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.

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

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.

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

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.

无论哪种方式,都不会在正确的线程上引发事件,并且该事件违反了任何UI组件的线程要求.由于某些奇怪的原因,台式机交换机上触发的同一事件往往会导致死锁或崩溃,这往往会引起人们的注意.

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.

您需要仔细查看程序的初始化代码.到目前为止,最常见的错误是创建自己的启动屏幕.确保使用.NET框架中的内置支持做到这一点.

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.

这篇关于如何停止我的应用程序接收某些“消息"?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆