Sign in to follow this  
Followers 0
Yashied

Tray notifications redirector

24 posts in this topic

#1 ·  Posted (edited)

LAST VERSION - 1.0

19-May-12

I think many of you would like to perform some action (for example, to call the dialog box) when a user clicks on the tray tip. Here is a simple way to do it. Unfortunately, without .dll do not seem possible. Note, only AutoIt window can be registered as a source window, see example.

AITray.png

AITray.dll (x86 and x64)

Previous downloads: 74

AITray.zip

Example

#Include <WindowsConstants.au3>

Opt('TrayAutoPause', 0)
Opt('WinTitleMatchMode', 3)
Opt('WinWaitDelay', 0)

Global Const $NIN_BALLOONSHOW = $WM_USER + 2
Global Const $NIN_BALLOONHIDE = $WM_USER + 3
Global Const $NIN_BALLOONUSERCLICK = $WM_USER + 5
Global Const $NIN_BALLOONTIMEOUT = $WM_USER + 4

$hForm = GUICreate('')

If @AutoItX64 Then
    $hDll = DllOpen(@ScriptDir & '\AITray_x64.dll')
Else
    $hDll = DllOpen(@ScriptDir & '\AITray.dll')
EndIf
If $hDll <> -1 Then
    $Ret = DllCall($hDll, 'int', 'AISetTrayRedirection', 'hwnd', WinGetHandle(AutoItWinGetTitle()), 'hwnd', $hForm)
    If (@Error) Or (Not $Ret[0]) Then
        DllClose($hDll)
        Exit
    EndIf
Else
    Exit
EndIf

GUIRegisterMsg($WM_USER + 1, 'WM_TRAYNOTIFY')

TrayTip('Tip', 'This is a tray tip, click here.', 10, 1)

While 1
    Sleep(1000)
WEnd

DllCall($hDll, 'int', 'AIRemoveTrayRedirection')
DllClose($hDll)

Func WM_TRAYNOTIFY($hWnd, $iMsg, $wParam, $lParam)
    Switch $hWnd
        Case $hForm
            Switch $lParam
                Case $NIN_BALLOONSHOW
                    ConsoleWrite('Balloon tip show.' & @CR)
                Case $NIN_BALLOONHIDE
                    ConsoleWrite('Balloon tip hide.' & @CR)
                Case $NIN_BALLOONUSERCLICK
                    ConsoleWrite('Balloon tip click.' & @CR)
                Case $NIN_BALLOONTIMEOUT
                    ConsoleWrite('Balloon tip close.' & @CR)
            EndSwitch
    EndSwitch
EndFunc   ;==>WM_TRAYNOTIFY
Edited by Yashied
3 people like this

Share this post


Link to post
Share on other sites



And about this DLL?

#WM_TRAYNOTIFY = #WM_USER + 1

Prototype.l SetWindowSubclass(*HWnd, *HProc, ID.i = 1000, IParam.i = 0)
Prototype.l RemoveWindowSubclass(*HWnd, *HProc, ID.i = 1000)

