首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何分配空间使用windows机箱调用GetInterfaceInfo?

如何分配空间使用windows机箱调用GetInterfaceInfo?
EN

Stack Overflow用户
提问于 2022-09-12 17:43:31
回答 1查看 100关注 0票数 0

我正在尝试使用微软的GetInterfaceInfo机箱获取有关系统上可用的网络接口的信息。这需要我做一些不安全的操作,我让它工作在一个接口上,而不是两个界面上:

代码语言:javascript
复制
#[cfg(test)]
mod tests {
    use super::*;
    use windows::{
        core::*, Data::Xml::Dom::*, Win32::Foundation::*, Win32::NetworkManagement::IpHelper::*,
        Win32::System::Threading::*, Win32::UI::WindowsAndMessaging::*,
    };

    #[test]
    fn main() {
        unsafe {
            let mut dw_out_buf_len: u32 = 0;

            let mut dw_ret_val =
                GetInterfaceInfo(std::ptr::null_mut(), &mut dw_out_buf_len as *mut u32);

            if dw_ret_val != ERROR_INSUFFICIENT_BUFFER.0 {
                panic!();
            }

            println!("Size: {}", dw_out_buf_len);
            // allocate that amount of memory, which will be used as a buffer
            let mut ip_interface_info = Vec::with_capacity(dw_out_buf_len as usize);
            let mut ptr = ip_interface_info.as_mut_ptr() as *mut IP_INTERFACE_INFO;

            dw_ret_val = GetInterfaceInfo(ptr, &mut dw_out_buf_len as *mut u32);

            println!("Num adapters: {}", (*ptr).NumAdapters);
            for i in 0..(*ptr).NumAdapters as usize {
                println!(
                    "\tAdapter index: {}\n\tAdapter name: {}",
                    (*ptr).Adapter[i].Index,
                    String::from_utf16(&(*ptr).Adapter[i].Name).unwrap()
                );
            }
        }
    }
}

当我试图访问第二个条目时,它会崩溃(尽管应该有两个可用的条目):

代码语言:javascript
复制
panicked at 'index out of bounds: the len is 1 but the index is 1'

包含所有数据的结构IP_INTERFACE_INFO有一个名为Adapter的字段,该字段似乎仅限于数组大小为1。我是否正确地读取了这个字段?那么它应该如何容纳多个适配器呢?

代码语言:javascript
复制
#[repr(C)]
#[doc = "*Required features: `\"Win32_NetworkManagement_IpHelper\"`*"]
pub struct IP_INTERFACE_INFO {
    pub NumAdapters: i32,
    pub Adapter: [IP_ADAPTER_INDEX_MAP; 1],
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-09-12 18:34:37

看来IP_INTERFACE_INFO使用的是C 柔性阵列构件,通常是语法。C++在使用GetInterfaceInfo管理接口中的例子证实了这种用法:

代码语言:javascript
复制
for (i = 0; i < (unsigned int) pInterfaceInfo->NumAdapters; i++) {
    printf("  Adapter Index[%d]: %ld\n", i,
           pInterfaceInfo->Adapter[i].Index);
    printf("  Adapter Name[%d]:  %ws\n\n", i,
           pInterfaceInfo->Adapter[i].Name);
}

在Rust中,等效的方法是接受单个元素数组,获取指向它的原始指针,然后遍历它。需要注意的细节有很多,如分配对齐和指针来源。下面是一个带注释的示例:

代码语言:javascript
复制
use std::{
    alloc::{GlobalAlloc, Layout, System},
    mem,
    ptr::{self, addr_of},
    slice,
};
use windows::{
    Win32::Foundation::*,
    Win32::NetworkManagement::IpHelper::{
        GetInterfaceInfo, IP_ADAPTER_INDEX_MAP, IP_INTERFACE_INFO,
    },
};

fn main() {
    unsafe {
        // Perform the first call to know how many bytes to allocate
        let mut raw_buf_len = 0;
        let ret_val = GetInterfaceInfo(ptr::null_mut(), &mut raw_buf_len);
        assert_eq!(
            ret_val, ERROR_INSUFFICIENT_BUFFER.0,
            "Expected to get the required buffer size, was {ret_val:?}",
        );

        // Allocate an appropriately sized *and aligned* buffer to store the result
        let buf_len = raw_buf_len.try_into().expect("Invalid buffer length");
        let layout = Layout::from_size_align(buf_len, mem::align_of::<IP_INTERFACE_INFO>())
            .expect("Could not calculate the appropriate memory layout");
        let base_ptr = System.alloc(layout);
        let ip_interface_info = base_ptr.cast();

        // Perform the second call to get the data
        let ret_val = GetInterfaceInfo(ip_interface_info, &mut raw_buf_len);
        assert_eq!(
            ret_val, NO_ERROR.0,
            "Could not get the data on the second call: {ret_val:?}",
        );

        // Construct a pointer to the adapter array that preserves the provenance of the original pointer
        let adapter_ptr = addr_of!((*ip_interface_info).Adapter);
        let adapter_ptr = adapter_ptr.cast::<IP_ADAPTER_INDEX_MAP>();

        // Combine the pointer and length into a Rust slice
        let n_adapters = (*ip_interface_info).NumAdapters;
        let n_adapters = n_adapters.try_into().expect("Invalid adapter count");
        let adapters = slice::from_raw_parts(adapter_ptr, n_adapters);

        println!("Num adapters: {}", adapters.len());
        for adapter in adapters {
            let IP_ADAPTER_INDEX_MAP {
                Index: index,
                Name: name,
            } = adapter;

            // The fixed-size buffer contains data after the UTF-16 NUL character
            let name_end = name.iter().position(|&c| c == 0).unwrap_or(name.len());
            let name = String::from_utf16_lossy(&name[..name_end]);

            println!("Adapter index: {index}\nAdapter name: {name}",);
        }

        // Free the allocation. This should be wrapped in a type that
        // implements `Drop` so we don't leak memory when unwinding a panic.
        System.dealloc(base_ptr, layout);
    }
}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73693265

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档