Taskbar - Nativeaz12722.vo.msecnd.net/windows7trainingcourse1-0... · Lab 4 The consolidation of...

31
Hands-On Lab Taskbar – Native Win32 Lab version: 1.0.0 Last updated: October 15, 2009

Transcript of Taskbar - Nativeaz12722.vo.msecnd.net/windows7trainingcourse1-0... · Lab 4 The consolidation of...

Page 1: Taskbar - Nativeaz12722.vo.msecnd.net/windows7trainingcourse1-0... · Lab 4 The consolidation of features into the new taskbar user interface is designed to provide a cleaner look

Hands-On Lab

Taskbar – Native Win32 Lab version: 1.0.0 Last updated: October 15, 2009

Page 2: Taskbar - Nativeaz12722.vo.msecnd.net/windows7trainingcourse1-0... · Lab 4 The consolidation of features into the new taskbar user interface is designed to provide a cleaner look

Lab

2

CONTENTS

OVERVIEW ............................................................................................................................................. 3

EXERCISE: EXPERIMENT WITH THE NEW WINDOWS 7 TASKBAR FEATURES ............................... 5 Task 1—Using Taskbar Overlay Icons and Progress Bars ................................................................... 6

Task 2—Using Live Thumbnail Previews and Tabbed Thumbnails ..................................................... 9

Task 3—Using Taskbar Jump Lists .................................................................................................. 22

SUMMARY ............................................................................................................................................ 31

Page 3: Taskbar - Nativeaz12722.vo.msecnd.net/windows7trainingcourse1-0... · Lab 4 The consolidation of features into the new taskbar user interface is designed to provide a cleaner look

Lab

3

Overview

The new Windows 7 Taskbar represents the culmination of many years of Windows launch-surface

evolution. The new taskbar streamlines many end-user scenarios including:

Launching applications

Switching between running applications and windows within a single application

Managing recent/frequent user destinations

Accessing common application tasks

Reporting progress and status notifications through the taskbar button

Controlling the application without leaving the taskbar thumbnail

Figure 1

The new Windows 7 Taskbar and Start Menu

The new taskbar is a differentiating opportunity that allows applications to shine on the Windows 7

platform. It is the end user’s primary point-of-contact for initiating and managing activities. Thus, the

integration of new taskbar features into modern Windows 7 applications is a critically important goal.

Page 4: Taskbar - Nativeaz12722.vo.msecnd.net/windows7trainingcourse1-0... · Lab 4 The consolidation of features into the new taskbar user interface is designed to provide a cleaner look

Lab

4

The consolidation of features into the new taskbar user interface is designed to provide a cleaner look to

Windows, reduce the number of concepts users must learn in order to interact with the system, ease

discoverability of key features, tasks, and destinations, and make common end-user scenarios more

accessible.

Objectives

In this Hands-On Lab, you will learn how to integrate your application with the Windows 7 Taskbar,

including how to:

Provide visual progress and status indicators using taskbar progress bars and overlay icons

Customize the taskbar thumbnail and live preview bitmaps

Display multiple taskbar thumbnails and live previews for tabs in a tabbed document interface

(TDI) application

Quickly access common tasks and frequent destinations using jump list tasks, system categories,

and custom categories

System Requirements

You must have the following items to complete this lab:

Microsoft Visual Studio 2008 SP1

Windows 7 RC or later

Windows SDK for Windows 7 RC or later

Graphics card fully supporting Windows Aero

Page 5: Taskbar - Nativeaz12722.vo.msecnd.net/windows7trainingcourse1-0... · Lab 4 The consolidation of features into the new taskbar user interface is designed to provide a cleaner look

Lab

5

Exercise: Experiment with the New

Windows 7 Taskbar Features

In this exercise, you will experiment with the new Windows 7 taskbar features. You will extend a

showcase application that demonstrates the use of the new taskbar functionality to provide a taskbar

progress bar, overlay icon, custom tabbed thumbnails, jump list, and more. Most of the application’s

user interface is already implemented; you will use Win32 functions and COM interfaces from the

Windows SDK to fill in the missing parts to order to interact with the Windows 7 taskbar.

To begin this exercise, open the TaskbarHOL_Starter solution (under the HOL root folder) in Visual

Studio.

Figure 2

TaskbarHOL solution structure in Visual Studio

Spend a minute or two exploring the C++ source and header files that comprise the demo application.

For your convenience, ensure that the Task List tool window is visible (in the View menu, choose Task

Page 6: Taskbar - Nativeaz12722.vo.msecnd.net/windows7trainingcourse1-0... · Lab 4 The consolidation of features into the new taskbar user interface is designed to provide a cleaner look

Lab

6

List) and in the tool window’s combo box select Comments. You will now see TODO items for each of the

tasks in this exercise.

Note: In the interests of brevity and simplicity, the demo application does not demonstrate best

practices of Win32 UI development (including error handling best practices), nor does it exhibit the

best design guidelines for working with the Windows 7 Taskbar. For more information, consult the

Windows 7 User Experience Guidelines (Taskbar) at http://msdn.microsoft.com/en-

us/library/aa511446.aspx and the Taskbar Extensions article at http://msdn.microsoft.com/en-

us/library/dd378460(VS.85).aspx

Task 1—Using Taskbar Overlay Icons and Progress Bars

In this task, you will toggle an overlay icon on the application’s taskbar button when the text entered

into an edit box is checked for spelling errors; you will also modify the state and value of the

application’s taskbar button progress bar when items are added to a list box.

1. Navigate to the MainDialog.cpp code file and locate the OnTaskbarButtonCreated method.

This method is invoked when the main dialog window procedure receives a window message

indicating that the taskbar button for the window has been created. Because there is no #define

directive in the Windows header files,, use the RegisterWindowMessage function as shown in

the OnInitDialog method in the MainDialog.cpp file to retrieve the window message identifier.

2. In the method’s code:

a. Co-create the CLSID_TaskbarList COM object and place the result in the _pTaskbar

member variable (of type ITaskbarList3*).

The ITaskbarList3* interface is the primary gateway for the Windows 7 Taskbar features,

including taskbar overlay icons and progress bars which are the subject of this task.

b. Call the HrInit method on the resulting interface pointer to initialize the object.

3. Call the TabWindow::EnableCustomPreviews method and pass to it the window handle of the

main dialog (stored in the _hwnd member variable).

This will be used in Task 2 to support customization of the application’s thumbnail and preview.

4. The complete code should be similar to the following:

C++

::CoCreateInstance(CLSID_TaskbarList,

NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&_pTaskbar));

_pTaskbar->HrInit();

TabWindow::EnableCustomPreviews(_hwnd);

5. Navigate to the OnSpellCheck method.

6. In the method’s code, if the SpellCheck::Check call returns false:

Page 7: Taskbar - Nativeaz12722.vo.msecnd.net/windows7trainingcourse1-0... · Lab 4 The consolidation of features into the new taskbar user interface is designed to provide a cleaner look

Lab

7

a. Use the SetOverlayIcon method of the ITaskbarList3 interface (stored in the _pTaskbar

member variable) to set the taskbar overlay icon to IDI_ERROR. (Use the LoadIcon

function to load the icon; pass the window’s handle, _hwnd, as the first parameter.)

This will cause an overlay icon to appear in the bottom-right corner of the application’s

taskbar button, providing an immediate status indicator without the need to switch to

the application’s window.

This feature is used by Windows Live Messenger to display online availability status, by

Microsoft Office Outlook 14 to display the new mail notification, and by many other

applications.

b. In the same conditional branch, use the SetProgressState method of the ITaskbarList3

interface to set the taskbar button’s progress state to the error state.

This will cause a progress bar to appear in the application’s taskbar button, providing an

immediate progress indicator without the need to switch to the application’s main

window. This feature is used by Windows Explorer when performing file operations, by

Internet Explorer when downloading files, and by other Windows applications.

7. If the SpellCheck::Check call returns true, repeat steps 6.a and 6.b to set the overlay icon to

IDI_WINLOGO and the progress state to the normal.

8. The complete code should be similar to the following:

C++

if (!SpellCheck::Check(text))

{

HICON hicon = ::LoadIcon(NULL, MAKEINTRESOURCE(IDI_ERROR));

hr = _pTaskbar->SetOverlayIcon(_hwnd, hicon, L"Spelling error");

hr = _pTaskbar->SetProgressState(_hwnd, TBPF_ERROR);

}

else

{

HICON hicon = ::LoadIcon(NULL, MAKEINTRESOURCE(IDI_WINLOGO));

hr = _pTaskbar->SetOverlayIcon(_hwnd, hicon, L"Spelling OK");

hr = _pTaskbar->SetProgressState(_hwnd, TBPF_NORMAL);

}

9. Compile and run the application.

10. Click Check Spelling. An overlay icon with the standard Windows error indicator should appear

on top of the application’s taskbar button. For example:

Figure 3

A taskbar overlay icon, conveying an error status

Page 8: Taskbar - Nativeaz12722.vo.msecnd.net/windows7trainingcourse1-0... · Lab 4 The consolidation of features into the new taskbar user interface is designed to provide a cleaner look

Lab

8

11. Modify the text in the edit box by removing the last word (‘text’). Click Check Spelling again.

The overlay icon should change. For example:

Figure 4

A taskbar overlay icon without the error indicator

12. Navigate to the OnAddToList method.

13. In the method’s code, use the Show method of the _pTabCtrl member variable to display the

List tab (use the LIST_TAB constant as the parameter).

14. Retrieve the handle to the list box window using the GetTab method of the _pTabCtrl member

variable and then the GetControl method (pass 0 as the control number).

15. Use the SendMessage function to add an item to the list box with arbitrary text (use the

LB_ADDSTRING message).

16. Obtain the current number of items in the list box by using the SendMessage function with the

LB_GETCOUNT message.

17. Use the SetProgressValue method of the _pTaskbar member variable to update the progress

value; use the number of items in the list box as the current value, and 10 as the maximum

value.

18. Compile and run the application.

19. Click Add to List a few times to add items to the list box. Observe the taskbar button and ensure

that the progress bar advances as items are being added. For example:

Figure 5

A taskbar progress bar when the window doesn’t have focus, with a ‘Normal’ progress state

20. Click Check Spelling and notice that the progress bar color changes to red, indicating that the

progress state is an error state. For example:

Figure 6

A taskbar progress bar when the window doesn’t have focus, with an ‘Error’ progress state and

an additional overlay icon

Page 9: Taskbar - Nativeaz12722.vo.msecnd.net/windows7trainingcourse1-0... · Lab 4 The consolidation of features into the new taskbar user interface is designed to provide a cleaner look

Lab

9

Task 2—Using Live Thumbnail Previews and Tabbed Thumbnails

In this task, you will customize live thumbnails (and previews) of the application’s window and provide

the displayed thumbnail lazily (on demand); you will also display multiple taskbar buttons with

thumbnails and live previews corresponding to each of the application’s tabs.

1. Navigate to the MainDialog.cpp code file and locate the OnSendThumbnail method.

The purpose of this method, which is invoked as a result of receiving the

WM_DWMSENDICONICTHUMBNAIL window message, is to provide a thumbnail preview of the

application’s main window. At this time, we will provide a simple screen capture of the window

that is not different from what DWM generates on its own. Later on, we will provide a custom

preview of the application’s tab, which will require a more sophisticated approach.

The main dialog’s window procedure determines the thumbnail dimensions by inspecting the

lParam message parameter. The high word (HIWORD) of the parameter is the thumbnail width;

the low word (LOWORD) of the parameter is the thumbnail height.

In Task 1 (step 3), we instructed the DWM to request a thumbnail bitmap and a live preview

bitmap from the application’s main window. If we didn’t do so, we wouldn’t get a chance to

customize the thumbnail bitmap and live preview bitmap.

Finally, note that the application’s WinMain function calls the ChangeWindowMessageFilter API

function to request that the WM_DWMSENDICONICTHUMBNAIL and

WM_DWMSENDICONICLIVEPREVIEWBITMAP window messages be allowed to pass through

UIPI. This enables the messages to pass through even when the application is running as an

administrator (with a High integrity level).

2. In the method’s code, use the GetWindowThumbnail method to retrieve the window thumbnail

bitmap and pass the resulting bitmap to the DwmSetIconicThumbnail method. Use the

DWM_SIT_DISPLAYFRAME constant for the last parameter.

3. Delete the created thumbnail bitmap using the DeleteObject GDI function to prevent a GDI

object leak.

4. The complete code should be similar to the following:

C++

HBITMAP hbm = GetWindowThumbnail(width, height);

::DwmSetIconicThumbnail(_hwnd, hbm, DWM_SIT_DISPLAYFRAME);

::DeleteObject(hbm);

5. Navigate to the OnSendLivePreview method.

6. In the method’s code, use the GetWindowPreview method to obtain a live preview bitmap and

pass the resulting bitmap to the DwmSetIconicLivePreviewBitmap method (with the

DWM_SIT_DISPLAYFRAME constant as before).

7. Delete the created live preview bitmap as in step 3.

Page 10: Taskbar - Nativeaz12722.vo.msecnd.net/windows7trainingcourse1-0... · Lab 4 The consolidation of features into the new taskbar user interface is designed to provide a cleaner look

Lab

10

8. The complete code should be similar to the following:

C++

HBITMAP hbm = GetWindowPreview();

::DwmSetIconicLivePreviewBitmap(_hwnd, hbm, NULL, DWM_SIT_DISPLAYFRAME);

::DeleteObject(hbm);

9. Compile and run the application.

10. Let the mouse hover over the application’s taskbar button. A thumbnail with the window’s

contents should appear. For example:

Figure 7

A standard thumbnail obtained by capturing the window

11. Now hover over the application’s thumbnail. A live preview of the window’s contents should

appear (notice that all other windows become transparent). For example:

Page 11: Taskbar - Nativeaz12722.vo.msecnd.net/windows7trainingcourse1-0... · Lab 4 The consolidation of features into the new taskbar user interface is designed to provide a cleaner look

Lab

11

Figure 8

A standard live preview obtained by capturing the window

12. Navigate to the OnShowTabbedThumbnails method.

In this method, we will create thumbnails and live previews for the three tabs that appear in the

application’s tab control. Each tab will have an individual thumbnail and live preview in the

taskbar, similarly to Internet Explorer 8 tabs.

Page 12: Taskbar - Nativeaz12722.vo.msecnd.net/windows7trainingcourse1-0... · Lab 4 The consolidation of features into the new taskbar user interface is designed to provide a cleaner look

Lab

12

Figure 9

Internet Explorer 8 features tabbed thumbnails of its TDI interface

The sequence of operations required to display a custom thumbnail and live preview is fairly

complicated. In this task we will perform most of the necessary steps.

13. In the method’s code, ensure that the _usingTabWindows Boolean flag is set to true and return

from the method.

14. Next, call the TabWindow::DisableCustomPreviews method and pass the dialog’s window

handle (_hwnd) as the parameter.

This is required because we are no longer interested in customizing the main window’s

thumbnail and live preview; instead, we will be showing custom tab thumbnails.

15. Retrieve the number of tabs in the tab control using the TabCount method of the _pTabCtrl

member variable.

16. Repeat steps 16.a through 16.g for each of the tabs in the tab control:

a. Create a new TabWindow object with the tab control’s window handle (obtained using

the Hwnd method) as the target.

The TabWindow class represents a top-level off-screen window that is used to proxy for

the actual window for which a custom thumbnail and a live preview are requested. The

Page 13: Taskbar - Nativeaz12722.vo.msecnd.net/windows7trainingcourse1-0... · Lab 4 The consolidation of features into the new taskbar user interface is designed to provide a cleaner look

Lab

13

need for a proxy window is a limitation of the Windows 7 DWM which interacts with

top-level windows only. You will see the implementation details of the TabWindow class

in subsequent steps during this task.

b. Use the SetPreviewRequestSink method to set the callback object that is invoked when

a thumbnail or live preview bitmap is requested to the _pPreviewSink member variable.

c. Insert the new TabWindow object into the _tabWindows collection.

d. Declare a new POINT object and use the GetTabControlPreview method to retrieve a

bitmap for the tab control’s window and the offset of the window from the original

window frame.

The reason for calculating the offset is that we want the actual taskbar thumbnail to

display only the image itself, and not the entire window frame. In this case, the taskbar

thumbnail APIs require the offset from the application’s main window frame to be

specified. Thumbnail customization can be useful if you want to draw attention to a

specific part of the window when it’s displayed as a thumbnail, or when you want to

dynamically decide which part of the window to display in the thumbnail. Technically,

you're not required to display a part of your window in the thumbnail—you could

provide a completely custom image—but this has the potential to confuse users.

e. Use the SetOffset method of the newly created TabWindow object to specify the offset

calculated in the previous step.

f. Use the AddPreviews method of the _pPreviewSink member variable to add the bitmap

created in step 16.c as the preview bitmap of the window returned from TabWindow’s

Hwnd method.

g. Finally, use the SetTabOrder and SetTabActive methods of the _pTaskbar member

variable to insert the new tab window thumbnail after the last thumbnail and to

indicate that the tab window is now active.

17. The complete code should be similar to the following:

C++

if (_usingTabWindows)

return;

_usingTabWindows = true;

TabWindow::DisableCustomPreviews(Hwnd());

for (SIZE_T nTab = 0; nTab < _pTabCtrl->TabCount(); ++nTab)

{

TabWindow* tabWindow = new TabWindow(

_pTabCtrl->Hwnd(), this, _pTabCtrl->GetTab(nTab)->Text(), nTab);

tabWindow->SetPreviewRequestSink(_pPreviewSink);

Page 14: Taskbar - Nativeaz12722.vo.msecnd.net/windows7trainingcourse1-0... · Lab 4 The consolidation of features into the new taskbar user interface is designed to provide a cleaner look

Lab

14

_tabWindows.push_back(tabWindow);

POINT offset;

HBITMAP tabPreview = GetTabControlPreview(&offset);

tabWindow->SetOffset(offset);

_pPreviewSink->AddPreviews(tabWindow->Hwnd(), tabPreview);

_pTaskbar->SetTabOrder(tabWindow->Hwnd(), NULL);

_pTaskbar->SetTabActive(tabWindow->Hwnd(), Hwnd(), 0);

}

18. Navigate to the OnNotify method.

In this method, you will update the thumbnail and live preview bitmaps of the tab that is

currently losing focus. Because there is no way to retrieve the window bitmap of a control that

is not currently drawn, we cache the result from the last time the control was shown—which is

exactly when the current selection is leaving this tab page.

19. In the method’s code, if the notify code is TCN_SELCHANGING, retrieve the tab control preview

bitmap as in step 16.c.

20. Retrieve the currently selected tab number using the CurrentTab method of the _pTabCtrl

member variable.

21. Retrieve the TabWindow object from the _tabWindows collection using the index obtained in

the previous step.

22. Add the preview for the tab window’s window handle as in steps 16.d and 16.e.

23. Call the InvalidatePreviews method of the TabWindow object to ensure that the preview

bitmaps are invalidated and redrawn when next requested; otherwise, a stale bitmap might be

shown).

24. If the notify code was TCN_SELCHANGE, ensure that the _usingTabWindows Boolean member

variable is true and call the SetTabActive method of the _pTaskbar member variable to mark the

newly selected tab as the current tab in the application’s taskbar button thumbnail list.

25. The complete code should be similar to the following:

C++

if (pNotifyHeader->code == TCN_SELCHANGING && _usingTabWindows)

{

POINT offset;

HBITMAP tabPreview = GetTabControlPreview(&offset);

SIZE_T curTab = _pTabCtrl->CurrentTab();

Page 15: Taskbar - Nativeaz12722.vo.msecnd.net/windows7trainingcourse1-0... · Lab 4 The consolidation of features into the new taskbar user interface is designed to provide a cleaner look

Lab

15

TabWindow* tabWindow = _tabWindows[curTab];

tabWindow->SetOffset(offset);

_pPreviewSink->AddPreviews(tabWindow->Hwnd(), tabPreview);

tabWindow->InvalidatePreviews();

}

if (pNotifyHeader->code == TCN_SELCHANGE)

{

SIZE_T curTab = _pTabCtrl->CurrentTab();

_pTabCtrl->Show(curTab);

if (_usingTabWindows)

{

_pTaskbar->SetTabActive(_tabWindows[curTab]->Hwnd(), _hwnd, 0);

}

}

26. Navigate to the RegisterTab method.

This method is called by the TabWindow class implementation when the tab window is first

created.

27. In the method’s code, call the RegisterTab method of the _pTaskbar member variable to

register the new tab.

28. The complete code should be similar to the following:

C++

_pTaskbar->RegisterTab(pTab->Hwnd(), Hwnd());

29. Navigate to the ActivateTab method.

The TabWindow class implementation calls this method when the user clicks on the tab’s

thumbnail.

30. In the method’s code, use the TabWindow parameter's Index method to retrieve the index of

the activated tab.

31. Call the SetCurrentTab method of the _pTabCtrl member variable and pass the value obtained

in the previous step to it.

The SetCurrentTab method dispatches the TCN_SELCHANGING and TCN_SELCHANGE

notifications that you handled in steps 19 to 24. Therefore, there’s no need to show the tab’s

controls or to set it as the active tab for the taskbar.

32. Call the SetForegroundWindow API function to set the main dialog as the foreground window

(users probably want to interact with the application itself when they click on one of the tab

thumbnails, so it should be brought to the foreground).

33. The complete code should be similar to the following:

Page 16: Taskbar - Nativeaz12722.vo.msecnd.net/windows7trainingcourse1-0... · Lab 4 The consolidation of features into the new taskbar user interface is designed to provide a cleaner look

Lab

16

C++

SIZE_T curTab = pTab->Index();

_pTaskbar->SetTabActive(pTab->Hwnd(), _hwnd, 0);

_pTabCtrl->Show(curTab);

::SetForegroundWindow(_hwnd);

34. Navigate to the UnregisterTab method.

The TabWindow class implementation calls this method when the tab is about to be removed as

a result of the user’s clicking the close button in the upper right corner of the tab’s thumbnail.

35. In the method’s code, call the UnregisterTab method of the _pTaskbar member variable and

pass the tab’s window handle to it (retrieved from the TabWindow’s Hwnd method).

36. The complete code should be similar to the following:

C++

_pTaskbar->UnregisterTab(pTab->Hwnd());

37. Navigate to the TabWindow.cpp code file and locate the TabWindow class constructor.

We will now implement the functionality of the TabWindow class, which creates a proxy top-

level window that handles DWM and other messages on behalf of the underlying tab page.

38. In the constructor code, initialize the _offset point member variable to 0, 0.

39. Use the CreateWindowEx API function to create a window with the c_szWindowClass window

class:

a. Position it -32000 pixels off the screen.

b. Pass the this pointer as the last parameter.

c. Assign the result to the _proxy member variable.

40. The complete code should be similar to the following:

C++

_offset.x = _offset.y = 0;

_proxy = ::CreateWindowEx(WS_EX_TOOLWINDOW | WS_EX_NOACTIVATE,

c_szWindowClass, szName,

WS_POPUP | WS_BORDER | WS_SYSMENU | WS_CAPTION,

-32000, -32000, 10, 10, NULL, NULL, MainDialog::Hinstance(),

(LPVOID)this);

41. Navigate to the TabWindow class destructor (~TabWindow).

42. In the destructor code, call the UnregisterTab method on the _pMainDlg member variable and

pass the this pointer as the parameter.

Page 17: Taskbar - Nativeaz12722.vo.msecnd.net/windows7trainingcourse1-0... · Lab 4 The consolidation of features into the new taskbar user interface is designed to provide a cleaner look

Lab

17

43. If the _thumbnail and/or _preview member variables are not NULL, call the DeleteObject GDI

function to destroy them.

44. Finally, call the DestroyWindow API function to destroy the proxy window (_proxy).

45. The complete code should be similar to the following:

C++

_pMainDlg->UnregisterTab(this);

if (_thumbnail != NULL)

::DeleteObject(_thumbnail);

if (_preview != NULL)

::DeleteObject(_preview);

::DestroyWindow(_proxy);

46. Navigate to the EnableDisableCustomPreviews method.

This method determines whether the DWM should consult the window procedure to determine

the thumbnail and live preview bitmaps for the window.

47. In the method’s code, initialize a BOOL variable according to the enable parameter.

48. Call the DwmSetWindowAttribute method with the DWMWA_FORCE_ICONIC_REPRESENTATION

flag:

a. Pass the hwnd parameter as the window handle

b. Pass the BOOL variable and its size as the third and fourth parameters accordingly.

49. Repeat the previous step with the DWMWA_HAS_ICONIC_BITMAP flag.

50. The complete code should be similar to the following:

C++

BOOL fForceIconic = enable ? TRUE : FALSE;

BOOL fHasIconicBitmap = enable ? TRUE : FALSE;

::DwmSetWindowAttribute(

hwnd,

DWMWA_FORCE_ICONIC_REPRESENTATION,

&fForceIconic,

sizeof(fForceIconic));

::DwmSetWindowAttribute(

hwnd,

DWMWA_HAS_ICONIC_BITMAP,

&fHasIconicBitmap,

sizeof(fHasIconicBitmap));

Page 18: Taskbar - Nativeaz12722.vo.msecnd.net/windows7trainingcourse1-0... · Lab 4 The consolidation of features into the new taskbar user interface is designed to provide a cleaner look

Lab

18

51. Navigate to the SendThumbnail method.

You will call this method from the tab window’s window procedure when a thumbnail is

requested by DWM.

52. In the method’s code, if the _pSink member variable is not NULL:

a. Use its OnSendThumbnail method to request a thumbnail bitmap dynamically.

b. Pass the result to the SetThumbnail method.

53. Next, call the DwmSetIconicThumbnail method and pass the:

a. _proxy window handle as the window handle

b. _thumbnail bitmap as the bitmap

c. DWM_SIT_DISPLAYFRAME constant as the final parameter

54. The complete code should be similar to the following:

C++

if (_pSink != NULL)

{

SetThumbnail(_pSink->OnSendThumbnail(_proxy, width, height), false);

}

::DwmSetIconicThumbnail(_proxy, _thumbnail, DWM_SIT_DISPLAYFRAME);

55. Navigate to the SendPreview method.

You will call this method from the tab window’s window procedure when a live preview is

requested by DWM.

56. In the method’s code, if the _pSink member variable is not NULL:

a. Use its OnSendPreview method to request a live preview bitmap dynamically.

b. Pass the result to the SetPreview method.

57. Next, call the DwmSetIconicLivePreviewBitmap with the:

a. Window handle as in step 53

b. _preview bitmap as the bitmap

c. Final parameter as in step 53

58. The complete code should be similar to the following:

C++

if (_pSink != NULL)

{

SetThumbnail(_pSink->OnSendThumbnail(_proxy, width, height), false);

}

::DwmSetIconicThumbnail(_proxy, _thumbnail, DWM_SIT_DISPLAYFRAME);

Page 19: Taskbar - Nativeaz12722.vo.msecnd.net/windows7trainingcourse1-0... · Lab 4 The consolidation of features into the new taskbar user interface is designed to provide a cleaner look

Lab

19

59. Navigate to the InvalidatePreviews method.

Clients of the TabWindow class can called this method to invalidate the existing thumbnail and

live preview bitmaps.

60. In the method’s code, call the DwmInvalidateIconicBitmaps method, and pass the _proxy

window handle as the parameter.

61. The complete code should be similar to the following:

C++

::DwmInvalidateIconicBitmaps(_proxy);

62. Navigate to the WindowProc method.

This method contains the heart of the thumbnail handling infrastructure. In the method’s code,

handle the messages described in the subsequent steps.

63. In response to WM_CREATE:

a. Enable custom previews for the _proxy window.

b. Call the RegisterTab method of the _pMainDlg member variable.

c. Pass the this pointer as the parameter.

64. In response to WM_ACTIVATE, if the low word of the wParam message parameter is

WA_ACTIVE, call the ActivateTab method of the _pMainDlg member variable.

This is required to activate the tab when the user clicks on the tab’s thumbnail.

65. In response to WM_SYSCOMMAND, if the wParam message parameter is SC_CLOSE, delegate

processing to the DefWindowProc API function.

If it’s not SC_CLOSE, send the WM_SYSCOMMAND message to the window handle returned by

_pMainDlg’s Hwnd method.

66. In response to WM_CLOSE, call the DestroyTab method of the _pMainDlg member variable.

67. In response to WM_DWMSENDICONICTHUMBNAIL, call the SendThumbnail method (extract the

thumbnail width from the high word and the thumbnail height from the low word of the lParam

message parameter).

68. In response to WM_DWMSENDICONICLIVEPREVIEWBITMAP, call the SendPreview method.

69. In the ‘default’ switch clause, delegate processing to the DefWindowProc API function.

70. The complete code should be similar to the following:

C++

LRESULT lResult = 0;

switch (message)

{

case WM_CREATE:

Page 20: Taskbar - Nativeaz12722.vo.msecnd.net/windows7trainingcourse1-0... · Lab 4 The consolidation of features into the new taskbar user interface is designed to provide a cleaner look

Lab

20

{

TabWindow::EnableCustomPreviews(_proxy);

_pMainDlg->RegisterTab(this);

break;

}

case WM_ACTIVATE:

if (LOWORD(wParam) == WA_ACTIVE)

{

_pMainDlg->ActivateTab(this);

}

break;

case WM_SYSCOMMAND:

if (wParam != SC_CLOSE)

{

lResult = SendMessage(

_pMainDlg->Hwnd(), WM_SYSCOMMAND, wParam, lParam);

}

else

{

lResult = ::DefWindowProc(_proxy, message, wParam, lParam);

}

break;

case WM_CLOSE:

_pMainDlg->DestroyTab(this);

break;

case WM_DWMSENDICONICTHUMBNAIL:

SendThumbnail(HIWORD(lParam), LOWORD(lParam));

break;

case WM_DWMSENDICONICLIVEPREVIEWBITMAP:

SendPreview();

break;

default:

lResult = ::DefWindowProc(_proxy, message, wParam, lParam);

break;

}

return lResult;

71. Compile and run the application.

72. Click Show Tabbed Thumbnails to unleash the tabbed thumbnails functionality. Note that three

tab thumbnails should appear (stacked) behind the application’s taskbar button. For example:

Page 21: Taskbar - Nativeaz12722.vo.msecnd.net/windows7trainingcourse1-0... · Lab 4 The consolidation of features into the new taskbar user interface is designed to provide a cleaner look

Lab

21

Figure 10

When multiple thumbnails are available for the same taskbar button, the button appears

stacked

73. Hover over the application’s taskbar button to view the three tab thumbnails and then hover

over the thumbnails to view the live previews.

Note that all three thumbnails contain the same preview bitmap. This is caused by the fact that

we haven’t visited the other tabs yet, so there was no opportunity for them to redraw the

preview bitmap. For example:

Figure 11

Thumbnail bitmaps and live preview bitmaps are not automatically updated when using tabbed

thumbnails and preview customization

74. Click on the thumbnails and ensure that the corresponding tab page is selected in the

application’s main window.

75. Close one of the tabs by clicking on the close button in the upper right corner of the tab’s

thumbnail; ensure that the tab thumbnail is removed and the tab page in the underlying tab

control is removed from the main window. For example:

Page 22: Taskbar - Nativeaz12722.vo.msecnd.net/windows7trainingcourse1-0... · Lab 4 The consolidation of features into the new taskbar user interface is designed to provide a cleaner look

Lab

22

Figure 12

Support for closing tabs from the taskbar thumbnail provides a nice finishing touch

Task 3—Using Taskbar Jump Lists

In this task, you will add the functionality to support adding user tasks, custom categories, and

destinations to the application’s jump list.

1. Navigate to the MainDialog.cpp code file and locate the OnCreateJumpList method. This

method orchestrates the registration of the application’s file types and the creation of the jump

list.

Note: In order to have items appear in the Recent or Frequent categories in the jump list, your

application needs a properly defined file-type association in the Windows Registry (although it

does not have to be the default handler for that file-type). The sample application can be

registered to handle TXT files. For more information about file-type associations, consult

http://msdn.microsoft.com/en-us/library/dd758090.aspx

2. In the method’s code, check the return value of the

FileRegistration::AreFileExtensionsRegistered method (pass the c_lpszProgID string to it).

Page 23: Taskbar - Nativeaz12722.vo.msecnd.net/windows7trainingcourse1-0... · Lab 4 The consolidation of features into the new taskbar user interface is designed to provide a cleaner look

Lab

23

If the method returns true, it means that the file associations for the application are already

present in the Windows Registry, and there’s no need to register them again.

3. If the method returns false, call the FileRegistration::RegisterFileExtensions method and pass

the c_lpszProgID string and the c_rglpszExtensions array of file extension strings to it.

This method registers the file association in the Windows Registry. Inspect the method’s code to

see what entries are added to the registry.

4. If the RegisterFileExtensions method returns a failure HRESULT, pass it to the

ShowAssociationsErrorMessage method and return from the current method.

Note: A possible reason for the RegisterFileExtensions (and later, the UnregisterFileExtensions)

method to fail is that the process is not running with administrator privileges. If this is the case,

the ShowAssociationsErrorMessage method will display an informative message asking the

user to re-run the application with administrative privileges. This does not necessarily

represent a development guideline with regard to User Account Control (UAC) and

administrative elevation.

5. Finally, initialize the _pJumpList variable with a new instance of the JumpList helper class, and

call the DeleteList and BuildList methods on that instance to construct the jump list.

6. The complete code should be similar to the following:

C++

if (!FileRegistration::AreFileExtensionsRegistered(c_lpszProgID))

{

HRESULT hr = FileRegistration::RegisterFileExtensions(

c_lpszProgID, c_rglpszExtensions, ARRAYSIZE(c_rglpszExtensions));

if (FAILED(hr))

{

ShowAssociationsErrorMessage(hr);

return;

}

}

_pJumpList = new JumpList();

_pJumpList->DeleteList();

_pJumpList->BuildList();

7. Navigate to the JumpList.cpp code file and locate the BuildList method.

8. In the method’s code, co-create the CLSID_DestinationList COM object and assign it to the _pcdl

member variable (of type ICustomDestinationList).

The ICustomDestinationList interface is used to manipulate the jump list contents, including

custom categories and user tasks, which are the subjects of this task.

Page 24: Taskbar - Nativeaz12722.vo.msecnd.net/windows7trainingcourse1-0... · Lab 4 The consolidation of features into the new taskbar user interface is designed to provide a cleaner look

Lab

24

9. Call the BeginList method and assign the removed items collection to the _poaRemoved

member variable.

The removed items collection represents the items removed by the user from the application’s

jump list. The user can remove items from the jump list by right-clicking them and selecting

‘Remove from this list’ from the context menu. Applications must honor the user’s selection of

removed items—if your application attempts to add an item that was previously removed by the

user, the list-building transaction will fail.

Figure 13

Users can remove items from the jump list by using the context menu’s ‘Remove from this list’

command

10. Call the AddCustomCategory and AddUserTasks methods.

11. If they both succeed, call the CommitList method.

12. Release the _pcdl and _poaRemoved interface pointers.

13. The complete code should be similar to the following:

C++

HRESULT hr = CoCreateInstance(CLSID_DestinationList, NULL,

CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&_pcdl));

if (SUCCEEDED(hr))

{

UINT cMinSlots;

hr = _pcdl->BeginList(&cMinSlots, IID_PPV_ARGS(&_poaRemoved));

if (SUCCEEDED(hr))

{

Page 25: Taskbar - Nativeaz12722.vo.msecnd.net/windows7trainingcourse1-0... · Lab 4 The consolidation of features into the new taskbar user interface is designed to provide a cleaner look

Lab

25

hr = AddCustomCategory();

if (SUCCEEDED(hr))

{

hr = AddUserTasks();

if (SUCCEEDED(hr))

{

hr = _pcdl->CommitList();

}

}

_poaRemoved->Release();

_poaRemoved = NULL;

}

_pcdl->Release();

_poaRemoved = NULL;

}

14. Navigate to the DeleteList method.

15. In the method’s code, co-create the CLSID_DestinationList object as in step 8.

16. Call the DeleteList method of the created object.

17. Release the created interface pointer.

18. The complete code should be similar to the following:

C++

HRESULT hr = CoCreateInstance(CLSID_DestinationList, NULL,

CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&_pcdl));

if (SUCCEEDED(hr))

{

hr = _pcdl->DeleteList(NULL);

_pcdl->Release();

}

19. Navigate to the AddUserTasks method.

In this method, you will add user tasks to the application’s jump list.

The target of the user tasks will be the same application (TaskbarHOL.exe), but the tasks will be

defined with a command line parameter. The WinMain function in MainDialog.cpp handles the

various command line parameters and displays a message box accordingly.

20. In the method’s code, co-create a CLSID_EnumerableObjectCollection COM object and assign it

to a variable of the IObjectCollection* type.

21. Retrieve the full file name of the application by using the GetModuleFileName API function.

22. Create a shell link using the CreateShellLink static method with the application path as the first

parameter, and the string “/Task1” as the argument.

23. Add the shell link created in the previous step to the collection created in step 20.

Page 26: Taskbar - Nativeaz12722.vo.msecnd.net/windows7trainingcourse1-0... · Lab 4 The consolidation of features into the new taskbar user interface is designed to provide a cleaner look

Lab

26

24. Create a jump list separator using the CreateSeparator static method.

25. Repeat step 23.

26. Create a shell link as in step 22 with the string “/Task3” as the argument.

27. Repeat step 23.

28. Query the object collection for the IObjectArray* interface.

29. Pass the resulting object to the AddUserTasks method of the _pcdl member variable.

30. Release the object array and the object collection interface pointers.

31. The complete code should be similar to the following:

C++

IObjectCollection *poc;

HRESULT hr = CoCreateInstance(CLSID_EnumerableObjectCollection, NULL,

CLSCTX_INPROC, IID_PPV_ARGS(&poc));

if (SUCCEEDED(hr))

{

WCHAR szAppPath[MAX_PATH];

::GetModuleFileName(NULL, szAppPath, ARRAYSIZE(szAppPath));

IShellLink *psl;

hr = JumpList::CreateShellLink(szAppPath, L"/Task1", L"Task 1", &psl);

if (SUCCEEDED(hr))

{

hr = poc->AddObject(psl);

psl->Release();

}

if (SUCCEEDED(hr))

{

hr = JumpList::CreateSeparator(&psl);

if (SUCCEEDED(hr))

{

hr = poc->AddObject(psl);

psl->Release();

}

}

if (SUCCEEDED(hr))

{

hr = JumpList::CreateShellLink(

szAppPath, L"/Task3", L"Task 3", &psl);

if (SUCCEEDED(hr))

{

hr = poc->AddObject(psl);

Page 27: Taskbar - Nativeaz12722.vo.msecnd.net/windows7trainingcourse1-0... · Lab 4 The consolidation of features into the new taskbar user interface is designed to provide a cleaner look

Lab

27

psl->Release();

}

}

if (SUCCEEDED(hr))

{

IObjectArray* poa;

hr = poc->QueryInterface(IID_PPV_ARGS(&poa));

if (SUCCEEDED(hr))

{

hr = _pcdl->AddUserTasks(poa);

poa->Release();

}

}

poc->Release();

}

return hr;

You’ve just added common user tasks to your application’s jump list. Common user tasks would

include launching the application with different command line arguments, navigating to a

specific area in the application, or even specifying commands for a running instance of the

application. For example, Windows Live Messenger uses jump list tasks for changing the user’s

online availability status.

Page 28: Taskbar - Nativeaz12722.vo.msecnd.net/windows7trainingcourse1-0... · Lab 4 The consolidation of features into the new taskbar user interface is designed to provide a cleaner look

Lab

28

Figure 14

The Windows Live Messenger taskbar jump list, featuring user tasks

32. Navigate to the AddCustomCategory method.

Custom categories are an advanced feature that can be used by an application to provide more

than just the Recent or Frequent system categories. For example, an e-mail application might

provide Inbox, Follow-up and other custom categories into which messages are grouped.

33. In the method’s code, co-create a CLSID_EnumerableObjectCollection as in step 20.

34. Initialize an array of file names and pass it to the CreateSampleFiles method, which creates the

files under the user’s Documents folder.

35. For each of the files:

a. Use the CreateShellItem static method to create a shell item from the file name.

b. Use the IsItemInArray method to ensure that the shell item is not in the array of items

removed by the user (_poaRemoved)

c. Add it to the collection created in step 33.

Page 29: Taskbar - Nativeaz12722.vo.msecnd.net/windows7trainingcourse1-0... · Lab 4 The consolidation of features into the new taskbar user interface is designed to provide a cleaner look

Lab

29

The difference between shell items and shell links (represented by IShellItem and IShellLink in

the COM Shell APIs), is that a shell item contains only a path to a document that your application

is registered to handle. A shell link serves as a shortcut and contains additional information

including the application to launch, command-line arguments to pass to that application, a

shortcut icon and other properties.

36. Query the object collection for the IObjectArray* interface.

37. Add the custom category to the jump list using the AppendCategory method of the _pcdl

member variable. Use a category name of your choice.

38. Release the object array and object collection interface pointers.

39. The complete code should be similar to the following:

C++

IObjectCollection *poc;

HRESULT hr = CoCreateInstance(CLSID_EnumerableObjectCollection, NULL,

CLSCTX_INPROC, IID_PPV_ARGS(&poc));

if (SUCCEEDED(hr))

{

LPCWSTR rglpszFiles[] =

{

L"TaskbarHOL_File1.txt",

L"TaskbarHOL_File2.txt",

L"TaskbarHOL_File3.txt"

};

hr = CreateSampleFiles(rglpszFiles, ARRAYSIZE(rglpszFiles));

if (SUCCEEDED(hr))

{

for (UINT i = 0; i < ARRAYSIZE(rglpszFiles); i++)

{

IShellItem *psi;

if (SUCCEEDED(JumpList::CreateShellItem(

rglpszFiles[i], &psi)))

{

if (!IsItemInArray(psi, _poaRemoved))

{

poc->AddObject(psi);

}

psi->Release();

}

}

IObjectArray *poa;

hr = poc->QueryInterface(IID_PPV_ARGS(&poa));

if (SUCCEEDED(hr))

Page 30: Taskbar - Nativeaz12722.vo.msecnd.net/windows7trainingcourse1-0... · Lab 4 The consolidation of features into the new taskbar user interface is designed to provide a cleaner look

Lab

30

{

hr = _pcdl->AppendCategory(L"Custom Category", poa);

poa->Release();

}

poc->Release();

}

}

return hr;

40. Compile and run the application.

41. Click the Create Jump List button. If you have not launched the application with elevated

privileges, you will see the following message box:

Figure 15

The application displays an error message if it doesn’t have administrative privileges

42. If this occurs, run the application again as an administrator and repeat the previous step.

43. Right click the application’s taskbar button and ensure that a jump list is present, with a custom

category containing destinations as well as user tasks and a separator. For example:

Page 31: Taskbar - Nativeaz12722.vo.msecnd.net/windows7trainingcourse1-0... · Lab 4 The consolidation of features into the new taskbar user interface is designed to provide a cleaner look

Lab

31

Figure 16

The application’s jump list contains custom destinations, user tasks, and taskbar tasks

44. Click the user tasks and ensure that the application launches with the specified command line

argument as per the lab instructions.

45. Click the destinations in the custom category and ensure that the application launches with the

appropriate command line argument (/HandleDocument).

46. When you’re done, click Clear Associations to remove any traces of the application’s file type

association from the Windows Registry. (This operation requires administrative privileges.)

Summary

In this lab, you have experimented with the Windows 7 Taskbar APIs and integrated a sample

application with the Windows 7 Taskbar. You have seen how easy it is to provide relevant progress and

status information from the taskbar button using progress bars and overlay icons, how to quickly access

common tasks and destinations using jump lists, how to customize thumbnails and live previews for

greater flexibility over what is shown in the application’s thumbnail, and how to provide multiple

taskbar buttons with custom thumbnails and live previews for a TDI application.

Integrating a production-quality application with the Windows 7 Taskbar might require slightly more

work than you have done in this lab, but you are now sufficiently prepared to begin this quest on your

own.