Feren6, I hope I am not overwhelming you, but I once clipped this text and I have not yet used it, I hope it can help you, especially the HSHELL_ENDTASK.
The documented values for wParam are:
1. HSHELL_WINDOWCREATED
2. HSHELL_WINDOWDESTROYED
3. HSHELL_ACTIVATESHELLWINDOW
4. HSHELL_WINDOWACTIVATED
5. HSHELL_GETMINRECT
6. HSHELL_REDRAW
7. HSHELL_TASKMAN
8. HSHELL_LANGUAGE
9. HSHELL_SYSMENU
10. HSHELL_ENDTASK
11. HSHELL_ACCESSIBILITYSTATE
12. HSHELL_APPCOMMAND
13. HSHELL_WINDOWREPLACED
14. HSHELL_WINDOWREPLACING
15. HSHELL_HIGHBIT
16. HSHELL_FLASH
17. HSHELL_RUDEAPPACTIVATED
lParam 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.
Code:
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.
Code:
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.
Code:
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 :
Code:
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
nhWndt: " WinExist("ahk_id" mVal) "
nTitlet: " 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 ) :
Code:
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%
}
}