本文给出了一个通用的windows窗口消息循环的实现,示例如下
定义窗口类
use windows::{
core::*, Win32::Foundation::*, Win32::System::DataExchange::*,
Win32::System::LibraryLoader::GetModuleHandleA,
Win32::UI::WindowsAndMessaging::*, Win32_UI_WindowsAndMessaging,
};
struct Window {
handle: HWND, // 窗口句柄
// todo 可以定义一些消息处理需要的参数
}
impl Window {
pub fn new() -> Result<Self> {
Ok(Window { handle: HWND(0) })
}
pub fn run(&mut self) -> Result<()> {
unsafe {
// 检索指定模块的模块句柄
let instance = GetModuleHandleA(None)?;
debug_assert!(instance.0 != 0);
let window_class = s!("WindowsDemo");
// 窗口类属性
let wc = WNDCLASSA {
// 实例的句柄,该实例包含类的窗口过程。
hInstance: instance.into(), // HMODULE -> HINSTANCE
// 窗口类名
lpszClassName: window_class,
// 指向窗口过程的指针。 必须使用 CallWindowProc 函数调用窗口过程。
lpfnWndProc: Some(Self::wndproc),
..Default::default()
};
// 注册一个窗口类
let atom = RegisterClassA(&wc);
debug_assert!(atom != 0);
let handle = CreateWindowExA(
WINDOW_EX_STYLE::default(),
window_class,
s!("Demo"),
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
None,
None,
instance,
Some(self as *mut _ as _), // 用于窗口内全局变量共享
);
debug_assert!(handle.0 != 0);
debug_assert!(handle == self.handle);
// 从调用线程的消息队列中检索消息
let mut msg = MSG::default();
// 从线程消息中取出一条消息
while GetMessageA(&mut msg, HWND(0), 0, 0).into() {
// 把取出的消息发送到目的窗口
TranslateMessage(&msg);
DispatchMessageA(&msg);
}
Ok(())
}
Ok(())
}
定义当前窗口的处理过程
extern "system" fn wndproc(
window: HWND,
message: u32,
wparam: WPARAM,
lparam: LPARAM,
) -> LRESULT {
unsafe {
if message == WM_NCCREATE {
// 获得窗口创建参数
let cs = lparam.0 as *const CREATESTRUCTA;
let this = (*cs).lpCreateParams as *mut Self;
(*this).handle = window;
// 设置与窗口关联的用户数据
SetWindowLongPtrA(window, GWLP_USERDATA, this as _);
} else if message == WM_PAINT {
// todo 自行处理窗口绘制
_ = ValidateRect(window, None);
} else {
// 获得窗口关联的用户数据
let this =
GetWindowLongPtrA(window, GWLP_USERDATA) as *mut Self;
// 处理接收到的窗口消息
if !this.is_null() {
return (*this).message_handler(message, wparam, lparam);
}
}
// 调用默认窗口过程,为应用程序不处理的任何窗口消息提供默认处理。
DefWindowProcA(window, message, wparam, lparam)
}
}
定义业务逻辑相关的消息处理函数
fn message_handler(
&mut self,
message: u32,
wparam: WPARAM,
lparam: LPARAM,
) -> LRESULT {
unsafe {
match message {
WM_CREATE => {
// todo 添加业务逻辑
}
WM_DESTROY => {
PostQuitMessage(0)
}
WM_CLOSE => {
return DefWindowProcA(
self.handle,
message,
wparam,
lparam,
);
}
// todo 添加其它的消息处理逻辑
_ => {
return DefWindowProcA(
self.handle,
message,
wparam,
lparam,
);
}
}
}
LRESULT(0)
}
参考
https://github.com/microsoft/windows-rs/tree/master/crates/tests