Смекни!
smekni.com
#pragma data_seg(".JOE")HANDLE hWnd = NULL;#pragma dta_seg()#pragma comment(linker, "/section:.JOE,rws")

Любые переменные, объявленные вами в области действия #pragma, определяющей сегмент данных, будут размещены в этом сегменте данных, при условии, что они инициализированы. Если вы не укажете инициализатор, переменные будут размещены в сегменте данных по умолчанию, и #pragma не имеет силы.

ПРИМЕЧАНИЕ В тот же момент оказывается, что эта особенность не позволяет использовать массивы объектов C++ в разделяемом сегменте данных, т.к. в C++ вы не можете инициализировать массив пользовательских объектов (предполагается, что этим должны заниматься их конструкторы по умолчанию). Это пересечение формальных требований C++ и расширений Microsoft, требующих наличия инициализаторов, оказывается фундаментальным ограничением.

Директива #pragma comment вызывает добавление указанного ключа к командной строке компоновщика на этапе связывания. Вы могли бы использовать Project | Settings в VC++ и изменить командную строку компоновщика, однако трудно помнить про необходимость такого действия, когда вы перемещаете код с места на место (и обычная ошибка - забыть выбрать All Configurations при изменении установок и, таким образом, успешно отлаживать, но получить сбой в конфигурации Release). Итак, я обнаружил, что лучше всего помещать команду непосредственно в исходном файле. Заметим, что используемый текст должен соответствовать синтаксису командного ключа компоновщика. Это означает, что вы не должны включать в указанный текст пробелы, иначе компоновщик не обработает его должным образом.

Обычно вы предоставляете некоторый механизм для установки дескриптора окна. Например,

void SetWindow(HWND w) { hWnd = w;}

хотя эта операция, как я покажу далее, часто совмещена с собственно установкой хука.

Пример: Мышиный Хук

заголовочный файл (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 используется PostMessageif(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.