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

如何为Rust Windows crate中的RegGetValueW分配内存?注册表值读取异常问题求助

解决Rust调用RegGetValueW返回ERROR_MORE_DATA的问题

我来帮你分析下问题所在,以及对应的解决方法:

核心问题分析

你的Rust代码有两个关键错误,导致了和C++版本不一致的结果:

  1. 宽字符串参数传递错误
    RegGetValueW是Windows API的宽字符版本,要求传入的子键路径是LPCWSTR(UTF-16编码的宽字符串)。但你直接传递了UTF-8格式的&str,这会导致API无法正确识别子键路径,甚至引发未定义行为——这也是为什么返回的size值(14)和C++版本(12)不符的原因之一。

  2. 缓冲区大小初始化错误
    根据Windows API文档,当你传递非NULL的pvData缓冲区时,pcbData参数必须初始化为缓冲区的字节大小。你的代码里把my_size初始化为0,相当于告诉API“缓冲区大小为0”,它自然会直接返回ERROR_MORE_DATA,并把所需的最小字节数写入size。

修正后的Rust代码

下面是修复后的完整代码,同时加入了更健壮的错误处理逻辑:

use winapi::{
    shared::minwindef::{DWORD, LPCWSTR, LSTATUS},
    um::winreg::{RegGetValueW, HKEY_CURRENT_USER, RRF_RT_REG_SZ},
};
use std::os::windows::ffi::OsStrExt;
use std::ffi::OsStr;
use std::iter::once;

fn main() {
    unsafe {
        // 将子键路径转换为UTF-16宽字符串(必须包含终止null字符)
        let subkey: Vec<u16> = OsStr::new("SOFTWARE\\MyTest\\foo")
            .encode_wide()
            .chain(once(0))
            .collect();
        
        // 初始化缓冲区:64个u16,字节大小为 64 * 2 = 128
        let mut value: Vec<u16> = vec![0; 64];
        let mut buffer_size: DWORD = (value.len() * std::mem::size_of::<u16>()) as DWORD;
        
        let result = RegGetValueW(
            HKEY_CURRENT_USER,
            subkey.as_ptr() as LPCWSTR,
            std::ptr::null(), // 对应C++的NULL,读取默认值
            RRF_RT_REG_SZ,
            std::ptr::null_mut(),
            value.as_mut_ptr() as *mut _,
            &mut buffer_size,
        );

        match result {
            0 => { // ERROR_SUCCESS
                // 从缓冲区提取有效字符串(忽略终止null字符)
                let value_str = String::from_utf16_lossy(&value[..(buffer_size as usize)/2]);
                println!("Value data: {} ({})", value_str, buffer_size);
            }
            234 => { // ERROR_MORE_DATA
                println!("缓冲区不足,需要{}字节", buffer_size);
                // 根据所需大小重新分配缓冲区并再次尝试
                let mut resized_value = vec![0; (buffer_size as usize)/2];
                let mut new_size = buffer_size;
                let retry_result = RegGetValueW(
                    HKEY_CURRENT_USER,
                    subkey.as_ptr() as LPCWSTR,
                    std::ptr::null(),
                    RRF_RT_REG_SZ,
                    std::ptr::null_mut(),
                    resized_value.as_mut_ptr() as *mut _,
                    &mut new_size,
                );
                if retry_result == 0 {
                    let value_str = String::from_utf16_lossy(&resized_value[..(new_size as usize)/2]);
                    println!("重试成功:Value data: {} ({})", value_str, new_size);
                } else {
                    println!("重试失败,错误码:{}", retry_result);
                }
            }
            err => println!("调用失败,错误码:{}", err),
        }
    }
}

额外说明

  • 关于size值的差异:修正路径和缓冲区大小后,你应该会得到和C++版本一致的12字节结果(对应hello\0共6个UTF-16字符,每个字符2字节)。
  • 宽字符串处理:务必确保传递给RegGetValueW的路径包含终止null字符,否则API可能读取越界内存。
  • 健壮性优化:处理注册表值时,先传递小缓冲区获取所需大小,再重新分配足够内存读取是标准做法,避免提前分配过大内存。

内容的提问来源于stack exchange,提问作者EndlessFlapjacks

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 23:37:45