Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

[tool] WinEventHook Messages


  • Please log in to reply
24 replies to this topic
pantagruel
  • Members
  • 97 posts
  • Last active: Oct 01 2013 08:18 PM
  • Joined: 08 Oct 2006
Hi,

I have a script that works reasonably well in my normal OS for hooking to alert boxes, but when I put it in a VM (that is running over Remote Desktop) I can't catch anything. The script is the following:

#SingleInstance Force
#Persistent
SetBatchLines,-1
HookProcAdr := RegisterCallback( "HookProc", "F" )
hWinEventHook := SetWinEventHook( 0x2, 0x2, 0, HookProcAdr, 0, 0, 0 )
OnExit, HandleExit
Return

HookProc( hWinEventHook, Event, hWnd, idObject, idChild, dwEventThread, dwmsEventTime )
{
   if Event ; EVENT_SYSTEM_ALERT = 0x2
   { 

      WinGetTitle, title, ahk_id %hWnd%
	If InStr( title, "msg.ahk" ){

SendInput,{Enter}


	}

If InStr( title, "test.ahk" ){

SendInput,{Enter}

 
	}
     
         
   }
}

SetWinEventHook(eventMin, eventMax, hmodWinEventProc, lpfnWinEventProc, idProcess, idThread, dwFlags)
{
   DllCall("CoInitialize", Uint, 0)
   return DllCall("SetWinEventHook"
   , Uint,eventMin   
   , Uint,eventMax   
   , Uint,hmodWinEventProc
   , Uint,lpfnWinEventProc
   , Uint,idProcess
   , Uint,idThread
   , Uint,dwFlags)   
}

UnhookWinEvent()
{
   Global
   DllCall( "UnhookWinEvent", Uint,hWinEventHook )
   DllCall( "GlobalFree", UInt,&HookProcAdr ) ; free up allocated memory for RegisterCallback
}

HandleExit:
UnhookWinEvent()
ExitApp
Return

the problem I have is it has to function inside of a VM at least - and probably over RD. the VM that is running is running Windows XP.

One thing is it definitely catches that the alert has happened, but in the environment in question I can't get the title of the window by using ahk_id hWnd....

Any ideas - things I should try?

I was thinking one obvious thing to do would be to when I catch such an event then just loop through windows looking for one matching the text I want.
Any better ideas than that?

zhuluobin
  • Members
  • 28 posts
  • Last active: Aug 07 2010 12:53 PM
  • Joined: 11 May 2009
i modified the example script for notepad to 'system properties', but the script only works since the second time i activate the window. i mean when 'system properties' window opens, nothing happens, i must switch to other window then switch back, the script works. why?

Mr_and_Mrs_D
  • Members
  • 164 posts
  • Last active: May 08 2013 08:09 PM
  • Joined: 19 Dec 2006
Thank you indeed for this hook !
I have known it for a year now but only lately I begin to understand it.
This is the only piece of code that detects creation of windows in an MDI app I work on.
My problem is to make it see window destruction (closing). When I hook the EVENT_OBJECT_DESTROY event I get all kinds of subcontrols being destroyed but not the window - is it possible to make the hook ignore (generic) controls and instead focus on windows ?
Thanks :)
XP SP3 Pro x32 / 7 x64 Pro - AHK 1.0.48.05

Mr_and_Mrs_D
  • Members
  • 164 posts
  • Last active: May 08 2013 08:09 PM
  • Joined: 19 Dec 2006
Question in my last post transferred here

