【问题标题】:Read/Write on protected memory exception thrown (.net)读/写受保护的内存异常抛出(.net)
【发布时间】:2009-06-29 05:32:40
【问题描述】:

最后一行抛出的异常告诉我,我正在尝试在受保护的内存上读/写。我在这里做错了什么?谢谢

   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

【问题讨论】:

    标签: c# winapi memory-leaks marshalling


    【解决方案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());
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2021-09-03
      • 2011-01-29
      • 2023-04-08
      • 1970-01-01
      • 2010-11-17
      • 1970-01-01
      • 1970-01-01
      • 2013-08-05
      • 2014-08-07
      相关资源
      最近更新 更多