我正在尝试使用Rust来计算在特定窗口内花费的时间。
现在我被Windows钩子卡住了。
我尝试使用windows
crate来设置钩子,但我无法使SetWindowsHookExW
工作,因为它不允许传递null ptr作为hmod
参数。SetWindowsHookW
编译后总是返回0
,就是这样。现在我切换到winapi
机箱,使用SetWinEventHookExW
返回类似0x00000000
的东西,我认为这是不成功的操作。调用SetWinEventHook
时,返回看似正常的值,但由于我不知道的原因,事件没有被捕获。以下是我的当前代码:
// dependencies imports
...
thread_local! {
static TX: OnceCell<Sender<RawWindowEvent>>= OnceCell::new()
}
extern "system" fn win_event_hook_callback(
child_id: HWINEVENTHOOK,
hook_handle: DWORD,
event_id: HWND,
window_handle: LONG,
object_id: LONG,
thread_id: DWORD,
timestamp: DWORD,
) -> () {
println!("EVENT?");
TX.with(|f| {
let tx = f.get().unwrap();
let event = RawWindowEvent {
child_id,
hook_handle,
event_id,
window_handle,
object_id,
thread_id,
timestamp,
};
println!("{:#?}", &event);
tx.send(event);
});
}
fn main() {
println!("Hello, world!");
let (tx, rx) = channel::<RawWindowEvent>();
match TX.with(|f| f.set(tx)) {
Err(err) => panic!("{:#?}", err),
_ => (),
};
unsafe {
let hook = SetWinEventHook(
0x0003,
0x0003,
ptr::null_mut(),
Some(win_event_hook_callback),
0,
0,
0,
);
println!("{:#?}", hook);
loop {
let event = rx.recv().unwrap();
println!("{:#?}", event);
}
UnhookWinEvent(hook);
}
}
#[derive(Debug)]
pub struct RawWindowEvent {
pub child_id: HWINEVENTHOOK,
pub hook_handle: DWORD,
pub event_id: HWND,
pub window_handle: LONG,
pub object_id: LONG,
pub thread_id: DWORD,
pub timestamp: DWORD,
}
1条答案
按热度按时间iszxjhcz1#
这里有几个问题,所以让我们快速覆盖那些实际上并不相关的问题:
我不能让
SetWindowsHookExW
工作,因为它不允许传递null ptr作为hmod
参数。windows
crate中SetWindowsHookExW
的签名需要一个为hmod
参数实现IntoParam<HMODULE>
的类型,这允许传递一个有效的HMODULE
值或None
(转换为空指针)。现在我切换到
winapi
机箱你不该这么做它不再积极维护,据我所知,不提供任何功能,也不能通过
windows
(或windows-sys
)板条箱。使用
SetWinEventHookExW
返回类似0x00000000
的东西,我认为这是不成功的操作我不知道
SetWinEventHookExW
是什么。我假设这是一个错字,应该读SetWindowsHookExW
代替。如果是这种情况,则返回值零表示失败。有了这些,WinEvents是最适合监视前台激活事件的系统服务,而
windows
是访问它最方便的Rust crate。无论您选择hooks还是WinEvents,您实际上总是必须在安装了钩子的线程上启动一个消息循环(调用GetMessage
/DispatchMessage
)以接收通知。下面的实现(使用
windows
crate)设置了一个WinEvents钩子来接收EVENT_SYSTEM_FOREGROUND
通知:这是利用了这样一个事实,即只要
MessageBoxW
启动,系统就会在调用线程上分发消息。根据应用程序的需要,您可能希望实现自己的消息循环。这并不严格要求旋转额外的线程;MsgWaitForMultipleObjectsEx
通过等待消息到达、内核对象收到信号或I/O完成例程/APC在调用线程上排队来解决这个问题。