Модераторы: feodorv, GremlinProg, xvr, Fixin
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Global Mouse Hook, Работает только локально 
V
    Опции темы
FiMa1
Дата 16.6.2008, 18:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 408
Регистрация: 23.9.2006

Репутация: нет
Всего: 6



Добрейшего времени суток, друзья!

Я столкнулся с довольно распространенной, судя по результатам поиска, проблемой, но все же не смог решить ее.
Мне нужно глобально отлавливать активность мыши (click, double click). Я воспользовался этим примером - Системный хук, но смог добиться только локального перехвата кликов мыши, похоже созданная мною dll проецируется все же на пространство вызывающего процесса, т.е., по просту, моего приложения.

Кто-нибудь может подсказать как мне сделать хук глобальным? Может быть нужно еще что-то предпринять для компиляции с разделяемым сегментом данных (Shared)? Заранее спасибо за помощь.

Для удобства приведу код здесь:
 --- код mousehook.dll ---
Код

#include <windows.h>

#pragma option -zRSHARESEG // sets segment name for this source file to SHARESEG
#pragma option -zTSHARECLS // sets class name for segment to SHARECLS

// экспортируемые функции
extern "C" __declspec(dllexport) bool InstallMouseHook();
extern "C" __declspec(dllexport) bool RemoveMouseHook();

// объявление функции обратного вызова
LRESULT CALLBACK MouseProc(int code, WPARAM wParam, LPARAM lParam);

// глобальные переменные
HHOOK HookHandle;
HINSTANCE DllInstance;
bool IsInRect = false;

//----------------------------------------------------------------------
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void*) {
    DllInstance = hinst;
    return 1;
}
//----------------------------------------------------------------------
bool InstallMouseHook() {
    HookHandle = SetWindowsHookEx(WH_MOUSE,
        reinterpret_cast<HOOKPROC>(MouseProc), DllInstance, 0);
    if(HookHandle == NULL)
        return false;
    else
        return true;
}
//----------------------------------------------------------------------
bool RemoveMouseHook() {
    if(UnhookWindowsHookEx(HookHandle) == 0)
        return false;
    else
        return true;
}
//----------------------------------------------------------------------
LRESULT CALLBACK MouseProc(int code, WPARAM wParam, LPARAM lParam) {
    if(code < 0)
        return CallNextHookEx(HookHandle, code, wParam, lParam);

    HWND myapp = FindWindow("TForm1", "Form1");
    switch( LOWORD( wParam ) ) {
        case WM_LBUTTONDOWN :
            SendMessage(myapp, LBUTTONDOWN, 0, 0);
            break;
            ...
    }

    // вызываем следующий хук в цепи
    return CallNextHookEx(HookHandle, code, wParam, lParam);
}

--- код исполняемого приложения. mousehook.h ---
Код

typedef bool (__stdcall *MOUSEHOOKFCT)();
HINSTANCE DllHandle;

--- код исполняемого приложения. mousehook.cpp ---
Код

#include <vcl.h>
#include "mousehook.h"
//----------------------------------------------------------------------
TForm1 *Form1;
//----------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner) { }
//----------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender) {
    DllHandle = LoadLibrary("mousehook.dll");
    MOUSEHOOKFCT InstHook = reinterpret_cast<MOUSEHOOKFCT>
        (GetProcAddress(DllHandle, "_InstallMouseHook"));
    if(!InstHook())
        Label1->Caption = "Unable to set mouse hook!";
}
//----------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender) {
    MOUSEHOOKFCT RemHook = reinterpret_cast<MOUSEHOOKFCT>
        (GetProcAddress(DllHandle, "_RemoveMouseHook"));
    if( ! RemHook() )
        Label1->Caption = "Unable to remove mouse hook";

    FreeLibrary(DllHandle);
}
//----------------------------------------------------------------------
void __fastcall TForm1::ApplicationEvents1Message(tagMSG &Msg,
        bool &Handled) {
    switch( Msg.message ) {
        case WM_LBUTTONDOWN :
            Form1->Caption = "LEFT MOUSE BUTTON PRESSED!";
            break;
            ...
    }
}

PM   Вверх
jonie
Дата 16.6.2008, 19:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 5613
Регистрация: 21.8.2005
Где: Владимир

Репутация: 7
Всего: 118



