VB.NET: Notify Icon Balloon On Vista

Joined
Dec 10, 2006
Messages
540
I am having an issue with my program in VB.Net. I am wanting a way to show a Balloon off the NotifyIcon that shows information and allows events. My code works in XP, but not in Vista. I assume since the code uses the Windows API. Can anyone help?

Balloon Class:
Code:
Imports System.Runtime.InteropServices

Class Balloon 'begin balloon class

    Private Const WM_USER As Long = &H400
    Private Const NIF_MESSAGE As Int32 = &H1
    Private Const NIF_ICON As Int32 = &H2
    Private Const NIF_STATE As Int32 = &H8
    Private Const NIF_INFO As Int32 = &H10
    Private Const NIF_TIP As Int32 = &H4
    Private Const NIM_ADD As Int32 = &H0
    Private Const NIM_MODIFY As Int32 = &H1
    Private Const NIM_DELETE As Int32 = &H2
    Private Const NIM_SETVERSION As Int32 = &H4
    Private Const NOTIFYICON_VERSION As Int32 = &H5
    Private Const NIIF_ERROR As Int32 = &H3
    Private Const NIIF_INFO As Int32 = &H1
    Private Const NIIF_NONE As Int32 = &H0
    Private Const NIM_SETFOCUS As Int32 = &H3
    Private Const NIN_BALLOONSHOW As Long = (WM_USER + 2)
    Private Const NIN_BALLOONHIDE As Long = (WM_USER + 3)
    Private Const NIN_BALLOONTIMEOUT As Long = (WM_USER + 4)
    Private Const NIN_BALLOONUSERCLICK As Long = (WM_USER + 5)

    Public Enum BalloonMessageTypes
        None = &H0
        Info = &H1
        [Error] = &H3
    End Enum

    <StructLayout(LayoutKind.Sequential)> _
    Private Structure NOTIFYICONDATA
        Public cbSize As Int32
        Public hwnd As IntPtr
        Public uID As Int32
        Public uFlags As Int32
        Public uCallbackMessage As IntPtr
        Public hIcon As IntPtr
        <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=128)> _
        Public szTip As String
        Public dwState As Int32
        Public dwStateMask As Int32
        <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=256)> _
        Public szInfo As String
        Public uTimeout As Int32
        <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=64)> _
        Public szInfoTitle As String
        Public dwInfoFlags As Int32
    End Structure

    Private Declare Auto Function Shell_NotifyIconA Lib "shell32" (ByVal dwMessage As Integer, _
    ByRef pnid As NOTIFYICONDATA) As Integer

    Public Shared Sub DisplayBalloon(ByRef NotifyIcon As System.Windows.Forms.NotifyIcon, ByVal BalloonTitle As String, ByVal BalloonText As String, _
Optional ByVal MessageType As BalloonMessageTypes = BalloonMessageTypes.None)
        Dim typNotifyIcon As Type = GetType(System.Windows.Forms.NotifyIcon)
        Dim ptrWindow As IntPtr = (CType(typNotifyIcon.GetField("window", System.Reflection.BindingFlags.Instance Or _
            System.Reflection.BindingFlags.NonPublic).GetValue(NotifyIcon), System.Windows.Forms.NativeWindow)).Handle
        Dim id As Int32 = CType(typNotifyIcon.GetField("id", System.Reflection.BindingFlags.Instance Or _
            System.Reflection.BindingFlags.NonPublic).GetValue(NotifyIcon), Integer)
        Dim clsNID As NOTIFYICONDATA
        With clsNID
            .szTip = ""
            .dwState = 0
            .dwStateMask = 0
            .hIcon = IntPtr.Zero
            .uCallbackMessage = New IntPtr(&H200)
            .uID = id
            .hwnd = ptrWindow
            .szInfo = BalloonText
            .szInfoTitle = BalloonTitle
            .uFlags = NIF_INFO
            .cbSize = Marshal.SizeOf(clsNID)
            .dwInfoFlags = CType(MessageType, Int32)
            .uTimeout = NOTIFYICON_VERSION
        End With
        Dim result As Int32 = Shell_NotifyIconA(NIM_MODIFY, clsNID)
    End Sub

    Public Shared Sub HideBalloon(ByRef NotifyIcon As System.Windows.Forms.NotifyIcon)
        Dim typNotifyIcon As Type = GetType(System.Windows.Forms.NotifyIcon)
        Dim ptrWindow As IntPtr = (CType(typNotifyIcon.GetField("window", System.Reflection.BindingFlags.Instance Or _
            System.Reflection.BindingFlags.NonPublic).GetValue(NotifyIcon), System.Windows.Forms.NativeWindow)).Handle
        Dim id As Int32 = CType(typNotifyIcon.GetField("id", System.Reflection.BindingFlags.Instance Or _
            System.Reflection.BindingFlags.NonPublic).GetValue(NotifyIcon), Integer)
        Dim clsNID As NOTIFYICONDATA
        With clsNID
            .szTip = ""
            .dwState = 0
            .dwStateMask = 0
            .hIcon = IntPtr.Zero
            .uCallbackMessage = New IntPtr(&H200)
            .uID = id
            .hwnd = ptrWindow
            .szInfo = ""
            .szInfoTitle = ""
            .uFlags = NIF_INFO
            .cbSize = Marshal.SizeOf(clsNID)
            .dwInfoFlags = CType(BalloonMessageTypes.None, Int32)
            .uTimeout = NOTIFYICON_VERSION
        End With
        Dim result As Int32 = Shell_NotifyIconA(NIM_MODIFY, clsNID)
    End Sub

    Public Shared Function HookBalloonEvents(ByVal NotifyIcon As System.Windows.Forms.NotifyIcon) As NotifyIconBalloon
        Dim clsEvents As New NotifyIconBalloon
        Dim typNotifyIcon As Type = GetType(System.Windows.Forms.NotifyIcon)
        Dim ptrWindow As IntPtr = (CType(typNotifyIcon.GetField("window", System.Reflection.BindingFlags.Instance _
            Or System.Reflection.BindingFlags.NonPublic).GetValue(NotifyIcon), System.Windows.Forms.NativeWindow)).Handle
        clsEvents.AssignHandle(ptrWindow)
        Return clsEvents
    End Function

    Public Class NotifyIconBalloon
        Inherits System.Windows.Forms.NativeWindow
        Public Event BallonHidden()
        Public Event BallonShown()
        Public Event BallonTimedOut()
        Public Event BallonClicked()
        Friend Sub New()
            '
        End Sub
        Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
            Select Case m.LParam.ToInt32
                Case NIN_BALLOONHIDE
                    RaiseEvent BallonHidden()
                Case NIN_BALLOONSHOW
                    RaiseEvent BallonShown()
                Case NIN_BALLOONTIMEOUT
                    RaiseEvent BallonTimedOut()
                Case NIN_BALLOONUSERCLICK
                    RaiseEvent BallonClicked()
                Case Else
            End Select
            MyBase.WndProc(m)
        End Sub
    End Class

