OnMessage

Registers a function to be called automatically whenever the script receives the specified message.

OnMessage MsgNumber, Callback , MaxThreads

パラメータ

MsgNumber

型:整数

監視または問い合わせるメッセージの番号で、0から4294967295(0xFFFFFFF)の間でなければなりません。システムメッセージ(つまり0x0400以下のもの)を監視したくない場合は、選択の余地がある範囲で4096(0x1000)より大きい数字を選ぶとよいでしょう。これにより、AutoHotkeyの現在および将来のバージョンで内部的に使用されるメッセージに干渉する可能性を低減することができます。

Callback

型:機能オブジェクト

The function to call.

The callback accepts four parameters and can be defined as follows:

MyCallback(wParam, lParam, msg, hwnd) { ...

パラメータに与える名前は重要ではないが、以下の値が順次割り当てられる:

  1. メッセージのWPARAMの値です。
  2. メッセージのLPARAM値です。
  3. The message number, which is useful in cases where a callback monitors more than one message.
  4. メッセージの送信先のウィンドウまたはコントロールのHWND(ユニークID)です。HWNDは、WinTitleパラメータで直接使用することができます。

対応する情報が不要な場合、コールバックのパラメータリストの最後から1つ以上のパラメータを省略することができますが、この場合、MyCallback(Param1, *)のように、最後のパラメータとしてアスタリスクを指定する必要があります。

WPARAMとLPARAMは、スクリプトを実行するexeが32ビットか64ビットかに応じて、符号なし32ビット整数(0から232-1)または符号付き64ビット整数(-263から263-1)です。32ビットスクリプトの場合、入力されるパラメータが符号付き整数であることを意図している場合、この例に従って負の数を明らかにすることができます:

if (A_PtrSize = 4 && wParam > 0x7FFFFFFF)  ; Checking A_PtrSize ensures the script is 32-bit.
    wParam := -(~wParam) - 1
MaxThreads

型:整数

If omitted, it defaults to 1, meaning the callback is limited to one thread at a time. This is usually best because otherwise, the script would process messages out of chronological order whenever the callback interrupts itself. そのため、MaxThreadsの代替として、以下のようにCriticalを使用することを検討します。

If the callback directly or indirectly causes the message to be sent again while the callback is still running, it is necessary to specify a MaxThreads value greater than 1 or less than -1 to allow the callback to be called for the new message (if desired). スクリプトの自プロセスが自分自身に送信する(投稿しない)メッセージは、遅延やバッファリングができません。

Specify 0 to unregister the previously registered callback identified by Callback.

By default, when multiple callbacks are registered for a single MsgNumber, they are called in the order that they were registered. To register a callback to be called before any previously registered callbacks, specify a negative value for MaxThreads. For example, OnMessage Msg, Fn, -2 registers Fn to be called before any other callbacks previously registered for Msg, and allows Fn a maximum of 2 threads. However, if the callback is already registered, the order will not change unless it is unregistered and then re-registered.

使用方法

Any number of callbacks can monitor a given MsgNumber.

Either of these two lines registers a callback to be called after any previously registered callbacks:

OnMessage MsgNumber, Callback     ; Option 1 - omit MaxThreads
OnMessage MsgNumber, Callback, 1  ; Option 2 - specify MaxThreads 1

This registers a callback to be called before any previously registered callbacks:

OnMessage MsgNumber, Callback, -1

To unregister a callback, specify 0 for MaxThreads:

OnMessage MsgNumber, Callback, 0

Additional Information Available to the Callback

In addition to the received parameters mentioned above, the callback may also consult the built-in variable A_EventInfo, which contains 0 if the message was sent via SendMessage. PostMessageで送信された場合、メッセージが投稿されたtick-count の時間が含まれます。

A callback's last found window starts off as the parent window to which the message was sent (even if it was sent to a control). If the window is hidden but not a GUI window (such as the script's main window), turn on DetectHiddenWindows before using it. 事例:

DetectHiddenWindows True
MsgParentWindow := WinExist()  ; This stores the unique ID of the window to which the message was sent.

What the Callback Should Return

If a callback uses Return without any parameters, or it specifies a blank value such as "" (or it never uses Return at all), the incoming message goes on to be processed normally when the callback finishes. The same thing happens if the callback exits or causes a runtime error such as running a nonexistent file. これに対して、整数を返すと、返信としてすぐに送信されます。つまり、プログラムはそれ以上メッセージを処理しません。For example, a callback monitoring WM_LBUTTONDOWN (0x0201) may return an integer to prevent the target window from being notified that a mouse click has occurred. 多くの場合(PostMessageで届いたメッセージなど)、どの整数を返すかは問題ではありませんが、疑わしい場合は通常0が最も安全です。

有効な戻り値の範囲は、スクリプトを実行するexeが32ビットか64ビットかによって異なります。空でない戻り値は、32ビットスクリプトでは -231 から 232-1 (A_PtrSize = 4) 、64ビットスクリプトでは -263 から 263-1 (A_PtrSize = 8) でなければなりません。

If there are multiple callbacks monitoring a given message number, they are called one by one until one returns a non-empty value.

総論

Unlike a normal function-call, the arrival of a monitored message calls the callback as a new thread. Because of this, the callback starts off fresh with the default values for settings such as SendMode and DetectHiddenWindows. これらのデフォルトは、スクリプト起動時に変更することができます。

コントロールに送信されたメッセージは(投稿されるのではなく)、システムが裏でコントロールに直接ルーティングするため、監視されることはありません。システムで生成されたメッセージは、そのほとんどが投稿されるため、これが問題になることはほとんどありません。

スクリプトがアイドル状態で実行され続け、メッセージの着信を監視することを意図している場合、スクリプトの終了を防ぐためにPersistent関数を呼び出す必要がある場合があります。OnMessage は、スクリプトを自動的に永続化するわけではありません。例えば、OnMessageを使用してGUIウィンドウへの入力を監視する場合(WM_LBUTTONDOWNの例など)、最後のGUIウィンドウが閉じられたときにスクリプトが自動的に終了するようにする方が適切な場合があります。

If a message arrives while its callback is still running due to a previous arrival of the same message, by default the callback will not be called again; instead, the message will be treated as unmonitored. もしこれが望ましくないのであれば、それを回避する方法は複数あります:

If a monitored message that is numerically greater than 0x0311 is posted while the script is uninterruptible, the message is buffered; that is, its callback is not called until the script becomes interruptible. しかし、投稿ではなく送信されるメッセージは、戻り値を提供する必要があるため、バッファリングすることはできません。システムダイアログ、リストビューのドラッグ&ドロップ操作、メニューなどのモーダルメッセージループが実行されている場合、投稿されたメッセージがバッファされない場合があります。

If a monitored message arrives and is not buffered, its callback is called immediately even if the thread is uninterruptible when the message is received.

OnMessageスレッドの優先順位は常に0です。その結果、現在のスレッドの優先順位が0より高い場合、メッセージの監視やバッファリングは行われない。

システムメッセージ(0x0400以下のメッセージ)を監視する場合は、注意が必要です。For example, if a callback does not finish quickly, the response to the message might take longer than the system expects, which might cause side-effects. Unwanted behavior may also occur if a callback returns an integer to suppress further processing of a message, but the system expected different processing or a different response.

スクリプトがMsgBoxなどのシステムダイアログを表示している場合、コントロールに投稿されたメッセージは監視されません。For example, if the script is displaying a message box and the user clicks a button in a GUI window, the WM_LBUTTONDOWN message is sent directly to the button without calling the callback.

外部プログラムがPostThreadMessage()などのAPIコールでスクリプトのスレッドに直接メッセージを投稿することもできますが、スクリプトがメッセージボックスなどのシステムウィンドウを表示している場合、メッセージが失われるためお勧めしません。Instead, it is usually best to post or send the messages to the script's main window or one of its GUI windows.

CallbackCreate, OnExit, OnClipboardChange, PostMessage, SendMessage, Functions, Windows Messages, Threads, Critical, DllCall

GUIウィンドウのマウスクリックを監視する。関連トピックContextMenuイベント

MyGui := Gui(, "Example Window")
MyGui.Add("Text",, "Click anywhere in this window.")
MyGui.Add("Edit", "w200")
MyGui.Show
OnMessage 0x0201, WM_LBUTTONDOWN

WM_LBUTTONDOWN(wParam, lParam, msg, hwnd)
{
    X := lParam & 0xFFFF
    Y := lParam >> 16
    Control := ""
    thisGui := GuiFromHwnd(hwnd)
    thisGuiControl := GuiCtrlFromHwnd(hwnd)
    if thisGuiControl
    {
        thisGui := thisGuiControl.Gui
        Control := "`n(in control " . thisGuiControl.ClassNN . ")"
    }
    ToolTip "You left-clicked in Gui window '" thisGui.Title "' at client coordinates " X "x" Y "." Control
}

システムのシャットダウン/ログオフを検出し、ユーザーがそれを中止できるようにします。Windows Vista以降では、シャットダウン/ログオフをブロックしているプログラムを示すユーザーインターフェイスを表示し、ユーザーが強制的にシャットダウン/ログオフできるようにします。古いOSの場合、スクリプトは確認プロンプトを表示します。関連トピックOnExit

; The following DllCall is optional: it tells the OS to shut down this script first (prior to all other applications).
DllCall("kernel32.dll\SetProcessShutdownParameters", "UInt", 0x4FF, "UInt", 0)
OnMessage(0x0011, On_WM_QUERYENDSESSION)
Persistent

On_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"
    try
    {
        ; Set a prompt for the OS shutdown UI to display.  We do not display
        ; our own confirmation prompt because we have only 5 seconds before
        ; the OS displays the shutdown UI anyway.  Also, a program without
        ; a visible window cannot block shutdown without providing a reason.
        BlockShutdown("Example script attempting to prevent " EventType ".")
        return false
    }
    catch
    {
        ; ShutdownBlockReasonCreate is not available, so this is probably
        ; Windows XP, 2003 or 2000, where we can actually prevent shutdown.
        Result := MsgBox(EventType " in progress. Allow it?",, "YN")
        if (Result = "Yes")
            return true  ; Tell the OS to allow the shutdown/logoff to continue.
        else
            return false  ; Tell the OS to abort the shutdown/logoff.
    }
}

BlockShutdown(Reason)
{
    ; If your script has a visible GUI, use it instead of A_ScriptHwnd.
    DllCall("ShutdownBlockReasonCreate", "ptr", A_ScriptHwnd, "wstr", Reason)
    OnExit StopBlockingShutdown
}

StopBlockingShutdown(*)
{
    OnExit StopBlockingShutdown, 0
    DllCall("ShutdownBlockReasonDestroy", "ptr", A_ScriptHwnd)
}

他のスクリプトやプログラムから、カスタムメッセージと最大2つの数字を受信する(数字ではなく文字列を送信する場合は、この後の例を参照してください)。

OnMessage 0x5555, MsgMonitor
Persistent

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

; The following could be used inside some other script to run the callback inside the above script:
SetTitleMatchMode 2
DetectHiddenWindows True
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 False  ; Must not be turned off until after PostMessage.

あるスクリプトから別のスクリプトへ、任意の長さの文字列を送信します。これを使うには、次の2つのスクリプトを保存して実行し、Win+Spaceを押して入力ボックスを表示し、文字列を入力するよう促します。両方のスクリプトは同じネイティブエンコーディングを使用する必要があります。

以下のスクリプトをReceiver.ahkとして保存し、起動してください。

#SingleInstance
OnMessage 0x004A, Receive_WM_COPYDATA  ; 0x004A is WM_COPYDATA
Persistent

Receive_WM_COPYDATA(wParam, lParam, msg, hwnd)
{
    StringAddress := NumGet(lParam, 2*A_PtrSize, "Ptr")  ; Retrieves the CopyDataStruct's lpData member.
    CopyOfData := StrGet(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.
}

以下のスクリプトをSender.ahkとして保存し、起動してください。その後、Win+Spaceのホットキーを押してください。

TargetScriptTitle := "Receiver.ahk ahk_class AutoHotkey"

#space::  ; Win+Space hotkey. Press it to show an input box for entry of a message string.
{
    ib := InputBox("Enter some text to Send:", "Send text via WM_COPYDATA")
    if ib.Result = "Cancel"  ; User pressed the Cancel button.
        return
    result := Send_WM_COPYDATA(ib.Value, TargetScriptTitle)
    if result = ""
        MsgBox "SendMessage failed or timed out. 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."
}

Send_WM_COPYDATA(StringToSend, TargetScriptTitle)
; 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.
{
    CopyDataStruct := Buffer(3*A_PtrSize)  ; Set up the structure's memory area.
    ; First set the structure's cbData member to the size of the string, including its zero terminator:
    SizeInBytes := (StrLen(StringToSend) + 1) * 2
    NumPut( "Ptr", SizeInBytes  ; OS requires that this be done.
          , "Ptr", StrPtr(StringToSend)  ; Set lpData to point to the string itself.
          , CopyDataStruct, A_PtrSize)
    Prev_DetectHiddenWindows := A_DetectHiddenWindows
    Prev_TitleMatchMode := A_TitleMatchMode
    DetectHiddenWindows True
    SetTitleMatchMode 2
    TimeOutTime := 4000  ; Optional. Milliseconds to wait for response from receiver.ahk. Default is 5000
    ; Must use SendMessage not PostMessage.
    RetValue := SendMessage(0x004A, 0, CopyDataStruct,, TargetScriptTitle,,,, TimeOutTime) ; 0x004A is WM_COPYDATA.
    DetectHiddenWindows Prev_DetectHiddenWindows  ; Restore original setting for the caller.
    SetTitleMatchMode Prev_TitleMatchMode         ; Same.
    return RetValue  ; Return SendMessage's reply back to our caller.
}

ネットワーク接続でデータが到着したときに通知を受け取るOnMessageの使い方の例は、WinLIRCクライアントスクリプトをご覧ください。