How to Hook on to Shell to receive its messages?
http://www.autohotke...p=123323#123323Foreword: The shell receives messages whenever a Window is being Created/Activated/Detroyed etc. This topic discusses on hooking Shell messages and the possible uses.
RegisterShellHookWindow Function :
The difference with RegisterShellHookWindow is that the messages are received through the specified window's WindowProc and not through a call back procedure.
A basic template would look like:Gui +LastFound hWnd := WinExist() DllCall( "RegisterShellHookWindow", UInt,hWnd ) MsgNum := DllCall( "RegisterWindowMessage", Str,"SHELLHOOK" ) OnMessage( MsgNum, "ShellMessage" ) Return ; // End of Auto-Execute Section // ShellMessage( wParam,lParam ) { ; Execute a command based on wParam and lParam }
The documented values for wParam are:
[*:23mbb9rw]HSHELL_WINDOWCREATED
[*:23mbb9rw]HSHELL_WINDOWDESTROYED
[*:23mbb9rw]HSHELL_ACTIVATESHELLWINDOW
[*:23mbb9rw]HSHELL_WINDOWACTIVATED
[*:23mbb9rw]HSHELL_GETMINRECT
[*:23mbb9rw]HSHELL_REDRAW
[*:23mbb9rw]HSHELL_TASKMAN
[*:23mbb9rw]HSHELL_LANGUAGE
[*:23mbb9rw]HSHELL_SYSMENU
[*:23mbb9rw]HSHELL_ENDTASK
[*:23mbb9rw]HSHELL_ACCESSIBILITYSTATE
[*:23mbb9rw]HSHELL_APPCOMMAND
[*:23mbb9rw]HSHELL_WINDOWREPLACED
[*:23mbb9rw]HSHELL_WINDOWREPLACING
[*:23mbb9rw]HSHELL_HIGHBIT
[*:23mbb9rw]HSHELL_FLASH
[*:23mbb9rw]HSHELL_RUDEAPPACTIVATEDlParam differs in type according to the value of wParam received. For most of the wParam values, the lParam is a handle to a window that can be used as ahk_id %lParam% in AHK's Window commands.
Some ideas:
The shell receives HSHELL_GETMINRECT ( with a shellhook structure ) whenever a window is being Minimised/Maximised. A script may monitor it to Minimize a window to the tray.
The shell receives HSHELL_REDRAW when a window is being Redrawn. A script may monitor it to activate a window whenever its contents are changed.
I tried experimenting and here are some examples:
Experiment 1:
In Windows XP, CTRL+ALT+DEL brings the Task Manager. The forum has seen some posts requesting a way to deny the access to Task Manager.
The following scripts detects and closes Windows Task Manager almost instantly when created.#Persistent SetBatchLines, -1 Process, Priority,, High Gui +LastFound hWnd := WinExist() DllCall( "RegisterShellHookWindow", UInt,hWnd ) MsgNum := DllCall( "RegisterWindowMessage", Str,"SHELLHOOK" ) OnMessage( MsgNum, "ShellMessage" ) Return ShellMessage( wParam,lParam ) { If ( wParam = 1 ) ; HSHELL_WINDOWCREATED := 1 { WinGetTitle, Title, ahk_id %lParam% If ( Title = "Windows Task Manager" ) { WinClose, ahk_id %lParam% ; Run, Calc.exe ; instead } } }
Experiment 2:
Hooking Shell messages provides a sure shot way of keeping a track on Last Active Window.
See: How to retrieve LAST active window? by r0lZ
The following script toggles the TopMost/TopLevel styles ( Always on Top On/OFF ) of the active window.#Persistent Menu, Tray, NoStandard Menu, Tray, Add, Toggle AOT, ToggleAOT Menu, Tray, Add, Menu, Tray, Add, Reload, ExitScript Menu, Tray, Add, Exit , ExitScript Menu, Tray, Tip, Toggle AOT Menu, Tray, Default, Toggle AOT Gui +LastFound DllCall( "RegisterShellHookWindow", UInt,WinExist() ) MsgNum := DllCall( "RegisterWindowMessage", Str,"SHELLHOOK" ) OnMessage( MsgNum, "ShellMessage" ) LastActiveWindowID := WinActive("A") Return ; // End of Auto-Execute Section // ShellMessage( wParam, lParam ) { Global LastActiveWindowID If ( wParam = 4 And WinExist( "ahk_id " lParam ) ) { ; HSHELL_WINDOWACTIVATED = 4 LastActiveWindowID := lParam } } ToggleAOT: WinSet, AlwaysOnTop, Toggle, ahk_id %LastActiveWindowID% Return ExitScript: DllCall( "DeregisterShellHookWindow", UInt,hWnd ) ; Redundant, I guess! IfEqual, A_ThisMenuItem, Reload, Reload ExitApp Return
Run the script.
Click on the target window to focus it.
Double click on the scripts tray icon.
The target window will be toggled between TopMost and TopLevel styles.
Experiment 3:
I have a Logitech multimedia Keyboard and have not installed the software that came with it. I was using my own OSD script which used VOLUME_UP /DN/MUTE keys as hotkeys to trigger adjustment with SoundGet / SoundSet commands.
Now I have found that, the Shell is notified ( HSHELL_APPCOMMAND ) whenever I press a mulitmedia key. The HiWord of lParam contains the value of the MM key pressed. So I have altered my Volume Change OSD script to work without HotKeys or SoundSet command.Gui, Color, FFFFFF Gui, -Caption +Border +AlwaysOnTop +ToolWindow +LastFound hWnd := WinExist() , DllCall( "RegisterShellHookWindow", UInt,hWnd ) MsgNum := DllCall( "RegisterWindowMessage", Str,"SHELLHOOK" ) OnMessage( MsgNum, "ShellMessage" ) Gui, Add, Picture, x5 y5 w32 h32 Icon4 vIcon1, SndVol32.exe Gui, Add, Picture, x5 y5 w32 h32 Icon5 vIcon2, SndVol32.exe Loop,25 Gui, Add, Text, x+3 w5 h32 Hidden Border vText%A_Index% 0x4 ; Return ; // End of Auto-Exexute Section // ShellMessage( wParam,lParam ) { If ( wParam = 12 AND ( (lParam>>16) >= 8 OR (lParam>>16) <= 10) ) { Gui, Show SoundGet, Volume, MASTER, VOLUME SoundGet, Mute , , MUTE Loop, 25 IfLessOrEqual, A_Index, % Round(Volume/4), GuiControl, Show, Text%A_Index% Else GuiControl, Hide, Text%A_Index% IfEqual, Mute, On, GuiControl, Hide, Icon2 Else GuiControl, Show, Icon2 SetTimer, GuiEscape, 1234 } } GuiEscape: SetTimer, GuiEscape, OFF Gui, Hide
Simply put, when wParam is 12 ( HSHELL_APPCOMMAND ), the HiWord of lParam contains one of the following constants:
APPCOMMAND_BROWSER_BACKWARD = 1
APPCOMMAND_BROWSER_FORWARD = 2
APPCOMMAND_BROWSER_REFRESH = 3
APPCOMMAND_BROWSER_STOP = 4
APPCOMMAND_BROWSER_SEARCH = 5
APPCOMMAND_BROWSER_FAVORITES = 6
APPCOMMAND_BROWSER_HOME = 7
APPCOMMAND_VOLUME_MUTE = 8
APPCOMMAND_VOLUME_DOWN = 9
APPCOMMAND_VOLUME_UP = 10
APPCOMMAND_MEDIA_NEXTTRACK = 11
APPCOMMAND_MEDIA_PREVIOUSTRACK = 12
APPCOMMAND_MEDIA_STOP = 13
APPCOMMAND_MEDIA_PLAY_PAUSE = 14
APPCOMMAND_LAUNCH_MAIL = 15
APPCOMMAND_LAUNCH_MEDIA_SELECT = 16
APPCOMMAND_LAUNCH_APP1 = 17
APPCOMMAND_LAUNCH_APP2 = 18
APPCOMMAND_BASS_DOWN = 19
APPCOMMAND_BASS_BOOST = 20
APPCOMMAND_BASS_UP = 21
APPCOMMAND_TREBLE_DOWN = 22
APPCOMMAND_TREBLE_UP = 23
APPCOMMAND_MICROPHONE_VOLUME_MUTE = 24
APPCOMMAND_MICROPHONE_VOLUME_DOWN = 25
APPCOMMAND_MICROPHONE_VOLUME_UP = 26
APPCOMMAND_HELP = 27
APPCOMMAND_FIND = 28
APPCOMMAND_NEW = 29
APPCOMMAND_OPEN = 30
APPCOMMAND_CLOSE = 31
APPCOMMAND_SAVE = 32
APPCOMMAND_PRINT = 33
APPCOMMAND_UNDO = 34
APPCOMMAND_REDO = 35
APPCOMMAND_COPY = 36
APPCOMMAND_CUT = 37
APPCOMMAND_PASTE = 38
APPCOMMAND_REPLY_TO_MAIL = 39
APPCOMMAND_FORWARD_MAIL = 40
APPCOMMAND_SEND_MAIL = 41
APPCOMMAND_SPELL_CHECK = 42
APPCOMMAND_DICTATE_OR_COMMAND_CONTROL_TOGGLE = 43
APPCOMMAND_MIC_ON_OFF_TOGGLE = 44
APPCOMMAND_CORRECTION_LIST = 45
Experiment 4:
While trying to study and understand the messages I wrote this crude Shell spy to monitor the messages being received by the Shell :#Persistent Menu,Tray,Add Menu,Tray,Add, &Show, GuiShow Menu,Tray,Default, &Show Gui, Font, s9, Courier New Gui +ToolWindow +AlwaysOnTop +Resize +LastFound hWnd := WinExist() DllCall( "RegisterShellHookWindow", UInt,hWnd ) MsgNum := DllCall( "RegisterWindowMessage", Str,"SHELLHOOK" ) OnMessage( MsgNum, "ShellMessages" ) Gui, Add, Edit, w512 h512 vMsgs hwndEditC +ReadOnly Gui, Show, x10 y10, Shell Spy MsgNames = ( HSHELL_WINDOWCREATED HSHELL_WINDOWDESTROYED HSHELL_ACTIVATESHELLWINDOW HSHELL_WINDOWACTIVATED HSHELL_GETMINRECT HSHELL_REDRAW HSHELL_TASKMAN HSHELL_LANGUAGE HSHELL_SYSMENU HSHELL_ENDTASK HSHELL_ACCESSIBILITYSTATE HSHELL_APPCOMMAND HSHELL_WINDOWREPLACED HSHELL_WINDOWREPLACING HSHELL_HIGHBIT HSHELL_FLASH HSHELL_RUDEAPPACTIVATED ) AppCommands = ( APPCOMMAND_BROWSER_BACKWARD = 1 APPCOMMAND_BROWSER_FORWARD = 2 APPCOMMAND_BROWSER_REFRESH = 3 APPCOMMAND_BROWSER_STOP = 4 APPCOMMAND_BROWSER_SEARCH = 5 APPCOMMAND_BROWSER_FAVORITES = 6 APPCOMMAND_BROWSER_HOME = 7 APPCOMMAND_VOLUME_MUTE = 8 APPCOMMAND_VOLUME_DOWN = 9 APPCOMMAND_VOLUME_UP = 10 APPCOMMAND_MEDIA_NEXTTRACK = 11 APPCOMMAND_MEDIA_PREVIOUSTRACK = 12 APPCOMMAND_MEDIA_STOP = 13 APPCOMMAND_MEDIA_PLAY_PAUSE = 14 APPCOMMAND_LAUNCH_MAIL = 15 APPCOMMAND_LAUNCH_MEDIA_SELECT = 16 APPCOMMAND_LAUNCH_APP1 = 17 APPCOMMAND_LAUNCH_APP2 = 18 APPCOMMAND_BASS_DOWN = 19 APPCOMMAND_BASS_BOOST = 20 APPCOMMAND_BASS_UP = 21 APPCOMMAND_TREBLE_DOWN = 22 APPCOMMAND_TREBLE_UP = 23 APPCOMMAND_MICROPHONE_VOLUME_MUTE = 24 APPCOMMAND_MICROPHONE_VOLUME_DOWN = 25 APPCOMMAND_MICROPHONE_VOLUME_UP = 26 APPCOMMAND_HELP = 27 APPCOMMAND_FIND = 28 APPCOMMAND_NEW = 29 APPCOMMAND_OPEN = 30 APPCOMMAND_CLOSE = 31 APPCOMMAND_SAVE = 32 APPCOMMAND_PRINT = 33 APPCOMMAND_UNDO = 34 APPCOMMAND_REDO = 35 APPCOMMAND_COPY = 36 APPCOMMAND_CUT = 37 APPCOMMAND_PASTE = 38 APPCOMMAND_REPLY_TO_MAIL = 39 APPCOMMAND_FORWARD_MAIL = 40 APPCOMMAND_SEND_MAIL = 41 APPCOMMAND_SPELL_CHECK = 42 APPCOMMAND_DICTATE_OR_COMMAND_CONTROL_TOGGLE = 43 APPCOMMAND_MIC_ON_OFF_TOGGLE = 44 APPCOMMAND_CORRECTION_LIST = 45 ) Return ShellMessages( wP,lP ) { Global EditC Global mVal := lP GuiControlGet, Msgs Routine := GetMessageName( wP ) IfEqual,Routine,, SetEnv, Routine, UNKNOWN GuiControl,, Msgs, % Msgs "`n`n" Routine " [" wP "]" If IsLabel(Routine) GoSub, %Routine% ControlSend,, ^{End}, ahk_id %EditC% } GetMessageName( FieldN=0 ) { Global MsgNames Loop, Parse, MsgNames, `n IfEqual, A_Index, %FieldN%, Return, A_LoopField } GetAppCommand( FieldN=0 ) { Global AppCommands Loop, Parse, AppCommands, `n IfEqual, A_Index, %FieldN%, Return, A_LoopField } UNKNOWN: HSHELL_WINDOWCREATED: HSHELL_WINDOWACTIVATED: HSHELL_WINDOWDESTROYED: HSHELL_REDRAW: HSHELL_FLASH: HSHELL_ENDTASK: HSHELL_WINDOWREPLACING: HSHELL_WINDOWREPLACED: HSHELL_RUDEAPPACTIVATED: WinGetTitle, Title, ahk_id %mVal% WinGetClass, Class, ahk_id %mVal% GuiControlGet, Msgs GuiControl,, Msgs , % Msgs "`n`nhWnd`t: " WinExist("ahk_id" mVal) "`nTitle`t: " Title "`nClass`t: " Class Return HSHELL_GETMINRECT: Return HSHELL_APPCOMMAND: GuiControlGet, Msgs GuiControl,, Msgs, % Msgs " // " GetAppCommand( mVal >> 16 ) Return GuiClose: Gui, Show, Hide Return GuiShow: Gui, Show, Return
It is not exhaustive, but useful to understand how the stuff works.
With the above code running, Run Calculator and change it from Standard to Scientific mode.
One will find that the Calculator window is destroyed and created again resulting in the change of handle. ( I did not know it )
Interestingly I found that an undocumented ( AFAIK ) value of 0x8006 ( 32774 ) is received by the Shell whenever a Window is Flashing its Titlebar/Taskbar button. The following code activates a window that is flashing: ( not sure whether it will work for everyone ) :Gui +LastFound hWnd := WinExist() , DllCall( "RegisterShellHookWindow", UInt,hWnd ) MsgNum := DllCall( "RegisterWindowMessage", Str,"SHELLHOOK" ) OnMessage( MsgNum, "ShellMessage" ) Return ; // End of Auto-Execute Section // ShellMessage( wParam,lParam ) { If ( wParam = 0x8006 ) ; 0x8006 is 32774 as shown in Spy! { WinActivate, ahk_id %lParam% } }
Case: problems activating windows by frenchSteve
If you want to contain/restrict the WinActivation to a particular class of Window, then set a condition using WinGetClass command.
Will try to post more examples when I find them
[How to] Hook on to Shell to receive its messages?
Started by
SKAN
, May 22 2007 08:17 AM
73 replies to this topic
#1
-
Posted 22 May 2007 - 08:17 AM
Now, this is a real trick! :idea:
Thx Skan, amazing work.
Thx Skan, amazing work.
#3
-
Posted 22 May 2007 - 09:21 AM
Wow, this answer lot of recurrent requests at once, superb!
#4
-
Posted 22 May 2007 - 10:33 AM
vPhiLho := RegExReplace("Philippe Lhoste", "^(\w{3})\w*\s+\b(\w{3})\w*$", "$1$2")
Hi Skan, I've found that you wrote:
How is supposed to detect when a window is being minimized or resized?? I cannot receive any HSHELL_GETMINRECT when minimizing/maximizing a window, only a HSHELL_WINDOWACTIVATED appears to the shell listener. What do you mean with "with a shellhook structure "? Any idea?. Thank you.The shell receives HSHELL_GETMINRECT ( with a shellhook structure ) whenever a window is being Minimised/Maximised. A script may monitor it to Minimize a window to the tray.
#7
-
Posted 13 October 2007 - 05:47 PM
Experiment 5:
The shell receives HSHELL_GETMINRECT ( with a shellhook structure ) whenever a window is being Minimised/Maximised. A script may monitor it to Minimize a window to the tray. Here is a working example:Gui +LastFound hWnd := WinExist() DllCall( "RegisterShellHookWindow", UInt,hWnd ) MsgNum := DllCall( "RegisterWindowMessage", Str,"SHELLHOOK" ) OnMessage( MsgNum, "ShellMessage" ) Return ; // End of Auto-Execute Section // ShellMessage( wParam,lParam ) { If ( wParam = 5 ) { ; HSHELL_GETMINRECT wID := NumGet( lParam+0 ) ; first member ( DWord ) of SHELLHOOKINFO structure is hWnd WinGet, mState, MinMax, ahk_id %wID% If ( mState = -1 ) { ; Window is being minimized WinGetTitle, Title, ahk_id %wID% TrayTip, Window was minimized!, %Title% } } }
@shader: The above example code works for me. Let me know the status so I will update the original post.
Thanks.
Edit:
Tested in:
Win XP SP2
Vista Home Premium
#8
-
Posted 13 October 2007 - 10:05 PM
Hi Skan, it doesnt work for me. OnMessage never return a 5 wParam message when minimized. I dont know why it doesnt return that message. Thanks.
#9
-
Posted 14 October 2007 - 11:09 AM
I am unsure about this, but try replacing
DllCall( "RegisterWindowMessage", Str,"SHELLHOOK" )
with
DllCall( "RegisterWindowMessageW", Str,"SHELLHOOK" )
:roll:
DllCall( "RegisterWindowMessage", Str,"SHELLHOOK" )
with
DllCall( "RegisterWindowMessageW", Str,"SHELLHOOK" )
:roll:
#12
-
Posted 14 October 2007 - 08:22 PM
No, it doesnt work. I hope someone can tell if he's having same behaviour or is a fault of my system. Thanks.
#13
-
Posted 14 October 2007 - 10:40 PM
Does work at XP Prof SP2 German.
Nice thing
Thalon
Nice thing
Thalon
#14
-
Posted 15 October 2007 - 09:57 AM