Windows API and GUI in safe, idiomatic Rust

20 releases

0.0.20 Mar 1, 2024
0.0.18 Oct 1, 2023
0.0.17 Jul 1, 2023
0.0.14 Mar 1, 2023
0.0.1 Oct 28, 2019

#11 in Windows APIs

Download history 32/week @ 2023-12-22 136/week @ 2023-12-29 266/week @ 2024-01-05 310/week @ 2024-01-12 481/week @ 2024-01-19 483/week @ 2024-01-26 304/week @ 2024-02-02 304/week @ 2024-02-09 286/week @ 2024-02-16 253/week @ 2024-02-23 452/week @ 2024-03-01 381/week @ 2024-03-08 389/week @ 2024-03-15 17267/week @ 2024-03-22 17441/week @ 2024-03-29 16794/week @ 2024-04-05

51,959 downloads per month
Used in 213 crates (5 directly)

MIT license

63K SLoC


Crates.io Docs.rs Lines of code License: MIT

Windows API and GUI in safe, idiomatic Rust.

WinSafe has:

  • low-level Win32 API constants, functions and structs;
  • high-level structs to build native Win32 GUI applications.

WinSafe documentation:

Branch Docs
Stable docs.rs/winsafe
Nightly (master) rodrigocfd.github.io/winsafe/winsafe

Current status

Native FFI items implemented:

Native FFI item Count
Functions 755
Structs 231
Constants 13,331
Window messages 651
Handles 45
COM interfaces 82
COM methods 450

High-level GUI controls:

  • User custom window/dialog – main, modal, modeless, control, message-only.
  • Native controls – button, check box, combo box, date and time picker, edit, header, label, list box, list view, month calendar, progress bar, radio button, status bar, tab, track bar, tree view, up down.


Add the dependency in your Cargo.toml:

winsafe = { version = "0.0.20", features = [] }

You can, alternatively, use the Nightly (master) branch directly, to get the latest features right away:

winsafe = { git = "https://github.com/rodrigocfd/winsafe", 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
comctl ComCtl32.dll, for Common Controls
dshow DirectShow
dwm Dwmapi.dll, the Desktop Window Manager
dxgi DirectX Graphics Infrastructure
gdi Gdi32.dll, the Windows GDI
gui The WinSafe high-level GUI abstractions
kernel Kernel32.dll, Advapi32.dll and Ktmw32.dll – all others will include it
mf Media Foundation
ole OLE and basic COM support
oleaut OLE Automation
shell Shell32.dll, Shlwapi.dll, and Userenv.dll, the COM-based Windows Shell
taskschd Task Scheduler
user User32.dll and ComDlg32.dll, the basic Windows GUI support
uxtheme UxTheme.dll, extended window theming
version Version.dll, to manipulate *.exe version info

Although WinSafe already has a lot of Win32 APIs, it doesn't have everything, simply because Win32 API is gigantic. So if you're looking for a comprehensive Win32 coverage, take a look at winapi or windows crates, which are unsafe, but have everything.


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:

Example 01

winsafe = { version = "0.0.20", features = ["gui"] }
#![windows_subsystem = "windows"]

use winsafe::{self as w, prelude::*, gui};

fn main() {
    let my = MyWindow::new(); // instantiate our main window
    if let Err(e) = my.wnd.run_main(None) { // ... and run it
        eprintln!("{}", e);

pub struct MyWindow {
    wnd:       gui::WindowMain, // responsible for managing the window
    btn_hello: gui::Button,     // a button

impl MyWindow {
    pub fn new() -> Self {
        let wnd = gui::WindowMain::new( // instantiate the window manager
            gui::WindowMainOpts {
                title: "My window title".to_owned(),
                size: (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: (20, 20),

        let new_self = Self { wnd, btn_hello };
        new_self.events(); // attach our events

    fn events(&self) {
        let wnd = self.wnd.clone(); // clone so it can be passed into the closure
        self.btn_hello.on().bn_clicked(move || {
            wnd.hwnd().SetWindowText("Hello, world!")?;


Licensed under MIT license, see LICENSE.md for details.

No runtime deps