【问题标题】:Unable to intercept the right-click event无法拦截右键事件
【发布时间】:2015-08-07 12:16:46
【问题描述】:

我需要在 Windows 中拦截具有特定标题的窗口的右键单击事件,因此我决定使用带有 WH_MOUSE 参数的 SetWindowsHookExA 函数,如下所示:

由此启动的应用程序

#include <Windows.h>

#include <cstdlib>
#include <iostream>

int main()
{
  HMODULE hook_dll_handle = LoadLibraryA("hook_dll.dll");
  if (hook_dll_handle == NULL)
  {
    std::cerr << "Unable to load \"hook_dll.dll\". Error code: " << GetLastError() << std::endl;
    return EXIT_FAILURE;
  }

  auto mouse_hook = (HOOKPROC)GetProcAddress(hook_dll_handle, "mouse_hook");
  if (mouse_hook == NULL)
  {
    std::cerr << "Unable to get \"mouse_hook\" function's address. Error code: " << GetLastError() << std::endl;
    return EXIT_FAILURE;
  }

  HHOOK hook = SetWindowsHookExA(WH_MOUSE, mouse_hook, hook_dll_handle, 0);
  if (hook == NULL)
  {
    std::cerr << "Unable to set hook. Error code: " << GetLastError() << std::endl;
    return EXIT_FAILURE;
  }

  std::cin.get();

  if (UnhookWindowsHookEx(hook) == 0)
  {
    std::cerr << "Unable to unhook mouse_hook. Error code: " << GetLastError() << std::endl;
    return EXIT_FAILURE;
  }
}

带有钩子函数的DLL

#include "stdafx.h"

BOOL APIENTRY DllMain(
  HMODULE hModule,
  DWORD  ul_reason_for_call,
  LPVOID lpReserved
)
{
  switch (ul_reason_for_call)
  {
  case DLL_PROCESS_ATTACH:
  case DLL_PROCESS_DETACH:
  case DLL_THREAD_ATTACH:
  case DLL_THREAD_DETACH:
    break;
  }
  return TRUE;
}

extern "C"
{
  __declspec(dllexport) LRESULT CALLBACK mouse_hook(int code, WPARAM wParam, LPARAM lParam)
  {
    return CallNextHookEx(NULL, code, wParam, lParam);
  }
}

不幸的是,它没有按预期工作。它会挂起整个 explorer.exe 或在不同平台上执行其他类型的操作。

我做错了什么?我该如何解决?

提前致谢。

【问题讨论】:

    标签: c++ windows winapi


    【解决方案1】:

    您现在需要一个消息循环,其中有std::cin.get()

    MouseProc documentation中的备注:

    这个钩子可以在安装它的线程的上下文中被调用。通过向安装钩子的线程发送消息来进行调用。 因此,安装钩子的线程必须有消息循环。

    哦,如果您不想使用 dll,可以使用 WH_MOUSE_LL,它在您自己的应用程序的上下文中调用。

    见:https://stackoverflow.com/a/872720/4928207

    【讨论】:

    • 感谢您的回答,但您说的最后一件事对我来说是新事物。根据 MSDN,“如果 dwThreadId 参数为零或指定由不同进程创建的线程的标识符,则 lpfn 参数必须指向 DLL 中的挂钩过程”。我认为它说“如果您的应用程序需要拦截其他应用程序的消息,那么您需要使用 DLL”。我错了吗?
    • 不是所有类型的钩子,看remarks from f.e. WH_MOUSE_LL
    • 但是是的,遗憾的是,关于 hooks 的信息有点分散,一些信息在通用页面上,一些信息在 HookProc 页面上。
    • 另外,here 我发布了一个功能齐全的控制台应用程序,它挂钩 WH_KEYBOARD_LL,将其更改为 WH_MOUSE_LL 应该很简单。
    • @MarkJansen:更好的是,由于 OP 想要挂钩特定的窗口,请使用 GetWindowThreadProcessId() 获取窗口所属的线程 ID。那么这个钩子将只针对那个线程,而不是针对系统上的所有线程。
    猜你喜欢
    • 2015-11-05
    • 2011-10-25
    • 1970-01-01
    • 1970-01-01
    • 2021-06-27
    • 2019-06-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多