Global Comctl32.l = OpenLibrary(#PB_Any, "comctl32.dll")
Global User32.l = OpenLibrary(#PB_Any, "user32.dll")

Global AutoIt.i = 0
Global Target.i = 0

Procedure.i SubclassProc(*HWnd, Msg.l, *WParam, *LParam, *ID, *IParam)
    Select Msg
        Case #WM_TRAYNOTIFY
            Select *LParam
                Case #NIN_BALLOONSHOW, #NIN_BALLOONHIDE, #NIN_BALLOONUSERCLICK, #NIN_BALLOONTIMEOUT
                    If Target
                        CallFunction(User32, "PostMessageW", Target, Msg, *WParam, *LParam)
                    EndIf
            EndSelect
    EndSelect
    ProcedureReturn CallFunction(Comctl32, "DefSubclassProc", *HWnd, Msg, *WParam, *LParam)
EndProcedure

ProcedureDLL.l AIRemoveTrayRedirection()
    If Not AutoIt
        ProcedureReturn 0
    EndIf
    RemoveWindowSubclass.RemoveWindowSubclass = GetFunction(Comctl32, "RemoveWindowSubclass")
    If IsWindow(AutoIt)
        If Not RemoveWindowSubclass(AutoIt, @SubclassProc())
            ProcedureReturn 0
        EndIf
    EndIf
    Target = 0
    AutoIt = 0
    ProcedureReturn 1
EndProcedure

ProcedureDLL.l AISetTrayRedirection(*HAutoIt, *HTarget)
    If (Not *HAutoIt) Or (Not *HTarget)
        ProcedureReturn 0
    EndIf
    If AutoIt
        If Not AIRemoveTrayRedirection()
            ProcedureReturn 0
        EndIf
    EndIf
    SetWindowSubclass.SetWindowSubclass = GetFunction(Comctl32, "SetWindowSubclass")
    If Not SetWindowSubclass(*HAutoIt, @SubclassProc())
        ProcedureReturn 0
    EndIf
    AutoIt = *HAutoIt
    Target = *HTarget
    ProcedureReturn 1
EndProcedure

Share this post


Link to post
Share on other sites

Again a nice and new feature !

Thanks Yashield ! ;)


AutoIt 3.3.14.2 X86 - SciTE 3.6.0WIN 8.1 X64 - Other Example Scripts

Share this post


Link to post
Share on other sites

Love it ;), much better than having to set the coordinates.

Share this post


Link to post
Share on other sites

What language is the code from the DLL?

Br,

UEZ


Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Share this post


Link to post
Share on other sites

#10 ·  Posted (edited)

PureBasic!!!!

Wow, I will endeavor to eliminate this dll, leaving only in AutoIt... ;)

Regards,

João Carlos.

Edited by JScript

http://forum.autoitbrasil.com/ (AutoIt v3 Brazil!!!)

Somewhere Out ThereJames Ingram

somewh10.png

dropbo10.pngDownload Dropbox - Simplify your life!
Your virtual HD wherever you go, anywhere!

Share this post


Link to post
Share on other sites

#11 ·  Posted (edited)

No, DllCallbackRegister() kill the script.

We just need a small ASM-stub to hook the window procedure and forwards WM_TRAYNOTIFY when the TrayClick is registered.

Edit: Does this seem about right? Values not yet read from stack, only symbols:

use32
test uMsg, WM_TRAYNOTIFY
jz skip_notify
push lparam
push wparam
push uMsg
push hWndRedirect
call PostMessage
skip_notify: push lparam
push wparam
push uMsg
push hWnd
call DefSubclassProc
ret 24
Edited by ProgAndy

*GERMAN* [note: you are not allowed to remove author / modified info from my UDFs]My UDFs:[_SetImageBinaryToCtrl] [_TaskDialog] [AutoItObject] [Animated GIF (GDI+)] [ClipPut for Image] [FreeImage] [GDI32 UDFs] [GDIPlus Progressbar] [Hotkey-Selector] [Multiline Inputbox] [MySQL without ODBC] [RichEdit UDFs] [SpeechAPI Example] [WinHTTP]UDFs included in AutoIt: FTP_Ex (as FTPEx), _WinAPI_SetLayeredWindowAttributes

Share this post


Link to post
Share on other sites

#12 ·  Posted (edited)

Ok, Is there any chance of making entirely in Autoit?

No, DllCallbackRegister() kill the script.

Pure AutoIt works for me...

#include <windowsconstants.au3>

Opt('TrayAutoPause', 0)
Opt('WinTitleMatchMode', 3)
Opt('WinWaitDelay', 0)
Opt('TrayMenuMode', 3)

Global Const $WM_TRAYNOTIFY = $WM_USER + 1
Global Const $NIN_BALLOONSHOW = $WM_USER + 2
Global Const $NIN_BALLOONHIDE = $WM_USER + 3
Global Const $NIN_BALLOONUSERCLICK = $WM_USER + 5
Global Const $NIN_BALLOONTIMEOUT = $WM_USER + 4
Global Const $subID = 1234
Global $iTip = 2
Global $psub = DllCallbackRegister("_subclass", "lresult", "hwnd;uint;wparam;lparam;uint_ptr;dword_ptr")
Global $hForm = GUICreate('')

DllCall("comctl32.dll", "bool", "SetWindowSubclass", "hwnd", WinGetHandle(AutoItWinGetTitle()), "ptr", DllCallbackGetPtr($psub), "uint_ptr", $subID, "dword_ptr", 0)

GUIRegisterMsg($WM_TRAYNOTIFY, 'WM_TRAYNOTIFY')

Global $iShow = TrayCreateItem("Show New Tip")
TrayCreateItem("")
Global $iExit = TrayCreateItem("Exit")

TrayTip('Tip', 'This is a tray tip, click here.', 10, 1)

While 1
    Switch TrayGetMsg()
        Case $iShow
            TrayTip('Tip', 'This is a tray tip, click here. [ ' & $iTip & ' ]', 10, 1)
            $iTip += 1
        Case $iExit
            ExitLoop
    EndSwitch
WEnd

DllCall("comctl32.dll", "bool", "RemoveWindowSubclass", "hwnd", WinGetHandle(AutoItWinGetTitle()), "ptr", DllCallbackGetPtr($psub), "uint_ptr", $subID)
DllCallbackFree($psub)

Func WM_TRAYNOTIFY($hWnd, $iMsg, $wParam, $lParam)
    Switch $hWnd
        Case $hForm
            Switch $lParam
                Case $NIN_BALLOONSHOW
                    ConsoleWrite('Balloon tip show.' & @CR)
                Case $NIN_BALLOONHIDE
                    ConsoleWrite('Balloon tip hide.' & @CR)
                Case $NIN_BALLOONUSERCLICK
                    ConsoleWrite('Balloon tip click.' & @CR)
                Case $NIN_BALLOONTIMEOUT
                    ConsoleWrite('Balloon tip close.' & @CR)
            EndSwitch
    EndSwitch
EndFunc   ;==>WM_TRAYNOTIFY

Func _subclass($hwnd, $uMsg, $wParam, $lParam, $uIdSubclass, $dwRefData)
    #forceref $hwnd, $uMsg, $wParam, $lParam, $uIdSubclass, $dwRefData
    Switch $uMsg
        Case $WM_TRAYNOTIFY
            Switch $uIdSubclass
                Case $subID
                    Switch $lParam
                        Case $NIN_BALLOONSHOW, $NIN_BALLOONHIDE, $NIN_BALLOONUSERCLICK, $NIN_BALLOONTIMEOUT
                            If $hForm Then
                                DllCall("user32.dll", "bool", "PostMessageW", "hwnd", $hForm, "uint", $uMsg, "wparam", $wParam, "lparam", $lParam)
                            EndIf
                    EndSwitch
            EndSwitch
    EndSwitch
    Local $ret = DllCall("comctl32.dll", "lresult", "DefSubclassProc", "hwnd", $hwnd, "uint", $uMsg, "wparam", $wParam, "lparam", $lParam)
    Return $ret[0]
EndFunc

However as noted in MSDN in the comments, there is no differentiation between a timeout and a close event. Seems like a Windows bug.

Edited by wraithdu
1 person likes this

Share this post


Link to post
Share on other sites

#15 ·  Posted (edited)

Share this post


Link to post
Share on other sites

I did it with a custom menu to exit the loop and gracefully unsubclass the window and free the callback before exiting. Works fine every time. Did you try my version?

Share this post


Link to post
Share on other sites

#17 ·  Posted (edited)

wraithdu, please comment the following lines and try to close the script from the tray.

