从偷焦点prevent WebBrowser控件? [英] Prevent WebBrowser control from stealing focus?

查看:277
本文介绍了从偷焦点prevent WebBrowser控件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有没有办法从导致其母公司的形式把自己带到前面停止WebBrowser控件?

Is there a way to stop the WebBrowser control from causing its parent form to bring itself to the front?

如果您使用InvokeScript方法来调用一个JavaScript函数调用焦点()在主父文档中的iframe,就会造成窗口把自己直接到前面(或至少使任务栏图标开始闪烁)。有没有一种方法,以prevent这种情况的发生?

If you use the InvokeScript method to invoke a JavaScript function that calls focus() on an iframe within the main parent document, it will cause the window to bring itself directly to the front(or atleast cause the taskbar icon to start flashing). Is there a way to prevent this from happening?

我找到了一个临时的回答我的问题。

I've found a temporary answer to my problem.

在web浏览器的父窗体的去激活事件被激发,我从包装箱中取出web浏览器,并重新添加它时,它的旧父窗体被再次激活。

When the WebBrowser's parent Form's Deactive event is fired, I remove the WebBrowser from its container, and re-add it when its old parent form is activated again.

这是一种哈克,但它的作品。我接受什么更好的建议,但。

It's kind of hacky, but it works. I'm open to any better suggestions, though.

推荐答案

编辑:完全重写的问题,我误会了原来的问题

complete question rewritten, I misunderstood original question

让我们概括的问题:控制或组件,你没有关于控制,可以调用 FlashWindow (Win32 API函数)来获取关注的用户。你不希望出现这种情况。

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.

通常有两种解决办法是:使用API​​钩子或消息挂钩。由于API钩子是复杂的,涉及的,我会present的消息挂钩的解决方案。

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.

微软并没有在这么多的话是什么 FlashWindow 做解释。不幸的是,它不会发送特定邮件(比如 WM_FLASH 或类似的),这已经使得它更容易捕捉和废止这种行为。相反, FlashWindow 做了三件事:

Microsoft 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:

  1. 在它设置一个系统定时器的闪烁间隔
  2. 在它发出了一个 WM_NCACTIVATE 消息的第一次闪光
  3. 在它发出了一个 WM_NCACTIVATE 消息时,计时器到期(在收到 WM_SYSTIMER
  1. It sets a system timer for the flashing intervals
  2. It sends a WM_NCACTIVATE message for the first flash
  3. It sends a WM_NCACTIVATE message when the timer expires (on receiving WM_SYSTIMER)

根据如何组件调用FlashWindow,这可以是无限期的,直至另一个超时发生,直到它已聚焦或一次。每个WM_NCACTIVATE消息激活或关闭NC-区(标题栏,任务栏上的按钮)。它不改变输入的焦点。

Depending on how the component calls FlashWindow, this can be indefinite, until another timeout occurs, until it has focus or just once. Each WM_NCACTIVATE message activates or deactivates the NC-zone (caption bar, button on taskbar). It doesn't change the input the focus.

为preventing闪烁的任何解决方案是一个有点麻烦。主要的挑战是:

Any solution for preventing the flashing is a bit involved. The main challenges are:

  1. WM_SYSTIMER 事件异步PostMessage的发送,而不是由窗体的的WndProc 方法获得(其仅处理同步消息)
  2. WM_NCACTIVATE 消息也用来当用户点击标题栏或任务栏按钮来设置输入焦点,简单地取消这些消息会产生有害的副作用
  3. FlashWindow总是闪烁至少一次,无论 WM_SYSTIMER 点火与否。
  1. the WM_SYSTIMER event is sent asynchronously with PostMessage and is not received by the WndProc method of the Form (it only processes synchronous messages)
  2. the WM_NCACTIVATE messages are also used when the user clicks on the title bar or taskbar button to set input focus, simply canceling these messages will have unwanted side effects
  3. FlashWindow will always flash at least once, regardless of the WM_SYSTIMER firing or not.

WM_SYSTIMER 消息是未记录。它具有价值 0x0118 ,并在内部使用Windows来一次这样的事情作为插入符的闪烁,在菜单中开启等。这里的延迟是用于时间在闪烁的。

The WM_SYSTIMER message is undocumented. It has the value 0x0118 and is used internally by Windows to time such things as the blinking of the caret, the delay in a menu opening etc. Here it is used for the time between the flashes.

该解决方案,我在这里present是进一步发展的基础。它不是一个完整的解决方案,但它解决了问题,在许多情况下。将下面的表单中的code:

The 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:

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已经prevents闪烁彻底。你必须添加一些逻辑来更改标题栏,因为完全不理 WM_NCACTIVATE 意味着标题栏会显得活跃的时候,即使事实并非如此。

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.

下面code为您提供更多的控制。你可以用它作出反应的闪烁本身。通常情况下,一个主窗口不接受 WM_SYSTIMER 事件如此频繁,但你必须尝试你是否应该例外。看来,对于 FlashWindow 的wParam 总是设置为 0xFFF8 ,但不要尝试它,因为这是不记录任何地方。

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.

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
    }
}

要激活此MessageFilter的,只是在某处添加以下行表单中的Load事件:

To activate this messagefilter, simply add the following line somewhere in your form load event:

Application.AddMessageFilter(new MyMessageFilter(this.Handle));

以下常量应放在一流水平。他们在这两个code以上部分使用:

The following constants should be placed at class level. They are used in both code sections above:

public const UInt32 WM_SYSTIMER = 0x0118;
public const UInt32 WM_NCACTIVATE = 0x86;

结论

虽然这个问题本身是可以解决的,它是迄今为止并不容易。通过上面的把手,你应该得到很远。使用过滤器prevent闪烁,但随后的第一个闪仍然发生。使用 WinProc 覆盖至prevent第一个也是如此,但是从行为太奇怪(添加一些逻辑,以prevent您的应用程序,即:始终处于非活动状态的标题栏,或始终处于激活状态)。你已经有了一些code,您可以使用此相结合,设置一些布尔标志。

Conclusion

Though 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.

这篇关于从偷焦点prevent WebBrowser控件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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