Click here to Skip to main content
Click here to Skip to main content

Web Browser Context Menu Ctrl: Load Shortcut From Your App In Any Browser

, 22 Jul 2014 CPOL
Rate this:
Please Sign up or sign in to vote.
Drop this control on your form, add it as a context menu to any control and you can load web links in any installed web browser. The control knows which web browser(s) are installed and only displays relevent choices.

Note: Release of Version 1.2.0.0 (07/22/2014)

I am release version 1.2.0.0 (previous version 1.1.0.0) to fix a problem with the latest version of the Opera web browser. If you have version 1.1.0.0 and newer versions (21.x, 22.x) you will most likely find that when you try to load the link from the menu that an exception will be thrown. Version 1.2.0.0 fixes that error.

I explain this further in the Updates section below.

Introduction

While writing an RSS Reader I wanted an easy way allow the user to load the individual articles that the RSS feed brought back(web links) via any web browser s/he chose. However, that would mean I would have to know which browsers were installed.

I decided to create a control based on ContextMenu that would :

  1. Determine which of the top 5 browsers (IE, FireFox, Chrome, Opera, Safari) were installed.
  2. Only show the choices for the browsers which are actually installed on the user's machine: ie - if only IE is installed, then the context menu should only show that choice.
  3. Allow me to set the URL which would be loaded
  4. Simply start the web browser if there is no URL associated.
  5. Make the context menu work in any project -- simply by dropping it on a form -- and with any control -- simply by setting the control's context menu to my control.

Ugly Example With the Pretty Menu

Here's a picture of what the menu looks like when the user right clicks any control that has its contextmenu set to point at it.

The over all example is a bit cluttered, but that's just because I am attempting to show you that you can use this new WebBrowserMenu with just about any control (DataGridView, TextBox, GroupBox, even PictureBox...and more).

Using the code

Download the code and build the project or just get the WebBrowserMenu.dll. That dll contains all the code you need.

Built In .NET 2.0 For A Reason

I built it in .NET 2.0 so it can be used in many projects (2.0, 3.0, 3.5, 4.0).

Windows OS Platforms

I've tested this on Windows XP (Service Pack 2 & 3), Vista 32-bit and Windows 7 64-bit. Others (Windows versions) are unknown, but I believe it will work.

Add A Reference

Go to Visual Studio and open the project you'd like to use the control in and right-click the [References] folder under Solution Explorer. Next, browse to the place where you've stored (or built) the WebBrowserMenu.dll and select it. It is now added as a reference to your project. This will enable you to use the control in your project.

Add Item To Toolbox

Next, we have to add the item to the Toolbox so we can drag and drop the control onto your Windows Form.

The easiest way I've found to get Visual Studio (2010) to do that is to:

  1. Choose the design view of your Windows form
  2. Go to your Toolbox
  3. Choose the General tab
  4. Right-click in the area where the controls normally appear.
  5. When the context menu appears, select the Choose Items... menu (see following image).

  1. The dialog box shown in the next image will appear.
  2. Click the Browse button and navigate to the place where you have the WebBrowserMenu.dll -- just like you did when you added the reference.
  3. When you select the DLL it should appear as checked -- see next image.
  4. Click the OK button and the WebBrowserContextMenu item should appear with a little gear icon next to it (shown in previous image).

Drag and Drop the WebBrowserContextMenu Control

Once you have followed those steps you'll be able to drag and drop one of the WebBrowserContextMenu controls onto any Windows Form in your project.

Make sure you have a Windows Form in Design view and do that now.

Once you drop the control on the form, it will look like this:

Visual Studio automatically names the instance of the control as: webBrowserContextMenu1.
We're ready to add the code to support the menu.

Add Code To Allow You To Set URL To Open

The first thing we need to do is add an event handler that will allow you to set the value of the URL that will open when the user selects a browser. Since you want the URL to be set right before the user clicks the menu item we add the Opening event handler. Open up the constructor of your form and add the following code:

//
// webBrowserContextMenu1.Opening += new CancelEventHandler(webBrowserContextMenu1_Opening);
// 

After you hit the dot(.) and type the 'O' you'll see the event appear with intellisense, so it'll be easy.

