Closed caesay closed 11 months ago
Defining new WM
constant can be done just like any other constant:
pub const MAKE_TOAST: co::WM = unsafe { co::WM::from_raw(co::WM::USER.raw() + 20) };
However, this is just the tip of the iceberg.
One of the greatest challenges while writing WinSafe's GUI module was how to deal with type-safe messages, since they have to be:
So, in order to properly declare a custom message, you must fulfill the bullets above. As an example, imagine that MAKE_TOAST
message, whose data is simply how many toasts you should make. It could be implemented like this:
use winsafe::{self as w, prelude::*, co, msg};
pub const MAKE_TOAST: co::WM = unsafe { co::WM::from_raw(co::WM::USER.raw() + 20) };
struct MakeToast {
how_many: u32,
}
unsafe impl MsgSend for MakeToast {
type RetType = ();
fn convert_ret(&self, _: isize) -> Self::RetType {
()
}
fn as_generic_wm(&mut self) -> msg::WndMsg {
msg::WndMsg {
msg_id: MAKE_TOAST,
wparam: self.how_many as _,
lparam: 0,
}
}
}
unsafe impl MsgSendRecv for MakeToast {
fn from_generic_wm(p: msg::WndMsg) -> Self {
Self {
how_many: p.wparam as _,
}
}
}
First, you define the struct with the data it contains, then you implement MsgSend
, so you message can be sent through SendMessage
. And finally you implement MsgSendRecv
, so your message can also be received in an on().wm(...)
handler.
Now sending becomes trivial:
self.wnd.hwnd().SendMessage(
MakeToast {
how_many: 3,
},
);
And when receiving, you must manually cast the generic parameters to the specialized struct:
self.wnd.on().wm(MAKE_TOAST, move |p| {
let p = MakeToast::from_generic_wm(p);
println!("Make {}", p.how_many);
Ok(None)
});
In fact, you made me realize that there is no clear documentation like this in the docs. This example is now here.
It's very common practice in C++ / win32 to define custom window messages (eg.
WM_USER + 1
) as constants and handle those in your message loop. I am fairly new to rust, so I might be missing something, but it doesn't seem to currently be possible. This provides an easy way to communicate between windows/threads when you already have a message loop.For example, define your constants:
Then try to hook up to these (following the custom controls example):
It's doesn't seem possible to do this, because as far as I can tell integers in rust can't be cast to enums like they can in other languages like C++ or C#. Shouldn't there be a version of
.wm()
which accepts an integer instead of the WM enum?This argument would extend to PostMessage / SendMessage, the compliment to this approach.