WinAPI OpenQuery Выдает ошибки

#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. Еще раз спасибо, приятель.