URLKicker: Clipboard Search / Url Wrap
Notification Area / Note Tray App
[Redux]
by Peter A. Bromberg, Ph.D.

Peter Bromberg

"If the goal of security is to protect against yesterday's attacks, we're really good at it." -- Bruce Schneier

NB: This utility was picked up by Scott Hanselman and is now featured (along with many other fine "tools") on his ".NET Power User Tool List " page. Since that time, we have added a new "Eggheadcafe.com CodeSnippets feature that lets valid Eggheadcafe.com members actually post code snippets with a Title, description, and code sample block to our "Tips And Tricks" section of the site. If you would like to participate in this new program, and make a contribution to the eggheadcafe.com community, you can download this special edition MSI installer here. The app will check for updates automatically, and if there is an update, you'll receive a popup with the opportunity to get the latest version. Running this MSI should remove the previous version, and install the new one automatically. For details on the original product, read on!

Often when we get frustrated enough, it leads to innovation and discovery. (Of course, some people just like to be frustrated, I know some of them. If you are in that camp, please seek help. Others, read on!).

Recently, I got frustrated enough about having desktop shortcuts to Url's that I often need which would hog the MSN WebMessenger IE window that was already open (or some other similar window). So I thought I'd write a little utility to be able to copy a url to the clipboard and have it use Process.Start to open it in a new IE process. What happened next is that I discovered other useful ingredients that could be added, and so UrlKicker was born.



UrlKicker is a little executable that will sit in the Notification Area. If you mouse over it, it will only show the Date and time. However if you right - click it to get the Context Menu, if offers some really useful choices (That little green arrow in the Notification Area is the UrlKicker icon):

 

If you have an HTTP or FTP URL you have copied to the Clipboard, even if it is a "wrapped" URL that has line breaks in it, you can choose any of the above options and UrlKicker will open IE in a new process and take you there. However, if you have copied text to the clipboard (a search phrase) that does not contain "http://" or "ftp://", you can choose Dictionary, Google, Google Groups, Google News, MSN Search, or VS.NET 2005 and UrlKicker will take you to your choice with an appropriately constructed search query. Neat! You can also clear the clipboard by choosing "Clear Clipboard" and of course, you can ask UrlKicker to go away by choosing "Exit".

I hasten to add that most of this code is not very innovative on my part - you can find sample snippets around that do various portions of what I have here in a number of places and by other authors. What's unique here is the combination of useful ingredients I've put together. Here' the source code, and you can download the VS.NET 2003 solution at the bottom of this article. If you just want to use the product, the /Release folder of the solution has a fully built executable. Simply copy it to the folder of your choice and add a shortcut to the Desktop or even the StartUp Program Files folder if you like, and you are "good to go". There isn't much to explain here; if you are interested in how it works, just run it in Debug mode and step through the code. Enjoy!

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using Microsoft.Win32;

namespace UrlKicker
{
 public class HostForm : System.Windows.Forms.Form
 {
  private System.ComponentModel.Container components = null;
  static private System.Windows.Forms.NotifyIcon notify = new NotifyIcon();
  static private System.Windows.Forms.ContextMenu CtxMenu;

  public HostForm()
  {   
   InitializeComponent();   
  }  
  protected override void Dispose( bool disposing )
  {
   if( disposing )
   {
    if (components != null) 
    {
     components.Dispose();
    }
   }
   base.Dispose( disposing );
  }

  #region Windows Form Designer generated code  
  private void InitializeComponent()
  {
   System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(HostForm));
   this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
   this.ClientSize = new System.Drawing.Size(232, 22);
   this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
   this.Name = "HostForm";
   this.Text = "UrlKicker";

  }
  #endregion

