Click here to Skip to main content
15,860,859 members
Articles / Programming Languages / C#
Article

Subclassing Internet Explorer for Context Menu Overriding

Rate me:
Please Sign up or sign in to vote.
4.82/5 (10 votes)
1 Sep 2004CPOL4 min read 80.5K   1.9K   34   18
Internet Explorer is a complex beast, I have managed to untangle the context menu to easily allow custom menus to appear when you right click

Image 1

Introduction

This is my first article here at CodeProject so please excuse the format or anything that you are used to with the myriads of excellent posts on this site.

This article has been put together to fill a void that I found when trying to use the Internet Explorer object. I have recently undertaken a project at work that required me to embed a browser object into an application and display reports through Microsoft Reporting Services.

There was a need to stop the user from making use of the internet through the software, but also to stop them from looking at the underlying code as well as giving them extra options on the context menu.

Background

The Internet Explorer is an odd control. Essentially if you use Spy++ you can see that the object has children that protect the object from people picking off the handle to the real Internet Explorer easily. There was a need to iterate through the browser object looking for the child object called Internet Explorer_Server .

Image 2

Much of the child search is done in the API Call 'EnumChildWindow'. The snippet of code makes use of some API calls to capture the correct handle for the Internet Explorer and then override the Context Menu and replace it with one that I wanted the user to see.

Win32 API in C# & Delegates

C#
private delegate Int32 EnumChildProc(IntPtr hWnd, IntPtr lParam);
private delegate int Win32WndProc(IntPtr hWnd, int Msg, 
  int wParam, int lParam);

[DllImport("user32")] 
public static extern int GetClassName(int hwnd, 
  StringBuilder lpClassName, int nMaxCount);
[DllImport("user32")] 
public static extern int EnumChildWindows(int hwndParent, 
  Delegate lpEnumFunc, int lParam);
[DllImport("user32")] 
private static extern IntPtr SetWindowLong(IntPtr hWnd, 
  int nIndex, Win32WndProc newProc);
[DllImport("user32")] 
private static extern int CallWindowProc(IntPtr lpPrevWndFunc, 
  IntPtr hWnd, int Msg, int wParam, int lParam);
[DllImport("user32")] 
private static extern IntPtr SetWindowLong(IntPtr hWnd, 
  int nIndex, IntPtr newProc);
[DllImport("user32")] 
public static extern int GetCursorPos(ref Point lpPoint);
[DllImport("user32")] 
public static extern int ScreenToClient(int hwnd, ref Point lpPoint);

To access these external API functions we need the namespace System.Runtime.InteropServices. This namespace provides a collection of classes useful for accessing COM objects, and native APIs. Shown below is the way the code is written in C#:

C#
[DllImport("user32")] 
public static extern int EnumChildWindows(int hwndParent, 
  Delegate lpEnumFunc, int lParam);

The

extern
keyword indicates that the method is implemented externally.
extern
methods must be declared as
static
.

Within this API call you may notice the Delegate reference.

C#
private delegate Int32 EnumChildProc(IntPtr hWnd, IntPtr lParam);

The delegate needs to be created in the same way that we create a class, shown below.

C#
EnumChildProc myEnumChildProc = new EnumChildProc(EnumChild);
EnumChildWindows(hWnd.ToInt32(), myEnumChildProc, hWnd.ToInt32());

The first line shows the creation of the delegate, we pass to EnumChildProc a reference to the EnumChild function. We then use the EnumChildWindow API call to drill down into the child windows and compare the name of the window against the one that we are trying to find.

This CallBack feature will iterate through each child until it either runs out of children or finds the window.

Using the code

To make use of this code and get you on the road to creating your very own web aware app, you need to add the 'IEHwd.cs' class to your project.

Once this is done, you need to create an instance of the object at a global level to your form.

C#
private IEHwd o = new IEHwd();

Once this is done you can now access the features within. You will need to pass to the class an instance of your form and also the context menu that you want to show when the right click is done.

I use the NavigateComplete2 event that gets fired once a response has been received from the web site that the page is being produced.

C#
if(o.oldWndProc.ToInt32() == 0)
{
    IntPtr s = o.IEFromhWnd(wbBrowser.Handle);
                
    o.IEContextMenu = IECustomContext;
    o.CurrForm = this;
                
    o.StartSubclass(s);
}

The above statement goes into the IEHwd.cs class and retrieves the browser handle. We pass the web browser handle into the object as a starting point. We then pass the Context Menu into the class via a property and the same for the current form.

