Загадки с хуками...
От: Kochuev  
Дата: 10.10.04 09:27
Оценка:
Господа, помогите понять в целях повышения самообразованности... СОздаю хук типа WH_CALLWNDPROC и в него не приходят сообщения WM_MOUSEMOVE... Это особенность хука (про нее правда в MSDN ничего не написано)? ОС Windows 2000. Обойти проблему удалось использованием WH_MOUSE_LL — низкоуровневого мышиного хука. Но для меня так и осталось непонятным, почему хук WH_CALLWNDPROC не ловит сообщения мыши. Если заменить WH_CALLWNDPROC на хук WH_GETMESSAGE — все работает! Мне всегда казалось, что разница между этими хуками только в моменте перехвата сообщения, а не в составе отлавливаемых сообщений... В чем бы могло быть дело? Может какой-то другой хук не передает сообщение дальше???

Кстати еще вопро в чем разница между низкоуровневыми (*_LL) и не низкоуровневыми хуками?


Вот код моей DLL хука:


#pragma data_seg(".SHRD")
HWND hWndServer = NULL;
#pragma data_seg()

HINSTANCE hInstance;
UINT UWM_MOUSEHOOK, UWM_WNDPROCHOOK;
HHOOK hMouseHook, hWndHook;

static LRESULT CALLBACK mousehook(int nCode, WPARAM wParam, LPARAM lParam);
static LRESULT CALLBACK wndhook(int nCode, WPARAM wParam, LPARAM lParam);



BOOL __stdcall DllMain(HINSTANCE hInst, DWORD Reason, LPVOID reserved)
{
 switch(Reason)
   { 
    //**********************************************
    // PROCESS_ATTACH
    //**********************************************
    case DLL_PROCESS_ATTACH:
       hInstance = hInst;
       UWM_MOUSEHOOK = RegisterWindowMessage(UWM_MOUSEHOOK_MSG);
       UWM_WNDPROCHOOK = RegisterWindowMessage(UWM_WNDPROCHOOK_MSG);
       return TRUE;

    //**********************************************
    // PROCESS_DETACH
    //**********************************************
    case DLL_PROCESS_DETACH:
       if(hWndServer != NULL)
          clearHooks(hWndServer);
       return TRUE;
   } 
}


CLOCKHOOK_API BOOL WINAPI setHooks(HWND hWnd)
  {
   if(hWndServer != NULL)
      return FALSE;
   hMouseHook = SetWindowsHookEx(
                                WH_MOUSE_LL,
                                (HOOKPROC)mousehook,
                                 hInstance,
                                0);

   hWndHook = SetWindowsHookEx(
                                WH_CALLWNDPROC,
                                (HOOKPROC)wndhook,
                                 hInstance,
                                0);

   if(hMouseHook != NULL && hWndHook != NULL)
     { 
      hWndServer = hWnd;
      return TRUE;
     } 
   return FALSE;
  } 


CLOCKHOOK_API BOOL clearHooks(HWND hWnd)
   {
    if(hWnd != hWndServer)
       return FALSE;
    BOOL unhooked = UnhookWindowsHookEx(hMouseHook) && UnhookWindowsHookEx(hWndHook);
    if(unhooked)
       hWndServer = NULL;
    return unhooked;
   }


//низкоуровневый мышиный хук
static LRESULT CALLBACK mousehook(int nCode, WPARAM wParam, LPARAM lParam)
 {

    if(nCode < 0)
      { 
       CallNextHookEx(hMouseHook, nCode,
                   wParam, lParam);
       return 0;
      } 


    LPMSLLHOOKSTRUCT mh = (LPMSLLHOOKSTRUCT)lParam;

    if(wParam == WM_MOUSEMOVE ) {
            PostMessage(hWndServer,
                  UWM_MOUSEHOOK,   
                  mh->pt.x,mh->pt.y);
    }

    return CallNextHookEx(hMouseHook, nCode, 
                       wParam, lParam);
   } // mousehook


