OnMessage()

提供: AutoHotkey Wiki
移動: 案内検索

実行制御 | GUI表示 | 演算・変数 | メモリ・DLL操作 | 文字列操作 | キーボード | マウス | シェル | ウィンドウ | ウィンドウグループ
ステータスバー | コントロール | サウンド | ファイル | INIファイル | レジストリ | 環境変数 | AutoHotkey | その他 | 設定関係 | オブジェクト

OnMessage()[編集]

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

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

Parameters[編集]

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

Return Values[編集]

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

FunctionNameで指定する関数[編集]

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

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

wParam, lParam はともに 符号無し32ビット精度の整数 で引き渡しが行われる。
メッセージの送信元が、パラメタが符号付き整数で送っている時は以下のようにすると符号を復元できる。

If wParam > 0x7FFFFFFF
   wParam := -(~wParam) - 1

関数内で利用できる情報[編集]

関数が呼び出される際には、以下の組み込み変数にもメッセージを受け取った状況に応じた値が設定される。
また、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 を使わず関数を終了させるか、 特殊な戻り値である空文字("")を返すようにする。

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

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)に送るとよい。

一般的なメッセージの一覧については、ウィンドウメッセージ一覧で検索 すると解説しているサイトが多数見つかる。

Related[編集]

RegisterCallback(), OnExit, OnClipboardChange, Post/SendMessage, 関数, ウィンドウメッセージ一覧, スレッド, Critical, DllCall()

Example(s)[編集]

GUIウィンドウでのマウスクリックを監視する。GuiContextMenuも参照のこと。

; Example: The following is a working script that monitors mouse clicks in a GUI window.
; Related topic: 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

システムのシャットダウンやログオフを検知してそれを中断する。なお、Vista以降では動作しない。 OnExitも参照のこと。

; The following DllCall is optional: it tells the OS to shut down this script first (prior to all other applications).
; This call has no effect on Windows 9x.
DllCall("kernel32.dll\SetProcessShutdownParameters", UInt, 0x4FF, UInt, 0)
OnMessage(0x11, "WM_QUERYENDSESSION")
Return

WM_QUERYENDSESSION(wParam, lParam)
{
  ENDSESSION_LOGOFF = 0x80000000
  If (lParam & ENDSESSION_LOGOFF)  ; User is logging off.
    EventType = Logoff
  Else            ; System is either shutting down or restarting.
    EventType = Shutdown
  MsgBox, 4,, %EventType% in progress.  Allow it?
  IfMsgBox Yes
    Return true   ; Tell the OS to allow the shutdown/logoff to continue.
  Else
    Return false  ; Tell the OS to abort the shutdown/logoff.
}

他のスクリプトやプログラムから送信されたメッセージを受けとる。

; Example: Have a script receive a custom message and up to two numbers from some other script or program
; (to send strings rather than numbers, see the example after this one).

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
If WinExist("Name of Receiving Script.ahk ahk_class AutoHotkey")
  PostMessage, 0x5555, 11, 22  ; The message is sent  to the "last found window" due to WinExist() above.
DetectHiddenWindows Off        ; Must not be turned off until after PostMessage.

スクリプトとスクリプトの間で任意の長さの文字列を引き渡す。

; Example: Send a string of any length from one script to another.  This is a working example.
; To use it, save and run both of the following scripts then press Win+Space to show an
; InputBox that will prompt you to type in a string.

; Save the following script as "Receiver.ahk" then launch it:
#SingleInstance
OnMessage(0x4a, "Receive_WM_COPYDATA")  ; 0x4a is WM_COPYDATA
Return

Receive_WM_COPYDATA(wParam, lParam)
{
  StringAddress := NumGet(lParam + 8)    ; lParam+8 is the address of CopyDataStruct's lpData member.
  StringLength := DllCall("lstrlen", UInt, StringAddress)
  If StringLength <= 0
  ToolTip %A_ScriptName%`nA blank string was received or there was an error.
  Else
  {
  VarSetCapacity(CopyOfData, StringLength)
  DllCall("lstrcpy", "str", CopyOfData, "uint", StringAddress)  ; Copy the string out of the structure.
  ; Show it with ToolTip vs. MsgBox so we can return in a timely fashion:
  ToolTip %A_ScriptName%`nReceived the following string:`n%CopyOfData%
  }
  Return true  ; Returning 1 (true) is the traditional way to acknowledge this message.
}

; Save the following script as "Sender.ahk" then launch it.  After that, press the Win+Space hotkey.
TargetScriptTitle = Receiver.ahk ahk_class AutoHotkey

#space::       ; Win+Space hotkey. Press it to show an InputBox for entry of a message string.
InputBox, StringToSend, Send text via WM_COPYDATA, Enter some text to Send:
If ErrorLevel  ; User pressed the Cancel button.
  Return
result := Send_WM_COPYDATA(StringToSend, TargetScriptTitle)
If result = FAIL
  MsgBox SendMessage failed. Does the following WinTitle exist?:`n%TargetScriptTitle%
Else If result = 0
  MsgBox Message sent but the target window responded with 0, which may mean it ignored it.
Return

Send_WM_COPYDATA(ByRef StringToSend, ByRef TargetScriptTitle)  ; ByRef saves a little memory in this case.
; This function sends the specified string to the specified window and returns the reply.
; The reply is 1 if the target window processed the message, or 0 if it ignored it.
{
  VarSetCapacity(CopyDataStruct, 12, 0)                ; Set up the structure's memory area.
  ; First set the structure's cbData member to the size of the string, including its zero terminator:
  NumPut(StrLen(StringToSend) + 1, CopyDataStruct, 4)  ; OS requires that this be done.
  NumPut(&StringToSend, CopyDataStruct, 8)             ; Set lpData to point to the string itself.
  Prev_DetectHiddenWindows := A_DetectHiddenWindows
  Prev_TitleMatchMode := A_TitleMatchMode
  DetectHiddenWindows On
  SetTitleMatchMode 2
  SendMessage, 0x4a, 0, &CopyDataStruct,, %TargetScriptTitle%  ; 0x4a is WM_COPYDATA. Must use Send not Post.
  DetectHiddenWindows %Prev_DetectHiddenWindows%      ; Restore original setting for the caller.
  SetTitleMatchMode %Prev_TitleMatchMode%             ; Same.
  Return ErrorLevel                                   ; Return SendMessage's reply back to our caller.
}