Last active
December 29, 2022 12:10
-
-
Save ruxo/95e186c901d46fe7ee1cc232c1079a7c to your computer and use it in GitHub Desktop.
Rust for Windows Desktop app with Win32
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| [package] | |
| name = "r4w" | |
| 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.43" | |
| features = [ | |
| "Win32_Foundation", | |
| "Win32_System_LibraryLoader", | |
| "Win32_Graphics_Gdi", | |
| "Win32_UI_WindowsAndMessaging", | |
| ] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #![windows_subsystem = "windows"] | |
| mod winui; | |
| mod simple_window; | |
| use windows::core::Result; | |
| fn main() -> Result<()> { | |
| simple_window::sample() | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| use windows::{ | |
| core::*, | |
| Win32::Graphics::Gdi::*, | |
| }; | |
| use windows::Win32::Foundation::{ HWND, LPARAM, LRESULT, WPARAM}; | |
| use windows::Win32::UI::WindowsAndMessaging::*; | |
| use crate::winui; | |
| pub fn sample() -> Result<()> { | |
| unsafe { | |
| let instance = winui::get_process_instance()?; | |
| let window_class = s!("Rux Window"); | |
| let wc = WNDCLASSA { | |
| hCursor: LoadCursorW(None, IDC_ARROW)?, | |
| hInstance: instance, | |
| lpszClassName: window_class, | |
| style: CS_HREDRAW | CS_VREDRAW, | |
| lpfnWndProc: Some(wndproc), | |
| ..Default::default() | |
| }; | |
| RegisterClassA(&wc); | |
| CreateWindowExA( | |
| WINDOW_EX_STYLE::default(), | |
| window_class, | |
| s!("A sample window"), | |
| WS_OVERLAPPEDWINDOW | WS_VISIBLE, | |
| CW_USEDEFAULT, CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT, | |
| None, None, instance, None | |
| ); | |
| let mut message = MSG::default(); | |
| let all_windows = HWND(0); | |
| while GetMessageA(&mut message, all_windows, 0, 0).into() { | |
| TranslateMessage(&message); | |
| DispatchMessageA(&message); | |
| } | |
| } | |
| Ok(()) | |
| } | |
| extern "system" fn wndproc(window :HWND, message :u32, wparam :WPARAM, lparam :LPARAM) -> LRESULT { | |
| unsafe { | |
| match message { | |
| WM_PAINT => { | |
| let mut ps = Default::default(); | |
| let hdc = BeginPaint(window, &mut ps); | |
| FillRect(hdc, &ps.rcPaint, HBRUSH((COLOR_WINDOW.0 + 1) as isize)); | |
| EndPaint(window, &ps); | |
| LRESULT(0) | |
| }, | |
| WM_DESTROY => { | |
| println!("WM_DESTROY"); | |
| PostQuitMessage(0); | |
| LRESULT(0) | |
| }, | |
| _ => DefWindowProcA(window, message, wparam, lparam), | |
| } | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| use windows::core::{Error, HRESULT, HSTRING, Result}; | |
| use windows::Win32::Foundation::{GetLastError, HINSTANCE, HWND, BOOL}; | |
| use windows::Win32::System::LibraryLoader::GetModuleHandleA; | |
| pub trait HandleValid { | |
| fn is_valid(&self) -> bool; | |
| } | |
| pub trait HandleValidation<T> where T: HandleValid { | |
| fn validate(self) -> Result<T>; | |
| fn validate_and_ignore(self) -> Result<()>; | |
| } | |
| impl HandleValid for HINSTANCE { | |
| #[inline(always)] | |
| fn is_valid(&self) -> bool { self.0 != 0 } | |
| } | |
| impl HandleValid for HWND { | |
| #[inline(always)] | |
| fn is_valid(&self) -> bool { self.0 != 0 } | |
| } | |
| impl HandleValid for u16 { | |
| #[inline(always)] | |
| fn is_valid(&self) -> bool { *self != 0 } | |
| } | |
| impl HandleValid for BOOL { | |
| #[inline(always)] | |
| fn is_valid(&self) -> bool { self.0 != 0 } | |
| } | |
| impl<T> HandleValidation<T> for Result<T> where T: HandleValid { | |
| fn validate(self) -> Result<T> { | |
| self.and_then(|inner| { | |
| if inner.is_valid() { Ok(inner) } else { | |
| let last_error = unsafe { GetLastError().0 }; | |
| Err(Error::new(HRESULT(-1), HSTRING::from(format!("Invalid Handle ({last_error})!")))) | |
| } | |
| }) | |
| } | |
| #[inline(always)] | |
| fn validate_and_ignore(self) -> Result<()> { self.validate().map(|_| {}) } | |
| } | |
| impl<T> HandleValidation<T> for T where T: HandleValid { | |
| #[inline(always)] | |
| fn validate(self) -> Result<T> { Ok(self).validate() } | |
| #[inline(always)] | |
| fn validate_and_ignore(self) -> Result<()> { self.validate().map(|_| {}) } | |
| } | |
| pub unsafe fn get_process_instance() -> Result<HINSTANCE> { GetModuleHandleA(None).validate() } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment