qt8gt0bxhw|20009F4EEE83|RyanMain|subtext_Content|Text|0xfbffc90000000000cb00000001000200
Often in applications you have the need to launch a browser window to open a specified URL. I recently evaluated various RSS readers where links to blog posts could be launched in an external browser window. What I found was that most of these applications would simply shell out the URL to launch and let Windows open it in the default application for http. The problem is that shelling the URL will pass it off to the default application, but not necessarily the a new instance of the default application. If there is an already running instance, then shelling the URL will simply cause the URL to be opened in that instance. Well, I hate that. I'll refer to that as hijacking my browser - even though that is a term that is more typically used for malicious spyware and nasty browser helper objects. So, repeat after me, “I will no longer hijack my users open brower windows from my applications“. But how do you go about that? Well, let's break it down and start by looking at the most common way to shell a URL from a .NET windows application and work our way up to making a generic way to launch a URL that will open in a new window every time.
Why not just change the setting in IE to not reuse windows? Telling the users of your application to make that change is just silly in my opinion. I wouldn't want to change that setting and have it effect every application just to get a single application to work the way it should. There are times when browser reuse makes sense - but there are also times when it does not. Besides, that applies to IE only, other browsers might not have that option.
Using the static Process.Start
When you typically see .NET code in a windows application that needs to launch a URL, you'll see the use of the static Start method of the Process class (found in the System.Diagnostics namespace). Something like this:
Process.Start("http://www.ryanfarley.com/");
There is nothing wrong with that. It will shell the URL out to the application configured as the default handler for http. However, shelling the URL like this does not cause a new instance to be started. If there are no currently running instances then of course one will be started, but in the case where you do have other browser windows running, the last opened window will be used to open the URL. That's no good, but this problem is not anything specific to Process.Start, you'd get the same results using the ShellExecute Win32API.
Shelling a new browser window
Something that you can do to force a new instance of the browser to be opened for the launched URL, is to shell an instance of the browser itself, instead of the URL, and pass the URL on the command-line to the browser. Any (good) browser I've ever used allows you to pass a URL on the command-line to it. When you shell the browser application and pass the URL on the command-line, a new browser window will be opened because it is the browser you are shelling. Here's an example that will launch a new instance of Internet Explorer and pass the URL to open on the command-line.
Process p = new Process();
p.StartInfo.FileName = "iexplore.exe";
p.StartInfo.Arguments = "http://www.ryanfarley.com/";
p.Start();
That will accomplish what we are after, but the big problem here is that now we have made it specific to Internet Explorer only. Your FireFox/Opera/whatever users (although their numbers may be small) won't be too happy about that. You'll often see code that uses COM interop to create an instance of InternetExplorer.Application or even worse, code to use SHDocVw as an embedded browser control (Ugh!). Neither of these are good since they both are specific to IE. What we need to do is something like the code above, but to first determine which application is the default application to handle http and use that instead of hard-coding “iexplore.exe”.
Determining the default browser
If we look in the registry we can easily determine which application is configured as the default browser. We'll need to find the application that will respond to a shell “open“ command for http. We can find that under HKEY_CLASSES_ROOT and look for the default value under the key HTTP\shell\open\command.
Make sure you check for the default application for http, not htm or html files or you might get an HTML editor instead of a browser.
When we look at that value, it might have other things in the string, not just the path & exe for the browser. For example, IE will have a value of something like "C:\Program Files\Internet Explorer\iexplore.exe" -nohome, FireFox will have a value like C:\PROGRA~1\MOZILL~1\FIREFOX.EXE -url "%1", etc. If we just trim it down to the path & exe only and pass the URL to that on the command-line then we'll be good in most cases. Something like this: (of course there are more efficient ways to get at just the full exe path from the string, but I'll just get rid of the quotes around it and trim off everything after the “.exe“ part, which is fine for this example)
private string getDefaultBrowser()
{
string browser = string.Empty;
RegistryKey key = null;
try
{
key = Registry.ClassesRoot.OpenSubKey(@"HTTP\shell\open\command", false);
//trim off quotes
browser = key.GetValue(null).ToString().ToLower().Replace("\"", "");
if (!browser.EndsWith("exe"))
{
//get rid of everything after the ".exe"
browser = browser.Substring(0, browser.LastIndexOf(".exe")+4);
}
}
finally
{
if (key != null) key.Close();
}
return browser;
}
That will return to us the full path to the default browser's executable. Now we can use that in the code we used earlier to launch the process (to shell the URL):
Process p = new Process();
p.StartInfo.FileName = getDefaultBrowser();
p.StartInfo.Arguments = "http://www.ryanfarley.com/";
p.Start();
That is it. That will work with the more common browsers (it will work with any of them that I've used). Now whether you think it is a good idea or not to shell all URLs in a new window, why make that decision for your users? Outlook 2003 launches all links in a new window, as do many other quality apps. At least give the user the option. In the RSS readers I evaluated I found that most of them would hijack my browser when launching external links. Another good thing about RSSBandit is that it also had the option to browse to a specific exe to launch when it would shell an external link. I could use that to browse to IEXPLORE.EXE to produce the same effect as described here - although it is always nice to see an option to let me choose if I want to always force the link to launch in a new window or not. Launching the URL on the command line to the browser will guarantee you happier users since they will no longer need to navigate back to pages that were open prior your launching a URL.