Click here to Skip to main content
6,822,123 members and growing! (18,663 online)
Email Password   helpLost your password?
Platforms, Frameworks & Libraries » Mobile Development » Controls     Beginner License: The Code Project Open License (CPOL)

Mouse Events for WebBrowser control in .NET CF

By Vu H. Pham

Expanding .NET CF's 2.0 WebBrowser to handle mouse events
C# (C#2.0), Windows, .NETCF, .NET, Dev
Revision:2 (See All)
Posted:12 Jul 2008
Views:18,591
Bookmarked:19 times
printPrint   add Share
      Discuss Discuss   Broken Article?Report  
6 votes for this article.
Popularity: 3.50 Rating: 4.50 out of 5

1

2

3
3 votes, 50.0%
4
3 votes, 50.0%
5

Introduction

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 (MouseUp, MouseDown, MouseMove).

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.

Background

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_LBUTTONUP, WM_LBUTTONDOWN and 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.

Remotespy.jpg

Implementation

There are only approximate 100 lines of code in the WebBrowserEx class, so I paste all here.

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using OpenNETCF.Windows.Forms;
using OpenNETCF.Win32;
using Microsoft.WindowsCE.Forms;

namespace webBrowserEx
{
    /// <summary>
    /// An extended WebBrowser, can handle Mouse Events.
    /// </summary>
    public class WebBrowserEx : System.Windows.Forms.WebBrowser, IMessageFilter
    {

        public WebBrowserEx()
        {
            //Initialize Message Filter, using OpenNETCF's ApplicationEx
            OpenNETCF.Windows.Forms.ApplicationEx.AddMessageFilter(this);
        }

        #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);

                switch (m.Msg)
                {
                    case (int)WM.LBUTTONUP:
                        base.OnMouseUp(e);
                        break;
                    case (int)WM.LBUTTONDOWN:
                        base.OnMouseDown(e);
                        break;
                    case (int)WM.MOUSEMOVE:
                        base.OnMouseMove(e);
                        break;
                }
            }

            return false;
        }

        #endregion

        #region ------- Private functions -----------------

        /// <summary>
        /// Check whether <see cref="hCheck"/> 
        /// is one of <see cref="hWnd"/>'s grandchildren.
        /// </summary>
        /// <param name="hWnd"></param>
        /// <param name="hCheck"></param>
        /// <returns></returns>
        private static bool IsChildestWindow(IntPtr hWnd, IntPtr hCheck)
        {
            IntPtr ret = hWnd;

            //Find the first "smallest" child
            while ((hWnd = GetWindow(hWnd, (int)GetWindowFlags.GW_CHILD)) != IntPtr.Zero)
            {
                ret = hWnd;
            }
            
            //goes through all of "smallest" grandchildren
            hWnd = ret;
            while ((ret != hCheck) &&
                ((hWnd = GetWindow(ret, (int)GetWindowFlags.GW_HWNDNEXT)) != IntPtr.Zero))
            {
                ret = hWnd;
            }

            return (hWnd != IntPtr.Zero);
        }

        #endregion

        #region -------- P/Invoke declarations ------------

        /// <summary>
        /// Get relative window with a given window.
        /// </summary>
        /// <param name="hwnd">the Given window</param>
        /// <param name="cmd">an <see cref="GetWindowFlags"/> value, 
        /// indicates the relation.</param>
        /// <returns></returns>
        [DllImport("coredll.dll")]
        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
        }

        #endregion
    }
}

The implementation is so easy. Whenever receiving a WM_MOUSEMOVE, WM_LBUTTONUP, 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 OpenNETCF.Windows.Forms.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
{
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [MTAThread]
    static void Main()
    {            
        // Instead of using Application class,
        // we use OpenNETCF's ApplicationEx which enables MessageFilter.
        OpenNETCF.Windows.Forms.ApplicationEx.Run(new Form1());
        //Application.Run(new Form1());
    }
} 

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 System.Windows.Forms.WebBrowser by OpenNETCF.Windows.Forms.WebBrowser:
    /// <summary>
    /// An extended WebBrowser, can handle Mouse Events.
    /// </summary>
    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.

History

  • July 13, 2008: Article submitted

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Vu H. Pham


Member
Vu is a student in C.S. at HCMUS. If doesn't fail anymore subjects, he will graduate in 2010 and (maybe) earn a B.S.

He currently develops in VB/VB.NET, C++/C#, ASP.NET, MFC. He love developing in .NET CF for Mobile devices. Twisted and Python are also interesting fields.
Occupation: Software Developer
Location: Vietnam Vietnam

Other popular Mobile Development articles:

  • Writing Your Own GPS Applications: Part 2
    In part two of the series, the author of "GPS.NET" teaches developers how to write GPS applications suitable for the real world by mastering GPS precision concepts. Source code includes a working NMEA interpreter and sample high-precision application in C# and VB.NET.
  • Writing Your Own GPS Applications: Part I
    What is it that GPS applications need to be good enough to use for in-car navigation? Also, how does the process of interpreting GPS data actually work? In this three-part series, I will cover both topics and give you the skills you need to write a commercial-grade GPS application.
  • Learn How to Find GPS Location on Any SmartPhone, and Then Make it Relevant
    A step by step tutorial for getting GPS from any SmartPhone, even without GPS built in, and then making location useful.
  • Windows Mobile, iPhone, Android - Marketplace Comparison
    Detailed comparison between Windows Mobile Marketplace, Apple's iPhone AppStore and Android Market from developer point of view.
  • iPhone UI in Windows Mobile
    It's an interface that works with transparency effects. As a sample I used an interface just like the iPhone one. In this tutorial I am explaining how simple is working with transparency on Windows Mobile.
Article Top
You must Sign In to use this message board.
FAQ FAQ 
 
Noise Tolerance  Layout  Per page   
 Msgs 1 to 8 of 8 (Total in Forum: 8) (Refresh)FirstPrevNext
GeneralIsChildestWindow slightly confusing PinmemberRobert.AC.Allen0:51 4 Dec '09  
GeneralRe: IsChildestWindow slightly confusing PinmemberVu H. Pham6:17 4 Dec '09  
Generalgetting elements by clicking the mouse.. Pinmemberyahavho14:40 2 Aug '09  
GeneralRe: getting elements by clicking the mouse.. PinmemberVu H. Pham20:51 4 Aug '09  
GeneralOMG Pinmemberthehai0090:46 6 Jul '09  
Generaleasy to understand PinmemberPapa Arubin2:03 21 Sep '08  
GeneralSo good! PinmemberPhuongkar19:35 13 Jul '08  
GeneralRe: So good! PinmemberVu H. Pham21:16 13 Jul '08  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads.

PermaLink | Privacy | Terms of Use
Last Updated: 12 Jul 2008
Editor: Deeksha Shenoy
Copyright 2008 by Vu H. Pham
Everything else Copyright © CodeProject, 1999-2010
Web19 | Advertise on the Code Project