native-dialog 0.9.6

A library to display dialogs. Supports GNU/Linux, BSD Unix, macOS and Windows.
Documentation
use crate::dialog::{DialogImpl, MessageAlert, MessageConfirm};
use crate::ffi::UnsafeWindowHandle;
use crate::{MessageLevel, Result};

impl MessageAlert {
    fn create(&self) -> MessageBoxParams<'_> {
        MessageBoxParams {
            title: &self.title,
            text: &self.text,
            level: self.level,
            owner: self.owner.clone(),
            ask: false,
        }
    }
}

impl DialogImpl for MessageAlert {
    fn show(self) -> Result<Self::Output> {
        super::process_init();
        message_box(self.create())?;
        Ok(())
    }

    #[cfg(feature = "async")]
    async fn spawn(self) -> Result<Self::Output> {
        self.show()
    }
}

impl MessageConfirm {
    fn create(&self) -> MessageBoxParams<'_> {
        MessageBoxParams {
            title: &self.title,
            text: &self.text,
            level: self.level,
            owner: self.owner.clone(),
            ask: true,
        }
    }
}

impl DialogImpl for MessageConfirm {
    fn show(self) -> Result<Self::Output> {
        super::process_init();
        message_box(self.create())
    }

    #[cfg(feature = "async")]
    async fn spawn(self) -> Result<Self::Output> {
        self.show()
    }
}

pub struct MessageBoxParams<'a> {
    title: &'a str,
    text: &'a str,
    level: MessageLevel,
    owner: UnsafeWindowHandle,
    ask: bool,
}

fn message_box(params: MessageBoxParams) -> Result<bool> {
    use std::ffi::OsStr;
    use std::iter::once;
    use std::os::windows::ffi::OsStrExt;
    use std::ptr::null_mut;

    use winapi::um::winuser::{
        IDYES, MB_ICONERROR, MB_ICONINFORMATION, MB_ICONWARNING, MB_OK, MB_YESNO, MessageBoxW,
    };

    let owner = unsafe { params.owner.as_win32().unwrap_or(null_mut()) };

    let text: Vec<u16> = OsStr::new(params.text)
        .encode_wide()
        .chain(once(0))
        .collect();

    let caption: Vec<u16> = OsStr::new(params.title)
        .encode_wide()
        .chain(once(0))
        .collect();

    let flags_type = if params.ask { MB_YESNO } else { MB_OK };
    let flags_icon = match params.level {
        MessageLevel::Info => MB_ICONINFORMATION,
        MessageLevel::Warning => MB_ICONWARNING,
        MessageLevel::Error => MB_ICONERROR,
    };

    let ret = super::with_visual_styles(|| unsafe {
        MessageBoxW(
            owner,
            text.as_ptr(),
            caption.as_ptr(),
            flags_type | flags_icon,
        )
    });

    match ret {
        0 => Err(std::io::Error::last_os_error().into()),
        x => Ok(x == IDYES),
    }
}