Skip to content

Commit

Permalink
HIcon
Browse files Browse the repository at this point in the history
  • Loading branch information
MaulingMonkey committed Jan 3, 2024
1 parent acb1c91 commit 1cf0245
Show file tree
Hide file tree
Showing 9 changed files with 159 additions and 20 deletions.
4 changes: 4 additions & 0 deletions crates/xtask/src/bin/gen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ mod natvis {
writeln!(nv, r#" <Type Name="hwnd::shared::windef::handles::hcursor::HCursor">"#)?;
writeln!(nv, r#" <DisplayString>HCursor({{__0,X}})</DisplayString>"#)?;
writeln!(nv, r#" </Type>"#)?;
writeln!(nv)?;
writeln!(nv, r#" <Type Name="hwnd::shared::windef::handles::hicon::HIcon">"#)?;
writeln!(nv, r#" <DisplayString>HIcon({{__0,X}})</DisplayString>"#)?;
writeln!(nv, r#" </Type>"#)?;

writeln!(nv)?;
writeln!(nv, r#" <Type Name="hwnd::um::winuser::enums::WM::WM16">"#)?; // doesn't exist yet
Expand Down
2 changes: 2 additions & 0 deletions examples/hello-world.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,13 @@ fn main() {
fn main_imp() -> i32 {
let hinstance = get_module_handle_entry_exe().unwrap();
let hcursor = load_cursor_w(None, IDC::ARROW).unwrap();
let hicon = load_icon_w(None, IDI::APPLICATION).unwrap();

let wc = WndClassW {
wnd_proc: Some(window_proc),
hinstance,
hcursor,
hicon,
class_name: cstr16!("SampleWndClass").into(),
.. WndClassW::zeroed()
};
Expand Down
4 changes: 4 additions & 0 deletions hwnd.natvis
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
<DisplayString>HCursor({__0,X})</DisplayString>
</Type>

<Type Name="hwnd::shared::windef::handles::hicon::HIcon">
<DisplayString>HIcon({__0,X})</DisplayString>
</Type>

<Type Name="hwnd::um::winuser::enums::WM::WM16">
<DisplayString>{__0,wm}</DisplayString>
</Type>
Expand Down
3 changes: 3 additions & 0 deletions src/_lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ mods! {
pub mod windef {
inl mod handles {
inl mod hcursor;
inl mod hicon;
inl mod hwnd_;
}

Expand Down Expand Up @@ -94,6 +95,7 @@ mods! {
pub mod GWL;
pub mod GWLP;
pub mod IDC;
pub mod IDI;
pub mod SW;
pub mod WM;
}
Expand Down Expand Up @@ -127,6 +129,7 @@ mods! {
inl mod in_send_message_;
inl mod is;
inl mod load_cursor;
inl mod load_icon;
inl mod peek_message;
inl mod post_message;
inl mod register_class_;
Expand Down
26 changes: 26 additions & 0 deletions src/shared/windef/handles/hicon.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
use crate::*;
use bytemuck::*;
use std::fmt::{self, Debug, Formatter};
use std::marker::PhantomData;



/// \[[docs.microsoft.com](https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-loadiconw)\]
/// HICON
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[derive(Default)]
pub struct HIcon<'a>(usize, PhantomData<&'a ()>);

impl HIcon<'_> {
/// ### Safety
/// * `hicon` must currently be valid or null
/// * `hicon` must outlive `'_`
pub unsafe fn from_unchecked(hicon: HICON) -> Self { Self(hicon as _, PhantomData) }
}

unsafe impl Zeroable for HIcon<'_> {}

impl From<HIcon<'_>> for HICON { fn from(c: HIcon) -> Self { c.0 as _ } }
impl From<()> for HIcon<'_> { fn from(_: ()) -> Self { Self(0, PhantomData) } }

impl Debug for HIcon<'_> { fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { write!(fmt, "HIcon(0x{:X})", self.0) } }
20 changes: 20 additions & 0 deletions src/um/winuser/enums/IDI.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//! \[[docs.microsoft.com](https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-loadicona)\]
//! IDI_\* flags for [load_icon_w]
#![allow(non_snake_case)]

use crate::*;



// XXX: is Atom sufficient typing?
pub const APPLICATION : Atom = Atom(32512);
pub const HAND : Atom = Atom(32513);
pub const QUESTION : Atom = Atom(32514);
pub const EXCLAMATION : Atom = Atom(32515);
pub const ASTERISK : Atom = Atom(32516);
pub const WINLOGO : Atom = Atom(32517); // WINVER >= 0x0400
pub const SHIELD : Atom = Atom(32518); // WINVER >= 0x0600

pub const WARNING : Atom = self::EXCLAMATION; // WINVER >= 0x0400
pub const ERROR : Atom = self::HAND; // WINVER >= 0x0400
pub const INFORMATION : Atom = self::ASTERISK; // WINVER >= 0x0400
34 changes: 20 additions & 14 deletions src/um/winuser/functions/load_cursor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ use winapi::um::winuser::*;
/// Loads a cursor, animated cursor, or bitmap.
///
/// ### Errors
/// * [ERROR::RESOURCE_NAME_NOT_FOUND] if `cursor_name` cannot be found for `hinstance`
/// * [ERROR::RESOURCE_DATA_NOT_FOUND] if `cursor_name` cannot be found for the system, and is an integer resource (e.g. `hinstance` is `None`)
/// * [ERROR::RESOURCE_DATA_NOT_FOUND] if `cursor_name` cannot be found for `Some(hinstance)`
/// * [ERROR::RESOURCE_NAME_NOT_FOUND] if `cursor_name` cannot be found for the system (e.g. `hinstance` is `None`)
/// * ~~[ERROR::RESOURCE_TYPE_NOT_FOUND]~~ never? (returned instead of [ERROR::RESOURCE_NAME_NOT_FOUND] by [load_icon_a])
///
/// ### Example
/// ```rust
Expand All @@ -20,14 +21,16 @@ use winapi::um::winuser::*;
/// let idc_arrow = load_cursor_a(None, IDC::ARROW).unwrap();
///
/// let exe = get_module_handle_entry_exe().unwrap();
/// assert_eq!(ERROR::RESOURCE_NAME_NOT_FOUND, load_cursor_a(None, 42).unwrap_err());
/// assert_eq!(ERROR::RESOURCE_DATA_NOT_FOUND, load_cursor_a(exe, 42).unwrap_err());
/// assert_eq!(ERROR::RESOURCE_NAME_NOT_FOUND, load_cursor_a(None, cstr!("nonexistant")).unwrap_err());
/// assert_eq!(ERROR::RESOURCE_DATA_NOT_FOUND, load_cursor_a(exe, cstr!("nonexistant")).unwrap_err());
/// assert_eq!(ERROR::RESOURCE_NAME_NOT_FOUND, load_cursor_a(None, IDI::WINLOGO).unwrap_err(), "icon-only atom to load_cursor");
/// assert_eq!(ERROR::RESOURCE_NAME_NOT_FOUND, load_cursor_a(None, 42).unwrap_err(), "(None, 42)");
/// assert_eq!(ERROR::RESOURCE_DATA_NOT_FOUND, load_cursor_a(exe, 42).unwrap_err(), "(exe, 42)");
/// assert_eq!(ERROR::RESOURCE_NAME_NOT_FOUND, load_cursor_a(None, cstr!("nonexistant")).unwrap_err(), "(None, \"nonexistant\")");
/// assert_eq!(ERROR::RESOURCE_DATA_NOT_FOUND, load_cursor_a(exe, cstr!("nonexistant")).unwrap_err(), "(exe, \"nonexistant\")");
/// ```
///
/// ### See Also
/// * [load_cursor_w]
/// * [load_cursor_w] &mdash; wide equivalent
/// * [load_icon_a] &mdash; icon equivalent
pub fn load_cursor_a<'h, 't>(hinstance: impl Into<HInstance<'h>>, cursor_name: impl Into<NameAtomOrZero<'t, u8>>) -> Result<HCursor<'h>, Error> {
fn_context!(load_cursor_a => LoadCursorA);
let hcursor = unsafe { LoadCursorA(hinstance.into().into(), cursor_name.into().as_atom_or_cstr_ptr()) };
Expand All @@ -41,8 +44,9 @@ pub fn load_cursor_a<'h, 't>(hinstance: impl Into<HInstance<'h>>, cursor_name: i
/// Loads a cursor, animated cursor, or bitmap.
///
/// ### Errors
/// * [ERROR::RESOURCE_DATA_NOT_FOUND] if `cursor_name` cannot be found for the system (e.g. `hinstance` is `None`)
/// * [ERROR::RESOURCE_NAME_NOT_FOUND] if `cursor_name` cannot be found for `hinstance`
/// * [ERROR::RESOURCE_DATA_NOT_FOUND] if `cursor_name` cannot be found for `Some(hinstance)`
/// * [ERROR::RESOURCE_NAME_NOT_FOUND] if `cursor_name` cannot be found for the system (e.g. `hinstance` is `None`)
/// * ~~[ERROR::RESOURCE_TYPE_NOT_FOUND]~~ never? (returned instead of [ERROR::RESOURCE_NAME_NOT_FOUND] by [load_icon_w])
///
/// ### Example
/// ```rust
Expand All @@ -52,14 +56,16 @@ pub fn load_cursor_a<'h, 't>(hinstance: impl Into<HInstance<'h>>, cursor_name: i
/// let idc_arrow = load_cursor_w(None, IDC::ARROW).unwrap();
///
/// let exe = get_module_handle_entry_exe().unwrap();
/// assert_eq!(ERROR::RESOURCE_NAME_NOT_FOUND, load_cursor_w(None, 42).unwrap_err());
/// assert_eq!(ERROR::RESOURCE_DATA_NOT_FOUND, load_cursor_w(exe, 42).unwrap_err());
/// assert_eq!(ERROR::RESOURCE_NAME_NOT_FOUND, load_cursor_w(None, cstr16!("nonexistant")).unwrap_err());
/// assert_eq!(ERROR::RESOURCE_DATA_NOT_FOUND, load_cursor_w(exe, cstr16!("nonexistant")).unwrap_err());
/// assert_eq!(ERROR::RESOURCE_NAME_NOT_FOUND, load_cursor_w(None, IDI::WINLOGO).unwrap_err(), "icon-only atom to load_cursor");
/// assert_eq!(ERROR::RESOURCE_NAME_NOT_FOUND, load_cursor_w(None, 42).unwrap_err(), "(None, 42)");
/// assert_eq!(ERROR::RESOURCE_DATA_NOT_FOUND, load_cursor_w(exe, 42).unwrap_err(), "(exe, 42)");
/// assert_eq!(ERROR::RESOURCE_NAME_NOT_FOUND, load_cursor_w(None, cstr16!("nonexistant")).unwrap_err(), "(None, \"nonexistant\")");
/// assert_eq!(ERROR::RESOURCE_DATA_NOT_FOUND, load_cursor_w(exe, cstr16!("nonexistant")).unwrap_err(), "(exe, \"nonexistant\")");
/// ```
///
/// ### See Also
/// * [load_cursor_a]
/// * [load_cursor_a] &mdash; narrow equivalent
/// * [load_icon_w] &mdash; icon equivalent
pub fn load_cursor_w<'h, 't>(hinstance: impl Into<HInstance<'h>>, cursor_name: impl Into<NameAtomOrZero<'t, u16>>) -> Result<HCursor<'h>, Error> {
fn_context!(load_cursor_w => LoadCursorW);
let hcursor = unsafe { LoadCursorW(hinstance.into().into(), cursor_name.into().as_atom_or_cstr_ptr()) };
Expand Down
74 changes: 74 additions & 0 deletions src/um/winuser/functions/load_icon.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
use crate::*;
use winapi::um::winuser::*;



/// \[[docs.microsoft.com](https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-loadicona)\]
/// LoadIconA
///
/// Loads an icon, animated icon, or bitmap.
///
/// ### Errors
/// * [ERROR::RESOURCE_DATA_NOT_FOUND] if `icon_name` cannot be found for `Some(hinstance)`
/// * ~~[ERROR::RESOURCE_NAME_NOT_FOUND]~~ never? (returned by [load_cursor_a])
/// * [ERROR::RESOURCE_TYPE_NOT_FOUND] if `icon_name` cannot be found for the system (e.g. `hinstance` is `None`)
///
/// ### Example
/// ```rust
/// # use abistr::*;
/// # use hwnd::*;
/// # use winresult::*;
/// let idi_error = load_icon_a(None, IDI::ERROR).unwrap();
///
/// let exe = get_module_handle_entry_exe().unwrap();
/// assert_eq!(ERROR::RESOURCE_TYPE_NOT_FOUND, load_icon_a(None, IDC::SIZE).unwrap_err(), "cursor-only atom to load_icon");
/// assert_eq!(ERROR::RESOURCE_TYPE_NOT_FOUND, load_icon_a(None, 42).unwrap_err(), "(None, 42)");
/// assert_eq!(ERROR::RESOURCE_DATA_NOT_FOUND, load_icon_a(exe, 42).unwrap_err(), "(exe, 42)");
/// assert_eq!(ERROR::RESOURCE_TYPE_NOT_FOUND, load_icon_a(None, cstr!("nonexistant")).unwrap_err(), "(None, \"nonexistant\")");
/// assert_eq!(ERROR::RESOURCE_DATA_NOT_FOUND, load_icon_a(exe, cstr!("nonexistant")).unwrap_err(), "(exe, \"nonexistant\")");
/// ```
///
/// ### See Also
/// * [load_icon_w] &mdash; wide equivalent
/// * [load_cursor_a] &mdash; cursor equivalent
pub fn load_icon_a<'h, 't>(hinstance: impl Into<HInstance<'h>>, icon_name: impl Into<NameAtomOrZero<'t, u8>>) -> Result<HIcon<'h>, Error> {
fn_context!(load_icon_a => LoadIconA);
let hicon = unsafe { LoadIconA(hinstance.into().into(), icon_name.into().as_atom_or_cstr_ptr()) };
fn_succeeded!(!hicon.is_null())?;
Ok(unsafe { HIcon::from_unchecked(hicon) })
}

/// \[[docs.microsoft.com](https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-loadiconw)\]
/// LoadIconW
///
/// Loads an icon, animated icon, or bitmap.
///
/// ### Errors
/// * [ERROR::RESOURCE_DATA_NOT_FOUND] if `icon_name` cannot be found for `Some(hinstance)`
/// * ~~[ERROR::RESOURCE_NAME_NOT_FOUND]~~ never? (returned by [load_cursor_w])
/// * [ERROR::RESOURCE_TYPE_NOT_FOUND] if `icon_name` cannot be found for the system (e.g. `hinstance` is `None`)
///
/// ### Example
/// ```rust
/// # use abistr::*;
/// # use hwnd::*;
/// # use winresult::*;
/// let idi_error = load_icon_w(None, IDI::ERROR).unwrap();
///
/// let exe = get_module_handle_entry_exe().unwrap();
/// assert_eq!(ERROR::RESOURCE_TYPE_NOT_FOUND, load_icon_w(None, IDC::SIZE).unwrap_err(), "cursor-only atom to load_icon");
/// assert_eq!(ERROR::RESOURCE_TYPE_NOT_FOUND, load_icon_w(None, 42).unwrap_err(), "(None, 42)");
/// assert_eq!(ERROR::RESOURCE_DATA_NOT_FOUND, load_icon_w(exe, 42).unwrap_err(), "(exe, 42)");
/// assert_eq!(ERROR::RESOURCE_TYPE_NOT_FOUND, load_icon_w(None, cstr16!("nonexistant")).unwrap_err(), "(None, \"nonexistant\")");
/// assert_eq!(ERROR::RESOURCE_DATA_NOT_FOUND, load_icon_w(exe, cstr16!("nonexistant")).unwrap_err(), "(exe, \"nonexistant\")");
/// ```
///
/// ### See Also
/// * [load_icon_a] &mdash; narrow equivalent
/// * [load_cursor_w] &mdash; cursor equivalent
pub fn load_icon_w<'h, 't>(hinstance: impl Into<HInstance<'h>>, icon_name: impl Into<NameAtomOrZero<'t, u16>>) -> Result<HIcon<'h>, Error> {
fn_context!(load_icon_w => LoadIconW);
let hicon = unsafe { LoadIconW(hinstance.into().into(), icon_name.into().as_atom_or_cstr_ptr()) };
fn_succeeded!(!hicon.is_null())?;
Ok(unsafe { HIcon::from_unchecked(hicon) })
}
12 changes: 6 additions & 6 deletions src/um/winuser/structures/wndclass.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ pub type WndProc = Option<WndProcNonNull>;
pub cls_extra: i32,
pub wnd_extra: i32,
pub hinstance: HInstance<'static>,
pub hicon: HICON, // TODO: lifetime bound handle?
pub hicon: HIcon<'static>,
pub hcursor: HCursor<'static>,
pub background: HBRUSH, // TODO: lifetime bound handle?
pub menu_name: Option<abistr::CStrNonNull<'a>>, // TODO: OrAtom types?
Expand All @@ -41,7 +41,7 @@ pub type WndProc = Option<WndProcNonNull>;
pub cls_extra: i32,
pub wnd_extra: i32,
pub hinstance: HInstance<'static>,
pub hicon: HICON, // TODO: lifetime bound handle?
pub hicon: HIcon<'static>,
pub hcursor: HCursor<'static>,
pub background: HBRUSH, // TODO: lifetime bound handle?
pub menu_name: Option<abistr::CStrNonNull<'a, u16>>, // TODO: OrAtom types?
Expand All @@ -62,12 +62,12 @@ pub type WndProc = Option<WndProcNonNull>;
pub cls_extra: i32,
pub wnd_extra: i32,
pub hinstance: HInstance<'static>,
pub hicon: HICON, // TODO: lifetime bound handle?
pub hicon: HIcon<'static>,
pub hcursor: HCursor<'static>,
pub background: HBRUSH, // TODO: lifetime bound handle?
pub menu_name: Option<abistr::CStrNonNull<'a>>, // TODO: OrAtom types?
pub class_name: Option<abistr::CStrNonNull<'a>>, // TODO: OrAtom types?
pub hicon_sm: HICON, // TODO: lifetime bound handle?
pub hicon_sm: HIcon<'static>,
}

/// \[[docs.microsoft.com](https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-wndclassexw)\]
Expand All @@ -84,12 +84,12 @@ pub type WndProc = Option<WndProcNonNull>;
pub cls_extra: i32,
pub wnd_extra: i32,
pub hinstance: HInstance<'static>,
pub hicon: HICON, // TODO: lifetime bound handle?
pub hicon: HIcon<'static>,
pub hcursor: HCursor<'static>,
pub background: HBRUSH, // TODO: lifetime bound handle?
pub menu_name: Option<abistr::CStrNonNull<'a, u16>>, // TODO: OrAtom types?
pub class_name: Option<abistr::CStrNonNull<'a, u16>>, // TODO: OrAtom types?
pub hicon_sm: HICON, // TODO: lifetime bound handle?
pub hicon_sm: HIcon<'static>,
}

unsafe impl Zeroable for WndClassA<'_> {} // wnd_proc
Expand Down

0 comments on commit 1cf0245

Please sign in to comment.