Я чувствую, что делаю что-то не так на стороне ржавчины. Во время изучения 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();
}