Перейти на главную страничку сайта (список статей, файлы для скачивания)

ФОРУМ (здесь можно обсудить эту статью, а также саму программу AutoHotkey и проблемы её использования)

Проект перевода документации AutoHotkey: перечень переведённых статей и статей в работе.

Оригинал статьи в AutoHotkey.chm: "RegisterCallback", в содержании - "Functions" - "RegisterCallback", v1.0.47.06.

Ник переводчика: Gourmet.

Настоящее имя переводчика: Валентина Гаврикова, г.Москва.

RegisterCallback

Создает машинный адрес, при обращении к которому вызов перенаправляется к одной из функций в скрипте.

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

Параметры

Address При успехе функция RegisterCallback() возвращает числовой адрес, который можно использовать при помощи функции DllCall() или чего-либо еще, имеющего способность обращаться к машинной функции. При неудаче возвращает пустую строку. Неудача случается, когда FunctionName: 1) не существует; 2) принимает количество параметров, не совпадающее с ParamCount; или 3) принимает какой-либо из параметров ByRef (по ссылке).
FunctionName Представляет собой имя функции. Если имеет буквальное значение, заключается в кавычки. Данная функция вызывается автоматически при каждом обращении к адресу Address и принимает параметры, которые передаются по адресу Address.
Options Задайте ни одной или несколько опций, указанных ниже. Опции отделяются между собой при помощи пробела. Например: "C Fast".

Fast или F: помогает избежать создания нового потока при каждом вызове функции FunctionName. Хотя это повышает производительность, использования этих опций следует избегать в тех случаях, когда Address вызывается из другого потока (т.е. когда обратный вызов запускается входящим сообщением), поскольку FunctionName сможет изменить такие глобальные настройки, как ErrorLevel, A_LastError и последнее найденное окно для любого потока, работающего во время вызова. (См. также примечания.)

CDecl или C: приводит Address в соответствие с соглашением о вызовах "Cи" ("C" calling convention). Данные опции обычно опускаются, поскольку в обратных вызовах чаще всего используется стандартное соглашение о вызовах.
ParamCount Количество параметров, которые передает программа, вызывающая Address. Если данная опция опущена, по умолчанию в описании FunctionName устанавливается необходимое обязательное количество параметров. В любом случае, убедитесь, что вызывающая программа передает точное число параметров.
EventInfo Целое число между 0 и 4294967295, которое FunctionName будет видеть в A_EventInfo каждый раз, когда функция вызывается посредством Address. Это удобно, если FunctionName вызывается несколько раз. Если данный параметр опущен, по умолчанию он равен адресу Address. Примечание: в отличие от других глобальных настроек, режим fast не затрагивает A_EventInfo текущего потока.

Параметры функции обратного вызова

Функция, прикрепленная к адресу обратного вызова, может принимать до 31 параметра. Разрешены опциональные параметры, что весьма удобно, если к функции обращаются несколько вызывающих программ.

Все входящие параметры являются целыми числами и принадлежат к диапазону от 0 до 4294967295. Если входящий параметр должен быть целым числом со знаком, отрицательные числа можно задать следующим образом:

if wParam > 0x7FFFFFFF
    wParam := -(~wParam) - 1

Если входящий параметр должен быть строкой, эту строку можно извлечь, скопировав ее в переменную. Например:

VarSetCapacity(MyString, DllCall("lstrlen", UInt, MyParameter))
; Если MyString уже достаточно велика, необходимости в этом нет.
DllCall("lstrcpy", Str, MyString, UInt, MyParameter)
; Копируем строку в переменную скрипта MyString.

Если входящий параметр является адресом структуры, части этой структуры можно извлечь, следуя инструкциям, описанным в статье "DllCall()".

Что должна возвращать функция

Если функция использует Return без каких-либо параметров или с пустым значением (например, ""), или не использует Return вообще, вызывающей адрес Address программе возвращается 0. Иначе, функция должна вернуть целое число в диапазоне от 2147483648 до 4294967295, которое затем возвращается вызывающей адрес Address программе.

