Creates a machine-code address that when called, redirects the call to a function in the script.
Address := RegisterCallback("FunctionName" [, Options = "", ParamCount = FormalCount, EventInfo = Address])
Address | Upon success, RegisterCallback() returns a numeric address that may be called by DllCall() or anything else capable of calling a machine-code function. Upon failure, it returns an empty string. Failure occurs when FunctionName: 1) does not exist; 2) accepts too many or too few parameters according to ParamCount; or 3) accepts any ByRef parameters. |
FunctionName | A function's name, which must be enclosed in quotes if it is a literal string. This function is called automatically whenever Address is called. The function also receives the parameters that were passed to Address. |
Options | Specify zero or more of the following words. Separate each option from the next with a space (e.g. "C Fast"). Fast or F: Avoids starting a new thread each time FunctionName is called. Although this performs better, it must be avoided whenever the thread from which Address is called varies (e.g. when the callback is triggered by an incoming message). This is because FunctionName will be able to change global settings such as ErrorLevel, A_LastError, and the last-found window for whichever thread happens to be running at the time it is called. For more information, see Remarks. CDecl or C : Makes Address conform to the "C" calling convention. This is typically omitted because the standard calling convention is much more common for callbacks. |
ParamCount | The number of parameters that Address's caller will pass to it. If entirely omitted, it defaults to the number of mandatory parameters in the definition of FunctionName. In either case, ensure that the caller passes exactly this number of parameters. |
EventInfo | An integer between 0 and 4294967295 that FunctionName will see in A_EventInfo whenever it is called via this Address. This is useful when FunctionName is called by more than one Address. If omitted, it defaults to Address. Note: Unlike other global settings, the current thread's A_EventInfo is not disturbed by the fast mode. |
A function assigned to a callback address may accept up to 31 parameters. Optional parameters are permitted, which is useful when the function is called by more than one caller.
All incoming parameters are integers between 0 and 4294967295. If an incoming parameter is intended to be a signed integer, any negative numbers can be revealed by following this example:
if wParam > 0x7FFFFFFF wParam := -(~wParam) - 1
If an incoming parameter is intended by its caller to be a string, that string may be retrieved by copying it into a variable. For example:
VarSetCapacity(MyString, DllCall("lstrlen", UInt, MyParameter)) ; Unnecessary if MyString is already big enough. DllCall("lstrcpy", Str, MyString, UInt, MyParameter) ; Copy the string into the script's MyString variable. VarSetCapacity(MyString, -1) ; Update the variable's internally-stored length to reflect its new contents.
If an incoming parameter is the address of a structure, the individual members may be extracted by following the steps at DllCall structures.
If the function uses Return without any parameters, or it specifies a blank value such as "" (or it never uses Return at all), 0 is returned to Address's caller. Otherwise, the function should return an integer between -2147483648 and 4294967295, which is then returned to Address's caller.
The default/slow mode causes the function to start off fresh with the default values for settings such as SendMode and DetectHiddenWindows. These defaults can be changed in the auto-execute section.
By contrast, the fast mode inherits global settings from whichever thread happens to be running at the time the function is called. Furthermore, any changes the function makes to global settings (including ErrorLevel and the last-found window) will go into effect for the current thread. Consequently, the fast mode should be used only when it is known exactly which thread(s) the function will be called from.
To avoid being interrupted by itself (or any other thread), a callback may use Critical as its first line. However, this is not completely effective when the function is called indirectly via the arrival of a message less than 0x312 (increasing Critical's interval may help). Furthermore, Critical does not prevent the function from doing something that might indirectly result in a call to itself, such as calling SendMessage or DllCall.
Each use of RegisterCallback() allocates a small amount of memory (32 bytes plus system overhead). Since the OS frees this memory automatically when the script exits, any script that allocates a small, fixed number of callbacks does not have to explicitly free the memory. By contrast, a script that calls RegisterCallback() an indefinite/unlimited number of times should explicitly call the following on any unused callbacks: DllCall("GlobalFree", UInt, Address)
DllCall(), OnMessage(), OnExit, OnClipboardChange, Sort's callback, Critical, Post/SendMessage, Functions, List of Windows Messages, 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", "" ; Specifies "" 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