2013-11-11 2 views
-1

Я установил крючок WH_KEYBOARD_LL для отслеживания нажатий клавиш код отлично работает некоторое время, но внезапно перестает быть жестким, приложение не дает ни одной ошибки.HookProc получает вызов только несколько раз

Я начал отлаживать его, и поведение выглядело раньше, когда в функции была точка останова. Похоже, что функция называется aproximatelly 6 раз, пока не прекратит принимать события клавиатуры.

function hookproc(code: Integer; wparam: WPARAM;lparam: LPARAM): LRESULT; stdcall; 
begin 
    result := CallNextHookEx(hook, code, wParam, lParam);  // I have put breakpoint here 
end; 

procedure Start(); 
begin 
     hook := SetWindowsHookEx(WH_KEYBOARD_LL,@hookproc,GetModuleHandle(nil),0); 
end; 

    procedure TMyApplication.DoRun; 
var 
    msg : tagMSG; 
begin 
    Start(); 
    ZeroMemory(@msg,sizeof(msg)); 
    while GetMessage(Msg, 0, 0, 0) do 
    begin 
    TranslateMessage(Msg); 
    DispatchMessage(Msg); 
    end; 
end. 

В основном я уменьшил код до этого, и поведение все еще существует. Любая идея, что не так с кодом?

+0

В соответствии с http://msdn.microsoft.com/en-us/library/windows/desktop/ms644936(v=vs.85).aspx вы не должны пропускать в 'nil' в качестве первого аргумента для 'GetMessage'. Вы также должны проверить возвращаемое значение 'GetMessage'. И почему вы используете ANSI-версию 'GetMessage'? – jpfollenius

+0

@jpfollenius Если hWnd NULL, GetMessage извлекает сообщения для любого окна, принадлежащего текущему потоку, и любые сообщения в очереди сообщений текущего потока, чье значение hwnd равно NULL (см. Структуру MSG). Поэтому, если hWnd NULL, обрабатываются как оконные сообщения, так и сообщения потоков. В любом случае у меня нет окна ... – opc0de

+0

Да, но первый аргумент не HWND, а указатель на структуру MSG, которая должна быть заполнена. – jpfollenius

ответ

2

Обновление: Первая часть этого ответа относится к коду, который впоследствии был удален из вопроса.

Ваш неправильный адрес 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. И в итоге ваша очередь сообщений заполняется.

+0

Попробуйте сейчас, все тот же режим. Полный код вырезания и вставки http://pastebin.com/VsrsM3yj – opc0de

+1

Код в порядке. Используйте OutputDebugString, а не отладчик. –

+0

Это верный ответ, на который я верю. ОС запускает невосприимчивые процедуры крюка из цепи крюка. Не * ломайте * в одном. –

Смежные вопросы