Jump to content
Yashied

Tray notifications redirector

Recommended Posts

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

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

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

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

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

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

Share this post


Link to post
Share on other sites

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

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

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

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

  • Similar Content

    • By MONaH-Rasta
      Opt('TrayAutoPause', 0) $iTray1 = TrayCreateItem('Tray 1') TrayItemSetState(-1, 1) TrayCreateItem('') $iTrayMenu1 = TrayCreateMenu('Tray Menu 1') $iTray2 = TrayCreateItem('Tray 2', $iTrayMenu1, -1, 1) TrayItemSetState(-1, 1) $iTray3 = TrayCreateItem('Tray 3', $iTrayMenu1, -1, 1) $iTray4 = TrayCreateItem('Tray 4', $iTrayMenu1, -1, 1) TrayCreateItem('') $iTrayMenu2= TrayCreateMenu('Tray Menu 2') $iTray5 = TrayCreateItem('Tray 5', $iTrayMenu2, -1, 1) TrayItemSetState(-1, 1) $iTray6 = TrayCreateItem('Tray 6', $iTrayMenu2, -1, 1) $iTray7 = TrayCreateItem('Tray 7', $iTrayMenu2, -1, 1) TrayCreateItem('') $iTray8 = TrayCreateItem('Tray 8') $iTray9 = TrayCreateItem('Tray 9') $iTray10 = TrayCreateItem('Tray 10') TrayItemSetState(-1, 1) While True Sleep(1000*5) WEnd When I click on Tray 3 / Tray 4 / Tray 6 / Tray 7 nothing happens. Only Tray 2 and Tray 5 stay checked.
      I have tried setting 
      Opt("TrayMenuMode", 8) In this case radio menuitems act like normal menuitems only looks different.
      I'm using AutoIt v3.3.14.5.
      Tested on Windows 10 LTSC 2019 (1809) x64 version: 10.0.17763 build 17763.475 and Windows Server 2008 R2.
      Tried run script x64 and x86 same result.
      Is this kind a bug or something?
    • By argumentum
      So I'm coding in win 10, ..every thing looks nice but then I think, what about XP, ...ugly, but I make it pretty again, no problem. Lets check in Win 7 and here is my conundrum.
      Win 10, DRM is on, XP is off ( well, non-existant ), so far so good. I decide to make it the "switch" to enable or disable the checkbox in the context menu.
      Win 7 ... I try to apply the same logic and:
      DRM on:

       
      DRM off:

       
      now, "Windows 7 Basic": DRM is off


      Question: how should I determine if to hide the check-mark or not?, Is there a way to know that this theme is ? or better yet, how can I know that the theme is classic ?
      Thanks
      PS: I know that the code is not here but I think that my trend of thought would make it irrelevant anyway.
       
    • 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.
       
       
    • 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!
    • 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! 
       
×
×
  • Create New...