使用Rust的windows-rs调用WlanGetAvailableNetworkList遇索引越界问题
问题描述
尝试通过WlanGetAvailableNetworkList获取所有可用网络列表,但根据dwNumberOfItems遍历网络数组时,仅能显示第一个网络,索引超过0时触发index out of bounds: the len is 1 but the index is 1错误,代码如下:
let mut w_handle: HANDLE = HANDLE::default(); let mut current_version: u32 = 0; if WIN32_ERROR(WlanOpenHandle(2, None, &mut current_version, &mut w_handle)) != ERROR_SUCCESS { return; } let mut wlan_interface_info_list = std::ptr::null_mut(); if WIN32_ERROR(WlanEnumInterfaces(w_handle, None, &mut wlan_interface_info_list)) != ERROR_SUCCESS { return; } for i in 0..wlan_interface_info_list.as_ref().unwrap().dwNumberOfItems { let interface_info = wlan_interface_info_list.as_ref().unwrap().InterfaceInfo[i as usize]; let interface_name = interface_info.strInterfaceDescription; let mut available_network_list = std::mem::zeroed(); if WIN32_ERROR(WlanGetAvailableNetworkList(w_handle, &interface_info.InterfaceGuid, 0, None, &mut available_network_list)) != ERROR_SUCCESS { continue; } let list = available_network_list.as_ref().unwrap(); println!("Number of available networks on {}: {}", String::from_utf16_lossy(&interface_name), list.dwNumberOfItems); for j in 0..list.dwNumberOfItems { let network_name = (*list).Network[j as usize].strProfileName; // <- Panicked println!("Network name: {}", String::from_utf16_lossy(&network_name)); } } WlanCloseHandle(w_handle, None);
问题原因
Win32 API绑定中,WLAN_AVAILABLE_NETWORK_LIST结构体的Network字段被声明为[WLAN_AVAILABLE_NETWORK; 1],这是C语言可变长度数组的常见Rust表示方式——仅标记数组的起始位置,而非实际长度。Rust会将其视为固定长度为1的数组,所以直接用索引访问j >=1的位置会触发越界错误。
解决方法
需要将Network字段的起始指针转换为对应长度的Rust切片,再进行遍历,同时别忘了释放WlanGetAvailableNetworkList返回的内存(否则会造成内存泄漏)。
修改后的完整代码:
let mut w_handle: HANDLE = HANDLE::default(); let mut current_version: u32 = 0; if WIN32_ERROR(WlanOpenHandle(2, None, &mut current_version, &mut w_handle)) != ERROR_SUCCESS { return; } let mut wlan_interface_info_list = std::ptr::null_mut(); if WIN32_ERROR(WlanEnumInterfaces(w_handle, None, &mut wlan_interface_info_list)) != ERROR_SUCCESS { return; } for i in 0..wlan_interface_info_list.as_ref().unwrap().dwNumberOfItems { let interface_info = wlan_interface_info_list.as_ref().unwrap().InterfaceInfo[i as usize]; let interface_name = interface_info.strInterfaceDescription; let mut available_network_list = std::mem::zeroed(); if WIN32_ERROR(WlanGetAvailableNetworkList(w_handle, &interface_info.InterfaceGuid, 0, None, &mut available_network_list)) != ERROR_SUCCESS { continue; } let list = available_network_list.as_ref().unwrap(); println!("Number of available networks on {}: {}", String::from_utf16_lossy(&interface_name), list.dwNumberOfItems); // 将Network指针转换为指定长度的切片 let networks = unsafe { std::slice::from_raw_parts(list.Network.as_ptr(), list.dwNumberOfItems as usize) }; // 遍历切片获取所有网络 for network in networks { let network_name = network.strProfileName; println!("Network name: {}", String::from_utf16_lossy(&network_name)); } // 释放WlanGetAvailableNetworkList返回的内存 unsafe { WlanFreeMemory(available_network_list as *mut _); } } // 释放WlanEnumInterfaces返回的接口列表内存 unsafe { WlanFreeMemory(wlan_interface_info_list as *mut _); } WlanCloseHandle(w_handle, None);
注:原代码遗漏了
WlanEnumInterfaces返回列表的内存释放,已补充,避免内存泄漏。
内容的提问来源于stack exchange,提问作者ymgpwcca
相关产品推荐
相关产品推荐

