Исключение чтения / записи в защищенной памяти (.net) - PullRequest
0 голосов
/ 29 июня 2009

Мне сообщают об исключении, которое выдается в последней строке, что я пытаюсь читать / писать в защищенной памяти. Что я здесь не так делаю? Спасибо

   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 Ответ

1 голос
/ 29 июня 2009

Из MSDN:

LB_GETTEXTLEN

Возвращаемое значение - это длина строки в TCHAR, за исключением завершающего нулевого символа. При определенных условиях это значение может фактически превышать длину текста. Для получения дополнительной информации см. Следующий раздел «Примечания».

LB_GETTEXT

Указатель на буфер, который получит строку; это тип LPTSTR, который впоследствии приводится к LPARAM. В буфере должно быть достаточно места для строки и завершающего нулевого символа. Сообщение LB_GETTEXTLEN может быть отправлено до сообщения LB_GETTEXT, чтобы получить длину строки в 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());
    }
}
...