【问题标题】:How to disable mouse with Ruby Win32API如何使用 Ruby Win32API 禁用鼠标
【发布时间】:2023-03-14 11:54:01
【问题描述】:

我正在尝试做这样的事情,但只能使用鼠标:

require 'win32api'
BlockInput = Win32API.new("user32", "BlockInput", ["I"], "I")

BlockInput.call(1)
sleep 5
BlockInput.call(0)

我正在尝试使用SetWindowsHookEx,但它说可以工作但没有任何反应,我可以继续移动并单击鼠标,这是代码:

require 'win32/api'

# SetWindowsHookEx CONSTANTS
WH_MOUSE = 7
WH_MOUSE_LL = 14

# MouseProc or LowLevelMouseProc CONSTANTS
WM_MOUSEMOVE = 0x0200
WM_LBUTTONDOWN = 0x0201
WM_LBUTTONUP = 0x0202
WM_MOUSEWHEEL = 0x020A
WM_MOUSEHWHEEL = 0x020E
WM_RBUTTONDOWN = 0x0204
WM_RBUTTONUP = 0x0205

SetWindowsHookEx = Win32::API.new('SetWindowsHookEx', ['I', 'K', 'L', 'I'], 'L', 'user32')
CallNextHookEx = Win32::API.new('CallNextHookEx', ['I', 'I', 'L', 'P'], 'I', 'user32')
UnhookWindowsHookEx = Win32::API.new('UnhookWindowsHookEx', ['I'], 'I', 'user32')
GetCurrentThreadId = Win32::API.new('GetCurrentThreadId', ['V'], 'I', 'kernel32')

MouseProc = Win32::API::Callback.new('ILP', 'L') do |nCode, wParam, lParam|
    # https://docs.microsoft.com/en-us/previous-versions/windows/desktop/legacy/ms644988(v=vs.85)
    if nCode < 0 # If nCode is less than zero, the hook procedure must return the value returned by CallNextHookEx.
        return CallNextHookEx.call(0, nCode, wParam, lParam)
    elsif wParam == WM_MOUSEMOVE or wParam == WM_LBUTTONDOWN or wParam == WM_LBUTTONUP
        # If the hook procedure processed the message, it may return a nonzero value to prevent the system from
        # passing the message to the rest of the hook chain or the target window procedure.
        return 1
    else
        # If nCode is greater than or equal to zero, and the hook procedure did not process the message,
        # it is highly recommended that you call CallNextHookEx and return the value it returns;
        # otherwise, other applications that have installed WH_MOUSE_LL hooks will not receive hook
        # notifications and may behave incorrectly as a result.
        return CallNextHookEx.call(0, nCode, wParam, lParam)
    end
end

threadID = GetCurrentThreadId.call
hMod = nil
# If the function succeeds, the return value is the handle to the hook procedure.
p hhk = SetWindowsHookEx.call(WH_MOUSE, MouseProc, hMod, threadID) #=> 166134929 (Good)
# But nothing happens, i can continue moving and clicking my mouse.
sleep 5
p UnhookWindowsHookEx.call(hhk) #=> 1 (Good)

如果有人知道如何做或如何以其他方式做,我将不胜感激。

编辑:我在 Windows 7(32 位)上以管理员权限运行代码

我正在尝试在Strive Sun - MSFT 的回答之后使用 GetMessage(),但我在传递 MSG 指针时遇到了一些问题

GetMessage = Win32::API.new('GetMessage', ['P', 'L', 'L', 'L'], 'I', 'user32')
point = [0, 0].pack('LL')
hwnd = uint = wparam = lparam = dword = 0
buf = [hwnd, uint, wparam, lparam, dword, point, dword].pack('JIL2Sa8S')
# J > hwnd, I > uint, L2 > wparam lparam, S > dword, a8 > point
GetMessage.call(buf, nil, 0, 0) #=> Stuck, i need to use Manager Task to close it.

【问题讨论】:

    标签: ruby winapi


    【解决方案1】:

    您的代码缺少消息循环。

    请参考:MouseProc callback function

    应用程序定义或库定义的回调函数,用于 SetWindowsHookEx 函数。系统在任何时候调用这个函数 一个应用程序调用GetMessagePeekMessage 函数并在那里 是要处理的鼠标消息。

    为什么必须将 SetWindowsHookEx 与 Windows 消息队列一起使用?

    正如Hans 所说,低级钩子WH_KEYBOARD_LLWH_MOUSE_LL 与所有其他钩子不同。他们不 需要将DLL 注入目标进程。反而, Windows 在您自己的进程中直接调用您的钩子回调。到 使这项工作,需要一个消息循环。没有其他的 Windows 在主线程上进行回调的机制, 回调只能在您调用 Get/PeekMessage() 时发生,这样 Windows 尽在掌控。

    WH_KEYBOARD 这样的全局钩子是非常不同的。它需要一个 DLL 并且回调发生在处理 键盘消息。您需要某种进程间通信来 让您自己的程序意识到这一点。命名管道是常见的 选择。否则当然需要这个注入的过程 泵出一个消息循环。否则它不会收到键盘消息。

    喜欢低级的钩子,它们更容易上手。但是做泵 否则它将无法正常工作。如果您没有响应,请注意超时 够了,那么 Windows 会在不通知的情况下杀死你的钩子。

    如果需要全局使用WH_MOUSE,请注入DLL。 如果您不想使用 DLL,请使用WH_MOUSE_LL 而不是WH_MOUSE

    更多详情请参考:Use WH_MOUSE globally without DLL

    这是 C++ 代码并且有效。因为不熟悉 Ruby,所以无法提供修改后的 Ruby 代码。

    #include <Windows.h>
    #include <iostream>
    
    using namespace std;
    
    HHOOK mouseHook;
    
    LRESULT __stdcall MouseHookCallback(int nCode, WPARAM wParam, LPARAM lParam)
    {
        if (nCode >= 0)
        {
            switch (wParam)
            {
            case WM_MOUSEWHEEL :
                return 1;
            case WM_LBUTTONDOWN:
                return 1;
            case WM_LBUTTONUP:
                return 1;
            case WM_MOUSEMOVE:
                return 1;
            }
        }
        return CallNextHookEx(mouseHook, nCode, wParam, lParam);
    }
    
    void SetHook()
    {
        if (!(mouseHook = SetWindowsHookEx(WH_MOUSE_LL, MouseHookCallback, NULL, 0)))
        {
            cout << "Failed to install mouse hook!" << endl;
        }
    }
    
    void ReleaseHook()
    {
        UnhookWindowsHookEx(mouseHook);
    }
    
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
    {
        SetHook();
        MSG msg;
    
        while (GetMessage(&msg, NULL, 0, 0))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        return msg.wParam;
    }
    

    【讨论】:

    • 感谢您的回答,它非常有用,我正在尝试使用 GetMessage() 但我在传递 MSG 指针时遇到了一些问题,如果有人可以帮助我,我将不胜感激。我编辑了主要帖子以添加代码。
    • 也许知道味精的大小会有用,你能告诉我吗?
    • @Andrek 你的意思是sizeof(MSG)?它的值为 28。
    • 我真的不知道该怎么办,我正在向我的 GetMessage 传递一个 28 字节大小的字符串,但它一直卡住,非常感谢:)。
    猜你喜欢
    • 2023-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-05
    • 1970-01-01
    • 1970-01-01
    • 2011-07-02
    相关资源
    最近更新 更多