rust 为什么窗口内容在重画时消失?

y0u0uwnf  于 2023-01-09  发布在  其他
关注(0)|答案(1)|浏览(157)

用Rust和winapi编写的桌面应用程序打开一个窗口,并在几个RedrawWindow()调用中添加文本行。文本行如预期出现,并在(某些)调整窗口大小、移动和遮挡窗口时持续存在。然而,当窗口最小化并再次打开时,仅显示最后一行文本;前面的代码行都没了,代码里漏了什么

//[dependencies]
//winapi = { version = "0.3.9", features = ["wingdi", "winuser", "libloaderapi", "combaseapi", "objbase", "shobjidl", "winerror"] }

use std::error::Error;
use std::ptr::{null, null_mut};
use std::sync::Mutex;
use std::thread;
use std::time;
use winapi::shared::minwindef::*;
use winapi::shared::windef::*;
use winapi::um::libloaderapi::GetModuleHandleW;
use winapi::um::winuser::*;

// Custom signal to inform that new text is available
pub const WM_WEBUPDT: UINT = 0xFEDC;

/// Turns a Rust string slice into a null-terminated utf-16 vector.
pub fn wide_null(s: &str) -> Vec<u16> {
    s.encode_utf16().chain(Some(0)).collect()
}

static TEXT: Mutex<String> = Mutex::new(String::new());

static mut UPPER_LINE: i32 = 0;

// Window procedure to handle events
pub unsafe extern "system" fn window_proc(
    hwnd: HWND, msg: UINT, wparam: WPARAM, lparam: LPARAM,
) -> LRESULT {
    match msg {
        WM_CLOSE => {
            DestroyWindow(hwnd);
        }
        WM_DESTROY => {
            PostQuitMessage(0);
        }
        WM_WEBUPDT => {
            RedrawWindow(hwnd, null(), null_mut(), RDW_INVALIDATE);
            UPPER_LINE += 25;

        }
        WM_PAINT => {
            let t: String = TEXT.lock().unwrap().clone();
            let mut ps: PAINTSTRUCT = std::mem::zeroed();
            let hdc: HDC;
            hdc = BeginPaint(hwnd, &mut ps);
            let mut rec: RECT = std::mem::zeroed();
            GetClientRect(hwnd, &mut rec);
            rec.top += 4 + UPPER_LINE;
            let txt = wide_null(&t);
            DrawTextW(
                hdc,
                txt.as_ptr(),
                txt.len().try_into().unwrap(),
                &mut rec,
                DT_TOP | DT_LEFT,
            );
            EndPaint(hwnd, &ps);
        }
        _ => return DefWindowProcW(hwnd, msg, wparam, lparam),
    }
    return 0;
}

// Declare class and instantiate window
fn create_main_window(name: &str, title: &str) -> Result<HWND, Box<dyn Error>> {
    let name = wide_null(name);
    let title = wide_null(title);

    unsafe {
        let hinstance = GetModuleHandleW(null_mut());
        let mut wc: WNDCLASSW = core::mem::zeroed();
        wc.lpfnWndProc = Some(window_proc);
        wc.hInstance = hinstance;
        wc.hbrBackground = COLOR_WINDOWFRAME as HBRUSH;
        wc.lpszClassName = name.as_ptr();

        // Register window class
        if RegisterClassW(&wc) == 0 {
            MessageBoxW(
                null_mut(),
                wide_null("Window Registration Failed!").as_ptr(),
                wide_null("Error").as_ptr(),
                MB_ICONEXCLAMATION | MB_OK,
            );
            return Err("Window Registration Failed".into());
        };
        // Create a window based on registered class
        let handle = CreateWindowExW(
            0,                                // dwExStyle
            name.as_ptr(),                    // lpClassName
            title.as_ptr(),                   // lpWindowName
            WS_OVERLAPPEDWINDOW | WS_VISIBLE, // dwStyle
            810,                              // Int x
            390,                              // Int y
            300,                              // Int nWidth
            300,                              // Int nHeight
            null_mut(),                       // hWndParent
            null_mut(),                       // hMenu
            hinstance,                        // hInstance
            null_mut(),                       // lpParam
        );

        if handle.is_null() {
            MessageBoxW( null_mut(),
                wide_null("Window Creation Failed!").as_ptr(),
                wide_null("Error!").as_ptr(), MB_ICONEXCLAMATION | MB_OK,
            );
            return Err("Window Creation Failed!".into());
        }
        Ok(handle)
    }
}

// Message handling loop
fn run_message_loop(hwnd: HWND) -> WPARAM {
    unsafe {
        let mut msg: MSG = std::mem::zeroed();
        loop {
            // Get message from message queue
            if GetMessageW(&mut msg, hwnd, 0, 0) > 0 {
                TranslateMessage(&msg);
                DispatchMessageW(&msg);
            } else {
                // Return on error (<0) or exit (=0) cases
                return msg.wParam;
            }
        }
    }
}

fn main() {
    *TEXT.lock().unwrap() = "This is first line".to_string();
    let hwnd = create_main_window("Main Window", "Main Window").expect("Window creation failed!");
    unsafe {
        ShowWindow(hwnd, SW_SHOW);
        UpdateWindow(hwnd);
    }

    let hwnd2 = hwnd as usize;
    thread::spawn(move || { unsafe {
            thread::sleep(time::Duration::from_millis(100));
            *TEXT.lock().unwrap() = "This is second line".to_string();
            PostMessageW (hwnd2 as HWND, WM_WEBUPDT, 0 as WPARAM, 0 as LPARAM);
            thread::sleep(time::Duration::from_millis(100));
            *TEXT.lock().unwrap() = "This is third line".to_string();
            PostMessageW (hwnd2 as HWND, WM_WEBUPDT, 0 as WPARAM, 0 as LPARAM);
        }
    }
    );
    run_message_loop(hwnd);
}

yiytaume

yiytaume1#

就我和我的测试而言,如果不处理WM_ERASEBKGND
The default handling for the WM_ERASEBKGND message is to fill the area with the current window background color.
另请参见my answer
其余的,正如评论所说,Windows在Minimized Windows之后没有缓冲。
最小化窗口可以减少应用程序在更新其主窗口时必须执行的工作量,从而提高系统性能。

相关问题