//хук WH_CALLWNDPROC
static LRESULT CALLBACK wndhook(int nCode, WPARAM wParam, LPARAM lParam)
 {

    if(nCode < 0)
      { 
       CallNextHookEx(hWndHook, nCode,
                   wParam, lParam);
       return 0;
      } 

    LPCWPSTRUCT cs = (LPCWPSTRUCT)lParam;

    //вот это условие никогда не выполняется.... :(
    if(cs->message == WM_MOUSEMOVE) {

            PostMessage(hWndServer,
                  UWM_WNDPROCHOOK,   
                  cs->message,0);
    }

    return CallNextHookEx(hWndHook, nCode, 
                       wParam, lParam);
   } // msghook


Буду благодарен за любые соображения на этот счет! Не дайте пропасть в неведении...
Re: Загадки с хуками...
От: Leonid Troyanovsky  
Дата: 10.10.04 15:19
Оценка:
Здравствуйте, Kochuev, Вы писали:

K>Господа, помогите понять в целях повышения самообразованности... СОздаю хук типа WH_CALLWNDPROC и в него не приходят сообщения WM_MOUSEMOVE... Это особенность хука (про нее правда в MSDN ничего не написано)? ОС Windows 2000. Обойти проблему удалось использованием WH_MOUSE_LL — низкоуровневого мышиного хука. Но для меня так и осталось непонятным, почему хук WH_CALLWNDPROC не ловит сообщения мыши. Если заменить WH_CALLWNDPROC на хук WH_GETMESSAGE — все работает! Мне всегда казалось, что разница между этими хуками только в моменте перехвата сообщения, а не в составе отлавливаемых сообщений... В чем бы могло быть дело? Может какой-то другой хук не передает сообщение дальше???


The WM_MOUSEMOVE message is posted to a window when the cursor moves. If the mouse is not captured, the message is posted to the window that contains the cursor. Otherwise, the message is posted to the window that has captured the mouse.

Posted vs sended.

Вообще, для мыши есть WH_MOUSE.

K>Кстати еще вопро в чем разница между низкоуровневыми (*_LL) и не низкоуровневыми хуками?


Низкоуровневые работают в контексте установившего их потока.
--
С уважением, LVT
Re[2]: Загадки с хуками...
От: Kochuev  
Дата: 10.10.04 16:55
Оценка:
Здравствуйте, Leonid Troyanovsky, Вы писали:


LT>The WM_MOUSEMOVE message is posted to a window when the cursor moves. If the mouse is not captured, the message is posted to the window that contains the cursor. Otherwise, the message is posted to the window that has captured the mouse.


LT> Posted vs sended.


Не совсем пойму... Хук-то глобальный. Для всех окон перехватывает...

LT> Вообще, для мыши есть WH_MOUSE.



K>>Кстати еще вопро в чем разница между низкоуровневыми (*_LL) и не низкоуровневыми хуками?


LT> Низкоуровневые работают в контексте установившего их потока.


Т.е. можно не писать DLL для перехвата? Я правильно понял?
Re[2]: Загадки с хуками...
От: Slava Antonov Россия http://deadbeef.narod.ru
Дата: 11.10.04 00:32
Оценка: 1 (1)
Hello Leonid Troyanovsky, you wrote:

> Низкоуровневые работают в контексте установившего их потока.


А также: "The system calls this function every time a new keyboard input
event is about to be posted into a thread input queue. The keyboard input
can come from the local keyboard driver or from calls to the keybd_event
function."
В то время как обычный хук "The system calls this function whenever an
application calls the GetMessage or PeekMessage function and there is a
keyboard message (WM_KEYUP or WM_KEYDOWN) to be processed"

И еще, работа низкоуровневого хука жестко ограничена по времени. "The hook
procedure should process a message in less time than the data entry
specified in the LowLevelHooksTimeout value in the following registry key:

HKEY_CURRENT_USER\Control Panel\Desktop

The value is in milliseconds. If the hook procedure does not return during
this interval, the system will pass the message to the next hook."

