以下是将 HICON
转换为 PNG
图标 base64 编码表示的方法:
use base64::{engine::general_purpose, Engine as _};
use image::RgbaImage;
use std::{mem::{self, MaybeUninit}, ptr::addr_of_mut};
use windows::Win32::{Foundation::HWND, Graphics::Gdi::{DeleteObject, GetDC, GetDIBits, GetObjectW, ReleaseDC, BITMAP, BITMAPINFOHEADER, BI_RGB, DIB_RGB_COLORS, HDC}, UI::WindowsAndMessaging::{GetIconInfo, HICON}};
unsafe fn icon_to_rgba_image(icon: HICON) -> String {
let bitmap_size = i32::try_from(mem::size_of::<BITMAP>()).unwrap();
let biheader_size = u32::try_from(mem::size_of::<BITMAPINFOHEADER>()).unwrap();
let mut info = MaybeUninit::uninit();
GetIconInfo(icon, info.as_mut_ptr()).unwrap();
let info = info.assume_init_ref();
DeleteObject(info.hbmMask).unwrap();
let mut bitmap: MaybeUninit<BITMAP> = MaybeUninit::uninit();
let result = GetObjectW(
info.hbmColor,
bitmap_size,
Some(bitmap.as_mut_ptr().cast()),
);
assert!(result == bitmap_size);
let bitmap = bitmap.assume_init_ref();
let width = u32::try_from(bitmap.bmWidth).unwrap();
let height = u32::try_from(bitmap.bmHeight).unwrap();
let w = usize::try_from(bitmap.bmWidth).unwrap();
let h = usize::try_from(bitmap.bmHeight).unwrap();
let buf_size = w
.checked_mul(h)
.and_then(|size| size.checked_mul(4))
.unwrap();
let mut buf: Vec<u8> = Vec::with_capacity(buf_size);
let dc = GetDC(HWND(0));
assert!(dc != HDC(0));
let mut bitmap_info = BITMAPINFOHEADER {
biSize: biheader_size,
biWidth: bitmap.bmWidth,
biHeight: -bitmap.bmHeight,
biPlanes: 1,
biBitCount: 32,
biCompression: BI_RGB,
biSizeImage: 0,
biXPelsPerMeter: 0,
biYPelsPerMeter: 0,
biClrUsed: 0,
biClrImportant: 0,
};
let result = GetDIBits(
dc,
info.hbmColor,
0,
height,
Some(buf.as_mut_ptr().cast()),
addr_of_mut!(bitmap_info).cast(),
DIB_RGB_COLORS,
);
buf.set_len(buf.capacity());
let result = ReleaseDC(HWND(0), dc);
assert!(result == 1);
DeleteObject(info.hbmColor).unwrap();
for chunk in buf.chunks_exact_mut(4) {
let [b, _, r, _] = chunk else { unreachable!() };
mem::swap(b, r);
}
let img = RgbaImage::from_vec(width, height, buf).unwrap();
let mut data: Vec<u8> = Vec::new();
img.write_to(&mut Cursor::new(&mut data), image::ImageOutputFormat::Png).unwrap();
general_purpose::STANDARD.encode(&data);
}
Tauri 是构建在 TAO 之上的,而 TAO 又是 winit 的一个分支,专门实现了跨平台的窗口管理。
具体来说,在 windows/window.rs 中处理了与窗口相关的实现。因此,你可能需要克隆 TAO 的仓库,并在那里添加必要的修改,然后使用 Cargo 的 依赖覆盖功能,使其指向你的 TAO 版本。
TAO 实现了与 hicon
相关的类,如下所示:
let class = WNDCLASSEXW {
cbSize: mem::size_of::<WNDCLASSEXW>() as u32,
style: CS_HREDRAW | CS_VREDRAW | CS_OWNDC,
lpfnWndProc: Some(window_proc),
cbClsExtra: 0,
cbWndExtra: 0,
hInstance: HINSTANCE(GetModuleHandleW(PCWSTR::null()).unwrap_or_default().0),
hIcon: HICON::default(),
hCursor: HCURSOR::default(), // 鼠标光标状态正常工作必须设为 null
hbrBackground: HBRUSH::default(),
lpszMenuName: PCWSTR::null(),
lpszClassName: PCWSTR::from_raw(class_name.as_ptr()),
hIconSm: HICON::default(),
};
值得一提的是,Tauri 使用了 windows 这个库来替代 winapi
,尽管下载量较少,但微软提供了更好的支持,且与 apple-sys 对 Mac 的支持方式类似。
如 Jonathan Potter 所指出的,要获取 hicon
的信息,你需要使用 GetIconInfo 函数,它会提供一个包含掩码和彩色位图句柄的 ICONINFO
结构体。
直接打印 hicon
是不可能的,因为它只是一个句柄,用来引用图标资源:
pub type HICON = isize;
附注:这是 TAO 检查 Windows 上窗口是否可见的方式。同时,在同一段代码中,有大约七种方法可以获取窗口的硬件ID,包括以 HWND
及其他格式。