Jump to content



Photo

Easy shell hooking example


  • Please log in to reply
36 replies to this topic

#1 Siao

Siao

    RTFM, foo!

  • Active Members
  • PipPipPipPipPipPip
  • 937 posts

Posted 06 November 2007 - 03:25 PM

Well, forum search on this didn't return anything noteworthy for me, so here we go.

Shell hooking is monitoring window activity, which helps when automating apps. This particular method is pretty similar to installing WH_SHELL hook with SetWindowsHookEx, but instead of callback proc it makes use of window's proc, so GuiRegisterMsg() can be used.

How to set it up:

First we have to register unique message - RegisterWindowMessage("SHELLHOOK")
Then GuiRegisterMsg() the message with a handler function, and of course hook up our GUI with RegisterShellHookWindow (and unregister when not needed anymore).
And that's pretty much it.

What it does:

$HSHELL_WINDOWCREATED, $HSHELL_WINDOWACTIVATED, $SHELL_WINDOWDESTROYED
Notifies when some window is created, activated or destroyed. Gives window handle.
$HSHELL_REDRAW
Notifies when some window (taskbar button?) is redrawed, mainly due to change of its title. Gives window handle.
$HSHELL_FLASH
Notifies when some window is flashing (is followed with $HSHELL_REDRAW). Gives window handle.
$HSHELL_GETMINRECT
Happens when some window is minimized/maximized, and is supposed to give rectangle coords with SHELLHOOKINFO structure, but that part isn't working for me, only window handle is.
$HSHELL_ACCESSIBILITYSTATE
Notifies when some accessibility options change...
$HSHELL_SYSMENU
Notifies when some window's system menu is brought up by right clicking its taskbar button. Gives window handle.

Other codes never triggered for me, but YMMV.

Much of this functionality can be achieved by polling WinActivate, WinExists and etc., but that is so uncool (not to mention CPU usage it may take if you want to monitor all windows). <_<
I threw this together when I was experimenting with various ways to keep other apps from stealing keyboard focus from my text editor.
Would be possible to write some taskbar-like utility using these too.

AutoIt         
#include <GuiConstants.au3> #include <Misc.au3> #NoTrayIcon Opt("GUICloseOnESC", 0) Opt("GUIOnEventMode", 1) Opt("WinWaitDelay", 0) Global Const $WM_SYSCOMMAND = 0x0112 Global Const $SC_MOVE = 0xF010 Global Const $SC_SIZE = 0xF000 Global Const $SC_CLOSE = 0xF060 ;ShellHook notification codes: Global Const $HSHELL_WINDOWCREATED = 1; Global Const $HSHELL_WINDOWDESTROYED = 2; Global Const $HSHELL_ACTIVATESHELLWINDOW = 3; Global Const $HSHELL_WINDOWACTIVATED = 4; Global Const $HSHELL_GETMINRECT = 5; Global Const $HSHELL_REDRAW = 6; Global Const $HSHELL_TASKMAN = 7; Global Const $HSHELL_LANGUAGE = 8; Global Const $HSHELL_SYSMENU = 9; Global Const $HSHELL_ENDTASK = 10; Global Const $HSHELL_ACCESSIBILITYSTATE = 11; Global Const $HSHELL_APPCOMMAND = 12; Global Const $HSHELL_WINDOWREPLACED = 13; Global Const $HSHELL_WINDOWREPLACING = 14; Global Const $HSHELL_RUDEAPPACTIVATED = 32772; Global Const $HSHELL_FLASH = 32774; Global $bHook = 1 ;GUI stuff: Global $iGuiW = 400, $iGuiH = 50, $sTitle = "Shell Hooker", $aBtnText[2] = ["START", "STOP"] $hGui = GUICreate($sTitle, $iGuiW, $iGuiH, -1, 0, $WS_POPUP+$WS_BORDER, $WS_EX_TOPMOST) GUISetOnEvent($GUI_EVENT_CLOSE, "SysEvents") GUISetOnEvent($GUI_EVENT_PRIMARYDOWN, "SysEvents") GUIRegisterMsg($WM_SYSCOMMAND, "On_WM_SYSCOMMAND") $cBtnMini = GUICtrlCreateButton("v", $iGuiW-$iGuiH, 0, $iGuiH/2, $iGuiH/2) GUICtrlSetOnEvent(-1, "CtrlEvents") GUICtrlSetTip(-1, "Minimize") $cBtnClose = GUICtrlCreateButton("X", $iGuiW-$iGuiH/2, 0, $iGuiH/2, $iGuiH/2) GUICtrlSetOnEvent(-1, "CtrlEvents") GUICtrlSetTip(-1, "Exit") $cBtnHook = GUICtrlCreateButton("", $iGuiW-$iGuiH, $iGuiH/2, $iGuiH, $iGuiH/2) GUICtrlSetData(-1, $aBtnText[$bHook]) GUICtrlSetTip(-1, "Hook/Unhook Shell") GUICtrlSetOnEvent(-1, "CtrlEvents") $cList = GUICtrlCreateList("", 0, 0, $iGuiW-$iGuiH-1, $iGuiH, $LBS_NOINTEGRALHEIGHT+$WS_VSCROLL) GUICtrlSetOnEvent(-1, "CtrlEvents") ;Hook stuff: GUIRegisterMsg(RegisterWindowMessage("SHELLHOOK"), "HShellWndProc") ShellHookWindow($hGui, $bHook) GUISetState() While 1     Sleep(1000) WEnd Func SysEvents()     Switch @GUI_CtrlId         Case $GUI_EVENT_CLOSE             Exit         Case $GUI_EVENT_PRIMARYDOWN             ;CTRL + Left click to drag GUI             If _IsPressed("11") Then                 DllCall("user32.dll", "int", "ReleaseCapture")                 DllCall("user32.dll", "int", "SendMessage", "hWnd", $hGui, "int", 0xA1, "int", 2, "int", 0)             EndIf     EndSwitch EndFunc Func CtrlEvents()     Switch @GUI_CtrlId         Case $cBtnMini             GUISetState(@SW_MINIMIZE)         Case $cBtnClose             _SendMessage($hGui, $WM_SYSCOMMAND, $SC_CLOSE, 0)         Case $cBtnHook             $bHook = BitXOR($bHook, 1)             ShellHookWindow($hGui, $bHook)             GUICtrlSetData($cBtnHook, $aBtnText[$bHook])     EndSwitch   EndFunc Func HShellWndProc($hWnd, $Msg, $wParam, $lParam)     Switch $wParam         Case $HSHELL_WINDOWCREATED             MsgPrint("Window created: " & $lParam & " (" & WinGetTitle($lParam) & ")")         Case $HSHELL_WINDOWDESTROYED             MsgPrint("Window destroyed: " & $lParam)         Case $HSHELL_ACTIVATESHELLWINDOW             MsgPrint("HSHELL_ACTIVATESHELLWINDOW: Not used.");         Case $HSHELL_WINDOWACTIVATED             MsgPrint("Window activated: " & $lParam & " (" & WinGetTitle($lParam) & ")")         Case $HSHELL_GETMINRECT             Local $tSHELLHOOKINFO = DllStructCreate("hwnd hwnd;int left;long top;long right;long bottom", $lParam)             MsgPrint("HSHELL_GETMINRECT: " & HWnd(DllStructGetData($tSHELLHOOKINFO, "hwnd")) & ' (' & _                                             DllStructGetData($tSHELLHOOKINFO, "left") & ',' & _                                             DllStructGetData($tSHELLHOOKINFO, "top") & ',' & _                                              DllStructGetData($tSHELLHOOKINFO, "right") & ',' & _                                                DllStructGetData($tSHELLHOOKINFO, "bottom") & ')')         Case $HSHELL_REDRAW             MsgPrint("Window redraw: " & $lParam & " (" & WinGetTitle($lParam) & ")")         Case $HSHELL_TASKMAN             MsgPrint("HSHELL_TASKMAN: Can be ignored.");         Case $HSHELL_LANGUAGE             MsgPrint("HSHELL_LANGUAGE: " & $lParam);         Case $HSHELL_SYSMENU             MsgPrint("HSHELL_SYSMENU: " & $lParam);         Case $HSHELL_ENDTASK             MsgPrint("Window needs to be closed: " & $lParam & " (" & WinGetTitle($lParam) & ")")         Case $HSHELL_ACCESSIBILITYSTATE             MsgPrint("HSHELL_ACCESSIBILITYSTATE: " & $lParam);         Case $HSHELL_APPCOMMAND             MsgPrint("HSHELL_APPCOMMAND: " & $lParam);         Case $HSHELL_WINDOWREPLACED             MsgPrint("Window replaced: " & $lParam & " (" & WinGetTitle($lParam) & ")")         Case $HSHELL_WINDOWREPLACING             MsgPrint("Window replacing: " & $lParam & " (" & WinGetTitle($lParam) & ")")         Case $HSHELL_RUDEAPPACTIVATED             MsgPrint("HSHELL_RUDEAPPACTIVATED: " & $lParam);         Case $HSHELL_FLASH             MsgPrint("Window flash: " & $lParam & " (" & WinGetTitle($lParam) & ")")         Case Else             MsgPrint("Unknown ShellHook message: " & $wParam & " , " & $lParam)     EndSwitch EndFunc ;register/unregister ShellHook Func ShellHookWindow($hWnd, $bFlag)     Local $sFunc = 'DeregisterShellHookWindow'     If $bFlag Then $sFunc = 'RegisterShellHookWindow'     Local $aRet = DllCall('user32.dll', 'int', $sFunc, 'hwnd', $hWnd)     MsgPrint($sFunc & ' = ' & $aRet[0])     Return $aRet[0] EndFunc Func MsgPrint($sText)     ConsoleWrite($sText & @CRLF)     GUICtrlSendMsg($cList, $LB_SETCURSEL, GUICtrlSendMsg($cList, $LB_ADDSTRING, 0, $sText), 0) EndFunc ;register window message Func RegisterWindowMessage($sText)     Local $aRet = DllCall('user32.dll', 'int', 'RegisterWindowMessage', 'str', $sText)     Return $aRet[0] EndFunc Func On_WM_SYSCOMMAND($hWnd, $Msg, $wParam, $lParam)     Switch BitAND($wParam, 0xFFF0)         Case $SC_MOVE, $SC_SIZE         Case $SC_CLOSE             ShellHookWindow($hGui, 0)             Return $GUI_RUNDEFMSG             ;Exit     EndSwitch EndFunc

