1use std::fmt::{Debug, Formatter};
15pub use windows::Win32::System::Performance::{
16 PDH_FMT_DOUBLE, PDH_FMT_LARGE, PDH_FMT_LONG, PDH_HCOUNTER, PDH_HQUERY,
17};
18use windows::{
19 core::HSTRING,
20 Win32::{
21 Foundation::HANDLE,
22 System::Performance::{
23 PdhAddCounterW, PdhAddEnglishCounterW, PdhCloseQuery, PdhCollectQueryData,
24 PdhCollectQueryDataEx, PdhGetCounterInfoW, PdhGetFormattedCounterValue, PdhOpenQueryW,
25 PdhRemoveCounter, PDH_COUNTER_INFO_W, PDH_FMT, PDH_FMT_COUNTERVALUE,
26 },
27 },
28};
29
30pub const PDH_FMT_NOSCALE: PDH_FMT = PDH_FMT(0x00001000);
32pub const PDH_FMT_1000: PDH_FMT = PDH_FMT(0x00002000);
33pub const PDH_FMT_NODATA: PDH_FMT = PDH_FMT(0x00004000);
34pub const PDH_FMT_NOCAP100: PDH_FMT = PDH_FMT(0x00008000);
36
37pub trait PdhFmtExt {
38 fn add(&self, value: PDH_FMT) -> PDH_FMT;
39}
40
41impl PdhFmtExt for PDH_FMT {
42 fn add(&self, value: PDH_FMT) -> PDH_FMT {
43 PDH_FMT(self.0 | value.0)
44 }
45}
46
47pub fn pdh_open_query(data_source: Option<String>, user_data: usize) -> PDH_HQUERY {
54 unsafe {
55 let mut handle = std::mem::zeroed();
56 match data_source {
57 None => PdhOpenQueryW(None, user_data, &mut handle),
58 Some(d) => PdhOpenQueryW(&HSTRING::from(d), user_data, &mut handle),
59 };
60 handle
61 }
62}
63
64pub fn pdh_close_query(h_query: PDH_HQUERY) {
69 unsafe { PdhCloseQuery(h_query) };
70}
71
72pub fn pdh_get_counter_info(
78 h_counter: PDH_HCOUNTER,
79 retrieve_explain_text: bool,
80) -> Vec<PDH_COUNTER_INFO_W> {
81 unsafe {
82 let mut size = std::mem::zeroed();
83 PdhGetCounterInfoW(h_counter, retrieve_explain_text, &mut size, None);
84 let mut v = vec![];
85 for _ in 0..size {
86 v.push(PDH_COUNTER_INFO_W::default());
87 }
88 PdhGetCounterInfoW(
89 h_counter,
90 retrieve_explain_text,
91 &mut size,
92 Some(v.as_mut_ptr()),
93 );
94 v
95 }
96}
97
98pub fn pdh_add_counter(
105 h_query: PDH_HQUERY,
106 full_counter_path: String,
107 user_data: usize,
108) -> PDH_HCOUNTER {
109 unsafe {
110 let mut handle = std::mem::zeroed();
111 PdhAddCounterW(
112 h_query,
113 &HSTRING::from(full_counter_path),
114 user_data,
115 &mut handle,
116 );
117 handle
118 }
119}
120
121pub fn pdh_add_english_counter(
128 h_query: PDH_HQUERY,
129 full_counter_path: String,
130 user_data: usize,
131) -> PDH_HCOUNTER {
132 unsafe {
133 let mut handle = std::mem::zeroed();
134 PdhAddEnglishCounterW(
135 h_query,
136 &HSTRING::from(full_counter_path),
137 user_data,
138 &mut handle,
139 );
140 handle
141 }
142}
143
144pub fn pdh_collect_query_data_ex(
151 h_query: PDH_HQUERY,
152 interval_time: u32,
153 h_new_data_event: HANDLE,
154) {
155 unsafe {
156 PdhCollectQueryDataEx(h_query, interval_time, h_new_data_event);
157 }
158}
159
160pub fn pdh_collect_query_data(h_query: PDH_HQUERY) {
164 unsafe {
165 PdhCollectQueryData(h_query);
166 }
167}
168
169pub fn pdh_get_formatted_counter_value(
178 h_counter: PDH_HCOUNTER,
179 r#format: PDH_FMT,
180) -> (u32, PDH_FMT_COUNTERVALUE) {
181 unsafe {
182 let mut r#type = std::mem::zeroed();
183 let mut value = std::mem::zeroed();
184 PdhGetFormattedCounterValue(h_counter, r#format, Some(&mut r#type), &mut value);
185 (r#type, value)
186 }
187}
188
189pub fn pdh_remove_counter(h_counter: PDH_HCOUNTER) {
194 unsafe {
195 PdhRemoveCounter(h_counter);
196 }
197}
198
199pub struct PdhCounter(PDH_HCOUNTER);
200
201impl Debug for PdhCounter {
202 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
203 let (r, v) = self.get_value();
204 write!(f, "PdhCounter({}, {})", r, v)
205 }
206}
207
208impl Drop for PdhCounter {
209 fn drop(&mut self) {
210 pdh_remove_counter(self.0)
211 }
212}
213
214unsafe impl Sync for PdhCounter {}
215unsafe impl Send for PdhCounter {}
216
217#[derive(Debug)]
218pub struct PdhQuery(PDH_HQUERY);
219
220impl PdhQuery {
221 pub fn new() -> Self {
225 Self(pdh_open_query(None, 0))
226 }
227
228 pub fn add_counter(&self, full_counter_path: String) -> PdhCounter {
233 PdhCounter(pdh_add_counter(self.0, full_counter_path, 0))
234 }
235
236 pub fn add_english_counter(&self, full_counter_path: String) -> PdhCounter {
241 PdhCounter(pdh_add_english_counter(self.0, full_counter_path, 0))
242 }
243
244 pub fn collect_data(&self) -> &Self {
246 pdh_collect_query_data(self.0);
247 self
248 }
249}
250
251impl Drop for PdhQuery {
252 fn drop(&mut self) {
253 pdh_close_query(self.0)
254 }
255}
256
257unsafe impl Sync for PdhQuery {}
258unsafe impl Send for PdhQuery {}
259
260pub trait PdhCounterExt {
261 fn get_value(&self) -> (u32, f64);
262}
263
264impl PdhCounterExt for PdhCounter {
265 fn get_value(&self) -> (u32, f64) {
269 let (t, v) = pdh_get_formatted_counter_value(self.0, PDH_FMT_DOUBLE);
270 unsafe { (t, v.Anonymous.doubleValue) }
271 }
272}
273
274#[cfg(test)]
275mod test_pdh {
276 use crate::pdh::PdhQuery;
277
278 #[test]
279 fn main() {
280 let pdh = PdhQuery::new();
281 let counter = pdh.add_counter(format!(
282 r"\Processor Information({})\% Processor Time",
283 "_Total"
284 ));
285 for _ in 0..10 {
286 pdh.collect_data();
287 dbg!(&counter);
288 std::thread::sleep(std::time::Duration::from_millis(1000));
289 }
290 dbg!(pdh);
291 }
292}