IPB
ЛогинПароль:

> ВНИМАНИЕ!

Прежде чем задать вопрос, смотрите FAQ.
Рекомендуем загрузить DRKB.

> Hooks api, несколько вопросов
Unconnected
сообщение 23.06.2010 23:55
Сообщение #1


mea culpa
*****

Группа: Пользователи
Сообщений: 1 372
Пол: Мужской
Реальное имя: Николай

Репутация: -  24  +


Привет всем, опять это я и API _)

Нужно мне было сделать глобальную ловушку на мышь. Чтобы какое-то время нигде, кроме окошка моего приложения, клики не имели действия. Решил смастерить сам, залез в MSDN и начал читать про SetWindowhookEx с WH_MOUSE и далее по ссылкам. Я так понял, мне в качестве HookId нужно использовать WH_MOUSE_LL, низкоуровневый перехват, что ли. Сделал такую Callback-функцию:

Function pinrct(x,y:integer):boolean;
begin
  if (x>=form1.left) and  (x<=form1.left+form1.width) and  (y>=form1.top) and  (y<=form1.top+form1.height) then result:=true else result:=false;
end;

function LowLevelMouseProc(var code:integer;wparam:wparam;lparam:lparam):integer;stdcall;
var mousep:TPoint;
begin
  mousep:=PMouseHookStruct(lparam)^.pt;
  if code=HC_ACTION then begin
    if ((wparam=WM_LBUTTONDOWN) or (wparam=WM_RBUTTONDOWN)) and not(pinrct(mousep.x,mousep.y)) then begin
    end else postmessage(form1.handle,wparam,lparam,nil);
  end;
//    Result := CallNextHookEx(hook,Code,wparam,lparam);
  end;
end;


Если я правильно перевёл, то если code будет равно HC_ACTION, то какое-то сообщение пришло. С PostMessage-параметрами там напутано, не пойму, какое сообщение слать, и на закомментированное присвоение Result-у ругается, на первый параметр. В msdn пишут, что он optional и вообще ignored. Я вот чего не пойму, почему везде пишут, что глобальные ловушки должны быть в dll; какая разница-то? И ещё, вот пришло сообщение в мой глобальный хук, если я не вызову настоящий обработчик оператором Inherited, то сообщение дальше не пойдёт?

Сообщение отредактировано: Unconnected - 23.06.2010 23:56


--------------------
"Знаешь, стыдно - когда не видно, что услышал всё, что слушал.."
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
 
 Ответить  Открыть новую тему 
Ответов(1 - 7)
Unconnected
сообщение 24.06.2010 0:18
Сообщение #2


mea culpa
*****

Группа: Пользователи
Сообщений: 1 372
Пол: Мужской
Реальное имя: Николай

Репутация: -  24  +


А, вроде чтобы сообщение закончило свои дни в ловушке, надо сделать result:=-1..


--------------------
"Знаешь, стыдно - когда не видно, что услышал всё, что слушал.."
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
volvo
сообщение 24.06.2010 1:54
Сообщение #3


Гость






Для начала - о том, почему глобальный (действительно глобальный) хук должен находиться в DLL. А вот почему:

"В Dll код нужно выносить по той простой причине, что этот код должен быть внедрён в адресное пространство целевого процесса.

Например, другой процесс, не связанный с вами, ставит хук. Вот вы вызывали GetMessage. Должен сработать хук. Сейчас управление находится в вашем процессе. Как система вызовет обработчик хука, находящийся вообще в другом адресном пространстве? А никак.
Поэтому она требует, чтобы код был в DLL. Тогда она может спокойно загрузить DLL в ваш процесс, а когда вы вызываете GetMessage, то система просто проходит по списку хуков и вызывает код каждого обработчика, который сейчас сидит в вашем адресном пространстве. Очень просто."
(С) CodeMonkey

Кстати, именно по этой причине тебе здесь не нужна DLL:
Цитата(MSDN)
This hook is called in the context of the thread that installed it.
(LowLevelMouseProc Callback Function)

Соответственно, чтобы запретить любые действия с мышой за пределами твоего окна, достаточно:
var myHook: HHOOK;

function LowLevelMouseProc(nCode: Integer; myWParam: WPARAM; myLParam: LPARAM): LRESULT; stdcall;
var
  MHS: PMOUSEHOOKSTRUCT;
  CR: TRect;
