(使用winapi crate)
在没有示例的情况下,我很难弄清楚如何在 Rust 中使用 WinAPI 函数。我觉得我几乎拥有它......但在将 WinAPI 类型转换为我的 Rust 类型时遇到一些问题。我不太确定我应该如何确定它。
我正在尝试调用 GetGeoInfoA 函数(超链接到微软文档)。
这是我当前的代码尝试:
unsafe {
let mut geo_data: Vec<i8> = Vec::new();
let result = GetGeoInfoA(2, 0, &mut geo_data[0], geo_data.len().try_into().unwrap(), 0);
println!("GEO RESULT: {:#?}", String::from_utf8(mem::transmute(&geo_data[..result as usize])).unwrap());
};
尽管我得到: “不能在不同大小的类型或大小相关的类型之间转换 源类型:
&[i8]
(128 位)
目标类型:Vec<u8>
(192 位)”
...这,我相当期待。但我觉得我处理这个问题的方法都是错误的。
例如,我如何知道从哪里获取函数在其第二个参数中调用的“GeoType”?它要求使用 u32,所以我猜测不同的选项是通过索引进行索引和选择的?我在哪里可以找到这些信息?
归根结底,我需要弄清楚如何让 GetGeoInfoA 函数正常工作,尽管非常感谢任何额外的提示!
您的代码有多个问题:
&mut geo_data[0]
。这是一个旧的 C++ 模式,甚至在 C++ 中它也已被弃用。请使用 geo_data.as_mut_ptr()
来代替。transmute
- transmute
可能会破坏很多东西,应该非常小心地使用,并且只有在使用它的人绝对理解它的作用的情况下。就您而言,这不仅无效,而且是错误且危险的。Vec
转换为 String
时,您正在混淆拥有的向量和切片。如果您获取子切片(通过 &geo_data[..result as usize]
),则无法将其转换为 String
,因为它不拥有数据。当然,您可以从中创建一个 &str
。但如果您想调整 Vec
的大小,请使用 .resize()
。Vec
是空的。用一些零填充它。0
,表示错误。Vec
的类型为 i8
,而 String
则需要 u8
。由于这两种类型是二进制兼容的,因此您可以将 Vec
更改为 Vec<u8>
并将指向它的指针转换为 i8
指针。解决了所有这些问题后,这里是一些工作代码:
use winapi::um::errhandlingapi::GetLastError;
use winapi::um::winnls::GetGeoInfoA;
fn main() {
let mut geo_data = vec![0u8; 10];
let result = unsafe {
GetGeoInfoA(
2,
6,
geo_data.as_mut_ptr().cast(),
geo_data.len().try_into().unwrap(),
0,
)
};
if result == 0 {
let err = unsafe { GetLastError() };
println!("Query failed with error: {}", err);
} else {
// Cut off the excess data
geo_data.resize(result as usize, 0);
println!("GEO RESULT: {}", String::from_utf8(geo_data).unwrap());
}
}
GEO RESULT: de-ag