Working with Taskbar Buttons in Windows

One of the most noticeable new features of the Windows 7 user interface is the new role of taskbar buttons, the graphic generally positioned at the bottom of the screen and showing the various applications that are currently running. In Windows 7 you can mix running applications with regularly used ones: You pin a program to the taskbar and its icon will remain there even when the application is not running.

These new taskbar buttons provide several ways to interact with an application. When the program is closed, you can see recent documents opened with it and see a menu with custom operations. When the program is running you can see a preview of its main windows (fully customizable), see status information, add extra buttons and commands, see the progress of a slow operation, and much more. I will not explore all of the features of taskbar buttons in Windows 7 here, while building an example called Win7Taskbar. I'll cover only the most common taskbar features48, while showing you how to use the related COM interfaces, which are part of the Windows Shell API.

The TaskList Interfaces

The ShlObj unit in Delphi 2010 defines the interfaces you can use to interact with the taskbar elements. There are actually four of these interfaces, each extending the previous one:

iTaskbarList = interface(iunknown) lTaskbarList2 = interface(lTaskbarList) ITaskbarList3 = interface(lTaskbarList2) lTaskbarList4 = interface(lTaskbarList3)

What you can do is to ask the system for an object implementing taskbar support and extract the various interfaces from it. As a helper you can use across projects, I've defined the following data structure: type

TTaskBarSupport = class public

TaskbarList: ITaskbarList; TaskbarList2: ITaskbarList2; TaskbarList3: ITaskbarList3; public constructor Create; procedure initTaskbarSupport; end;

The core of this class is in the method that creates the first COM objects and extracts its various interfaces49:

procedure TTaskBarSupport.InitTaskbarSupport; begin

TaskbarList := CreateComObject(CLSID_TaskbarList) as ITaskbarList;

48 For more examples and Delphi components you can use to simplify your interaction with the Windows 7 taskbar (also using older versions of Delphi) see Daniel Wischnewski blog on www.gumpi.com and (in particular) the post: http://www.gumpi.com/Blog/2009/ 09/27/DelphiControlsForWindows7StateUpdate.aspx

TaskbarList.HrInit;

Supports(TaskbarList, IID_ITaskbarList2, TaskbarList2); Supports(TaskbarList, IID_ITaskbarList3, TaskbarList3); end;

The TaskbarSupportUnit unit that defines this data structure creates a global instance of the class (called TaskBarSupport) in its initialization section, so it can be used directly within any program that includes the unit.

A Progress in the Taskbar

Now that we have a way to access to the taskbar interfaces, we can u —■

start implementing one of the new Windows 7 taskbar features, namely the display of progress bar information within a taskbar button, as you can see here on the right. This display is enabled by calling the

ITaskbarList3. SetProgressState method, while the actual progress is set by calling ITaskbarList3 .SetProgressVal ue. At the end you have to restore the progress state of the taskbar button to normal.

To make the user interface more intuitive, I've also added a ProgressBar component to the main form, moving it in sync with the taskbar button:

procedure TWin7TaskForm.btnProgressClick(Sender: TObject); var

I: Integer; FormHandle: THandle; begin

FormHandle := GetTaskBarEntryHandle; TaskbarSupport.TaskbarList3.SetProgressState(

FormHandle, TBPF_NORMAL); for I := 1 to 100 do begin

  1. Position := I;
  2. TaskbarList3.SetProgressValue(

FormHandle, I, 100); Application.ProcessMessages; Sleep (100); end;

TaskbarSupport.TaskbarList3.SetProgressState( FormHandle, TBPF_NOPROGRESS);

end;

49 Notice that the class ID of the COM object you pass to the CreateComObject function (in this case CLSID_TaskbarList) matches the interface ID of the interface the object implements (in this case IID_ITaskbarList). I find this approach confusing, as it doesn't follow standard COM development guidelines, but you can easily get used to it.

Notice that each of the calls requires the handle of the form visible in the taskbar. This can be either the main form or the application hidden form, depending on the VCL configuration:

function GetTaskBarEntryHandle: THandle; begin if not Application.MainFormOnTaskBar then

Result := Application.Handle else

Result := Application.MainForm.Handle;

Was this article helpful?

+3 0

Post a comment