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 구조의 단계를 따라 추출합니다.

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

callback := RegisterCallback("TheFunc", "F", 1)  ; 매개변수 개수를 명시해야 합니다.
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 호출 관례를 사용합니다. 이 관례는 고정된 개수의 매개변수를 요구합니다. 그러므로, 역호출이 생성될 때 ParamCount를 지정해야 합니다. 64-비트 빌드에서는 ParamCount를 생략할 수 있고 32-비트 빌드는 Cdecl 역호출을 사용합니다 - 그런 경우 모든 선택적인 매개변수는 기본 값을 받고 params에 저장하기 위해 주소를 계산하기 위한 목적으로는 무시됩니다.

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

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

빠르게 vs. 느리게

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

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

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

메모리

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

DllCall("GlobalFree", "Ptr", Address, "Ptr")
선택 | 내려받기

관련 항목

DllCall(), OnMessage(), OnExit, 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", ""  ; ""를 지정하여 상속을 받는데 빠른-모드를 회피합니다.
    , 4, MyTextHwnd)  ; EventInfo 매개변수가 존재하면 정확하게 ParamCount를 지정해야 합니다.
WindowProcOld := DllCall(SetWindowLong, Ptr, GuiHwnd, Int, -4  ; -4 is GWL_WNDPROC
    , Ptr, WindowProcNew, Ptr) ; 반환값은  Ptr 또는 UPtr 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", 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
선택 | 내려받기