1) SendMessage вашему окну плозая идея. используйте PostMessage.
2) if (DLL_PROCESS_ATTACH ==reason ) DllInstance = hinst; добавьте в DllMain
3) на это я думаю тоже можно забить :
Код

    if(code < 0)
        return CallNextHookEx(HookHandle, code, wParam, lParam);

4) незабывайте проверять на ошибки.


--------------------
Что-то не поняли? -> Напейтесь до зеленых человечков... эта сверхцивилизация Вам поможет...
PM MAIL Jabber   Вверх
FiMa1
Дата 16.6.2008, 21:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 408
Регистрация: 23.9.2006

Репутация: нет
Всего: 6



Цитата

1) SendMessage вашему окну плохая идея. используйте PostMessage.

jonie, спасибо за справедливое замечание. Я так и планировал в конечном счете заменить SendMessage на PostMessage. Для последователей цитата из Хуки и DLL:
Цитата

Существует множество решений для организации взаимодействия вашей DLL и ее управляющего сервера. Одно из решений заключается в использовании ::PostMessage или ::SendMessage (заметим, что здесь я ссылаюсь на вызовы чистого API, а не вызовы MFC!). Там, где возможно использовать вызов ::PostMessage, лучше используйте его, а не ::SendMessage, т.к. иначе вы можете получить опасные тупиковые ситуации. Если Ваш Процесс в итоге останавливается, все остальные процессы в системе остановятся, т.к. все заблокированы на вызове ::SendMessage, который никогда не возвратится, и вы просто вывели всю систему из строя с возможностью серьезной потери данных в важных для пользователя приложениях. Это Совершенно Однозначно Не Хорошая Ситуация.

Цитата

3) на это я думаю тоже можно забить:
Код

    if(code < 0)
        return CallNextHookEx(HookHandle, code, wParam, lParam);


Ммм... даже не знаю, позаимствовал отсюда - Хуки и DLL:
Цитата

Код

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)


И вот еще от WinAPI: Hook System:
Цитата

code - определяет когда должна процедура перехвата обработать сообщение. Если code равен HC_ACTION, хук процедура должна обработать сообщение. Если code меньше нуля, хук процедура должна передать сообщение к функции CallNextHookEx без дальнейшей обработки и должна возвратить значение, возвращенное функцией CallNextHookEx. 

Я попробовал собрать dll в VC2005 с помещением хэндла процесса в разделяемый сегмент данных, но в этом случае dll не загружается корректно в исполняемое приложение - обращение по нулевому адресу памяти...
--- код mousehook.dll (VC2005) ---
Код

// mousehook.cpp : Defines the entry point for the DLL application.

#include "stdafx.h"

#pragma data_seg(".hdata") // секция в памяти общая для всех процессов
HINSTANCE h = NULL; // эта переменная может изменяться любым процессом, поэтому здесь не д.б. ничего лишнего
#pragma data_seg() // конец секции
#pragma comment(linker, "/section:.hdata,rws") // даем права этой секции

// объявление функции обратного вызова
LRESULT CALLBACK MouseProc(int code, WPARAM wParam, LPARAM lParam); 

// глобальные переменные
HHOOK HookHandle; 
HINSTANCE DllInstance; 

#ifdef _MANAGED
#pragma managed(push, off)
#endif
//----------------------------------------------------------------------
BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    // вызывается каждый раз когда новый процесс грузит DLL в свою память
    if( ul_reason_for_call == DLL_PROCESS_ATTACH ) {
        if( ! h ) {
            // сохpаняем handle пpоцесса DLL в глобальную пеpеменную DllInstance
            // для использования внутpи функции InstallMouseHook.
            // Так как входная функция вызывается пpежде, чем будут вызваны
            // дpугие функции в DLL, InstallMouseHook будет всегда веpен.
            // Мы помещаем hInstance в секцию .data (см. директивы pragma выше),
            // поэтому это значение будет pазличаться от пpоцесса к пpоцессу.
            DllInstance = hModule;
        }
    }

    return TRUE;
}
//----------------------------------------------------------------------
extern "C" __declspec (dllexport) BOOL InstallMouseHook(void) { 
   HookHandle = SetWindowsHookEx(WH_MOUSE, 
   reinterpret_cast<HOOKPROC>(MouseProc), DllInstance, 0); 
   if(HookHandle == NULL) 
     return false;
   else 
     return true; 
 } 
