July 2009

Volume 24 Number 07

Inside Windows 7 - Introducing The Taskbar APIs

By Yochay Kiriaty, Sasha Goldshtein | July 2009

This article discusses:

  • Taskbar Buttons
  • Overlay Icons
  • Progress Bars
  • Thumbnail Toolbars
This article uses the following technologies:
Windows 7

View the entire series:

This article is based on a prerelease version of Windows 7. Details are subject to change.

Contents

Taskbar Buttons
Overlay Icons and Progress Bars
Thumbnail Toolbars
Jump Lists
Miscellaneous Features
Summary

The Windows 7 taskbar is the latest in a series of evolutionary taskbar designs that started with Windows 1.0. It represents a design and architectural change with regard to user experience, and offers significant improvements in user productivity. Figure 1 shows the Windows 1.0 taskbar. (Note that the 1.0 taskbar bears more resemblance to the Windows 7 taskbar than to the Windows Vista taskbar.)

Figure 1

Figure 1 Windows 1.0 taskbar

Analysis from a number of user sessions during recent years has shown that having an abundance of launch surfaces (those areas dedicated to launch programs) does not necessarily make the user's work any easier. As far as user interface design is concerned, to prevent user confusion it's often better to have only one way to accomplish a task.

The design goals of the Windows 7 taskbar are to bring control back to the user and to minimize confusion, by supporting the following principles:

  • Single launch surface for frequent programs and destinations. This helps keep those applications and data that you use all the time right at your fingertips.
  • Easy to control, where switching between applications and windows and arranging windows are made easy and manageable.
  • Clean, noise-free, simple.

Large taskbar buttons, visual clarity, and sleekness of design dominate users experience once they are logged on to Windows 7. But how can developers leverage the new functionality that the Windows 7 taskbar has to offer? How do the underlying mechanisms work together to enable the best user experience? In this article, we will explore the new features and underlying functionality of the Windows 7 taskbar, supported with examples in native and managed code.

Taskbar Buttons

Taskbar buttons provide the gateway to access the functionality of the new Windows 7 taskbar. The biggest thing to notice is that the taskbar also contains icons for applications that are not currently running. For example, the user may pin applications to the taskbar, which results in a pinned icon on the taskbar but the application is not running. Clicking the icon causes the app to launch. This is a unification of the Quick Launch concept and the standard Windows taskbar. In fact, there is no need for the Quick Launch area on Windows 7 any longer; the only reason the Quick Launch folder is still in Windows 7 is for backwards compatibility.

You may have already heard about jump lists, thumbnail toolbars, taskbar progress bars, and other features. They are all connected with the large, redesigned taskbar buttons that occupy the new taskbar. The Windows 7 taskbar buttons, shown in Figure 2, are identified with multiple visual effects. They make it possible to immediately identify which applications are running, whether there are multiple windows in the same application, which application is currently active, and which taskbar button currently has the mouse hovering over it.

Figure 2

Figure 2 Various Windows 7 Taskbar Button States

All the Windows 7 taskbar features are unlocked only after you have created the taskbar button for your application. This makes sense, since you can't change the taskbar overlay icon, for example, if there is no taskbar button yet! In practice, this means that managed and native applications using the new Windows 7 taskbar APIs will have to wait for a new window message, identifiable by the TaskbarButtonCreated string. To obtain the identifier of this message, you must call the RegisterWindowMessage Win32 API and pass the TaskbarButtonCreated string as a parameter.

The following code shows how a Win32 application receives the window message indicating that the taskbar button is created:

DWORD g_wmTBC = (DWORD)-1; //In the window procedure: switch (msg) { case WM_CREATE: g_wmTBC = RegisterWindowMessage(L"TaskbarButtonCreated"); //Proceed to create the window case g_wmTBC: //The taskbar button has been created }

A managed application, for example an application using Windows Forms, would have to override the window procedure (the WndProc method) of the form to process window messages. The following code shows this:

uint wmTBC = (uint)-1; [DllImport("user32.dll")] static extern uint RegisterWindowMessage(string message); void Form_Load() { wmTBC = RegisterWindowMessage(L"TaskbarButtonCreated"); } protected override void WndProc(...) { if (msg == wmTBC) { //The taskbar button has been created } }

Now you know how to make sure that your application does not use the Windows 7 taskbar before there is a taskbar button in place. Before we jump to more interesting features, there's just one additional piece of information that you need to complete the puzzle. How are taskbar buttons associated with windows and applications? How does the system decide whether an application needs two taskbar buttons for its different windows or whether multiple applications need to share a single taskbar button?

The answer is application ID. This is a new property of the Windows Shell and is an attribute of windows, processes and shell links (also known as shortcuts). By controlling the application ID of individual windows and processes, application developers can ensure that the taskbar buttons are associated to their windows exactly as they deem fit. The application ID is a string—not a GUID—that can take a free format of up to 128 characters. To make sure application IDs do not accidentally collide, the recommendation is to include in the application ID the company name, product name, and application name. The default application ID for a window is determined by the default application ID for the process to which the window belongs. This is, in turn, a default application ID generated for the executable file that the process runs. Try launching an application like Notepad several times to see this in action. There is only one taskbar button created even if you run multiple instances of Notepad at the same time.

Customizing these default IDs involves explicitly setting an application ID for the process or for an individual window, producing interesting scenarios. For example, if you set the application ID of two different processes to the same value, windows created by both of these processes will be grouped to the same taskbar button. Alternatively, if you set the application ID of two individual windows (within the same process) to different values, two taskbar buttons will be created, one for each window. The combination of process application ID and window-specific application ID provides for maximum flexibility. In Figure 3, the left pane shows that the windows from different processes are all grouped under one taskbar button. The right pane shows that multiple windows from the same process have multiple taskbar buttons.

Figure 3

Figure 3 Windows, Processes, and Taskbar Buttons

Setting the application ID for a process involves a call to the SetCurrentProcessExplicitAppUserModelID Win32 function from shell32.dll. Setting the application ID for a window requires calling the SHGetPropertyStoreForWindow function and then manipulating the returned IPropertyStore object. The following example shows you how to do this:

PROPVARIANT pv; InitPropVariantFromString(L"MyAppID", &pv); IPropertyStore* pps; VERIFY(SHGetPropertyStoreForWindow(hwnd, IID_PPV_ARGS(&pps))); VERIFY(pps->SetValue(PKEY_AppUserModel_ID, pv)); VERIFY(pps->Commit());

So far we've escaped the necessity of calling complicated APIs from managed code, but now we have no choice. Fortunately, the Windows API Code Pack comes to the rescue.

The Windows API Code Pack for the Microsoft .NET Framework provides a library that can be used to access new Windows 7 and Windows Vista features from managed code. . At the time of this writing, the code pack includes support for Windows 7 shell libraries, known folders, Windows Vista task dialogs, Windows 7 jump lists, icon overlays, progress bars, and other features. While this is not an officially supported Microsoft product, the code pack provides a very good jump-start for managed application developers targeting Windows 7. It alleviates the necessity to implement managed wrappers for complicated Windows features.

The Windows API Code Pack provides the static Taskbar.AppId property for manipulating the application ID of a given process. Unfortunately, there is no equivalent for setting the application ID of a specific window. Instead, this can be accomplished by either writing the required wrapper manually or using the predecessor of the Windows API Code Pack. (A sample interoperability library for the Windows 7 taskbar can be downloaded from Windows 7 taskbar: Developer Resources. Using the library provides you with the Windows7Taskbar.SetWindowAppId static method which does the ugly interoperability work.)

Overlay Icons and Progress Bars

The route to most Windows 7 taskbar features is via the ITaskbarList3 interface. If you're using managed code and managed wrappers, you might never have to come across this interface. However, if you're using native code, it's important that you know how to get your hands on one. That's easy if you just make sure that you do so after you received the message indicating that the taskbar button was created. In other words, you must wait for the taskbar button to become initialized, and then obtain a pointer to the ITaskbarList3 interface, like so:

ITaskbarList3* ptl; VERIFY(CoCreateInstance( CLSID_TaskbarList, NULL, CLSCTX_ALL, IID_ITaskbarList3, (void**)&ptl));

Setting an overlay icon or providing a progress bar in the Windows 7 taskbar is a fairly easy task. Fortunately, for managed developers, there is a managed equivalent in the Windows API Code Pack. To set an overlay icon, you use the ITaskbarList3::SetOverlayIcon method, which takes an icon handle (HICON) and a string serving as an accessible description. The managed equivalent is the Taskbar.OverlayImage property, which is equally easy to use.

The following code controls an application's overlay icon based on a selection made in a combo box (also shown in Figure 4):

void comboBox1_ValueChanged(...) { if (comboBox1.SelectedItem == ...) { Taskbar.OverlayImage = new OverlayImage(icon1, "Icon 1"); } else { Taskbar.OverlayImage = new OverlayImage(icon2, "Icon 2"); } }

Figure 4

Figure 4 Windows Live Messenger and its Overlay Icon

Similarly, the ITaskbarList3::SetProgressState and ITaskbarList3::SetProgressValue methods modify the state of the taskbar progress bar. There are several states available for applications to use: indeterminate, paused, error and normal. The appearances of the various states are summarized in Figure 5. The managed equivalent is the Taskbar.ProgressBar.State and Taskbar.ProgressBar.CurrentValue static properties, as well as the Taskbar.ProgressBar.MaxValue property.

Figure 5

Figure 5 Various States of the Taskbar Progress Bar

The following code and Figure 6 demonstrate how a background operation can affect the state of the taskbar progress control (assume that the DoWork function runs in a separate, background thread):

HWND hmainwnd;//Application main window ITaskbarList3* ptl;//Created earlier DWORD WINAPI DoWork(LPVOID) { ptl->SetProgressState(hmainwnd, TBPF_NORMAL); for (int i = 0; i < WorkToDo; ++i) { DoSomePartOfTheWork(i); ptl->SetProgressValue(hmainwnd, i, WorkToDo); } ptl->SetProgressState(hmainwnd, TBPF_PAUSED); return 0; }

Figure 6

Figure 6 Internet Explorer Reports Download Progress.

Applications that take advantage of the built-in file operation functionality, added to the Windows Shell in Windows Vista, automatically get taskbar progress support for free. If you use the Win32 SHFileOperation function or IFileOperation interface, your taskbar button will automatically light up with progress information, even if you're invoking the APIs from a console application. In managed code, you can read Stephen Toub's MSDN Magazine article from December 2007, titled ".NET Matters: IFileOperation in Windows Vista." His FileOperation class provides an excellent wrapper of the underlying native API and makes it equally easy to use from managed code. Try his samples on Windows 7, and you will immediately see a demonstration of the taskbar progress bar.

Thumbnail Toolbars

Thumbnail toolbars are a great addition to the Windows 7 taskbar landscape. Thumbnail and live preview functionality have been greatly enriched in Windows 7 (unfortunately, it is not within the scope of this article to discuss them in any detail). Thumbnail toolbars provide a mini "remote-control" opportunity for a window from its thumbnail. For example, to switch to the next song in Windows Media Player you don't need to use the clumsy Media Player desk band or to switch to the Media Player application. Instead, you can use the thumbnail toolbar directly to perform this task, without interrupting your work flow by jumping to another application, as shown in Figure 7.

Figure 7

Figure 7 Windows Media Player Provides a Thumbnail Toolbar for Convenient Navigation.

To use a thumbnail toolbar, you must wait for the taskbar button to become initialized, and then obtain a pointer to the ITaskbarList3 interface, as described earlier. Next, you initialize a set of THUMBBUTTON structures that describe the individual buttons that appear in the toolbar (note that you are limited to seven buttons at most, and that there is no way to add or remove buttons after you initialize the toolbar, only to disable or hide them.) Finally, you call the ITaskbarList3::ThumbBarAddButtons and ITaskbarList3::ThumbBarUpdateButtons methods to control the thumbnail toolbar.

When a thumbnail button is clicked, the application receives a WM_COMMAND message with the high word of the wParam set to THBN_CLICKED and the low word set to the button ID. This message is dispatched to the window to which the thumbnail belongs. Figure 8 demonstrates the creation and message handling that are required.

Figure 8 Creation and Message Handling

ITaskbarList3* ptl;//Created earlier //In your window procedure: switch (msg) { case g_wmTBC://TaskbarButtonCreated THUMBBUTTON buttons[2]; buttons[0].dwMask = THB_ICON|THB_TOOLTIP|THB_FLAGS; buttons[0].iId = 0; buttons[0].hIcon = GetIconForButton(0); wcscpy(buttons[0].szTip, L"Tooltip 1"); buttons[0].dwFlags = THBF_ENABLED; buttons[1].dwMask = THB_ICON|THB_TOOLTIP|THB_FLAGS; buttons[1].iId = 1; buttons[1].hIcon = GetIconForButton(1); wcscpy(buttons[0].szTip, L"Tooltip 2"); buttons[1].dwFlags = THBF_ENABLED; VERIFY(ptl->ThumbBarAddButtons(hWnd, 2, buttons)); break; case WM_COMMAND: if (HIWORD(wParam) == THBN_CLICKED) { if (LOWORD(wParam) == 0) MessageBox(L"Button 0 clicked", ...); if (LOWORD(wParam) == 1) MessageBox(L"Button 1 clicked", ...); } break;

The managed equivalent does not currently appear in the Windows API Code Pack, but it is planned to appear in a future release. In the meantime, you can use the Windows 7 taskbar Interop Sample Library. It contains the ThumbButtonManager class with the corresponding CreateThumbButton and AddThumbButtons methods for controlling the thumbnail toolbar, and also the ThumbButton class for modifying the thumbnail button state at runtime. To receive notifications, you register for the ThumbButton.Clicked event and override your window procedure to dispatch the messages to the ThumbButtonManager class, which does the dispatching magic for you. (For more details, see the blog article "Windows 7 Taskbar: Thumbnail Toolbars.")

Jump Lists

The final feature of the Windows 7 taskbar that we discuss in detail here is the jump list, arguably the most important feature that applications need to take advantage of in order to truly shine on Windows 7. In the Windows 7 taskbar, each taskbar button is associated with a jump list. This is a retractable menu that shows a collection of items (also called destinations) and tasks that are relevant to the given application. Destinations are typically represented by shell items (through the IShellItem interface), and are files/documents that your application works with. Tasks are typically represented by shell links (also known as shortcuts, through the IShellLink interface), and can be used to launch other associated applications or even your own application with a different set of command line arguments.

Some applications may choose to customize the tasks area of a jump list. For example, Windows Live Messenger uses a variety of tasks and separators to make it easier to use the application from the jump list, as shown in Figure 9.

Figure 9

Figure 9 Windows Live Messenger

Some other applications might choose to customize the items (or destinations) area of the jump list, and even categorize the items to make the user's work more convenient. At the very least, applications should provide a collection of recent or frequent items pertinent to the application, because users will grow to expect this functionality from every Windows 7 application. As an example, consider the Microsoft Office Word jump list, as shown in Figure 10. Even though Word was not designed for Windows 7, it uses the recent items infrastructure built into Windows and the jump list works by default.

Figure 10

Figure 10 Jump List of Recent Documents

It should be pretty clear that it's possible to get the jump list to work for you without a significant effort. For recent items to appear in your application's jump list, follow these steps:

  1. Make sure that your application's file type is associated with your application in the Windows registry (as a registered handler). Note that your application does not have to be the primary or default handler for the file type. (See msdn.microsoft.com/en-us/library/dd378402(VS.85).aspx for more information.)
  2. Make sure that you use the common file dialogs for loading and saving files. If you aren't using the common file dialogs, let the Windows Shell know when you're using a file as a result of a user's request by calling the SHAddToRecentDocs Win32 function. (See the "Common Dialog Box Library" article on MSDN for more information on common dialogs.)

If your jump list requires further customization, you can add custom categories of destinations or custom tasks to enrich its functionality. The ICustomDestinationList is the source of jump list functionality, along with the following useful methods: AddUserTasks, AppendCategory, and AppendKnownCategory. To begin a list-building transaction, you call BeginList, and then you can choose between AbortList and CommitList, which are self-explanatory. You can also delete all items from the list by calling DeleteList. An example of a list-building transaction is available in the Windows 7 SDK.

The managed equivalent is significantly easier to use. It all begins with the Taskbar.JumpList property, which unlocks a handful of methods for manipulating the jump list's destinations and tasks: the AddToRecent method is the equivalent of SHAddToRecentDocs, the KnownCategoryToDisplay property determines whether to show recent or frequent items by default, the UserTasks property returns a modifiable collection of user tasks, and the CustomCategories property returns a collection of custom categories (each custom category has a name and a collection of jump list items). The following example demonstrates a list-building transaction for adding items and tasks to the application's jump list:

JumpListLink notepad = new JumpListLink { Title = "Launch Notepad", Path = @"C:\Windows\notepad.exe" }; JumpListItem doc1 = new JumpListItem(@"doc1.txt"); JumpListItem doc2 = new JumpListItem(@"doc2.txt"); CustomCategory category = new CustomCategory("Special Items"); category.JumpListItems.Add(doc1); category.JumpListItems.Add(doc2); Taskbar.JumpList.UserTasks.Add(notepad); Taskbar.JumpList.CustomCategories.Add(category);

An important thing to note is that the user may choose to remove items from the taskbar by right-clicking them and selecting "Remove from this list." Applications must be aware of this functionality. If they attempt to add an item that a user has removed, it will cause the entire list-building transaction to fail. In Win32 code, when calling the ICustomDestinationList::BeginList method, you receive a collection of removed items that should require extra care so you don't add these items again:

ICustomDestinationList* cdl; VERIFY(CoCreateInstance(CLSID_DestinationList, ..., IID_ICustomDestinationList, (void**)cdl)); IObjectArray* removedItems; cdl->BeginList(&maxSlots, IID_IObjectArray, (void**)removedItems); //…Iterate removedItems and make decisions removedItems->Release();

Alternatively, you can proactively call the ICustomDestinationList::GetRemovedDestinations method to retrieve the removed items before initiating the list-building transaction. Managed applications can leverage the functionality built into the Windows API Code Pack and rely on the JumpList class that automatically does not add items that were previously removed by the user. Alternatively, managed applications can register to the Taskbar.JumpList.JumpListItemsRemoved event that occurs when the infrastructure detects (within a list-building transaction) that items were removed from the jump list.

While the variety of alternatives in the jump list might appear overwhelming, bear in mind that most users will expect your application to provide at least the simplest interface—such as the list of recent or frequent items that have been used throughout your application. If you adhere to this fundamental requirement, you are almost guaranteed to satisfy your users; if you add custom functionality to your jump list through custom tasks and destinations, you've got your differentiation opportunity on Windows 7.

Miscellaneous Features

The Windows 7 taskbar contains a variety of other features that we did not cover in this article. Among them are: Live Preview (also known as Aero Peek), thumbnail customization (can enhance users productivity when previewing applications,) thumbnail support for Tabbed Document Interface (TDI) and Multiple Document Interface (MDI) applications, and several others.

For an overview of these features, as well as a discussion of the related native APIs and their managed equivalents, see the following resources:

Summary

In this article, we have explored some features of the Windows 7 taskbar, such as application IDs, thumbnail toolbars, overlay icons, progress bars and jump lists. The Windows 7 taskbar provides a clean, sleek launch surface that strongly benefits users. Integrating into this surface will be a primary goal for any application developer for Windows 7.

Using the native Win32 APIs or the managed Windows API Code Pack provides you with a differentiating opportunity to light up your applications on Windows 7. Bear in mind that the taskbar is the first thing users see after logging on to Windows, and you'll want your application to be pinned to their taskbar.

Yochay Kiriaty is a Technical Evangelist at Microsoft , focusing on Windows 7. He has more than a decade of experience in software development. He has written and taught academic computer science courses and is an active contributor to The Windows Blog.

Sasha Goldshtein is a Senior Consultant at Sela Group, an international training, consulting and development company. Sasha leads the Performance and Debugging team at Sela and specializes in managed and native solutions on Windows, including high-performance applications, interoperability scenarios and high-availability server applications. He is the author of Windows Internals and Windows Vista courses that have been delivered worldwide and submitted to the Microsoft Courseware Library. Sasha is a speaker at various Microsoft conferences.