【问题标题】:WinAPI - Hook Mouse Move not workingWinAPI - 挂钩鼠标移动不起作用
【发布时间】:2014-06-07 17:52:31
【问题描述】:

我正在尝试挂钩所有鼠标移动事件,但我从未收到任何消息。这是完整的代码:

#include <Windows.h>
#include <windowsx.h>
#include <iostream>

LRESULT CALLBACK MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    if (wParam != WM_MOUSEMOVE)
    {
        return CallNextHookEx(NULL, nCode, wParam, lParam);
    }

    std::cout << GET_X_LPARAM(lParam) << std::endl;
    return 0;
}

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;

    case WM_MOUSEMOVE:
        int xPos = GET_X_LPARAM(lParam);
        int yPos = GET_Y_LPARAM(lParam);
        std::cout << xPos << " - " << yPos << std::endl;
        return 0;
    }

    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR lpCmdLine, INT nCmdShow)
{
    AllocConsole();

    HHOOK mouseHook = SetWindowsHookEx(WH_MOUSE_LL, MouseHookProc, hInstance, NULL);

    MSG msg;

    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return 0;
}

【问题讨论】:

  • 对于全局挂钩,您的挂钩过程必须位于可加载模块 (DLL) 中。您的MouseHookProc始终致电CallNextHookEx,除非您希望完全过滤掉该消息。在后一种情况下,您的钩子过程应该返回一个非零值。不满足要求会破坏系统中的其他钩子。请务必仔细阅读LowLevelMouseProc。我刚才所说的一切都在那里拼写出来。
  • @IInspectable 询问者正在使用低级挂钩
  • @David 好点。对于低级挂钩,挂钩过程不需要驻留在 DLL 中。其余要求仍然有效,MouseHookProc 需要修复。

标签: winapi visual-c++


【解决方案1】:
   std::cout << GET_X_LPARAM(lParam) << std::endl;

钩子工作正常,当您构建没有控制台的程序时,您只是高估了 CRT 正确初始化标准输出的能力。挂钩回调代码通常不正确。你会像这样点亮它:

LRESULT CALLBACK MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam) {
    if (nCode >= 0 && wParam == WM_MOUSEMOVE) {
        MSLLHOOKSTRUCT* mh = (MSLLHOOKSTRUCT*)lParam;
        std::stringstream ss;
        ss << mh->pt.x << ", " << mh->pt.y << std::endl;
        OutputDebugStringA(ss.str().c_str());
    }
    return CallNextHookEx(NULL, nCode, wParam, lParam);
}

您会在调试器中看到文本,对于 Visual Studio,它将显示在“输出”窗口中。

另一种方法是简单地构建一个控制台模式应用程序,以便您立即获得控制台并且标准输出将工作。将 WinMain() 更改为 main()。

或者通过重新打开标准输出,可能是你喜欢的。像这样:

  AllocConsole();
  freopen("CONOUT$", "wb", stdout);

【讨论】:

    【解决方案2】:

    如果您尝试捕获所有进程的鼠标事件(最后一个参数为 NULL),则需要在 DLL 中使用系统范围的挂钩。

    我的网站上有一个例子here

    【讨论】:

    • 不正确,低级鼠标钩子从不使用 DLL。
    • 啊,没发现是低级的。
    【解决方案3】:

    是的,就像@HansPassant 提到的std::cout 不是显示内容的有效方式,除非您每次更新控制台时都刷新它。

    我重新制作了整个程序,因为我也需要,使用 code:blocks 默认 win32 模板并替换 MouseHookProc :)

    #include <windows.h>
    #include <windowsx.h>
    #include <iostream>
    #include <sstream>
    
    LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
    LRESULT CALLBACK MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam);
    
    char szClassName[ ] = "CodeBlocksWindowsApp";
    HWND Label1, Label2; //adding 2 static controls to display things
    
    int WINAPI WinMain (HINSTANCE hThisInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR lpszArgument,
                     int nCmdShow)
    {
    // adding hook
    HHOOK mouseHook = SetWindowsHookEx(WH_MOUSE_LL, MouseHookProc, hThisInstance, NULL);
    
    HWND hwnd;
    MSG messages;
    WNDCLASSEX wincl;
    wincl.hInstance = hThisInstance;
    wincl.lpszClassName = szClassName;
    wincl.lpfnWndProc = WindowProcedure;
    wincl.style = CS_DBLCLKS;
    wincl.cbSize = sizeof (WNDCLASSEX);
    wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
    wincl.lpszMenuName = NULL;
    wincl.cbClsExtra = 0;
    wincl.cbWndExtra = 0;
    wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;
    
    if (!RegisterClassEx (&wincl))
        return 0;
    
    hwnd = CreateWindowEx (0, szClassName, "Code::Blocks Template Windows App", 
           WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 544, 375, 
           HWND_DESKTOP, NULL, hThisInstance, NULL);
    
    ShowWindow (hwnd, nCmdShow);
    
    while (GetMessage (&messages, NULL, 0, 0))
    {
        TranslateMessage(&messages);
        DispatchMessage(&messages);
    }
    
    return messages.wParam;
    }
    
    
    LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
    switch (message)
    {
        case WM_CREATE:
            //creating those 2 static controls
            Label1 = CreateWindow("STATIC", "Label1", WS_VISIBLE | WS_CHILD, 10,10,60,18, hwnd, NULL, NULL, NULL);
            Label2 = CreateWindow("STATIC", "Label2", WS_VISIBLE | WS_CHILD, 70,10,60,18, hwnd, NULL, NULL, NULL);
        break;
        //adding mousemove event
        case WM_MOUSEMOVE: {
            int xPos = GET_X_LPARAM(lParam);
            int yPos = GET_Y_LPARAM(lParam);
            //std::cout << xPos << " - " << yPos << std::endl;
            TCHAR Coords[20];
            wsprintf(Coords, "%i, %i", xPos, yPos);
            SetWindowText(Label1, Coords);
        return 0; }
    
        case WM_DESTROY:
            PostQuitMessage (0);
            break;
        default:
            return DefWindowProc (hwnd, message, wParam, lParam);
    }
    return 0;
    }
    
    //replacing MouseHookProc
    LRESULT CALLBACK MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam) {
        if (nCode >= 0 && wParam == WM_MOUSEMOVE) {
            MSLLHOOKSTRUCT* mh = (MSLLHOOKSTRUCT*)lParam;
            std::stringstream ss;
            ss << mh->pt.x << ", " << mh->pt.y << std::endl;
            //OutputDebugStringA(ss.str().c_str());
            SetWindowText(Label2, ss.str().c_str());
        }
        return CallNextHookEx(NULL, nCode, wParam, lParam);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多