CreateDIBSectionを使ってDIBを作り、CreateCompatibleDCを使って描画してみる。
各関数・データ型・定数がwindows-rsのどこにあるかさえわかれば、あとはそこまで難しくはない。
一番厄介なのはwinmain.rs内でmydibのインスタンスであるグローバル変数で、これはstatic + Lazy + Mutexで実現しないといけない。
use windows::Win32::Graphics::Gdi::*; use windows::core::*; use windows::Win32::Foundation::*; // ■ BITMAPINFO ... windows::Win32::Graphics::Gdi::BITMAPINFO // ■ BITMAPINFOHEADER ... windows::Win32::Graphics::Gdi::BITMAPINFOHEADER // ■ BI_RGB ... windows::Win32::Graphics::Gdi::BI_RGB // ■ CreatedHDC ... windows::Win32::Graphics::Gdi::CreatedHDC // ■ CreateDCA ... windows::Win32::Graphics::Gdi::CreateDCA // ■ CreateCompatibleDC ... windows::Win32::Graphics::Gdi::CreateCompatibleDC // ■ CreateDIBSection ... windows::Win32::Graphics::Gdi::CreateDIBSection // ■ DIB_RGB_COLORS ... windows::Win32::Graphics::Gdi::DIB_RGB_COLORS // ■ DeleteDC ... windows::Win32::Graphics::Gdi::DeleteDC // ■ HBITMAP ... windows::Win32::Graphics::Gdi::HBITMAP // ■ HBITMAP ... windows::Win32::Graphics::Gdi::HBITMAP // ■ SelectObject ... windows::Win32::Graphics::Gdi::SelectObject // ■ HANDLE ... windows::Win32::Foundation::HANDLE // ■ PCSTR ... windows::core::PCSTR pub struct Win32DIBCanvas{ pub bitmap :HBITMAP, pub bitmapInfo :BITMAPINFO, pub ppixel :*mut std::ffi::c_void, pub hMemDC : CreatedHDC, } // ppixel:*mut std::ffi::c_void, があるので、Send,Syncを実装しなければmyDIBをLazy<Mutex<myDIB>>に入れられない unsafe impl Send for Win32DIBCanvas {} unsafe impl Sync for Win32DIBCanvas {} impl Win32DIBCanvas{ pub fn new()->Win32DIBCanvas{ Win32DIBCanvas{ bitmap :HBITMAP(0), bitmapInfo:Default::default(), ppixel :std::ptr::null_mut(), hMemDC :CreatedHDC(0), } } pub fn create(&mut self,width:i32,height:i32){ unsafe{ let mut hdca = CreateDCA( PCSTR::from_raw("DISPLAY\0".as_ptr()), None, None, None ); self.bitmapInfo.bmiHeader.biSize = std::mem::size_of::<BITMAPINFOHEADER>() as u32; self.bitmapInfo.bmiHeader.biWidth = width; self.bitmapInfo.bmiHeader.biHeight = -height; self.bitmapInfo.bmiHeader.biPlanes = 1; self.bitmapInfo.bmiHeader.biBitCount = 3*8; self.bitmapInfo.bmiHeader.biCompression = BI_RGB; let hBitmap = CreateDIBSection( hdca, &self.bitmapInfo, DIB_RGB_COLORS, &mut self.ppixel, HANDLE(0), 0 ); self.hMemDC = CreateCompatibleDC(hdca); if let Ok(hbmp) = hBitmap{ SelectObject(self.hMemDC,hbmp); } DeleteDC(hdca); } } }
main関数。CではWinMain開始だが、Rustではwindowsプログラムもmainから始める。
気分的にWinMainが欲しいので、main関数からWinMainを呼ぶようにしている。
mod winmain; use winmain::WinMain; use windows::Win32::Foundation::*; use windows::Win32::System::LibraryLoader::*; use windows::Win32::System::Threading::*; // ■ HINSTANCE ... windows::Win32::Foundation::HINSTANCE // ■ GetModuleHandleA ... windows::Win32::System::LibraryLoader::GetModuleHandleA // ■ STARTUPINFOW ... windows::Win32::System::Threading::STARTUPINFOW // ■ GetStartupInfoW ... windows::Win32::System::Threading::GetStartupInfoW // Rustのwindows-rsからウィンドウズアプリケーションをビルドする時には、 // WinWain ではなくmainをエントリポイントとする。 fn main()-> windows::core::Result<()> { let hInstance:HINSTANCE; unsafe{ // https://github.com/microsoft/windows-samples-rs/blob/master/create_window/src/main.rs hInstance = GetModuleHandleA(None).unwrap(); } // https://doc.rust-jp.rs/book-ja/ch12-01-accepting-command-line-arguments.html let args: Vec<String> = std::env::args().collect(); // https://stackoverflow.com/questions/68322072/how-to-get-args-from-winmain-or-wwinmain-in-rust let mut si = STARTUPINFOW { cb: std::mem::size_of::<STARTUPINFOW>() as u32, ..Default::default() }; unsafe { GetStartupInfoW(&mut si) }; let cmd_show = si.wShowWindow as i32; //////////////////////////////////////////////////////////////////////////////////// // 自作WinMainを呼び出す WinMain( hInstance, HINSTANCE(0), args, cmd_show ); Ok(()) }
#[path="./win32dib.rs"] mod win32dib; use win32dib::Win32DIBCanvas; use windows::{ core::*, Win32::Foundation::*, Win32::Graphics::Gdi::*, Win32::UI::WindowsAndMessaging::*, }; use once_cell::sync::Lazy; use std::sync::Mutex; // ■ Mutex ... std::sync::Mutex // ■ Lazy ... once_cell::sync::Lazy // DIBを管理する構造体のグローバル変数 static mydib:Lazy<Mutex<Win32DIBCanvas>> = Lazy::new(|| Mutex::new( Win32DIBCanvas::new() ) ); // ■ COLORREF ... windows::Win32::Foundation::COLORREF // ■ HINSTANCE ... windows::Win32::Foundation::HINSTANCE // ■ HWND ... windows::Win32::Foundation::HWND // ■ LPARAM ... windows::Win32::Foundation::LPARAM // ■ LRESULT ... windows::Win32::Foundation::LRESULT // ■ POINT ... windows::Win32::Foundation::POINT // ■ RECT ... windows::Win32::Foundation::RECT // ■ WPARAM ... windows::Win32::Foundation::WPARAM // ■ BeginPaint ... windows::Win32::Graphics::Gdi::BeginPaint // ■ BitBlt ... windows::Win32::Graphics::Gdi::BitBlt // ■ CreatePen ... windows::Win32::Graphics::Gdi::CreatePen // ■ EndPaint ... windows::Win32::Graphics::Gdi::EndPaint // ■ LineTo ... windows::Win32::Graphics::Gdi::LineTo // ■ MoveToEx ... windows::Win32::Graphics::Gdi::MoveToEx // ■ PS_SOLID ... windows::Win32::Graphics::Gdi::PS_SOLID // ■ PAINTSTRUCT ... windows::Win32::Graphics::Gdi::PAINTSTRUCT // ■ SelectObject ... windows::Win32::Graphics::Gdi::SelectObject // ■ SRCCOPY ... windows::Win32::Graphics::Gdi::SRCCOPY // ■ CreateWindowExA ... windows::Win32::UI::WindowsAndMessaging::CreateWindowExA // ■ CS_HREDRAW ... windows::Win32::UI::WindowsAndMessaging::CS_HREDRAW // ■ CS_VREDRAW ... windows::Win32::UI::WindowsAndMessaging::CS_VREDRAW // ■ CW_USEDEFAULT ... windows::Win32::UI::WindowsAndMessaging::CW_USEDEFAULT // ■ DefWindowProcA ... windows::Win32::UI::WindowsAndMessaging::DefWindowProcA // ■ DispatchMessageA ... windows::Win32::UI::WindowsAndMessaging::DispatchMessageA // ■ GetMessageA ... windows::Win32::UI::WindowsAndMessaging::GetMessageA // ■ LoadCursorW ... windows::Win32::UI::WindowsAndMessaging::LoadCursorW // ■ IDC_ARROW ... windows::Win32::UI::WindowsAndMessaging::IDC_ARROW // ■ MSG ... windows::Win32::UI::WindowsAndMessaging::MSG // ■ PostQuitMessage ... windows::Win32::UI::WindowsAndMessaging::PostQuitMessage // ■ RegisterClassA ... windows::Win32::UI::WindowsAndMessaging::RegisterClassA // ■ WNDCLASSA ... windows::Win32::UI::WindowsAndMessaging::WNDCLASSA // ■ WS_OVERLAPPEDWINDOW ... windows::Win32::UI::WindowsAndMessaging::WS_OVERLAPPEDWINDOW // ■ WS_VISIBLE ... windows::Win32::UI::WindowsAndMessaging::WS_VISIBLE // ■ PCSTR ... windows::core::PCSTR extern "system" fn wndproc(window: HWND, message: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT { unsafe { let rectnullptr: Option<*const RECT> = None; match message as u32 { WM_CREATE => { let refmydib = &mut mydib.lock().unwrap(); refmydib.create(640,480); let hPen = CreatePen( PS_SOLID, 1, COLORREF(0x000000FF) ); // 赤いペンを作成 if hPen.is_invalid() == false{ // ペンが作成できていたら線を引く let oldPen = SelectObject( refmydib.hMemDC, hPen ); // refmydib.hMemDC の 50,50 ~ 100,100 に線を引く MoveToEx( refmydib.hMemDC, 50, 50, None as Option<*mut POINT> ); LineTo( refmydib.hMemDC, 100, 100 ); SelectObject( refmydib.hMemDC, oldPen ); // ペンを削除 DeleteObject(hPen); } LRESULT(0) } WM_PAINT => { let mut ps = PAINTSTRUCT::default(); let hdc = BeginPaint(window, &mut ps); let refmydib = &mut mydib.lock().unwrap(); BitBlt( hdc, 0, 0, 640, 480, refmydib.hMemDC, 0, 0, SRCCOPY ); EndPaint(window, &ps); LRESULT(0) } WM_DESTROY => { PostQuitMessage(0); LRESULT(0) } _ => DefWindowProcA(window, message, wparam, lparam), } } } /// 自作 WinMain pub fn WinMain( hInstance : HINSTANCE, hPrevInstance : 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=WNDCLASSA{ hCursor :_hCursor, hInstance: _hInstance, lpszClassName: _lpszClassName, style: _style, lpfnWndProc: Some(wndproc), ..Default::default() }; let atom = RegisterClassA(&wc); debug_assert!(atom != 0); let nullptr: 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; }