0

我想转发MouseWheel在表单级别生成的事件,以便它们将由嵌入式WebBrowser控件处理,即使该控件没有焦点。

这是我所做的:

  1. 实施IMessageFilter.PreFilterMessage
  2. 将过滤器注册为Application.AddMessageFilter.
  3. 在过滤器中,收听WM_MOUSEWHEEL消息。
  4. 将消息转发SendMessage到目标控件(在我的情况下WebBrowser)。

在代码中,这看起来像这样:

bool IMessageFilter.PreFilterMessage(ref Message m)
{
    if (m.Msg == 0x20A)     //  WM_MOUSEWHEEL
    {
        if (this.target != null)
        {
            var handle = this.target.Handle;
            Native.SendMessage (handle, m.Message, m.WParam, m.LParam);
            return true;
        }
    }
    return false;
}

// Registering the message filter:

System.Windows.Forms.Application.AddMessageFilter (this);

// Win32 code:

protected static class NativeMethods
{
    [System.Runtime.InteropServices.DllImport ("user32.dll")]
    public static extern System.IntPtr SendMessage(System.IntPtr hWnd, System.Int32 Msg, System.IntPtr wParam, System.IntPtr lParam);
}

这不起作用。什么都没发生。

但是,如果WebBrowser我指定 a而不是 aPanel作为目标,那么这将非常有效。

4

2 回答 2

1

皮埃尔的回答对我有用(不能投票,因为声誉不足)。但是,它需要进行调整才能在 VB.NET 中工作,所以我想我会发布,以防有​​人卡在这一点上:

Imports System.Runtime.InteropServices

Public Class Form1 Implements IMessageFilter

    Public Sub New()

        ' This call is required by the designer.
        InitializeComponent()

        ' Add any initialization after the InitializeComponent() call.
        System.Windows.Forms.Application.AddMessageFilter(Me)

    End Sub

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
        Me.WebBrowser1.Navigate("D:\Development\test3.html")
    End Sub

    Private Function IMessageFilter_PreFilterMessage(ByRef m As Message) As Boolean Implements IMessageFilter.PreFilterMessage

        If m.Msg = &H20A Then
            '  WM_MOUSEWHEEL

            If m.HWnd <> 0 Then
                Dim handle = m.HWnd
                handle = NativeMethods.FindWindowEx(handle, IntPtr.Zero, "Shell Embedding", Nothing)
                handle = NativeMethods.FindWindowEx(handle, IntPtr.Zero, "Shell DocObject View", Nothing)
                handle = NativeMethods.FindWindowEx(handle, IntPtr.Zero, "Internet Explorer_Server", Nothing)
                NativeMethods.SendMessage(handle, m.Msg, m.WParam, m.LParam)
                Return True
            End If

        End If

        Return False

    End Function

    Protected NotInheritable Class NativeMethods
        Private Sub New()
        End Sub
        <System.Runtime.InteropServices.DllImport("user32.dll")> _
        Public Shared Function SendMessage(hWnd As System.IntPtr, Msg As System.Int32, wParam As System.IntPtr, lParam As System.IntPtr) As System.IntPtr
        End Function

        <System.Runtime.InteropServices.DllImport("user32.dll")> _
        Public Shared Function FindWindowEx(hwndParent As System.IntPtr, hwndChildAfter As System.IntPtr, className As String, windowName As String) As System.IntPtr
        End Function
    End Class


End Class
于 2014-11-08T11:36:47.150 回答
1

用 Spy++ 调查发现,WebBrowserWinForms 中的控件使用了几层容器来包装真正的 IE 组件:

System.Windows.Forms.WebBrowser
  Shell Embedding
    Shell DocObject View
      Internet Explorer_Server

将事件发送到任何容器都不会产生任何影响。必须将WM_MOUSEWHEEL事件发送到Internet Explorer_Server句柄才能使其工作。

这是修改后的代码,它通过挖掘容器来找到 IE 组件:

bool IMessageFilter.PreFilterMessage(ref Message m)
{
    if (m.Msg == 0x20A)     //  WM_MOUSEWHEEL
    {
        if (this.target != null)
        {
            var handle = this.target.Handle;
            handle = NativeMethods.FindWindowEx (handle, IntPtr.Zero, "Shell Embedding", null);
            handle = NativeMethods.FindWindowEx (handle, IntPtr.Zero, "Shell DocObject View", null);
            handle = NativeMethods.FindWindowEx (handle, IntPtr.Zero, "Internet Explorer_Server", null);
            Native.SendMessage (handle, m.Msg, m.WParam, m.LParam);
            return true;
        }
    }
    return false;
}

protected static class NativeMethods
{
    [System.Runtime.InteropServices.DllImport ("user32.dll")]
    public static extern System.IntPtr SendMessage(System.IntPtr hWnd, System.Int32 Msg, System.IntPtr wParam, System.IntPtr lParam);

    [System.Runtime.InteropServices.DllImport ("user32.dll")]
    public static extern System.IntPtr FindWindowEx(System.IntPtr hwndParent, System.IntPtr hwndChildAfter, string className, string windowName);
}
于 2013-06-21T05:07:20.700 回答