//----------------------------------------------------------------------
extern "C" __declspec (dllexport) BOOL RemoveMouseHook(void) { 
   if(UnhookWindowsHookEx(HookHandle) == 0) 
     return false; 
   else 
     return true; 
 } 
//----------------------------------------------------------------------
LRESULT CALLBACK MouseProc(int code, WPARAM wParam, LPARAM lParam) { 
    if(code < 0) 
        return CallNextHookEx(HookHandle, code, wParam, lParam); 

    HWND h = FindWindow(L"TForm1", L"Form1");
    switch( LOWORD ( wParam ) ) {
        case WM_LBUTTONDOWN :
            PostMessage(h, WM_LBUTTONDOWN, 0, 0);
            break;
        case WM_LBUTTONUP :
            PostMessage(h, WM_LBUTTONUP, 0, 0);
            break;
        case WM_RBUTTONDOWN :
            PostMessage(h, WM_RBUTTONDOWN, 0, 0);
            break;
        case WM_RBUTTONUP :
            PostMessage(h, WM_RBUTTONUP, 0, 0);
            break;
    }
   
    // вызываем следующий хук в цепи 
    return CallNextHookEx(HookHandle, code, wParam, lParam); 
 }
//----------------------------------------------------------------------

#ifdef _MANAGED
#pragma managed(pop)
#endif

PM   Вверх
jonie
Дата 17.6.2008, 00:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 5613
Регистрация: 21.8.2005
Где: Владимир

Репутация: 7
Всего: 118



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


--------------------
Что-то не поняли? -> Напейтесь до зеленых человечков... эта сверхцивилизация Вам поможет...
PM MAIL Jabber   Вверх
FiMa1
Дата 18.6.2008, 23:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 408
Регистрация: 23.9.2006

Репутация: нет
Всего: 6



jonie, спасибо еще раз помощь!
Цитата

кстати, есть низкоуровневые хуки, они не требуют длл-ки...

На том и порешим. Ниже код рабочего низкоуровневого хука для мыши. Вот только по закрытии формы, все жестко подвисает, но это уже совсем другая история  smile .
Код

//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
#include <windows.h>
#include <stdio.h>
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
HHOOK MouseHook;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
}
//---------------------------------------------------------------------------
LRESULT CALLBACK LowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam) {
    if (nCode == HC_ACTION) {
        switch (wParam) {
            case WM_LBUTTONDOWN :
                Form1->Label1->Caption = "LEFT BUTTON PRESSED";
                break;
            case WM_RBUTTONDOWN :
                Form1->Label1->Caption = "RIGHT BUTTON PRESSED";
                break;
        }
    }
    return CallNextHookEx(NULL, nCode, wParam, lParam);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::btnStopHookClick(TObject *Sender) {
    UnhookWindowsHookEx(MouseHook);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender) {
    MouseHook = SetWindowsHookEx(WH_MOUSE_LL,
        reinterpret_cast<HOOKPROC>(LowLevelMouseProc), HInstance, NULL);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action) {
    UnhookWindowsHookEx(MouseHook);
}


Это сообщение отредактировал(а) FiMa1 - 18.6.2008, 23:14
PM   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Системное программирование и WinAPI"
Fixin
GremlinProg
xvr
feodorv
  • Большое количество информации и примеров с использованием функций WinAPI можно найти в MSDN
  • Описание сообщений, уведомлений и примеров с использованием компонент WinAPI (BUTTON, EDIT, STATIC, и т.п.), можно найти в MSDN Control Library
  • Непосредственно, перед созданием новой темы, проверьте заголовок и удостоверьтесь, что он отражает суть обсуждения.
  • После заполнения поля "Название темы", обратите внимание на наличие и содержание панели "А здесь смотрели?", возможно Ваш вопрос уже был решен.
  • Приводите часть кода, в которой предположительно находится проблема или ошибка.
  • Если указываете код, пользуйтесь тегами [code][/code], или их кнопочными аналогами.
  • Если вопрос решен, воспользуйтесь соответствующей ссылкой, расположенной напротив названия темы.
  • Один топик - один вопрос!
  • Перед тем как создать тему - прочтите это .

На данный раздел распространяются Правила форума и Правила раздела С++:Общие вопросы .


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Chipset, Step, Fixin, GremlinProg, xvr. feodorv.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Системное программирование и WinAPI | Следующая тема »


 




[ Время генерации скрипта: 0.0478 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.