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