begin
  CR := Rect(Form1.Left, Form1.Top, Form1.Left + Form1.Width, Form1.Top + Form1.Height);
  result := 1;

  MHS := PMOUSEHOOKSTRUCT(myLParam);

  if nCode = HC_ACTION then
  begin
    case myWParam of

      WM_RBUTTONDOWN,
      WM_LBUTTONDOWN:
      begin
        if PtInRect(CR, MHS^.pt) then
        begin
          // Кнопка нажата в окне приложения, ничего делать не будем,
          // нажатие передастся куда нужно
        end
        else
        begin
          // Ага... вот оно, нажатие вне окна... Вернем ненулевое число
          // (как советует MSDN) для завершения его обработки, дальше оно не пройдет...
          exit;
        end;

      end;
    end;
  end;
  result:=CallNextHookEx(MyHook, nCode, myWParam, myLParam);
end;


// устанавливаем хук, например ,по нажатию какой-то кнопки или при создании формы
  myHook := SetWindowsHookEx(WH_MOUSE_LL, @LowLevelMouseProc, hInstance, 0 );


// снимаем хук, нажатием другой кнопки (в твоем-то приложении кнопки нажимаются)
// или при удалении формы
  UnhookWindowsHookEx(MyHook);

 К началу страницы 
+ Ответить 
Unconnected
сообщение 24.06.2010 2:07
Сообщение #4


mea culpa
*****

Группа: Пользователи
Сообщений: 1 372
Пол: Мужской
Реальное имя: Николай

Репутация: -  24  +


Клааасс, как всегда очень познавательно и понятно, спасибо ! good.gif Кстати, у меня WH_MOUSE_LL не опознаётся, говорит, что unknown identifier, ну я его просто на число 14 заменил smile.gif


--------------------
"Знаешь, стыдно - когда не видно, что услышал всё, что слушал.."
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
volvo
сообщение 24.06.2010 2:17
Сообщение #5


Гость






Цитата
ну я его просто на число 14 заменил
Не надо этого делать... Опиши константу
const
  WH_MOUSE_LL = 14;

, и используй ее... А пользоваться "магическими числами", да еще и при работе с хуками - себе дороже.
 К началу страницы 
+ Ответить 
Unconnected
сообщение 26.06.2010 23:56
Сообщение #6


mea culpa
*****

Группа: Пользователи
Сообщений: 1 372
Пол: Мужской
Реальное имя: Николай

Репутация: -  24  +


Кстати, если кому интересно, я тут заметил, что не всё подряд перехватывается smile.gif Например :

function LowLevelMouseProc(nCode: Integer; myWParam: WPARAM; myLParam: LPARAM): LRESULT; stdcall;
var
  MHS: PMOUSEHOOKSTRUCT;
  CR: TRect;
begin
  CR := Rect(Form1.Left, Form1.Top, Form1.Left + Form1.Width, Form1.Top + Form1.Height);
  result := 1;
  MHS := PMOUSEHOOKSTRUCT(myLParam);
  if nCode = HC_ACTION then
  begin
    case myWParam of
      WM_RBUTTONDOWN:exit;
    end;
  end;
  result:=CallNextHookEx(MyHook, nCode, myWParam, myLParam);
end;


, позволяет кликнуть правой кнопкой на десктопе, чтобы появилось popup-меню. Наверное, его нельзя перехватывать. И ещё, если привязываться к координатам, то мышь всё равно будет работать, если чужое окно (или кусок того же popup-а) будет поверх моей формы smile.gif

Сообщение отредактировано: Unconnected - 26.06.2010 23:57


--------------------
"Знаешь, стыдно - когда не видно, что услышал всё, что слушал.."
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
volvo
сообщение 27.06.2010 1:17
Сообщение #7


Гость






Цитата
позволяет кликнуть правой кнопкой на десктопе, чтобы появилось popup-меню
А, собственно, кто тебе сказал, что меню появляется по WM_RBUTTONDOWN, а не по WM_RBUTTONUP? smile.gif Заблокируй и WM_RBUTTONUP, никакой поп-ап не появится...
 К началу страницы 
+ Ответить 
Unconnected
сообщение 27.06.2010 1:29
Сообщение #8


mea culpa
*****

Группа: Пользователи
Сообщений: 1 372
Пол: Мужской
Реальное имя: Николай

Репутация: -  24  +


И правда, ничего теперь не всплывает, спасибо smile.gif Надо было самому догадаться - ведь если правую кнопку зажать, то popup-а не будет, пока не отожмёшь)


--------------------
"Знаешь, стыдно - когда не видно, что услышал всё, что слушал.."
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 

 Ответить  Открыть новую тему 
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 

- Текстовая версия 27.07.2025 3:53
Хостинг предоставлен компанией "Веб Сервис Центр" при поддержке компании "ДокЛаб"