Introduction
This is a quick step by step guide to help all .NET developers to take advantage of the new features of Windows 7.
What you will need
- Visual Studio 2008 or 2010
- Windows API Code Pack for Microsoft .NET Framework (can be downloaded from http://code.msdn.microsoft.com/WindowsAPICodePack)
- .NET Framework 3.5 SP1 or higher.
- A Windows 7 machine.
Getting ready
You will need to compile the Windows API Code Pack DLLs. After extracting the WindowsAPICodePack.zip file, open the WindowsAPICodePack.sln located inside
the WindowsAPICodePack folder and Build the solution. This will produce the following DLLs:
- Core
- Shell (Note: this depends on the Core project)
You will need to add a reference to them in your applications.
Compatibility with different versions of Windows
The application will crash and exit if, for example, a feature exclusive to Windows 7 was called and it was running under Windows vista or Windows XP. So to prevent your application
from crashing and to ensure a level of compatibility with different versions of Windows, you will need to check for the current running version of Windows.
- Checking the shared Boolean properties
RunningOnWin7
, RunningOnVista
, and RunningOnXP
under MS.WindowsAPICodePack.Internal.CoreHelpers
,
you will need to add a reference to the WindowsAPICodePack\Core project source code after adding it to your solution or its DLL. - While using the
TaskbarManager
class, you will see it provides a simple Boolean property IsPlatformCompatible
,
you can use it to do a simple check before calling your code.
Now from here on, you can skip to any section of this article and continue learning about the features you like, as all of the following sections
of this article are independent from each other.
Jump lists
The right click menu of the application's icon in the task bar has a new feature called JumpLists. You will also see it in the application shortcuts in the Start menu.
You can add your own shortcuts in the menu and sort them in categories if you like. The shortcuts can point to anything like recent documents, frequently used documents,
and application functionality. It is very simple to use but there are a few points you need to know about it to successfully use it:
- The application must have a valid icon in the task bar, so you cannot use the load event, for example, to create the new instance of the jumplist.
- If you are going to add a file, you must ensure the file association relationship to your application, for example, to add a "file.abc",
you need to make sure the abc file type is associated with your application.
- You can add your items to the User Tasks or the Recent Sections of the jump list or you can create your own custom categories.
- To actually add the jumplist or update it, you need to call the
refresh()
method in the new jumplist instance you create.
To use the JumpLists in your own applications:
- Add a reference to Microsoft.WindowsAPICodePack.Shell and Microsoft.WindowsAPICodePack.
- You will be using the
Microsoft.WindowsAPICodePack.Taskbar
and Microsoft.WindowsAPICodePack.Shell
namespaces. - Create an instance of the
JumpList
class after the window has been created, that can be done using the shown
event
in WinForms or the loaded
event in WPF. - You can add different items to the jump list in User Tasks or Recent Sections, or create you own custom category.
- Display the jump list by calling the
Refresh
method.
VB
Dim JList As JumpList
JList = JumpList.CreateJumpList()
JList.ClearAllUserTasks()
Dim Link0 As New JumpListLink("cmd.exe", "Cmd") With {.IconReference =
New IconReference("cmd.exe", 0)}
Dim Link1 As New JumpListLink("Calc.exe", "Calculator") With {.IconReference =
New IconReference("Calc.exe", 0)}
JList.AddUserTasks(Link0)
JList.AddUserTasks(New JumpListSeparator())
JList.AddUserTasks(Link1)
Dim Link2 As New JumpListLink("Notepad.exe", "Notepad") With {.IconReference =
New IconReference("Notepad.exe", 0)}
Dim Category As New JumpListCustomCategory("New Category 1")
Category.AddJumpListItems(Link2)
JList.AddCustomCategories(Category)
Dim Link3 As New JumpListLink("mspaint.exe", "Paint") With {.IconReference =
New IconReference("mspaint.exe", 0)}
Category.AddJumpListItems(Link3)
JList.KnownCategoryToDisplay = JumpListKnownCategoryType.Frequent
JList.Refresh()
C#
JumpList JList = default(JumpList);
JList = JumpList.CreateJumpList();
JList.ClearAllUserTasks();
JumpListLink Link0 = new JumpListLink("cmd.exe", "Cmd") { IconReference =
new IconReference("cmd.exe", 0) };
JumpListLink Link1 = new JumpListLink("Calc.exe", "Calculator") {
IconReference = new IconReference("Calc.exe", 0) };
JList.AddUserTasks(Link0);
JList.AddUserTasks(new JumpListSeparator());
JList.AddUserTasks(Link1);
JumpListLink Link2 = new JumpListLink("Notepad.exe", "Notepad") {
IconReference = new IconReference("Notepad.exe", 0) };
JumpListCustomCategory Category = new JumpListCustomCategory(
"New Category 1");
Category.AddJumpListItems(Link2);
JList.AddCustomCategories(Category);
JumpListLink Link3 = new JumpListLink("mspaint.exe", "Paint") {
IconReference = new IconReference("mspaint.exe", 0) };
Category.AddJumpListItems(Link3);
JList.KnownCategoryToDisplay = JumpListKnownCategoryType.Frequent;
JList.Refresh();
The last thing to note about the jumplists is that you can add commands to the jumplists that will execute in your running application. For example,
to add a "play song" or "new document", there's no simplified or direct way to do that in the API code pack or in the .NET
Framework. To add a command, you can add an item to the jump list that points back to your application and add a command line argument that will be passed to your application.
This will run another instance of your application and pass the command line argument to it. What you will need to do next is if a command was passed to the application,
it will need to send it to the first instance of the application, and that's called inter-process communication, or IPC, and there are multiple ways to implement this.
For instance, you could use memory-mapped files, TCP/IP sockets, or named kernel objects. One option is to use named pipes, which provides a straightforward
way to send messages without changing the security or firewall settings, but that's another subject outside the scope of this article. I'm sure you will find
many articles here in CodeProject that covers this.
Icon overlay
This new feature of Windows7 will give you the ability to update the icon of the application itself shown in the task bar. With overlays, you can use
it to indicate a status change or an error. For example, you can do that by overlaying a smaller icon and it will be placed in the lower right corner
of the main window icon to indicate the status of the application.
To use the Task Bar Icon Overlay, you need to:
- Add a reference to Microsoft.WindowsAPICodePack.Shell and Microsoft.WindowsAPICodePack.
- You will be using the
Microsoft.WindowsAPICodePack.Taskbar
and Microsoft.WindowsAPICodePack.Shell
namespaces. - To change the overlay icon:
TaskbarManager.Instance.SetOverlayIcon(Icon, "accessibility text")
The SetOverlayIcon
method accepts a System.Drawing.Icon
object and a text for accessibility.
I'd like to mention the StockIcon
class in the API code pack. This class can be used to return an icon from the system icons.
The StockIcon
constructor accepts four parameters:
- An
enum
value to a very large collection of stock icons. - The icon size, this will not change the size of the icon on the overlay but rather the returned icon itself as some icons have more than 1 bitmap for different sizes.
IsLink
is a Boolean that if true will display a small shortcut arrow on the return icon.IsSelected
is a Boolean that dimes the returned icon a bit to indicate a selected state.
VB
Dim ID As StockIconIdentifier =StockIconIdentifier.Shield
Dim Size As StockIconSizes =ShellSize
Dim SelectedIcon As New Microsoft.WindowsAPICodePack.Shell.StockIcon(ID, Size, false,
false)
TaskbarManager.Instance.SetOverlayIcon(Me.Handle, SelectedIcon.Icon, "Icon Name")
C#
StockIconIdentifier ID = StockIconIdentifier.Shield;
StockIconSizes Size = ShellSize;
Microsoft.WindowsAPICodePack.Shell.StockIcon SelectedIcon =
new Microsoft.WindowsAPICodePack.Shell.StockIcon(ID, Size, false, false);
TaskbarManager.Instance.SetOverlayIcon(this.Handle, SelectedIcon.Icon, "Icon Name");
Progress bar
The area for each application icon in the Windows 7 task bar provides new functionality. If you download a file using Internet Explorer 8, you will notice the icon
background can act as a progress bar.
To use the Task Bar Progress Bar, you need to:
- Add a reference to Microsoft.WindowsAPICodePack.Shell and Microsoft.WindowsAPICodePack.
- You will be using the
Microsoft.WindowsAPICodePack.Taskbar
namespace. - To set the progress bar value:
TaskbarManager.Instance.SetProgressValue(Value, Maximum , handle )
SetProgressValue
accepts the value and the max value and a handle to the window to show the progressbar.
- To change the state of the progress bar:
TaskbarManager.Instance.SetProgressState
SetProgressState
accepts a single enum parameter (TaskbarProgressBarState
) and it has these values:
NoProgress
: No progress is displayed.Indeterminate
: The progress is indeterminate (marquee).Normal
: Normal progress is displayed (Green).Error
: Error progress bar (Red).Paused
: Paused progress bar (Yellow). Note that all it does is change the color to yellow; if you change the value of the progress bar it will move and it will stay yellow.
Also note that if you change the value of the progress bar after setting the state to NoProgress
or Indeterminate
, the progress bar
will go back to normal state automatically.
Very important point: Both methods for setting the value or changing the state of the progress bar has two overloads: the second
one lets you select the window you want to show the progress bar on. If you didn't set the window handle, the progress bar will be shown on the main
application icon in the task bar and not on the open window with the progress bar.
Another effect of not passing the window handle is when the progress window closes, the progress bar will not automatically clear from the main application icon,
and you will have to clear it manually. To understand it clearly, right click the task bar > Properties > and set the task bar buttons to never combine,
and then experiment with the source code provided with this article to see the difference between passing the window handle or not.
Thumbnail toolbars
Thumbnail toolbars enable users to access the application’s functionality even when the application is not in focus, or the application window
is behind another window making it not visible on the screen. It enables you to access the application without the need to switch to it and make
it the active window. Open "Windows Media Player" to see a very good example of the thumbnail toolbars functionality.
To be able to add buttons to thumbnail toolbars, there are some rules to follow:
- You are limited by up to 7 buttons with the size of 16 x 16 pixels.
- You can only hide a button after it has been added, you cannot add or delete buttons after the task bar icon is shown.
To add thumbnail toolbars, you need to:
- Create an instance of the buttons you would like to add using the
ThumbnailToolbarButton
. - Add the button to the thumbnail toolbars by calling the
TaskbarManager.Instance.ThumbnailToolbars.AddButtons
method.
This method will take the window handle you like to add the ThumbnailToolbar buttons to and the button instance you like to add.
VB
Dim B1Icon As Icon = New StockIcon(StockIconIdentifier.Shield).Icon
Dim B2Icon As Icon = New StockIcon(StockIconIdentifier.Users).Icon
Dim B3Icon As Icon = New StockIcon(StockIconIdentifier.Help).Icon
Dim button1 As New ThumbnailToolbarButton(B1Icon, "First Button")
Dim WithEvents button2 As New ThumbnailToolbarButton(B2Icon, "Second Button")
Dim WithEvents button3 As New ThumbnailToolbarButton(B3Icon, "Third Button")
AddHandler button1.Click, AddressOf Button_Click
AddHandler button2.Click, AddressOf Button_Click
AddHandler button3.Click, AddressOf Button_Click
button1.Visible = Not button1.Visible
button2.Enabled = Not button2.Enabled
button3.Tooltip = txtTooltip.Text
Sub Button_Click(ByVal sender As Object, ByVal e As ThumbnailButtonClickedEventArgs)
Me.EventsList.Items.Add(e.ThumbnailButton.Tooltip & " Clicked")
End Sub
C#
Icon B1Icon = new StockIcon(StockIconIdentifier.Shield).Icon;
Icon B2Icon = new StockIcon(StockIconIdentifier.Users).Icon;
Icon B3Icon = new StockIcon(StockIconIdentifier.Help).Icon;
ThumbnailToolbarButton button1 =
new Microsoft.WindowsAPICodePack.Taskbar.ThumbnailToolbarButton (B1Icon,
"First Button");
ThumbnailToolbarButton button2 =
new Microsoft.WindowsAPICodePack.Taskbar.ThumbnailToolbarButton(B2Icon,
"Second Button");
ThumbnailToolbarButton button3 =
new Microsoft.WindowsAPICodePack.Taskbar.ThumbnailToolbarButton(B3Icon,
"Third Button");
button1.Click += button_Click;
button2.Click += button_Click;
button3.Click += button_Click;
TaskbarManager.Instance.ThumbnailToolbars.AddButtons(this.Handle,button1,button2,button3);
button1.Visible = !button1.Visible;
button2.Enabled = !button2.Enabled;
button3.Tooltip = txtTooltip.Text;
Network management
You can use it to know if the computer your application is working on has a network connection or not.
If it is connected to the internet, retrieve the network name. If you are on a domain, get the NetworkID, and more.
To make use of the network management APIs, you need to:
- Add a reference to Microsoft.WindowsAPICodePack, the Core project only.
- You will be using the
Microsoft.WindowsAPICodePack.Net
namespace. - To list all the available networks, call the
NetworkListManager.GetNetworks()
method. It accepts an enum parameter:
All
: return all networks, connected and disconnected.Connected
: return only the connected networks.Disconnected
: return only the disconnected networks.
- You can enumerate through the returned networks list to get information about all the networks, information like the network ID (that is the GUID
of the network interface), the network name, the network description, if it is a domain or not, the time this network connection was created, and the time it was
connected, and all the available connections under this network.
VB
Dim networks As NetworkCollection = _
NetworkListManager.GetNetworks(NetworkConnectivityLevels.All)
For Each n As Network In networks
Dim network As Network = n
txtName.Text = network.Name
txtDecription.Text = network.Description
txtDomainType.Text = network.DomainType.ToString()
chkIsConnected.Checked = network.IsConnected
chInternet.Checked = network.IsConnectedToInternet
txtCategory.Text = network.Category.ToString()
txtCreatedTime.Text = network.CreatedTime.ToString()
txtConnectedTime.Text = network.ConnectedTime.ToString()
txtConnectivity.Text = network.Connectivity.ToString()
Dim Connections As NetworkConnectionCollection = network.Connections
For Each Connection As NetworkConnection In network.Connections
lstConnections.Items.Add("ConnectionID: " &
Connection.ConnectionId.ToString)
lstConnections.Items.Add("Adapter ID:: " & Connection.AdapterId.ToString)
Next
End If
Next
C#
NetworkCollection networks =
NetworkListManager.GetNetworks(NetworkConnectivityLevels.All);
foreach (Network n in networks) {
Network network = n;
txtName.Text = network.Name;
txtDecription.Text = network.Description;
txtDomainType.Text = network.DomainType.ToString();
chkIsConnected.Checked = network.IsConnected;
chInternet.Checked = network.IsConnectedToInternet;
txtCategory.Text = network.Category.ToString();
txtCreatedTime.Text = network.CreatedTime.ToString();
txtConnectedTime.Text = network.ConnectedTime.ToString();
txtConnectivity.Text = network.Connectivity.ToString();
NetworkConnectionCollection Connections = network.Connections;
foreach (NetworkConnection Connection in network.Connections) {
lstConnections.Items.Add("ConnectionID: " +
Connection.ConnectionId.ToString);
lstConnections.Items.Add("Adapter ID:: " +
Connection.AdapterId.ToString);
}
}