元のプログラムは以下。しかし一部コピペでは動かなかった部分もあるので修正をしている。
https://github.com/microsoft/windows-samples-rs/blob/master/create_window/src/main.rs
以前作った自作WinMainを呼び出すmain関数。
main.rsと同じディレクトリに次のWinMain.rsが存在する。
use windows::Win32::System::LibraryLoader::GetModuleHandleA; use std::env; use windows::Win32::System::Threading::{GetStartupInfoW, STARTUPINFOW}; // mod ファイル名 mod winmain; // use 関数名(など) use winmain::WinMain; // Rustのwindows-rsからウィンドウズアプリケーションをビルドする時には、 // WinWain ではなくmainをエントリポイントとする。 fn main()-> windows::core::Result<()> { let hInstance:windows::Win32::Foundation::HINSTANCE; unsafe{ // https://github.com/microsoft/windows-samples-rs/blob/master/create_window/src/main.rs hInstance = windows::Win32::System::LibraryLoader::GetModuleHandleA(None).unwrap(); } // https://doc.rust-jp.rs/book-ja/ch12-01-accepting-command-line-arguments.html let args: Vec<String> = env::args().collect(); // https://stackoverflow.com/questions/68322072/how-to-get-args-from-winmain-or-wwinmain-in-rust let mut si = windows::Win32::System::Threading::STARTUPINFOW { cb: std::mem::size_of::<windows::Win32::System::Threading::STARTUPINFOW>() as u32, ..Default::default() }; unsafe { windows::Win32::System::Threading::GetStartupInfoW(&mut si) }; let cmd_show = si.wShowWindow as i32; //////////////////////////////////////////////////////////////////////////////////// // 自作WinMainを呼び出す WinMain( hInstance, windows::Win32::Foundation::HINSTANCE(0), args, cmd_show ); Ok(()) }
use windows::{ core::*, Win32::Foundation::*, Win32::Graphics::Gdi::ValidateRect, Win32::System::LibraryLoader::GetModuleHandleA, Win32::UI::WindowsAndMessaging::*, };
extern "system" fn wndproc(window: HWND, message: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT { unsafe { let rectnullptr: ::core::option::Option<*const windows::Win32::Foundation::RECT> = None; match message as u32 { WM_PAINT => { println!("WM_PAINT"); ValidateRect(window, rectnullptr); LRESULT(0) } WM_DESTROY => { println!("WM_DESTROY"); PostQuitMessage(0); LRESULT(0) } _ => DefWindowProcA(window, message, wparam, lparam), } } }
/// 自作 WinMain pub fn WinMain( hInstance : windows::Win32::Foundation::HINSTANCE, hPrevInstance : windows::Win32::Foundation::HINSTANCE, lpCmdLine:Vec<String>, nCmdShow:i32 )->i32{ unsafe{ let _hCursor = LoadCursorW(None,IDC_ARROW).unwrap(); let _hInstance = hInstance; let _lpszClassName = PCSTR::from_raw("MY_NEW_WINDOW\0".as_ptr()); let _style = CS_HREDRAW | CS_VREDRAW; // https://microsoft.github.io/windows-docs-rs/doc/windows/Win32/UI/WindowsAndMessaging/struct.WNDCLASSA.html let wc=windows::Win32::UI::WindowsAndMessaging::WNDCLASSA{ hCursor :_hCursor, hInstance: _hInstance, lpszClassName: _lpszClassName, style: _style, lpfnWndProc: Some(wndproc), ..Default::default() }; let atom = RegisterClassA(&wc); debug_assert!(atom != 0); let nullptr: ::core::option::Option<*const ::core::ffi::c_void> = None; CreateWindowExA( Default::default(), _lpszClassName, PCSTR::from_raw("This is a sample window\0".as_ptr()), WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, None, None, _hInstance, nullptr, ); let mut message = MSG::default(); while GetMessageA(&mut message, HWND(0), 0, 0).into() { DispatchMessageA(&mut message); } } return 0; }
[package]
name = "rs_win"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
[dependencies.windows]
version = "0.44.0"
# 最新版のバージョンは https://github.com/microsoft/windows-rs で確認
# ・バージョンによってfeaturesを変えなければいけないかもしれない
features = [
"Win32_Graphics_Gdi",
"Win32_Foundation",
"Win32_UI_WindowsAndMessaging",
"Win32_System_LibraryLoader",
"Win32_System_Threading",
]
例えば、WNDCLASSAが見つからずエラーになった場合、まず以下のURLへ飛ぶ。
Required features:
"Win32_UI_WindowsAndMessaging"
,"Win32_Foundation"
,"Win32_Graphics_Gdi"
これらが必要なので、Cargo.tomlに記述する。
features = [
"Win32_Graphics_Gdi",
"Win32_Foundation",
"Win32_UI_WindowsAndMessaging",
]
PCSTR::from_rawを使う。
PCSTR::from_raw("This is a sample window\0".as_ptr()),
Result<>をunwrap()する。
let _hCursor = LoadCursorW(None,IDC_ARROW).unwrap();
::core::option::OptionにNoneを代入
let nullptr: ::core::option::Option<*const ::core::ffi::c_void> = None;
問題はOptionのGeneric<>に何を渡すかで、これは関数定義を素直にコピペするのが一番楽。VSCode関数を右クリックなどして定義へ移動し、該当引数の型をそのまま持ってきてNone代入する。