rust 使用 windows crate 显示窗口

问题描述 投票:0回答:2

在我的 Rust 实验中,我目前正在尝试以下操作。我想使用 windows crate 和 windows API 显示一个基本的空窗口。下面的代码编译并执行。它唯一不做的就是显示一个实际的窗口。我在这里做错了什么,因为代码看起来对我来说很重要,例如我相信 c++ 等效项会显示一个窗口。


use windows::{
    core::*, Win32::{Foundation::*, Graphics::Gdi::{CreateSolidBrush, UpdateWindow, ValidateRect, COLOR_WINDOW, HBRUSH}, System::LibraryLoader::{GetModuleHandleA, GetModuleHandleW}, UI::WindowsAndMessaging::*},
};
fn main() -> Result<()> {
    
    

    unsafe{
        let window_class = w!("the_window");
        let window_name = w!("The Factory");
        let instance = GetModuleHandleW(None)?;
        let kleur = COLORREF{
            0: 255,
        };
        let brush: HBRUSH = CreateSolidBrush(kleur);
        debug_assert!(instance.0 != 0);

        //define the window
        let wc = WNDCLASSW {
            hCursor: LoadCursorW(None, IDC_ARROW)?,
            style: CS_HREDRAW | CS_VREDRAW,
            lpszClassName: window_name,
            hInstance: instance.into(),
            hbrBackground: brush,
            lpfnWndProc: Some(wndproc),
            ..Default::default()
        };

        //register the class
        let atom = RegisterClassW(&wc);
        debug_assert!(atom != 0);
        let hwnd_desktop = GetDesktopWindow();

        let hwnd = CreateWindowExW(WINDOW_EX_STYLE::default(), window_class, window_name, WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 100, 100, hwnd_desktop, None, instance, None);
        
        
        ShowWindow(hwnd, SW_SHOW);
        UpdateWindow(hwnd);

        let mut message = std::mem::zeroed();
        println!("init the msg structure success.");

        while GetMessageA(&mut message, None, 0, 0).into() {
            TranslateMessage(&message);
            DispatchMessageA(&message);
        }
        Ok(())
    }

    
}

extern "system" fn wndproc(window: HWND, message: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT {
    unsafe {
        match message {
            WM_PAINT => {
                println!("WM_PAINT");
                _ = ValidateRect(window, None);
                LRESULT(0)
            }
            WM_DESTROY => {
                println!("WM_DESTROY");
                PostQuitMessage(0);
                LRESULT(0)
            }
            _ => DefWindowProcA(window, message, wparam, lparam),
        }
    }
}
windows winapi rust
2个回答
0
投票

我无法追踪错误的根源,但我想知道

hwnd
参数是否为0或主消息循环返回-1。

还有一些备注:

  1. 您使用
    WNDCLASS
    CreateWindowEx
    的 Unicode 变体(末尾均带有 W),但使用
    DefWindowProc
    DispatchMessage
    GetMessage
    的 ANSI 变体。这会导致标题栏仅显示第一个字符。
  2. 我不知道什么是
    WINDOW_EX_STYLE::default()
    ,但如果它是无效标志,则可能会导致窗口没有正确的标题栏或首先显示。
  3. 主消息循环可以返回-1,表示发生错误。正如官方页面所说:

在 hWnd 是无效参数的情况下(例如引用已被销毁的窗口),可能返回 -1 值,这意味着此类代码可能会导致致命的应用程序错误。相反,使用这样的代码:

while( (bRet = GetMessage( &msg, hWnd, 0, 0 )) != 0)


0
投票

等效的 C++ 代码失败的原因与此代码相同:尝试创建尚未注册的类的窗口。

具体问题在这里:

let wc = WNDCLASSW {
    // ...
    lpszClassName: window_name,
    // ...
    ..Default::default()
};

这将准备一个

WNDCLASSW
结构,以名称window_
name
进行
注册
。随后对
CreateWindowExW()
的调用会请求创建
window_
class
类的窗口(尚未注册)。

在继续解决问题之前,让我们了解

CreateWindowExW()
可能会失败的事实,并添加以下错误处理代码:

let hwnd = CreateWindowExW(
    // ...
);

if hwnd == HWND::default() {
    return Err(Error::from_win32());
}

完成后,程序现在终止。发出

cargo run
会产生(除其他外)以下输出:

Error: Error { code: HRESULT(0x8007057F), message: "Cannot find window class." }

这很有帮助,并证实了注册的类名和请求的类名之间不匹配的怀疑。

修复方法很简单:确保注册的类名和请求的类名一致。将

WNDCLASSW
初始化更新为 read

let wc = WNDCLASSW {
    // ...
    lpszClassName: window_class,
    // ...
    ..Default::default()
};

得到你

this

完成!


直到抓住右边缘并将其进一步向右移动。足以让人们毫无疑问地发现某些东西没有按预期显示。类似的东西

this

窗口标题应为

The Factory
,但显示屏显示为
T
。这是程序“G”阻止你关机的另一个化身。

简而言之:用于类注册的编码变体(

RegisterClassA
RegisterClassW
)必须与所提供的窗口过程所假定的编码一致。最突出的例子是未处理消息的委托:

注册的类的窗口过程

  • RegisterClassA
    必须委托给
    DefWindowProcA
  • RegisterClassW
    必须委托给
    DefWindowProcW

相关代码使用

RegisterClassW
注册窗口类,但委托给
DefWindowProcA
,导致(以及其他问题)显示的窗口标题被截断。

这里的修复同样简单:

_ => DefWindowProcW(window, message, wparam, lparam),

产生这个窗口

as intended

© www.soinside.com 2019 - 2024. All rights reserved.