【问题标题】:P/Invoke: OREnumValue returning ERROR_INVALID_PARAMETERP/Invoke:OREnumValue 返回 ERROR_INVALID_PARAMETER
【发布时间】:2022-01-03 05:19:23
【问题描述】:

我正在为非托管Offline Registry Library 编写一个基本的.NET 包装器。目前,我正在努力实现一个类 OfflineRegistryKey,它以 Microsoft.Win32.RegistryKey 为模型,但旨在用于离线 Registry Hives 而不是实时系统 Registry。

在尝试实现与 GetValueNames() 方法等效的方法(枚举注册表项中的值)时,我在尝试从 Offreg.dll 中 P/Invoke 非托管函数 OREnumValue 时遇到了一些麻烦。在这种情况下,我唯一感兴趣的参数是值的名称,或 lpValueName

我的 OREnumValue 的 P/Invoke 代码:

[DllImport("Offreg.dll", CharSet = CharSet.Auto, SetLastError = false)]
public static extern uint OREnumValue(
    SafeRegistryHandle Handle,
    uint dwIndex,
    IntPtr lpValueName,
    ref uint lpcValueName,
    IntPtr lpType,
    IntPtr lpData,
    ref uint lpcbData);

我在我的代码中这样调用函数:

public class OfflineRegistryKey : IDisposable
{
    private readonly SafeRegistryHandle hKey;

    public string[] GetValueNames()
    {
        uint dwIndex = 0;
        while (true)
        {
            uint lpcValueName = 0;
            uint lpcbData = 0;

            uint returnValue = OREnumValue(hKey, dwIndex, IntPtr.Zero, ref lpcValueName, IntPtr.Zero, IntPtr.Zero, ref lpcbData);
            if (returnValue == 0x0103) // ERROR_NO_MORE_ITEMS
            {
                break;
            }
            else if (returnValue == 0x00EA) // ERROR_MORE_DATA
            {
                // Do stuff...
            }
            else
            {
                throw new Win32Exception(returnValue);
            }

            dwIndex++;
        }
    }
}
        

理想情况下,对 OREnumKey 的调用将返回 0xEA (ERROR_MORE_DATA),之后将再次调用它,直到到达结束索引并返回 0x103 (ERROR_NO_MORE_ITEMS)。

我得到的返回值(在运行时抛出异常并在循环的第一次迭代时停止执行)是0x57 (ERROR_INVALID_PARAMETER),这让我相信我以某种方式搞砸了 P /调用调用。如果对 P/Invoke 和 Windows API 有更深入了解的人可以为我提供一些指导,我将不胜感激。

谢谢!

【问题讨论】:

标签: c# winapi runtime-error registry pinvoke


【解决方案1】:

您的 P/Invoke 声明不正确,因为 lpValueName 不接受 NULL according to the documentation

它也被定义为 Unicode,所以你应该指定它。

[DllImport("Offreg.dll", CharSet = CharSet.Unicode, SetLastError = false)]
public static extern uint OREnumValue(
    SafeRegistryHandle Handle,
    uint dwIndex,
    [Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder lpValueName,
    ref uint lpcValueName,
    IntPtr lpType,
    IntPtr lpData,
    ref uint lpcbData);

然后您只需传递一个预先分配的缓冲区。理论上it could be 16383 characters,你可以使用ORQueryInfoKey 来获得最大大小,或者只是分配整个东西。我建议你只在循环外分配一次。

public string[] GetValueNames()
{
    const int ERROR_SUCCESS = 0;
    const int ERROR_NO_MORE_ITEMS = 0x103;
    const int ERROR_MORE_DATA = 0x00EA;
    uint dwIndex = 0;
    string lpValueName = new StringBuilder(16384);
    while (true)
    {
        uint lpcValueName = 0;
        uint lpcbData = 0;

        uint returnValue = OREnumValue(hKey, dwIndex, IntPtr.Zero, ref lpcValueName, IntPtr.Zero, IntPtr.Zero, ref lpcbData);
        if (returnValue == ERROR_NO_MORE_ITEMS)
        {
            break;
        }
        else if (returnValue == ERROR_MORE_DATA)
        {
            // Do stuff...
        }
        else if (returnValue != ERROR_SUCCESS)
        {
            throw new Win32Exception(returnValue);
        }

        dwIndex++;
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-04
    • 1970-01-01
    相关资源
    最近更新 更多