win32_ecoqos/
process.rs

1use std::ffi::c_void;
2
3use crate::preset::{PROCESS_RESTORE, PROCESS_THROTTLE, PROCESS_UNTHROTTLE};
4use windows::Win32::{
5    Foundation::{CloseHandle, HANDLE},
6    System::Threading::{
7        GetProcessInformation, OpenProcess, ProcessPowerThrottling, SetPriorityClass,
8        SetProcessInformation, IDLE_PRIORITY_CLASS, NORMAL_PRIORITY_CLASS, PROCESS_CREATION_FLAGS,
9        PROCESS_INFORMATION_CLASS, PROCESS_POWER_THROTTLING_CURRENT_VERSION,
10        PROCESS_POWER_THROTTLING_EXECUTION_SPEED, PROCESS_POWER_THROTTLING_STATE,
11        PROCESS_SET_INFORMATION,
12    },
13};
14
15unsafe fn toggle_efficiency_mode_impl(
16    hprocess: HANDLE,
17    processinformation: *const c_void,
18    processinformationclass: PROCESS_INFORMATION_CLASS,
19    processinformationsize: u32,
20    dwpriorityclass: PROCESS_CREATION_FLAGS,
21) -> Result<(), windows_result::Error> {
22    unsafe {
23        SetProcessInformation(
24            hprocess,
25            processinformationclass,
26            processinformation,
27            processinformationsize,
28        )?;
29        SetPriorityClass(hprocess, dwpriorityclass)?;
30    }
31
32    Ok(())
33}
34
35/// Toggle efficiency mode of a process, by it's PID.
36///
37/// ```rust
38/// use win32_ecoqos::process::toggle_efficiency_mode;
39///
40/// let pid = std::process::id();
41///
42/// // Enable EcoQoS
43/// toggle_efficiency_mode(pid, Some(true));
44/// // Enable HighQoS
45/// toggle_efficiency_mode(pid, Some(false));
46/// // Let system decide
47/// toggle_efficiency_mode(pid, None);
48/// ```
49pub fn toggle_efficiency_mode(pid: u32, enable: Option<bool>) -> Result<(), windows_result::Error> {
50    let hprocess = unsafe { OpenProcess(PROCESS_SET_INFORMATION, false, pid)? };
51    let result = unsafe { toggle_efficiency_mode_handle(hprocess, enable) };
52    let _ = unsafe { CloseHandle(hprocess) };
53
54    result
55}
56
57/// Toggle efficiency mode of a process, by a [`HANDLE`](https://microsoft.github.io/windows-docs-rs/doc/windows/Win32/Foundation/struct.HANDLE.html).
58///
59/// [`GetCurrentProcess`]: https://microsoft.github.io/windows-docs-rs/doc/windows/Win32/System/Threading/fn.GetCurrentProcess.html
60/// The handle returned by [`GetCurrentProcess`] have a `PROCESS_ALL_ACCESS`.
61///
62/// You must enable [`PROCESS_SET_INFORMATION`](https://microsoft.github.io/windows-docs-rs/doc/windows/Win32/System/Threading/constant.PROCESS_SET_INFORMATION.html)
63/// access flag on your handle to apply EcoQoS throttle.
64///
65/// SAFETY: `hprocess` must be a valid process handle. DO NOT pass null ptr, e.g.
66///
67/// ```rust
68/// use win32_ecoqos::process::toggle_efficiency_mode_handle;
69/// use windows::Win32::Foundation::CloseHandle;
70/// use windows::Win32::System::Threading::GetCurrentProcess;
71///
72/// unsafe {
73///     let hprocess = GetCurrentProcess();
74///
75///     // Enable EcoQos
76///     toggle_efficiency_mode_handle(hprocess, Some(true));
77///     // Enable HighQos
78///     toggle_efficiency_mode_handle(hprocess, Some(false));
79///     // Let system decide
80///     toggle_efficiency_mode_handle(hprocess, None);
81///
82///     // Avoid resource leak
83///     CloseHandle(hprocess);
84/// }
85/// ```
86pub unsafe fn toggle_efficiency_mode_handle(
87    hprocess: HANDLE,
88    enable: Option<bool>,
89) -> Result<(), windows_result::Error> {
90    let new_state = match enable {
91        Some(true) => PROCESS_THROTTLE,
92        Some(false) => PROCESS_UNTHROTTLE,
93        None => PROCESS_RESTORE,
94    };
95
96    let processinformationclass = ProcessPowerThrottling;
97    let processinformation = &new_state as *const _ as *const c_void;
98    let processinformationsize = size_of::<PROCESS_POWER_THROTTLING_STATE>() as u32;
99
100    let dwpriorityclass = if let Some(true) = enable {
101        IDLE_PRIORITY_CLASS
102    } else {
103        NORMAL_PRIORITY_CLASS
104    };
105
106    unsafe {
107        toggle_efficiency_mode_impl(
108            hprocess,
109            processinformation,
110            processinformationclass,
111            processinformationsize,
112            dwpriorityclass,
113        )
114    }
115}
116
117/// check whether EcoQoS is enabled on a process.
118///
119/// `hprocess` must have `PROCESS_QUERY_INFORMATION` access right.
120///
121/// SAFETY: `hprocess` must be a valid process handle. DO NOT pass null ptr, e.g.
122pub unsafe fn ecoqos_enabled(hprocess: HANDLE) -> Result<bool, windows_result::Error> {
123    let mut process_info = PROCESS_POWER_THROTTLING_STATE {
124        Version: PROCESS_POWER_THROTTLING_CURRENT_VERSION,
125        ControlMask: 0,
126        StateMask: 0,
127    };
128
129    unsafe {
130        GetProcessInformation(
131            hprocess,
132            ProcessPowerThrottling,
133            &mut process_info as *mut _ as *mut _,
134            size_of::<PROCESS_POWER_THROTTLING_STATE>() as u32,
135        )?;
136    }
137
138    Ok(
139        process_info.StateMask & PROCESS_POWER_THROTTLING_EXECUTION_SPEED
140            == PROCESS_POWER_THROTTLING_EXECUTION_SPEED,
141    )
142}