Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "WinAPI";
Текущий архив: 2006.03.12;
Скачать: [xml.tar.bz2];

Вниз

Проблема с Hook om   Найти похожие ветки 

 
Igor_thief   (2005-12-17 13:54) [0]

Почему хук миши не срабатует тогда, когда клик происходит по заголовку окна?
Почему хук перестает работать, когда выйти из прилодения, которое установило хук?

Вот код:
library Hook;

uses
 SysUtils, Classes, Messages, WinTypes, WinProcs;

var
 HookHandle: HHOOK;
 IsHooked: Boolean;
 DesktopWin: HWND;

function HookProc(Code: integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
begin
 if wParam = WM_LBUTTONDOWN then
   Beep(100, 100);

 Result := CallNextHookEx(HookHandle, Code, wParam, lParam);
end;

function SetHook: Boolean; stdcall;
begin
 Result := false;

 if IsHooked then
   Exit;

 DesktopWin := GetDesktopWindow;
 HookHandle := SetWindowsHookEx(WH_MOUSE, HookProc, HInstance, 0);

 Result := HookHandle <> 0;
end;

function RemoveHook: Boolean; stdcall;
begin
 Result := false;

 if (not IsHooked) and (HookHandle <> 0) then
   Result := UnhookWindowsHookEx(HookHandle);

 IsHooked := false;
end;

exports
 SetHook name "SetHook",
 RemoveHook name "RemoveHook",
 HookProc name "HookProc";

{$R *.res}

begin
 IsHooked := false;
end.


Исользуюющая программа:

unit frmMainU;

interface

uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs, StdCtrls;

type
 TfrmMain = class(TForm)
   btnHook: TButton;
   btnUnhook: TButton;
   procedure btnUnhookClick(Sender: TObject);
   procedure btnHookClick(Sender: TObject);
 private
   { Private declarations }
 public
   { Public declarations }
 end;

 function SetHook: Boolean; stdcall;
 function RemoveHook: Boolean; stdcall;

var
 frmMain: TfrmMain;

implementation

{$R *.dfm}

 function SetHook; external "Hook.dll" name "SetHook";
 function RemoveHook; external "Hook.dll" name "RemoveHook";

procedure TfrmMain.btnHookClick(Sender: TObject);
begin
 if SetHook then
   ShowMessage("Global Hook is setted!")
 else
   ShowMessage("Error!");
end;

procedure TfrmMain.btnUnhookClick(Sender: TObject);
begin
 if RemoveHook then
   ShowMessage("Global Hook is removed!")
 else
   ShowMessage("Error!");
end;

end.


 
Lamer@fools.ua ©   (2005-12-17 14:20) [1]

>Почему хук миши не срабатует тогда, когда клик происходит по заголовку окна?
Потому что там приходит другое сообщение. Не WM_LBUTTONDOWN, а WM_NCLBUTTONDOWN, если не ошибаюсь.

>Почему хук перестает работать, когда выйти из прилодения, которое установило хук?
Спросите у Microsoft"а.


 
Igor_thief   (2005-12-17 14:54) [2]

Lamer@fools.ua ©   (17.12.05 14:20) [1]
Потому что там приходит другое сообщение. Не WM_LBUTTONDOWN, а WM_NCLBUTTONDOWN, если не ошибаюсь.

Проверю.

Lamer@fools.ua ©   (17.12.05 14:20) [1]
Спросите у Microsoft"а.

:))


 
Lamer@fools.ua ©   (2005-12-17 21:06) [3]

Смех смехом, а Рихтера всё-таки почитайте:
http://www.podgoretsky.com/ftp/Docs/Classics/Richter/


 
Se   (2005-12-18 09:24) [4]

Igor_thief ты не один такой. Я тоже мучаюсь с этим вопросом (посмотри "Форма не обрабатывает сообщения, когда неактивна").


 
Igor_thief   (2005-12-18 12:57) [5]

Lamer@fools.ua ©   (17.12.05 14:20) [1]
Потому что там приходит другое сообщение. Не WM_LBUTTONDOWN, а WM_NCLBUTTONDOWN, если не ошибаюсь.

