OnMessage()

GUIウィンドウに特定のメッセージが送られたときに実行される関数を割り当てる

OnMessage(MsgNumber [, "FunctionName", MaxThreads])

Parameters

引数名説明
MsgNumber 監視・応答させたいメッセージの番号
FunctionName メッセージを受け取ったときに実行させたい関数の関数名を文字列として指定する
空の文字列を指定すると、MsgNumberに対する関数の割り当てを解除する。
第2引数以降を省略すると、割り当ての変更は行われない。
MaxThreads メッセージを受け取って関数を実行中に同じメッセージが送られたとき、スレッド割り込みによって実行できる数の上限を指定する。
省略時は「1」。
割り込まれなかった場合は、後述の条件によって後回しにされるか無視される。
割り込みを許すと、メッセージイベントが時系列順に処理されなくなるため、通常は変更しない。

FunctionNameで指定する関数

FunctionName([wParam,lParam,msg,hwnd])
{
}
引数説明
wParamメッセージとともに送られるWPARAMパラメータの値が0...4294967296の整数値で与えられる
lParamメッセージとともに送られるLPARAMパラメータの値が-2147483648...2147483647.の整数値で与えられる
msg送られたメッセージの番号が与えられる
hwndメッセージが送られたウィンドウやコントロールのウィンドウハンドルが与えられる

割り当てる関数は、4つの引数を受け取ることができる。
引数名は自由につけてかまわない。
その引数で与えられる情報が必要ない場合、引数の設定を省略してもかまわない。

関数が呼び出される際には、以下の組み込み変数にもメッセージを受け取った状況に応じた値が設定される。
また、LastFoundWindowはメッセージを受け取ったウィンドウ(メッセージがコントロールに送られた場合は、その親ウィンドウ)になる。

A_Gui
メッセージを受け取ったのがGUIウィンドウやGUIウィンドウ上のコントロールだった場合、GUIウィンドウの番号が格納される。
AutoHotkeyのメインウィンドウなど、それ以外のウィンドウだった場合は空文字列になる。
A_GuiControl
メッセージを受け取ったのがGUIウィンドウ上のコントロールだった場合、そのコントロールに割り当てられた変数名(なければコントロールのテキスト)が格納される。
それ以外の場合、空の文字列になる。
A_GuiX
A_GuiY
メッセージがPostMessageによって送られた場合、それぞれメッセージが送られたときのマウスカーソルの横座標と縦座標が格納される。
メッセージがSendMessageによって送られた場合、-2147483648になる。
A_EventInfo
メッセージがPostMessageによって送られた場合、メッセージが送られた時間がOS起動時からの経過ミリ秒数で格納される。
この値は、A_TickCountと比較して使用できる。
メッセージがSendMessageによって送られた場合、0になる。

関数はReturn文で-2147483648から4294967295までの値を返せる。
値を返した場合、メッセージへの応答はそこで完了する。
関数が返すべき値は、メッセージの種類によって異なる。
何も値を返さなかった場合、AutoHotkeyの通常の処理が行われる。

返り値

問題なく割り当てが行われると、それまでMsgNumberに割り当てられていた関数の関数名が返される。
ただし、それまで何も割り当てられていなかった場合、新たに割り当てた関数名自体が返される。
指定された関数が存在しなかったり、設定された引数が間違っている場合など、正常に割り当てが行えなかった場合は、空文字列が返される。
FunctionNameを与えなかった場合、現在割り当てられている関数名が返される。この場合、関数が割り当てられていなければ、空文字列が返される。

Remarks

メッセージイベントによる関数の実行は、現在実行中のスレッドに割り込んで、新規スレッドとして実行される。

AutoHotkeyのスクリプトがメニューを表示中や、KeyDelayMouseDelayの途中などで停止している間に送られた場合、
0x312番未満のメッセージに割り当てられたイベントは無視される。
0x312番以上のメッセージの場合は、後回しにされる。

イベントが無視された場合、割り当てられた関数は実行されず、通常のメッセージ応答が行われる。
イベントが後回しにされた場合、スクリプトが実行可能になった時点で実行される。

MsgBoxコマンドなどでダイアログが表示されている間は、ウィンドウ上のコントロールに対するメッセージは無視される。

同じ番号のメッセージイベントが実行中だった場合、MaxThreadsの上限を超えていなければ、実行中のスレッドに割り込んでメッセージイベントが実行される。
メッセージが0x312番以上で、実行中のスレッドがCritical状態だった場合、メッセージイベントは後回しにされる
それ以外の場合、メッセージイベントは無視される。

別のメッセージイベントか、メッセージイベント以外のスレッドが実行中で、スレッドがCritical状態だったり、Thread,Interruptの設定による割り込み禁止期間だった場合、
0x0〜0x311番のメッセージは例外的に割り込まれる。
0x312番以上のメッセージは後回しにされる。

メッセージ応答イベントの優先度は常に0であるため、実行中のスレッドの優先度が0より大きい場合、すべてのメッセージは無視される。

0x0〜0x311番のメッセージイベントが無視されずに実行されるようにするためには、次にメッセージがチェックされる前にメッセージイベントが終了するようにすればよい。
短い処理の場合は、「Critical,30」のようにしてメッセージチェック間隔を十分に広くすれば、スレッドが終了するまでメッセージがチェックされず、無視されることもなくなる。
処理が長い場合は、以下のようにして、別の0x312番以上のメッセージイベントを呼び出し、元のスレッドは即座に終了すればよい。

MSG=0x000	;処理を割り当てたいメッセージ
OnMessage(MSG,"OnMSG")
OnMSG(w,l,m,h){
	PostMessage,0x4000,%w%,%l%,,ahk_id %h%
}
OnMessage(0x4000,"OnMSGMain")
OnMSGMain(w,l,m,h){
	Critical	;同じメッセージが来たら後回しにされるようにする
	/*
		ここで時間がかかる処理を実行
		処理中にMSG番のメッセージが来たら、割り込みでイベントが発生し、
		0x4000番のメッセージが再送信され、そのイベントが後回しで実行される
	*/
}

MsgNumberで関数を割り当てられるメッセージの数は、最大で500までである。
それ以上のメッセージに応答しようとすると、この関数は失敗する。

OnMessageを使用しているスクリプトは、自動的に常駐状態かつ#SingleInstance(複数実行不可)になる。

自作プログラム同士で独自のメッセージをやり取りしたい場合は、Windowsにあらかじめ定義されたメッセージやAutoHotkeyが使用するメッセージと重ならないように0x1000(4096)番以降のメッセージ番号を使用するのがよい。

GUIを持たないAutoHotkeyのスクリプトにメッセージを送りたい場合は、AutoHotkeyのメインウィンドウ(ahk_class AutoHotkey)に送るとよい。

一般的なメッセージの一覧については、WinAPI Database for VB Programmerのアルファベット順表示「W」の項などが詳しい。

Related

RegisterCallback(), OnExit, OnClipboardChange, Post/SendMessage, Functions, List of Windows Messages, DllCall(), Threads

Examples


; Example: Have a script receive a custom message from some other script or program.

OnMessage(0x5555, "MsgMonitor")
OnMessage(0x5556, "MsgMonitor")

MsgMonitor(wParam, lParam, msg)
{
	; Since returning quickly is often important, it is better to use a ToolTip than
	; something like MsgBox that would prevent the function from finishing:
	ToolTip Message %msg% arrived:`nWPARAM: %wParam%`nLPARAM: %lParam%
}

; The following could be used inside some other script to run the function inside the above script:
SetTitleMatchMode 2
DetectHiddenWindows On
ReceivingScript := WinExist("Name of Receiving Script.ahk ahk_class AutoHotkey")
if ReceivingScript
	PostMessage, 0x5555, 11, 22  ; Sends to the "last found window" due to WinExist() above.
DetectHiddenWindows Off  ; Must not be turned off until after PostMessage.


; Example: The following is a working script that monitors mouse clicks in a GUI window.
; See also: GuiContextMenu

Gui, Add, Text,, Click anywhere in this window.
Gui, Add, Edit, w200 vMyEdit
Gui, Show
OnMessage(0x201, "WM_LBUTTONDOWN")
return

WM_LBUTTONDOWN(wParam, lParam)
{
	X := lParam & 0xFFFF
	Y := lParam >> 16
	if A_GuiControl
		Control := "`n(in control " . A_GuiControl . ")"
	ToolTip You left-clicked in Gui window #%A_Gui% at client coordinates %X%x%Y%.%Control%
}

GuiClose:
ExitApp