zero-dialog 0.1.0

Ultra-lightweight, dependency-free system dialog library.
Documentation
use std::ffi::OsStr;
use std::os::windows::ffi::OsStrExt;

use crate::{ButtonKind, Error, IconKind, Response};

// Flags for MessageBoxW
//   https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-messageboxw
type HWND = isize;
type LPCWSTR = *const u16;

// Link to user32 library
#[link(name = "user32")]
unsafe extern "system" {
    unsafe fn MessageBoxW(hWnd: HWND, text: LPCWSTR, caption: LPCWSTR, r#type: u32) -> i32;
}

// Win32 constants
const MB_OK: u32 = 0x00000000;
const MB_OKCANCEL: u32 = 0x00000001;
const MB_ICONINFORMATION: u32 = 0x00000040;
const MB_ICONWARNING: u32 = 0x00000030;
const MB_ICONQUESTION: u32 = 0x00000020;
const MB_ICONERROR: u32 = 0x00000010;

const IDCANCEL: u32 = 2;
const IDOK: u32 = 1;

/// Convert `IconKind` to MessageBox icon
fn to_win32_icon(icon: IconKind) -> u32 {
    match icon {
        IconKind::Info => MB_ICONINFORMATION,
        IconKind::Warning => MB_ICONWARNING,
        IconKind::Error => MB_ICONERROR,
        IconKind::Question => MB_ICONQUESTION,
    }
}

/// Convert `ButtonKind` to MessageBox button
fn to_win32_buttons(btn: ButtonKind) -> u32 {
    match btn {
        ButtonKind::Ok => MB_OK,
        ButtonKind::OkCancel => MB_OKCANCEL,
    }
}

pub fn win32_show_dialog(
    title: &str,
    message: &str,
    icon: IconKind,
    btn: ButtonKind,
) -> Result<Response, Error> {
    let title: Vec<u16> = OsStr::new(title).encode_wide().chain(Some(0)).collect();
    let message: Vec<u16> = OsStr::new(message).encode_wide().chain(Some(0)).collect();

    unsafe {
        let result = MessageBoxW(
            0, // NULL hWnd
            message.as_ptr(),
            title.as_ptr(),
            to_win32_icon(icon) | to_win32_buttons(btn),
        ) as std::ffi::c_int;

        match result as u32 {
            IDOK => Ok(Response::Ok),
            IDCANCEL => Ok(Response::Cancel),
            _ => Ok(Response::None),
        }
    }
}