The WM_NCLBUTTONDOWN message is posted when the user presses the left mouse button while the cursor is within the nonclient area of a window. This message is posted to the window that contains the cursor. If a window has captured the mouse, this message is not posted.
и
The WM_LBUTTONDOWN message is posted when the user presses the left mouse button while the cursor is in the client area of a window. If the mouse is not captured, the message is posted to the window beneath the cursor. Otherwise, the message is posted to the window that has captured the mouse.

Следовательно сделал такие изменения:

function HookProc(Code: integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
begin
 if wParam = WM_NCLBUTTONDOWN then
   Beep(100, 100);

 if wParam = WM_LBUTTONDOWN then
   Beep(100, 100);

 Result := CallNextHookEx(HookHandle, Code, wParam, lParam);
end;


 
Igor_thief   (2005-12-18 19:58) [6]

Теперь появилась новая проблема. Надо чтобы когда срабатывал хук мыши (на нажатие левой кнопки), мое приложение обрабатывало это событие.
Сразу в голове возникло два варианта решения проблемы. Первый - CallBack функция, второй - зарегистрировать уникальное сообщение (RegisterWindowMessage).
Для начала решил пойти вторым путем. Вроде работает нормально, но все же есть один нюанс! Помогите решить, плиз. Суть нюанаса -
BroadcastSystemMessage(BSF_IGNORECURRENTTASK or BSF_POSTMESSAGE, @Recepients, UserMsg, 0, 0);
вот так работает правильно, если не клацать в форме окна, которое зарегистрировало хук. Теоретически, для чтобы обойти это и сделать так, чтобы работало даже если клик происходит в окне, чей процесс зарегистровал хук, надо всего лишь убрать параметр BSF_IGNORECURRENTTASK. Как только я это делаю, приложение просто увеивает машину (загрузка проца - 100%).
Далее привожу полный код хука и решистрируещего приложения:
library Hook;

uses
 SysUtils, Classes, Messages, WinTypes, WinProcs;

var
 HookHandle: HHOOK;
 IsHooked: Boolean;
 DesktopWin: HWND;
 UserMsg: UINT;
 Recepients: DWORD;

function HookProc(Code: integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
begin
 if (wParam = WM_NCLBUTTONDOWN) or (wParam = WM_LBUTTONDOWN) then
   BroadcastSystemMessage(BSF_IGNORECURRENTTASK or BSF_POSTMESSAGE, @Recepients, UserMsg, 0, 0);

 Result := CallNextHookEx(HookHandle, Code, wParam, lParam);
end;

function SetHook: Boolean; stdcall;
begin
 Result := false;

 if IsHooked then
   Exit;

 DesktopWin := GetDesktopWindow;
 HookHandle := SetWindowsHookEx(WH_MOUSE, HookProc, HInstance, 0);

 Result := HookHandle <> 0;
end;

function RemoveHook: Boolean; stdcall;
begin
 Result := false;

 if (not IsHooked) and (HookHandle <> 0) then
   Result := UnhookWindowsHookEx(HookHandle);

 IsHooked := false;
end;

exports
 SetHook name "SetHook",
 RemoveHook name "RemoveHook",
 HookProc name "HookProc";

{$R *.res}

begin
 IsHooked := false;
 Recepients := BSM_APPLICATIONS;
 UserMsg := RegisterWindowMessage("{FF4B9248-40A7-4062-9CA3-CF08E2031306}");
end.


Программа которая обрабатывает сообщение:


unit frmMainU;

interface

uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs, StdCtrls;

type
 TfrmMain = class(TForm)
   btnHook: TButton;
   btnUnhook: TButton;
   procedure FormDestroy(Sender: TObject);
   procedure FormCreate(Sender: TObject);
   procedure btnUnhookClick(Sender: TObject);
   procedure btnHookClick(Sender: TObject);
 private
   { Private declarations }
 public
   { Public declarations }
 end;

 function SetHook: Boolean; stdcall;
 function RemoveHook: Boolean; stdcall;
 function NewWindowProc(TheWindow: HWND; Msg: Integer; wParam: WPARAM;
                        lParam: LPARAM): Longint; stdcall;

var
 frmMain: TfrmMain;
 UserMsg: UINT;
 OldWindowProc: TFNWndProc;

implementation

{$R *.dfm}

 function SetHook; external "Hook.dll" name "SetHook";
 function RemoveHook; external "Hook.dll" name "RemoveHook";

procedure TfrmMain.btnHookClick(Sender: TObject);
begin
 if SetHook then
   ShowMessage("Global Hook is setted!")
 else
   ShowMessage("Error!");
end;

procedure TfrmMain.btnUnhookClick(Sender: TObject);
begin
 if RemoveHook then
   ShowMessage("Global Hook is removed!")
 else
   ShowMessage("Error!");
end;

function NewWindowProc(TheWindow: HWND; Msg: Integer; wParam: WPARAM; lParam: LPARAM): Longint;
begin
 if Msg = UserMsg then
 begin
   frmMain.Tag := frmMain.Tag + 1;
   frmMain.Caption := frmMain.Caption + IntToStr(frmMain.Tag);
//    Application.ProcessMessages;

   {the message was handled, so return a one}
   Result := 1;
 end
 else
   {any other message must be passed to the previous window procedure}
   Result := CallWindowProc(OldWindowProc, TheWindow, Msg, wParam, lParam);
end;

procedure TfrmMain.FormCreate(Sender: TObject);
begin
 UserMsg := RegisterWindowMessage("{FF4B9248-40A7-4062-9CA3-CF08E2031306}");
 OldWindowProc := TFNWndProc(SetWindowLong(frmMain.Handle, GWL_WNDPROC,
                                  Longint(@NewWindowProc)));
end;

procedure TfrmMain.FormDestroy(Sender: TObject);
begin
 SetWindowLong(frmMain.Handle, GWL_WNDPROC, Longint(OldWindowProc));
end;

end.


 
Igor_thief   (2005-12-19 17:26) [7]

Удалено модератором
Примечание: Создание пустых сообщений


 
ANB ©   (2005-12-20 11:27) [8]


> Igor_thief   (18.12.05 19:58) [6]

C CallBack можешь даже не начинать, т.к. хуковый фильтр/процедура в DLL будет работать в АП чужого процесса, для которого адрес твоей CallBack функции - бессмысленный набор цифр.
Рассылка броадкастом вообще то избыточна. Можно заранее при установке хука передать хендл окна, которое будет обрабатывать служебные сообщения, в DLL, а там сохранить ее в MMF, чтобы хендл стал доступен всем экземплярам DLL. В MMF можно еще много чего полезного напихать. Регистрять отдельное сообщение и его же передавать тоже будет не круто, т.к. у тебя в него не влезет вся нужная информация (ссылки через WM_USER передавать бессмысленно). Хотя можно опять таки использовать MMF, но тут возникнет куча проблем с синхронизацией доступа. Короче - я использую помеченную WM_COPYDATA. Работает шустро и не сбоит.


 
Igor_thief   (2005-12-20 20:24) [9]

Сделал используя MMF.


 
grisme ©   (2005-12-21 11:32) [10]


> Почему хук миши не срабатует тогда, когда клик происходит
> по заголовку окна?



Потому что необходимо обрабатывать не WM_LBUTTONDOWN, а WM_NCHITTEST (вроде так - в хелпе посмотри!)



Страницы: 1 вся ветка

Форум: "WinAPI";
Текущий архив: 2006.03.12;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.49 MB
Время: 0.012 c
3-1137591605
Quantum
2006-01-18 16:40
2006.03.12
многопоточность и БД


2-1140527296
Mahab
2006-02-21 16:08
2006.03.12
JPEG


2-1140728065
Kolan
2006-02-23 23:54
2006.03.12
Как сделать чтобы форма вернула результат...


15-1140349376
Jim27
2006-02-19 14:42
2006.03.12
Виснет компьютер


2-1140631346
Volf_555
2006-02-22 21:02
2006.03.12
Как изменить функцию InputQuery, не переписывая её полностью?





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский