【问题标题】:Implement IWbemObjectSink interface in Rust在 Rust 中实现 IWbemObjectSink 接口
【发布时间】:2021-03-31 03:05:41
【问题描述】:

我希望能够在 Rust 中调用 SWbemServices 的 ExecQueryAsync,就像在 C++ 中的这个示例一样: https://docs.microsoft.com/fr-fr/windows/win32/wmisdk/example--getting-wmi-data-from-the-local-computer-asynchronously

我的问题是它需要 IWbemObjectSink 的实现,而 winapi 中没有。 winapi crates 提供an interface definition in Rust,但我应该如何在 Rust 中“实现”它? 我可以编写一个尊重接口的结构,我可以从 winapi crate 导入接口,但是我怎样才能将两者粘合在一起?

我还用 com-rs crate 做了一些实验,因为它提供了an example to implement an interface with the com::class! macro 但我能做的是创建另一个IWbemObjectSink接口并实现它,而不是从winapi::um::wbemcli:IWbemObjectSink开始并实现它......

感谢您的见解

【问题讨论】:

  • “但我能做的是创建另一个 IWbemObjectSink 接口并实现它” - 这正是你想要的。这是您提供自定义回调实现的机会,然后您将其传递给ExecQueryAsync。后者会针对它收到的每个结果调用您的 Indicate 实现。您链接到的 C++ 示例代码正是这样做的(请参阅 QuerySink.hQuerySink.cpp 文件)。所以这就是你的解决方案,除非我误解了这个问题。
  • 您好@IInspectable 感谢您的回答,在我的上下文中,我“不能”创建一个新接口,即使它与winapi::um::wbemcli:IWbemObjectSink 完全相同,因为 Rust 编译器不会请允许我将我的接口提供给ExecQueryAsync,而不是winapi::um::wbemcli:IWbemObjectSink。 winapi crate 的维护者建议我查看com-impl crate 而不是更新的com crate,因为最后一个与 winapi 不兼容。只要我有一个工作示例,我就会将它发布在这里(目前,它可以编译,这是一个很好的第一步!)

标签: winapi rust interface com wmi


【解决方案1】:

如果有人尝试实现 winapi 板条箱的 COM 接口,例如 IWbemObjectSink,而 WMI 没有提供实现,这里有一个方法。

不要使用 Microsoft 维护的 com-rs crate,只要它们不添加对 winapi crate 的支持。更喜欢 com-impl crate,结合 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
    }
}

其他一些有用的信息:

如果您需要将成员添加到您的班级(此处为 yoloswag),请执行以下操作:

#[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) }
    }
}

com-impl将方法名从snake_case转换为PascalCase。

这就是为什么我的 QuerySink 使用了 set_statusindicate,它们映射到 SetStatusIndicate。 com-impl 提供了#[com_name = "..."] 属性,如果您想按照自己的方式进行操作。了解细节最好的方法是看https://github.com/Connicpu/com-impl/blob/master/derive-com-impl/src/lib.rs中的cmets

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-03-01
    • 2018-07-25
    • 2012-02-01
    • 2016-07-03
    • 2012-03-20
    • 2011-05-06
    相关资源
    最近更新 更多