window_getter/platform_impl/
windows.rs1use windows::{
2 Win32::{Foundation::LPARAM, UI::WindowsAndMessaging::IsWindow},
3 core::BOOL,
4};
5
6use crate::{Error, Window};
7
8pub use error::WindowsError;
9pub use window::WindowsWindow;
10
11pub type WindowsBounds = windows::Win32::Foundation::RECT;
12pub type WindowsWindowId = windows::Win32::Foundation::HWND;
13
14pub fn get_window(id: WindowsWindowId) -> Option<Window> {
16 let hwnd = id;
17
18 if hwnd.is_invalid() || !unsafe { IsWindow(Some(hwnd)) }.as_bool() {
19 None
20 } else {
21 Some(Window(WindowsWindow::new(hwnd)))
22 }
23}
24
25unsafe extern "system" fn enum_windows_callback(
26 hwnd: windows::Win32::Foundation::HWND,
27 lparam: LPARAM,
28) -> BOOL {
29 let windows = unsafe { &mut *(lparam.0 as *mut Vec<Window>) };
30 windows.push(Window(WindowsWindow::new(hwnd)));
31
32 BOOL::from(true)
33}
34
35pub fn get_windows() -> Result<Vec<Window>, Error> {
37 let mut windows = Vec::new();
38
39 unsafe {
41 windows::Win32::UI::WindowsAndMessaging::EnumWindows(
42 Some(enum_windows_callback),
43 LPARAM(&mut windows as *const Vec<Window> as _),
44 )?
45 };
46
47 Ok(windows)
48}
49
50mod window {
51 use windows::Win32::{
52 Foundation::{self, HWND, RECT},
53 Graphics::Dwm::{DWMWA_EXTENDED_FRAME_BOUNDS, DwmGetWindowAttribute},
54 System::Threading,
55 UI::WindowsAndMessaging::{self, GetWindowRect},
56 };
57
58 use crate::Bounds;
59
60 use super::WindowsError;
61
62 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
64 pub struct WindowsWindow(pub(crate) HWND);
65
66 unsafe impl Send for WindowsWindow {}
67 unsafe impl Sync for WindowsWindow {}
68
69 impl WindowsWindow {
70 pub fn new(hwnd: HWND) -> Self {
77 Self(hwnd)
78 }
79
80 pub fn hwnd(&self) -> HWND {
82 self.0
83 }
84
85 pub fn title(&self) -> Result<Option<String>, WindowsError> {
87 let mut buffer = [0u16; 256];
88 let length = unsafe { WindowsAndMessaging::GetWindowTextW(self.0, &mut buffer) };
89
90 if length == 0 {
91 let raw = windows::core::Error::from_thread();
92
93 return match raw.code() {
94 Foundation::S_OK => Ok(None),
97 _ => Err(raw),
98 };
99 }
100
101 Ok(Some(String::from_utf16_lossy(&buffer[..length as usize])))
102 }
103
104 pub fn rect(&self) -> Result<RECT, WindowsError> {
109 Ok(unsafe {
110 let mut rect = std::mem::zeroed();
111 GetWindowRect(self.0, &mut rect)?;
112 rect
113 })
114 }
115
116 pub fn bounds(&self) -> Result<Bounds, WindowsError> {
118 Ok(self.rect()?.into())
119 }
120
121 pub fn extended_frame_bounds(&self) -> Result<RECT, WindowsError> {
124 Ok(unsafe {
125 let mut rect: RECT = std::mem::zeroed();
126 DwmGetWindowAttribute(
127 self.0,
128 DWMWA_EXTENDED_FRAME_BOUNDS,
129 &mut rect as *mut RECT as _,
130 std::mem::size_of::<RECT>() as _,
131 )?;
132 rect
133 })
134 }
135
136 pub fn visible_bounds(&self) -> Result<Bounds, WindowsError> {
140 Ok(self.extended_frame_bounds()?.into())
141 }
142
143 pub fn owner_pid(&self) -> Result<u32, WindowsError> {
145 let mut pid = 0;
146 let thread =
147 unsafe { WindowsAndMessaging::GetWindowThreadProcessId(self.0, Some(&mut pid)) };
148
149 if thread == 0 {
150 Err(windows::core::Error::from_thread())
151 } else {
152 Ok(pid)
153 }
154 }
155
156 pub fn owner_process_handle(
158 &self,
159 ) -> Result<windows::Win32::Foundation::HANDLE, WindowsError> {
160 let pid = self.owner_pid()?;
161 let process_handle = unsafe {
162 Threading::OpenProcess(
163 Threading::PROCESS_QUERY_INFORMATION | Threading::PROCESS_VM_READ,
164 false,
165 pid,
166 )?
167 };
168
169 Ok(process_handle)
170 }
171
172 pub fn owner_name(&self) -> Result<String, WindowsError> {
175 let process_handle = self.owner_process_handle()?;
176
177 let mut buffer = [0u16; 256];
178 let length = unsafe {
179 windows::Win32::System::ProcessStatus::GetModuleBaseNameW(
180 process_handle,
181 None,
182 &mut buffer,
183 )
184 };
185
186 if length == 0 {
187 return Err(windows::core::Error::from_thread());
188 }
189
190 Ok(String::from_utf16_lossy(&buffer[..length as usize]))
191 }
192
193 pub fn is_foreground(&self) -> bool {
195 self.0 == unsafe { WindowsAndMessaging::GetForegroundWindow() }
196 }
197 }
198}
199
200mod error {
201 pub type WindowsError = windows::core::Error;
202
203 impl From<WindowsError> for crate::Error {
204 fn from(error: WindowsError) -> Self {
205 if error.code() == windows::Win32::Foundation::E_ACCESSDENIED {
206 Self::PermissionDenied(error)
207 } else {
208 Self::PlatformSpecificError(error)
209 }
210 }
211 }
212}