I'm trying to write a simple windows app in rust with windows-rs crate. I'd like to have a state wrapped in Counter struct and pass it to window_proc function. It is successful to retrieve the pointer and store it by GWLP_USERDATA index. My question is that why it increases in WM_CREATE msg without error, but does not work in WM_COMMAND msg?
struct Counter {
counter: i32
}
fn main() -> Result<()> {
let lparam: *mut Counter = Box::leak(Box::new(Counter{
counter: 1
}));
unsafe {
let mut instance = Default::default();
GetModuleHandleExW(0, None, &mut instance)?;
let wnd_class = WNDCLASSEXW {
// ... ...
};
let atom = RegisterClassExW(&wnd_class);
debug_assert!(atom != 0);
let hwnd = CreateWindowExW(
// ... ...
Some(lparam as *mut c_void),
);
// ... ...
}
}
fn increase_and_print(parent: HWND) {
unsafe {
let ptr = GetWindowLongPtrW(parent, GWLP_USERDATA);
println!("GetWindowLongPtrW: {}", ptr);
let ptr = GetWindowLongPtrW(parent, GWLP_USERDATA) as *mut Box<Counter>;
debug_assert!(!ptr.is_null());
let c = &mut *ptr;
c.counter += 1;
println!("counter: {}", c.counter);
}
}
extern "system" fn window_proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT {
unsafe {
match msg {
WM_CREATE => {
// Create a click button
// Retrieve the pointer to your state and store it in the window's user data
SetWindowLongPtrW(hwnd, GWLP_USERDATA, lparam.0 as isize);
increase_and_print(hwnd);
LRESULT(0)
},
WM_DESTROY => {
PostQuitMessage(0);
LRESULT(0)
},
WM_COMMAND => {
increase_and_print(hwnd);
return LRESULT(0);
},
_ => DefWindowProcW(hwnd, msg, wparam, lparam)
}
}
}
The counter is initialized to 1, then increased to 2 in WM_CREATE msg. I expect it prints 3 after clicking the button (i.e. WM_COMMAND msg was called) Output in console
GetWindowLongPtrW: 359815702944
counter: 2
GetWindowLongPtrW: 359815702944
thread 'main' panicked at 'misaligned pointer dereference: address must be a multiple of 0x4 but is 0xb', apps\counter\src\main.rs:73:9
I search for apps created by windows-rs on GitHub, finally I got this robmikh/minesweeper-rs windows.rs. It's totally what I was looking for.
Set counter to User data
Retrieve counter and update its value
As I am new to Rust, I would be grateful if somebody could explain this in detail.