running-process-platform-internal 4.10.4

Blessed platform process operations for running-process (implementation detail)
Documentation
use std::collections::HashSet;
use std::time::{Duration, Instant};

use winapi::shared::minwindef::{BOOL, LPARAM, TRUE};
use winapi::shared::windef::HWND;
use winapi::um::winuser::{EnumWindows, GetWindowTextW, GetWindowThreadProcessId, IsWindowVisible};

use crate::platform::process::ConsoleWindowInfo;

fn enumerate_visible_windows() -> Vec<ConsoleWindowInfo> {
    let mut results = Vec::new();

    unsafe extern "system" fn enum_callback(hwnd: HWND, lparam: LPARAM) -> BOOL {
        if IsWindowVisible(hwnd) == 0 {
            return TRUE;
        }
        let mut pid = 0;
        GetWindowThreadProcessId(hwnd, &mut pid);
        let mut title_buf = [0u16; 512];
        let len = GetWindowTextW(hwnd, title_buf.as_mut_ptr(), title_buf.len() as i32);
        let title = if len > 0 {
            String::from_utf16_lossy(&title_buf[..len as usize])
        } else {
            String::new()
        };
        let results = &mut *(lparam as *mut Vec<ConsoleWindowInfo>);
        results.push(ConsoleWindowInfo {
            pid,
            title,
            hwnd: hwnd as u64,
        });
        TRUE
    }

    unsafe {
        EnumWindows(
            Some(enum_callback),
            &mut results as *mut Vec<ConsoleWindowInfo> as LPARAM,
        );
    }
    results
}

pub fn monitor_console_windows(duration: Duration) -> Vec<ConsoleWindowInfo> {
    let baseline: HashSet<u64> = enumerate_visible_windows()
        .iter()
        .map(|window| window.hwnd)
        .collect();
    let mut seen_new = HashSet::new();
    let mut new_windows = Vec::new();
    let start = Instant::now();
    while start.elapsed() < duration {
        std::thread::sleep(Duration::from_millis(50));
        for info in enumerate_visible_windows() {
            if !baseline.contains(&info.hwnd) && seen_new.insert(info.hwnd) {
                new_windows.push(info);
            }
        }
    }
    new_windows
}