Проблема с SetWindowsHookEx

Тема в разделе "WASM.BEGINNERS", создана пользователем Xerx, 31 окт 2006.

  1. Xerx

    Xerx Алексей

    Публикаций:
    0
    Регистрация:
    17 фев 2005
    Сообщения:
    528
    Адрес:
    Russia
    Ставлю SetWindowsHookEx(WH_MOUSE, MouseHookFunc, hooker, 0), где MouseHookFunc - функция из загруженной библиотеки hooker. Она посылает сообщение окну через SendMessage и вызывает следующий обработчик CallNextHookEx. У окна есть обработчик этого сообщения с некоторой обработкой (неважно какой).

    Объясните является ли данный обработчик глобальным, или только для моей программы? Ибо сообщения поступают только когда мышь в пределах окна. А мне нужен глобальный перехватчик. Объясните в чем дело, что не так?
     
  2. opennetworks

    opennetworks New Member

    Публикаций:
    0
    Регистрация:
    20 окт 2006
    Сообщения:
    436
    Смотри исходник с МСДН
     
  3. Xerx

    Xerx Алексей

    Публикаций:
    0
    Регистрация:
    17 фев 2005
    Сообщения:
    528
    Адрес:
    Russia
    Все вроде сделал, но как-то странно работает.
    Упрощенные вариант:
    Код (Text):
    1. typedef struct
    2. {
    3.  DWORD X, Y;
    4. } mouse_data;
    5.  
    6. extern "C" HOOKDLL_API int __stdcall CALLBACK GetMouseData(mouse_data *md);
    7.  
    8. mouse_data m_d;
    9.  
    10. LRESULT CALLBACK MouseFunc(int nCode, WPARAM wParam, LPARAM lParam)
    11. {
    12.     if (nCode >= 0)
    13.     {
    14.         LPMOUSEHOOKSTRUCT   param;
    15.         param = (MOUSEHOOKSTRUCT*)lParam;
    16.  
    17.         m_d.type = wParam;
    18.         m_d.X = param->pt.x;
    19.         m_d.Y = param->pt.y;
    20.     }
    21.    
    22.     return CallNextHookEx(mouse_hook, nCode, wParam, lParam);
    23. }
    24.  
    25. int CALLBACK GetMouseData(TMouseData &md)
    26. {
    27.     if (!InitCalled) return 0;
    28.     md = m_d;
    29.     return 1;
    30. }
    Примерно так. И вот, когда курсор в пределах окна - все нормально. Когда он вне пределов - ничего: MouseFunc работает, но GetMouseData возвращает координаты последнего нахождения курсора в пределах окна. Когда курсор возвращается, все снова работает. В примере из MSDN немного другой принцип и не могу понять в чем дело?
     
  4. IceStudent

    IceStudent Active Member

    Публикаций:
    0
    Регистрация:
    2 окт 2003
    Сообщения:
    4.300
    Адрес:
    Ukraine
    Xerx
    А смысл этого хука? Не проще в таймере опрашивать положение курсора?
     
  5. Xerx

    Xerx Алексей

    Публикаций:
    0
    Регистрация:
    17 фев 2005
    Сообщения:
    528
    Адрес:
    Russia
    IceStudent>
    Я ж написал, что это упрощенный вариант. Лишнее, не изменяющее суть я в этом примере выкинул.
     
  6. Demon666

    Demon666 New Member

    Публикаций:
    0
    Регистрация:
    19 май 2006
    Сообщения:
    99
    Хм..! А что здесь делает ЯВУ!?
    Трабл, скорее всего в неинициализированных данных! Читаем Iczelion`a (Урок 24. Windows-хуки)

    P. S.
    Цитата:
    Важная деталь относительно удаленных хуков: хук-процедура должна
    находиться в DLL, которая будет промэппирована в другой процесс. Когда
    Windows мэппирует DLL в другой процесс, секция данных мэппироваться не
    будет. То есть, все процессы разделяют одну копию секции кода, но у них
    будет своя личная копия секции кода DLL! Это может стать большим сюрпризом
    для непредупрежденного человека.
    Вы можете подумать, что при сохранении
    значения в переменную в секции данных DLL, это значение получать все
    процессы, загрузившие DLL в свое адресное пространство. Hа самом деле, это
    не так. В обычной ситуации, такое поведение правильно, потому что это
    создает иллюзию, что у каждого процесса есть отдельная копия DLL. Hо не
    тогда, когда это касается хуков Windows. Hам нужно, чтобы DLL была
    идентична во всех процессах, включая данные. решение: вы должны пометить
    секцию данных как разделяемую.
     
  7. n0name

    n0name New Member

    Публикаций:
    0
    Регистрация:
    5 июн 2004
    Сообщения:
    4.336
    Адрес:
    Russia
    В Beginners и Delphi иногда попадается :P
     
  8. Xerx

    Xerx Алексей

    Публикаций:
    0
    Регистрация:
    17 фев 2005
    Сообщения:
    528
    Адрес:
    Russia
    А что делать, если этот форум лучший из всех, что я знаю. Кроме того, меня просили сделать программу именно на C++. Сам я хуки делал в MASM'е. Там все работало, а теперь не понимаю в чем дело!
    Соответственно Iczelion'а читал.

    Я жду помоши и объяснения чего не так АБСТРАГИРУЯСЬ от функциональности.
     
  9. DelExe

    DelExe New Member

    Публикаций:
    0
    Регистрация:
    22 авг 2005
    Сообщения:
    165
    Тебе же Demon666 объяснил - сделай через прагму шаровую секцию:

    #pragma data_seg(".JOE")
    mouse_data m_d = {0, 0, 0}; //Обязательно инициализировать
    #pragma data_seg()
    #pragma comment("linker, /section:.JOE,rws")
     
  10. Xerx

    Xerx Алексей

    Публикаций:
    0
    Регистрация:
    17 фев 2005
    Сообщения:
    528
    Адрес:
    Russia
    Так уже было. Вот полный код:
    Код (Text):
    1. #include <windows.h>
    2.  
    3. #define HOOKDLL_API __declspec(dllexport)
    4.  
    5. typedef struct
    6. {
    7.     DWORD   type;
    8.     int     X, Y;
    9. } TMouseData, *PMouseData;
    10.  
    11. extern "C" HOOKDLL_API int __stdcall CALLBACK InstallHook(bool set);
    12. extern "C" HOOKDLL_API int __stdcall CALLBACK SetHWND(HWND hwnd);
    13. extern "C" HOOKDLL_API int __stdcall CALLBACK GetMouseData(DWORD &type, DWORD &xy);
    14.  
    15. LRESULT CALLBACK MouseFunc(int nCode, WPARAM wParam, LPARAM lParam);
    16.  
    17. HINSTANCE   hInstance = 0;
    18. int         InitCalled = 0;
    19.  
    20. #pragma data_seg("SHARDATA")
    21. HHOOK       mouse_hook = 0;
    22. static TMouseData mouse_data = {0, 0, 0};
    23. static HWND hWnd = NULL;
    24. #pragma data_seg()
    25. #pragma comment("linker, /section:SHARDATA,rws")
    26.  
    27. int WINAPI DllEntryPoint(HINSTANCE hInst, DWORD, LPVOID)
    28. {
    29.     hInstance = hInst;
    30.     return 1;
    31. }
    32.  
    33. int CALLBACK SetHWND(HWND hwndParent)
    34. {
    35.     hWnd = hwndParent;
    36.     InitCalled = 1;
    37.     return 0;
    38. }
    39.  
    40. int CALLBACK InstallHook(bool set)
    41. {
    42.     if (!InitCalled) return 0;
    43.     if (set)
    44.     {                                                              
    45.         mouse_hook = SetWindowsHookEx(WH_MOUSE, (FARPROC)MouseFunc, hInstance, 0);
    46.     }
    47.     else
    48.     {
    49.         UnhookWindowsHookEx(mouse_hook);
    50.         mouse_hook = 0;
    51.     }
    52.     return 1;
    53. }
    54.  
    55. LRESULT CALLBACK MouseFunc(int nCode, WPARAM wParam, LPARAM lParam)
    56. {
    57.     if (nCode >= 0)
    58.     {
    59.         LPMOUSEHOOKSTRUCT   param;
    60.         param = (MOUSEHOOKSTRUCT*)lParam;
    61.  
    62.         mouse_data.type = wParam;
    63.         mouse_data.X = param->pt.x;
    64.         mouse_data.Y = param->pt.y;
    65.     }
    66.     return CallNextHookEx(mouse_hook, nCode, wParam, lParam);
    67. }
    68.  
    69. int CALLBACK GetMouseData(DWORD &type, DWORD &xy)
    70. {
    71.     if (!InitCalled) return 0;
    72.     type = mouse_data.type;
    73.     xy = (mouse_data.X << 16) | mouse_data.Y;
    74.     return 1;
    75. }
    Не работает! Точнее, только в пределах окна.
    Что я только не делал, как только не описывал переменные - бесполезно. Что можно сделать?
     
  11. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    у меня тоже бывает, что линкер не видит pragma comment в исходнике.
    В таком случае непосредственно в командной строке линкера указываю ключи (через батник).
     
  12. DelExe

    DelExe New Member

    Публикаций:
    0
    Регистрация:
    22 авг 2005
    Сообщения:
    165
    1. Исходник в студию: весь проект - библиотеку и инжектор.
    2. Такая ситуация возможна ещё и при инжекте процесса, вместо библиотеки, когда hInstance == NULL (или 0x40....)
    3. Вообще в таких случаях выводят дебаг-сообщения и ловят их с помощью hххp://www.sysinternals.com/Utilities/DebugView.html
    Тогда уж точно видно в какой последовательности, с какими параметрами и что собственно вызывается.

    P.S. Где увереность что DllEntryPoint вызываеться?
     
  13. DelExe

    DelExe New Member

    Публикаций:
    0
    Регистрация:
    22 авг 2005
    Сообщения:
    165
    PPS Где увереность что DllEntryPoint вызываеться именно один раз, а значит hInstance принимает правильное значение?
     
  14. Demon666

    Demon666 New Member

    Публикаций:
    0
    Регистрация:
    19 май 2006
    Сообщения:
    99
    Интересно, почему Quantum не высказывается по данному вопросу?
    Помнится, он даже доказывал, что системные хуки это есть гуд!
    Я же отталкиваться буду от своего опыта и тестирования на разных компьютерах с установленным разным софтом:
    1. системные хуки тяжело состыковываются с разными программами.
    2. Xerx ты уверен, что правильно у тебя написан код?

    P. S.
    +1
     
  15. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    Дался вам этот код. Нормальный он. Не в нем дело.
    Дело в pragma comment. Не работает эта фича. Сам сейчас проверил. А указал в батнике соответствующие ключи для линкера - и все заработало.
    В аттаче пример, показывающий координату х мыши независимо от того, над каким окном она находится.
    Код в dll такой:

    Код (Text):
    1. LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam){
    2.     PMOUSEHOOKSTRUCT        pData = (PMOUSEHOOKSTRUCT) lParam;
    3.     char                    buffer[32];
    4.  
    5.     if (wParam == WM_MOUSEMOVE) {
    6.         wsprintf (buffer, "mouse.x: %lu", pData->pt.x);
    7.         SetWindowText (hWndLoader, buffer);
    8.     }
    9.  
    10.     CallNextHookEx (hHook, nCode, wParam, lParam);
    11.     return 0;
    12. }
    Ключи линкера (компилировал и линковал батником):
    link /subsystem:windows /SECTION:.bss,S /dll /def:mousehook.def mousehook.obj
     
  16. Demon666

    Demon666 New Member

    Публикаций:
    0
    Регистрация:
    19 май 2006
    Сообщения:
    99
    cresta
    Найди десять различий ;)

    #pragma data_seg("SHARDATA")
    HHOOK mouse_hook = 0;
    static TMouseData mouse_data = {0, 0, 0};
    static HWND hWnd = NULL;
    #pragma data_seg()
    #pragma comment("linker, /section:SHARDATA,rws")

    #pragma data_seg("bss")
    HHOOK mouse_hook = 0;
    static TMouseData mouse_data = {0, 0, 0};
    static HWND hWnd = NULL;
    #pragma data_seg()
    #pragma comment(linker, "/SECTION:.bss,s")

    P. S.
    Хе-хе читаем доки и учим синтаксис, блин и я тоже не исключение =)))
     
  17. Xerx

    Xerx Алексей

    Публикаций:
    0
    Регистрация:
    17 фев 2005
    Сообщения:
    528
    Адрес:
    Russia
    Проверял - один раз.

    cresta>
    А у меня твой пример не работает :) Точнее работает как и у меня. Кроме того, у меня другая проблема: у тебя ничего из основной программы, кроме HWND не используется, а мне нужно передавать структуры. У меня был РАБОЧИЙ пример, в котором САМА DLL выводила на контекст рабочего стола (HDC hDC = GetDC(0)) координаты. Пример РАБОТАЛ над любым окном, даже при свернутом приложении! А передача работает (и работала) только над моим окном.

    Demon666> А программе по-прежнему до лампочки :dntknw:

    Короче, выкладываю код. BCB 6.0. Извините уж, что на C++.

    P.S. Не надо предлагать переделать на ASM. Нельзя.

    Очень надеюсь на вашу помощь! Меня эта фигня уже достала :[
     
  18. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    Xerx
    Пример, приведенный мною, на 100% рабочий. Разбирайся со своей виндой. Если ты сделаешь dll с разделяемыми секциями, то всё равно, что в коде dll написано. Работать будет над любым окном.
    В примере именно dll рисует текст на родительском окне.
    А передаваемые параметры (hwnd, структуры и т.д.) и их количество никакого отношения к работоспособности хука не имеют.

    Получилась у тебя dll с требуемой структурой или нет, можешь посмотреть например в PEExplorer, там выводится информация о секциях.
     
  19. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    Ещё совет: возьми какую-нибудь тулзу, показывающую подгруженные в процессы dll-ки, запусти свой хук и посмотри, подгружается твоя dll куда-нибудь ещё, кроме твоего приложения, или нет. Например в процесс explorer.
     
  20. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    Посмотрел твою dll - нет в ней секции bss.
    Есть: .text, .data, .idata, .edata, .tls, .rsrc, .reloc. Всё.
    #pragma comment(linker, "/SECTION:.bss,s") не сработала.
    Делайте секцию.