Rust Windows Crate Rust Window ExW

p1tboqfb  于 4个月前  发布在  Windows
关注(0)|答案(1)|浏览(51)

我正在写一个函数来创建一个窗口,我提供了下面不能工作的代码。此代码使用windows crate和最新版本的rust(在编写rustc 1.74.0时)。

use std::ptr;
 
use windows::{
    core::{w, PCWSTR},
    Win32::{
        Foundation::{GetLastError, HINSTANCE, HWND, LPARAM, LRESULT, WPARAM},
        Graphics::Gdi::HBRUSH,
        System::LibraryLoader::GetModuleHandleW,
        UI::WindowsAndMessaging::{
            CreateWindowExW, DefWindowProcW, DestroyWindow, PostQuitMessage, RegisterClassW,
            CS_HREDRAW, CS_VREDRAW, CW_USEDEFAULT, HCURSOR, HICON, WINDOW_EX_STYLE, WNDCLASSW,
            WS_OVERLAPPEDWINDOW,
        },
    },
};
 
fn main() {
    match create_window() {
        Ok(_) => {}
        Err(e) => eprintln!("{}", e),
    };
}
 
pub fn create_window() -> Result<(), Box<dyn std::error::Error>> {
    let h_instance: HINSTANCE = unsafe { GetModuleHandleW(None) }?.into();
    let lp_sz_class_name = w!("window_class");
    let lp_sz_window_name = w!("window_title");
 
    let window_class = WNDCLASSW {
        style: CS_HREDRAW | CS_VREDRAW,
        lpfnWndProc: Some(window_proc),
        cbClsExtra: 0,
        cbWndExtra: 0,
        hInstance: h_instance,
        hIcon: HICON(0),
        hCursor: HCURSOR(0),
        hbrBackground: HBRUSH(2),
        lpszMenuName: PCWSTR(ptr::null_mut()),
        lpszClassName: lp_sz_class_name,
    };
 
    if unsafe { RegisterClassW(&window_class) } == 0 {
        unsafe { GetLastError() }?;
    };
 
    let hwnd = unsafe {
        CreateWindowExW(
            WINDOW_EX_STYLE(0),
            window_class.lpszClassName,
            lp_sz_window_name,
            WS_OVERLAPPEDWINDOW,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            None,
            None,
            window_class.hInstance,
            None,
        )
    };
 
    if hwnd == HWND(0) {
        unsafe { GetLastError() }?;
    }
 
    Ok(())
}
 
unsafe extern "system" fn window_proc(
    hwnd: HWND,
    msg: u32,
    wparam: WPARAM,
    lparam: LPARAM,
) -> LRESULT {
    match msg {
        WM_CLOSE => {
            unsafe { PostQuitMessage(0) };
            unsafe { DestroyWindow(hwnd) };
            LRESULT(0)
        }
        WM_DESTROY => {
            unsafe { PostQuitMessage(0) };
            LRESULT(0)
        }
        _ => return unsafe { DefWindowProcW(hwnd, msg, wparam, lparam) },
    }
}

字符串
当这段代码运行时,它会产生一个错误“创建窗口失败>参数不正确。(0x80070057)"。这表明函数CreateWindowExW的参数无效。
我尝试了逐个隔离参数,但都有数据,我无法找到无效参数。我想知道是否有人可以看看,看看我是否错过了什么?
我期望窗口类注册成功,而窗口句柄创建失败。

gpfsuwkq

gpfsuwkq1#

我编译了你粘贴的MRE,它产生了这个警告,这是一个大红旗:

warning: unreachable pattern
  --> src/main.rs:82:9
   |
77 |         WM_CLOSE => {
   |         -------- matches any value
...
82 |         WM_DESTROY => {
   |         ^^^^^^^^^^ unreachable pattern
   |
   = note: `#[warn(unreachable_patterns)]` on by default

字符串
window_proc中的相关代码是这样的:

match msg {
        WM_CLOSE => { /*... */ ; LRESULT(0) }
        WM_DESTROY => { ... }
        _ => DefWindowProcW(hwnd, msg, wparam, lparam),
    }


但是常量WM_*对于Rust编译器来说是未知的,所以这实际上等价于:

match msg {
        _ => { /*... */ ; LRESULT(0) }
        /* blah, blah DefWindowProcW something that is never run */
    }


也就是说,这个函数总是返回LRESULT(0),不管处理的是什么消息。正如我之前评论的,窗口函数得到的第一条消息之一,甚至在CreateWindow返回之前,是WM_NCCREATE。但是为该消息返回0将中止窗口创建。GetLastError()返回的值将是您使用SetLastError()设置的任何值,但是您没有调用它,所以你得到了无意义的错误代码。
解决方案很简单,只需导入消息常量:

unsafe extern "system" fn window_proc(
    hwnd: HWND,
    msg: u32,
    wparam: WPARAM,
    lparam: LPARAM,
) -> LRESULT {
    use windows::Win32::UI::WindowsAndMessaging::*; // <---- Here!

    match msg {
        WM_CLOSE => { ...


这就是为什么你永远不应该忽略Rust编译器的警告,以及为什么你应该总是在StackOverflow问题中添加一个MRE!

相关问题