Mouse wheel scrolling the Web Browser control

A fairly common interface style these days is the multi-pane reading UI. You see it in Outlook, RSS Bandit, Sharp Reader, Sauce Reader, etc.  Outlook 2003 includes a nice feature when using the mouse wheel to scroll a window - the window that the mouse cursor is over is the one that scrolls, rather than the window that has focus. I've gotten quite used to this behavior, and was disappointed when I found that RSS Bandit didn't support it when trying to scroll the reading pane (I don't know about Sharp Reader, I haven't tried it).

Since RSS Bandit is open source, I started poking around in the code to figure out why. A comment in the code indicated that this was a known issue - clearly someone just hadn't had a chance to figure out the solution yet.

Generally, this style of wheel support is provided by filtering the WM_MOUSEWHEEL message and forwarding it to the control that the mouse wheel is over. The RSS Bandit code has a nice general implementation of this (see WheelSupport.cs if you're interested in the details), but it didn't work for the Reading Pane (which is actually an instance of the Web Browser control). Simply forwarding the WM_MOUSEWHEEL to the browser control didn't cause the window to scroll for some reason.

It took a little Spying, a little Googling, and a little experimenting to figure out how to make it work. The trick is to get the IOleWindow interface for the IHtmlDocument object displayed in the brower control. You can get the HWND from the IOleWindow and post the WM_MOUSEWHEEL message to that window. This window is actually a couple levels of children down from the web browser control window.

For example, if you have a WM_MOUSEWHEEL message and a web browser control, you would do something like this:

private bool ScrollWebBrowser(AxSHDocVw.AxWebBrowser control, Message m)
{
   IntPtr hwnd;
   IOleWindow oleWindow = (IOleWindow) control.Document;
  
   oleWindow.GetWindow(out hwnd);

   if (m.HWnd == hwnd)
   { // avoid recursion
      return false;
   }
 
   PostMessage(hwnd, WM_MOUSEWHEEL, m.WParam, m.LParam);

   return true;
}

The interop declarations for IOleWindow and PostMessage can be found at the PInvoke.NET web site. I've submitted a patch to the RSS Bandit project for this - if you want to see the full implementation, check there.

 

1 Comment

Comments have been disabled for this content.