Next, it'll prompt you to hit the tab key to add the webBrowserContextMenu1_Opening method. You can name this method anything as long as it has a signature like:

// void webBrowserContextMenu1_Opening(object sender, CancelEventArgs e) 

The Opening eventhandler takes an object and the CancelEvenArgs so as long as we have a method with that signature you can call it whatever you like:

// void WebBrowserOpening(object sender, CancelEventArgs e)

Just make sure the eventhandler has the same name:

// webBrowserContextMenu1.Opening += new CancelEventHandler(WebBrowserOpening);

More About Opening Event

The Opening event fires right before the menu opens so this gives us a chance to set the Url value of the WebBrowserContextMenu control.

The CancelEventArgs parameter can allow you to cancel this event, but we won't need to do that.

Add Switch Statement To Handle Specific Controls

Next, we want to add a switch statement to our Opening event method so that we can set the Url property of the WebBrowserContextMenu specifically related to the calling control.

Read Different Values For Url From Different Calling Controls

This is because we may want to read the .Text value of a TextBox or a specific cell value from a DataGridView.

void webBrowserContextMenu1_Opening(object sender, CancelEventArgs e)
{




    switch (webBrowserContextMenu1.SourceControl.Name.ToUpper())
    {
        case "DATAGRIDVIEW1" :
            {
                webBrowserContextMenu1.Url = dataGridView1.SelectedCells[0].Value.ToString();
                break;
            }
        case  "TEXTBOX1" :
            {
                webBrowserContextMenu1.Url = textBox1.Text;
                break;
            }
        case "PICTUREBOX1":
            {
                webBrowserContextMenu1.Url = "www.daytonartinstitute.org";
                break;
            }
    }
}

What Are We Switching On?

The code in the switch():

webBrowserContextMenu1.SourceControl

gets the SourceControl which was under the mouse pointer when the Context Menu fired.

The code then simply grabs the name, does a comparison and then runs specific code depending upon which control was firing the ContextMenu. That allows us to get the value for the URL dynamically.

See It In Action

For example, if you download my sample program and run it, you'll see that if choose a cell in the DataGridView and then right-click and select a browser, the browser will load the URL that was in the DataGridView cell. This would load http://oreilly.com.

And this one would load whatever value (codeproject.com) is typed into the TextBox:

I Have All 5 Browsers On My Computer: Do You?

Keep in mind that all five browsers show up as a choice on my computer, because I have all 5 of them installed. If you do not, then you will only see menu items for those browsers that you have installed.

That is the beauty of this control. It is dynamic and won't confuse your users, with options they do not have.

One More Thing To Do: Set the Context Menu of Your Calling Control

To make the Context Menu control appear when a user right-clicks a control on your form you simply set the ContextMenu property on your control. To do that:

  1. Click on the control (textbox, datagridview, etc) in Design View.
  2. Go to the Properties dialog and scroll down until you see ContextMenuStrip.
  3. Drop the list, you will see WebBrowserContextMenu1.
  4. Select WebBrowserContextMenu1

In my example, you can see that I have chosen to add the context menu to GroupBox1.

Bad URL, No URL

If the URL is invalid, the browser will attempt to load it and fail.

If the URL is blank the browser will open with its home page (default page).

Points of Interest

I've used this control in a couple of projects. Note that it contains a Browser class which keeps all the browser info separate. This class has further uses as I've extended it to read all the browser history from all browsers for a single repository of history information. I'll be writing more articles on that in the future. There are lots of applications for that.

If you've enjoyed this article and my code, I hope you'll consider reading my upcoming book, The Software Development Map, which will release as a Kindle book on May 31, 2012.

Odd Visual Studio Designer Error

If you see something like the following:

It is simply because you are referencing the control project and the DLL which contains the control is not built yet, but the form requires it to be built to draw the design surface.

Resolution

If that happens just build the entire solution, close the form and open it again and everything will be fine.

*Important Update* (v1.1.0.0) Please Read First

Iteration 2 of Update -- Most Recent

I have finally figured out the problem (which I first mentioned below see Iteration 1 of Update section below) and have updated the code and uploaded the fix. Here's the deal, for some reason when the code tries to find/register the installed browsers it (in some cases) registers the browsers multiple times. That means it adds a new eventhandler for the ChromeMenu_Click multiple times. It does this for various browsers which it believes are installed numerous times.

I've added a simple boolean check to see if ChromeMenuItem is already initialized (not null) and only add the EventHandler if it has not already been added -- if the ChromeMenuItem hasn't already been created.

The new code looks like the following (from WebBrowserContextMenu.cs) but basically I just added the IF statement checking for the null condition. Also, this is the example for the Chrome browser, but this check is now added for each of the web browsers supported (Big 5 - IE, FF, Chrome, Safari, Opera) by this control.

WebBrowserContextMenu Constructor

As I examine this further, I find that the code above is in the InitializeBrowserMenus() method which is only called from the WebBrowserContextMenu Constructor. It is odd that now for some reason this constructor and Initialize method are (in some cases) called twice and this is somehow different on the two OS versions (as mentioned below in Iteration 1 of Update section)

 case Constants.BrowserType.CHROME:
{
   // check to see if the item is visible, which means it is already registered
   // this mitigates the bug where teh system thinks chrome is registered more than once.
      if (ChromeMenuItem == null)
         {
             ChromeMenuItem = (ToolStripMenuItem)tsmi.DropDown.Items[0];
             ChromeMenuItem.Click += new EventHandler(ChromeMenu_Click);
             ChromeMenuItem.Visible = true;
         }
         break;
}   

Iteration 1 of Update

Suddenly, while running another program I've written which implements the browser context menu control in this article, I've found that opening the link via the control actually opens 2 windows in the browser (Chrome - non-default browser for my machine). It is as if the ContextMenu code is firing twice.

My machine is running Windows 7 and it did recently update. I am running an older version of Chrome (Version 26.0.1410.43 m). I have also tested the sample project from this article and it still opens two windows or tabs in Chrome.

I then moved to another machine (Virtual Machine) running Windows Server 2003 R2 (SP2) and running Chrome (Version 28.0.1500.72 m). The sample project running in that environment only opens one tab or window in Chrome.

Something Has Changed In the Way ContextMenu Events Fire

I believe that something has changed in the way the contextmenu events fire. It is as if the OnMenuClick is firing twice. On the same Windows 7 machine where I'm seeing two Chrome windows open, I also have FireFox and it opens two windows also. My default browser on that machine is IE9.x and it only opens one window/tab as expected. What is this craziness?

Default Browser?

I set FireFox to be the default browser and this control still opens two tabs/windows when I attempt to open one.

Visual Studio 2012?

The only other update I've made to the machine is adding Visual Studio 2012? Would that affect the way the contextmenu events fire? Not sure. Please leave a comment if you get the same behavior. Thanks.

Updates

Version 1.1.0.0 : Problem explained - Fixed in Version 1.2.0.0

If you are running the older version of the WebBrowserMenu control (1.1.0.0) you may have encountered a problem with newer versions (21.x and later) of Opera web browser where it fails when you attempt to load the URL.

The reason this occurs is because the path to the opera.exe is incorrect in these newer versions.

When the WebBrowserMenu control class Browsers reads the registry key (uninstall ) which tells us where each browser's exe can be found, it gets the value to the root directory -- which previously worked -- but now Opera Software has added some version directories under the \program files\Opera\ directory. They now place their Opera.exe in those version directories and the old WebBrowserMenu control didn't know about this change.

You can see this in the following image:

Code Change: Very Small

Fixing this only took a very small code change.

First I added a new property to the Browser class

public string DisplayVersion 
        {
            get 
            {
                return displayVersion; 
            }
            set 
            { 
                displayVersion = value; 
            }
        }

That change allows me to now store this new value I need which is found in the registry at (HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\Opera )

I also had to add one line of code to the Browsers class to load the value for each browser object.

I added that one line to the LoadSubKeyInfo() method -- it simply gets the DisplayVersion from the registry and loads it into the new Browser.DisplayVersion property so the value is available.

  public void LoadSubKeyInfo(RegistryKey subkey, string displayName, Constants.BrowserType browserType)
        {
            Browser tempBrowser = new Browser(browserType);
            tempBrowser.Name = displayName;
            tempBrowser.InstallPath = subkey.GetValue("InstallLocation") as string;
            tempBrowser.DisplayVersion = subkey.GetValue("DisplayVersion") as string;
            this.Add(tempBrowser);
        }

