Can Of Code

How to add JumpLists to a C# Application

Yesterday I thought that I would have a go at adding “JumpLists” to a C# WPF application. I thought it should be simple, perhaps all I would need to do is drag a component into the Visual Studio Designer and then it would be done. Well I was wrong…

JumpLists were introduced in Windows 7 and is a menu that appears when you right click the application icon in the taskbar.

a JumpList in action.

a JumpList in action.

The way I use the JumpList in this tutorial is a simplified approach to the Single Instance taskbar tutorial. To add this functionality there are two real steps:

  • Adding the JumpList (easy bit)
  • Getting it to do something when the user clicks an item (hard bit)

Before we start

The JumpList functionality is not included in the .NET framework. So the first step we need to take is to download the Windows API code pack.

Once you have downloaded the API you need to add a reference to the Microsoft.WindowsAPICodePack.shell.dll that comes in the API.

We should also add a using to the top of our code:

using Microsoft.WindowsAPICodePack.Taskbar;

Adding the JumpList

The first issue you will be faced with is where to put the code, the code wont work in the forms constructor so to overcome I have put the code in a form event called Form.Shown.

      private void Form1_Shown(Object sender, EventArgs e)
        {
            // get where the app is running from
            string cmdPath = Assembly.GetEntryAssembly().Location;

            // create a jump list
            JumpList jumpList = JumpList.CreateJumpList();

            JumpListCustomCategory category = new JumpListCustomCategory("Food");
            category.AddJumpListItems(
                new JumpListLink(cmdPath, "Crabs") { Arguments = "Crabs" },
                new JumpListLink(cmdPath, "Prawns") { Arguments = "Prawns" },
                new JumpListLink(cmdPath, "Shrimps") { Arguments = "Shrimps" });
            jumpList.AddCustomCategories(category);

            jumpList.Refresh();
        }

I don’t check that the user is running Windows 7 which will cause an Exception with non Windows 7 users so its worth adding a check before running this code.

A JumpList contains JumpListLinks. These links consists of a path and arguments that when the JumpListLink is clicked it runs the path with the arguments via a command.

So in the code above, all you need to is change the “crabs”, “prawns” etc to names that are more relevant to your application. Don’t forget to also add the event to the form using the Properties Window in Visual Studio.

If you run your project now you will notice that your JumpList appears but when you click one of your JumpList items it opens a new instance of your application.

Getting the JumpList Items to change your application

So how do we get round the issue of a new instance being opened when the JumpList item is clicked?  The tutorial I mentioned before has a rather complex solution. The key problem is that we need the new instance to talk to the running one and tell it that the user has clicked the JumpList item.

The solution I found easiest was to use the SendMessage API.

The first thing we need to do is when the application is first open we need to read the arguments passed to it and look out for the ones we are passing when we set up the JumpList (“crabs”, “prawns”). The  code below can be added to the Program.cs file within the main method. I’ve modified the Main method by adding the argStrings.

try
{
     if (args[0] == "crabs")
     {
          //get this running process
          var proc = Process.GetCurrentProcess();
          //get all other (possible) running instances
          Process[] processes = Process.GetProcessesByName(proc.ProcessName);

          if (processes.Length > 1)
          {
                //iterate through all running target applications      
                foreach (Process p in processes)
                {
                    if (p.Id != proc.Id)
                    {
                          //now send the RF_TESTMESSAGE to the running instance
                          SendMessage(p.MainWindowHandle, RF_TESTMESSAGE, 
                                                   IntPtr.Zero, IntPtr.Zero);
                          Environment.Exit(0);
                    }
                }
           }
      }
}
catch (Exception)
{

}

much of that code is borrowed from the tutorial mentioned above. What it does is find all the running instances of the application and then sends a message to each of them. You should also add the following within the Program class block of your Program.cs file.

     
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SendMessage(IntPtr hwnd, uint Msg, 
                                            IntPtr wParam, IntPtr lParam);
private const int RF_TESTMESSAGE = 0xA123;

Now when we click the JumpList item we send a message to the application and then close our second instance. All we have to do next is add some code into our application that will accept the message and then perform an action for us when it gets the message.

so we do that in the following code:

        protected override void WndProc(ref Message message)
        {
            //filter the RF_TESTMESSAGE
            if (message.Msg == RF_TESTMESSAGE)
            {
                MessageBox.Show("hello");
            }
            //be sure to pass along all messages to the base also
            base.WndProc(ref message);
        }

This code will read in all the messages sent to the process and if the message is the one we sent it will show the MessageBox. With this now in place we are finished. Now when you click your JumpList item it will pop up with a message box instead of creating a new instance.

I hope that’s an easier to understand approach to using JumpLists. I would love to hear your comments and feedback.

Comments

  • TonyIsBack says:

    Thx for this superb code.

    If you want your application to display multiple MessageBoxes without closing the previous, you have to use Tasks:

    protected override void WndProc(ref Message message)
    {
    //filter the RF_TESTMESSAGE
    if (message.Msg == RF_TESTMESSAGE)
    {
    var task = new Task(() => ShowMessage());
    task.Start();
    }
    //be sure to pass along all messages to the base also
    base.WndProc(ref message);
    }
    private void ShowMessage()
    {
    MessageBox.Show(“crabs”);
    }

  • Jared Yelton says:

    I know this may seem pedantic, but please capitalize “I” when referring to yourself. The article comes across as unprofessional.

    • josh says:

      Thanks for your feedback Jared. Completely agree with you, it was embarrassing for me to re-read. I have gone through it and hopefully improved it.

  • Muhammad Arshad says:

    hi, i use this code in my app but it does not show msg when three options (crabes…) are clicked. It only open new instance when press on my app name in task bar

  • Muhammad Arshad says:

    ok, now jumplist is working but when exe is pinned in taskbar, and does not work when exe is unpinned

Leave a Reply

Your email address will not be published. Required fields are marked *