I am new to Rust and i am learning it, however when i search for information around this issue, there is simply no information.
The problem exists in the main loop of the program for which the code looks like this (i will post the fill code for the 2 files at the end for people to read):
main loop function
pub fn run(&mut self) -> isize {
let mut msg = MSG {
hwnd: null_mut(),
lParam: 0,
message: 0,
pt: POINT {
x: 0,
y: 0
},
time: 0,
wParam: 0,
};
loop {
if unsafe { PeekMessageW(&mut msg, self.hwnd, 0, 0, PM_REMOVE) } != 0 {
if msg.message == WM_QUIT {
break;
}
unsafe { TranslateMessage(&msg); }
unsafe { DispatchMessageW(&msg); }
} else {
// TODO: Add stuff here
}
}
0
}
The desired behaviour is that when the PostQuitMessage(0)
is send in the window_proc
function the window is destroyed and the loop inside of run
intercepts the WM_QUIT
message and then break
the loop.
The actual behaviour i am finding is that the window closes and is destroyed but the "main loop" in the run
function never detects the WM_QUIT
message and subsequentially never exits, leaving the window destroyed and the main loop still running.
win64.rs
#![cfg(windows)]
use std::error::Error;
use std::ptr::null_mut;
use std::mem::size_of;
use winapi::shared::minwindef::*;
use winapi::shared::windef::*;
use winapi::um::libloaderapi::{ GetModuleHandleW };
use winapi::um::wingdi::*;
use winapi::um::winuser::*;
fn to_wstring(s: &str) -> Vec<u16> {
use std::os::windows::ffi::OsStrExt;
std::ffi::OsStr::new(s).encode_wide().chain(std::iter::once(0)).collect()
}
pub extern "system" fn window_proc(hwnd: HWND, msg: UINT, wparam: WPARAM, lparam: LPARAM) -> LRESULT {
match msg {
WM_CLOSE => {
unsafe { PostQuitMessage(0) };
unsafe { DestroyWindow(hwnd) };
0
}
WM_DESTROY => {
unsafe { PostQuitMessage(0) };
0
}
_ => return unsafe { DefWindowProcW(hwnd, msg, wparam, lparam) }
}
}
pub struct Window {
h_instance: HINSTANCE,
hwnd: HWND,
rect: RECT,
}
impl Window {
pub fn new(title: &str, width: u32, height: u32) -> Result<Window, Box<(dyn Error + 'static)>> {
let title = to_wstring(title);
let class_name = to_wstring("_class64");
let mut wnd = Window {
h_instance: unsafe { GetModuleHandleW(null_mut()) },
hwnd: null_mut(),
rect: RECT {
left: 0,
top: 0,
right: width as i32,
bottom: height as i32,
}
};
if wnd.h_instance == null_mut() {
let err_str = "failed to obtain window instance";
unsafe { MessageBoxW(null_mut(), to_wstring(err_str).as_ptr(), to_wstring("Error").as_ptr(), MB_ICONERROR | MB_OK); }
return Err(err_str.into());
}
let wnd_class_ex = WNDCLASSEXW {
cbClsExtra: 0,
cbSize: size_of::<WNDCLASSEXW>() as u32,
cbWndExtra: 0,
hbrBackground: unsafe { GetStockObject(BLACK_BRUSH as i32) as HBRUSH},
hCursor: unsafe { LoadCursorW(null_mut(), IDC_ARROW) },
hIcon: unsafe { LoadIconW(null_mut(), IDI_APPLICATION) },
hIconSm: unsafe { LoadIconW(null_mut(), IDI_APPLICATION) },
hInstance: wnd.h_instance,
lpfnWndProc: Some(window_proc),
lpszClassName: class_name.as_ptr(),
lpszMenuName: null_mut(),
style: CS_OWNDC | CS_HREDRAW | CS_VREDRAW,
};
if unsafe { RegisterClassExW(&wnd_class_ex) } == 0 {
let err_str = "failed to register window";
unsafe { MessageBoxW(null_mut(), to_wstring(err_str).as_ptr(), to_wstring("Error").as_ptr(), MB_ICONERROR | MB_OK); }
return Err(err_str.into());
}
wnd.hwnd = unsafe { CreateWindowExW(
0,
class_name.as_ptr(),
title.as_ptr(),
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT, CW_USEDEFAULT,
wnd.rect.right, wnd.rect.bottom,
null_mut(), null_mut(), wnd.h_instance, null_mut())
};
if wnd.hwnd == null_mut() {
let err_str = "failed to create window";
unsafe { MessageBoxW(null_mut(), to_wstring(err_str).as_ptr(), to_wstring("Error").as_ptr(), MB_ICONERROR | MB_OK); }
return Err(err_str.into());
}
unsafe { ShowWindow(wnd.hwnd, SW_SHOW); }
unsafe { UpdateWindow(wnd.hwnd); }
Ok(wnd)
}
pub fn run(&mut self) -> isize {
let mut msg = MSG {
hwnd: null_mut(),
lParam: 0,
message: 0,
pt: POINT {
x: 0,
y: 0
},
time: 0,
wParam: 0,
};
loop {
if unsafe { PeekMessageW(&mut msg, self.hwnd, 0, 0, PM_REMOVE) } != 0 {
if msg.message == WM_QUIT {
break;
}
unsafe { TranslateMessage(&msg); }
unsafe { DispatchMessageW(&msg); }
} else {
// TODO: Add stuff here
}
}
0
}
}
main.rs
mod win64;
fn main() {
println!("running create_window_win32api");
let mut wnd = win64::Window::new("test window", 1280, 720).expect("failed to create window");
wnd.run();
}