WinAPI с Rust: CreateWindowExW завершается ошибкой во второй раз, когда он вызывается с тем же WNDCLASSEXW - PullRequest
0 голосов
/ 06 марта 2019

Я чувствую, что делаю что-то не так на стороне ржавчины. Во время изучения WinAPI я попытался создать второе окно с тем же WNDCLASSEXW, но этот вызов завершился ошибкой 1407 (ERROR_CANNOT_FIND_WND_CLASS).

Поскольку я был почти уверен, что это должно работать концептуально, я переписал «ту же самую» (вероятно, не ту же) программу на c ++: она работает!

Что я здесь не так делаю?

Маленькие (ish) примеры, которые показывают объясненное поведение:

C ++:

class WindowClass{
public:
    WindowClass(WNDCLASSEXW wndclass, HMODULE hmodule){
        _wndclass = wndclass;
        _hmodule = hmodule;
    }

    WNDCLASSEXW _wndclass;
    HMODULE _hmodule;
};

class Window{
public:
    Window(LPCWSTR title, WindowClass& window_class){
        auto hwnd = CreateWindowExW(
            0,
            window_class._wndclass.lpszClassName,
            title,
            WS_OVERLAPPEDWINDOW,
            CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
            nullptr,
            nullptr,
            window_class._hmodule,
            nullptr);

    if ( hwnd == nullptr ) {
        std::cout << "Error CreateWindowExW " << GetLastError() << std::endl;
    }

    _handle = hwnd;
}

void show(){
    ShowWindow(_handle, SW_SHOWDEFAULT);
}

static WindowClass create_window_class(LPCWSTR class_name){
    auto hmodule = GetModuleHandleW(nullptr);

    WNDCLASSEXW wndclass = {};
    wndclass.cbSize = sizeof(WNDCLASSEXW);
    wndclass.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
    wndclass.lpfnWndProc = DefWindowProcW;
    wndclass.hInstance = hmodule;
    wndclass.lpszClassName = class_name;

    if ( RegisterClassExW(&wndclass) == 0 ) {
        std::cout << "Error RegisterClassExW: " << GetLastError() << std::endl;
    }

    return WindowClass{wndclass, hmodule};
}

private:
    HWND _handle;
};

int main(){
    auto window_class = Window::create_window_class(L"windowclass");
    Window window1(L"Window1", window_class);
    window1.show();
    Window window2(L"Window2", window_class);
    window2.show();
    auto foo = 0;
    std::cin >> foo;
}

Ржавчина:

trait Win32String{
    fn as_win32_string(&self) -> Vec<u16>;
}

impl Win32String for str{
    fn as_win32_string(&self) -> Vec<u16> {
        OsStr::new( self ).encode_wide().chain( once( 0 ) ).collect()
    }
}

pub struct Window{
    pub handle: HWND
}

impl Window{
    pub fn create_window_class(class_name: &str, styles: u32) -> Result<WindowClass, Error>{
        let class_name = class_name.as_win32_string();
        let hmodule = unsafe{
            GetModuleHandleW( null_mut())
        };

        let wnd_class = WNDCLASSEXW {
            cbSize: mem::size_of::<WNDCLASSEXW>() as u32,
            style : styles,
            lpfnWndProc : Some( DefWindowProcW ),
            hInstance : hmodule,
            lpszClassName : class_name.as_ptr(),
            cbClsExtra : 0,
            cbWndExtra : 0,
            hIcon: null_mut(),
            hCursor: null_mut(),
            hbrBackground: null_mut(),
            lpszMenuName: null_mut(),
            hIconSm: null_mut(),
        };

        if unsafe { RegisterClassExW(&wnd_class) } == 0 { // <-- This fails the second time
            return Err(Error::last_os_error());
        } else {
            return Ok(WindowClass{ class: wnd_class, hmodule})
        }
    }

    pub fn new(title: &str, window_class: &WindowClass) -> Result<Window, Error>{
        let title = title.as_win32_string();

        let hwnd = unsafe { CreateWindowExW(
            0,
            window_class.class.lpszClassName,
            title.as_ptr(),
            WS_OVERLAPPEDWINDOW,
            CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
            null_mut(),
            null_mut(),
            window_class.hmodule as *mut _,
            null_mut()
        )};

        if hwnd == null_mut() { return Err(Error::last_os_error()); }

        Ok(Window{handle: hwnd})
    }

    pub fn show(&self) -> bool {
        unsafe {
            let ret = ShowWindow(self.handle, SW_SHOWDEFAULT);
            ret != 0
        }
    }
}


pub struct WindowClass{
    class: WNDCLASSEXW,
    hmodule: HMODULE
}


fn main() {
    let window_class = Window::create_window_class(
        "windowclass",
        CS_OWNDC | CS_HREDRAW |CS_VREDRAW
    ).unwrap();
    let window = Window::new("Window1", &window_class).unwrap();
    window.show();
    let window2 = Window::new("Window2", &window_class).unwrap();
    window2.show();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...