-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
misc. HWND APIs for future hwnd thread ownership testing
- Loading branch information
1 parent
4627cc5
commit ae1c72a
Showing
12 changed files
with
309 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
<!-- functions --> | ||
|
||
[GetCurrentProcessId]: https://docs.microsoft.com/en-gb/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentprocessid | ||
[GetCurrentThreadId]: https://docs.microsoft.com/en-gb/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentthreadid |
37 changes: 37 additions & 0 deletions
37
thindx/src/headers/processthreadsapi.h/functions/get_current.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
use winapi::um::processthreadsapi::*; | ||
|
||
|
||
|
||
/// \[[docs.microsoft.com](https://docs.microsoft.com/en-gb/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentprocessid)\] | ||
/// GetCurrentProcessId | ||
/// | ||
/// ### Example | ||
/// ```rust | ||
/// # use thindx::*; | ||
/// let process_id = win32::get_current_process_id(); | ||
/// assert!(process_id != 0); | ||
/// ``` | ||
pub fn get_current_process_id() -> u32 { | ||
fn_context!(win32::get_current_process_id => GetCurrentThreadId); | ||
unsafe { GetCurrentProcessId() } | ||
} | ||
|
||
/// \[[docs.microsoft.com](https://docs.microsoft.com/en-gb/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentthreadid)\] | ||
/// GetCurrentThreadId | ||
/// | ||
/// ### Example | ||
/// ```rust | ||
/// # use thindx::*; | ||
/// let thread_id = win32::get_current_thread_id(); | ||
/// assert!(thread_id != 0); | ||
/// ``` | ||
pub fn get_current_thread_id() -> u32 { | ||
// XXX: We could make this return NonZeroU32: | ||
// > Note that no thread identifier will ever be 0. | ||
// > https://docs.microsoft.com/en-us/windows/win32/procthread/thread-handles-and-identifiers | ||
// However, that might be awkward to work with. | ||
// We could have an alternative function...? | ||
// Also, what if we run on a hacked up emulator that violates this invariant? | ||
fn_context!(win32::get_current_thread_id => GetCurrentThreadId); | ||
unsafe { GetCurrentThreadId() } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
mods! { | ||
inl mod functions { | ||
inl mod get_current; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
<!-- functions --> | ||
|
||
[DestroyWindow]: https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-destroywindow | ||
|
||
[GetClientRect]: https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getclientrect | ||
[GetDesktopWindow]: https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getdesktopwindow | ||
|
||
[GetWindowThreadProcessId]: https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getwindowthreadprocessid | ||
|
||
[IsWindow]: https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-iswindow | ||
[IsWindowUnicode]: https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-iswindowunicode | ||
[IsWindowVisible]: https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-iswindowvisible | ||
|
||
|
||
|
||
<!-- types --> | ||
[HWND]: https://docs.microsoft.com/en-us/windows/win32/learnwin32/what-is-a-window- | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,228 @@ | ||
//! ### Safety | ||
//! | ||
//! `HWND`s are pretty funky. | ||
//! On the one hand, they're supposedly pointers, and in the single threaded days of 16-bit windows, they perhaps were. | ||
//! Modern 32-bit windows has turned these into generational indicies of sorts, and has sunken a lot of time into making Win32 safe/sound despite userspace's abuse. | ||
//! Windows may be owned by another thread, and thus destroyed at any time. | ||
//! Windows may be owned by another process, and thus destroyed at any time. | ||
//! Windows may be owned by another user, probably? | ||
//! HWNDs should generally be treated as weak references without proper validity checking. | ||
|
||
use crate::{Error, ErrorKind, ERROR}; | ||
use crate::d3d::Rect; // ...? | ||
|
||
use winapi::um::winuser::*; | ||
|
||
|
||
|
||
/// \[[docs.microsoft.com](https://docs.microsoft.com/en-us/windows/win32/learnwin32/what-is-a-window-)\] | ||
/// HWND | ||
/// | ||
/// A window handle. | ||
/// Note that Window's definition of a "window" is [pretty expansive](https://docs.microsoft.com/en-us/windows/win32/learnwin32/what-is-a-window-). | ||
/// There's a reason it's named "Windows"! | ||
/// | ||
/// Windows are "windows". | ||
/// Buttons are "windows". | ||
/// The desktop is a "window". | ||
/// ~~You're a "window".~~ | ||
/// Windows belonging to other threads are windows. | ||
/// Windows belonging to other processes are windows. | ||
/// Windows belonging to other users... *maybe* you're isolated from those? But probably not. | ||
pub type HWND = winapi::shared::windef::HWND; | ||
|
||
/// \[[docs.microsoft.com](https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-destroywindow)\] | ||
/// DestroyWindow | ||
/// | ||
/// Destroys the specified window. | ||
/// | ||
/// ### ⚠️ Safety ⚠️ | ||
/// * Destroying a window out from underneath a 3D rendering API such as Direct3D is generally unsound. | ||
/// * Destroying a "destroyed" window is unlikely to be sound. While windows itself can handle it, | ||
/// it can result in multiple WM_DESTROY and WM_NCDESTROY events, which the underlying wndprocs likely can't handle. | ||
/// * Destroying a window belonging to another thread or process is an incredibly bad idea, if it even works. | ||
/// * Honestly, you should probably only destroy windows you created, in your own process, on your own thread, and even then be careful! | ||
/// | ||
/// ### Errors | ||
/// * [ERROR::INVALID_WINDOW_HANDLE] | ||
/// | ||
/// ### Example | ||
/// ```rust | ||
/// # use thindx::*; | ||
/// # use std::ptr::*; | ||
/// assert_eq!(ERROR::INVALID_WINDOW_HANDLE, unsafe { win32::destroy_window(null_mut()) }); | ||
/// ``` | ||
pub unsafe fn destroy_window(hwnd: impl Into<HWND>) -> Result<(), Error> { | ||
fn_context!(win32::destroy_window => DestroyWindow); | ||
let hwnd = hwnd.into(); | ||
let succeeded = unsafe { DestroyWindow(hwnd) != 0 }; | ||
if succeeded { Ok(()) } else { fn_err!(get_last_error()) } | ||
} | ||
|
||
/// \[[docs.microsoft.com](https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getclientrect)\] | ||
/// GetClientRect | ||
/// | ||
/// Retrieves the coordinates of a window's client area. | ||
/// The client coordinates specify the upper-left and lower-right corners of the client area. | ||
/// Because client coordinates are relative to the upper-left corner of a window's client area, the coordinates of the upper-left corner are (0,0). | ||
/// | ||
/// ### Errors | ||
/// * [ERROR::INVALID_WINDOW_HANDLE] | ||
/// | ||
/// ### Example | ||
/// ```rust | ||
/// # use thindx::*; | ||
/// # use std::ptr::*; | ||
/// assert_eq!(ERROR::INVALID_WINDOW_HANDLE, win32::get_client_rect(null_mut())); | ||
/// let rect = win32::get_client_rect(win32::get_desktop_window()).unwrap(); | ||
/// assert_eq!(0, rect.left()); | ||
/// assert_eq!(0, rect.top()); | ||
/// assert!(0 != rect.width()); | ||
/// assert!(0 != rect.height()); | ||
/// # for p in 0 .. 8 * std::mem::size_of::<win32::HWND>() { | ||
/// # let e = win32::get_client_rect((1usize << p) as win32::HWND); // shouldn't crash | ||
/// # if e.is_err() { assert_eq!(ERROR::INVALID_WINDOW_HANDLE, e) } | ||
/// # } | ||
/// ``` | ||
pub fn get_client_rect(hwnd: impl TryInto<HWND>) -> Result<Rect, Error> { | ||
fn_context!(win32::get_client_rect => GetClientRect); | ||
let hwnd = hwnd.try_into().map_err(|_| fn_param_error!(hwnd, ERROR::INVALID_WINDOW_HANDLE))?; | ||
let mut rect = Rect::zeroed(); | ||
let succeeded = unsafe { GetClientRect(hwnd, rect.as_mut()) != 0 }; | ||
if succeeded { Ok(rect) } else { fn_err!(get_last_error()) } | ||
} | ||
|
||
/// \[[docs.microsoft.com](https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getdesktopwindow)\] | ||
/// GetDesktopWindow | ||
/// | ||
/// Retrieves a handle to the desktop window. | ||
/// The desktop window covers the entire screen. | ||
/// The desktop window is the area on top of which other windows are painted. | ||
/// | ||
/// ### Example | ||
/// ```rust | ||
/// # use thindx::win32; | ||
/// let hwnd = win32::get_desktop_window(); | ||
/// # assert!(win32::is_window(hwnd)); | ||
/// ``` | ||
#[must_use] pub fn get_desktop_window() -> HWND { | ||
fn_context!(win32::get_desktop_window => GetDesktopWindow); | ||
unsafe { GetDesktopWindow() } | ||
} | ||
|
||
/// \[[docs.microsoft.com](https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getwindowthreadprocessid)\] | ||
/// GetWindowThreadProcessId | ||
/// | ||
/// Retrieves the identifier of the thread that created the specified window and, optionally, the identifier of the process that created the window. | ||
/// | ||
/// ### Returns | ||
/// * Ok((thread_id, process_id)) | ||
/// * [ERROR::INVALID_WINDOW_HANDLE] | ||
/// | ||
/// ### Example | ||
/// ```rust | ||
/// # use thindx::*; | ||
/// # let hwnd = win32::get_desktop_window(); | ||
/// let (thread, process) = win32::get_window_thread_process_id(hwnd).unwrap(); | ||
/// let hwnd_belongs_to_this_thread = thread == win32::get_current_thread_id(); | ||
/// # assert!(!hwnd_belongs_to_this_thread, "desktop doesn't belong to us!"); | ||
/// # | ||
/// # for p in 0 .. 8 * std::mem::size_of::<win32::HWND>() { | ||
/// # let e = win32::get_window_thread_process_id((1usize << p) as win32::HWND); // shouldn't crash | ||
/// # if e.is_err() { assert_eq!(ERROR::INVALID_WINDOW_HANDLE, e) } | ||
/// # } | ||
/// ``` | ||
#[must_use] pub fn get_window_thread_process_id(hwnd: impl Into<HWND>) -> Result<(u32, u32), Error> { | ||
fn_context!(win32::get_window_thread_process_id => GetWindowThreadProcessId); | ||
let hwnd = hwnd.into(); | ||
let mut pid = 0; | ||
let tid = unsafe { GetWindowThreadProcessId(hwnd, &mut pid) }; | ||
if tid != 0 { Ok((tid, pid)) } else { fn_err!(get_last_error()) } | ||
} | ||
|
||
/// \[[docs.microsoft.com](https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-iswindow)\] | ||
/// IsWindow | ||
/// | ||
/// Determines whether the specified window handle identifies an existing window. | ||
/// | ||
/// Valid uses of this function are few and far between - windows belonging to another thread | ||
/// or process could be destroyed immediately after this returns true, and invalidated handles | ||
/// might suddenly spring back to life as the handle value is reused. | ||
/// | ||
/// ### Example | ||
/// ```rust | ||
/// # use thindx::win32; | ||
/// # let valid_hwnd = win32::get_desktop_window(); | ||
/// # let invalid_hwnd : win32::HWND = !42 as _; | ||
/// assert!( win32::is_window( valid_hwnd)); | ||
/// assert!(!win32::is_window(invalid_hwnd)); | ||
/// assert!(!win32::is_window(std::ptr::null_mut())); | ||
/// # for p in 0 .. 8 * std::mem::size_of::<win32::HWND>() { | ||
/// # let _ = win32::is_window((1usize << p) as win32::HWND); // shouldn't crash | ||
/// # } | ||
/// ``` | ||
#[must_use] pub fn is_window(hwnd: impl TryInto<HWND>) -> bool { | ||
fn_context!(win32::is_window => IsWindow); | ||
match hwnd.try_into() { | ||
Ok(hwnd) => unsafe { IsWindow(hwnd) != 0 }, | ||
Err(_) => false, | ||
} | ||
} | ||
|
||
/// \[[docs.microsoft.com](https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-iswindow)\] | ||
/// IsWindowUnicode | ||
/// | ||
/// Determines whether the specified window is a native Unicode window. | ||
/// | ||
/// ### Returns | ||
/// * `true` if the window's class was registered with `RegisterClassW` | ||
/// * `false` if the window's class was registered with `RegisterClassA` | ||
/// * `false` if the window isn't valid, probably? (TryInto failed, HWND null/dangling/destroyed, ...) | ||
/// | ||
/// ### Example | ||
/// ```rust | ||
/// # use thindx::win32; | ||
/// # let unicode_hwnd = win32::get_desktop_window(); // TODO: replace with an explicitly created unicode hwnd | ||
/// assert!( win32::is_window_unicode(unicode_hwnd)); | ||
/// assert!(!win32::is_window_unicode(std::ptr::null_mut())); | ||
/// # for p in 0 .. 8 * std::mem::size_of::<win32::HWND>() { | ||
/// # let _ = win32::is_window_unicode((1usize << p) as win32::HWND); // shouldn't crash | ||
/// # } | ||
/// ``` | ||
#[must_use] pub fn is_window_unicode(hwnd: impl TryInto<HWND>) -> bool { | ||
fn_context!(win32::is_window_unicode => IsWindowUnicode); | ||
match hwnd.try_into() { | ||
Ok(hwnd) => unsafe { IsWindowUnicode(hwnd) != 0 }, | ||
Err(_) => false, | ||
} | ||
} | ||
|
||
/// \[[docs.microsoft.com](https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-iswindow)\] | ||
/// IsWindowVisible | ||
/// | ||
/// Determines whether the specified window is WS_VISIBLE. | ||
/// May return `true` even if the window is totally obscured by other windows, clipped out-of-bounds, etc. | ||
/// | ||
/// ### Example | ||
/// ```rust | ||
/// # use thindx::win32; | ||
/// # let hwnd = win32::get_desktop_window(); // TODO: replace with an explicitly created unicode hwnd | ||
/// assert!( win32::is_window_visible(hwnd)); | ||
/// assert!(!win32::is_window_visible(std::ptr::null_mut())); | ||
/// # for p in 0 .. 8 * std::mem::size_of::<win32::HWND>() { | ||
/// # let _ = win32::is_window_visible((1usize << p) as win32::HWND); // shouldn't crash | ||
/// # } | ||
/// ``` | ||
#[must_use] pub fn is_window_visible(hwnd: impl TryInto<HWND>) -> bool { | ||
fn_context!(win32::is_window_unicode => IsWindowVisible); | ||
match hwnd.try_into() { | ||
Ok(hwnd) => unsafe { IsWindowVisible(hwnd) != 0 }, | ||
Err(_) => false, | ||
} | ||
} | ||
|
||
|
||
|
||
#[must_use] fn get_last_error() -> ErrorKind { | ||
ErrorKind(unsafe { winapi::um::errhandlingapi::GetLastError() } as _) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
mods! { | ||
inl mod functions { | ||
inl mod window; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
//! General windows APIs | ||
|
||
pub use crate::processthreadsapi_h::*; | ||
pub use crate::winuser_h::*; |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.