Once that is done we call StartSubclass where we store away the old handle so that we can exit the program cleanly at the end (when the form is discarded.)

C#
switch(Msg)
{
    case WM_RBUTTONDOWN:
    {
        //Right Mouse Button has been pressed
        //We need to capture the area on the screen
        //Next to the mouse we post our Custom Context Menu
        Point p = new Point();
        GetCursorPos(ref p);
        ScreenToClient(currForm.Handle.ToInt32(), ref p);
        ieContextMenu.Show(currForm, p);

        return 0;
    }
    case WM_RBUTTONDBLCLK:
        return 0;
    default:
        break;
}

When the user clicks the right mouse button over the Internet Explorer window we want to capture the right click event. This happens by checking for the WM_RBUTTONDOWN. Once pressed we need to get the point where the mouse is using the the GetCursorPos. Then we make use of the ScreenToClient API call to make sure that the Context Menu appears under the mouse and not somewhere else on the screen.

Finally we show the Context Menu that we passed into the class earlier and return 0 to stop the real Internet Explorer Context Menu from showing.

You may notice that I also trap the WM_RBUTTONDBLCLK message also. I found if you repeatedly clicked the right mouse button it would display the real Internet Explorer Context Menu.

Points of Interest

I leant that there are some interesting features available in the API. I have not used the API as much as I should and will endeavor to make more use of it in the future.

Credits

I would like to acknowledge Chris Wilcock for assistance with the API calls.

License

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


Written By
Software Developer (Senior) Positive Solutions
United Kingdom United Kingdom
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionWhat if My webbrowse has multiple IE_server? Pin
xiviwo11-Jul-10 23:21
xiviwo11-Jul-10 23:21 
Generali want to register new context menu to the IE Pin
Ahmad Eid Salim28-Oct-07 4:11
Ahmad Eid Salim28-Oct-07 4:11 
GeneralCapturing Paste Click/Command Pin
Cyrus Chan27-Mar-07 22:12
Cyrus Chan27-Mar-07 22:12 
GeneralPlease help with IDocHostUIHandler Pin
megadino8-Aug-05 22:35
megadino8-Aug-05 22:35 
GeneralMyWndProc not called Pin
xreita8-May-05 23:17
xreita8-May-05 23:17 
GeneralRe: MyWndProc not called Pin
Paul Talbot8-May-05 23:50
Paul Talbot8-May-05 23:50 
GeneralIE's context menu is still accessible Pin
all_ids_are_taken_already26-Apr-05 8:16
all_ids_are_taken_already26-Apr-05 8:16 
GeneralRe: IE's context menu is still accessible Pin
Paul Talbot26-Apr-05 21:13
Paul Talbot26-Apr-05 21:13 
QuestionIs it possible to trigger WM_HSCROLL or WM_VSROLL event? Pin
25-Apr-05 20:41
suss25-Apr-05 20:41 
AnswerRe: Is it possible to trigger WM_HSCROLL or WM_VSROLL event? Pin
Paul Talbot25-Apr-05 21:59
Paul Talbot25-Apr-05 21:59 
QuestionwbBrowser_NavigateComplete2() fn was not calling? Pin
25-Apr-05 1:24
suss25-Apr-05 1:24 
AnswerRe: wbBrowser_NavigateComplete2() fn was not calling? Pin
Paul Talbot25-Apr-05 21:45
Paul Talbot25-Apr-05 21:45 
GeneralIE URL Pin
safinahmed19-Oct-04 7:43
safinahmed19-Oct-04 7:43 
GeneralRe: IE URL Pin
Paul Talbot19-Oct-04 22:04
Paul Talbot19-Oct-04 22:04 
QuestionHow to Restore Old IE context Menu Pin
jk chan17-Sep-04 1:42
jk chan17-Sep-04 1:42 
Hi paul

Pls say how to restore old context menu.. Waiting for reply

Thanks & Regards
Krishnadevan.K

krishnadk
AnswerRe: How to Restore Old IE context Menu Pin
Paul Talbot17-Sep-04 3:04
Paul Talbot17-Sep-04 3:04 
QuestionWhy subclassing? Pin
Matze1-Sep-04 22:39
Matze1-Sep-04 22:39 
AnswerRe: Why subclassing? Pin
Paul Talbot1-Sep-04 22:57
Paul Talbot1-Sep-04 22:57 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

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