End Class 'end balloon class
It get's called in a matter like this:
Code:
 Private m_clsBalloon As Balloon.NotifyIconBalloon

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        'if we haven't already, hook into the NotifyIcon to trap balloon interaction events...
        If m_clsBalloon Is Nothing Then
            m_clsBalloon = Balloon.HookBalloonEvents(NotifyIcon1)
            AddHandler m_clsBalloon.BallonClicked, AddressOf BalloonClicked
            AddHandler m_clsBalloon.BallonShown, AddressOf BalloonShown
            AddHandler m_clsBalloon.BallonHidden, AddressOf BalloonHidden
        End If
        'show the balloon...
        Balloon.DisplayBalloon(NotifyIcon1, "This is a test", "This is a test balloon. Click on it to raise a click event...", Balloon.BalloonMessageTypes.Info)
    End Sub

    Private Sub BalloonHidden()
        MessageBox.Show("Balloon Hidden!")
    End Sub

    Private Sub BalloonShown()
        MessageBox.Show("Balloon Shown!")
    End Sub

    Private Sub BalloonClicked()
        MessageBox.Show("Balloon Clicked!")
    End Sub
 
I'm a bit confused--you are using a NotifyIcon but you aren't using the ShowBalloonTip(Int32) method (or one of it's overloads)? That would seem to be the far simpler solution, unless I am missing something...?

NotifyIcon Class description (and examples): http://msdn2.microsoft.com/en-us/library/system.windows.forms.notifyicon_members.aspx
NotifyIcon Class members: http://msdn2.microsoft.com/en-us/library/system.windows.forms.notifyicon_members.aspx
NotifyIcon.ShowBalloonTip method: http://msdn2.microsoft.com/en-us/library/system.windows.forms.notifyicon.showballoontip.aspx

That is what I am referring to--doesn't that do what you are describing? If not then how should it work as opposed to how that method above works?

EDIT: After reading your description, I thought it'd be relevant to also link the BalloonTipClick event, which seems to be what you are describing in your code:

NotifyIcon.BalloonTipClick event: http://msdn2.microsoft.com/en-us/library/system.windows.forms.notifyicon.balloontipclicked.aspx

202276
 
Thanks, that helps out. I just didn't know about the Balloon Tip Click event, so that works out nicely, thanks, much much much more cleaner.
 
Thanks, that helps out. I just didn't know about the Balloon Tip Click event, so that works out nicely, thanks, much much much more cleaner.

H2H! :) Even if you have to pop up a menu of available options when the user clicks on the Balloon that will be nicer than trying to roll your own custom balloons.

202276
 
Back
Top