Proper notifications from a SystrayIcon balloon message

Windows specific forum
merendo
Enthusiast
Enthusiast
Posts: 449
Joined: Sat Apr 26, 2003 7:24 pm
Location: Germany
Contact:

Proper notifications from a SystrayIcon balloon message

Post by merendo »

Cheers!

I've put together some code, which displays a Balloon message for a given SystrayIcon. Now I know this Balloon message can hand me back some user events, which I'd like to process, but I'm too clumsy with Window callbacks, so I'd appreciate some help here.

The MSDN documentation for NOTIFYICONDATA does say something about the events being parsed through the lParam, but it doesn't say which values I should look for when I want to know, for example, when the user has clicked the X on the Balloon message.

EDIT: I just learned that I wanna look for the event values #NIN_BALLOONTIMEOUT, #NIN_BALLOONHIDE and #NIN_BALLOONUSERCLICK, but I still don't know how or where to receive them.

Code: Select all

Structure MY_NOTIFYICONDATA
  cbSize.l
  hWnd.i
  uID.l
  uFlags.l
  uCallbackMessage.l
  hIcon.i
  szTip.s{128}
  dwState.l
  dwStateMark.l
  szInfo.s{256}
  StructureUnion
    uTimeout.l
    uVersion.l
  EndStructureUnion
  szInfoTitle.s{64}
  dwInfoFlags.l
EndStructure

Procedure MyCallback(WindowID, Message, wParam, lParam)
  If WindowID = WindowID(0)
    
    ; I assume I wanna process the event the system sends me here.
    
  EndIf
EndProcedure



OpenWindow(0, 0, 0, 200, 40, "Icontest", #PB_Window_SystemMenu)
ButtonGadget(0, 5, 5, 190, 30, "Show balloon message")


; You might wanna specify a path which corresponds to any valid .ico file on your system.
LoadImage(0, "C:\Programme\PureBasic\Examples\Sources - Advanced\Waponez II\Waponez.ico")

AddSysTrayIcon(0, WindowID(0), ImageID(0))
SysTrayIconToolTip(0, "Naah, I ain't no systray icon, I'm just cleanin' down 'ere.")


;SetWindowCallback(@MyCallback(), 0)  ; Uncomment me and - voilá - the button disappears. WTF?


NIData.MY_NOTIFYICONDATA
NIData\cbSize = SizeOf(MY_NOTIFYICONDATA)
NIData\hWnd = WindowID(0)
NIData\uFlags = #NIF_INFO
NIData\szInfo = "I'm just a small speech bubble."
NIData\uTimeout = 15000
NIData\uVersion = #NOTIFYICON_VERSION
NIData\szInfoTitle = "Hey there!"
NIData\dwInfoFlags = #NIIF_INFO

Repeat

  event = WaitWindowEvent()

  If event = #PB_Event_Gadget
    If EventGadget() = 0 
      Shell_NotifyIcon_(#NIM_MODIFY, NIData)
    EndIf
  EndIf

Until event = #PB_Event_CloseWindow
Weird enough, once I assign my window the callback procedure (incomplete), the button disappears. Anyone got an idea why that is?

Help appreciated!
merendo
The truth is never confined to a single number - especially scientific truth!
merendo
Enthusiast
Enthusiast
Posts: 449
Joined: Sat Apr 26, 2003 7:24 pm
Location: Germany
Contact:

Re: Proper notifications from a SystrayIcon balloon message

Post by merendo »

Persistence leads to victory, isn't that right? I worked out most issues, here's my updated code:

Code: Select all

Structure MY_NOTIFYICONDATA
  cbSize.l
  hWnd.i
  uID.l
  uFlags.l
  uCallbackMessage.l
  hIcon.i
  szTip.s{128}
  dwState.l
  dwStateMark.l
  szInfo.s{256}
  StructureUnion
    uTimeout.l
    uVersion.l
  EndStructureUnion
  szInfoTitle.s{64}
  dwInfoFlags.l
EndStructure

#WINDOW = 0
Enumeration
#BUTTON_SHOW
#BUTTON_HIDE
#SYSTRAYICON
EndEnumeration


Procedure MyCallback(WindowID, Message, wParam, lParam)
  If WindowID = WindowID(0)
    
    If Message = 99999 ; Does that make sense?
      If wParam = #SYSTRAYICON
        Select lParam
          Case #NIN_BALLOONTIMEOUT
            Debug "Balloon timed out or was closed by the user"
          Case #NIN_BALLOONUSERCLICK
            Debug "Balloon got clicked by the user"
          Case #NIN_BALLOONHIDE
            Debug "Balloon got hidden"
        EndSelect
      EndIf
    EndIf
    
  EndIf
  ProcedureReturn #PB_ProcessPureBasicEvents 
EndProcedure



OpenWindow(#WINDOW, 0, 0, 200, 75, "Icontest", #PB_Window_SystemMenu)
ButtonGadget(#BUTTON_SHOW, 5, 5, 190, 30, "Show balloon message")
ButtonGadget(#BUTTON_HIDE, 5, 40, 190, 30, "Hide balloon message")


; You might wanna specify a path which corresponds to any valid .ico file on your system.
LoadImage(0, "C:\Programme\PureBasic\Examples\Sources - Advanced\Waponez II\Waponez.ico")

AddSysTrayIcon(#SYSTRAYICON, WindowID(0), ImageID(0))
SysTrayIconToolTip(#SYSTRAYICON, "Naah, I ain't no systray icon, I'm just cleanin' down 'ere.")

SetWindowCallback(@MyCallback(), 0)

NIData.MY_NOTIFYICONDATA
NIData\cbSize = SizeOf(MY_NOTIFYICONDATA)
NIData\hWnd = WindowID(0)
NIData\uID = #SYSTRAYICON
NIData\uFlags = #NIF_INFO | #NIF_MESSAGE
NIData\uCallbackMessage = 99999
NIData\uTimeout = 10
NIData\uVersion = #NOTIFYICON_VERSION
NIData\szInfoTitle = "Hey there!"
NIData\dwInfoFlags = #NIIF_INFO

Repeat

  event = WaitWindowEvent()

  If event = #PB_Event_Gadget
    Select EventGadget() 
      Case #BUTTON_SHOW:
        NIData\szInfo = "I'm just a small speech bubble."
        Shell_NotifyIcon_(#NIM_MODIFY, NIData)
      Case #BUTTON_HIDE:
        NIData\szInfo = ""
        Shell_NotifyIcon_(#NIM_MODIFY, NIData)
    EndSelect
  EndIf

Until event = #PB_Event_CloseWindow
I'm still not sure about which NOTIFYICONDATA\uCallbackMessage code to use, though. I used 99999 here because I figured that is likely to be available. According to MSDN, message is "An application-defined message identifier. The system uses this identifier to send notification messages to the window identified in hWnd." Can I just freely use any number I want here??
Last edited by merendo on Fri Feb 03, 2012 8:44 pm, edited 1 time in total.
The truth is never confined to a single number - especially scientific truth!
c4s
Addict
Addict
Posts: 1981
Joined: Thu Nov 01, 2007 5:37 pm
Location: Germany

Re: Proper notifications from a SystrayIcon balloon message

Post by c4s »

Nice code, looks useful to me!
I'd really say you can define any id you want to as the quoted description of MSDN says so.

And a small tip. Use #PB_Compiler_Home for the icon path, like this:

Code: Select all

LoadImage(0, #PB_Compiler_Home + "\Examples\Sources - Advanced\Waponez II\Waponez.ico")
If any of you native English speakers have any suggestions for the above text, please let me know (via PM). Thanks!
merendo
Enthusiast
Enthusiast
Posts: 449
Joined: Sat Apr 26, 2003 7:24 pm
Location: Germany
Contact:

Re: Proper notifications from a SystrayIcon balloon message

Post by merendo »

Well, I'm not sure now. When I add the line 'debug Message' in the Callback procedure (inside the If hWnd = WindowID() block), I get all sorts of messages whenever I interact with the window (like hovering over the window with the mouse), so it seems there are at least a good handfull of reserved codes.

Perhaps there is one, which I can safely use or even one which is meant for exactly this purpose? All you Callback geeks, where are you? 8)
The truth is never confined to a single number - especially scientific truth!
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5494
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: Proper notifications from a SystrayIcon balloon message

Post by Kwai chang caine »

Works great on XP
Thanks for sharing
ImageThe happiness is a road...
Not a destination
merendo
Enthusiast
Enthusiast
Posts: 449
Joined: Sat Apr 26, 2003 7:24 pm
Location: Germany
Contact:

Re: Proper notifications from a SystrayIcon balloon message

Post by merendo »

You're very welcome. However, my original questions still remains unanswered: Which callbackMessage can I safely use without running the risk of interfering with existing codes? 99999 probably works, but this number is completely random and a shot in the dark - not a satisfactory solution to me.
The truth is never confined to a single number - especially scientific truth!
c4s
Addict
Addict
Posts: 1981
Joined: Thu Nov 01, 2007 5:37 pm
Location: Germany

Re: Proper notifications from a SystrayIcon balloon message

Post by c4s »

I'd say using #WM_APP+1 is save.
If any of you native English speakers have any suggestions for the above text, please let me know (via PM). Thanks!
merendo
Enthusiast
Enthusiast
Posts: 449
Joined: Sat Apr 26, 2003 7:24 pm
Location: Germany
Contact:

Re: Proper notifications from a SystrayIcon balloon message

Post by merendo »

Great. I know who to come back to if it doesn't work :twisted:

Thank you!

Btw: I got carried away and converted my example into a complete app. http://www.mediafire.com/?v9x45sjg4e1gz10 (Yeah, I know there is a better way to capture those Icons, but at the time I wrote this, I didn't care.)
The truth is never confined to a single number - especially scientific truth!
merendo
Enthusiast
Enthusiast
Posts: 449
Joined: Sat Apr 26, 2003 7:24 pm
Location: Germany
Contact:

Re: Proper notifications from a SystrayIcon balloon message

Post by merendo »

Okay, problem. Please run this code:

Code: Select all

    Structure MY_NOTIFYICONDATA
      cbSize.l
      hWnd.i
      uID.l
      uFlags.l
      uCallbackMessage.l
      hIcon.i
      szTip.s{128}
      dwState.l
      dwStateMark.l
      szInfo.s{256}
      StructureUnion
        uTimeout.l
        uVersion.l
      EndStructureUnion
      szInfoTitle.s{64}
      dwInfoFlags.l
    EndStructure

    #WINDOW = 0
    Enumeration
    #BUTTON_SHOW
    #BUTTON_HIDE
    #SYSTRAYICON
    EndEnumeration


    Procedure MyCallback(WindowID, Message, wParam, lParam)
      If WindowID = WindowID(0)
       
        If Message = 99999 ; Does that make sense?
          If wParam = #SYSTRAYICON
            Select lParam
              Case #NIN_BALLOONTIMEOUT
                Debug "Balloon timed out or was closed by the user"
              Case #NIN_BALLOONUSERCLICK
                Debug "Balloon got clicked by the user"
              Case #NIN_BALLOONHIDE
                Debug "Balloon got hidden"
            EndSelect
          EndIf
        EndIf
       
      EndIf
      ProcedureReturn #PB_ProcessPureBasicEvents
    EndProcedure

    OpenWindow(#WINDOW, 0, 0, 200, 75, "Icontest", #PB_Window_SystemMenu)
    ButtonGadget(#BUTTON_SHOW, 5, 5, 190, 30, "Show balloon message")
    ButtonGadget(#BUTTON_HIDE, 5, 40, 190, 30, "Hide balloon message")


    ; You might wanna specify a path which corresponds to any valid .ico file on your system.
    LoadImage(0, #PB_Compiler_Home + "\Examples\Sources - Advanced\Waponez II\Waponez.ico")

    AddSysTrayIcon(#SYSTRAYICON, WindowID(0), ImageID(0))
    SysTrayIconToolTip(#SYSTRAYICON, "Naah, I ain't no systray icon, I'm just cleanin' down 'ere.")

    SetWindowCallback(@MyCallback(), 0)

    NIData.MY_NOTIFYICONDATA
    NIData\cbSize = SizeOf(MY_NOTIFYICONDATA)
    NIData\hWnd = WindowID(0)
    NIData\uID = #SYSTRAYICON
    NIData\uFlags = #NIF_INFO | #NIF_MESSAGE
    NIData\uCallbackMessage = 99999
    NIData\uTimeout = 10
    NIData\uVersion = #NOTIFYICON_VERSION
    NIData\szInfoTitle = "Hey there!"
    NIData\dwInfoFlags = #NIIF_INFO

    Repeat

      event = WaitWindowEvent()

      If event = #PB_Event_Gadget
        Select EventGadget()
          Case #BUTTON_SHOW:
            NIData\szInfo = "I'm just a small speech bubble."
            Shell_NotifyIcon_(#NIM_MODIFY, NIData)
          Case #BUTTON_HIDE:
            NIData\szInfo = ""
            Shell_NotifyIcon_(#NIM_MODIFY, NIData)
        EndSelect
      EndIf
      
			If event = #PB_Event_SysTray
				If EventGadget() = #SYSTRAYICON
					MessageRequester("Message", "Systrayicon got clicked.")
				EndIf
			EndIf

    Until event = #PB_Event_CloseWindow
First, try clicking on the systrayicon before first displaying a balloon message (the messagerequester should appear), then display a balloon message, then try clicking the systrayicon again (no messagerequester should appear). I have worked out that whenever I set the #NIF_MESSAGE flag in NIData\uFlags (meaning that the NIData\uCallbackMessage is valid), the PureBasic event handler somehow won't receive events from that systrayicon anymore. Does anybody know how to restore proper handling of these events?
The truth is never confined to a single number - especially scientific truth!
RASHAD
PureBasic Expert
PureBasic Expert
Posts: 4946
Joined: Sun Apr 12, 2009 6:27 am

Re: Proper notifications from a SystrayIcon balloon message

Post by RASHAD »

Change

Code: Select all

    NIData.MY_NOTIFYICONDATA
    NIData\cbSize = SizeOf(MY_NOTIFYICONDATA)
    NIData\hWnd = WindowID(0)
    NIData\uID = #SYSTRAYICON
    NIData\uFlags = #NIF_INFO
    NIData\uCallbackMessage = 99999
    NIData\uTimeout = 10
    NIData\uVersion = #NOTIFYICON_VERSION
    NIData\szInfoTitle = "Hey there!"
    NIData\dwInfoFlags = #NIIF_INFO
Egypt my love
merendo
Enthusiast
Enthusiast
Posts: 449
Joined: Sat Apr 26, 2003 7:24 pm
Location: Germany
Contact:

Re: Proper notifications from a SystrayIcon balloon message

Post by merendo »

If I do that (i.e. remove the #NIF_MESSAGE flag from NIData\uFlags), the events for the info bubble don't get processed anymore...
The truth is never confined to a single number - especially scientific truth!
RASHAD
PureBasic Expert
PureBasic Expert
Posts: 4946
Joined: Sun Apr 12, 2009 6:27 am

Re: Proper notifications from a SystrayIcon balloon message

Post by RASHAD »

After using Shell_NotifyIcon_() the PB #PB_Event_SysTray change permanent
Next is a workaround for time being till we find another way

Code: Select all

    Structure MY_NOTIFYICONDATA
      cbSize.l
      hWnd.i
      uID.l
      uFlags.l
      uCallbackMessage.l
      hIcon.i
      szTip.s{128}
      dwState.l
      dwStateMark.l
      szInfo.s{256}
      StructureUnion
        uTimeout.l
        uVersion.l
      EndStructureUnion
      szInfoTitle.s{64}
      dwInfoFlags.l
    EndStructure

    #WINDOW = 0
    Enumeration
    #BUTTON_SHOW
    #BUTTON_HIDE
    #SYSTRAYICON
    EndEnumeration


Procedure MyCallback(WindowID, Message, wParam, lParam)
  If WindowID = WindowID(0)   
    If Message = #WM_NOTIFYICON ; Does that make sense?
      If wParam = #SYSTRAYICON
        Select lParam
          Case #NIN_BALLOONTIMEOUT
            Debug "Balloon timed out or was closed by the user"
            AddSysTrayIcon(#SYSTRAYICON, WindowID(0), ImageID(0)) 
          Case #NIN_BALLOONUSERCLICK
            Debug "Balloon got clicked by the user"
            AddSysTrayIcon(#SYSTRAYICON, WindowID(0), ImageID(0)) 
          Case #NIN_BALLOONHIDE
            Debug "Balloon got hidden"
            AddSysTrayIcon(#SYSTRAYICON, WindowID(0), ImageID(0))            
        EndSelect
      EndIf
    EndIf   
  EndIf              
  ProcedureReturn #PB_ProcessPureBasicEvents
EndProcedure

    OpenWindow(#WINDOW, 0, 0, 200, 75, "Icontest", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)
    ButtonGadget(#BUTTON_SHOW, 5, 5, 190, 30, "Show balloon message")
    ButtonGadget(#BUTTON_HIDE, 5, 40, 190, 30, "Hide balloon message")


    ; You might wanna specify a path which corresponds to any valid .ico file on your system.
    LoadImage(0, #PB_Compiler_Home + "\Examples\Sources - Advanced\Waponez II\Waponez.ico")

    AddSysTrayIcon(#SYSTRAYICON, WindowID(0), ImageID(0))
    SysTrayIconToolTip(#SYSTRAYICON, "Naah, I ain't no systray icon, I'm just cleanin' down 'ere.")

    SetWindowCallback(@MyCallback(), 0)

    NIData.MY_NOTIFYICONDATA
    NIData\cbSize = SizeOf(MY_NOTIFYICONDATA)
    NIData\hWnd = WindowID(0)
    NIData\uID = #SYSTRAYICON
    NIData\uFlags = #NIF_INFO | #NIF_MESSAGE
    NIData\uCallbackMessage = #WM_NOTIFYICON
    NIData\uTimeout = 2
    NIData\uVersion = #NOTIFYICON_VERSION
    NIData\szInfoTitle = "Hey there!"
    NIData\dwInfoFlags = #NIIF_INFO

    Repeat

      event = WaitWindowEvent()

      If event = #PB_Event_Gadget
        Select EventGadget()
          Case #BUTTON_SHOW:
            NIData\szInfo = "I'm just a small speech bubble."
            Shell_NotifyIcon_(#NIM_MODIFY, NIData)
          Case #BUTTON_HIDE:
            NIData\szInfo = ""
            Shell_NotifyIcon_(#NIM_MODIFY, NIData)
        EndSelect
      EndIf
      
     If event = #PB_Event_SysTray
        If EventGadget() = #SYSTRAYICON
           MessageRequester("Message", "Systrayicon got clicked.")
        EndIf
     EndIf

    Until event = #PB_Event_CloseWindow

Egypt my love
merendo
Enthusiast
Enthusiast
Posts: 449
Joined: Sat Apr 26, 2003 7:24 pm
Location: Germany
Contact:

Re: Proper notifications from a SystrayIcon balloon message

Post by merendo »

Seems to work fine for me now. Thank you very much!
The truth is never confined to a single number - especially scientific truth!
RASHAD
PureBasic Expert
PureBasic Expert
Posts: 4946
Joined: Sun Apr 12, 2009 6:27 am

Re: Proper notifications from a SystrayIcon balloon message

Post by RASHAD »

Hi merendo
I did not like the previous workaround

Change

Code: Select all

Procedure MyCallback(WindowID, Message, wParam, lParam)
  If WindowID = WindowID(0)   
    If Message = #WM_NOTIFYICON ; Does that make sense?
      If wParam = #SYSTRAYICON
        Select lParam
          Case #NIN_BALLOONTIMEOUT
            Debug "Balloon timed out or was closed by the user"
            
          Case #NIN_BALLOONUSERCLICK
            Debug "Balloon got clicked by the user"
            
          Case #NIN_BALLOONHIDE
            Debug "Balloon got hidden"
                     
          Case #WM_LBUTTONUP
             MessageRequester("Message", "Systrayicon got clicked.")
        EndSelect

      EndIf
    EndIf   
  EndIf              
  ProcedureReturn #PB_ProcessPureBasicEvents
EndProcedure

Egypt my love
merendo
Enthusiast
Enthusiast
Posts: 449
Joined: Sat Apr 26, 2003 7:24 pm
Location: Germany
Contact:

Re: Proper notifications from a SystrayIcon balloon message

Post by merendo »

That works even better. Your efforts are much appreciated, thanks!

Perhaps when someone from the PB team reads this posting, they could tell us which uCallbackMessage the Notifyicon needs to be reassigned in order to restore the systray icon to it's original function, but until then, the workaround provides a satisfactory solution.
The truth is never confined to a single number - especially scientific truth!
Post Reply