(Rust question) C++ double pointer to void 含义

(Rust question) C++ double pointer to void meaning

我正在尝试按照 Microsoft 为 ADSI API 和 Windows-RS crate 发布的 c++ 示例使用 Rust 中的活动目录。我不太明白这里发生了什么:

https://docs.microsoft.com/en-us/windows/win32/api/adshlp/nf-adshlp-adsopenobject

他们创建了一个指向 IAD 的未初始化指针(根据我的 c# 知识,它看起来像一个接口)然后,当需要使用它时,他们有一个双指针,该指针被转换为 void。我试图在 Rust 中复制这种行为,但我想我只是不明白到底发生了什么。这是我到目前为止尝试过的:

// bindings omitted
use windows::Interface;
use libc::c_void;
 
fn main() -> windows::Result<()> {
        let mut pads: *mut IADs = ptr::null_mut();
        let ppads: *mut *mut c_void = pads as _;

        unsafe {
            let _ = CoInitialize(ptr::null_mut());
            let mut ldap_root: Vec<u16> = "LDAP://rootDSE[=10=]".encode_utf16().collect();
            let hr = ADsOpenObject(
                ldap_root.as_mut_ptr() as _,
                ptr::null_mut(),
                ptr::null_mut(),
                ADS_AUTHENTICATION_ENUM::ADS_SECURE_AUTHENTICATION.0 as _,
                & IADs::IID,
                ppads,
            );

            if !hr.is_err() {
                ...
            }

        }
   
    Ok(())
}

首先,我创建一个空指针可能是错误的,因为这不是他们在示例中所做的,但问题是 Rust 不允许使用未初始化的变量,所以我'我不确定等效项是什么。

其次,大概 pADs 变量是输出应该去的地方,但我不理解有一个指针的交互,然后是一个双指针,指向一个没有所有者的对象。即使这在 rust 中是可能的,我也觉得这不是我应该做的。

第三,一旦我通过 FFI 调用更新了指针,我如何告诉 Rust 结果输出类型是什么,以便我们可以用它做更多的工作?做 _ 是行不通的,因为它是一个结构,而且我觉得使用 transmute 是不好的

指针参数通常在 FFI 中用作 return 数据以及 return 值本身的一种方式。这个想法是指针应该指向调用将用结果填充的一些现有对象。由于 Windows API 函数经常 return HRESULT 指示成功和失败,因此它们使用指向 return 其他内容的指针。

在这种情况下,ADsOpenObject想要return一个*void(请求的ADs接口对象),所以你需要给它一个指向现有[=13的指针=] 要填充的对象:

let mut pads: *mut c_void = std::ptr::null_mut();
let ppads = &mut pads as *mut *mut c_void;

// or inferred inline

let hr = ADsOpenObject(
    ...
    &mut pads as _,
);

我将pads更改为*mut c_void以简化此演示并匹配ADsOpenObject参数。调用成功后,你可以将pads转换成任何你需要的。

主要区别在于转换 pads&mut pads。您之前所做的是使 ppadspads 的值相同,从而告诉函数 *void 结果应写入 null。不好。这使得参数指向改为pads

并且未初始化与 null 的区别是没有实际意义的,因为该函数的目标是无论如何都要覆盖它。