Tauri窗口切换器:获取HICON的方法是否正确?如何输出日志?
问题
我正在使用Rust和SolidJS开发一款基于Tauri的窗口切换器,通过winapi与Windows系统交互。目前已完成以下功能:
- 构建存储
<窗口标题(string), HWND>的HashMap; - 将窗口标题发送至前端;
- 点击标题可正确切换目标窗口。
我希望在窗口标题旁显示应用图标以提升识别度,为此修改代码将获取到的HICON与HWND一同存储,代码如下:
unsafe extern "system" fn enum_windows_proc(hwnd: HWND, lparam: LPARAM) -> BOOL { let title_length = GetWindowTextLengthW(hwnd); if title_length > 0 { let mut buffer: Vec<u16> = vec![0; (title_length + 1) as usize]; // +1 for null terminator GetWindowTextW(hwnd, buffer.as_mut_ptr(), buffer.len() as i32); if IsWindowVisible(hwnd) != 0 { let window_title = OsString::from_wide(&buffer).to_string_lossy().to_string(); let title_map = &mut *(lparam as *mut HashMap<String, (HWND, HICON)>); let app_icon = get_app_icon(hwnd); if app_icon.is_some() { title_map.insert(window_title, (hwnd, app_icon.unwrap())); } } } 1 } fn get_app_icon(hwnd: HWND) -> Option<HICON> { let icon_handle: usize = unsafe { GetClassLongPtrW(hwnd, GCLP_HICON as i32) }; if icon_handle == 0 { None } else { Some(icon_handle as HICON) } }
请问我获取HICON的方法是否正确?另外,尝试打印icon_handle无输出,替换为字符串则正常,该如何正确输出HICON相关日志?
回答
关于HICON获取方法的正确性
你当前的方法有局限性:
GetClassLongPtrW(hwnd, GCLP_HICON)只能获取窗口类注册时指定的32x32大图标,如果窗口没设置类大图标、用的是16x16小图标,或者程序动态修改了窗口图标,这个调用会返回0。- 更可靠的做法是优先通过
WM_GETICON消息获取窗口当前显示的图标,失败后再 fallback 到类图标:
use winapi::{shared::minwindef::*, um::winuser::*}; fn get_app_icon(hwnd: HWND) -> Option<HICON> { unsafe { // 先拿窗口当前的大图标 let mut icon = SendMessageW(hwnd, WM_GETICON, ICON_BIG as WPARAM, 0); if icon == 0 { // 大图标不存在就拿小图标 icon = SendMessageW(hwnd, WM_GETICON, ICON_SMALL as WPARAM, 0); if icon == 0 { // 再尝试类大图标 icon = GetClassLongPtrW(hwnd, GCLP_HICON as i32) as HICON; if icon == 0 { // 最后尝试类小图标 icon = GetClassLongPtrW(hwnd, GCLP_HICONSM as i32) as HICON; } } } icon.ne(&0).then_some(icon) } }
关于HICON的日志输出问题
HICON本质是内存指针,Rust默认没有为它实现Display/Debug trait,直接打印会无输出。你可以把它转换成usize类型,打印其内存地址:
// 在get_app_icon中添加日志 fn get_app_icon(hwnd: HWND) -> Option<HICON> { unsafe { let icon_handle = GetClassLongPtrW(hwnd, GCLP_HICON as i32); // 转成usize后以十六进制打印 println!("Icon handle: 0x{:X}", icon_handle as usize); if icon_handle == 0 { None } else { Some(icon_handle as HICON) } } }
如果需要关联窗口信息排查问题,还可以结合窗口标题打印:
// 在enum_windows_proc中添加 println!("Window: '{}' - Icon handle: {:?}", window_title, app_icon.map(|icon| icon as usize));
内容的提问来源于stack exchange,提问作者Saverio
相关产品推荐
相关产品推荐

