Introduction
You would think that launching the user's preferred internet browser from a desktop application would be easy, given how tightly many apps integrate internet technology. Alas, that is not the situation.
I went searching for how to do this, and found a lot of complex, occasionally contradictory instructions. Then I learned that Microsoft recently restructured the Registry to make this a bit easier to manage.
I am not sure if these changes were made in the newer browsers, or just in the Vista Operating System. I can tell you that the code I've given works on Vista with both IE 7 and Firefox 3.0.1. If you have different configurations, I hope you will post a response and let the CodeProject community know what does and does not work.
The Theory
The key change in the Registry is the addition of HKEY_CURRENT_USER\Software\Microsoft\Windows\Shell\Associations\UrlAssociations. This key keeps track of what application should be used when a particular protocol is invoked. This is in the Current User hive, so the data will reflect the preferences of whoever is logged in. On my machine, it has ftp, http, https, and mms as subkeys. Each of these has a subkey, UserChoice, which in turn has a value called Progid. This program ID maps to an entry under HKEY_CLASSES_ROOT, which is where to find the browser's command line. Pass that to System.Diagnostics.Process.Start
with a starting URL (if any) to launch the browser.
The Code
Once you have the theory, coding is pretty straightforward. Here is what I did:
Imports Microsoft.Win32
Imports System.ComponentModel
Imports System.Text
Private Sub LaunchDefaultBrowser(Optional ByVal URL As String = "")
Dim RegPath As New StringBuilder("Software\Microsoft\" & _
"Windows\Shell\Associations\UrlAssociations\ ")
Dim ThisUrl As String = URL.Trim
Dim Protocol As String = "http"
Dim Browser As String = "IE.HTTP"
Dim AppPath As String = ""
Dim Splitters As String() = {""""c}
If ThisUrl <> String.Empty Then
Dim i As Integer = ThisUrl.IndexOf(":")
If i = -1 Then
ThisUrl= String.Format("{0}://{1}", Protocol, ThisUrl)
Else
Protocol = ThisUrl.Substring(0, i).ToLower
End If
End If
Select Case Protocol
Case "http", "https"
RegPath.AppendFormat("{0}\UserChoice", Protocol)
Case Else
MsgBox(String.Format("Unsupported protocol: {0}.", Protocol), _
MsgBoxStyle.Exclamation)
Exit Sub
End Select
Dim RegKey As RegistryKey = Registry.CurrentUser.OpenSubKey(RegPath.ToString)
If RegKey IsNot Nothing Then
Browser = RegKey.GetValue("ProgId", "IE.HTTP").ToString
RegKey.Close()
End If
RegKey = Registry.ClassesRoot.OpenSubKey(String.Format("{0}\Shell\Open\Command", Browser))
If RegKey IsNot Nothing Then
AppPath = RegKey.GetValue("").ToString
RegKey.Close()
End If
If AppPath = String.Empty Then
MsgBox("Unable to locate default browser.", MsgBoxStyle.Exclamation)
Exit Sub
End If
Dim s() As String = AppPath.Split(Splitters, StringSplitOptions.RemoveEmptyEntries)
Dim AppToLaunch As String = ""
If s.Length > 0 Then AppToLaunch = s(0)
If AppToLaunch = String.Empty Then
MsgBox("Unable to locate default browser.", MsgBoxStyle.Exclamation)
Else
System.Diagnostics.Process.Start(AppToLaunch, ThisUrl)
End If
End Sub
I started by initializing a few variables. If I cannot find a default browser, I will try to use IE. Please note that there is an extra space at the end of the initialization string for RegPath
; this was added to make sure the ending double quote was treated as a delimiter. This space should be removed if you copy and paste the code.
Next, I retrieve the protocol found in the URL, if one is given. This is for security reasons: I do not want my users trying to open a mailto or file link. If there is a supplied URL and it does not have a protocol, assume http. Once I have that, I can check that the protocol is the one that I am supporting.
Now I can use the protocol to check for a key in UrlAssociations
. If it exists, make a note; otherwise, use my default.
Then it is over to the Class Root hive. The value I just found should map to a class name here; the command I want is the default value for the subkey \Shell\Open\Command. If you are not familiar with how to read the Registry in .NET, please note that the default value is gotten by passing an empty string into the GetValue
method. I put this value into AppPath
.
Command strings stored in the Registry usually have the main command line within double quotes, followed by any parameter which may or may not have quotes. By way of example, my Firefox command looks like this:
"C:\Program Files\Mozilla Firefox\firefox.exe" -requestPending -osint -url "%1"
There are any number of ways to parse this out; I chose to split the string using double quotes as delimiters, and discarding any blank fields. The command line will then be the first entry in the resulting string array.
Assuming I have a value at this point, I can launch it. If ThisUrl
is an empty string, the browser will launch itself and show its default starting page; otherwise, it will launch and show the supplied web link.
And there you go!
The Demo App
The demo app is pretty basic. It has a single form with a label, textbox, and button. Clicking the button will pass the text in the textbox into the method given above.
Does this Work for You?
My options for testing are a bit limited, and I am not sure where Microsoft made these changes (Browsers? OS?) I hope that CodeProject members could help me compile a list of browsers and Operating Systems that do or do not work using this code.