#winapi #rust
#winapi #Ржавчина
Вопрос:
Я использую ящик winapi-rs и пытаюсь получить загрузку процессора, однако я даже не могу сделать это так далеко.
PdhCollectQueryData возвращает ‘-2147481643’ при преобразовании в шестнадцатеричный код, а затем в код ошибки ‘0x800007D5 (PDH_NO_DATA) Нет данных для возврата.’ с этой проблемой я сталкиваюсь.
Может кто-нибудь помочь определить, что я делаю неправильно, чтобы вызвать «x800007D5 (PDH_NO_DATA) Нет данных для возврата»? Я могу заставить это работать на C (код приведен ниже), но при попытке преобразовать его в код Rust все идет совсем не так хорошо.
use wmi::{COMLibrary, Variant, WMIConnection};
use std::{collections::HashMap, ptr::null};
use winapi::{ctypes::{c_char, c_void},um::{pdh::*, winnt::{LPCSTR}}};
#[cfg(windows)]
fn main() -> Result<(), Box<dyn std::error::Error>> {
const CPU_TIME: LPCSTR = "\Processor(_Total)\% Processor Time".as_ptr() as *const i8;
unsafe
{
//cpuQuery
let mut hquery: PDH_HQUERY = std::ptr::null_mut();
let hquery_address: *mut PDH_HQUERY = amp;mut hquery as *mut *mut _ as *mut *mut c_void;
//cpuCounter
let mut hcounter: PDH_HCOUNTER = std::ptr::null_mut();
let hcounter_address: *mut PDH_HCOUNTER = amp;mut hcounter as *mut *mut _ as *mut *mut c_void;
//open query
PdhOpenQueryA(null(), 0, hquery_address);
PdhAddCounterA(hquery, CPU_TIME, 0, hcounter_address);
PdhCollectQueryData(hquery);
}
Ok(())
}
Пример того, что возвращается для некоторых значений после завершения программы, если я распечатаю значения:
hquery: 0x2541b495e00
hquery_address: 0xce3dafef00
PdhOpenQueryA: 0
PdhCollectQueryData -2147481643
Рабочий код на C (взят из другого ответа Stack Overflow и отлично работает при его запуске)
#include <TCHAR.h>
#include <pdh.h>
#include <windows.h>
#include <stdio.h>
#include <iostream>
#include <chrono>
#include <thread>
#pragma comment(lib, "pdh.lib")
using namespace std;
static PDH_HQUERY cpuQuery;
static PDH_HCOUNTER cpuTotal = NULL;
int _tmain(int argc, _TCHAR* argv[])
{
PdhOpenQuery(NULL, NULL, amp;cpuQuery);
PdhAddCounter(cpuQuery, L"\Processor(_Total)\% Processor Time", NULL, amp;cpuTotal);
PDH_FMT_COUNTERVALUE counterVal;
PdhCollectQueryData(cpuQuery);
this_thread::sleep_for(chrono::milliseconds(1000));
PdhCollectQueryData(cpuQuery);
PdhGetFormattedCounterValue(cpuTotal, PDH_FMT_DOUBLE, NULL, amp;counterVal);
cout << counterVal.doubleValue << "n";
getchar();
}
Итак, поскольку код на C работает, счетчик есть. Что я делаю не так с кодом rust для сбора запроса, который не работает корректно и выдает ‘x800007D5 (PDH_NO_DATA) Нет данных для возврата.’??
Комментарии:
1. Я все это преобразовал, но удалил часть, пока не получил код, который вызывал первую ошибку PdhCollectQueryData (hquery). PdhCollectQueryData(hquery) выдает код ошибки: 0x800007D5 (PDH_NO_DATA) Нет данных для возврата, и я не могу понять, почему это происходит. Я обновил вопрос, чтобы, надеюсь, сделать его более понятным, мой плохой 🙂
2. Нигде нет обработки ошибок или отчетов об ошибках. Это уже неправильно в C и, безусловно, противоречит всему, за что выступает Rust. Первым шагом в переносе плохого кода на C обычно является добавление отчетов об ошибках.
3. @IInspectable да, я понимаю, что код на C не очень хорош, и я взял его из другого ответа SO, поскольку я просто хотел посмотреть, смогу ли я заставить это работать tbh. Определенно будет работать над очисткой кода Rust с обработкой ошибок, извиняюсь.
Ответ №1:
Вот буквальный перевод вашего примера C на Rust с использованием winapi
ящика.
Как сказал IInspectable в комментариях, вам нужно будет добавить некоторую обработку ошибок, в данном случае я добавил некоторые assert_eq!
.
use std::ptr;
// winapi = { version = "0.3.9", features = ["pdh", "winerror"] }
use winapi::{ctypes::c_char, shared::winerror::ERROR_SUCCESS, um::pdh::*};
fn main() {
unsafe {
let mut cpu_query: PDH_HQUERY = ptr::null_mut();
let mut cpu_total: PDH_HCOUNTER = ptr::null_mut();
let err = PdhOpenQueryA(ptr::null(), 0, amp;mut cpu_query);
assert_eq!(err, ERROR_SUCCESS as i32);
let err = PdhAddCounterA(
cpu_query,
b"\Processor(_Total)\% Processor Time".as_ptr() as *const c_char,
0,
amp;mut cpu_total,
);
assert_eq!(err, ERROR_SUCCESS as i32);
let mut counter_val: PDH_FMT_COUNTERVALUE = std::mem::zeroed();
let err = PdhCollectQueryData(cpu_query);
assert_eq!(err, ERROR_SUCCESS as i32);
std::thread::sleep(std::time::Duration::from_millis(1000));
let err = PdhCollectQueryData(cpu_query);
assert_eq!(err, ERROR_SUCCESS as i32);
let err = PdhGetFormattedCounterValue(
cpu_total,
PDH_FMT_DOUBLE,
ptr::null_mut(),
amp;mut counter_val,
);
assert_eq!(err, ERROR_SUCCESS as i32);
println!("{:?}", counter_val.u.doubleValue());
}
}
Комментарии:
1. Вау, большое вам спасибо! Это работает отлично, и я, деффо, добавлю больше обработки ошибок. Очевидно, мне еще многое предстоит узнать о Rust, но я очень ценю это.
2. Добро пожаловать, рад, что я смог помочь 🙂 если вы изучаете Rust, то вы определенно делаете это трудным путем, используя Windows API напрямую
3. Я новичок, я создал другие небольшие фрагменты в Rust (не волнуйтесь, на гораздо более высоком уровне, чем то, что я опубликовал в своем вопросе), но я очень новичок в системном программировании и особенно в Windows API. Но я младший и перешел от базовых программ и решения вопросов с LeetCode в Rust к этому lmao. Еще раз спасибо, приятель.