【问题标题】:C# Offreg.dll 'System.AccessViolationException' ORGetValueC# Offreg.dll 'System.AccessViolationException' ORGetValue
【发布时间】:2012-10-12 07:16:49
【问题描述】:

我正在尝试从脱机配置单元中包含的注册表项中获取值。代码会编译,但我得到“System.AccessViolationException”或程序刚刚关闭。

我认为程序正在尝试读取或写入未分配的内存。但是我尝试使用 stringbuilder 为 myValue 分配内存。

当我将 pcbData 设置为任何低于 66 的值时,我得到的返回值为 234,这意味着指定的缓冲区大小不足以容纳数据。

OROpenHive 似乎正在工作,因为我得到的返回值为 0。

http://msdn.microsoft.com/en-us/library/ee210767(v=vs.85).aspx处的 ORGetValue 语法

DWORD ORGetValue(
    _In_         ORHKEY Handle,
    _In_opt_     PCWSTR lpSubKey,
    _In_opt_     PCWSTR lpValue,
    _Out_opt_    PDWORD pdwType,
    _Out_opt_    PVOID pvData,
    _Inout_opt_  PDWORD pcbData
);

这是我的代码:

    [DllImport("offreg.dll", CharSet = CharSet.Auto, EntryPoint = "ORGetValue",          SetLastError = true, CallingConvention = CallingConvention.StdCall)]
    public static extern uint ORGetValue(
        IntPtr Handle, 
        string lpSubKey, 
        string lpValue, 
        out uint pdwType, 
        out StringBuilder pvData, 
        ref uint pcbData);

    [DllImport("offreg.dll", CharSet = CharSet.Auto)]
    public static extern uint OROpenHive(
        String lpHivePath,
        out IntPtr phkResult);

    private void button2_Click(object sender, EventArgs e)
    {
        IntPtr myHive;
        String filepath = @"C:\Users\JON\Desktop\NTUSER.DAT";

        StringBuilder myValue = new StringBuilder("", 256);
        uint pdwtype;
        uint pcbdata = 66;

        uint ret2 = OROpenHive(filepath, out myHive);
        this.textBox1.Text = ret2.ToString();

        uint ret3 = ORGetValue(myHive, "Environment", "TEMP", out pdwtype, out myValue,  ref pcbdata);
        this.textBox1.Text = ret3.ToString();
    }

【问题讨论】:

    标签: c# winapi registry


    【解决方案1】:

    你把结果弄错了。 pcbdata 应该传入缓冲区的大小,它会包含函数返回后实际读取的字符数。

    Winapi 函数不知道缓冲区的大小,因此即使您分配 256 个字节,您也会告诉 ORGetValue 您只分配了 66 个...如果您正在读取需要超过 66 个字节的密钥,它将返回234(或ERROR_MORE_DATA)。

    你通常会这样做:

    StringBuilder myValue = new StringBuilder("", 256);
    uint pcbdata = myValue.Capacity;
    //...
    uint ret3 = ORGetValue(myHive, "Environment", "TEMP", out pdwtype, out myValue,  ref pcbdata);
    this.textBox1.Text = "Read " + pcbdata.ToString() + " bytes - returned: " + ret3.ToString();
    

    如果您的密钥为 66 字节,则应为:Read 66 bytes - returned: 0

    【讨论】:

    • 我一定错过了什么。 Visual Basic 不允许 uint pcbdata = myValue.Capacity();
    • 您基本上为返回的字符串分配了 256 个字节,但告诉函数您只分配了 66 个字节(因此该函数认为您的缓冲区只有 66 个字节长)。如果它需要超过 66 个字节,它会报错。
    • 抱歉,我搞砸了编辑按钮。我想说的是这个。 Visual Basic 不允许 uint pcbdata = myValue.Capacity();我不断收到“Non-Invocable member 'System.Text.StringBuilder.Capacity' 不能像方法一样使用”。
    • 即使将 pcbdata 的值更改为 256,我仍然收到 System.AccessViolationException。
    • 哦,抱歉,没看到:尽量不要在StringBuilder 参数上使用out...返回时您没有得到StringBuilder,您正在填写一个你传入。删除定义和调用中的out
    猜你喜欢
    • 1970-01-01
    • 2013-12-22
    • 1970-01-01
    • 2012-05-02
    • 2010-09-15
    • 1970-01-01
    • 1970-01-01
    • 2011-01-22
    • 1970-01-01
    相关资源
    最近更新 更多