Using Windows 7 Features In .NET
BootBlock | 13 February, 2009
One of the things I like with new versions of Windows is the possibility of new features for developers. Windows 7, like Vista, seems to include a few little things for us to play about with, namely the ITaskbarList3 Interface exposed by the Windows Shell.
ITaskbarList3
This is an Interface exposed by the Shell32.dll library that provides API functions for launching and adding switching taskbar button functionality, in addition to displaying thumbnail representations of tabs in a tabbed application, thumbnail toolbars, notification and status overlays, and – what we’re primarily interested in – progress indicators.
I installed the Windows 7 Beta a little while back as I was interested in making use of the progress indicator display exposed by the Shell in my own applications. For those that haven’t seen this in action, here’s a screen-grab of YouChoob‘s taskbar entry (the right-most icon) while downloading a video…
![]()
YouChoob has downloaded 50% of the video; as you can see, the downloaded percentage is reflected within the background of YouChoob’s taskbar entry. With the inclusion of the file at the end of this post, adding such a feature to your application is very easy.
ITaskbarList3::HrInit
This is the very first call you must make before any other calls detailed below. It initialises the Taskbar list object for use. There is no de-initialisation equivalent required at the end of program execution.
ITaskbarList3::SetProgressState(windowHandle, flag)
This allows you to specify which state your progress bar is in to Explorer. Here are the flags that can be passed, along with simplified descriptions of them.
- TBPF_NOPROGRESS: Stops displaying any progress information and returns the taskbar entry back to its default state. This should be called when your application’s progress has completed.
- TBPF_INDERTERMINATE: Displays a marquee that constantly cycles from left to right to show that the application is busy, but it has no estimation on how long it will be busy for.
- TBPF_NORMAL: Displays a standard green progress bar that goes from left to right, indicating a growing percentage.
- TBPF_ERROR: Displays a red progress bar that indicates an error has occurred.
- TBPF_PAUSED: Turns the progress bar yellow indicating that it is currently paused.
ITaskbarList3::SetProgressValue(windowHandle, currentProgress, totalProgress)
This is the method that will be getting called the most from your code as it updates the percentage (and ultimately the size of the bar) that is displayed on your application’s taskbar entry. The totalProgress parameter isn’t just a value from 0 to 100, but instead the raw value that denotes what value currentProgress must be for completion. For example, if you’re downloading a file that is 4,096 bytes in size, the totalProgress value will be 4,096 and currentProgress will be starting from 0 and working its way up to that 4,096 value.
Example Code Overview
What we’re going to be doing in the example code below is initialise the taskbar object, display an ever-increasing progress bar over the course of a 25 second time period, and then dismiss the progress bar when we’re finished. Examples for both VB.Net (WinForms) and C# (WPF) are listed.
SetProgressState and SetProgressValue requires the handle to the window that “owns” the progress information as their first parameter.
Example Code – VB.Net WinForms
‘ Create an instance of the TaskbarList for use.
Dim taskList As New TaskbarLib.TaskbarList
‘ Initialise the Tasklist so we can call its methods.
taskList.HrInit()
‘ Put the progress bar in its Normal state.
taskList.SetProgressState(myForm.Handle, TaskbarLib.TBPFLAG.TBPF_NORMAL)
‘ Do a standard 1 to 100 loop.
For index As Integer = 1 To 100
‘ Increment the progress bar by the new index value.
taskList.SetProgressValue(myForm.Handle, index, 100)
‘ Simulate some work being done by sleeping for 250ms.
Threading.Thread.Sleep(250)
Next
‘ Dismiss the progress bar from the taskbar entry now that we’re done with it.
taskList.SetProgressState(myForm.Handle, TaskbarLib.TBPFLAG.TBPF_NOPROGRESS)
Example Code – C# WPF
// Obtain a handle to our current window via the interop helper as WPF
// doesn’t natively expose the Handle property.
int handle = new System.Windows.Interop.WindowInteropHelper(this).Handle.ToInt32();
// Create an instance of the TaskbarList for use.
TaskbarLib.TaskbarList taskList = new TaskbarLib.TaskbarList();
// Initialise the Tasklist so we can call its methods.
taskList.HrInit();
// Put the progress bar in its Normal state.
taskList.SetProgressState(handle, TaskbarLib.TBPFLAG.TBPF_NORMAL);
‘ Do a standard 1 to 100 loop.
for (ulong index = 1; index < 100; index++) {
// Increment the progress bar by the new index value.
taskList.SetProgressValue(handle, index, 100);
// Simulate some work being done by sleeping for 250ms.
System.Threading.Thread.Sleep(250);
}
// Dismiss the progress bar from the taskbar entry now that we’re done with it.
taskList.SetProgressState(handle, TaskbarLib.TBPFLAG.TBPF_NOPROGRESS);
ITaskbarList3 In Previous Versions of Windows
Trying to use any of the ITaskbarList3 features in any version of Windows prior to 7 will result in a standard application crash. To get around this, you’ll need to check to make sure that your app is running in Windows 7 or higher before making any calls to the new interface. You could do this in various ways; here’s a simple method that returns a True or False determining if the current OS is Windows 7 or higher. The comparisons haven’t been short-circuited due to reasons of clarity.
Edit: Thanks to Larry Osterman, I’ve fixed a very stupid error in the version check code, although Larry’s posting goes a bit far saying that version checking “is hard”. My excuse is: I was pissing around in a language I’m not familiar with while not really paying attention to what I was writing (a bit of a dialogue was happening within the comments I was trying to keep up with). In addition, I’ve removed the VB code rather than rewrite it as WordPress is driving me mad when I want nicely formatted code.
// Simple example in C#; you can cache the return result or whatever should you so wish.internal bool SupportsTaskProgress() { if (System.Environment.OSVersion.Version.Major == 6) { return (System.Environment.OSVersion.Version.Minor >= 1); } else { return (System.Environment.OSVersion.Version.Major > 6); }
}
In Conclusion
Windows 7 provides a way for developers to display progress information while their application isn’t being directly displayed or is obscured. To begin using this functionality, extract the file below and reference it in your solution within Visual Studio.
Download: TaskbarLib.dll





C# newbie here!
What should I put in “myForm.Handle”‘s place?
Hey Tommo,
myForm is just the reference to the form that “owns” the progress bar, so just supply the variable that holds that reference. If you don’t have one, you could just do “this.Handle;” if your progress code resides in the form itself.
‘WpfApplication_iiNet.Window1′ does not contain a definition for ‘Hanlde’ and no extension method ‘Hanlde’ accepting a first argument of type ‘WpfApplication_iiNet.Window1′ could be found (are you missing a using directive or an assembly reference?)
Hehe. :>
Oh right it’s WPF – I assumed you were using standard WinForms. I can’t test this with TaskbarLib right now, but this should work:
IntPtr handle = new System.Windows.Interop.WindowInteropHelper(this).Handle;
Should have mentioned WPF >.<
Unfortunately, your code didn’t change the error.
Thanks for your lightening fast reply though
It seems to compile without any problems here, so I suspect there’s something fundamental (not) happening. WindowInteroptHelper seems to be available to all versions of WPF and it definately does have the .Handle property.
It’s not failing due to the typo that was in the example code (“Hanlde”) is it?
If you copy and paste the code above (“IntPtr handle = …”) and try and compile – what’s the exact error that it gives?
If you’ve got a skeleton project/solution, I’ll be happy to take a look at it if you can archive and upload it somewhere. Just for the record, I’m using Visual Studio 2008 SP1 with .NET 3.5 + SP1.
Here’s what it looks like in my editor:
http://img4.imageshack.us/img4/6695/windowinterophelperhand.png
lol I corrected the typo and the rror is gives hasn’t changed at all… like it’s ignoring the new code.
Screenshot added above.
Make sure you’re actually building/running the code – the C# editor is a bit rubbish in that it doesn’t necessarily update certain error messages immediately until a build has happened.
I agree with you there.
I removed .Handle and alas…
Here’s your code in the wild: http://z1zbca.bay.livefilestore.com/y1pQPF5081Z3iWcViFmDgBMiLgLsiA5S9yZE0M70gmNw2QTQYbCyg2sx3ihSJe3to1Fxnb_8ZfnuxNSiJjn0hoBsA/Capture.jpg
Oh! Errors #3 and #5 aren’t still there because the compiler isn’t able to compile the code due to the existing errors? Comment/fix all the other lines so only the “IntPtr handle = …” line remains and try re-building the solution.
I’ll try and use ITaskbarLib in WPF and see why it could be giving those errors…
OK, I’m a stupid arse. I completely forgot that the API call requires the handle to be an integer as opposed to an IntPtr, so what you want is:
int handle = new System.Windows.Interop.WindowInteropHelper(this).Handle.ToInt32();
Also: I managed to completely lock-up Windows 7! Woot!
Not sure how to handle #2 and #4 and #1 and #6 disappear magically when no other errors are present. I quote a friend, “WPF can be a bitch.”
It seems Windows 7 with Aero disabled (I’m running it in a virtual machine so Aero is a no-no
) completely dies after about five seconds if a WPF app is run.
But the ITaskbarLib stuff seems to work; I’ll edit the post above with a C# WPF example in a couple of minutes…
… OK, all done. Took a bit longer than I thought, but I’ve fully tested it within Windows 7 and it all works. Let me know how you get on!
Ha ha! Your example worked great! Thanks mate.
Awesome, that’s great to hear! Sorry about all the messing about – finally got there in the end, though!
Another comment!
I forgot to mention this in the original posting, but trying to call the Windows 7 progress stuff in anything lower than Windows 7 causes the app to go down in flames.
I did a little method that ensures Windows 7 or higher is available before calling the methods in the TaskbarLib; I’ll amend the post once I’ve had my widdle sleepy…
haha.. yes well that’s basically the story of my life. wall, wall, wall, wall … TA DA!!
I’m eagerly awaiting your amendments! ;D
BootBlock,
You can sleep in WPF the same way as WinForms. System.Threading.Thread.Sleep(int ms);
I forgot to add,
Is there any way you can add support for JumpLists?
Aaah – it seems Using/Imports in C# works differently than it does in VB. Thanks – example amended!
Windows 7 check example code is now in.
@Brent: I want to do a proper .Net assembly (with XML comments, built-in OS feature checking, etc), along with support for JumpLists and taskbar buttons. It probably would’ve been done by now if I could just work out how to properly access the ITaskbarList3 interface in .Net …
BootBlock,
You may want to check out: http://blogs.microsoft.co.il/blogs/sasha/archive/2009/02/12/windows-7-taskbar-apis.aspx
Please don’t use the version check that you just posted. When Microsoft comes out with a version of Windows with version 7.0, your application will break because the inner check will fail.
Only look for > 1 if the major version == 6.
[...] was wandering around the web the other day and ran into this post. In general I don’t have many issues with the post, until you get to the bottom of the [...]
@Larry: Oh, pants – good point! Bit embarrassing, that. Ahem. Thanks, all fixed now. I was meaning to originally edit it (too many lines for something so simple), but WordPress is such a nightmare with code that I generally avoid going back to edit code.
Thanks for the link-back, even though, yeah, it’s to show I made a dopey error.
Although in your post you recommend to check to see if the instantiated object is Null as a way of testing to see if the ITaskbarList3 feature is supported as opposed to the version check, but in Vista it isn’t Null even though of course it isn’t available.
Incidentally, as noted, the reason for the “untightened” code is for reasons of clarity. The above version check now reflects how I’d ordinarily write it. Except it wouldn’t be in C#, natch.
@Brent: Aah, yeah, the Vista Bridge. I gave it a look a bit back and it seemed interesting. It didn’t occurr to me that it might have been updated with new Windows 7 features. Will take a further look at it, thanks!
I’ve edited my original post and the above comment about 14 times; hopefully I haven’t screwed anything up.
Watching TV + Editing Code & Posts + Playing WoW = BAD.
If you want to do the check for functionality without an explicit version test you just need to call QueryInterface requesting ITaskBarList3. At least that’s what you’d do in native COM – I’ve no idea how you do it in the managed world but there must be a way.
Hi BootBlock,
in the C# WPF example above you use an int instead of an IntPtr which makes the sample crash on 64-bit versions of the OS. Is there any magic reason for using int for a handle that I don’t see?
Regards
@David Heffernan: I have no idea how to do that in .Net, but it’s good to know about QueryInterface – thanks for that.
@Ooh: The TaskbarLib.dll (and its IDL presumably) uses an int for the handle. I originally was passing an IntPtr (as that would seem logical) which it didn’t like, hence the big splat of comments above where I made a gimp of myself by passing the wrong data.
I can’t say I’ve seen an int passed as a handle since my VB6 days, so I’m not entirely sure what you’re supposed to do on x64 machines. Maybe an int is actually 64-bit on x64 hardware, I don’t really know.
Edit: Yep, just checked some compiler docs and it does indeed appear to be the case.
Your version check still looks wrong. Why not just check for version 6.1 or greater?
System.Environment.OSVersion.Version >= New Version(6, 1)
@Jonathan Allen: Wrong in what way?
> System.Environment.OSVersion.Version >= New Version(6, 1)
I didn’t know that Version could be used like that, although I suspect some people would use the version check multiple times and in that case I’d rather it didn’t go creating objects for every check (especially in the case of updating the progress value).
Then don’t make the check multiple times. If you think ” New Version(6, 1)” is expensive, then you don’t want to know what’s going on inside “Environment.get_OSVersion”.
I’m not. Others might be.
Hi again,
well int is still 32-bit on 64-bit hardware. That’s what IntPtr is good for: it’s the managed equivalent of handles and unmanaged pointers. So its size depends on the platform.
In the meantime I also got it regarding the TaskbarLib… I downloaded it and had a look at it in Reflector. And of course it is not 64-bit compatible because all window handles should have been imported as IntPtr. Can you contact the owners of the library?
It seems that marquee (TBPF_INDETERMINATE) works only if the previous state was TBPF_NOPROGRESS or TBPF_NORMAL.
can you implement ICustomDestinationList jumplists?