【问题标题】:Mouse and Keyboard system Global Hook鼠标和键盘系统 Global Hook
【发布时间】:2014-05-19 14:05:35
【问题描述】:

我想使用 DLL 在 C++ 中为键盘和鼠标设置全局系统挂钩。我的程序正在运行,但不完全符合我的需要。例如,程序不会在其他窗口或弹出菜单或模式对话框上挂钩鼠标事件。我想在其他窗口、程序等的任何地方挂钩鼠标和键盘事件,所有系统鼠标和键盘事件。我的代码有什么问题要更改什么才能使其按需要工作,我找不到自己的问题,我正在按照文档中的说明进行操作,我需要帮助。

我正在使用 VCL 在 C++ Builder 中编码

DLL:

#include <vcl.h>
#include <windows.h>
#include "main.h"
#pragma hdrstop
#pragma argsused

typedef struct _HOOKSTRUCT
{
    int nType;
    HOOKPROC hkprc;
    HHOOK hhook;
    bool bInstalled;
} HOOKSTRUCT;

static HOOKSTRUCT hook[2];
HINSTANCE hDLL;
int nThreadCode;
bool bInit;
TForm1 *form;
extern "C" __stdcall __declspec(dllexport) LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam);
extern "C" __stdcall __declspec(dllexport) LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam);
//---------------------------------------------------------------------------
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{
        hDLL = hinst;
        bInit = false;
        return 1;
}
//---------------------------------------------------------------------------
extern "C" __stdcall __declspec(dllexport) void Init()
{
        hook[0].nType = WH_KEYBOARD;
        hook[0].hkprc = (HOOKPROC)KeyboardProc;
        hook[0].bInstalled = false;
        hook[1].nType = WH_MOUSE;
        hook[1].hkprc = (HOOKPROC)MouseProc;
        hook[1].bInstalled = false;
        bInit = true;
}
//---------------------------------------------------------------------------
extern "C" __stdcall __declspec(dllexport) bool SetHook(int nHook)
{
        if(!bInit)
        {
                Init();
        }
        hook[nHook].hhook = NULL;
        hook[nHook].hhook = SetWindowsHookEx(hook[nHook].nType,
                (HOOKPROC)hook[nHook].hkprc, hDLL, 0);
        if(hook[nHook].hhook != NULL)
        {
                MessageBox(NULL, "Setup hook successful", "Information", MB_OK);
        }
        return true;
}
//---------------------------------------------------------------------------
extern "C" __stdcall __declspec(dllexport) void UnsetHook(int nHook)
{
        UnhookWindowsHookEx(hook[nHook].hhook);
}
//---------------------------------------------------------------------------
extern "C" __stdcall __declspec(dllexport) LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
        if(((DWORD)lParam&0x40000000) && (HC_ACTION==nCode))
        {
                if(form != NULL)
                {
                        form->Memo1->Lines->Add("Key Pressed");
                }
        }
        return CallNextHookEx(hook[0].hhook, nCode, wParam, lParam);
}
//---------------------------------------------------------------------------
extern "C" __stdcall __declspec(dllexport) LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{
        char str[128];
        PMOUSEHOOKSTRUCT Info = (PMOUSEHOOKSTRUCT)lParam;
        wsprintf(str, "The mouse message at X: %d,Y: %d", Info->pt.x, Info->pt.y);
        form->Memo2->Lines->Add(str);
        return CallNextHookEx(hook[1].hhook, nCode, wParam, lParam);
}
//---------------------------------------------------------------------------
extern "C" __stdcall __declspec(dllexport) void SetControl(TForm1 *Object, int nApp)
{
        form =  Object;
        nThreadCode = nApp;
}

计划:

#include <vcl.h>
#pragma hdrstop

