在discussing/learning about the correct way to call a FFI of the Windows-API from Rust之后,我进一步玩了一下,想要仔细检查我的理解 .
我有一个被调用两次的Windows API . 在第一次调用中,它返回实际out参数所需的缓冲区大小 . 然后,使用足够大小的缓冲区第二次调用它 . 我目前正在使用 Vec
作为此缓冲区的数据类型(请参阅下面的示例) .
代码有效,但我想知道这是否是正确的方法,或者是否更好地利用像 alloc::heap::allocate
这样的函数直接保留一些内存,然后使用 transmute
将结果从FFI转换回来 . 我的代码再次起作用,但我试图在幕后看一点 .
extern crate advapi32;
extern crate winapi;
extern crate widestring;
use widestring::WideCString;
use std::io::Error as IOError;
use winapi::winnt;
fn main() {
let mut lp_buffer: Vec<winnt::WCHAR> = Vec::new();
let mut pcb_buffer: winapi::DWORD = 0;
let rtrn_bool = unsafe {
advapi32::GetUserNameW(lp_buffer.as_mut_ptr(),
&mut pcb_buffer )
};
if rtrn_bool == 0 {
match IOError::last_os_error().raw_os_error() {
Some(122) => {
// Resizing the buffers sizes so that the data fits in after 2nd
lp_buffer.resize(pcb_buffer as usize, 0 as winnt::WCHAR);
} // This error is to be expected
Some(e) => panic!("Unknown OS error {}", e),
None => panic!("That should not happen"),
}
}
let rtrn_bool2 = unsafe {
advapi32::GetUserNameW(lp_buffer.as_mut_ptr(),
&mut pcb_buffer )
};
if rtrn_bool2 == 0 {
match IOError::last_os_error().raw_os_error() {
Some(e) => panic!("Unknown OS error {}", e),
None => panic!("That should not happen"),
}
}
let widestr: WideCString = unsafe { WideCString::from_ptr_str(lp_buffer.as_ptr()) };
println!("The owner of the file is {:?}", widestr.to_string_lossy());
}
依赖关系:
[dependencies]
advapi32-sys = "0.2"
winapi = "0.2"
widestring = "*"
2 回答
理想情况下,您将使用std::alloc::alloc,因为您可以指定所需的对齐作为布局的一部分:
主要的缺点是你需要知道对齐,即使你释放了分配 .
通常的做法是使用
Vec
作为简单的分配机制,但在使用它时需要小心 .确保您的单位正确 - "length"参数是项目数还是字节数?
如果将
Vec
溶解到组件中,则需要跟踪长度和容量 . 有些人使用shrink_to_fit来确保这两个值是相同的 .
避免穿越流 - 内核由Rust分配,而 must 由Rust释放 . 将其转换回
Vec
即可删除 .注意空
Vec
确实 not 有一个NULL指针!:对于您的具体情况,我可能建议使用
Vec
的capacity
而不是自己跟踪第二个变量 . 你会注意到你忘了在第一次调用后更新pcb_buffer
,所以我很烦人,因为它需要是一个可变的引用,所以你不能完全摆脱它 .此外,您可以只使用reserve空间而不是
extend
.也不能保证第一次通话期间所需的大小与第二次通话期间所需的大小相同 . 你可以做某种循环,但是你必须担心发生无限循环 .
这就是我提出的 .
使用
u8
向量创建FFI对象,以便大小以字节为单位 . 这可以推广到使用任意类型而不是u8
,但要记住Shepmaster关于字节数和项数之间区别的警告 .这是使用
FfiObject
的示例: