Skip to content

Instantly share code, notes, and snippets.

@ruxo
Last active December 29, 2022 12:10
Show Gist options
  • Select an option

  • Save ruxo/95e186c901d46fe7ee1cc232c1079a7c to your computer and use it in GitHub Desktop.

Select an option

Save ruxo/95e186c901d46fe7ee1cc232c1079a7c to your computer and use it in GitHub Desktop.
Rust for Windows Desktop app with Win32
[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",
]
#![windows_subsystem = "windows"]
mod winui;
mod simple_window;
use windows::core::Result;
fn main() -> Result<()> {
simple_window::sample()
}
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),
}
}
}
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