You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 00:55:54