(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
。您之前所做的是使 ppads
与 pads
的值相同,从而告诉函数 *void
结果应写入 null
。不好。这使得参数指向改为pads
。
并且未初始化与 null
的区别是没有实际意义的,因为该函数的目标是无论如何都要覆盖它。
我正在尝试按照 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
。您之前所做的是使 ppads
与 pads
的值相同,从而告诉函数 *void
结果应写入 null
。不好。这使得参数指向改为pads
。
并且未初始化与 null
的区别是没有实际意义的,因为该函数的目标是无论如何都要覆盖它。