Rust WinApi中如何将LPVOID转换为NETRESOURCEW结构体?
Rust WinApi 枚举网络计算机:LPVOID 转 NETRESOURCEW 解决方案
你的核心问题是不能直接将LPVOID(即*mut c_void)转换成NETRESOURCEW结构体——LPVOID是无类型指针,指向的是NETRESOURCEW结构体数组的起始地址,而非单个结构体实例。正确做法是先将其转换为*mut NETRESOURCEW指针,再基于枚举返回的条目数生成切片遍历。另外你的代码存在内存泄漏,需在结束后调用GlobalFree释放分配的内存。
修改后的完整代码
use winapi::{ shared::minwindef::{DWORD, HANDLE, LPVOID}, um::{ winbase::GlobalFree, winnetwk::{ WNetCloseEnum, WNetEnumResourceW, WNetOpenEnumW, ERROR_NO_MORE_ITEMS, NO_ERROR, RESOURCE_GLOBALNET, RESOURCETYPE_ANY, NETRESOURCEW, LPNETRESOURCEW, }, }, }; fn enumerate_network_computers(lpnr: LPNETRESOURCEW) -> u32 { unsafe { let mut h_enum: HANDLE = std::ptr::null_mut(); let mut cb_entries: DWORD = 9999; let mut cb_buffer: DWORD = 16384; let lpnr_local: LPVOID = winapi::um::winbase::GlobalAlloc(winapi::um::winbase::GPTR, cb_buffer as usize); if lpnr_local.is_null() { return winapi::um::winerror::ERROR_NOT_ENOUGH_MEMORY; } let mut dw_err = WNetOpenEnumW( RESOURCE_GLOBALNET, RESOURCETYPE_ANY, 0, lpnr, &mut h_enum, ); if dw_err != NO_ERROR { GlobalFree(lpnr_local); return dw_err; } loop { // 每次枚举前重置参数 cb_entries = 9999; cb_buffer = 16384; dw_err = WNetEnumResourceW( h_enum, &mut cb_entries, lpnr_local as LPNETRESOURCEW, // 强制转换为NETRESOURCEW指针 &mut cb_buffer, ); if dw_err == NO_ERROR || dw_err == winapi::um::winerror::ERROR_MORE_DATA { // 将指针转为切片,遍历所有枚举到的资源 let resources = std::slice::from_raw_parts(lpnr_local as *const NETRESOURCEW, cb_entries as usize); for res in resources { // 提取并打印远程计算机名称 if !res.lpRemoteName.is_null() { let name = String::from_utf16_lossy( std::slice::from_raw_parts(res.lpRemoteName, 0..) .iter() .take_while(|&&c| c != 0) .copied() .collect::<Vec<_>>() ); println!("网络计算机: {}", name); } } } if dw_err == ERROR_NO_MORE_ITEMS { break; } else if dw_err != NO_ERROR && dw_err != winapi::um::winerror::ERROR_MORE_DATA { break; } } // 清理资源:关闭枚举句柄、释放内存 WNetCloseEnum(h_enum); GlobalFree(lpnr_local); dw_err } }
关键修改说明
- 指针类型转换:将
lpnr_local(LPVOID)强制转为LPNETRESOURCEW(*mut NETRESOURCEW),因为WNetEnumResourceW会把枚举结果写入该指针指向的内存,内存布局为NETRESOURCEW数组。 - 切片遍历:用
std::slice::from_raw_parts将指针转为切片,长度由cb_entries(实际返回的条目数)决定,实现安全遍历。 - 宽字符串处理:
NETRESOURCEW的字段是UTF-16宽字符串,通过String::from_utf16_lossy转换为Rust字符串,需截断到第一个空字符(\0)。 - 资源清理:添加
WNetCloseEnum关闭枚举句柄、GlobalFree释放内存,避免泄漏。 - 错误完善:处理
ERROR_MORE_DATA(缓冲区不足)的情况,若实际场景中遇到可动态调整缓冲区大小。
内容的提问来源于stack exchange,提问作者NikoBosko
相关产品推荐
相关产品推荐

