libobs_window_helper\util/
validators.rs

1use std::os::raw::c_void;
2use windows::Win32::UI::WindowsAndMessaging::{
3    GetClientRect, GetWindowLongPtrW, IsIconic, IsWindowVisible, GWL_EXSTYLE, GWL_STYLE, WS_CHILD,
4    WS_EX_TOOLWINDOW,
5};
6use windows::{
7    core::Result,
8    Win32::{
9        Foundation::{HWND, RECT},
10        Graphics::Dwm::{DwmGetWindowAttribute, DWMWA_CLOAKED},
11    },
12};
13
14const INTERNAL_MICROSOFT_EXES_EXACT: &[&str] = &[
15    "startmenuexperiencehost.exe",
16    "applicationframehost.exe",
17    "peopleexperiencehost.exe",
18    "shellexperiencehost.exe",
19    "microsoft.notes.exe",
20    "systemsettings.exe",
21    "textinputhost.exe",
22    "searchapp.exe",
23    "video.ui.exe",
24    "searchui.exe",
25    "lockapp.exe",
26    "cortana.exe",
27    "gamebar.exe",
28    "tabtip.exe",
29    "time.exe",
30];
31
32const INTERNAL_MICROSOFT_EXES_PARTIAL: &[&str] = &["windowsinternal"];
33
34#[derive(Debug, Clone, Copy, PartialEq, Eq)]
35pub enum WindowSearchMode {
36    ExcludeMinimized,
37    IncludeMinimized,
38}
39
40#[allow(clippy::upper_case_acronyms)]
41type DWORD = u32;
42
43pub(crate) fn is_window_cloaked(handle: HWND) -> bool {
44    let cloaked: DWORD = 0;
45    let res = unsafe {
46        // Safety: `handle` is provided by Win32 window enumeration and `cloaked` is a valid out pointer
47        // sized for the DWMWA_CLOAKED attribute.
48        DwmGetWindowAttribute(
49            handle,
50            DWMWA_CLOAKED,
51            cloaked as *mut c_void,
52            size_of::<DWORD>() as u32,
53        )
54    };
55
56    res.is_ok() && cloaked != 0
57}
58
59pub fn is_window_valid(handle: HWND, mode: WindowSearchMode) -> Result<bool> {
60    let is_visible = unsafe {
61        // Safety: `handle` references a Win32 window; querying its visibility does not require additional
62        // invariants beyond a valid HWND.
63        IsWindowVisible(handle)
64    };
65    if !is_visible.as_bool() {
66        return Ok(false);
67    }
68
69    if mode == WindowSearchMode::ExcludeMinimized {
70        let is_minimized = unsafe {
71            // Safety: `handle` is a valid HWND and can be queried for its minimized state via `IsIconic`.
72            IsIconic(handle).as_bool()
73        } || is_window_cloaked(handle);
74        if is_minimized {
75            return Ok(false);
76        }
77    }
78
79    let mut rect = RECT::default();
80    let styles;
81    let ex_styles;
82
83    unsafe {
84        // Safety: `handle` is a valid HWND; `rect`, `styles`, and `ex_styles` are local writable buffers and
85        // remain valid for the duration of these Win32 queries.
86        GetClientRect(handle, &mut rect)?;
87
88        // Use the W function because obs can only be compiled for 64-bit
89        styles = GetWindowLongPtrW(handle, GWL_STYLE) as DWORD;
90        ex_styles = GetWindowLongPtrW(handle, GWL_EXSTYLE) as DWORD;
91    }
92
93    if ex_styles & WS_EX_TOOLWINDOW.0 > 0 {
94        return Ok(false);
95    }
96    if styles & WS_CHILD.0 > 0 {
97        return Ok(false);
98    }
99
100    if mode == WindowSearchMode::ExcludeMinimized && (rect.bottom == 0 || rect.right == 0) {
101        return Ok(false);
102    }
103
104    Ok(true)
105}
106
107pub fn is_microsoft_internal_exe(exe: &str) -> bool {
108    let exact = INTERNAL_MICROSOFT_EXES_EXACT.contains(&exe);
109    let partial = INTERNAL_MICROSOFT_EXES_PARTIAL
110        .iter()
111        .any(|e| exe.contains(e));
112
113    exact || partial
114}