views:

211

answers:

1

I am being told by an exception that's being thrown in the last line, that I'm trying to read/write on protected memory. What am I doing wrong here? Thanks

   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  A: 

From the msdn:

LB_GETTEXTLEN

The return value is the length of the string, in TCHARs, excluding the terminating null character. Under certain conditions, this value may actually be greater than the length of the text. For more information, see the following Remarks section.

LB_GETTEXT

A pointer to the buffer that will receive the string; it is type LPTSTR which is subsequently cast to an LPARAM. The buffer must have sufficient space for the string and a terminating null character. An LB_GETTEXTLEN message can be sent before the LB_GETTEXT message to retrieve the length, in TCHARs, of the string.

You need to provide space for one additional null TCHAR. However I see several other problems in your code:

  • Your system is WinNT? Then lb_gettextlen returns length in TCHAR and on NT systems one TCHAR is two bytes long
  • I see AllocHGlobal, but I do not see FreeHGlobal. Memory leak?
  • Why you convert byte array to string using UTF8 encoding? You need to use Unicode.
  • Your SendMessage interface potentially dangerous, because it does not expect x64 pointers.

Update: In general your code must look like this:

[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());
    }
}
arbiter