45829 (665173), страница 2
Текст из файла (страница 2)
заголовочный файл (myhook.h)
Здесь должны быть объявлены функции setMyHook и clearMyHook, но это требование разъяснено в моем очерке The Ultimate DLL Header File.
#define UWM_MOUSEHOOK_MSG \ _T("UMW_MOUSEHOOK-" \ "{B30856F0-D3DD-11d4-A00B-006067718D04}") |
исходный файл (myhook.cpp)
#include "stdafx.h" #include "myhook.h" #pragma data_seg(".JOE") HWND hWndServer = NULL; #pragma data_seg() #pragma comment("linker, /section:.JOE,rws") HINSTANCE hInstance; UINT HWM_MOUSEHOOK; HHOOK hook; // опережающее объявление static LRESULT CALLBACK msghook(int nCode, WPARAM wParam, LPARAM lParam); /**************************************************************** * DllMain * Вход: * HINSTANCE hInst: Дескриптор экземпляра DLL * DWORD Reason: причина вызова * LPVOID reserved: зарезервировано * Выход: BOOL * TRUE при успешном завершении * FALSE при наличии ошибок (не возвращается никогда) * Действие: * инициализация DLL. ****************************************************************/ BOOL DllMain(HINSTANCE hInst, DWORD Reason, LPVOID reserved) { switch(Reason) { /* причина */ //********************************************** // PROCESS_ATTACH //********************************************** case DLL_PROCESS_ATTACH: // Сохраним дескриптор экземпляра, т.к. он понадобится нам позднее для установки хука hInstance = hInst; // Данный код инициализирует сообщение уведомления хука UWM_MOUSEHOOK = RegisterWindowMessage(UWM_MOUSEHOOK_MSG); return TRUE; //********************************************** // PROCESS_DETACH //********************************************** case DLL_PROCESS_DETACH: // Если сервер не снял хук, снимем его, т.к. мы выгружаемся if(hWndServer != NULL) clearMyHook(hWndServer); return TRUE; } /* причина */ } /**************************************************************** * setMyHook * Вход: * HWND hWnd: Окно, чей хук предстоит поставить * Выход: BOOL * TRUE если хук успешно поставлен * FALSE если произошла ошибка, например, если хук * уже был установлен * Действие: * Устанавливает хук для указанного окна * Сначала устанавливает хук перехватывающий сообщения (WH_GETMESSAGE) * Если установка прошла успешно, hWnd устанавливается в качестве * окна сервера. ****************************************************************/ __declspec(dllexport) BOOL WINAPI setMyHook(HWND hWnd) { if(hWndServer != NULL) return FALSE; hook = SetWindowsHookEx( WH_GETMESSAGE, (HOOKPROC)msghook, hInstance, 0); if(hook != NULL) { /* удача */ hWndServer = hWnd; return TRUE; } /* удача */ return FALSE; } // SetMyHook /**************************************************************** * clearMyHook * Вход: * HWND hWnd: Окно, чей хук должен быть снят * Выход: BOOL * TRUE если хук успешно снят * FALSE если вы передали неверный параметр * Действие: * Снимает установленный хук. ****************************************************************/ __declspec(dllexport) BOOL clearMyHook(HWND hWnd) { if(hWnd != hWndServer) return FALSE; BOOL unhooked = UnhookWindowsHookEx(hook); if(unhooked) hWndServer = NULL; return unhooked; } /**************************************************************** * msghook * Вход: * int nCode: Значение кода * WPARAM wParam: параметр * LPARAM lParam: параметр * Выход: LRESULT * * Действие: * Если сообщение является сообщением о перемещении мыши, отправляет его * окну сервера с координатами мыши * Замечания: * Функция должна быть CALLBACK-функцией, или она не будет работать! ****************************************************************/ static LRESULT CALLBACK msghook(int nCode, WPARAM wParam, LPARAM lParam) { // If the value of nCode is < 0, just pass it on and return 0 // this is required by the specification of hook handlers // Если значение nCode < 0, просто передаем его дальше и возвращаем 0 // этого требует спецификация обработчиков хуков if(nCode < 0) { /* передаем дальше */ CallNextHookEx(hook, nCode, wParam, lParam); return 0; } /* передаем дальше */ // Прочитайте документацию, чтобы выяснить смысл параметров WPARAM и LPARAM // Для хука WH_MESSAGE, LPARAM определяется как указатель на структуру MSG, // таким образом следующий код делает эту структуру доступной LPMSG msg = (LPMSG)lParam; // Если это сообщение о перемещении мыши, либо в клиентской (client), либо // в не клиентской (non-client) области, мы хотим уведомить родителя о его // возникновении. Заметим, что вместо SendMessage используется PostMessage if(msg->message == WM_MOUSEMOVE || msg->message == WM_NCMOUSEMOVE) PostMessage(hWndServer, UWM_MOUSEMOVE, 0, 0); // Передаем сообщение следующему хуку return CallNextHookEx(hook, nCode, wParam, lParam); } // msghook |
Приложение сервера
В заголовочном файле добавьте следующее в секцию protected класса:
afx_msg LRESULT OnMyMouseMove(WPARAM,LPARAM); |
В фале приложения добавьте это где-нибудь в начале файла:
UINT UWM_MOUSEMOVE = ::RegisterWindowMessage(UWM_MOUSEMOVE_MSG); |
Добавьте следующее в MESSAGE_MAP вне специальных комментариев //{AFX_MSG:
ON_REGISTERED_MESSAGE(UWM_MOUSEMOVE, OnMyMouseMove) |
В файл приложения добавьте следующую функцию:
LRESULT CMyClass::OnMyMouseMove(WPARAM, LPARAM) { // ...тут что-то делаем return 0; } |
Я написал небольшой пример для демонстрации, но поскольку я утомился создавать функцию глобального хука в n+1 раз, я сделал ему отличный пользовательский интерфейс. Кот смотрит из окна и следит за мышью. Но будьте осторожны! Подойдите достаточно близко к коту, и он схватит мышь!
Вы можете скачать этот проект и собрать его. Ключевое значение имеет подпроект DLL; остальное - это использующая ее декоративная мишура.
В этом примере показаны несколько других приемов, включая различные приемы рисования, использование ClipCursor и SetCapture, выбор региона, обновление экрана, и т.д. Таким образом, помимо демонстрации использования перехватывающей функции, для начинающих программистов этот пример имеет ценность в различных аспектах программирования под Windows.
Список литературы
Для подготовки данной работы были использованы материалы с сайта http://www.rsdn.ru/