Windows API and GUI in safe, idiomatic Rust.
WinSafe has:
- high-level structs to build native Win32 GUI applications;
- low-level Win32 API constants, functions and structs related to GUI.
If you're looking for a comprehensive Win32 coverage, take a look at winapi or windows crates, which are unsafe, but have everything.
WinSafe documentation:
- stable release: docs.rs/winsafe
- master branch: rodrigocfd.github.io/winsafe/winsafe
This crate is still in alpha stage. Below is an estimated progress of feature groups:
Feature group | Estimated progress |
---|---|
User windows (main, modal and control) | |
Native controls | |
Window messages | |
Overall Win32 APIs |
Add the dependency in your Cargo.toml
:
[dependencies]
winsafe = { version = "0.0.9", features = [] }
Then you must enable the Cargo features you want to be included – these modules are named after native Windows DLL and library names, mostly.
The following Cargo features are available so far:
Feature | Description |
---|---|
advapi |
Advapi32.dll, for Windows Registry |
comctl |
ComCtl32.dll, for Common Controls |
comdlg |
ComDlg32.dll, for the old Common Dialogs |
dshow |
DirectShow |
gdi |
Gdi32.dll, the Windows GDI |
gui |
The WinSafe high-level GUI structs |
kernel |
Kernel32.dll, all others will include it |
msimg |
Msimg32.dll |
ole |
OLE and basic COM support |
oleaut |
OLE Automation |
shell |
Shell32.dll, the COM-based Windows Shell |
shlwapi |
Shlwapi.dll, for some Shell functions |
user |
User32.dll, the basic Windows GUI support |
uxtheme |
UxTheme.dll, extended window theming |
version |
Version.dll, to manipulate *.exe version info |
Note that a Cargo feature may depend on other features, which will be enabled automatically.
Note: You can find several examples in the dedicated repo: github.com/rodrigocfd/winsafe-examples
WinSafe allows you to create windows in two ways:
- programmatically defining parameters; or
- loading dialogs from a
.res
file created with a WYSIWYG resource editor.
The example below creates a window with a button programmatically. Note how the click event is handled with a closure:
[dependencies]
winsafe = { version = "0.0.9", features = ["gui"] }
#![windows_subsystem = "windows"]
use winsafe::prelude::*;
use winsafe::{gui, POINT, SIZE, WinResult};
fn main() {
let my = MyWindow::new(); // instantiate our main window
if let Err(e) = my.wnd.run_main(None) { // ... and run it
eprintln!("{}", e);
}
}
#[derive(Clone)]
pub struct MyWindow {
wnd: gui::WindowMain, // responsible for managing the window
btn_hello: gui::Button, // a button
}
impl MyWindow {
pub fn new() -> MyWindow {
let wnd = gui::WindowMain::new( // instantiate the window manager
gui::WindowMainOpts {
title: "My window title".to_owned(),
size: SIZE::new(300, 150),
..Default::default() // leave all other options as default
},
);
let btn_hello = gui::Button::new(
&wnd, // the window manager is the parent of our button
gui::ButtonOpts {
text: "&Click me".to_owned(),
position: POINT::new(20, 20),
..Default::default()
},
);
let new_self = Self { wnd, btn_hello };
new_self.events(); // attach our events
new_self
}
fn events(&self) {
self.btn_hello.on().bn_clicked({
let wnd = self.wnd.clone(); // clone so it can be passed into the closure
move || {
wnd.hwnd().SetWindowText("Hello, world!")?;
Ok(())
}
});
}
}
Licensed under MIT license, see LICENSE.md for details.