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 match unsafe {
123 FormatMessage(
124 co::FORMAT_MESSAGE::ALLOCATE_BUFFER
125 | co::FORMAT_MESSAGE::FROM_SYSTEM
126 | co::FORMAT_MESSAGE::IGNORE_INSERTS,
127 None,
128 err_code,
129 LANGID::USER_DEFAULT,
130 None,
131 )
132 } {
133 // This function never fails, return an informational text about the formatting error.
134 Err(e) => match e {
135 co::ERROR::MR_MID_NOT_FOUND => {
136 "(The system cannot format this message error.)".to_owned()
137 },
138 e => format!(
139 "The system failed to format error {:#06x} with error {:#06x}.",
140 err_code, e
141 ),
142 },
143 Ok(s) => s,
144 }
145 }
146}