我对 Rust 编程有点陌生。在过去的两个月里我学到了很多东西,但目前我可以使用一些有根据的建议。
过去,我一直遵循 C++ 教程系列来使用 DirectX11 构建引擎(参见此)到了一定程度。了解 Rust 后,我决定将项目转移到 Rust,并在此过程中了解更多信息。
所以我想重现的是,教程将指向窗口类的指针插入到窗口回调中的方式。我通过实施成功实现了它
// inside 'impl BEWindow'
extern "system" fn initialize_proc(window:HWND, message: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT {
unsafe {
if message == WM_CREATE {
let pCreate = *(lparam.0 as *const c_void as *const CREATESTRUCTA);
let wnd = pCreate.lpCreateParams as *mut BEWindow;
SetWindowLongPtrW(window, GWLP_USERDATA, *(wnd as *mut isize));
SetWindowLongPtrW(window, GWLP_WNDPROC, BEWindow::run_proc as *const c_void as isize);
let ret =wnd.as_ref().unwrap().handle_message(window, message, wparam, lparam);
return ret
}
}
extern "system" fn run_proc(window:HWND, message:u32, wparam: WPARAM, lparam: LPARAM) ->LRESULT {
unsafe {
if let Some(optional_wnd) = &GLOBAL_WND {
let mut wnd = optional_wnd.lock().unwrap();
return wnd.handle_message(window, message, wparam, lparam)
}
else {
LRESULT(0)
}
}
}
这种短期有效。在回调的前几次迭代之后,引用的结构发生了移动,并且我收到了分段错误,因为用户数据中的指针未更新。
经过一些研究,我发现 Arc 和 Mutex 看起来有点适合我的问题。据我理解本教程,“外部“系统”回调”应该由窗口线程执行。
我想知道我是否需要initialize_proc将指针放入UserData中,当我也可以使用静态时。
static mut GLOBAL_WND: Option<Arc<Mutex<BEWindow>>> = None;
//struct BEWindow
impl BEWindow{
//other functions
// new function sets the value of GLOBAL_WND to Some( ... arc ...) and returns a cloned
// version of the arc, it also creates the window with the winapi
extern "system" fn run_proc(window:HWND, message:u32, wparam: WPARAM, lparam: LPARAM) ->LRESULT {
unsafe {
if let Some(optional_wnd) = &GLOBAL_WND {
let mut wnd = optional_wnd.lock().unwrap();
return wnd.handle_message(window, message, wparam, lparam)
}
else {
LRESULT(0)
}
}
}
}
这似乎不起作用。静态永远不会真正更新。调试时:在回调中,静态似乎始终为 None。
所以我认为我对 Rust 中的静态以及它们在多线程中的行为方式缺乏一些了解。 它也可能与我的新函数中的操作顺序有关。 (我现在还没有一个最小的例子)
我愿意接受代码的某些替代结构。我真正想通过获取指针来实现的是过滤从窗口获得的消息,将它们放入一些队列中,并从主线程中的游戏循环访问它们。 我认为这可以通过一些不太复杂的代码来实现。