--
Всего хорошего, Слава
Posted via RSDN NNTP Server 1.9 gamma
Re[3]: Загадки с хуками...
От: Slava Antonov Россия http://deadbeef.narod.ru
Дата: 11.10.04 01:11
Оценка:
Hello Kochuev, you wrote:

> Т.е. можно не писать DLL для перехвата? Я правильно понял?


Да.

--
Всего хорошего, Слава
Posted via RSDN NNTP Server 1.9 gamma
Re: Загадки с хуками...
От: Kochuev  
Дата: 11.10.04 03:59
Оценка:
Всем спасибо за оказанную помощь Вы помогли несколько все разложить по полочкам

Правда, еше не совсем понятно, почему при иснользовании НЕ низкоуровневого хука, процедура хука перестает перехватывать сообщения мыши, когда курсор находится в НЕ-клиентской области какого-либо окна. именно из-за этого и пришлось использовать низкоуровневый хук. Возможно это из-за каких-то других хуков, перехватывающих не пропускающих соощение по цепочке хуков? Если кто-то знает, почему, буду очень благодарен.
Re[2]: Загадки с хуками...
От: AcidTheProgrammer Россия https://hts.tv/
Дата: 11.10.04 07:43
Оценка:
Здравствуйте, Kochuev, Вы писали:

K>Всем спасибо за оказанную помощь Вы помогли несколько все разложить по полочкам


K>Правда, еше не совсем понятно, почему при иснользовании НЕ низкоуровневого хука, процедура хука перестает перехватывать сообщения мыши, когда курсор находится в НЕ-клиентской области какого-либо окна. именно из-за этого и пришлось использовать низкоуровневый хук. Возможно это из-за каких-то других хуков, перехватывающих не пропускающих соощение по цепочке хуков? Если кто-то знает, почему, буду очень благодарен.


Может потому, что не то сообщение смотришь. Попробуй WM_NCMOUSEMOVE
Re[3]: Загадки с хуками...
От: Kochuev  
Дата: 11.10.04 11:01
Оценка:
Здравствуйте, AcidTheProgrammer, Вы писали:

ATP>Может потому, что не то сообщение смотришь. Попробуй WM_NCMOUSEMOVE


Я говорю о хуке WH_MOUSE, который не передает в процедуру хука никаких сведений о сообщении. Так что возможности смотреть сообщения нет, а значит, проблема не в этом.

Причем, если заменить тип хука на WH_MOUSE_LL, то все работает без проблем с перемещением в неклиентской области.

В чем же тогда дело?...
Re: Загадки с хуками...
От: Auster Ниоткуда  
Дата: 13.10.04 10:21
Оценка:
Здравствуйте, Kochuev, Вы писали:

K>Господа, помогите понять в целях повышения самообразованности... СОздаю хук типа WH_CALLWNDPROC и в него не приходят сообщения WM_MOUSEMOVE... Это особенность хука (про нее правда в MSDN ничего не написано)? ОС Windows 2000. Обойти проблему удалось использованием WH_MOUSE_LL — низкоуровневого мышиного хука. Но для меня так и осталось непонятным, почему хук WH_CALLWNDPROC не ловит сообщения мыши. Если заменить WH_CALLWNDPROC на хук WH_GETMESSAGE — все работает! Мне всегда казалось, что разница между этими хуками только в моменте перехвата сообщения, а не в составе отлавливаемых сообщений... В чем бы могло быть дело? Может какой-то другой хук не передает сообщение дальше???


Возможно здесь дело в том, что сообщение WM_MOUSEMOVE не есть обычное типа WM_MOUSEDOWN и не постится в оконную очередь приложения, а генерится налету, когда приложение вызывает GetMessage(), подобно WM_TIMER или как его там...

Копайте MSDN глубже, Шура, они золотые..
... << RSDN@Home 1.1.3 stable >>
Re[2]: Загадки с хуками...
От: Pavel Dvorkin Россия  
Дата: 14.10.04 09:30
Оценка:
Привет!