Attached Files


Edited by Siao, 06 November 2007 - 04:04 PM.

"be smart, drink your wine"





#2 A. Percy

A. Percy

    VW Sedan user

  • Active Members
  • PipPipPipPipPipPip
  • 561 posts

Posted 06 November 2007 - 03:48 PM

Nice!
Good work! <_<
Só o que posso lhe dizer, bom é quando faz mal!My work:Au3Irrlicht - Irrlicht for AutoItMsAgentLib - An UDF for MSAgentAu3GlPlugin T2 - A 3D plugin for AutoIt...OpenGl Plugin - The old version of Au3GlPlugin.MAC Address Changer - Changes the MAC AddressItCopter - A dragonfly R/C helicopter simulator

Posted Image VW Bug userPosted Image

Pinheiral (Pinewood) city: http://pt.wikipedia.org/wiki/Pinheiral

#3 zfisherdrums

zfisherdrums

    Universalist

  • Active Members
  • PipPipPipPipPipPip
  • 391 posts

Posted 06 November 2007 - 03:59 PM

Very nice!!!
I will enjoy using the functionality you have demonstrated in our automation framework(s).
Thank you so very much for sharing this!

Zach...

#4 JohnBailey

JohnBailey

    Scripter

  • Active Members
  • PipPipPipPipPipPip
  • 943 posts

Posted 06 November 2007 - 07:32 PM

AMAZING!!!! WELL DONE <_<
A decision is a powerful thing

#5 JohnBailey

JohnBailey

    Scripter

  • Active Members
  • PipPipPipPipPipPip
  • 943 posts

Posted 06 November 2007 - 07:40 PM

You answered a problem I had!

See: http://www.autoitscript.com/forum/index.php?showtopic=56129

THANK YOU THANK YOU THANK YOU
A decision is a powerful thing

#6 magician13134

magician13134

    Universalist

  • Active Members
  • PipPipPipPipPipPip
  • 394 posts

Posted 13 November 2007 - 08:07 PM

Very good work! My only question is how to use this without a GUI. I tried commenting out everything that looked like GUI stuff, but then it didn't work (go figure :P)

I want to use these hooks in a program I'm writing, so I just want your script to alert my program anytime one of these events happens. Thanks for any help!

Also, is there any way to grab the name of a window before it gets closed?

Edited by magician13134, 13 November 2007 - 08:13 PM.


#7 Siao

Siao

    RTFM, foo!

  • Active Members
  • PipPipPipPipPipPip
  • 937 posts

Posted 14 November 2007 - 03:45 PM

Very good work! My only question is how to use this without a GUI. I tried commenting out everything that looked like GUI stuff, but then it didn't work (go figure :P)

I want to use these hooks in a program I'm writing, so I just want your script to alert my program anytime one of these events happens. Thanks for any help!

You need a window which will be receiving the messages. It doesn't have to be visible. So you need GUICreate.

Also, is there any way to grab the name of a window before it gets closed?

Using this method?
I assume these notifications are received post factum. So when you receive "window destroyed" notification, there's no such window to get the title from anymore.
Keep a list, array or whatever, of handles and titles from $HSHELL_WINDOWCREATED, $HSHELL_REDRAW (and possibly $HSHELL_WINDOWACTIVATED). This will allow you to get the last known window title by the handle you get from $SHELL_WINDOWDESTROYED.
"be smart, drink your wine"

#8 magician13134

magician13134

    Universalist

  • Active Members
  • PipPipPipPipPipPip
  • 394 posts

Posted 14 November 2007 - 08:05 PM

Ok, cool, thanks for your answers. Also, I'm using a pre-stored WinList() array that gets updated every time a window is created or destroyed to find the name of the hWnd. Thanks for all your help.

#9 Armand

Armand

    Universalist

  • Active Members
  • PipPipPipPipPipPip
  • 541 posts

Posted 24 November 2007 - 07:32 AM

OVERWHELMING WORK !!!!

p.s - where can i find all the windows msgs ?!

#10 Fossil Rock

Fossil Rock

    ASCII a stupid question,… get a stupid ANSI.

  • Active Members
  • PipPipPipPipPipPip
  • 1,084 posts

Posted 03 January 2008 - 02:13 PM

Would something like this be able to "grab" text from a textbox while the app is minimized or would it require something completely different? Basically intercepting the messages before getting to the textbox.

Agreement is not necessary - thinking for one's self is!

Posted Image

Posted Image


#11 Oldschool

Oldschool

    Universalist

  • Active Members
  • PipPipPipPipPip
  • 254 posts

Posted 18 March 2008 - 04:06 PM

OMG, I just found this Siao...great work.

4 months later... :)

#12 koushik

koushik

    Seeker

  • Active Members
  • 12 posts

Posted 24 June 2008 - 09:52 PM

good work!!

Thanks for sharing

#13 Skrip

Skrip

    Psychonaut

  • Active Members
  • PipPipPipPipPipPip
  • 2,340 posts

Posted 25 June 2008 - 02:29 AM

very nice.

We're trapped in the belly of this horrible machine.And the machine is bleeding to death...


#14 rasim

rasim

    Gray Scripter

  • Active Members
  • PipPipPipPipPipPip
  • 1,708 posts

Posted 03 July 2008 - 02:11 PM

Very nice and useful! Five stars! Thank you Siao :muttley:
OS: Windows XP SP3, AutoIt version: 3.3.0.0Posted Image My Projects: Free_Resources | Splitter | wgetGUI | UnRARIt | USBMon | CDROM-Control | Volume Serial Changer | WinTrayPosted Image My UDFs: _ScreenSetting | ListView_Progress | ContextHelp | ToolTip_UDF | UnRAR | Zip32 | BassMod | ShellTreeView | GuiHotKey | 7ZipPosted Image My Examples: TrayIcon_Click | SystemTray_Refresh | _ListView_Sort | CPUmonLike above scripts? Please rate the topic Posted Image

#15 Zedna

Zedna

    AutoIt rulez!

  • MVPs
  • 8,315 posts

Posted 03 July 2008 - 02:20 PM

Very nice siao.
Your examples are really good!

#16 sandin

sandin

    Universalist

  • Active Members
  • PipPipPipPipPipPip
  • 569 posts

Posted 04 July 2008 - 06:22 PM

This is soo cool!!, I want this to use in my script, but it's not hooking all windows like task manager. Is it possible to make it hook all windows? oO

#17 RobOtter

RobOtter

    Seeker

  • Active Members
  • 11 posts

Posted 02 February 2009 - 09:39 AM

I have the same question:
Nearly all window creation events of the system control windows are not recognized. Interesting enough, destroying the windows is always recognized...

Any hints?

#18 JonusC

JonusC

    Wayfarer

  • Active Members
  • Pip
  • 54 posts

Posted 03 February 2009 - 08:25 AM

Would this allow me to add items to the system menu (context menu of a programs' taskbar)? I can't figure it out... if so, WOW.

#19 JonusC

JonusC

    Wayfarer

  • Active Members
  • Pip
  • 54 posts

Posted 19 November 2009 - 01:40 AM

Once we add a new menu item (for example, in an external System Menu), how does one get the Control ID of the new clicked MenuItem? I can't seem to get it to send a message back to the AutoIt script/GUI. I tried a few things; a new WM_SYSCOMMAND case, the DummyGUI method, some other random nonsense and experimentation... couldn't get anything to fire as far as Winspector could tell. Maybe it's a problem with On Event mode? Or unique to Windows 7? UAC is off for this machine though.

Any tips or pointers would be totally awesome - I'm not asking for an example, but if someone knows a specific function I should try out let me know :)

For all those wondering, I'm basically trying to create a script like PowerMenu - only better/extensible since it will be open source (the original creator of the amazing PowerMenu prog has disappeared for years and kept it closed source...) - I would of posted what I have so far but it's largely identical to the OP's example with pretty much some extra Menu UDF commands (that part works) and cheap method of hooking any active window (it works for CMD.EXE and Task Manager!).

Cheers!

#20 wraithdu

wraithdu

    I am less fun than a twisted ankle.

  • MVPs
  • 2,137 posts

Posted 19 November 2009 - 04:56 AM

You won't like the answer. Here's what I think you'd have to do:

Inject a DLL into the target process, subclass the main window procedure so you can intercept the process's window messages, then set up some interprocess communication with your AutoIt script.




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users