Solved

vb.net programming the Windows7 taskbar icons

Posted on 2015-01-20
6
354 Views
Last Modified: 2015-01-24
Hi experts.  Without using WPF or Windows-API-Code-Pack-1.1, can anyone please advise if it is possible to add right click commands to the VB programs icons  on the taskbar?    Sort of like the system tray but using the taskbar icons?  If so please point me in the right direction for sample code.   The only thing I can find is Windows-API-Code-Pack-1.1  which is unsupported and may not last past Windows 7.  Many Thanks
0
Comment
Question by:PNRT
  • 3
  • 2
6 Comments
 
LVL 14

Expert Comment

by:brendanmeyer
ID: 40561217
Set objAppl = CreateObject("Shell.Application")

Sub Pin(Path, File)
	If objFSO.FileExists(Path & "\" & File) Then
		Set objFolder = objAppl.Namespace(Path)
		Set objFolderItem = objFolder.ParseName(File)
		Set colVerbs = objFolderItem.Verbs
		For Each objVerb in colVerbs
			If Replace(objVerb.name, "&", "") = "Pin to Taskbar" Then objVerb.DoIt
		Next
	End If
End Sub

Open in new window


vbs code though\
but you may be a starting point
0
 
LVL 1

Author Comment

by:PNRT
ID: 40561660
Hi - Thanks for the reply.  Apologies and please correct me if I'm wrong but doesn't this just pin to the taskbar?
I was looking for the ability to add commands to the right click function of the icon in the taskbar
0
 
LVL 32

Accepted Solution

by:
it_saige earned 500 total points
ID: 40562204
You can still use the Windows API (but it's not the perfect answer for all Windows versions):
Imports System.Runtime.InteropServices

Public Class Form1
#Region "Win32 API Stuff"
	' Define the Win32 API methods we are going to use
	<DllImport("user32.dll")> _
	Private Shared Function GetSystemMenu(ByVal hWnd As IntPtr, ByVal bRevert As Boolean) As IntPtr
	End Function

	<DllImport("user32.dll")> _
	Private Shared Function InsertMenu(ByVal hMenu As IntPtr, ByVal wPosition As Int32, ByVal wFlags As Int32, ByVal wIDNewItem As Int32, ByVal lpNewItem As String) As Boolean
	End Function

	''' Define our Constants we will use
	Public Const WM_SYSCOMMAND As Int32 = &H112
	Public Const MF_SEPARATOR As Int32 = &H800
	Public Const MF_BYPOSITION As Int32 = &H400
	Public Const MF_STRING As Int32 = &H0
#End Region

	Public Const SettingsMenuID As Int32 = 1000
	Public Const AboutMenuID As Int32 = 1001

	Private Sub OnLoad(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load
		' Get the Handle for the Forms System Menu
		Dim hMenu As IntPtr = GetSystemMenu(Handle, False)

		' Create our new System Menu items just before the Close menu item
		InsertMenu(hMenu, 5, MF_BYPOSITION Or MF_SEPARATOR, 0, String.Empty)
		' <-- Add a menu seperator
		InsertMenu(hMenu, 6, MF_BYPOSITION, SettingsMenuID, "Settings...")
		InsertMenu(hMenu, 7, MF_BYPOSITION, AboutMenuID, "About...")
	End Sub

	Protected Overloads Overrides Sub WndProc(ByRef m As Message)
		' Check if a System Command has been executed
		If m.Msg = WM_SYSCOMMAND Then
			' Execute the appropriate code for the System Menu item that was clicked
			Select Case m.WParam.ToInt32()
				Case SettingsMenuID
					MessageBox.Show("Settings menu was clicked")
					Exit Select
				Case AboutMenuID
					MessageBox.Show("About menu was clicked")
					Exit Select
			End Select
		End If

		MyBase.WndProc(m)
	End Sub
End Class

Open in new window

Produces the following output -Right-clicking on the application menubar.As you can see by the previous image, the menubar in the the application shows our menu (it displays equally the same on the taskbar icon for Windows Vista, Windows Server 2008 [non-R2], Windows Server 2003, Windows XP and Windows 2000).  For example -Right-clicking on the windows taskbar of a Windows Vista operating system.Right-clicking on the windows taskbar of a Windows Server 2008 [Non-R2].Right-clicking on the windows taskbar of a Windows Server 2003 operating system.Now why do I stipulate that it is not the perfect solution for all windows versions.  Because of the changes that Microsoft made to the shell interface in Windows 7 and above.  If we right-click the same application in Windows 7, we get this -Standard right-click on a taskbar icon in Windows 7.We can subvert this behaviour by holding the Shift key while right-clicking (this will give us the standard Micosoft context menu) -Holding Shift Right-Click in Windows 7.To make life easier on the developer Micorosoft introduced the Taskbar Extensions library (referenced in the Windows API Code Pack).

Oh, by the way, when we click on the menu items on the context menu.  We get a message box stating that the menu was clicked:Capture.JPG
-saige-
0
Highfive Gives IT Their Time Back

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 
LVL 1

Author Comment

by:PNRT
ID: 40563821
Many thanks indeed, this is an excellent response.    Just one thing.  You mentioned the API Code pack.  This looked perfect for what I needed but I was worried about the fact that it was not supported and that it seemed to be very Windows 7 oriented.   What is your view on it?  Would it be OK with Windows 8.1, Is it stable?    I am mainly interested in Windows 7 and Windows 8  

Many Thanks again for your help
0
 
LVL 32

Expert Comment

by:it_saige
ID: 40565503
I'm not finding anywhere that indicates that the Windows API Pack is not supported.  As for it's availability beyond Windows 7.  Looking at the latest version of Windows (Windows 10), the GUI still supports the same functionality and features as Windows 7.  Also, yes there is the Metro Interface on Windows 8/8.1 but that only accounts for a part of the user experience.  The desktop still uses the same elements introduced in Windows 7.Standard right-click on Windows 8/8.1 Desktop Taskbar Icon.Holding Shift Right-Click on Windows 8/8.1 Dekstop Taskbar Icon.That being said, while you may design this for Windows 7 (and for the time being, 8, 8.1 and 10), this should not preclude you from considering the kernels that were used for Vista, XP, 2000 and 2003.  You can essentially have your cake and eat it too.

Here is one method (using the SendMessage API to send a Registered Message based on the Code Project by Ahmed Said):

1. Using the [url="https://visualstudiogallery.msdn.microsoft.com/27077b70-9dad-4c64-adcf-c7cf6bc9970c

NuGet Package Manager extension[/url] I installed the WindowsAPIPack Core and Extensions."]Right-click on the References in your Project and choose 'Manage NuGet Packages'Choose the Online section and search for 'Windows 7 API Code'.Select the package and click the 'Install' button.Open the Package Manager Console window.In the 'Package Manager Console' type 'Install-Package winapicp' and press enter.Verify the installation and addition of the references to the project.

2. Make your project a 'Single Instance' application.

Right-click on the project and choose 'Properties'.On the Application tab, check the box for 'Make single instance application'.

3. Add the Native Methods for this example.

Add a class called 'NativeMethods.vb' to your project and place the following into the code file:
Imports System.Runtime.InteropServices

Public Class NativeMethods
	''' Define our Constants we will use
	Public Const WM_SYSCOMMAND As Int32 = &H112
	Public Const MF_SEPARATOR As Int32 = &H800
	Public Const MF_BYPOSITION As Int32 = &H400
	Public Const MF_STRING As Int32 = &H0
	Public Const MF_SETTINGS As Int32 = 1000
	Public Const MF_ABOUT As Int32 = 1001

	<DllImport("user32.dll")> _
	Public Shared Function FindWindow(ByVal lpClassName As String, ByVal lpWindowName As String) As IntPtr
	End Function

	<DllImport("user32.dll")> _
	Public Shared Function GetSystemMenu(ByVal hWnd As IntPtr, ByVal bRevert As Boolean) As IntPtr
	End Function

	<DllImport("user32.dll")> _
	Public Shared Function InsertMenu(ByVal hMenu As IntPtr, ByVal wPosition As Int32, ByVal wFlags As Int32, ByVal wIDNewItem As Int32, ByVal lpNewItem As String) As Boolean
	End Function

	<DllImport("user32.dll")> _
	Public Shared Function RegisterWindowMessage(ByVal msgName As String) As Integer
	End Function

	<DllImport("user32.dll", CharSet:=CharSet.Auto)> _
	Public Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal wMsg As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer
	End Function
End Class

Open in new window

4. Create the Global settings for this example.

Add a module to your project named 'Globals.vb' and add the following to the code file:
Imports Microsoft.WindowsAPICodePack.Shell
Imports Microsoft.WindowsAPICodePack.Taskbar
Imports System.IO

Module Globals
	Public Property IsUsingStandardAPIMenu() As Boolean = False
	Public Property Windows7APIMenu() As JumpList
	Public ShowAboutArg As Integer = NativeMethods.RegisterWindowMessage("JumpList.ShowAboutArg")
	Public ShowSettingsArg As Integer = NativeMethods.RegisterWindowMessage("JumpList.ShowSettingsArg")

	Public Sub LoadStandardAPIMenu(ByVal Handle As IntPtr)
		' Get the Handle for the Forms System Menu
		Dim hMenu As IntPtr = NativeMethods.GetSystemMenu(Handle, False)

		' Create our new System Menu items just before the Close menu item
		NativeMethods.InsertMenu(hMenu, 5, NativeMethods.MF_BYPOSITION Or NativeMethods.MF_SEPARATOR, 0, String.Empty)
		' <-- Add a menu seperator
		NativeMethods.InsertMenu(hMenu, 6, NativeMethods.MF_BYPOSITION, NativeMethods.MF_SETTINGS, "Settings...")
		NativeMethods.InsertMenu(hMenu, 7, NativeMethods.MF_BYPOSITION, NativeMethods.MF_ABOUT, "About...")
		IsUsingStandardAPIMenu = True
	End Sub

	Public Sub LoadWindows7APIMenu(ByVal Handle As IntPtr)
		Dim list As JumpList = JumpList.CreateJumpListForIndividualWindow(TaskbarManager.Instance.ApplicationId, Handle)
		Dim current As FileInfo = New FileInfo(Application.ExecutablePath())
		list.ClearAllUserTasks()
		list.AddCustomCategories(New JumpListCustomCategory("Actions"))
		list.AddUserTasks(New JumpListLink(current.FullName, "Settings...") With {.Arguments = String.Format("Handle={0}|Command={1}", Handle, ShowSettingsArg), .IconReference = New IconReference(current.FullName, 0)})
		list.AddUserTasks(New JumpListLink(current.FullName, "About...") With {.Arguments = String.Format("Handle={0}|Command={1}", Handle, ShowAboutArg), .IconReference = New IconReference(current.FullName, 0)})
		list.AddUserTasks(New JumpListSeparator())
		list.Refresh()
		Windows7APIMenu = list
	End Sub

	Public Function RegisterMessage(ByVal MessageName As String) As Integer
		Return NativeMethods.RegisterWindowMessage(MessageName)
	End Function

	Public Sub SendMessage(ByVal Handle As IntPtr, ByVal MessageID As Integer)
		SendMessage(Handle, MessageID, IntPtr.Zero, IntPtr.Zero)
	End Sub

	Public Function SendMessage(ByVal Handle As IntPtr, ByVal MessageID As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Boolean
		Dim result As Long = NativeMethods.SendMessage(Handle, MessageID, wParam, lParam)
		Return result = 0
	End Function
End Module

Open in new window

5. Setup the main form to create the menu and overload the WndProc method.

Add the following to your main form code file (generally Form1.vb):
	Private Sub OnLoad(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load
		If Environment.OSVersion.Platform = PlatformID.Win32NT Then
			If Environment.OSVersion.Version.Major < 6 Then
				LoadStandardAPIMenu(Handle)
			ElseIf Environment.OSVersion.Version.Major >= 6 Then
				If Environment.OSVersion.Version.Minor < 1 Then
					LoadStandardAPIMenu(Handle)
				ElseIf Environment.OSVersion.Version.Minor >= 1 Then
					LoadWindows7APIMenu(Handle)
				End If
			End If
		End If
	End Sub

	Protected Overloads Overrides Sub WndProc(ByRef m As Message)
		If IsUsingStandardAPIMenu Then
			' Check if a System Command has been executed
			If m.Msg = NativeMethods.WM_SYSCOMMAND Then
				' Execute the appropriate code for the System Menu item that was clicked
				Select Case m.WParam.ToInt32()
					Case NativeMethods.MF_SETTINGS
						MessageBox.Show("Settings menu was clicked")
						Exit Select
					Case NativeMethods.MF_ABOUT
						MessageBox.Show("About menu was clicked")
						Exit Select
				End Select
			End If
		Else
			If m.Msg = ShowSettingsArg Then
				MessageBox.Show("Settings task list menu was clicked")
			ElseIf m.Msg = ShowAboutArg Then
				MessageBox.Show("About task list menu was clicked")
			End If
		End If

		MyBase.WndProc(m)
	End Sub

Open in new window

6. Handle your Application events for Startup and StartupNextInstance.

In the project properties, on the Application tab, click the 'View Application Events' button.In the ApplicationEvents.vb add the following code:
		Public Sub OnStartup(ByVal sender As Object, ByVal e As StartupEventArgs) Handles Me.Startup
			For Each arg As String In e.CommandLine
				If arg.ToUpper().Contains("HANDLE=") Then
					Dim message = arg.ToUpper().Split(New String() {"|"c}, StringSplitOptions.RemoveEmptyEntries).Select(Function(pairs) pairs.Split("="c)).ToDictionary(Function(key) key(0).ToUpper(), Function(val) If(val.Length = 1, String.Empty, val(1)))
					Dim handle As Integer = -1
					Dim command As Integer = -1
					If Not message.TryGetValue("HANDLE", handle) Then handle = -1
					If Not message.TryGetValue("COMMAND", command) Then command = -1

					If handle <> -1 AndAlso command <> -1 Then
						SendMessage(handle, command)
					End If
				End If
			Next
		End Sub

		Public Sub OnStartupNextInstance(ByVal sender As Object, ByVal e As StartupNextInstanceEventArgs) Handles Me.StartupNextInstance
			e.BringToForeground = True
			For Each arg As String In e.CommandLine
				If arg.ToUpper().Contains("HANDLE=") Then
					Dim message = arg.ToUpper().Split(New String() {"|"c}, StringSplitOptions.RemoveEmptyEntries).Select(Function(pairs) pairs.Split("="c)).ToDictionary(Function(key) key(0).ToUpper(), Function(val) If(val.Length = 1, String.Empty, val(1)))
					Dim handle As Integer = -1
					Dim command As Integer = -1
					If Not message.TryGetValue("HANDLE", handle) Then handle = -1
					If Not message.TryGetValue("COMMAND", command) Then command = -1

					If handle <> -1 AndAlso command <> -1 Then
						SendMessage(handle, command)
					End If
				End If
			Next
		End Sub

Open in new window

If done correctly, when you run the application on a Windows Vista or lower computer, you should see the standard menu as presented in the examples above.  Running on Windows 7/8/8.1/10 should give you the following:Capture.JPGClicking on either the Settings or About task list item should give you a message box:Capture.JPGProof of Concept on Windows 8.1:Capture.JPGProof of Concept on Windows 2003:Capture.JPG-saige-
0
 
LVL 1

Author Comment

by:PNRT
ID: 40568027
Many thanks for you help.  Have closed the question and awarded the points (I should have been able to give you double for the excellent answer), but I just wondered if this is the same API Code pack that you were referring to?
 http://channel9.msdn.com/coding4fun/articles/Coding-4-Fun-Windows-7-Taskbar
I ask only because there are many articles stating that this has been retired and is no longer supported
http://archive.msdn.microsoft.com/
0

Featured Post

Threat Intelligence Starter Resources

Integrating threat intelligence can be challenging, and not all companies are ready. These resources can help you build awareness and prepare for defense.

Join & Write a Comment

Article by: Kraeven
Introduction Remote Share is a simple remote sharing tool, enabling you to see, add and remove remote or local shares. The application is written in VB.NET targeting the .NET framework 2.0. The source code and the compiled programs have been in…
I think the Typed DataTable and Typed DataSet are very good options when working with data, but I don't like auto-generated code. First, I create an Abstract Class for my DataTables Common Code.  This class Inherits from DataTable. Also, it can …
Sending a Secure fax is easy with eFax Corporate (http://www.enterprise.efax.com). First, Just open a new email message.  In the To field, type your recipient's fax number @efaxsend.com. You can even send a secure international fax — just include t…
Illustrator's Shape Builder tool will let you combine shapes visually and interactively. This video shows the Mac version, but the tool works the same way in Windows. To follow along with this video, you can draw your own shapes or download the file…

708 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

15 Experts available now in Live!

Get 1:1 Help Now