EDIT 2011.10.13 21.37 UTC
I wasn't freeing properly + corrected the bug in version 3 (dwFlags were set to 0 instead of 1)
/EDIT
I post here a variation of serenity's hook using DllCall to retrieve class and title - not sure which is more efficient still DllCall is much "snappier" in getting the info :D
Commented out the sleep part and added EVENT_OBJECT_DESTROY hook :
; WinEventHook Messages v0.3 by Serenity
; http://www.autohotkey.com/forum/viewtopic.php?t=35659
#SingleInstance Force
#Persistent
SetBatchLines,-1
; Process, Priority,, High
ExcludeScriptMessages = 1 ; 0 to include
ExcludeGuiEvents = 1 ; 0 to include
Title := "WinEventHook Messages", Filters := "", Pause := 0
FilterMenu(), Gui()
ahk := WinExist(), WM_VSCROLL := 0x115, SB_BOTTOM := 7
HookProcAdr := RegisterCallback( "HookProc", "F" )
dwFlags := ( ExcludeScriptMessages = 1 ? 0x1 : 0x0 )
hWinEventHook1 := SetWinEventHook( 0x00008001, 0x00008001, 0, HookProcAdr, 0, 0, dwFlags )
hWinEventHook2 := SetWinEventHook( 0x1, 0x17, 0, HookProcAdr, 0, 0, dwFlags )
hooks = 2
Return

FilterMenu()
{
   Global FilterList
   Menu, Filter, Add, Filter &All, FilterAll
   Menu, Filter, Add, Filter &None, FilterNone
   Menu, Filter, Add
   FilterList = SOUND,ALERT,FOREGROUND,MENUSTART,MENUEND,MENUPOPUPSTART,MENUPOPUPEND
   ,CAPTURESTART,CAPTUREEND,MOVESIZESTART,MOVESIZEEND,CONTEXTHELPSTART
   ,CONTEXTHELPEND,DRAGDROPSTART,DRAGDROPEND,DIALOGSTART,DIALOGEND,SCROLLINGSTART
   ,SCROLLINGEND,SWITCHSTART,SWITCHEND,MINIMIZESTART,MINIMIZEEND

   Loop, Parse, FilterList, `,
   {
      If A_Loopfield
         Menu, Filter, Add, %A_Loopfield%, SetFilter
   }
   Menu, FilterMenu, Add, Message &Filter, :Filter
   Gui, Menu, FilterMenu
}

Gui()
{
   Global
   Gui, +LastFound +AlwaysOnTop +Resize ; +ToolWindow
   Gui, Margin, 0, 0
   Gui, Font, s8, Microsoft Sans Serif
   Gui, Color,, DEDEDE
   Gui, Add, ListView, w600 r10 vData +Grid +NoSort, Hwnd|idObject|idChild|Title|Class|Event|Message
   LV_ModifyCol( 1, 60 ), LV_ModifyCol( 2, 40), LV_ModifyCol( 3, 40)
   LV_ModifyCol( 4, 100 ), LV_ModifyCol( 5, 100 ), LV_ModifyCol( 7, 190 )
   Gui, Show,, %Title%
}

HookProc( hWinEventHook, Event, hWnd, idObject, idChild, dwEventThread, dwmsEventTime )
{
   Global Pause,WM_VSCROLL,SB_BOTTOM,ahk,Filters

   SetFormat, Integer, Dec
   Event += 0

   if Event = 1
      Message = EVENT_SYSTEM_SOUND
   else if Event = 2
      Message = EVENT_SYSTEM_ALERT
   else if Event = 3
      Message = EVENT_SYSTEM_FOREGROUND
   else if Event = 4
      Message = EVENT_SYSTEM_MENUSTART
   else if Event = 5
      Message = EVENT_SYSTEM_MENUEND
   else if Event = 6
      Message = EVENT_SYSTEM_MENUPOPUPSTART
   else if Event = 7
      Message = EVENT_SYSTEM_MENUPOPUPEND
   else if Event = 8
      Message = EVENT_SYSTEM_CAPTURESTART
   else if Event = 9
      Message = EVENT_SYSTEM_CAPTUREEND
   else if Event = 10
      Message = EVENT_SYSTEM_MOVESIZESTART
   else if Event = 11
      Message = EVENT_SYSTEM_MOVESIZEEND
   else if Event = 12
      Message = EVENT_SYSTEM_CONTEXTHELPSTART
   else if Event = 13
      Message = EVENT_SYSTEM_CONTEXTHELPEND
   else if Event = 14
      Message = EVENT_SYSTEM_DRAGDROPSTART
   else if Event = 15
      Message = EVENT_SYSTEM_DRAGDROPEND
   else if Event = 16
      Message = EVENT_SYSTEM_DIALOGSTART
   else if Event = 17
      Message = EVENT_SYSTEM_DIALOGEND
   else if Event = 18
      Message = EVENT_SYSTEM_SCROLLINGSTART
   else if Event = 19
      Message = EVENT_SYSTEM_SCROLLINGEND
   else if Event = 20
      Message = EVENT_SYSTEM_SWITCHSTART
   else if Event = 21
      Message = EVENT_SYSTEM_SWITCHEND
   else if Event = 22
      Message = EVENT_SYSTEM_MINIMIZESTART
   else if Event = 23
      Message = EVENT_SYSTEM_MINIMIZEEND
   else if Event = 32769
      Message = EVENT_OBJECT_DESTROY

   ; Sleep, 50 ; give a little time for WinGetTitle/WinGetActiveTitle functions, otherwise they return blank

   EventHex := Event
   SetFormat, Integer, Hex
   EventHex += 0, hWnd += 0, idObject += 0, idChild += 0

   If Event not in %Filters%
   {
      If ( Pause = 0 )
      {
         LV_Add( "", hWnd, idObject, idChild, WinGetTitle(hWnd), WinGetClass(hWnd), EventHex, Message )
      }
      SendMessage, WM_VSCROLL, SB_BOTTOM, 0, SysListView321, ahk_id %ahk%
   }
}

WinGetTitle( hwnd )
{
	; WinGetTitle, wtitle, ahk_id %hwnd%
	VarSetCapacity(sClass,47,0)
	DllCall("GetWindowTextA", "UInt", hWnd, "Str", sClass, "Int", VarSetCapacity(sClass)+1)
	wtitle := sClass
	sClass =
	Return wtitle
}

WinGetClass( hwnd )
{
	; WinGetClass, wclass, ahk_id %hwnd%
	VarSetCapacity(sClass,47,0)
	DllCall("GetClassNameA", "UInt", hWnd, "Str", sClass, "Int", VarSetCapacity(sClass)+1)
	wclass := sClass
	sClass =
	Return wclass
}

SetFilter:
Menu, Filter, ToggleCheck, %A_ThisMenuItem%
Loop, Parse, FilterList, `,
{
   If ( A_ThisMenuItem = A_Loopfield )
   {
      If A_Index in %Filters% ; remove from filter
      {
         Filter := A_Index
         Loop, Parse, Filters, `,
         {
            If ( A_Loopfield != Filter )
               NewFilters .= A_Loopfield . ( A_Loopfield != "" ? "`," : "" )
         }
         Filters := NewFilters, NewFilters := ""
      }
      Else ; add to filter
      {
         Filters .= A_Index . ","
      }
   }
}
Return

FilterAll:
Filters =
Loop, Parse, FilterList, `,
{
   Menu, Filter, Check, %A_Loopfield%
   Filters .= A_Index . ( A_Index != 23 ? "," : "" )
}
Return

FilterNone:
Loop, Parse, FilterList, `,
{
   Menu, Filter, UnCheck, %A_Loopfield%
   Filters =
}
Return

SetWinEventHook(eventMin, eventMax, hmodWinEventProc, lpfnWinEventProc, idProcess, idThread, dwFlags)
{
   DllCall("CoInitialize", Uint, 0)
   return DllCall("SetWinEventHook"
   , Uint,eventMin
   , Uint,eventMax
   , Uint,hmodWinEventProc
   , Uint,lpfnWinEventProc
   , Uint,idProcess
   , Uint,idThread
   , Uint,dwFlags)
}

NewHook()
{
   Global

   If HookSelected = 1
   {
      LV_GetText( SelHwnd, LV_GetNext(0, "Focused") )
      WinGet, idProcess, PID, ahk_id %SelHwnd%
      If idProcess =
      {
         Menu, Ctx, ToggleCheck, &Receive events from this process only
         HookSelected := !HookSelected
         Return
      }
   }
   Else
   {
      idProcess = 0 ; hook all
   }
   UnhookWinEvent()
   HookProcAdr := RegisterCallback( "HookProc", "F" ) ; new hook
   hWinEventHook1 := SetWinEventHook( 0x1, 0x17, 0, HookProcAdr, idProcess, 0, dwFlags )
   hWinEventHook2 := SetWinEventHook( 0x00008001, 0x00008001, 0, HookProcAdr, idProcess, 0, dwFlags )
}

UnhookWinEvent()
{
   Global
   Loop %hooks%
   {
	   DllCall( "UnhookWinEvent", Uint,hWinEventHook%A_Index% )
   }
   DllCall( "GlobalFree", UInt,&HookProcAdr ) ; free up allocated memory for RegisterCallback
}

GuiContextMenu:
Menu, Ctx, Add, &Receive events from this process only, HookMode
Menu, Ctx, Show
Return

HookMode:
Menu, Ctx, ToggleCheck, &Receive events from this process only
HookSelected := !HookSelected
NewHook()
Return

GuiSize:
GuiControl, Move, Data, w%A_GuiWidth% h%A_GuiHeight%
SendMessage, WM_VSCROLL, SB_BOTTOM, 0, SysListView321, ahk_id %ahk%
Return

GuiClose:
GuiEscape:
ExitApp
Return

#IfWinActive WinEventHook Messages
   C::LV_Delete()

   P::
   Pause :=! Pause, WinTitle := ( Pause = 0 ? Title : Title . " (Paused)" )
   WinSetTitle %WinTitle%
   Return

   R::Reload
   X::ExitApp

   ^C::
   Clipboard =
   Loop, % LV_GetCount("Col")
   {
      LV_GetText( lv%A_Index%, LV_GetNext(0, "Focused"), A_Index )
      Clipboard .= lv%A_Index% . ( A_Index != LV_GetCount("Col") ? "|" : "" )
   }
   Return
#IfWinActive
EDITWould be great if someone would add to it so that theGUI events were dropped there was a bug in serenity's v0.3 - now edited out
/EDIT
XP SP3 Pro x32 / 7 x64 Pro - AHK 1.0.48.05

bw800402
  • Members
  • 16 posts
  • Last active: Apr 17 2011 03:51 PM
  • Joined: 06 Apr 2011
I have recently tried to use the notepad popup blocker example but the first two parameters in the call to SetWinEventHook() set to 0x15. It seems that WinGetClass can not handle the hWnd parameter given by this message for switch_end. I can use MsgBox to see that hWnd is given a number and so the event is triggered but the hWnd is not a number WinGetClass can use.

I do realize that to trigger this event I use the alt+tab switcher and switch to Notepad.

What do i do to make this work?

EDIT: should probably include the code I am trying

#SingleInstance Force
#Persistent
SetBatchLines,-1
HookProcAdr := RegisterCallback( "HookProc", "F" )
hWinEventHook := SetWinEventHook( 0x15, 0x15, 0, HookProcAdr, 0, 0, 0 )
OnExit, HandleExit
Return

HookProc( hWinEventHook, Event, hWnd, idObject, idChild, dwEventThread, dwmsEventTime )
{
   if Event 
   {   
      WinGetClass, class, ahk_id %hWnd%
      If class = Notepad
         WinClose, ahk_class Notepad      
   }
}

SetWinEventHook(eventMin, eventMax, hmodWinEventProc, lpfnWinEventProc, idProcess, idThread, dwFlags)
{
   DllCall("CoInitialize", Uint, 0)
   return DllCall("SetWinEventHook"
   , Uint,eventMin   
   , Uint,eventMax   
   , Uint,hmodWinEventProc
   , Uint,lpfnWinEventProc
   , Uint,idProcess
   , Uint,idThread
   , Uint,dwFlags)   
}

UnhookWinEvent()
{
   Global
   DllCall( "UnhookWinEvent", Uint,hWinEventHook )
   DllCall( "GlobalFree", UInt,&HookProcAdr ) ; free up allocated memory for RegisterCallback
}

HandleExit:
UnhookWinEvent()
ExitApp
Return


Mr_and_Mrs_D
  • Members
  • 164 posts
  • Last active: May 08 2013 08:09 PM
  • Joined: 19 Dec 2006

I have recently tried to use the notepad popup blocker example but the first two parameters in the call to SetWinEventHook() set to 0x15. It seems that WinGetClass can not handle the hWnd parameter given by this message for switch_end. I can use MsgBox to see that hWnd is given a number and so the event is triggered but the hWnd is not a number WinGetClass can use.

I do realize that to trigger this event I use the alt+tab switcher and switch to Notepad.

What do i do to make this work?

EDIT: should probably include the code I am trying


WinGetClass works - however I have the impression that the handle returned is the Alt-Tab window handle - using window detective - anyone knows its class or how can I be sure about that ?

Anyway I updated the code in my post above - freeing properly and correcting a bug in Serenity's (had 0 instead of dwflags)

Anyone any ideas on hooking windows destruction using this (and not the subcontrols)
XP SP3 Pro x32 / 7 x64 Pro - AHK 1.0.48.05

Mr_and_Mrs_D
  • Members
  • 164 posts
  • Last active: May 08 2013 08:09 PM
  • Joined: 19 Dec 2006
As I understand it (tested) when one HookProc runs and another event is caught it will launch a new thread interrupting the HookProc that currently runs - which will resume as soon as the second one finishes. How can I prevent this while not dropping the new event ?
XP SP3 Pro x32 / 7 x64 Pro - AHK 1.0.48.05

random11
  • Members
  • 102 posts
  • Last active: May 27 2014 02:48 PM
  • Joined: 10 Dec 2008
does anyone know how to hook a WM_COMMAND message? using 0x0111 in the code doesnt work. I tried this:

#SingleInstance Force
#Persistent
SetTitleMatchMode, 1
SetBatchLines,-1
HookProcAdr := RegisterCallback( "HookProc", "F" )
hWinEventHook := SetWinEventHook( 0x0111, 0x0111, 0, HookProcAdr, 0, 0, 0 )
OnExit, HandleExit
Return

HookProc( hWinEventHook, Event, hWnd, idObject, idChild, dwEventThread, dwmsEventTime )
{
   if Event ; WM_Command = 0x0111
   {   
      WinGetClass, class, ahk_id %hWnd%
      If class = wxWindowClassNR
         MsgBox, Text   
   }
}

SetWinEventHook(eventMin, eventMax, hmodWinEventProc, lpfnWinEventProc, idProcess, idThread, dwFlags)
{
   DllCall("CoInitialize", Uint, 0)
   return DllCall("SetWinEventHook"
   , Uint,eventMin   
   , Uint,eventMax   
   , Uint,hmodWinEventProc
   , Uint,lpfnWinEventProc
   , Uint,idProcess
   , Uint,idThread
   , Uint,dwFlags)   
}

UnhookWinEvent()
{
   Global
   DllCall( "UnhookWinEvent", Uint,hWinEventHook )
   DllCall( "GlobalFree", UInt,&HookProcAdr ) ; free up allocated memory for RegisterCallback
}

HandleExit:
UnhookWinEvent()
ExitApp
Return


Mr_and_Mrs_D
  • Members
  • 164 posts
  • Last active: May 08 2013 08:09 PM
  • Joined: 19 Dec 2006

does anyone know how to hook a WM_COMMAND message? using 0x0111 in the code doesnt work. I tried this:


Why would it work - this is for EVENTS not messages
XP SP3 Pro x32 / 7 x64 Pro - AHK 1.0.48.05

lenina
  • New members
  • 2 posts
  • Last active: Sep 01 2015 03:27 AM
  • Joined: 31 Aug 2015

This script is treasure!!! Shad light on many questions of mine.