everything_ipc/
lib.rs

1//! Rust binding for Everything's IPC SDK.
2//!
3//! ## Features
4#![cfg_attr(docsrs, feature(doc_auto_cfg))]
5#![cfg_attr(feature = "doc", doc = document_features::document_features!())]
6
7use tracing::debug;
8use widestring::{U16Str, u16str};
9use windows_sys::Win32::{
10    Foundation::{BOOL, FALSE, HWND, LPARAM, TRUE},
11    System::Threading::GetCurrentThreadId,
12    UI::WindowsAndMessaging::{EnumThreadWindows, GetClassNameW, SendMessageW, WM_USER},
13};
14
15const IPC_CLASS_PREFIX: &U16Str = u16str!("EVERYTHING_TASKBAR_NOTIFICATION");
16
17const EVERYTHING_WM_IPC: u32 = WM_USER;
18
19struct EnumWindowsData {
20    result: Option<IpcWindow>,
21}
22
23unsafe extern "system" fn enum_windows_proc(hwnd: HWND, lparam: LPARAM) -> BOOL {
24    let data = unsafe { &mut *(lparam as *mut EnumWindowsData) };
25
26    let mut buf = [0; 256];
27    let len = unsafe { GetClassNameW(hwnd, buf.as_mut_ptr(), buf.len() as i32) };
28    if len > 0 {
29        let class_name = U16Str::from_slice(&buf[..len as usize]);
30        // debug!(?hwnd, ?class_name, "enum_windows_proc");
31        if class_name
32            .as_slice()
33            .starts_with(IPC_CLASS_PREFIX.as_slice())
34        {
35            data.result = Some(IpcWindow {
36                hwnd,
37                class_name: class_name.to_string().unwrap(),
38            });
39            return FALSE;
40        }
41    }
42
43    TRUE
44}
45
46#[derive(Debug)]
47pub struct IpcWindow {
48    hwnd: HWND,
49    class_name: String,
50}
51
52impl IpcWindow {
53    pub fn from_current_thread() -> Option<Self> {
54        let mut data = EnumWindowsData { result: None };
55
56        let tid = unsafe { GetCurrentThreadId() };
57        debug!(?tid, "from_current_thread");
58        unsafe {
59            EnumThreadWindows(tid, Some(enum_windows_proc), &mut data as *mut _ as LPARAM);
60        }
61
62        data.result
63    }
64
65    pub fn hwnd(&self) -> HWND {
66        self.hwnd
67    }
68
69    pub fn class_name(&self) -> &str {
70        &self.class_name
71    }
72
73    pub fn instance_name(&self) -> Option<&str> {
74        // e.g. "EVERYTHING_TASKBAR_NOTIFICATION_(1.5a)"
75        self.class_name
76            .strip_prefix("EVERYTHING_TASKBAR_NOTIFICATION_(")
77            .and_then(|s| s.strip_suffix(')'))
78    }
79
80    pub fn get_version(&self) -> Version {
81        const EVERYTHING_IPC_GET_MAJOR_VERSION: u32 = 0;
82        const EVERYTHING_IPC_GET_MINOR_VERSION: u32 = 1;
83        const EVERYTHING_IPC_GET_REVISION: u32 = 2;
84        const EVERYTHING_IPC_GET_BUILD_NUMBER: u32 = 3;
85        // const EVERYTHING_IPC_GET_TARGET_MACHINE: u32 = 5;
86
87        let send_u32 = |command: u32| unsafe {
88            SendMessageW(self.hwnd, EVERYTHING_WM_IPC, command as usize, 0)
89        } as u32;
90
91        Version {
92            major: send_u32(EVERYTHING_IPC_GET_MAJOR_VERSION),
93            minor: send_u32(EVERYTHING_IPC_GET_MINOR_VERSION),
94            revision: send_u32(EVERYTHING_IPC_GET_REVISION),
95            build: send_u32(EVERYTHING_IPC_GET_BUILD_NUMBER),
96        }
97    }
98}
99
100#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
101pub struct Version {
102    pub major: u32,
103    pub minor: u32,
104    pub revision: u32,
105    pub build: u32,
106}
107
108impl Version {
109    pub fn new(major: u32, minor: u32, revision: u32, build: u32) -> Self {
110        Self {
111            major,
112            minor,
113            revision,
114            build,
115        }
116    }
117}