Обновление: Первая часть этого ответа относится к коду, который впоследствии был удален из вопроса.
Ваш неправильный адрес GetMessage
. Вы должны передать указатель на структуру MSG. Если вы не отправляете сообщения из очереди, вы не будете вытаскивать их из очереди.
Я не уверен, где вы получаете GetMessageA
. Объявленный в Windows.pas параметр var
для параметра MSG
.
Возможно, вы также должны отправить сообщения. На самом деле, я не понимаю, почему вы не используют стандартное сообщение насос:
while GetMessage(Msg, 0, 0, 0) do
begin
TranslateMessage(Msg);
DispatchMessage(Msg);
end;
В вопросе вы говорите, что вы устанавливаете контрольную точку в функции крючков. documentation имеет это сказать:
процедура
крючка должна обрабатывать сообщение в меньшее время, чем данные записи, указанная в значении LowLevelHooksTimeout в следующем разделе реестра:
HKEY_CURRENT_USER\Control Panel\Desktop
значением является в миллисекундах. Если процедура крючка заканчивается, система передает сообщение на следующий крючок. Однако, в Windows 7 и позже, крючок тихо удаляется без вызова. Существует не способ для приложения узнать, удаляется ли крючок.
Итак, вам нужно прекратить использование контрольных точек. Вместо этого используйте такую технику, как OutputDebugString
.
Даже при этих изменениях крюк никогда не вызывается, когда я запускаю программу. Вероятно, причина, по которой ваш вызов не вызывается, заключается в том, что очередь сообщений о потоке вашего основного приложения консоли неактивна. Окно, в котором находится консоль, находится в другом процессе conhost.exe. Ваша программа - консольное приложение, которое не создает окон, и поэтому у него не будет очереди сообщений. Когда я запускаю вашу программу, вызов GetMessage
никогда не возвращается, как и ожидалось.
Вы можете видеть, что код подключения работает, если вы переключитесь на приложение подсистемы графического интерфейса. Например:
program LowLevelKeyboardHook;
uses
SysUtils, Windows, Forms;
var
hook : HHook;
function hookproc(code: Integer; wparam: WPARAM; lparam: LPARAM): LRESULT; stdcall;
begin
OutputDebugString('hookproc called');
result := CallNextHookEx(hook, code, wParam, lParam);
end;
var
Form: TForm;
begin
hook := SetWindowsHookEx(WH_KEYBOARD_LL, @hookproc, GetModuleHandle(0), 0);
Application.CreateForm(TForm, Form);
Application.Run;
end.
И взять чтение информативных комментариев Sertaç в. Его тесты подтверждают гипотезу о том, что ваша проблема сводится к отсутствию очереди сообщений. Он вызывает звонок PeekMessage
, чтобы создать очередь, и это изменяет поведение.
Все это говорит о том, что я подозреваю, что проблема вашего реального приложения отличается. Я подозреваю, что проблема в том, что вы проходите nil
до первого параметра GetMessage
. И в итоге ваша очередь сообщений заполняется.
В соответствии с http://msdn.microsoft.com/en-us/library/windows/desktop/ms644936(v=vs.85).aspx вы не должны пропускать в 'nil' в качестве первого аргумента для 'GetMessage'. Вы также должны проверить возвращаемое значение 'GetMessage'. И почему вы используете ANSI-версию 'GetMessage'? – jpfollenius
@jpfollenius Если hWnd NULL, GetMessage извлекает сообщения для любого окна, принадлежащего текущему потоку, и любые сообщения в очереди сообщений текущего потока, чье значение hwnd равно NULL (см. Структуру MSG). Поэтому, если hWnd NULL, обрабатываются как оконные сообщения, так и сообщения потоков. В любом случае у меня нет окна ... – opc0de
Да, но первый аргумент не HWND, а указатель на структуру MSG, которая должна быть заполнена. – jpfollenius