Реализовать интерфейс IWbemObjectSink в Rust

Я хотел бы иметь возможность вызывать ExecQueryAsync для SWbemServices в Rust, как в этом примере на C++: https://learn.microsoft.com/fr-fr/windows/win32/wmisdk/example--getting-wmi-data-from-the-local-computer-асинхронно

Моя проблема в том, что ему нужна реализация IWbemObjectSink, а в winapi ее нет. Ящики winapi предоставляют определение интерфейса в Rust, но как я должен «внедрить» его в Rust? Я могу написать структуру, учитывающую интерфейс, я могу импортировать интерфейс из корзины winapi, но как склеить их вместе?

Я также провел несколько экспериментов с крейтом com-rs, так как он предоставляет пример для реализации интерфейса с классом com::class! макрос Но что я могу сделать, так это создать другой интерфейс IWbemObjectSink и реализовать его, не начиная с winapi::um::wbemcli:IWbemObjectSink и реализовать его...

Спасибо за ваши идеи

«Но что я могу сделать, так это создать еще один интерфейс IWbemObjectSink и реализовать его» — это именно то, что вы хотите. Это ваша возможность предоставить собственную реализацию обратного вызова, которую вы затем передаете в ExecQueryAsync. Последний вызывает вашу реализацию Indicate для каждого полученного результата. Пример кода C++, на который вы ссылались, делает именно это (см. файлы QuerySink.h и QuerySink.cpp). Так что это ваше решение, если я неправильно понял проблему.

IInspectable 21.12.2020 18:41

Привет @IInspectable, спасибо за ваш ответ. В моем контексте я «не могу» создать новый интерфейс, даже если он точно такой же, как winapi::um::wbemcli:IWbemObjectSink, потому что компилятор Rust не позволит мне передать мой интерфейс ExecQueryAsync вместо а winapi::um::wbemcli:IWbemObjectSink. Сопровождающий ящик winapi советует мне изучить ящик com-impl вместо более свежего ящика com, потому что последний не совместим с winapi. Как только у меня появится рабочий пример, я опубликую его здесь (на данный момент он компилируется, что является отличным первым шагом!)

KIRGO 23.12.2020 17:15
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
0
2
229
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Если кто-то пытается реализовать COM-интерфейс контейнера winapi, такого как IWbemObjectSink, для которого WMI не предоставляет реализацию, вот способ сделать это.

НЕ используйте ящик com-rs, поддерживаемый Microsoft, пока они не добавляют поддержку ящика winapi. Отдайте предпочтение крейту com-impl в сочетании с wio ComPtr (не обязательно, но удобно).

use winapi::{
    um::wbemcli::{
        {IWbemClassObject,IWbemObjectSink, IWbemObjectSinkVtbl},
        WBEM_S_NO_ERROR,
    },
    shared::{
        ntdef::HRESULT,
        wtypes::BSTR,
    },
    ctypes::{
        c_long,
    },
};
use com_impl::{ComImpl, VTable, Refcount};
use wio::com::ComPtr;

#[repr(C)]
#[derive(ComImpl)]
#[interfaces(IWbemObjectSink)]
pub struct QuerySink {
    vtbl: VTable<IWbemObjectSinkVtbl>,
    refcount: Refcount,
}

impl QuerySink {
    pub fn new() -> ComPtr<IWbemObjectSink> {
        let ptr = QuerySink::create_raw();
        let ptr = ptr as *mut IWbemObjectSink;
        unsafe { ComPtr::from_raw(ptr) }
    }
}

// AddRef and Release methods are provided by com_impl
#[com_impl::com_impl]
unsafe impl IWbemObjectSink for QuerySink2 {
    pub unsafe fn indicate(
        &self,
        _lObjectCount: c_long,
        _apObjArray: *mut *mut IWbemClassObject
    ) -> HRESULT {
        WBEM_S_NO_ERROR as i32
    }

    pub unsafe fn set_status(
        &self,
        _lFlags: c_long,
        _hResult: HRESULT,
        _strParam: BSTR,
        _pObjParam: *mut IWbemClassObject
    ) -> HRESULT {
        WBEM_S_NO_ERROR as i32
    }
}

Еще немного полезной информации:

Если вам нужно добавить участников в свой класс (здесь yolo и swag), выполните следующие действия:

#[repr(C)]
#[derive(ComImpl)]
#[interfaces(IWbemObjectSink)]
pub struct QuerySink2 {
    vtbl: VTable<IWbemObjectSinkVtbl>,
    refcount: Refcount,
    yolo: i32,
    swag: u8,
}

impl QuerySink2 {
    pub fn new(param1: i32, param2: u8) -> ComPtr<IWbemObjectSink> {
        let ptr = QuerySink2::create_raw(param1, param2);
        let ptr = ptr as *mut IWbemObjectSink;
        unsafe { ComPtr::from_raw(ptr) }
    }
}

Имена методов преобразуются из snake_case в PascalCase с помощью com-impl.

Вот почему для моего QuerySink я использовал set_status и indicate, которые сопоставляются с SetStatus и Indicate. com-impl предоставляет атрибут #[com_name = "..."], если вы хотите сделать это по-своему. Лучший способ разобраться в деталях — просмотреть комментарии в https://github.com/Connicpu/com-impl/blob/master/derive-com-impl/src/lib.rs

Другие вопросы по теме