Windows 7 Taskbar – Part 1, The Basics

This post is one of a series of Windows 7 Taskbar posts and webcasts. You can watch Jump into the Windows 7 Taskbar Jump Lists webcast on Channel 9 for further technical information, or the entire Windows 7 Taskbar webcasts series . You can also download the code sample.

One of the first Windows 7 changes that developers should pay attention to is the new Windows Taskbar. This new feature introduces a functionality that developers need to understand so they can take full advantage of it in their own applications to better enhance their end users’ experiences.

The new Taskbar is the most noticeable change to Windows 7 when you first log on. The Windows 7 Taskbar is an application-launching and window-switching mechanism that consolidates the functionalities from previous Windows Desktop mechanisms such as Quick Launch, Recent Documents, Notification area icons, desktop shortcuts, and running application windows.

If you are unfamiliar with and haven’t seen any demonstrations of the Windows 7 Taskbar, please watch Chitnya’s online Windows 7 Taskbar in Action demo during his Welcome to the New Desktop PDC session. This will give you some context for the technical material we are going to cover here. Additional information about the Windows 7 Taskbar can be found in The Windows 7 Taskbar E7 blog and in Channel 9 Windows Taskbar Webcast series.

In this article, we address Windows 7 Taskbar functionality and provide a high-level overview of its programming model to help developers to better prepare for Windows 7. Obviously, this will not be a comprehensive step-by-step developer guide to the Windows 7 Taskbar, but rather a broad overview. Please look for additional content about the Windows 7 taskbar in future posts.

The Windows 7 Taskbar is designed to provide users with quick and easy access to those “things” they use all the time. “Things” can be any type of content such as pictures, music, word documents or links and shortcuts to applications or folders. By quick and easy access, we mean accessing commonly used programs with a single mouse click or significantly reducing the number of clicks per operation. Quick and easy access also means users should be able to “jump” directly to those things they want to work with and start working with them in a single mouse click. To provide this functionality, Windows 7 Taskbar introduces the concept of “Jump Lists.”

As a developer, think of Jump Lists as your own mini Start Menu for imageyour application. Jump Lists surface commonly used nouns (destinations) and verbs (tasks) of a program, enabling easy user access to destinations by eliminating the need to launch the application and then load the relevant content, or by performing common tasks without launching the application in advance. The following diagram illustrates how Jump Lists work with Microsoft Office Word. You can see that under the “Recent” category, there is a list of recent documents that I’ve used with Office Word. Clicking on one of the items in the “Recent” list will launch Office Word with the relevant document already loaded.

 

 

 

The out-of-the-box experience of the Jump Lists includes only the default Taskbar Tasks. These provide the means to launch a new instance of the application, to pin or unpin an application to the taskbar, and to close the application. You can access the Jump List by right clicking on an application icon in the Taskbar. However, as the following diagram illustrates, you can opt into the Taskbar experience by customizing the context of the Jump Lists for your application.

image

Image from Robert Jarrett’s slide deck from his PDC session

Definitions from the Windows 7 SDK:

”… Destinations are items that appear in the Recent, Frequent or custom categories (the “Important” category in the diagram above), based on the user’s items usage. Destination can be files, folders, Web sites or other content-based items, but are not necessarily file-backed. Destinations can be pinned to or removed from the Jump List by the user. They are generally represented by IShellItem objects, but they can also be IShellLink objects…”

”…Tasks are common actions performed in applications that apply to all users of the application regardless of the individual usage patterns. Task can’t be pinned or removed. Tasks are represented by IShellLInk objects because they are actually links (with parameters – optional) to commands – “Actions”…”

As developers, we can:

  1. Control Application Destinations (that is control the items we want users to be able to “Jump” directly into and start working on)
    • Destinations can be any one of the known categories such as Recent or Frequent.
    • The Custom category is just like any other Destination category, except that it allows developers to create a new name for that category as well as populate it with items.
    • The Pinned category is provided for pinned items that users want to keep permanently in their Jump Lists.

2. Define common user Tasks

    • The Taskbar surfaces its own out-of-the-box tasks such as launching, pinning/unpinning, or closing the application. As developers we have no control over the Taskbar Tasks. However, we do control the User Tasks.
    • User Tasks are common tasks the application developer wants to surface at the Jump List level that will enable users to perform a task directly from the Jump List (e.g. Play all music in media player without switching to media player). Usually, this will result in launching an instance of the application and performing the task. Again, this saves time and reduces the number of clicks needed to achieve the same end goal without the Jump List functionality.

It is time we address the Taskbar programming model. The Taskbar exposes its set of APIs like any other Windows Shell component, through a set of COM interfaces. However, there are a few actions we developers can do even before starting to use the Windows Taskbar COM APIs.

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” (document) 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 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 has a registered handler (this does not have to be the default handler). 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 to open files through our applications.

Both of the above cases exploit default Windows behavior in case you have a registered handler and an Application ID by which the files are assoctiated 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 item 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. 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

Here is a code snippet for a function that creates a new custom list called “Custom Lists” and appends 4 items to it:

    1:  void CreateJumpList()
    2:  {    
    3:      ICustomDestinationList *pcdl;
    4:      HRESULT hr = CoCreateInstance
    5:                     (CLSID_DestinationList, 
    6:                      NULL, CLSCTX_INPROC_SERVER, 
    7:     IID_PPV_ARGS(&pcdl));
    8:   
    9:      if (SUCCEEDED(hr))
   10:      {
   11:          hr = pcdl->SetAppID(c_szAppID);
   12:          if (SUCCEEDED(hr))
   13:          {
   14:              UINT uMaxSlots;
   15:              IObjectArray *poaRemoved;
   16:              hr = pcdl->BeginList
   17:                  (&uMaxSlots, IID_PPV_ARGS(&poaRemoved));
   18:              if (SUCCEEDED(hr))
   19:              {
   20:                  hr = _AddCategoryToList(pcdl, poaRemoved);
   21:                  if (SUCCEEDED(hr))
   22:                  {
   23:                      pcdl->CommitList();
   24:                  }
   25:                  poaRemoved->Release();
   26:              }
   27:          }
   28:      }
   29:  }
 // 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;
 }

 

We started with a call to CoCreateInstance to initialize the ICustomDestinationList object (this is the joy of working with COM….). Next, we set the Application ID, so we could start populating items to the list. The Application ID is a string the uniquely identifies your application and make sure all the different windows are clustered under the same glom as well as all the files in the Recent category, however, Application ID is important enough to get its own full blog in the near future.

Using the BeginList function initiated the build session for the custom Jump List. Note the Remove item parameter, IObjectArray *poaRemoved, that the BeginList() returned as an out parameter. We will handle the removed items list below.

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

Another new interface, the IObjectCollection, represents a collection of objects that support IUnKnown, to which we will add the IShellItems. Each item we added is of an IShellItem type and we created each item in the documents known folder. However, before we actually added the new item to the collection, we needed to check if the user already removed it. If the user explicitly removed an item from the Jump List, that item will be in the Removed Item List (again associated with the App ID), 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 the process of creating a new list.

At this stage, we have a collection if IShellItems that the user expects to see in his 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);.

We have successful 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 is to call the CommitList() function that ends the "transaction" that began with calling the BeginList() function. Only after our call to CommitList()arethe 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 ICustomDestinationist 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.

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

There are many more features the new Windows 7 Taskbar that further enhance the user experience, including cool visual and informative notifications using Overlay icons, a Progress Bar indicator, and Thumbnail icons. We will address these features in future posts.