P/Invoke调用OREnumValue返回ERROR_INVALID_PARAMETER错误如何解决
问题原因与解决方案
你遇到的ERROR_INVALID_PARAMETER(0x57)错误由两个核心问题导致:
- P/Invoke声明的字符集配置错误:Offreg.dll的所有导出函数仅提供Unicode实现,不存在ANSI版本,你使用
CharSet.Auto会导致字符长度计算逻辑与非托管API预期不匹配 - 可选参数传参不符合API校验规则:OREnumValue的
lpcbData参数为可选参数,如果你不需要获取值内容,仅需要查询值名称,必须将该参数显式传NULL,你当前声明为ref uint会始终传入非空指针,触发Offreg的严格参数校验失败
修正后的代码
1. P/Invoke声明修正
// 仅用于查询值名称的重载,不需要类型和数据参数时使用 [DllImport("Offreg.dll", CharSet = CharSet.Unicode, SetLastError = false)] public static extern uint OREnumValue( SafeRegistryHandle Handle, uint dwIndex, IntPtr lpValueName, ref uint lpcValueName, IntPtr lpType, IntPtr lpData, IntPtr lpcbData); // 可选补充:需要读取值内容时的重载 [DllImport("Offreg.dll", CharSet = CharSet.Unicode, SetLastError = false)] public static extern uint OREnumValue( SafeRegistryHandle Handle, uint dwIndex, IntPtr lpValueName, ref uint lpcValueName, out uint lpType, IntPtr lpData, ref uint lpcbData);
2. GetValueNames实现修正
public class OfflineRegistryKey : IDisposable { private readonly SafeRegistryHandle hKey; private const uint ERROR_NO_MORE_ITEMS = 0x103; private const uint ERROR_MORE_DATA = 0xEA; private const uint ERROR_SUCCESS = 0; public string[] GetValueNames() { List<string> valueNames = new List<string>(); uint dwIndex = 0; while (true) { uint nameCharLength = 0; // 首次调用查询所需的名称缓冲区长度 uint ret = OREnumValue(hKey, dwIndex, IntPtr.Zero, ref nameCharLength, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); if (ret == ERROR_NO_MORE_ITEMS) { break; } if (ret != ERROR_MORE_DATA) { throw new Win32Exception((int)ret); } // 缓冲区长度+1兼容末尾空字符 nameCharLength++; IntPtr nameBuffer = Marshal.AllocHGlobal((int)nameCharLength * 2); // Unicode每个字符占2字节 try { ret = OREnumValue(hKey, dwIndex, nameBuffer, ref nameCharLength, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); if (ret == ERROR_SUCCESS) { valueNames.Add(Marshal.PtrToStringUni(nameBuffer, (int)nameCharLength)); } else { throw new Win32Exception((int)ret); } } finally { Marshal.FreeHGlobal(nameBuffer); } dwIndex++; } return valueNames.ToArray(); } // 其余IDisposable实现逻辑省略 }
额外注意事项
- 确保你使用的
SafeRegistryHandle是对Offreg返回的ORHKEY句柄的正确封装,句柄释放逻辑要匹配Offreg的ORCloseKey函数 - 如果后续需要读取值内容,使用第二个重载传入对应的类型、数据缓冲区参数即可
内容的提问来源于stack exchange,提问作者AveryM
相关产品推荐
相关产品推荐

