Reading RTF RichTextBox in another application

I am having difficulty getting an RTF RichTextBox from another application.

Now let's work with WordPad.

I can get the handle to the textarea in WordPad just fine. And even I can get plain text from the textarea using SendMessage and WM_GETTEXT. It's all good.

However, I need to get RTF from another application. In the docs, I see that EM_STREAMOUT should be used with an EDITSTREAM structure.

Here is the code I have for this so far.

private const uint WM_USER = 0x0400;
private const uint EM_STREAMOUT = WM_USER + 74;
private const uint SF_RTF = 2;

[DllImport("user32.dll", EntryPoint="GetForegroundWindow")]
private static extern IntPtr GetForegroundWindow();

[DllImport("user32.dll", EntryPoint="GetWindowThreadProcessId", SetLastError=true)]
private static extern IntPtr GetWindowThreadProcessId(IntPtr hWnd, out IntPtr lpdwProcessId);

[DllImport("user32.dll", EntryPoint="GetGUIThreadInfo", SetLastError=true)]
private static extern bool GetGUIThreadInfo(IntPtr hThreadID, ref GUITHREADINFO lpgui);

[DllImport("user32.dll", EntryPoint = "SendMessage", CharSet = CharSet.Auto)]
private static extern IntPtr SendMessage(IntPtr hWnd, uint msg, uint wParam, ref EDITSTREAM lParam);

private delegate int EditStreamCallback(MemoryStream dwCookie, IntPtr pbBuff, int cb, out int pcb);

private static int EditStreamProc(MemoryStream dwCookie, IntPtr pbBuff, int cb, out int pcb)
{
    pcb = cb;
    byte[] buffer = new byte[cb];
    Marshal.Copy(pbBuff, buffer, 0, cb);
    dwCookie.Write(buffer, 0, cb);
    return 0;
}

[StructLayout(LayoutKind.Sequential)]
private class EDITSTREAM
{
    public MemoryStream dwCookie;
    public uint dwError;
    public EditStreamCallback pfnCallback;
}

private struct RECT
{
    public int iLeft;
    public int iTop;
    public int iRight;
    public int iBottom;
}

private struct GUITHREADINFO
{
    public int cbSize;
    public int flags;
    public IntPtr hwndActive;
    public IntPtr hwndFocus;
    public IntPtr hwndCapture;
    public IntPtr hwndMenuOwner;
    public IntPtr hwndMoveSize;
    public IntPtr hwndCaret;
    public RECT rectCaret;
}

public static string GetRTFFromActiveWindowElement()
{
    try
    {
        IntPtr windowHWnd = GetForegroundWindow();
        IntPtr lpdwProcessId;
        IntPtr threadId = GetWindowThreadProcessId(windowHWnd, out lpdwProcessId);

        GUITHREADINFO lpgui = new GUITHREADINFO();
        lpgui.cbSize = Marshal.SizeOf(lpgui);

        GetGUIThreadInfo(threadId, ref lpgui);

        string result = String.Empty;
        using (MemoryStream stream = new MemoryStream())
        {
            EDITSTREAM editStream = new EDITSTREAM();
            editStream.pfnCallback = new EditStreamCallback(EditStreamProc);
            editStream.dwCookie = stream;

            SendMessage(lpgui.hwndFocus, EM_STREAMOUT, SF_RTF, ref editStream);

            stream.Seek(0, SeekOrigin.Begin);
            using (StreamReader reader = new StreamReader(stream))
            {
                result = reader.ReadToEnd();
            }
        }

        return result;
    }
    catch (Exception e)
    {
        Console.Write(e.Message);
        return null;
    }
}

      

When I call the GetRTFFromActiveWindowElement method, another application crashes that I am trying to read from (WordPad). Initially I was getting the ability to debug another program and saw that it was a memory access violation. However, I am unable to repeat this error message. In its current state, the other application simply blocks and crashes without an error message.

Just a side note: WordPad is a simple testing application. I also did it with my own simple WinForms app which only has RichTextBox and the same problem exists.

After solving this problem, I would also like to write the RTF back to another application.

Suggestions?

+3


source to share





All Articles