读取/写入受保护的内存异常抛出(.net)

时间:2009-06-29 05:32:40

标签: c# winapi memory-leaks marshalling

我被一个异常告知,在最后一行被抛出,我正在尝试读取/写入受保护的内存。我在这做错了什么?感谢

   int count = (int)WinApi.SendMessage(_chatHwnd, WinApi.LB_GETCOUNT, 0, 0);
    Debug.WriteLine("count=" + count);
    StringBuilder sb = new StringBuilder(count * 20);

    for (int i = _lastReadPosition; i < count; i++) {
        int len = (int)WinApi.SendMessage(_chatHwnd, WinApi.LB_GETTEXTLEN, i, 0);

        IntPtr text = Marshal.AllocHGlobal(len);
        byte[] itemText = new byte[len];

        WinApi.SendMessage(_chatHwnd, WinApi.LB_GETTEXT, i, text.ToInt32());
        Marshal.Copy(text, itemText, 0, len);

        string s = System.Text.Encoding.UTF8.GetString(itemText);
        sb.Append(s);
    }
    Debug.WriteLine("analise"); <- EXCEPTION THROWN HERE

1 个答案:

答案 0 :(得分:1)

来自msdn:

<强> LB_GETTEXTLEN

  

返回值是字符串的长度,在TCHAR中,不包括终止空字符。在某些条件下,此值实际上可能大于文本的长度。有关更多信息,请参阅以下备注部分。

<强> LB_GETTEXT

  

指向将接收字符串的缓冲区的指针;它是LPTSTR类型,随后被转换为LPARAM。缓冲区必须有足够的空间用于字符串和终止空字符。可以在LB_GETTEXT消息之前发送LB_GETTEXTLEN消息,以检索字符串的长度(在TCHAR中)。

您需要为一个额外的空TCHAR提供空间。但是,我在您的代码中看到了其他几个问题:

  • 您的系统是WinNT?然后lb_gettextlen在TCHAR中返回长度,在NT系统上,一个TCHAR长度为两个字节
  • 我看到AllocHGlobal,但我没有看到FreeHGlobal。内存泄漏?
  • 为什么使用UTF8编码将字节数组转换为字符串?您需要使用Unicode。
  • 您的SendMessage接口可能存在危险,因为它不期望x64指针。

更新:通常,您的代码必须如下所示:

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
private static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
private static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, 
    [MarshalAs(UnmanagedType.LPTStr)] StringBuilder lParam);

private void Form1_Shown(object sender, EventArgs e)
{
    int count = (int)SendMessage(_chatHwnd, WinApi.LB_GETCOUNT, IntPtr.Zero, IntPtr.Zero);
    StringBuilder sb = new StringBuilder(count * 20);

    for (int i = _lastReadPosition; i < count; i++)
    {
        int len = (int)SendMessage(_chatHwnd, WinApi.LB_GETTEXTLEN, (IntPtr)i, IntPtr.Zero);
        StringBuilder LineBuilder = new StringBuilder(len + 1);
        SendMessage(_chatHwnd, WinApi.LB_GETTEXT, (IntPtr)i, LineBuilder);
        sb.Append(LineBuilder.ToString());
    }
}