RegisterCallback() [v1.0.47+]

호출 될 때 머신-코드 주소를 생성해서, 그 호출을 스크립트의 함수로 방향전환합니다.

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

매개변수

Address

성공하면, RegisterCallback()은 숫치 주로를 돌려줍니다. 이 주소를 DllCall() 또는 기타 머신-코드 함수를 호출할 수 있는 다른 함수가 호출할 수 있습니다. 실패하면, 빈 문자열을 돌려줍니다. 실패가 일어나는 경우는 FunctionName이: 1) 존재하지 않을 경우; 2) ParamCount 보다 너무 많거나 너무 적게 매개변수를 받은 경우; 3) 또는 ByRef 매개변수를 받은 경우입니다.

FunctionName

함수의 이름입니다. 기호 그대로의 문자열일 경우 반드시 따옴표로 둘러 싸야 합니다. 이 함수는 Address가 호출될 때마다 자동으로 호출됩니다. 함수는 또 Address에 건네어진 매개변수들도 받습니다.

[v1.1.06+]: 함수 이름 대신에 함수 참조를 건넬 수 있습니다.

Options

0개 이상의 다음 단어들을 지정합니다. 각 옵션은 다음 옵션과 스페이스로 구분하십시오 (예, C Fast).

Fast 또는 F: FunctionName이 호출될 때마다 새 쓰레드가 시작하는 것을 피합니다. 비록 수행성능은 좋아지지만, Address로 호출되는 쓰레드가 달라질 경우는 (예, 들어오는 메시지에 의하여 역호출이 촉발될 때는) 피해야 합니다. 왜냐하면 호출되는 순간에 쓰레드가 실행되는 경우 FunctionNameErrorLevel, A_LastError, 그리고 마지막으로-발견된 창과 같이 전역 설정을 바꾸어 버릴 위험이 있기 때문입니다. 더 자세한 정보는 논평을 보십시오.

CDecl 또는 C: Address가 "C" 호출 관례를 따르도록 만듭니다. 이는 전형적으로 생략됩니다. 왜냐하면 표준 호출 관례가 훨씬 더 많이 역호출에 사용되기 때문입니다.

ParamCount

매개변수의 개수입니다. Address의 호출자가 건넵니다. 전부 생략하면, 기본값은 FunctionName정의된 필수 매개변수의 개수입니다. 어느 경우든, 호출자가 정확하게 이 개수의 매개변수를 건네는지 확인하십시오.

EventInfo

FunctionNameAddress를 통하여 호출될 때마다 A_EventInfo에서 보게될 정수입니다. FunctionName이 하나 이상의 Address로 호출될 때 유용합니다. 생략되면, 기본값은 Address입니다. 주의: 다른 전역 설정과 다르게, 현재 쓰레드의 A_EventInfo는 빠른 모드에 영향을 받지 않습니다.

스크립트를 실행하는 파일이 32-비트이면, 이 매개변수는 0부터 4294967295 사이의 값입니다. 64비트이면, 이 매개변수는 64-비트 정수입니다. A_EventInfo는 보통 부호없는 정수를 돌려주지만, 오토핫키는 부호없는 64-비트 정수를 완벽하게 지원하지 못합니다. 그래서 어떤 연산은 그 값을 부호있는 정수에 싸서 돌려주기도 합니다.

역호출 함수의 매개변수

역호출 주소에 할당된 함수는 매개변수를 31개까지 받을 수 있습니다. 선택적 매개변수를 허용합니다. 이는 함수가 여러 호출자에게 호출될 때 유용합니다.

매개변수를 올바르게 번역하려면 x86 호출 관례의 작동 방식을 이해해야 합니다. 오토핫키는 매개변수가 유형이 정의되지 않으므로, 역호출 함수의 매개변수 리스트는 정수로 구성되어 있다고 간주됩니다. 그리고 약간의 재번역이 요구됩니다.

AutoHotkey 32-bit: 들어오는 모든 매개변수는 32-비트 정수입니다. 더 작은 유형은 32비트에 맞게 패드를 덧댑니다. 반면에 더 큰 유형은 두 개의 32 비트 매개변수로 쪼개어집니다.

들어오는 매개변수가 부호있는 정수를 의도하면, 음의 정수는 다음 예제 중 하나로 노출시킬 수 있습니다:

; 방법 #1
if (wParam > 0x7FFFFFFF)
    wParam := -(~wParam) - 1

