2013-06-21 41 views
0

我想轉發MouseWheel在表單級別生成的事件,以便即使在該控件沒有焦點時,它們也會由嵌入的WebBrowser控件處理。將MouseWheel消息發送到System.Windows.Forms.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,我指定Panel作爲目標,那麼這個工作非常好。

回答

1

與間諜++調查,發現該WebBrowser控制Winforms中使用的容器的若干層來包裹真實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); 
} 
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 
+0

除了從C#到VB翻譯,什麼是你必須做的好辦法? –

+0

嗨皮埃爾。只是一對夫婦,可能只是與使VB.NET和C#不同的東西有關。我最初通過Developerfusion上的代碼轉換工具運行你的代碼,但它並沒有馬上工作。有一件事是用m.HWnd替換this.target;另一個是用m.Msg替換m.Message。在第二點上,我想知道它是否是原始C#示例中的拼寫錯誤?乾杯,羅賓 –

+0

是的,的確,「m.Msg」是我的一個錯字。對不起,我編輯了我的答案,以使其筆直。 –