I am having to write an application that communicates with a third-party program (AOL, I\'m sorry. :()
Doing a lot of research I found some ways to do this with P/In
I was getting a crash from Marshal.PtrToStringUni(bf)
statement in similar situation where SendMessage
was returning a "wrong size" for a text length with WM_GETTEXTLENGTH
argument (the control class was "RICHEDIT50W"; multi-line text).
I had tried adding 1, 10, 100 (to text length query result) and still would get an error even though (later on) the text length was equal what was returned from the first call (WM_GETTEXTLENGTH
).
My solution was: I multiplied the result with 2 then I trimmed it.
I did use Marshal.AllocHGlobal(sz)
and then Marshal.Release(bf)
, so there was no problem with memory efficiency. My guess is that for multi-line texts Marshal.AllocHGlobal(sz)
wasn't making enough space in the memory even with exact text size (+1).
Maybe the return character within the text (vbCr, vbLf) requires more memory: I found nothing to explain this isue, but doubling the size worked for me.
Did you manage to solve the "Attempted to read or write protected memory." error? t0mm13b's answer seems to allocate a StringBuilder
whose buffer is one character too small (to accommodate the trailing '\0').
Here's code that works for me:
[DllImport("user32.dll", EntryPoint = "SendMessage", SetLastError = true)]
private static extern Int32 SendMessageByString(IntPtr wnd, UInt32 msg, Int32 WParam, StringBuilder output);
const int WM_GETTEXTLENGTH = 0x000e;
const int WM_GETTEXT = 0x000d;
public static string GetText(IntPtr hWnd)
{
int len = SendMessageByString(hWnd, WM_GETTEXTLENGTH, 0, null);
var sb = new StringBuilder(len + 1); // +1 is for the trailing '\0'
SendMessageByString(hWnd, WM_GETTEXT, sb.Capacity, sb);
return sb.ToString();
}
You are using the Wide byte SendMessage..ie for Wide Characters, have you tried the normal Sendmessage..
public static extern int SendMessage(IntPtr hWnd, UInt32 Msg, Int32 wParam, Int32 lParam);
I also notice it's like as if you are trying to change the value based on the handle of the richtextbox's control hence the looking around for the AOL's client window in another process...is that correct?
That could be the source of the problem, directly modifying a control that belongs to a window that is not yours (your program is managed, modifying a unmanaged process's window)...that could explain why it crashed. Can you clarify what is the hex constants for?
Edit: When you use the WM_GETTEXTLENGTH and WM_GETTEXT, they are part of the Windows Messages to retrieve the text length and the actual text from the control. If you look here and see what pinvoke.net has to say about them..When you issue a 'SendMessage', with WM_GETTEXTLENGTH and WM_GETTEXT, you are telling Windows - 'Hey, get me the length of the text in that associated handle which I've given you in the parameter n
. Just occurred to me, worth trying out...I would get rid of those SendMessage pinvokes and use just this one..
[DllImport("user32.dll", CharSet = CharSet.Auto)] static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, StringBuilder lParam); //If you use '[Out] StringBuilder', initialize the string builder with proper length first.
child = FindClientWindow(); room = FindChildByClass(child, "RICHCNTLREADONLY"); length = SendMessage(n, 0x000E, IntPtr.Zero, IntPtr.Zero); StringBuilder sbBuf = new StringBuilder(length); SendMessageByString(room, 0x000D, new IntPtr( length.ToInt32() + 1 ), out sbBuf); // this is the line that keeps crashing on me.
Try that and get back here ... :)
Hope this helps, Best regards, Tom.