After that, we only have to change one method to insure the Opera browser will now load the URL properly.

That method is found in the WebBrowserContextMenu class which is the main class for the custom ContextMenu.

Here's the code change:

 Browser currentBrowser = GetBrowserType(browsers, Constants.BrowserType.OPERA);
      try
       {
        System.Diagnostics.Process.Start(
            Path.Combine(currentBrowser.InstallPath, currentBrowser.ExecutableName),
            url);
       }
       catch
        {
          System.Diagnostics.Process.Start(
          Path.Combine(Path.Combine(currentBrowser.InstallPath, currentBrowser.DisplayVersion), currentBrowser.ExecutableName),
              url);
        }

As you can see, I've simply wrapped the old call to load the Opera.exe in a try...catch. This insures it will still work the old way -- loading from the root installation dir -- but then if the exception is thrown we try the new path

Path.Combine(Path.Combine(currentBrowser.InstallPath, currentBrowser.DisplayVersion)

which I combine with the InstallPath to try to run the Opera.exe from the subdirectory also.

If that fails too, however, it will still fail. But it should work with one of these.

Power of OOP: Keep It In Mind

This is the power of OOP, because I had somewhat of a major change, but was able to deal with it and alter my code without impacting any other code.

Using Version 1.2.0.0 With Older Software: Updating to Use New DLL

You can simply drop the new DLL v1.2.0.0 into the directory with your older software, overwriting the older version (1.1.0.0) and then start your program and it will use the new DLL.

I've done this with my application and it works great. This is very cool.

History

Initial article written on: May 10, 2012

Release Version 1.1.0.0 : July 17, 2013 This fixes the issue where multiple windows may open upon attempting to open the URL in one of the installed browsers. Please see the last section *Important Update* for more details.

Release Version 1.2.0.0: July 22, 2014 This fixes the issue with Opera web browser installing to a subdirectory (named after the displayVersion value). Version 1.1.0.0 would fail when trying to load the URL from the menu when Opera is ver 21.x or later. See Updates section for more information.

License

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

Share

About the Author

newton.saber
Architect
United States United States
My newest book is Learn Python, Think Python (amazon link opens in new window/tab)
 
My previous book is Object-Oriented JavaScript (See it at Amazon.com)
 
My book, Learn JavaScript - amazon.com link is available at Amazon.
 
My upcoming book, Learn AngularJS - Think AngularJS, will be releasing later in 2014.
 
You can learn more about me and my other books, at, NewtonSaber.com
Follow on   Twitter

Comments and Discussions

 
NewsSome ideas on the implementation [modified] PinprofessionalBrisingr Aerowing31-Aug-14 10:39 
GeneralRe: Some ideas on the implementation Pinmembernewton.saber31-Aug-14 12:01 
GeneralMy vote of 5 PinprofessionalS.P.Tiwari24-Jan-14 5:18 
GeneralRe: My vote of 5 Pinmembernewton.saber24-Jan-14 7:36 
GeneralMy vote of 5 PinmemberBillWoodruff20-Aug-13 19:52 
GeneralRe: My vote of 5 Pinmembernewton.saber21-Aug-13 2:14 
GeneralMy vote of 5 Pinmemberfredatcodeproject22-Jul-13 13:33 
GeneralRe: My vote of 5 Pinmembernewton.saber23-Jul-13 3:39 
QuestionMy vote of 5 PinmemberZac Greve8-Jun-12 13:00 
AnswerRe: My vote of 5 Pinmembernewton.saber11-Jun-12 3:42 
GeneralMy vote of 5 Pinmembernewton.saber16-May-12 17:14 
QuestionHow are browsers detected? PinmemberThe JZ16-May-12 1:26 
AnswerRe: How are browsers detected? Pinmembernewton.saber16-May-12 2:26 
GeneralRe: How are browsers detected? PinmemberThe JZ16-May-12 2:52 

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

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

| Advertise | Privacy | Mobile
Web04 | 2.8.141015.1 | Last Updated 22 Jul 2014
Article Copyright 2014 by newton.saber
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid