winsafe\kernel/
traits.rs

1#![allow(non_snake_case)]
2
3use std::{fmt, hash};
4
5use crate::co;
6use crate::decl::*;
7
8/// A native
9/// [handle](https://learn.microsoft.com/en-us/windows/win32/sysinfo/handles-and-objects),
10/// implemented by all handle types.
11///
12/// Prefer importing this trait through the prelude:
13///
14/// ```no_run
15/// use winsafe::prelude::*;
16/// ```
17pub trait Handle:
18	Sized
19	+ PartialEq
20	+ Eq
21	+ Send
22	+ hash::Hash
23	+ fmt::Debug
24	+ fmt::Display
25	+ fmt::LowerHex
26	+ fmt::UpperHex
27{
28	/// The null, uninitialized handle; equals to `0`.
29	const NULL: Self;
30
31	/// The invalid handle; equals to `-1`.
32	///
33	/// Operations upon this handle will fail with
34	/// [`ERROR::INVALID_HANDLE`](crate::co::ERROR::INVALID_HANDLE) error code.
35	const INVALID: Self;
36
37	/// Constructs a new handle object by wrapping a pointer.
38	///
39	/// This method can be used as an escape hatch to interoperate with other
40	/// libraries.
41	///
42	/// # Safety
43	///
44	/// Be sure the pointer has the correct type and isn't owned by anyone else,
45	/// otherwise you may cause memory access violations.
46	#[must_use]
47	unsafe fn from_ptr(p: *mut std::ffi::c_void) -> Self;
48
49	/// Returns a raw copy of the underlying handle pointer.
50	///
51	/// # Safety
52	///
53	/// As the name implies, `raw_copy` returns a raw copy of the handle, so
54	/// closing one of the copies won't close the others. This means a handle
55	/// can be used after it has been closed, what can lead to errors and
56	/// undefined behavior. Even worse: sometimes Windows reuses handle values,
57	/// so you can call a method on a completely different handle type, what can
58	/// be catastrophic.
59	///
60	/// However, in some cases the Windows API *demands* a copy of the handle –
61	/// `raw_copy` is an escape hatch to fill this gap.
62	#[must_use]
63	unsafe fn raw_copy(&self) -> Self {
64		unsafe { Self::from_ptr(self.ptr()) }
65	}
66
67	/// Returns a mutable reference to the underlying raw pointer.
68	///
69	/// This method can be used as an escape hatch to interoperate with other
70	/// libraries.
71	///
72	/// # Safety
73	///
74	/// This method exposes the raw pointer used by raw Windows calls. It's an
75	/// opaque pointer to an internal Windows structure, and no dereferencings
76	/// should be attempted.
77	#[must_use]
78	unsafe fn as_mut(&mut self) -> &mut *mut std::ffi::c_void;
79
80	/// Returns the underlying raw pointer.
81	///
82	/// This method exposes the raw pointer used by raw Windows calls. It's an
83	/// opaque pointer to an internal Windows structure, and no dereferencings
84	/// should be attempted.
85	///
86	/// This method can be used as an escape hatch to interoperate with other
87	/// libraries.
88	#[must_use]
89	fn ptr(&self) -> *mut std::ffi::c_void;
90
91	/// Returns `None` if the handle is null or invalid, otherwise returns
92	/// `Some(&self)`.
93	///
94	/// # Examples
95	///
96	/// ```no_run
97	/// use winsafe::{self as w, prelude::*};
98	///
99	/// let hfile = w::HFILE::NULL;
100	///
101	/// match hfile.as_opt() {
102	///     Some(hfile) => println!("Never prints"),
103	///     None => println!("The handle is null"),
104	/// }
105	/// ```
106	#[must_use]
107	fn as_opt(&self) -> Option<&Self> {
108		if *self == Self::NULL || *self == Self::INVALID { None } else { Some(self) }
109	}
110}
111
112/// A system error which can be formatted with
113/// [`FormatMessage`](crate::FormatMessage), exhibiting a description string
114/// provided by the OS.
115pub trait SystemError: Into<u32> {
116	/// Returns the textual description of the system error, by calling
117	/// [`FormatMessage`](crate::FormatMessage).
118	/// function.
119	#[must_use]
120	fn FormatMessage(self) -> String {
121		let err_code: u32 = self.into();
122
123		// Wininet error codes require specific treatment.
124		let is_wininet = err_code >= 12001 && err_code <= 12192;
125		let (wininet_flags, maybe_wininet_dll) = if is_wininet {
126			(
127				Some(co::FORMAT_MESSAGE::FROM_HMODULE),
128				Some(
129					HINSTANCE::GetModuleHandle(Some("wininet.dll"))
130						.expect("wininet.dll failed to load.") // should never happen
131						.ptr(),
132				),
133			)
134		} else {
135			(None, None)
136		};
137
138		match unsafe {
139			FormatMessage(
140				co::FORMAT_MESSAGE::ALLOCATE_BUFFER
141					| co::FORMAT_MESSAGE::FROM_SYSTEM
142					| co::FORMAT_MESSAGE::IGNORE_INSERTS
143					| wininet_flags.unwrap_or_default(),
144				maybe_wininet_dll,
145				err_code,
146				LANGID::USER_DEFAULT,
147				&[],
148			)
149		} {
150			// This function never fails, return an informational text about the formatting error.
151			Err(e) => match e {
152				co::ERROR::MR_MID_NOT_FOUND => {
153					"(The system cannot format this message error.)".to_owned()
154				},
155				e => format!(
156					"The system failed to format error {:#06x} with error {:#06x}.",
157					err_code, e
158				),
159			},
160			Ok(s) => s,
161		}
162	}
163}