Developing for the Windows 7 Taskbar – Jump into Jump Lists – Part 2

This is the second post about the Taskbar Jump List in a series of Windows 7 Taskbar posts. In the previous post, Developing for the Windows 7 Taskbar – Jump into Jump Lists – Part 1, we introduced the elements that comprise the Taskbar Jump Lists: the destination (also referred to as “nouns”) and the Tasks (also referred to as “verbs”). As developer, you have a large amount of control over these elements. In this post, we walk through the different APIs that you can use when programming the Taskbar Jump Lists.

Before we begin, there is one very important thing you need to know. “Items” in the Recent category, or in any other category (any destination), must have a registered file handler for your application in the registry. This doesn’t mean that your application must be the default handler for that specific file type, it just means that your application must have a registered handler for all the files that you want to be visible in the Jump List. Therefore, “items” can only be files. Remember, by clicking on one of the items in the Jump List, the OS executes the command associated with that file as it relates to your application. When you register a file handler, you also specify the application that handles this file, and you define how to pass the input parameter for the application. Another important note to remember: All the items (files) have to be local – that is, on the local hard drive, and accessible to your application. Therefore, we can say that each and every item among the Jump List destinations is an accessible, local file, with a file handler registered to your application.

As we explain in the following section, once you have registered your file handlers, the OS actually helps you keep track of all your files. We will cover file handler registration in the next post.

Step 1 – Use the Out-of-the-Box Windows Experience and Default Behavior

By default, a Jump List contains a Recent category that is populated automatically for file-based applications through the SHAddToRecentDocs function. This function adds the used “item” (file) to the Shell's list of recently used documents. In addition to updating its list of recent documents, the Shell adds a shortcut to the user's Recent directory. The Windows 7 Taskbar uses that list and the Recent directory to populate the list of recent items in the Jump Lists.

Windows can also do the work for you if your application's file type is registered. Anytime you double click on a file type with a registered handler, before Windows launches your application it automatically calls SHAddToRecentDocs on your application's behalf. This inserts the item in the Windows Recent list and eventually into the Jump List Recent Category. The same automatic behavior occurs when using the Windows Common File Dialog (CFD) to open files through our applications. Therefore, this is another good reason to use the CFD introduced in the Windows Vista timeframe, and it also plays a vital role regarding libraries, as we explained in the Light Up with Windows 7 Libraries post.

Both of the above cases exploit default Windows behavior in cases where you have a registered handler and an Application ID by which the files are associated with Recent and Frequent lists. In both cases, Windows automatically inserts the items into the Jump Lists unless you specifically remove this functionality by using the COM API. Obviously, users also have the option to remove any items from their Jump Lists. By explicitly removing an item from the Jump List, you insert it into the Removed Items List, which we will discuss below.

Step 2 – Create Your Own Category

If the default Recent or Frequent categories do not meet your application's needs, it is time to create your own custom category. In order to do so, you need to use the ICustomDestinationList interface to create a custom Destination List.

The ICustomDestinationList exposes methods that allow an application to provide a custom Jump List, including destinations and tasks, for display in the Taskbar. Here are the methods that we are using for the example below:

  • AppendCategory Defines a custom category and the destinations that it contains for inclusion in a custom Jump List
  • AppendKnownCategory Specifies that the Frequent or Recent category should be included in the Jump List
  • BeginList Initiates a building session for a custom Jump List
  • CommitList Declares that the Jump List initiated by a call to BeginList is complete and ready for display

The following code snippet shows how to create a new custom list called “Custom Lists” and appends a few items to it:

void CreateJumpList()
{
ICustomDestinationList *pcdl;
HRESULT hr = CoCreateInstance(
CLSID_DestinationList,
NULL,
CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(&pcdl));
if (SUCCEEDED(hr))
{
//important to setup App Id for the Jump List
hr = pcdl->SetAppID(c_szAppID);
if (SUCCEEDED(hr))
{
UINT uMaxSlots;
IObjectArray *poaRemoved;
hr = pcdl->BeginList(
&uMaxSlots,
IID_PPV_ARGS(&poaRemoved));
if (SUCCEEDED(hr))
{
hr = _AddCategoryToList(pcdl, poaRemoved);
if (SUCCEEDED(hr))
{
pcdl->CommitList();
}
poaRemoved->Release();
}
}
}
}

Here you see that we started with a standard COM initialization call. We call CoCreateInstance to initialize the ICustomDestinationList object (this is the joy of working with COM….). Next, we set the Application ID in order to allow you to start populating items to the list.

The BeginList function initiated the build session for the custom Jump List. This function returns the maximum number of items that can fit in a given Jump List; the default is 10. You may note the Remove item parameter, IObjectArray *poaRemoved, that the BeginList() returned as an out parameter. This holds any specific items that the user removed from the Jump List in his current session. We discuss the Removed Items List later in this post.

Next we called a helper function, _AddCategoryToList(), to do the actual work of adding items into the custom category.

// This is the helper function that actually appends the items to a collection 
// object HRESULT _AddCategoryToList(ICustomDestinationList *pcdl,
// IObjectArray *poaRemoved)
{
IObjectCollection *poc;
HRESULT hr = CoCreateInstance
(CLSID_EnumerableObjectCollection,
NULL,
CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(&poc));
if (SUCCEEDED(hr))
{
for (UINT i = 0; i < ARRAYSIZE(c_rgpszFiles); i++)
{
IShellItem *psi;
if (SUCCEEDED(SHCreateItemInKnownFolder(
FOLDERID_Documents,
KF_FLAG_DEFAULT,
c_rgpszFiles[i],
IID_PPV_ARGS(&psi)))
)
{
if(!_IsItemInArray(psi, poaRemoved))
{
poc->AddObject(psi);
}

psi->Release();
}
}

IObjectArray *poa;
hr = poc->QueryInterface(IID_PPV_ARGS(&poa));
if (SUCCEEDED(hr))
{
pcdl->AppendCategory(L"Custom category", poa);
poa->Release();
}
poc->Release();
}
return hr;
}

Another new interface that we use is the IObjectCollection that represents a collection of objects that support IUnknown. To this collection we add IShellItems. Each item (file) that we added to the Jump List is of an IShellItem type. In the above code, we created a Shell item object for a single file that exists inside a known folder, Documents. However, before we actually added the new item to the collection, we needed to determine if the user had already removed it. If the user explicitly removed an item from the Jump List, that item will be in the Removed Items List (again associated with the AppID), and, as developers, we need to respect the user's requests and avoid adding that item to the Jump List. We already have the list of removed items, IObjectArray *poaRemoved, that we got when we called the BeginList(…) function when we initiated creation of a new list.

At this stage, you have a collection of Shell items that the user expects to see in the Jump List. Next we added that collection to the ICustomDestinationList object and created a new category named “Custom category”, pcdl->AppendCategory (L"Custom category", poa);.

So now you have successfully created a new category in the Taskbar called “Custom category” and populated it with four items. However, our work is not done yet. The final step in the CreateJumpList function is to call CommitList() to end the “transaction” that began with calling BeginList(). Only after our call to CommitList() are the new category and new items displayed. Calling CommitList() causes the stored list of removed items to be cleared and a new Removed Items List to begin. The ICustomDestinationList interface provides a "transactional base" API.

In order to ensure a positive end user experience, make sure that a safe copy of the new repopulated list is complete and ready for use, and that the only operation the Taskbar must perform is to switch the pointer to the new list. The end result looks like:

image

Using the Windows API Code Pack we can write the same application using managed code.

Once we are sure that we are using the same AppID with all the Taskbar elements, we can create an instance of the Taskbar Jump List for the button that we are working on, as shown in the following code snippet. This code snippet is part of the CTOR of the main application window:

// Set the application specific id
Taskbar.AppId = appId;
// Retrieve the taskbar jump list
jumpList = Taskbar.JumpList;
category1 = new CustomCategory("Custom Category 1");
category2 = new CustomCategory("Custom Category 2");
// Add custom categories
jumpList.CustomCategories.Add(category1);
jumpList.CustomCategories.Add(category2);
// Default values for jump lists
comboBoxKnownCategoryType.SelectedItem = "Recent";

Here you can see that we set the AppID using the AppId property and created an instance of the Taskbar Jump List using the Taskbar.JumpList static property. We also create two categories, named Custom Category 1 and Custom Category 2. Next, we add these categories to the Jump List custom categories container. Last we set the Known category of this Taskbar Jump List to Recent. This will automatically get populated as described above.

After we set up the custom category, it is time to put some content in it. To do so, we just need to call the Add function to add a JumpListItem to the JumpListCollection. The JumpListItemCollection is a generic collection (of<IJumpListItem>) holding IJumpListItem items. IJumpListItem item is basically some sort of wrapper for the native IShellItem.

// Specify path for shell item
string path = String.Format("{0}\\test{1}.txt",
executableFolder,
category1.JumpListItems.Count);
// Add shell item to custom category
category1.JumpListItems.Add(new JumpListItem(path));
First, we need to construct a path to the file we want to include in the Jump List. Please remember that we can call the Add function only if this file is local and accessible to your user. The above code (along with a few other methods that we will describe in future posts), results in a Taskbar dialog that looks like:
image
Finally, we need to call the Taskbar.JumpList.RefreshTaskbarList() Function. As with the native Jump List implementation, we need to “commit” the changes made to the Jump List. A closer look at this Refresh function (you have access to it in the Code Pack API) shows a call to the AppendCustomCategories function that appends any custom categories to the Taskbar button Jump List. Within this function, you can find a managed code implementation of the native code shown above. It includes a call to the AppendCateogry function that is a wrapper for the native AppendCategory function above.
 
IObjectCollection categoryContent =
(IObjectCollection)new CEnumerableObjectCollection();

// Add each link's shell representation to the object array
foreach (IJumpListItem link in category.JumpListItems)
categoryContent.AddObject(link.GetShellRepresentation());

// Add current category to destination list
HRESULT hr = customDestinationList.AppendCategory(
category.Name,
(IObjectArray)categoryContent);
 

As you can see, it is easy to opt into the Windows 7 Taskbar functionality. Windows automatically performs most of the work for you and, if you do need to create your own category, that is also very easy.

In the next post we will describe how you can add new Tasks to the Jump List and how to register a file handler.


Comments

  1. Posted on: June 27, 2009 at 1:24AM  

    Wish Windows Search/Start menu search could find results from jump lists. Like how we can search menu commands in Mac OS X or Search Commands addin for Office 2007.

Trackbacks

  1. Posted by: Developing Windows 7 Taskbar Jump Lists – Part 2 on June 26, 2009 at 5:37AM

    Pingback from  Developing Windows 7 Taskbar Jump Lists – Part 2

  2. Posted by: Developing for the Windows 7 Taskbar ??? Jump into Jump Lists ??? Part 2|Join Our Story!|AngNetwork Blog on June 26, 2009 at 6:11AM

    Pingback from  Developing for the Windows 7 Taskbar ??? Jump into Jump Lists ??? Part 2|Join Our Story!|AngNetwork Blog

  3. Posted by: Dew Drop – June 26, 2009 | Alvin Ashcraft's Morning Dew on June 26, 2009 at 8:41AM

    Pingback from  Dew Drop – June 26, 2009 | Alvin Ashcraft's Morning Dew

  4. Posted by: Developing for the Windows 7 Taskbar ??? Jump into Jump Lists ??? Part … | networking-the.info on June 26, 2009 at 10:29AM

    Pingback from  Developing for the Windows 7 Taskbar ??? Jump into Jump Lists ??? Part … | networking-the.info

  5. Posted by: Developing for the Windows 7 Taskbar ??? Jump into Jump Lists ??? Part … on June 26, 2009 at 10:41AM

    Pingback from  Developing for the Windows 7 Taskbar ??? Jump into Jump Lists ??? Part …

  6. Posted by: Windows 7 for Developers on July 02, 2009 at 3:59PM

    So far, you have seen how you can opt into the Windows 7 Taskbar Jump List experience by creating a Jump

  7. Posted by: Developing for the Windows 7 Taskbar ??? Jump into Jump Lists ??? Part 3 | Windows Seven 7 on July 02, 2009 at 4:29PM

    Pingback from  Developing for the Windows 7 Taskbar ??? Jump into Jump Lists ??? Part 3 | Windows Seven 7

  8. Posted by: Developing for the Windows 7 Taskbar ??? Jump into Jump Lists ??? Part 3 | Windows Seven 7 on July 02, 2009 at 4:30PM

    Pingback from  Developing for the Windows 7 Taskbar ??? Jump into Jump Lists ??? Part 3 | Windows Seven 7

  9. Posted by: Developing for the Windows 7 Taskbar ??? Jump into Jump Lists ??? Part 3 | Windows 7 Information, News, Downloads, Support Forums on July 03, 2009 at 3:44AM

    Pingback from  Developing for the Windows 7 Taskbar ??? Jump into Jump Lists ??? Part 3 | Windows 7 Information, News, Downloads, Support Forums

  10. Posted by: Developing for the Windows 7 Taskbar – Jump into Jump Lists – Part 3 | Futurecat - Michael Karek on July 10, 2009 at 2:25AM

    Pingback from  Developing for the Windows 7 Taskbar – Jump into Jump Lists – Part 3 | Futurecat - Michael Karek

  11. Posted by: Windows 7 for Developers on July 28, 2009 at 12:31PM

    We covered the basics of the Windows 7 Taskbar in Developing for the Windows 7 Taskbar – Application

  12. Posted by: Windows 7 Taskbar Dynamic Overlay Icons and Progress Bars | Windows Seven 7 on July 28, 2009 at 1:33PM

    Pingback from  Windows 7 Taskbar Dynamic Overlay Icons and Progress Bars | Windows Seven 7

  13. Posted by: Windows 7 for Developers on December 04, 2009 at 1:45PM

    It is time to return to our usual routine of describing Windows 7 APIs. We already covered the basics

  14. Posted by: Developing for Windows 7 Taskbar – Thumbnail Toolbars | Windows Seven 7 on December 04, 2009 at 2:37PM

    Pingback from  Developing for Windows 7 Taskbar – Thumbnail Toolbars | Windows Seven 7

  15. Posted by: Goldendevelopersworld.com » Blog Archive » Developing for Windows 7 Taskbar – Thumbnail Toolbars on December 04, 2009 at 6:15PM

    Pingback from  Goldendevelopersworld.com  » Blog Archive   » Developing for Windows 7 Taskbar – Thumbnail Toolbars