Java FFI调用SetWindowsHookEx获取窗口消息时出现Access Denied错误
问题根因
你调用SetWindowsHookExA失败的核心原因不是权限不足,而是WH_CALLWNDPROCRET类型的线程钩子要求回调函数必须位于可被目标进程加载的Win32 DLL模块中。你传入的pointerToHookProcUpcall是Java进程地址空间内的函数指针,目标进程(如Notepad++)无法访问该内存地址,因此触发访问拒绝报错,和你是否以管理员权限运行、是否关闭UAC无关。
可行解决方案
方案1:无需注入的叠加层实现(推荐,适配Java FFI场景)
如果你的核心需求仅为添加窗口叠加层,完全不需要使用注入式钩子,可采用轻量无侵入方案:
- 调用
EnumWindows、GetWindowThreadProcessId、GetModuleBaseName等API,按EXE名称、窗口标题筛选目标窗口,拿到对应的窗口句柄 - 创建带有
WS_EX_LAYERED、WS_EX_TRANSPARENT、WS_EX_NOACTIVATE扩展属性的顶层窗口作为叠加层,通过GetWindowRect定时获取目标窗口的位置、大小,同步调整叠加层窗口的坐标即可 - 如需实现目标窗口移动、缩放、隐藏时的即时同步,可调用
SetWinEventHook监听EVENT_OBJECT_LOCATIONCHANGE、EVENT_OBJECT_HIDE、EVENT_OBJECT_CLOAKED等事件,该类事件钩子不需要注入DLL,可直接在Java进程内处理回调,无跨进程权限限制,普通权限运行即可适配Notepad++这类非管理员目标程序。
方案2:注入式钩子实现(仅当有额外消息处理需求时使用)
如果你必须要Hook目标进程的窗口消息流程,需要按以下步骤调整:
- 编写和目标进程位数完全匹配的标准Win32 DLL,在DLL内部实现
WH_CALLWNDPROCRET的回调逻辑,通过共享内存、命名管道、Windows消息等IPC方式将捕获到的消息传递回Java进程,不要尝试在DLL内直接调用Java侧的Upcall,目标进程内不存在Java运行时环境,调用会直接崩溃 - 调用
SetWindowsHookExA时,第三个参数传入你加载DLL后拿到的HMODULE句柄,Windows会自动将该DLL注入到目标进程的地址空间,回调函数才可正常执行 - 程序退出前必须调用
UnhookWindowsHookEx释放钩子资源,避免目标进程出现内存泄漏或崩溃
内容的提问来源于stack exchange,提问作者Moocow9m T
相关产品推荐
相关产品推荐

