| EDIT: complete question rewritten, I misunderstood original question Let's generalize the problem: a control or component that you don't have control about, can call FlashWindow (the Win32 API function) to get attention from the user. You don't want that. There are generally two solutions for this: use API hooking or Message hooking. Since API hooking is complex and involved, I'll present a solution for Message hooking. FlashWindowMicrosoft doesn't explain in so many words what FlashWindow does. Unfortunately, it doesn't send a specific message (say WM_FLASH or similar), which would've made it easier to capture and annul this behavior. Instead, FlashWindow does three things:
ChallengeAny solution for preventing the flashing is a bit involved. The main challenges are:
SolutionThe solution I present here is a basis for further development. It is not a complete solution, but it solves the issue in many cases. Place the following in your form code: [code=csharp]protected override void WndProc(ref Message m) { bool messageHandled = false; if (m.Msg == WM_NCACTIVATE) { // add logic here to determine user action, losing focus etc and set // messageHandled and m.Result only when user action is not the cause // of triggering WM_NCACTIVATE m.Result = IntPtr.Zero; messageHandled = true; } if(!messageHandled) base.WndProc(ref m); }[/code]The above code already prevents flashing completely. You'll have to add some logic to change the title bar, because totally ignoring WM_NCACTIVATE means that the title bar will look active all the time, even when it isn't. The following code gives you more control. You can use it to react to the flashing itself. Normally, a main window does not receive WM_SYSTIMER events so often, but you'll have to experiment whether you should make exceptions. It seems that for FlashWindow, the wParam is always set to 0xFFF8, but do experiment with it, as this is not documented anywhere. [code=csharp]public class MyMessageFilter : IMessageFilter { // an application can have many windows, only filter for one window at the time IntPtr FilteredHwnd = IntPtr.Zero; public MyMessageFilter(IntPtr hwnd) { this.FilteredHwnd = hwnd; } public bool PreFilterMessage(ref Message m) { if (this.FilteredHwnd == m.HWnd && m.Msg == WM_SYSTIMER) return true; // stop handling the message further else return false; // all other msgs: handle them } }[/code]To activate this messagefilter, simply add the following line somewhere in your form load event: Application.AddMessageFilter(new MyMessageFilter(this.Handle));The following constants should be placed at class level. They are used in both code sections above: [code=csharp]public const UInt32 WM_SYSTIMER = 0x0118;public const UInt32 WM_NCACTIVATE = 0x86;[/code]ConclusionThough the problem itself is solvable, it is by far not easy. With the above handles, you should get quite far. Use the filter to prevent the flashing, but then the first "flash" still happens. Use the WinProc override to prevent the first one too, but add some logic to prevent your application from behaving too oddly (i.e.: always inactive title bar, or always active). You already have some code that you can combine with this to set some boolean flags. |
欢迎光临 苏飞论坛 (http://www.sufeinet.com/) | Powered by Discuz! X3.4 |