; 방법 #2: 오토핫키가 근본적으로 부호 있는 64-비트 정수를 사용한다는 사실에 의존합니다.
wParam := wParam << 32 >> 32

AutoHotkey 64-bit: 들어오는 모든 매개변수는 부호있는 64-비트 정수입니다. 오토핫키는 부호없는 64-비트 정수를 지원하지 않습니다. 더 작으면 64 비트까지 패드가 덧대어지고, 더 크면 언제나 주소로 건네집니다.

AutoHotkey 32-bit/64-bit: 들어오는 매개변수가 8-비트 또는 16-비트를 의도한다면 (또 x64 머신에서는 32-비트 ), 값의 상위 비트들은 "쓰레기"로 채워집니다. 이 쓰레기들은 비트별-and 연산으로 다음 예제와 같이 여과할 수 있습니다:

Callback(UCharParam, UShortParam, UIntParam) {
    UCharParam &= 0xFF
    UShortParam &= 0xFFFF
    UIntParam &= 0xFFFFFFFF
    ;...
}

들어오는 매개변수가 그의 호출자에게 문자열이기를 의도한다면, 실제로 받는 것은 그 문자열의 주소입니다. 문자열 자체를 받으려면 StrGet()을 사용하십시오:

MyString := StrGet(MyParameter)  ; [AHK_L 46+] 필요

들어오는 매개변수가 구조체의 주소이면, 각 멤버들은 다음 DllCall 구조의 단계를 따라 추출합니다.

주소로 매개변수 받기 [AHK_L 60+]: 함수가 가변함수로 선언되어 있으면, 그의 마지막 매개변수는 역호출 함수의 첫 매개변수 주소에 할당됩니다. 스크립트 매개변수에 할당되지 않습니다. 예를 들어:

callback := RegisterCallback("TheFunc", "F", 3)  ; Parameter list size must be specified.
TheFunc("TheFunc was called directly.")          ; 직접 TheFunc를 호출합니다.
DllCall(callback, "float", 10.5, "int64", 42)        ; 역호출을 통하여 TheFunc를 호출합니다.
TheFunc(params*) {
    if IsObject(params)
        MsgBox % params[1]
    else
        MsgBox % NumGet(params+0, "float") ", " NumGet(params+A_PtrSize, "int64")
}

대부분의 역호출함수는 stdcall 호출 관례를 사용합니다. 이 관례는 고정된 개수의 매개변수를 요구합니다. In those cases, ParamCount must be set to the size of the parameter list, where Int64 and Double count as two 32-bit parameters.

With Cdecl or the 64-bit calling convention, ParamCount only affects how many script parameters are assigned values. If omitted, all optional parameters receive their default values and are excluded from the calculations for the address stored in params.

함수는 무엇을돌려주어야 하는가

함수가 매개변수 없이 Return을 사용하거나, ""와 같이 빈 값을 지정하면 (또는 전혀 Return을 사용하지 않으면), 0이 역호출의 호출자에게 반환됩니다. 그렇지 않으면, 함수는 정수를 반환해야 합니다. 이 값은 그러면 호출자에게 반환됩니다. 오토핫키 32-비트는 반환 값을 32-비트로 잘라냅니다. 반면에 오토핫키 64-비트는 64-비트 반환값을 지원합니다. 이 보다 큰 값을 (값으로) 반환하는 것은 지원하지 않습니다.

빠르게 vs. 느리게

기본/느리게 모드에서 함수는 SendMode 그리고 DetectHiddenWindows와 같은 설정에 대하여 기본 값으로 새롭게 시작합니다. 이 기본 값은 자동-실행 섹션에서 변경할 수 있습니다.

대조적으로, 빠른 모드는 함수가 호출되는 순간에 우연하게 실행중인 쓰레드로부터 전역 설정을 물려받습니다. 게다가, 함수가 전역 설정에 가하는 모든 변경은 (ErrorLevel 그리고 마지막으로-발견된 창을 포함하여) 현재 쓰레드 안으로 영향을 줍니다. 결과적으로, 빠른 모드는 정확하게 어느 쓰레드로부터 함수가 호출되는지 알 경우에만 사용해야 합니다.