#include "main.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
HINSTANCE hInst;
typedef bool (*install)(int);
typedef void (*uninstall)(int);
typedef void (*passself)(TForm1 *, int);
install InstallHook;
uninstall UninstallHook;
passself PassThis;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
        N2->Enabled = true;
        N3->Enabled = true;
        N4->Enabled = false;
        N5->Enabled = false;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
        Memo1->Clear();
        Memo2->Clear();
        hInst = LoadLibrary("ch49dll.dll");
        if(hInst == NULL)
        {
                ShowMessage("Load DLL error " + AnsiString(GetLastError()));
                return;
        }
        InstallHook = (install)GetProcAddress(hInst, "SetHook");
        if(InstallHook == NULL)
        {
                ShowMessage("Get SetHook ProcAddress Error");
                return;
        }
        UninstallHook = (uninstall)GetProcAddress(hInst, "UnsetHook");
        if(UninstallHook == NULL)
        {
                ShowMessage("Get UnsetHook ProcAddress Error");
                return;
        }
        PassThis = (passself)GetProcAddress(hInst, "SetControl");
        if(PassThis == NULL)
        {
                ShowMessage("Get SetControl ProcAddress Error");
                return;
        }
        PassThis(this, 0);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormDestroy(TObject *Sender)
{
        FreeLibrary(hInst);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::N2Click(TObject *Sender)
{
        InstallHook(0);
        N2->Enabled = false;
        N4->Enabled = true;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::N3Click(TObject *Sender)
{
        InstallHook(1);
        N3->Enabled = false;
        N5->Enabled = true;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::N4Click(TObject *Sender)
{
        UninstallHook(0);
        N4->Enabled = false;
        N2->Enabled = true;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::N5Click(TObject *Sender)
{
        UninstallHook(1);
        N5->Enabled = false;
        N3->Enabled = true;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::N7Click(TObject *Sender)
{
        Close();
}
//---------------------------------------------------------------------------

程序头:

#ifndef mainH
#define mainH
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <Menus.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:    // IDE-managed Components
        TMemo *Memo1;
        TMemo *Memo2;
        TMainMenu *MainMenu1;
        TMenuItem *N1;
        TMenuItem *N2;
        TMenuItem *N3;
        TMenuItem *N4;
        TMenuItem *N5;
        TLabel *Label1;
        TLabel *Label2;
        TMenuItem *N6;
        TMenuItem *N7;
        void __fastcall FormCreate(TObject *Sender);
        void __fastcall FormDestroy(TObject *Sender);
        void __fastcall N2Click(TObject *Sender);
        void __fastcall N3Click(TObject *Sender);
        void __fastcall N4Click(TObject *Sender);
        void __fastcall N5Click(TObject *Sender);
        void __fastcall N7Click(TObject *Sender);
private:    // User declarations
public:     // User declarations
        __fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif

所以程序可以工作并且可以挂钩外部事件,但是对于某些对话框窗口,我的程序不会挂钩鼠标事件。例如,当我右键单击任务栏通知区域中的图标时,将显示一个弹出窗口,如果我在弹出窗口区域中输入鼠标光标,那么我的程序将不会记录这些鼠标移动事件。其他情况是当我单击其他程序中的关于程序菜单或关于菜单时,将显示一个窗口,如果我将光标移动到该窗口区域内,那么我的程序将不会挂钩鼠标和键盘事件,为什么?如何让它挂钩任何窗口的任何地方

【问题讨论】:

    标签: c++ winapi c++builder


    【解决方案1】:

    两个非常明显的问题:

    1. DLL 将被注入所有其他进程。您不能指望从已挂接到另一个进程的 DLL 中调用 VCL 方法。您必须找到另一种报告诊断的方法。
    2. 因为您使用的是全局挂钩,所以您需要处理 32/64 位问题。您需要生成 32 位和 64 位版本的 DLL,并从 32 位和 64 位进程中为它们设置挂钩。

    如果您可以使用低级挂钩,则应考虑采用该选项。优点是没有低级钩子的注入。您根本不需要创建 DLL。

    【讨论】:

    • 我会考虑你的通知,我想使用低级别的钩子,但是你能不能给我一些指导,用一些代码示例来了解它,如果我能在没有事件的情况下钩子就好了动态链接库。我想低级是汇编程序,但这对我来说是新的,如果可能的话给我一个小例子
    • 低级不是汇编程序。您按照当前的方式进行操作,但使用 WH_KEYBOARD_LLWH_MOUSE_LL 挂钩。仔细阅读文档,你应该没问题。确保在调用SetWindowsHookEx 的线程中发送消息。在 VCL 主线程中调用它,您可以直接使用 VCL 对象作为额外的奖励!我认为我不需要写一个例子,那里已经有数百万了。您清楚地知道如何根据 MSDN 文档编写代码。你会没事的!
    • 如果这意味着 WH_MOUSE_LL 或 WH_KEYBOARD_LL 然后我试了一下,我得到了与 WH_KEYBOARD 或 WH_MOUSE 相同的结果
    • 是的,它正在工作,原始代码也在工作,但可能我没有正确解释。我的程序可以挂钩外部事件,但是对于某些窗口,当光标在这些窗口上时,我的程序无法挂钩事件,我是否需要制作一个短视频来展示这个问题,我不知道如何更好地解释它
    • 例如,当我右键单击任务栏通知区域中的图标时,将显示一个弹出窗口,如果我在弹出窗口区域中输入鼠标光标,那么我的程序将不会记录那些鼠标移动事件
    【解决方案2】:

    一些 cmets,希望能解决您的问题:使用“低级”钩子(WH_MOUSE_LL、WH_KEYBOARD_LL),因为它们保证是全局的。在我看来,您的应用程序只有一个“本地”(线程)钩子。

    当与钩子一起使用时,我对 CBuilder 创建的 DLL 有不好的体验。 ...即:与您描述的完全相同的问题。我建议使用 Microsoft 编译器重新编译您的 DLL(并提供一个 .DEF 文件以供使用)。

    您可能需要将 DLL 放置在标识为系统目录的位置。

    您不需要将 SetHook 放在 DLL 中,这也可以从“主”应用程序中完成。

    【讨论】:

    • WH_MOUSE_LL 或 WH_KEYBOARD_LL 给我与 WH_KEYBOARD 或 WH_MOUSE 相同的东西。在 windows XP 上它可以工作,但在 windows 7 上却不行
    • @ManY 在 Win 7 上,您只能挂钩来自具有相同或更低权限的程序的消息。 IE。如果您自己的程序以标准权限运行,它将永远不会看到任何针对进程的鼠标或键盘消息,例如管理员权限。
    • @iamjoosy 是的,你说得对,这是我的问题,发表你的评论作为答案,我会将其标记为已接受
    • @iamjoosy 你知道如何让 C++ Builder 应用程序以完全管理员权限运行或至少请求他们
    【解决方案3】:

    在 Win 7 上,您只能挂钩来自具有相同或更低权限的程序的消息。 IE。如果您自己的程序以标准权限运行,它将永远不会看到任何针对进程的鼠标或键盘消息,例如管理员权限。 – 艾姆乔西

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-02-13
      • 1970-01-01
      • 1970-01-01
      • 2011-12-10
      • 2014-09-18
      相关资源
      最近更新 更多