libobs_window_helper\util/
validators.rs

1use std::os::raw::c_void;
2use windows::Win32::UI::WindowsAndMessaging::{GetClientRect, GetWindowLongPtrW, IsIconic, IsWindowVisible, GWL_EXSTYLE, GWL_STYLE, WS_CHILD, WS_EX_TOOLWINDOW};
3use windows::Win32::{
4    Foundation::{HWND, RECT},
5    Graphics::Dwm::{DwmGetWindowAttribute, DWMWA_CLOAKED},
6};
7
8use windows_result::Result;
9
10const INTERNAL_MICROSOFT_EXES_EXACT: &'static [&'static str] = &[
11    "startmenuexperiencehost.exe",
12    "applicationframehost.exe",
13    "peopleexperiencehost.exe",
14    "shellexperiencehost.exe",
15    "microsoft.notes.exe",
16    "systemsettings.exe",
17    "textinputhost.exe",
18    "searchapp.exe",
19    "video.ui.exe",
20    "searchui.exe",
21    "lockapp.exe",
22    "cortana.exe",
23    "gamebar.exe",
24    "tabtip.exe",
25    "time.exe",
26];
27
28const INTERNAL_MICROSOFT_EXES_PARTIAL: &'static [&'static str] = &["windowsinternal"];
29
30#[derive(Debug, Clone, Copy, PartialEq, Eq)]
31pub enum WindowSearchMode {
32    ExcludeMinimized,
33    IncludeMinimized,
34}
35
36type DWORD = u32;
37
38pub(crate) fn is_window_cloaked(handle: HWND) -> bool {
39    let cloaked: DWORD = 0;
40    let res = unsafe {
41        DwmGetWindowAttribute(
42            handle,
43            DWMWA_CLOAKED,
44            cloaked as *mut c_void,
45            size_of::<DWORD>() as u32,
46        )
47    };
48
49    return res.is_ok() && cloaked != 0;
50}
51
52pub fn is_window_valid(handle: HWND, mode: WindowSearchMode) -> Result<bool> {
53    let is_visible = unsafe { IsWindowVisible(handle) };
54    if !is_visible.as_bool() {
55        return Ok(false);
56    }
57
58    if mode == WindowSearchMode::ExcludeMinimized {
59        let is_minimized = unsafe { IsIconic(handle).as_bool() } || is_window_cloaked(handle);
60        if is_minimized {
61            return Ok(false);
62        }
63    }
64
65    let mut rect = RECT::default();
66    let styles;
67    let ex_styles;
68
69    unsafe {
70        GetClientRect(handle, &mut rect)?;
71
72        // Use the W function because obs can only be compiled for 64-bit
73        styles = GetWindowLongPtrW(handle, GWL_STYLE) as DWORD;
74        ex_styles = GetWindowLongPtrW(handle, GWL_EXSTYLE) as DWORD;
75    }
76
77    if ex_styles & WS_EX_TOOLWINDOW.0 > 0 {
78        return Ok(false);
79    }
80    if styles & WS_CHILD.0 > 0 {
81        return Ok(false);
82    }
83
84    if mode == WindowSearchMode::ExcludeMinimized && (rect.bottom == 0 || rect.right == 0) {
85        return Ok(false);
86    }
87
88    return Ok(true);
89}
90
91pub fn is_microsoft_internal_exe(exe: &str) -> bool {
92    let exact = INTERNAL_MICROSOFT_EXES_EXACT.iter().any(|e| *e == exe);
93    let partial = INTERNAL_MICROSOFT_EXES_PARTIAL
94        .iter()
95        .any(|e| exe.contains(e));
96
97    return exact || partial;
98}