자기 자신 (또는 다른 쓰레드)로부터 인터럽트되지 않으려면, 역호출함수는 자신의 첫 줄에 임계값(Critical)을 사용해야 합니다. 그렇지만, 이것이 완전하게 효과가 있는 것은 아닙니다. 함수가 0x0312 보다 작은 메시지의 도착을 통하여 간접적으로 호출될 때는 효력을 미치지 못합니다 (Critical의 간격을 증가시키면 도움이 될 수 있습니다). 게다가, 임계값(Critical)으로는 함수가 간접적으로 자신을 호출하는 결과가 되는 것을 막지 못합니다. 예를 들어 SendMessage이나 DllCall()를 호출하는 것을 막을 수 없습니다.

메모리

RegisterCallback()을 사용할 때마다 작은 메모리가 할당됩니다 (32 바이트에다 약간의 시스템 오버헤드). OS는 스크립트가 종료할 때 이 메모리를 자동으로 해제하기 때문에 , 스크립트가 작은, 고정 개수의 역호출을 등록한다면 명시적으로 메모리를 해제할 필요가 없습니다. 대조적으로, 스크립트가 RegisterCallback()을 무제한/끝없이 호출한다면 명시적으로 다음과 같이 사용되지 않는 역호출 함수를 호출해야 합니다:

DllCall("GlobalFree", "Ptr", Address, "Ptr")

DllCall(), OnMessage(), OnExit(), OnExit, OnClipboardChange(), OnClipboardChange 라벨, Sort의 역호출, Critical, Post/SendMessage, 함수, 윈도우즈 메시지 리스트, 쓰레드

예제

스크 모든 최상위 창의 정보를 요약해 보여줍니다.

; 수행성능과 메모리 보전을 위해, 주어진 역호출에 대해서 RegisterCallback()을 한 번만 호출합니다:
if not EnumAddress  ; 빠른-모드는 이 쓰레드에서만 호출되기 때문에 괜찮습니다:
    EnumAddress := RegisterCallback("EnumWindowsProc", "Fast")

DetectHiddenWindows On  ; 빠른 모드 때문에, 이 설정은 역호출에게도 영향을 미칩니다.

; 제어를 EnumWindows()에게 건넵니다. 이 함수는 반복적으로 역호출을 호출합니다:
DllCall("EnumWindows", "Ptr", EnumAddress, "Ptr", 0)
MsgBox %Output%  ; 역호출이 축적한 정보를 보여줍니다.
    
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  ;  EnumWindows()에게 모든 창이 열거될 때까지 계속하라고 명령합니다.
}

스크 GUI 창을 상속받는 법을 보여줍니다. 그의WindowProc을 스크립트의 새 WindowProc으로 방향 전환합니다. 이 경우, 텍스트 콘트롤의 배경색은 맞춤 색으로 바뀝니다.

TextBackgroundColor := 0xFFBBBB  ; BGR 포맷의 맞춤 색.
TextBackgroundBrush := DllCall("CreateSolidBrush", "UInt", TextBackgroundColor)

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

; 64-비트 스크립트는 SetWindowLong 대신에 SetWindowLongPtr를 호출해야 합니다:
SetWindowLong := A_PtrSize=8 ? "SetWindowLongPtr" : "SetWindowLong"

WindowProcNew := RegisterCallback("WindowProc", ""  ; ""를 지정하여 상속을 받는데 빠른-모드를 회피합니다.
    , , MyTextHwnd)  ; ParamCount can be omitted like this in [v1.1.12+].
WindowProcOld := DllCall(SetWindowLong, "Ptr", GuiHwnd, "Int", -4  ; -4은 GWL_WNDPROC입니다
    , "Ptr", WindowProcNew, "Ptr") ; 반환값은  Ptr 또는 UPtr vs. Int으로 설정해야 합니다.

Gui Show
return

WindowProc(hwnd, uMsg, wParam, lParam)
{
    Critical
    global TextBackgroundColor, TextBackgroundBrush, WindowProcOld
    if (uMsg = 0x0138 && lParam = A_EventInfo)  ; 0x0138은 WM_CTLCOLORSTATIC입니다.
    {
        DllCall("SetBkColor", "Ptr", wParam, "UInt", TextBackgroundColor)
        return TextBackgroundBrush  ; HBRUSH을 돌려주어 OS에게 HDC를 변경했다고 알립니다.
    }
    ; 그렇지 않으면 (위가 반환되지 않았기 때문에), 처리되지 않은 모든 이벤트를 원래의 WindowProc에 건넵니다.
    return DllCall("CallWindowProc", "Ptr", WindowProcOld, "Ptr", hwnd, "UInt", uMsg, "Ptr", wParam, "Ptr", lParam)
}

GuiClose:
ExitApp