如何为Rust Windows crate中的RegGetValueW分配内存?注册表值读取异常问题求助
解决Rust调用RegGetValueW返回ERROR_MORE_DATA的问题
我来帮你分析下问题所在,以及对应的解决方法:
核心问题分析
你的Rust代码有两个关键错误,导致了和C++版本不一致的结果:
宽字符串参数传递错误
RegGetValueW是Windows API的宽字符版本,要求传入的子键路径是LPCWSTR(UTF-16编码的宽字符串)。但你直接传递了UTF-8格式的&str,这会导致API无法正确识别子键路径,甚至引发未定义行为——这也是为什么返回的size值(14)和C++版本(12)不符的原因之一。缓冲区大小初始化错误
根据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
相关产品推荐
相关产品推荐