Быстро или медленно

При режиме default/slow, функция начинает работать заново со значениями настроек по умолчанию, такими, как SendMode и DetectHiddenWindows. Значения по умолчанию можно изменить в секции автовыполнения скрипта.

В противоположность режиму default/slow, режим fast mode наследует глобальные настройки от исполняемого в момент вызова функции потока. Кроме того, любые изменения, которые функция вносит в глобальные настройки, вступят в силу для текущего потока. Следовательно, режим fast mode можно использовать только тогда, когда точно известно, из какого потока (потоков) будет вызвана функция.

Чтобы не прерывать себя самому (или другим потоком), обратный вызов в качестве первой строки может использовать Critical. Однако, если функция вызывается непрямым образом, а посредством прибываемого сообщения размером менее 0x312, такой метод эффективен не на 100% (здесь может помочь увеличение интервала Critical). Кроме того, Critical не предотвращает действия функции, могущие косвенно привести к самовызову, например, к вызову SendMessage или DllCall.

Память

Каждый вызов функции RegisterCallback() резервирует небольшое количество памяти (32 байта плюс память, необходимую для системных операций). Так как операционная система автоматически освобождает память по завершении работы скрипта, скрипты, которые делают небольшое, фиксированное количество обратных вызовов, не должны явно освобождать память. В отличие от этого, скрипты, вызывающие функцию RegisterCallback() бесконечное/неограниченное число раз, должны явно вызывать DllCall("GlobalFree", UInt, Address) на любом неиспользуемом обратном вызове.

Примеры

; Пример: ниже представлен работающий скрипт, который отображает сводку всех окон верхнего уровня.
; С целью быстродействия и экономии памяти, для данного обратного вызова
; вызываем функцию RegisterCallback() только один раз.
if not EnumAddress ; Режим Fast-mode здесь подходит, поскольку это будет вызвано только из этого потока:
    EnumAddress := RegisterCallback("EnumWindowsProc", "Fast")
    DetectHiddenWindows On ; Благодаря режиму fast-mode, эта настройка вступит в силу также для обратного вызова.
; Передаем управление функции EnumWindows(), которая многократно делает callback.
DllCall("EnumWindows", UInt, EnumAddress, UInt, 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, Вот некоторый текст, которому задают`nпроизвольный цвет фона.
Gui +LastFound
GuiHwnd := WinExist()

WindowProcNew := RegisterCallback("WindowProc", "" ; "", чтобы избежать режима fast-mode для сабклассинга
    , 4, MyTextHwnd) ; если присутствует параметр EventInfo, необходимо задать точно ParamCount
WindowProcOld := DllCall("SetWindowLong", UInt, GuiHwnd, Int, -4 ; -4 это GWL_WNDPROC
    , Int, WindowProcNew, UInt) ; Возвращаемое значение должно быть установлено как UInt или Int.

Gui Show
return

WindowProc(hwnd, uMsg, wParam, lParam)
{
    Critical
    global TextBackgroundColor, TextBackgroundBrush, WindowProcOld
    if (uMsg = 0x138 && lParam = A_EventInfo) ; 0x138 это WM_CTLCOLORSTATIC.
    {
        DllCall("SetBkColor", UInt, wParam, UInt, TextBackgroundColor)
        return TextBackgroundBrush ; Возвращаем HBRUSH, чтобы уведомить операционную систему об изменении HDC.
    }
    ; Иначе (поскольку значение, о котором говорится выше, возвращено не было),
    ; передаем все необработанные события начальному WindowProc.
    return DllCall("CallWindowProcA", UInt, WindowProcOld, UInt, hwnd, UInt, uMsg, UInt, wParam, UInt, lParam)
}

GuiClose:
ExitApp

Перейти на главную страничку сайта (список статей, файлы для скачивания)

© 2007 http://www.script-coding.com При любом использовании материалов сайта обязательна ссылка на него как на источник информации, а также сохранение целостности и авторства материалов.