Ставлю SetWindowsHookEx(WH_MOUSE, MouseHookFunc, hooker, 0), где MouseHookFunc - функция из загруженной библиотеки hooker. Она посылает сообщение окну через SendMessage и вызывает следующий обработчик CallNextHookEx. У окна есть обработчик этого сообщения с некоторой обработкой (неважно какой). Объясните является ли данный обработчик глобальным, или только для моей программы? Ибо сообщения поступают только когда мышь в пределах окна. А мне нужен глобальный перехватчик. Объясните в чем дело, что не так?
Все вроде сделал, но как-то странно работает. Упрощенные вариант: Код (Text): typedef struct { DWORD X, Y; } mouse_data; extern "C" HOOKDLL_API int __stdcall CALLBACK GetMouseData(mouse_data *md); mouse_data m_d; LRESULT CALLBACK MouseFunc(int nCode, WPARAM wParam, LPARAM lParam) { if (nCode >= 0) { LPMOUSEHOOKSTRUCT param; param = (MOUSEHOOKSTRUCT*)lParam; m_d.type = wParam; m_d.X = param->pt.x; m_d.Y = param->pt.y; } return CallNextHookEx(mouse_hook, nCode, wParam, lParam); } int CALLBACK GetMouseData(TMouseData &md) { if (!InitCalled) return 0; md = m_d; return 1; } Примерно так. И вот, когда курсор в пределах окна - все нормально. Когда он вне пределов - ничего: MouseFunc работает, но GetMouseData возвращает координаты последнего нахождения курсора в пределах окна. Когда курсор возвращается, все снова работает. В примере из MSDN немного другой принцип и не могу понять в чем дело?
IceStudent> Я ж написал, что это упрощенный вариант. Лишнее, не изменяющее суть я в этом примере выкинул.
Хм..! А что здесь делает ЯВУ!? Трабл, скорее всего в неинициализированных данных! Читаем Iczelion`a (Урок 24. Windows-хуки) P. S. Цитата: Важная деталь относительно удаленных хуков: хук-процедура должна находиться в DLL, которая будет промэппирована в другой процесс. Когда Windows мэппирует DLL в другой процесс, секция данных мэппироваться не будет. То есть, все процессы разделяют одну копию секции кода, но у них будет своя личная копия секции кода DLL! Это может стать большим сюрпризом для непредупрежденного человека. Вы можете подумать, что при сохранении значения в переменную в секции данных DLL, это значение получать все процессы, загрузившие DLL в свое адресное пространство. Hа самом деле, это не так. В обычной ситуации, такое поведение правильно, потому что это создает иллюзию, что у каждого процесса есть отдельная копия DLL. Hо не тогда, когда это касается хуков Windows. Hам нужно, чтобы DLL была идентична во всех процессах, включая данные. решение: вы должны пометить секцию данных как разделяемую.
А что делать, если этот форум лучший из всех, что я знаю. Кроме того, меня просили сделать программу именно на C++. Сам я хуки делал в MASM'е. Там все работало, а теперь не понимаю в чем дело! Соответственно Iczelion'а читал. Я жду помоши и объяснения чего не так АБСТРАГИРУЯСЬ от функциональности.
Тебе же Demon666 объяснил - сделай через прагму шаровую секцию: #pragma data_seg(".JOE") mouse_data m_d = {0, 0, 0}; //Обязательно инициализировать #pragma data_seg() #pragma comment("linker, /section:.JOE,rws")
Так уже было. Вот полный код: Код (Text): #include <windows.h> #define HOOKDLL_API __declspec(dllexport) typedef struct { DWORD type; int X, Y; } TMouseData, *PMouseData; extern "C" HOOKDLL_API int __stdcall CALLBACK InstallHook(bool set); extern "C" HOOKDLL_API int __stdcall CALLBACK SetHWND(HWND hwnd); extern "C" HOOKDLL_API int __stdcall CALLBACK GetMouseData(DWORD &type, DWORD &xy); LRESULT CALLBACK MouseFunc(int nCode, WPARAM wParam, LPARAM lParam); HINSTANCE hInstance = 0; int InitCalled = 0; #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") int WINAPI DllEntryPoint(HINSTANCE hInst, DWORD, LPVOID) { hInstance = hInst; return 1; } int CALLBACK SetHWND(HWND hwndParent) { hWnd = hwndParent; InitCalled = 1; return 0; } int CALLBACK InstallHook(bool set) { if (!InitCalled) return 0; if (set) { mouse_hook = SetWindowsHookEx(WH_MOUSE, (FARPROC)MouseFunc, hInstance, 0); } else { UnhookWindowsHookEx(mouse_hook); mouse_hook = 0; } return 1; } LRESULT CALLBACK MouseFunc(int nCode, WPARAM wParam, LPARAM lParam) { if (nCode >= 0) { LPMOUSEHOOKSTRUCT param; param = (MOUSEHOOKSTRUCT*)lParam; mouse_data.type = wParam; mouse_data.X = param->pt.x; mouse_data.Y = param->pt.y; } return CallNextHookEx(mouse_hook, nCode, wParam, lParam); } int CALLBACK GetMouseData(DWORD &type, DWORD &xy) { if (!InitCalled) return 0; type = mouse_data.type; xy = (mouse_data.X << 16) | mouse_data.Y; return 1; } Не работает! Точнее, только в пределах окна. Что я только не делал, как только не описывал переменные - бесполезно. Что можно сделать?
у меня тоже бывает, что линкер не видит pragma comment в исходнике. В таком случае непосредственно в командной строке линкера указываю ключи (через батник).
1. Исходник в студию: весь проект - библиотеку и инжектор. 2. Такая ситуация возможна ещё и при инжекте процесса, вместо библиотеки, когда hInstance == NULL (или 0x40....) 3. Вообще в таких случаях выводят дебаг-сообщения и ловят их с помощью hххp://www.sysinternals.com/Utilities/DebugView.html Тогда уж точно видно в какой последовательности, с какими параметрами и что собственно вызывается. P.S. Где увереность что DllEntryPoint вызываеться?
PPS Где увереность что DllEntryPoint вызываеться именно один раз, а значит hInstance принимает правильное значение?
Интересно, почему Quantum не высказывается по данному вопросу? Помнится, он даже доказывал, что системные хуки это есть гуд! Я же отталкиваться буду от своего опыта и тестирования на разных компьютерах с установленным разным софтом: 1. системные хуки тяжело состыковываются с разными программами. 2. Xerx ты уверен, что правильно у тебя написан код? P. S. +1
Дался вам этот код. Нормальный он. Не в нем дело. Дело в pragma comment. Не работает эта фича. Сам сейчас проверил. А указал в батнике соответствующие ключи для линкера - и все заработало. В аттаче пример, показывающий координату х мыши независимо от того, над каким окном она находится. Код в dll такой: Код (Text): LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam){ PMOUSEHOOKSTRUCT pData = (PMOUSEHOOKSTRUCT) lParam; char buffer[32]; if (wParam == WM_MOUSEMOVE) { wsprintf (buffer, "mouse.x: %lu", pData->pt.x); SetWindowText (hWndLoader, buffer); } CallNextHookEx (hHook, nCode, wParam, lParam); return 0; } Ключи линкера (компилировал и линковал батником): link /subsystem:windows /SECTION:.bss,S /dll /def:mousehook.def mousehook.obj
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. Хе-хе читаем доки и учим синтаксис, блин и я тоже не исключение =)))
Проверял - один раз. cresta> А у меня твой пример не работает Точнее работает как и у меня. Кроме того, у меня другая проблема: у тебя ничего из основной программы, кроме HWND не используется, а мне нужно передавать структуры. У меня был РАБОЧИЙ пример, в котором САМА DLL выводила на контекст рабочего стола (HDC hDC = GetDC(0)) координаты. Пример РАБОТАЛ над любым окном, даже при свернутом приложении! А передача работает (и работала) только над моим окном. Demon666> А программе по-прежнему до лампочки Короче, выкладываю код. BCB 6.0. Извините уж, что на C++. P.S. Не надо предлагать переделать на ASM. Нельзя. Очень надеюсь на вашу помощь! Меня эта фигня уже достала :[
Xerx Пример, приведенный мною, на 100% рабочий. Разбирайся со своей виндой. Если ты сделаешь dll с разделяемыми секциями, то всё равно, что в коде dll написано. Работать будет над любым окном. В примере именно dll рисует текст на родительском окне. А передаваемые параметры (hwnd, структуры и т.д.) и их количество никакого отношения к работоспособности хука не имеют. Получилась у тебя dll с требуемой структурой или нет, можешь посмотреть например в PEExplorer, там выводится информация о секциях.
Ещё совет: возьми какую-нибудь тулзу, показывающую подгруженные в процессы dll-ки, запусти свой хук и посмотри, подгружается твоя dll куда-нибудь ещё, кроме твоего приложения, или нет. Например в процесс explorer.
Посмотрел твою dll - нет в ней секции bss. Есть: .text, .data, .idata, .edata, .tls, .rsrc, .reloc. Всё. #pragma comment(linker, "/SECTION:.bss,s") не сработала. Делайте секцию.