RegisterCallback()

DllCall()で呼び出した関数などからスクリプト内の関数を呼び出すためのラッパー関数を生成し、アドレスを返す

RegisterCallback("FunctionName" [, Options = "", ParamCount = FormalCount, EventInfo = Address])

Parameters

引数名説明
FunctionName スクリプト内の関数名を文字列値として指定する。
Options 以下のオプションを半角スペース区切りで指定する。
Fast
FunctionNameで指定した関数を実行するとき、新たなスレッドを開始しないことにより、処理速度を向上させる。
この場合、コールバック関数が呼び出されていたときに実行されていたスレッドのErrorLevelやA_LastError、LastFoundWindowなどが上書きされてしまう。
コールバック関数がいつ呼ばれるか不定な場合などは、指定してはいけない。
CDecl
呼び出し規約が「CDecl」方式の関数を生成したい場合に指定する。
ParamCount 関数が受け取る引数の数を指定する。
省略時は、FunctionNameの関数に定義されている必須の引数と同じ数になる。 FunctionNameに指定されている引数の数より多かったり、必須の引数の数より少なかったりしてはならない。
EventInfo 作成されたコールバック関数からスクリプトの関数が呼ばれるときにA_EventInfo変数に格納される値を指定する。
省略時は、コールバック関数のアドレスとなる。
A_EventInfo変数は、OptionsにFastが指定されていても、既存スレッドの変数を上書きしない。

返り値

成功した場合、作成した関数のアドレスを返す。
FunctionNameで指定した関数が存在しなかったり、引数の数や形式に問題があった場合などは、空の文字列が返される。

Remarks

コールバック関数は、DllCall()で呼び出す関数の引数に関数のアドレスを渡さなくてはならない場合などに使用する。
DLLの関数からコールバック関数が呼び出されると、FunctionNameで指定した関数がAutoHotkeyによって実行される。

FunctionNameで指定する関数には、最大31個までの引数を定義できる。
省略可能引数を使用すれば、ParamCountの違うコールバック関数から同じ関数を呼び出せるように出来る。
ByRef引数は使用できない。

引数は、どのような型であっても、32ビット符号無し整数(0〜4294967295)に変換される。
本来の型が符号付き整数である場合は、「(param>0x7FFFFFFF)?-(~param+1):param」のような式で復元できる。
本来の型が文字列値である場合は、下記のようなコードで内容を取り出せる。

VarSetCapacity(MyString, DllCall("lstrlen", UInt, MyParameter))
DllCall("lstrcpy", Str, MyString, UInt, MyParameter)

FunctionNameで指定した関数は、returnで-2147483648〜4294967295の整数を返せる。
負の値は、32ビット符号付整数として扱われ、それ以外は32ビット符号無し整数として扱われる。
有効な数値を返さなかった場合、コールバック関数の返値は0になる。

関数の最初にCriticalコマンドを実行することで、関数実行中に他のスレッドが割り込むのを抑制できる

コールバック関数を一つ生成するごとに、32バイト程度のメモリを消費する。
不特定多数のコールバック関数を生成する場合は、不要になった時点で「DllCall("GlobalFree", UInt, MyCallBackFunc)」のようにして解放すること。

Related

DllCall(), OnMessage(), OnExit, OnClipboardChange, Sort's callback, Critical, Post/SendMessage, Functions Threads

; Example: The following is a working script that displays a summary of all top-level windows.

; For performance and memory conservation, call RegisterCallback() only once for a given callback:
if not EnumAddress  ; Fast-mode is okay because it will be called only from this thread:
    EnumAddress := RegisterCallback("EnumWindowsProc", "Fast")

DetectHiddenWindows On  ; Due to fast-mode, this setting will go into effect for the callback too.

; Pass control to EnumWindows(), which calls the callback repeatedly:
DllCall("EnumWindows", UInt, EnumAddress, UInt, 0)
MsgBox %Output%  ; Display the information accumulated by the callback.
    
EnumWindowsProc(hwnd, lParam)
{
    global Output
    WinGetTitle, title, ahk_id %hwnd%
    WinGetClass, class, ahk_id %hwnd%
    if title
        Output .= "HWND: " . hwnd . "`tTitle: " . title . "`tClass: " . class . "`n"
    return true  ; Tell EnumWindows() to continue until all windows have been enumerated.
}

 

; Example: The following is a working script that demonstrates how to subclass a GUI window by
; redirecting its WindowProc to a new WindowProc in the script. In this case, the background
; color of a text control is changed to a custom color.

TextBackgroundColor := 0xFFBBBB  ; A custom color in BGR format.
TextBackgroundBrush := DllCall("CreateSolidBrush", UInt, TextBackgroundColor)

Gui, Add, Text, HwndMyTextHwnd, Here is some text that is given`na custom background color.
Gui +LastFound
GuiHwnd := WinExist()

WindowProcNew := RegisterCallback("WindowProc", ""  ; "" to avoid fast-mode for subclassing.
    , 4, MyTextHwnd)  ; Must specify exact ParamCount when EventInfo parameter is present.
WindowProcOld := DllCall("SetWindowLong", UInt, GuiHwnd, Int, -4  ; -4 is GWL_WNDPROC
    , Int, WindowProcNew, UInt)  ; Return value must be set to UInt vs. Int.

Gui Show
return

WindowProc(hwnd, uMsg, wParam, lParam)
{
    Critical
    global TextBackgroundColor, TextBackgroundBrush, WindowProcOld
    if (uMsg = 0x138 && lParam = A_EventInfo)  ; 0x138 is WM_CTLCOLORSTATIC.
    {
        DllCall("SetBkColor", UInt, wParam, UInt, TextBackgroundColor)
        return TextBackgroundBrush  ; Return the HBRUSH to notify the OS that we altered the HDC.
    }
    ; Otherwise (since above didn't return), pass all unhandled events to the original WindowProc.
    return DllCall("CallWindowProcA", UInt, WindowProcOld, UInt, hwnd, UInt, uMsg, UInt, wParam, UInt, lParam)
}

GuiClose:
ExitApp