Auster wrote:
>
> Здравствуйте, Kochuev, Вы писали:
>
> K>Господа, помогите понять в целях повышения самообразованности... СОздаю хук типа WH_CALLWNDPROC и в него не приходят сообщения WM_MOUSEMOVE... Это особенность хука (про нее правда в MSDN ничего не написано)? ОС Windows 2000. Обойти проблему удалось использованием WH_MOUSE_LL — низкоуровневого мышиного хука. Но для меня так и осталось непонятным, почему хук WH_CALLWNDPROC не ловит сообщения мыши.

/////////////////////////////////////////////////////////////////////////////////////////////////////////

CallWndRetProc Function

--------------------------------------------------------------------------------

The CallWndRetProc hook procedure is an application-defined or
library-defined callback function used with the SetWindowsHookEx
function. The system calls this function after the SendMessage function
is called. The hook procedure can examine the message; it cannot modify
it.

/////////////////////////////////////////////////////////////////////////////////////////////////////////

С каких это пор WM_MOUSEMOVE стало посылаться через SendMessage ?

>Если заменить WH_CALLWNDPROC на хук WH_GETMESSAGE — все работает!


Естественно.

/////////////////////////////////////////////////////////////////////////////////////////////////////////

GetMsgProc Function

--------------------------------------------------------------------------------

The GetMsgProc function is an application-defined or library-defined
callback function used with the SetWindowsHookEx function. The system
calls this function whenever the GetMessage or PeekMessage function has
retrieved a message from an application message queue. Before returning
the retrieved message to the caller, the system passes the message to
the hook procedure.

/////////////////////////////////////////////////////////////////////////////////////////////////////////

Поэтому и работает, так как через GetMessage проходит.


>Мне всегда казалось, что разница между этими хуками только в моменте перехвата сообщения, а не в составе >отлавливаемых сообщений... В чем бы могло быть дело? Может какой-то другой хук не передает сообщение >дальше???


Вот в этом и дело. MSDN читать надо.

>

> Возможно здесь дело в том, что сообщение WM_MOUSEMOVE не есть обычное типа WM_MOUSEDOWN

Обычное вполне.


>и не постится в оконную очередь приложения, а генерится налету, когда приложение вызывает GetMessage(), >подобно WM_TIMER или как его там...



Это как так налету ?

Кстати, и WM_TIMER через очередь проходит (точнее, там QS_TIMER флаг
взводится). См.GetQueueStatus


--
With best regards,
Pavel Dvorkin
Posted via RSDN NNTP Server 1.9 gamma
With best regards
Pavel Dvorkin
Re[3]: Загадки с хуками...
От: Auster Ниоткуда  
Дата: 14.10.04 10:43
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

>>и не постится в оконную очередь приложения, а генерится налету, когда приложение вызывает GetMessage(), >подобно WM_TIMER или как его там...


PD>Это как так налету ?


в момет вызова приложением GetMessage()

PD>Кстати, и WM_TIMER через очередь проходит (точнее, там QS_TIMER флаг

PD>взводится). См.GetQueueStatus

вот, вот, а для mouse move там есть флаг QS_MOUSEMOVE.
Сами же сообщения WM_MOUSEMOVE в оконной очереди реально не хранятся.
А иначе как? С какой скоростью они бы эту очередь заполняли, скажем, на пне 3.0 гигагерца, пока приложение ожидает, например, окончания сетевой операции, а юзер нервно дергает мышью?
... << RSDN@Home 1.1.3 stable >>
Re[4]: Загадки с хуками...
От: Pavel Dvorkin Россия  
Дата: 14.10.04 11:20
Оценка:
Привет!

Auster wrote:
> вот, вот, а для mouse move там есть флаг QS_MOUSEMOVE.

Там много флагов есть. Например :

QS_KEY
A WM_KEYUP, WM_KEYDOWN, WM_SYSKEYUP, or WM_SYSKEYDOWN message is in the
queue.
QS_MOUSEBUTTON
A mouse-button message (WM_LBUTTONUP, WM_RBUTTONDOWN, and so on).
QS_MOUSEMOVE
A WM_MOUSEMOVE message is in the queue.


> Сами же сообщения WM_MOUSEMOVE в оконной очереди реально не хранятся.

> А иначе как? С какой скоростью они бы эту очередь заполняли, скажем, на пне 3.0 гигагерца, пока приложение ожидает, например, окончания сетевой операции, а юзер нервно дергает мышью?

Сообщения там все же хранятся, или объясни, где тогда хранятся
координаты курсора мыши, присылаемые с этим сообщением ? lParam то есть.
Для каждого сообщения свой.

А 3.0 ГГц здесь ни при чем. Вот когда ты начнешь мышь двигать с частотой
3 Ггц, тогда поговорим.

--
With best regards,
Pavel Dvorkin
Posted via RSDN NNTP Server 1.9 gamma
With best regards
Pavel Dvorkin
Re[5]: Загадки с хуками...
От: Auster Ниоткуда  
Дата: 14.10.04 13:07
Оценка: 26 (2)
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Сообщения там все же хранятся, или объясни, где тогда хранятся

PD>координаты курсора мыши, присылаемые с этим сообщением ? lParam то есть.
PD>Для каждого сообщения свой.

PD>А 3.0 ГГц здесь ни при чем. Вот когда ты начнешь мышь двигать с частотой

PD>3 Ггц, тогда поговорим.

Мда.. Видимо майкрософту тоже было проще написать, что они попадают в очередь, чем объяснить откуда они берутся...

Несмотря на то, что мы уже далеко ушли от темы, позволю себе привести здесь небольшое "доказательство от обратного".

Пусть сообщения WM_MOUSEMOVE постятся в оконную очередь приложения при движении мышки с некоторой периодичностью (то ли per seconds, то ли per pixels), и приложение некоторое время не выбирает сообщения из очереди. Через какое-то время (мышь прошла по сложной траектории) приложение начинает вызывать GetMessage() и получает все эти сообщения, то есть ту самую траекторию. Так?

Хорошо. Попробуем это доказать.
Для этого понадобится обычный Paint и Process Explorer от sysinternals. Расположим их рядом. В Paint выберем Pencil и проведем сложную траекторию. Думаю, Вы не будете спорить, что Paint нарисовал ее по сообщениям WM_MOUSEMOVE из очереди?

Теперь сотрем все, приостановим процесс mspaint.exe в Process Explorer (popup menu -> Suspend) и повторим операцию рисования (т.е. mouse down, complex mouse moving and mouse up). Исходя из наших предположений, вся траектория мышки сейчас в очереди приложения. Теперь достаточно пустить процесс (popup menu -> Resume) и увидеть как Paint нарисует прямую линию между начальной и конечной точкой.
Вывод, надеюсь, сделаете сами?

Что бы убедится окончательно, что paint получит только один последний WM_MOUSEMOVE, причем с теми же координатами, что и следующий за ним WM_MOUSEUP, можно еще Spy поцепить на этот процесс. У немя под рукой сейчас нет к сожалению, как и MSDNa
... << RSDN@Home 1.1.3 stable >>
Re[6]: Загадки с хуками...
От: Pavel Dvorkin Россия  
Дата: 14.10.04 13:24
Оценка:
Привет!

Auster wrote:
> Мда.. Видимо майкрософту тоже было проще написать, что они попадают в очередь, чем объяснить откуда они берутся...
>
> Несмотря на то, что мы уже далеко ушли от темы, позволю себе привести здесь небольшое "доказательство от обратного".

<skipped>
> Вывод, надеюсь, сделаете сами?

Не могу утверждать определенно. Может, ты и прав. Кстати, если уж так (у
меня сейчас нет времени на проверку — слишком поздно, иду домой) , то
тогда сообщения WM_KEYDOWN, WM_LBUTTONDOWN и т.д. (насчет них, как я
понимаю, ты согласен, что в очереди хранятся) должны после приостановки
и продолжения процесса прибыть ВСЕ. Можешь попробовать ? Т.е. останови
процесс и пощелкай в его окне мышкой, а потом отпусти процесс. Процесс
можешь сам элементарно сотворить такой, чтобы любой WM_KEYDOWN,
WM_LBUTTONDOWN рисовал что-то.

Если нарисует — ты прав. Если нет — надо копать дальше.


--
With best regards,
Pavel Dvorkin
Posted via RSDN NNTP Server 1.9 gamma
With best regards
Pavel Dvorkin
Re[7]: Загадки с хуками...
От: Pavel Dvorkin Россия  
Дата: 15.10.04 04:15
Оценка:
Привет еще раз!

Должен признать, что ты прав.

Я проделал следующий эксперимент. Сделал приложение , где на пункт меню
выполняется длинный цикл. За время этого цикла я подвигал в окне мышкой,
при том, что на WM_MOUSEMOVE выводится пиксель. Результат — пикселей
нет.

После этого я сделал то же, но на WM_LBUTTONDOWN рисуется прямоугольник.
Пощелкал несколько раз во время задержки. После окончания задержки
прямоугольники появились.


--
With best regards,
Pavel Dvorkin
Posted via RSDN NNTP Server 1.9 gamma
With best regards
Pavel Dvorkin
Re[8]: Загадки с хуками...
От: Alex Reyst Россия  
Дата: 15.10.04 04:56
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Должен признать, что ты прав.


Извините, что вмешиваюсь в разговор

В MSDN есть такая фраза:

When mouse messages are posted faster than a thread can process them, the system discards all but the most recent mouse message.


Т.е. не означает ли это, что каждое сообщение WM_MOUSEMOVE просто заменяет предыдущее в очереди, если оно еще не обработано?
Все, что здесь сказано, может и будет использоваться против меня...
Re[9]: Загадки с хуками...
От: Pavel Dvorkin Россия  
Дата: 15.10.04 05:11
Оценка:
Привет!

Alex Reyst wrote:
>
> Здравствуйте, Pavel Dvorkin, Вы писали:
>
> PD>Должен признать, что ты прав.
>
> Извините, что вмешиваюсь в разговор

Бога ради

>

> В MSDN есть такая фраза:
>

> When mouse messages are posted faster than a thread can process them, the system discards all but the most recent mouse message.

>
> Т.е. не означает ли это, что каждое сообщение WM_MOUSEMOVE просто заменяет предыдущее в очереди, если оно еще не обработано?

Похоже, что это именно так. То есть получается, что сообщение все же в
очереди есть, но только одно. Кстати, похоже (хоть и не точно) на
WM_PAINT — оно там всегда одно, если есть.


--
With best regards,
Pavel Dvorkin
Posted via RSDN NNTP Server 1.9 gamma
With best regards
Pavel Dvorkin
Re[10]: Загадки с хуками...
От: Alex Reyst Россия  
Дата: 15.10.04 05:37
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Похоже, что это именно так. То есть получается, что сообщение все же в

PD>очереди есть, но только одно. Кстати, похоже (хоть и не точно) на
PD>WM_PAINT — оно там всегда одно, если есть.

Так. Проведенный тщательный эксперимент показал, что из очереди "сокращаются" последовательные WM_MOUSEMOVE, не разделенные другими событиями мыши.
Все логично.
Все, что здесь сказано, может и будет использоваться против меня...
Re[11]: Загадки с хуками...
От: Auster Ниоткуда  
Дата: 15.10.04 11:08
Оценка:
Здравствуйте, Alex Reyst, Вы писали:

AR>Так. Проведенный тщательный эксперимент показал, что из очереди "сокращаются" последовательные WM_MOUSEMOVE, не разделенные другими событиями мыши.


Возможно и так.
Но я думаю, это было проще реализовать через флаги и хранение некоторых параметров отдельно (например региона для WM_PAINT), кроме того, то же WM_PAINT имеет более низкий приоритет, то есть "выбирается из очереди" последним.

Что касательно "разделения" DOWN и UP сообщением MOVE, я думаю это своеобразный bugfix — наверно некоторые не анализируют координаты в WM_LBUTTONUP, рассчитывая на WM_MOUSEMOVE, если было движение.
... << RSDN@Home 1.1.3 stable >>
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.