  [STAThread]
  static void Main() 
  {  
   System.Reflection.Assembly assy = System.Reflection.Assembly.GetExecutingAssembly();
   System.IO.Stream ResStream = assy.GetManifestResourceStream("UrlKicker.Tray.ico");
   notify.Icon = new System.Drawing.Icon(ResStream);
   notify.Visible = true;
   notify.Text =  DateTime.Now.ToString();    
   notify.ContextMenu = CreateMenu();
   notify.MouseMove+=new MouseEventHandler(notify_MouseMove);
   Application.Run();
  }

private static System.Windows.Forms.ContextMenu CreateMenu()
{
 CtxMenu = new System.Windows.Forms.ContextMenu();
 System.Windows.Forms.MenuItem m;

 RegistryKey key = Registry.CurrentUser.OpenSubKey("Software\\PAB\\UrlKicker" );
 if (key != null)
 {
  string[] keys = key.GetSubKeyNames();
  foreach (string s in keys) 
  {   
   m = new MenuItem(s,new System.EventHandler(Kick));
   CtxMenu.MenuItems.Add(m);
   
  }
  
 }
 else
 {  
  key = Registry.CurrentUser.CreateSubKey("Software\\PAB\\UrlKicker\\Google");
  key.SetValue("uri","http://www.google.com/search?q=");

  key = Registry.CurrentUser.CreateSubKey("Software\\PAB\\UrlKicker\\Dictionary");
  key.SetValue("uri","http://www.dictionary.com/search?q=");

  key = Registry.CurrentUser.CreateSubKey("Software\\PAB\\UrlKicker\\GoogleNews");
  key.SetValue("uri","http://news.google.com/news?q=");
  

  key = Registry.CurrentUser.CreateSubKey("Software\\PAB\\UrlKicker\\GoogleGroups");
  key.SetValue("uri","http://groups-beta.google.com/groups?q=");


  key = Registry.CurrentUser.CreateSubKey("Software\\PAB\\UrlKicker\\MSNSearch");
  key.SetValue("uri","http://search.msn.com/results.aspx?q="); 

  key = Registry.CurrentUser.CreateSubKey("Software\\PAB\\UrlKicker\\VS.Net2005");
  key.SetValue("uri","http://lab.msdn.microsoft.com/searchbeta/Default.aspx?Query=");

  return CreateMenu();
 }
 m = new MenuItem("Exit",new System.EventHandler(ExitApp));
 CtxMenu.MenuItems.Add(m);
 m = new MenuItem("Clear Clipboard",new System.EventHandler(Clear));
 CtxMenu.MenuItems.Add(m);
 return CtxMenu;
}

  private static void Clear(object sender, System.EventArgs e)
  {
   Clipboard.SetDataObject(String.Empty);
  }

private static void Kick(object sender, System.EventArgs e) 
{
 try 
 {
  string name = ((MenuItem)sender).Text;
  string s = (string)Clipboard.GetDataObject().GetData("System.String",true);
 
  if(s==null || s==String.Empty) 
  {
   MessageBox.Show("Nothing in ClipBoard.");
   return;
  }
 
  
  s=s.Replace("\n",""); 
  RegistryKey key = Registry.CurrentUser.OpenSubKey("Software\\PAB\\UrlKicker\\" + name );
  if(s.ToLower().IndexOf("http://")==-1 && s.ToLower().IndexOf("ftp://")==-1)
  s = key.GetValue("uri") + s;  
  System.Diagnostics.Process p = new System.Diagnostics.Process();
  p.StartInfo.FileName = "iexplore.exe";
  p.StartInfo.Arguments = s;
  p.StartInfo.UseShellExecute = true;
  p.Start();
 }
 catch (Exception err)
 {
  MessageBox.Show(err.Message,"Error");
 }
}
  private static void notify_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
  {

   try
   {
    if((string)Clipboard.GetDataObject().GetData("System.String",true)==String.Empty)
    notify.Text=System.DateTime.Now.ToString();
    else
    notify.Text=(string)Clipboard.GetDataObject().GetData("System.String",true);
   }
   catch(Exception ex)
   {
    System.Diagnostics.Debug.WriteLine(ex.Message +ex.StackTrace);
   }
  }
  
private static void ExitApp(object sender, EventArgs e) 
{
 Application.Exit();   
}
}
}

Since I published the original article above in April 2005, I decided to get a little more innovative and I added a "Notes" facility and update the URLs in the choices (MSDN Beta search had changed). Now you have a "Notes" choice which will pop up a "Notes" form like this:

This stores the Notes in a DataSet that is loaded and saved via the ReadXml and WriteXml intrinsic DataSet class methods to the same folder where the UrlKicker executable is installed. You can edit the DataGrid by simply clicking and typing, and you can search in your notes on the Subject and Note fields by entering any string of text and hit "Search". When you click the "Save /Exit" button, the DataSet is saved; if you click the red X, changes are not saved. I have found this is a very convenient way to keep "TO DO's" nicely organized in a single place, and if I need to transport my "TO DO LIST" to another PC, all I need to do is email or FTP the NotesData.xml serialized DataSet Xml File to myself. In the downloadable Solution all the enhancements are included in the source code, and there is a built MSI Installer if you only want the free product to use.

Download the VS.NET 2003 Solution that accompanies this article


Peter Bromberg is a C# MVP, MCP, and .NET consultant who has worked in the banking and financial industry for 20 years. He has architected and developed web - based corporate distributed application solutions since 1995, and focuses exclusively on the .NET Platform.
Article Discussion: