Nearly, in one of my .NET Compact Framework 2.0 projects, I want to use the
WebBrowser control to display rich-media content. Unfortunately, the
WebBrowser control in the .NET CF is not as powerful as the .NET Framework's control. It does not have some of the useful interfaces, especially it does not support DOM model... My requirements for the control are:
- Doesn't have the progress bar at the bottom.
- Doesn't use the default context menu (disable it, or even better, I can customize the context menu).
- Has a way to append HTML text into it (
DocumentText or something like that).
- Can handle Mouse events (
The OpenNETCF's SDF
WebBrowser control does satisfy the first three requirements, but it still cannot handle mouse events. So I decided to expand the standard
WebBrowser control so that it can play with mouse events.
In the .NET Framework, using the
Document property, we can easily handle mouse events for the
WebBrowser control; but the .NET CF doesn't. Because when the user clicks on the
WebBrowser control, he actually clicks on the
Document that the control hosts, so the
WebBrowser does not know this event, and of course it doesn't raise the correlative events.
The idea to solve the problem: derive the
WebBrowser control, and hook all of the mouse events which occur inside the control. Thanks to OpenNETCF's
ApplicationEx class, we can achieve this in managed code. Concretely, we write a class called
WebBrowserEx, which is derived from .NET CF's
WebBrowser control, and implement the
IMessageFilter interface. This interface will help us to hook and catch
WM_MOUSEMOVE message. (If you aren't familiar with
IMessageFiter, you should go to the OpenNETCF's website and have a look).
But, when you click on the WebBrowser, which is the child window receives these messages? Not a problem! Using the Remote Spy utility (in the Visual Studio Remote Tools), we can see a grandchild window of the
WebBrowser control. This window belongs to
PIEHTML class and receives all of the mouse messages.
There are only approximate 100 lines of code in the
WebBrowserEx class, so I paste all here.
public class WebBrowserEx : System.Windows.Forms.WebBrowser, IMessageFilter
#region ------ IMessageFilter implementation ------
public bool PreFilterMessage(ref Message m)
if ((m.Msg == (int)WM.LBUTTONDOWN || m.Msg == (int)WM.LBUTTONUP ||
m.Msg == (int)WM.MOUSEMOVE)
&& IsChildestWindow(this.Handle, m.HWnd))
int xPos = (int)m.LParam & 0xFFFF;
int yPos = ((int)m.LParam >> 16) & 0xFFFF;
MouseEventArgs e = new MouseEventArgs(MouseButtons.Left, 1,
xPos, yPos, 0);
#region ------- Private functions -----------------
private static bool IsChildestWindow(IntPtr hWnd, IntPtr hCheck)
IntPtr ret = hWnd;
while ((hWnd = GetWindow(hWnd, (int)GetWindowFlags.GW_CHILD)) != IntPtr.Zero)
ret = hWnd;
hWnd = ret;
while ((ret != hCheck) &&
((hWnd = GetWindow(ret, (int)GetWindowFlags.GW_HWNDNEXT)) != IntPtr.Zero))
ret = hWnd;
return (hWnd != IntPtr.Zero);
#region -------- P/Invoke declarations ------------
private static extern IntPtr GetWindow(IntPtr hwnd, int cmd);
private enum GetWindowFlags : int
GW_HWNDFIRST = 0,
GW_HWNDLAST = 1,
GW_HWNDNEXT = 2,
GW_HWNDPREV = 3,
GW_OWNER = 4,
GW_CHILD = 5,
GW_MAX = 5
The implementation is so easy. Whenever receiving a
WM_LBUTTONDOWN message, we will check if the
m.HWnd is a grandchild of the
WebBrowser (i.e. the
PIEHTML window) and raise the correlative events.
The last thing we have to do is use the
ApplicationEx class to run the application, instead of
System.Windows.Forms.Application. This will help in receiving and processing messages in the
PreFilterMessage function. We place this code in Program.cs:
static class Program
static void Main()
Points of Interest
- I built the sample code in VS 2008, using Smart Device Project on .NET Compact Framework 2.0. But in .NET CF 3.5, it should be fine.
- Instead of using
System.Windows.Forms.WebBrowser, you can use the
OpenNETCF.Windows.Forms.WebBrowser class. In that case, you only have to replace
public class WebBrowserEx : OpenNETCF.Windows.Forms.WebBrowser, IMessageFilter
Derived from OpenNETCF's
WebBrowser, you can use
WebBrowserEx in .NET CF 1.0, and it has built-in functions such as: disabled the default context menu, doesn't have the progress bar...
Through the years, I learnt a lot of interesting things from CodeProject, but this is my first article, with a shy code... So, feel free to comment and... ^^.
Sorry for my English, it's not my mother language.
- July 13, 2008: Article submitted