Displaying progress in the Windows 7 Taskbar

I admit, this is a bit out of date. I’m not using Windows 8 yet. But if anybody still needs to know how to display progress in the Windows 7 Taskbar, read on to find out how easy it is.

Again, the source, for this and a whole bunch of other stuff, is here: RomyView.zip

I added this to my base Form class, so it is then inherited by my base Dialog class, and all derived dialogs. (Because the typical place to display progress is a dialog.)

  1. /// <summary>Display progress in the Windows 7 TaskBar.</summary>
  2. /// <remarks>Be sure to call this with 100%, to <b>remove</b> the
  3. /// progress bar when done.</remarks>
  4. /// <param name=”percentage”>The percentage to display.</param>
  5. protected virtual void DisplayProgressOnTaskbar(double percentage)
  6. {
  7.     if (!this.Disposing && !this.IsDisposed)
  8.     {
  9.         TaskbarList.SetProgressValue(this.Handle, percentage, 100D);
  10.  
  11.         if (percentage >= 100D)
  12.             TaskbarList.SetProgressState(this.Handle, TBPFLAG.TBPF_NOPROGRESS);
  13.     }
  14. }

 

So what’s a TaskbarList? Well, that’s just my class that wraps the Windows ITaskbarList3. It’s a COM interface that’s implemented by the Windows shell. All we need to do is declare it properly, then we can call the Windows implementation and have it do our bidding, just like any Windows API through pinvoke. Here’s the full source of my wrapper class.

  1. namespace System.Runtime.InteropServices.ComTypes
  2. {
  3.     /// <summary>Interacts with the Windows 7 extended TaskBar through the
  4.     /// Windows ITaskbarList3 CLSID_TaskbarList implementation.</summary>
  5.     public static class TaskbarList
  6.     {
  7.         #region Fields
  8.  
  9.         private static Lazy<bool> supported = new Lazy<bool>(() => System.Environment.OSVersion.Version >= new Version(6, 1));
  10.  
  11.         private static Lazy<ITaskbarList3> taskbar = new Lazy<ITaskbarList3>(() => (ITaskbarList3)new CLSID_TaskbarList());
  12.  
  13.         #endregion Fields
  14.  
  15.         #region Properties
  16.  
  17.         public static bool Supported
  18.         {
  19.             get { return TaskbarList.supported.Value; }
  20.         }
  21.  
  22.         internal static ITaskbarList3 Taskbar
  23.         {
  24.             get { return TaskbarList.taskbar.Value; }
  25.         }
  26.  
  27.         #endregion Properties
  28.  
  29.         #region Methods
  30.  
  31.         #region Public Methods
  32.  
  33.         public static void MarkFullscreenWindow(IntPtr hwnd, bool fullScreen)
  34.         {
  35.             if (Supported && hwnd != IntPtr.Zero)
  36.                 TaskbarList.Taskbar.MarkFullscreenWindow(hwnd, fullScreen ? 1 : 0);
  37.         }
  38.  
  39.         public static void SetProgressState(IntPtr hwnd, TBPFLAG state)
  40.         {
  41.             if (Supported && hwnd != IntPtr.Zero)
  42.                 TaskbarList.Taskbar.SetProgressState(hwnd, state);
  43.         }
  44.  
  45.         public static void SetProgressValue(IntPtr hwnd, double value, double max)
  46.         {
  47.             if (Supported && hwnd != IntPtr.Zero)
  48.                 TaskbarList.Taskbar.SetProgressValue(hwnd, (ulong)value, (ulong)max);
  49.         }
  50.  
  51.         #endregion Public Methods
  52.  
  53.         #endregion Methods
  54.  
  55.         #region Nested Classes
  56.  
  57.         [ClassInterface(ClassInterfaceType.None),
  58.         ComImport, Guid(“56FDF344-FD6D-11d0-958A-006097C9A090”)]
  59.         private class CLSID_TaskbarList { }
  60.  
  61.         #endregion Nested Classes
  62.     }
  63.  
  64.     /// <summary>Extends ITaskbarList2 by exposing methods that support the unified launching and switching
  65.     /// taskbar button functionality added in Windows 7. This functionality includes thumbnail representations
  66.     /// and switch targets based on individual tabs in a tabbed application, thumbnail toolbars, notification
  67.     /// and status overlays, and progress indicators.</summary>
  68.     [ComImport, Guid(“ea1afb91-9e28-4b86-90e9-9e9f8a5eefaf”),
  69.     InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
  70.     internal interface ITaskbarList3
  71.     {
  72.         // ITaskbarList
  73.  
  74.         /// <summary>Initializes the taskbar list object. This method must be
  75.         /// called before any other ITaskbarList methods can be called.</summary>
  76.         void HrInit();
  77.  
  78.         /// <summary>Adds an item to the taskbar.</summary>
  79.         /// <param name=”hWnd”>A handle to the window to be
  80.         /// added to the taskbar.</param>
  81.         void AddTab(IntPtr hWnd);
  82.  
  83.         /// <summary>Deletes an item from the taskbar.</summary>
  84.         /// <param name=”hWnd”>A handle to the window to be deleted
  85.         /// from the taskbar.</param>
  86.         void DeleteTab(IntPtr hWnd);
  87.  
  88.         /// <summary>Activates an item on the taskbar. The window is not actually activated;
  89.         /// the window’s item on the taskbar is merely displayed as active.</summary>
  90.         /// <param name=”hWnd”>A handle to the window on the taskbar to be displayed as active.</param>
  91.         void ActivateTab(IntPtr hWnd);
  92.  
  93.         /// <summary>Marks a taskbar item as active but does not visually activate it.</summary>
  94.         /// <param name=”hWnd”>A handle to the window to be marked as active.</param>
  95.         void SetActiveAlt(IntPtr hWnd);
  96.         // ITaskbarList2
  97.  
  98.         /// <summary>Marks a window as full-screen</summary>
  99.         /// <param name=”hWnd”></param>
  100.         /// <param name=”fFullscreen”></param>
  101.         void MarkFullscreenWindow(IntPtr hWnd, int fFullscreen);
  102.  
  103.         /// <summary>Displays or updates a progress bar hosted in a taskbar button to show
  104.         /// the specific percentage completed of the full operation.</summary>
  105.         /// <param name=”hWnd”>The handle of the window whose associated taskbar button is being used as
  106.         /// a progress indicator.</param>
  107.         /// <param name=”ullCompleted”>An application-defined value that indicates the proportion of the
  108.         /// operation that has been completed at the time the method is called.</param>
  109.         /// <param name=”ullTotal”>An application-defined value that specifies the value ullCompleted will
  110.         /// have when the operation is complete.</param>
  111.         void SetProgressValue(IntPtr hWnd, ulong ullCompleted, ulong ullTotal);
  112.  
  113.         /// <summary>Sets the type and state of the progress indicator displayed on a taskbar button.</summary>
  114.         /// <param name=”hWnd”>The handle of the window in which the progress of an operation is being
  115.         /// shown. This window’s associated taskbar button will display the progress bar.</param>
  116.         /// <param name=”tbpFlags”>Flags that control the current state of the progress button. Specify
  117.         /// only one of the following flags; all states are mutually exclusive of all others.</param>
  118.         void SetProgressState(IntPtr hWnd, TBPFLAG tbpFlags);
  119.  
  120.         /// <summary>Informs the taskbar that a new tab or document thumbnail has been provided for
  121.         /// display in an application’s taskbar group flyout.</summary>
  122.         /// <param name=”hWndTab”>Handle of the tab or document window. This value is required and cannot
  123.         /// be NULL.</param>
  124.         /// <param name=”hWndMDI”>Handle of the application’s main window. This value tells the taskbar
  125.         /// which application’s preview group to attach the new thumbnail to. This value is required and
  126.         /// cannot be NULL.</param>
  127.         void RegisterTab(IntPtr hWndTab, IntPtr hWndMDI);
  128.  
  129.         /// <summary>Removes a thumbnail from an application’s preview group when that tab or document is closed in the application.</summary>
  130.         /// <param name=”hWndTab”>The handle of the tab window whose thumbnail is being removed. This is the same
  131.         /// value with which the thumbnail was registered as part the group through ITaskbarList3::RegisterTab.
  132.         /// This value is required and cannot be NULL.</param>
  133.         void UnregisterTab(IntPtr hWndTab);
  134.  
  135.         /// <summary>Inserts a new thumbnail into a tabbed-document interface (TDI) or multiple-document
  136.         /// interface (MDI) application’s group flyout or moves an existing thumbnail to a new position in
  137.         /// the application’s group.</summary>
  138.         /// <param name=”hWndTab”>The handle of the tab window whose thumbnail is being placed. This value
  139.         /// is required, must already be registered through ITaskbarList3::RegisterTab, and cannot be NULL.</param>
  140.         /// <param name=”hWndInsertBefore”>The handle of the tab window whose thumbnail that hwndTab is
  141.         /// inserted to the left of. This handle must already be registered through ITaskbarList3::RegisterTab.
  142.         /// If this value is NULL, the new thumbnail is added to the end of the list.</param>
  143.         void SetTabOrder(IntPtr hWndTab, IntPtr hWndInsertBefore);
  144.  
  145.         /// <summary>Informs the taskbar that a tab or document window has been made the active window.</summary>
  146.         /// <param name=”hWndTab”>Handle of the active tab window. This handle must already be registered
  147.         /// through ITaskbarList3::RegisterTab. This value can be NULL if no tab is active.</param>
  148.         /// <param name=”hWndMDI”>Handle of the application’s main window. This value tells the taskbar
  149.         /// which group the thumbnail is a member of. This value is required and cannot be NULL.</param>
  150.         /// <param name=”tbatFlags”>None, one, or both of the following values that specify a thumbnail
  151.         /// and peek view to use in place of a representation of the specific tab or document.</param>
  152.         void SetTabActive(IntPtr hWndTab, IntPtr hWndMDI, UInt32 tbatFlags);
  153.  
  154.         /// <summary>Adds a thumbnail toolbar with a specified set of buttons to the thumbnail image of a window
  155.         /// in a taskbar button flyout.</summary>
  156.         /// <param name=”hWnd”>The handle of the window whose thumbnail representation will receive the toolbar.
  157.         /// This handle must belong to the calling process.</param>
  158.         /// <param name=”cButtons”>The number of buttons defined in the array pointed to by pButton. The maximum
  159.         /// number of buttons allowed is 7.</param>
  160.         /// <param name=”pButton”>A pointer to an array of THUMBBUTTON structures. Each THUMBBUTTON defines an
  161.         /// individual button to be added to the toolbar. Buttons cannot be added or deleted later, so this must
  162.         /// be the full defined set. Buttons also cannot be reordered, so their order in the array, which is the
  163.         /// order in which they are displayed left to right, will be their permanent order.</param>
  164.         void ThumbBarAddButtons(IntPtr hWnd, uint cButtons, [MarshalAs(UnmanagedType.LPArray)] THUMBBUTTON[] pButton);
  165.  
  166.         /// <summary>Shows, enables, disables, or hides buttons in a thumbnail toolbar as required by the
  167.         /// window’s current state. A thumbnail toolbar is a toolbar embedded in a thumbnail image of a window
  168.         /// in a taskbar button flyout.</summary>
  169.         /// <param name=”hWnd”>The handle of the window whose thumbnail representation contains the toolbar.</param>
  170.         /// <param name=”cButtons”>The number of buttons defined in the array pointed to by pButton.
  171.         /// The maximum number of buttons allowed is 7. This array contains only structures that represent existing buttons that are being updated.</param>
  172.         /// <param name=”pButton”>A pointer to an array of THUMBBUTTON structures. Each THUMBBUTTON defines an individual button. If the button already exists
  173.         /// (the iId value is already defined), then that existing button is updated with the information provided in the structure.</param>
  174.         void ThumbBarUpdateButtons(IntPtr hWnd, uint cButtons, [MarshalAs(UnmanagedType.LPArray)] THUMBBUTTON[] pButton);
  175.  
  176.         /// <summary>Specifies an image list that contains button images for a toolbar embedded in
  177.         /// a thumbnail image of a window in a taskbar button flyout.</summary>
  178.         /// <param name=”hWnd”>The handle of the window whose thumbnail representation contains the
  179.         /// toolbar to be updated. This handle must belong to the calling process.</param>
  180.         /// <param name=”himl”>The handle of the image list that contains all button images to be used in the toolbar.</param>
  181.         void ThumbBarSetImageList(IntPtr hWnd, IntPtr himl);
  182.  
  183.         /// <summary>Applies an overlay to a taskbar button to indicate application status or a notification to the user.</summary>
  184.         /// <param name=”hWnd”>The handle of the window whose associated taskbar button receives the overlay.
  185.         /// This handle must belong to a calling process associated with the button’s application and must be
  186.         /// a valid HWND or the call is ignored.</param>
  187.         /// <param name=”hIcon”>The handle of an icon to use as the overlay. This should be a small icon,
  188.         /// measuring 16×16 pixels at 96 dots per inch (dpi). If an overlay icon is already applied to the
  189.         /// taskbar button, that existing overlay is replaced.</param>
  190.         /// <param name=”pszDescription”>A pointer to a string that provides an alt text version of the
  191.         /// information conveyed by the overlay, for accessibility purposes.</param>
  192.         void SetOverlayIcon(IntPtr hWnd, IntPtr hIcon, string pszDescription);
  193.  
  194.         /// <summary>Specifies or updates the text of the tooltip that is displayed when the mouse
  195.         /// pointer rests on an individual preview thumbnail in a taskbar button flyout.</summary>
  196.         /// <param name=”hWnd”>The handle to the window whose thumbnail displays the tooltip.
  197.         /// This handle must belong to the calling process.</param>
  198.         /// <param name=”pszTip”>The pointer to the text to be displayed in the tooltip. This value can
  199.         /// be NULL, in which case the title of the window specified by hwnd is used as the tooltip.</param>
  200.         void SetThumbnailTooltip(IntPtr hWnd, string pszTip);
  201.  
  202.         /// <summary>Selects a portion of a window’s client area to display as that window’s thumbnail in the taskbar.</summary>
  203.         /// <param name=”hWnd”>The handle to a window represented in the taskbar.</param>
  204.         /// <param name=”prcClip”>A pointer to a RECT structure that specifies a selection within the window’s
  205.         /// client area, relative to the upper-left corner of that client area. To clear a clip that is already
  206.         /// in place and return to the default display of the thumbnail, set this parameter to NULL.</param>
  207.         void SetThumbnailClip(IntPtr hWnd, IntPtr prcClip);
  208.     }
  209.  
  210.     enum THUMBBUTTONMASK
  211.     {
  212.         THB_BITMAP = 0x1,
  213.         THB_ICON = 0x2,
  214.         THB_TOOLTIP = 0x4,
  215.         THB_FLAGS = 0x8
  216.     }
  217.  
  218.     public struct THUMBBUTTON
  219.     {
  220. #pragma warning disable 0169
  221.  
  222.         THUMBBUTTONMASK dwMask;
  223.         uint iId;
  224.         uint iBitmap;
  225.         IntPtr hIcon;
  226.  
  227.         [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
  228.         public string szTip;
  229.         THUMBBUTTONFLAGS dwFlags;
  230.  
  231. #pragma warning restore 0169
  232.     }
  233.  
  234.     [Flags]
  235.     enum THUMBBUTTONFLAGS
  236.     {
  237.         THBF_ENABLED = 0,
  238.         THBF_DISABLED = 0x1,
  239.         THBF_DISMISSONCLICK = 0x2,
  240.         THBF_NOBACKGROUND = 0x4,
  241.         THBF_HIDDEN = 0x8,
  242.         THBF_NONINTERACTIVE = 0x10
  243.     }
  244.  
  245.     [System.Diagnostics.CodeAnalysis.SuppressMessage(“Microsoft.Design”, “CA1027:MarkEnumsWithFlags”)]
  246.     public enum TBPFLAG
  247.     {
  248.         TBPF_NOPROGRESS = 0,
  249.         TBPF_INDETERMINATE = 0x1,
  250.         TBPF_NORMAL = 0x2,
  251.         TBPF_ERROR = 0x4,
  252.         TBPF_PAUSED = 0x8
  253.     }
  254. }

 

That’s all you need. I do a bit more from my video conversion progress dialogs; that is, I track all the conversions in progress, then the value I display as the Taskbar progress value is actually the instantaneous average of all the conversions in progress. But that’s beyond the scope if this article, and specific to my application anyway.

You now have what you need to display progress in the Taskbar. Enjoy.

Advertisements

About Jerome

I am a senior C# developer in Johannesburg, South Africa. I am also a recovering addict, who spent nearly eight years using methamphetamine. I write on my recovery blog about my lessons learned and sometimes give advice to others who have made similar mistakes, often from my viewpoint as an atheist, and I also write some C# programming articles on my programming blog.
This entry was posted in Programming and tagged , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s