Привет всем, опять это я и 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;
А, вроде чтобы сообщение закончило свои дни в ловушке, надо сделать result:=-1..
Для начала - о том, почему глобальный (действительно глобальный) хук должен находиться в DLL. А вот почему:
"В Dll код нужно выносить по той простой причине, что этот код должен быть внедрён в адресное пространство целевого процесса.
Например, другой процесс, не связанный с вами, ставит хук. Вот вы вызывали GetMessage. Должен сработать хук. Сейчас управление находится в вашем процессе. Как система вызовет обработчик хука, находящийся вообще в другом адресном пространстве? А никак.
Поэтому она требует, чтобы код был в DLL. Тогда она может спокойно загрузить DLL в ваш процесс, а когда вы вызываете GetMessage, то система просто проходит по списку хуков и вызывает код каждого обработчика, который сейчас сидит в вашем адресном пространстве. Очень просто." (С) CodeMonkey
Кстати, именно по этой причине тебе здесь не нужна DLL:
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);
Клааасс, как всегда очень познавательно и понятно, спасибо ! Кстати, у меня WH_MOUSE_LL не опознаётся, говорит, что unknown identifier, ну я его просто на число 14 заменил
const
WH_MOUSE_LL = 14;
Кстати, если кому интересно, я тут заметил, что не всё подряд перехватывается Например :
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-а не будет, пока не отожмёшь)