Am I misapplying OnMessage()? Topic is solved

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
m904begley
Posts: 7
Joined: 15 Jul 2016, 21:24

Am I misapplying OnMessage()?

22 Aug 2019, 17:01

Hello, everyone... I need my script to monitor an application (e.g. Notepad) and to respond if the window closes for any reason. I've been trying to use OnMessage() with no success so I know I'm probably barking up the wrong tree. I've studied the documentation but I just can't seem to grasp it. I'd appreciate any help.

Code: Select all

run, Notepad
OnMessage(0x10, WM_Close)
return

WM_Close:
Msgbox, Notepad was closed
return

esc::ExitApp
User avatar
Learning one
Posts: 173
Joined: 04 Oct 2013, 13:59
Location: Croatia
Contact:

Re: Am I misapplying OnMessage()?

22 Aug 2019, 17:11

Code: Select all

Run, notepad.exe
WinWait, ahk_class Notepad
WinWaitClose, ahk_class Notepad
MsgBox, Notepad is now closed.
m904begley
Posts: 7
Joined: 15 Jul 2016, 21:24

Re: Am I misapplying OnMessage()?

22 Aug 2019, 17:23

Thanks, Learning One, but this isn't what I need because the script pauses after the WinWaitClose command. I need the script to constantly monitor the window while continuing to run the script. Then, respond with an alert when the Close button is pressed. I hope I'm explaining it clearly enough.
tmplinshi
Posts: 1604
Joined: 01 Oct 2013, 14:57

Re: Am I misapplying OnMessage()?

22 Aug 2019, 19:03

With hook.dll (Download), but still unable to cancel WM_CLOSE.

Code: Select all

if (A_PtrSize = 8)
	throw "Please run the script using 32-bit AutoHotkey"

SetWorkingDir, %A_ScriptDir%
if !FileExist("hook.dll")
	throw "hook.dll is missing"

Run, Notepad,,, pid
WinWait, % "ahk_pid " pid

hWnd := WinExist()
hook1 := new HookMsg(hWnd, 0x10, "WM_CLOSE")
Return

WM_CLOSE(wParam, lParam, msg, hWnd) {
	global hook1
	MsgBox, close?
	hook1 := "" ; remove hook
	return 0
}

class HookMsg
{
	__New(hWnd, MsgNumber, FuncName)
	{
		; hook.dll -- https://www.autoitscript.com/forum/applications/core/interface/file/attachment.php?id=7166
		static _ := DllCall("LoadLibrary", "Str", "hook.dll", "Ptr")
		static WH_CALLWNDPROC := 4
		     , WH_GETMESSAGE := 3
		     , UM_ADDMESSAGE := (WM_USER := 1024) + 0x100

		this.hWnd := hWnd
		this.iThreadIdTarget := DllCall("GetWindowThreadProcessId", "Ptr", this.hWnd, "Ptr", 0)
		hook := DllCall("hook\InstallFilterDLL", "Int", WH_CALLWNDPROC, "Int", this.iThreadIdTarget, "Ptr", this.hWnd) ; 0 = Ok
		hookG := DllCall("hook\InstallFilterDLL", "Int", WH_GETMESSAGE, "Int", this.iThreadIdTarget, "Ptr", this.hWnd) ; 0 = Ok
		DllCall("SendMessage", "Ptr", this.hWnd, "UInt", UM_ADDMESSAGE, "UPtr", MsgNumber, "Ptr", A_ScriptHwnd, "Ptr")
		OnMessage(MsgNumber, FuncName)
	}

	__Delete()
	{
		DllCall("hook\UnInstallFilterDLL", "Int", this.iThreadIdTarget, "Ptr", this.hWnd, "Ptr", A_ScriptHwnd)
	}
}
Last edited by tmplinshi on 23 Aug 2019, 01:52, edited 1 time in total.
m904begley
Posts: 7
Joined: 15 Jul 2016, 21:24

Re: Am I misapplying OnMessage()?

22 Aug 2019, 20:03

Thanks for the reply, tmplinshi. Wow, this looks way above my paygrade. I DL'd MsgFilter and unzipped it into my working directory. When I run the script it opens Notepad but doesn't seem to be calling WM_Close when I close Notepad. Msgbox isn't popping up. Any ideas?
Odlanir
Posts: 659
Joined: 20 Oct 2016, 08:20

Re: Am I misapplying OnMessage()?

23 Aug 2019, 01:50

Code: Select all

active := true
run,notepad
SetTimer, look, 100
return

look:
   process, exist, notepad.exe
   if (!ErrorLevel && active) {
      MsgBox % "Notepad has been closed"
      active := false
      return
   } else if ErrorLevel{
      active := true
   }
   
return
____________________________________________________________________________
Windows 10 Pro 64 bit - Autohotkey v1.1.30.01 64-bit Unicode
tmplinshi
Posts: 1604
Joined: 01 Oct 2013, 14:57

Re: Am I misapplying OnMessage()?

23 Aug 2019, 02:47

oh, that hook.dll is 32-bit, it cannot run on 64-bit AutoHotkey. And the WM_CLOSE function should return 0, otherwise it'll crash the script. I've updated the code.

It seems you don't need monitor WM_CLOSE message. A SetTimer shoud be enough like what Odlanir did. Or maybe SHELLHOOK:

Code: Select all

#Persistent

Run, Notepad,,, pid
WinWait, % "ahk_pid " pid
global g_hWnd := WinExist()

DllCall("RegisterShellHookWindow", "Ptr", A_ScriptHwnd)
MsgNum := DllCall("RegisterWindowMessage", "Str", "SHELLHOOK")
OnMessage(MsgNum, "ShellMessage")
Return

ShellMessage(wParam, lParam) {
	if (wParam = 2) ; HSHELL_WINDOWDESTROYED
	&& (lParam = g_hWnd)
		MsgBox Notepad closed
}
Odlanir
Posts: 659
Joined: 20 Oct 2016, 08:20

Re: Am I misapplying OnMessage()?

23 Aug 2019, 03:14

@tmplinshi Your script works only with the notepad instance launched by the script itself. Maybe this should do the trick:

Code: Select all

ShellMessage(wParam, lParam) {
	WinGet,hwnd, ID, ahk_class Notepad
	if (wParam = 2) ; HSHELL_WINDOWDESTROYED
	&& (lParam = hWnd)
		MsgBox Notepad closed
}
____________________________________________________________________________
Windows 10 Pro 64 bit - Autohotkey v1.1.30.01 64-bit Unicode
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: Am I misapplying OnMessage()?

23 Aug 2019, 06:34

You call the function incorrectly, see onmessage,
A function's name or, in [v1.1.20+], a function object. To pass a literal function name, it must be enclosed in quotes.
Labels aren't supported.

Cheers :train:
tmplinshi
Posts: 1604
Joined: 01 Oct 2013, 14:57

Re: Am I misapplying OnMessage()?

23 Aug 2019, 07:08

@Odlanir Right. But it's better to get the target hwnd before OnMessage started, since ShellMessage function will be triggered frequently by many events such as HSHELL_WINDOWACTIVATED, etc..
When HSHELL_WINDOWDESTROYED event is received, the window is already destroyed, so WinGet, hwnd, ID, ahk_class Notepad will fail.
Maybe something like this:

Code: Select all

ShellMessage(wParam, lParam) {
	if (wParam = 2) ; HSHELL_WINDOWDESTROYED
	{
		if (lParam = g_hWnd)
			MsgBox Notepad closed
	}
	else if (wParam = 1) ; HSHELL_WINDOWCREATED
	{
		if h := WinExist("ahk_exe notepad.exe")
			g_hWnd := h
	}
}
m904begley
Posts: 7
Joined: 15 Jul 2016, 21:24

Re: Am I misapplying OnMessage()?

23 Aug 2019, 15:45

@Odlanir Right. But it's better to get the target hwnd before OnMessage started, since ShellMessage function will be triggered frequently by many events such as HSHELL_WINDOWACTIVATED, etc..
When HSHELL_WINDOWDESTROYED event is received, the window is already destroyed, so WinGet, hwnd, ID, ahk_class Notepad will fail.
Maybe something like this:

Code: Select all

ShellMessage(wParam, lParam) {
	if (wParam = 2) ; HSHELL_WINDOWDESTROYED
	{
		if (lParam = g_hWnd)
			MsgBox Notepad closed
	}
	else if (wParam = 1) ; HSHELL_WINDOWCREATED
	{
		if h := WinExist("ahk_exe notepad.exe")
First of all, many thanks for all the help. You guys are amazing! This code worked perfectly for Notepad so I thought it would be a simple matter to adapt the script to OpenOffice (which was my real intention) by plugging in soffice.exe but I couldn't make the code work with my changes...

Code: Select all

#Persistent

Run, soffice.exe,,, pid
WinWait, % "ahk_pid " pid
global g_hWnd := WinExist()

DllCall("RegisterShellHookWindow", "Ptr", A_ScriptHwnd)
MsgNum := DllCall("RegisterWindowMessage", "Str", "SHELLHOOK")
OnMessage(MsgNum, "ShellMessage")
Return

ShellMessage(wParam, lParam) {
	if (wParam = 2) ; HSHELL_WINDOWDESTROYED
	{
		if (lParam = g_hWnd)
			MsgBox OpenOffice closed
	}
	else if (wParam = 1) ; HSHELL_WINDOWCREATED
	{
		if h := WinExist("ahk_exe soffice.bin")
			g_hWnd := h
	}
}
tmplinshi
Posts: 1604
Joined: 01 Oct 2013, 14:57

Re: Am I misapplying OnMessage()?  Topic is solved

24 Aug 2019, 00:49

If you double-click the tray icon of your script, you'll see the script stopped at WinWait, % "ahk_pid " pid

Image

soffice.exe does not have a visible window, the script will wait forever. You can change the WinWait to:

Code: Select all

WinWait, % "ahk_exe soffice.bin"
or

Code: Select all

WinWait, % "ahk_class SALFRAME"
You can get the window info using WindowSpy.ahk that inside the AutoHotkey installation folder. WindowSpy can also be opened via script tray menu -> Window Spy.
m904begley
Posts: 7
Joined: 15 Jul 2016, 21:24

Re: Am I misapplying OnMessage()?

24 Aug 2019, 14:06

Your solution worked beautifully, tmplinshi! I was so wrapped up in trying to understand DllCall that I completely overlooked the WinWait command. That was the final obstacle to completing my script. Hopefully I can finish it now without further assistance. I will also be studying your code snippet until I'm able to understand DllCall. Your examples are far more explanatory than those provided in the official documentation. Many thanks, for all the help, friend!
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: Am I misapplying OnMessage()?

02 Sep 2019, 06:38

Two variants to notify when a Notepad window is created/closed.
Using RegisterWindowMessage and SetWinEventHook.

SetWinEventHook:

Code: Select all

#Persistent

;based on:
;Is possible to get path when Explorer window is closing and restore when is opening? - AutoHotkey Community
;https://autohotkey.com/boards/viewtopic.php?f=5&t=49842&p=221423#p221423

OnNotepadStartEnd(hWinEventHook, vEvent, hWnd)
{
	;EVENT_OBJECT_CREATE := 0x8000
	;EVENT_OBJECT_DESTROY := 0x8001
	static _ := DllCall("user32\SetWinEventHook", "UInt",0x8000, "UInt",0x8001, "Ptr",0, "Ptr",RegisterCallback("OnNotepadStartEnd"), "UInt",0, "UInt",0, "UInt",0, "Ptr")
	DetectHiddenWindows, On
	WinGetClass, vWinClass, % "ahk_id " hWnd
	if !(vWinClass = "Notepad")
		return

	if (vEvent = 0x8000)
		SoundPlay, *64
	else if (vEvent = 0x8001)
	{
		WinGetTitle, vWinTitle, % "ahk_id " hWnd
		SoundPlay, *48
		MsgBox, % vWinTitle
	}
}
RegisterWindowMessage (similar to tmplinshi's example):

Code: Select all

#Persistent

DllCall("user32\RegisterShellHookWindow", "Ptr",A_ScriptHwnd)
vMsg := DllCall("user32\RegisterWindowMessage", "Str","SHELLHOOK", "UInt")
OnMessage(vMsg, "OnNotepadStartEndAlt")
return

OnNotepadStartEndAlt(vEvent, hWnd)
{
	if !(vEvent = 1) ;HSHELL_WINDOWCREATED := 1
	&& !(vEvent = 2) ;HSHELL_WINDOWDESTROYED := 2
		return
	DetectHiddenWindows, On
	WinGetClass, vWinClass, % "ahk_id " hWnd
	if !(vWinClass = "Notepad")
		return

	if (vEvent = 1)
		SoundPlay, *64
	else
	{
		WinGetTitle, vWinTitle, % "ahk_id " hWnd
		SoundPlay, *48
		MsgBox, % vWinTitle
	}
}
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: filipemb and 308 guests