;Opt('TrayAutoPause', 0)
Opt('WinTitleMatchMode', 3)
Opt('WinWaitDelay', 0)
;Opt('TrayMenuMode', 3)
Edited by Yashied

Share this post


Link to post
Share on other sites

Can confirm that wraithdu's code works properly on my machine (Win7 x64 running it at x86 & x64 mode)!

Br,

UEZ


Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Share this post


Link to post
Share on other sites

#19 ·  Posted (edited)

wraithdu, please comment the following lines and try to close the script from the tray.

;Opt('TrayAutoPause', 0)
Opt('WinTitleMatchMode', 3)
Opt('WinWaitDelay', 0)
;Opt('TrayMenuMode', 3)

Why would I purposely break it? If it is required to change the menu mode so you can exit properly, then do it! You must unsubclass and unregister the callback. You can't do that from the default tray menu, unless you want to add a function with OnAutoItExitRegister (didn't try, but would probably also work). Edited by wraithdu

Share this post


Link to post
Share on other sites

#20 ·  Posted (edited)

So do it this way:

#include <windowsconstants.au3>

Opt('TrayAutoPause', 0)
Opt('WinTitleMatchMode', 3)
Opt('WinWaitDelay', 0)
Opt('TrayMenuMode', 2)

Global Const $WM_TRAYNOTIFY = $WM_USER + 1
Global Const $NIN_BALLOONSHOW = $WM_USER + 2
Global Const $NIN_BALLOONHIDE = $WM_USER + 3
Global Const $NIN_BALLOONUSERCLICK = $WM_USER + 5
Global Const $NIN_BALLOONTIMEOUT = $WM_USER + 4
Global Const $subID = 1234
Global $iTip = 2
Global $psub = DllCallbackRegister("_subclass", "lresult", "hwnd;uint;wparam;lparam;uint_ptr;dword_ptr")
Global $hForm = GUICreate('')

DllCall("comctl32.dll", "bool", "SetWindowSubclass", "hwnd", WinGetHandle(AutoItWinGetTitle()), "ptr", DllCallbackGetPtr($psub), "uint_ptr", $subID, "dword_ptr", 0)

GUIRegisterMsg($WM_TRAYNOTIFY, 'WM_TRAYNOTIFY')
OnAutoItExitRegister("SafeExit")

Global $iShow = TrayCreateItem("Show New Tip")
;~ TrayCreateItem("")
;~ Global $iExit = TrayCreateItem("Exit")

TrayTip('Tip', 'This is a tray tip, click here.', 10, 1)

While 1
    Switch TrayGetMsg()
        Case $iShow
            TrayTip('Tip', 'This is a tray tip, click here. [ ' & $iTip & ' ]', 10, 1)
            $iTip += 1
;~         Case $iExit
;~             ExitLoop
    EndSwitch
;~  Sleep(1000)
WEnd

;~ DllCall("comctl32.dll", "bool", "RemoveWindowSubclass", "hwnd", WinGetHandle(AutoItWinGetTitle()), "ptr", DllCallbackGetPtr($psub), "uint_ptr", $subID)
;~ DllCallbackFree($psub)

Func SafeExit()
    ConsoleWrite("exiting..." & @CRLF)
    DllCall("comctl32.dll", "bool", "RemoveWindowSubclass", "hwnd", WinGetHandle(AutoItWinGetTitle()), "ptr", DllCallbackGetPtr($psub), "uint_ptr", $subID)
    DllCallbackFree($psub)
EndFunc

Func WM_TRAYNOTIFY($hWnd, $iMsg, $wParam, $lParam)
    Switch $hWnd
        Case $hForm
            Switch $lParam
                Case $NIN_BALLOONSHOW
                    ConsoleWrite('Balloon tip show.' & @CR)
                Case $NIN_BALLOONHIDE
                    ConsoleWrite('Balloon tip hide.' & @CR)
                Case $NIN_BALLOONUSERCLICK
                    ConsoleWrite('Balloon tip click.' & @CR)
                Case $NIN_BALLOONTIMEOUT
                    ConsoleWrite('Balloon tip close.' & @CR)
            EndSwitch
    EndSwitch
EndFunc   ;==>WM_TRAYNOTIFY

Func _subclass($hwnd, $uMsg, $wParam, $lParam, $uIdSubclass, $dwRefData)
    #forceref $hwnd, $uMsg, $wParam, $lParam, $uIdSubclass, $dwRefData
    Switch $uMsg
        Case $WM_TRAYNOTIFY
            Switch $uIdSubclass
                Case $subID
                    Switch $lParam
                        Case $NIN_BALLOONSHOW, $NIN_BALLOONHIDE, $NIN_BALLOONUSERCLICK, $NIN_BALLOONTIMEOUT
                            If $hForm Then
                                DllCall("user32.dll", "bool", "PostMessageW", "hwnd", $hForm, "uint", $uMsg, "wparam", $wParam, "lparam", $lParam)
                            EndIf
                    EndSwitch
            EndSwitch
    EndSwitch
    Local $ret = DllCall("comctl32.dll", "lresult", "DefSubclassProc", "hwnd", $hwnd, "uint", $uMsg, "wparam", $wParam, "lparam", $lParam)
    Return $ret[0]
EndFunc
Edited by wraithdu

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0

  • Similar Content

    • ur
      By ur
      I need to read the status of OneDrive icon running in the taskbar and update the status in a log file.
      2nd part I can complete
      But the first part, how to read the status of tray menu icon.

      I need the text above from the tray icon.
      I looked into , but not that helpful.
       
       
    • WoodGrain
      By WoodGrain
      Hi All,
      I'm using UseTraySetIcon("shell32.dll", xx) to set my tray icon to a specific icon while running, is there a way I can specify this icon when I compile my script into an exe so my exe icon is the same?
      Thanks!
    • 9252Survive
      By 9252Survive
      Hello Guys, 
      Is there a way to have Auto it Exe messages/line number when you hover over the tray icon just at it shows when you run Au3.?
      For an example, if I the script has paused due to WinWait or Sleep I could hover over the icon and it shows the line where it's at. Is there a way to achieve the same with the compiled exe? 
      Many thanks for the help! 
       
    • jpujut
      By jpujut
      I have a script that gets a list of visible windows and makes a tray item of each in the tray menu. I'd also want it to update every time I want to access that menu again, in case new windows have appeared or some would have been closed. I'm using TrayOnEventMode option and trying to get the update going with TraySetOnEvent($TRAY_EVENT_PRIMARYDOWN...) as in the snippet below. However, the list doesn't update until after the tray menu has been closed again. I think I could work around this by having the script update the list constantly in the background, but that feels like it'd take up unnecessary amount of resources since the script might be used rarely by the user anyway. I tried using TraySetOnEvent($TRAY_EVENT_MOUSEOVER...), and that kind of does it, but it actually still calls my function many times (since the mouse cursor moves quite a bit on the icon) before the tray menu is opened. I could put another menuitem to call the update function, but I'd much rather have just the minimal amount of user actions. Similarly I could have tray menu open with a double click (with TraySetClick()) and have the first click just call the update function, but can anyone tell me if there's a way to call the update once and then have the menu open without these gimmicks?
       
      Opt("TrayOnEventMode", 1) TraySetOnEvent($TRAY_EVENT_PRIMARYDOWN, "UpdateWindowsList")  
    • Kyou
      By Kyou
      I have a working code here. 
      #include <GUIConstants.au3> #include <Constants.au3> Opt("GUIOnEventMode",1) $title = "WINDOW" $text="" $fullTest = WinExistsExact($title, $text) $PASSWORD = "PASS" $retryCount = 0 $stop = 1 ;<<<<<<<<<<<<<<<<<<<<<<<<< While 1 if $retryCount > 0 then Exit $input = InputBox("Password Protected", "Enter the password to continue", "", "*") If @error Or $input <> $PASSWORD Then MsgBox(4096,"Error", "Incorrect Password") $retryCount = $retryCount + 1 Else ;MsgBox(4096,"Success", "Password Accepted") ExitLoop EndIf Wend If $fullTest = 1 Then ;MsgBox(0, "WINDOW", "Press Ok to continue") GUICreate("WINDOW", 241, 78) ;$label = GUICtrlCreateInput ("test", 10, 10, 50, 20) GuiSetOnEvent($GUI_EVENT_CLOSE,"Quit") $button = GUICtrlCreateButton ("Start", 18, 31, 100, 25) $button1 = GUICtrlCreateButton ("Hide", 128, 31, 91, 25) ; <----- THIS IS THE BUTTON GuiCtrlSetOnEvent($button,"DoScript") GUISetState (@SW_SHOW) GUIRegisterMsg($WM_COMMAND, "_WM_COMMAND") ;<<<<<<<<<<<<<<<<<<<<< Else MsgBox(0, "WINDOW", "You need to run WINDOW client first.") EndIf While 1 Sleep(10) Wend Func _WM_COMMAND($hWnd, $Msg, $wParam, $lParam) If BitAND($wParam, 0x0000FFFF) = $button Then $stop = not $stop If $stop = 0 Then GUICtrlSetData($button, "Stop") If $stop = 1 Then GUICtrlSetData($button, "Start") EndIf Return $GUI_RUNDEFMSG EndFunc Func WinExistsExact($title, $text) AutoItSetOption( "WinTitleMatchMode", $OPT_MATCHEXACT ) $res = WinExists($title, $text) AutoItSetOption( "WinTitleMatchMode", $OPT_MATCHSTART ) Return $res EndFunc Func DoScript() While 1 For $i = 1 to 300 Sleep (10) If $stop = 1 Then Return ; GuiCtrlSetData($label, $i) Next ControlSend ( $title, "", 0, "{F12}") $a = Random(300, 900, 1) For $i = 1 to $a Sleep (10) If $stop = 1 Then Return Next ControlSend ( $title, "", 0, "{Del}") $a = Random(100, 500, 1) For $i = 1 to $a Sleep (10) If $stop = 1 Then Return Next WEnd EndFunc Func Quit() Exit EndFunc What I wanted to do is to make the 'Hide' button minimized the entire window when clicked and while it is on tray, there will be a menu if a user right clicked on it. Exactly what the code below should do.
      #NoTrayIcon #include <guiconstantsex.au3> #include <constants.au3> Opt("TrayOnEventMode", 1) Opt("TrayMenuMode", 3) ; Create tray menu items and set the events $About = TrayCreateItem("About") TrayItemSetOnEvent($About, "_About") TrayCreateItem("") ; Create a separator line. $Exit = TrayCreateItem("Exit") TrayItemSetOnEvent($Exit, "_Exit") ; Set the action if you left click on the tray icon TraySetOnEvent($TRAY_EVENT_PRIMARYUP, "SpecialEvent") ; Show the menu if the icon is right clicked TraySetClick(8) Global $MainGui = GUICreate("TestGUI", 392, 316, -1, -1) GUISetState() ;Test() While 1 Switch GUIGetMsg() Case $GUI_EVENT_MINIMIZE ; Hide the GUI GUISetState(@SW_HIDE) ; Show the icon TraySetState(1) Case $GUI_EVENT_CLOSE ExitLoop EndSwitch WEnd Func SpecialEvent() ; Show the GUI GUISetState(@SW_SHOW) GUISetState(@SW_RESTORE) ; Hide the icon TraySetState(2) EndFunc ;==>SpecialEvent Func _About() MsgBox(0,0,"Test") EndFunc Func _Exit() Exit EndFunc My problem is I cannot integrate this code to the one I have. Can anyone help me with this? I would be very much thankful as I am just starting to learn.