在另一个应用程序中读取RichTextBox的RTF

时间:2014-11-12 22:27:24

标签: c# rtf sendmessage

我在从另一个应用程序获取RichTextBox的RTF时遇到了困难。

现在,让我们使用写字板。

我可以很好地获取写字板中文本区域的句柄。 我甚至可以使用SendMessage和WM_GETTEXT从文本区域获取纯文本。 这一切都很好。

但是,我需要从其他应用程序获取RTF。 在文档中,我看到EM_STREAMOUT应该与EDITSTREAM结构一起使用。

到目前为止,这是我的代码。

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;
    }
}

当我调用GetRTFFromActiveWindowElement方法时,我尝试读取的另一个应用程序(写字板)崩溃了。 最初我得到了调试其他程序的选项,并发现它是一个内存访问冲突。但是,我无法复制再次看到此错误消息。在当前状态下,另一个应用程序只是锁定并崩溃而没有错误消息。

请注意:写字板只是一个易于测试的应用程序。我也使用我自己的简单WinForms应用程序完成了这项工作,该应用程序中只有一个RichTextBox,并且存在同样的问题。

解决了这个问题之后,我还希望能够将RTF写回另一个应用程序。

建议?

0 个答案:

没有答案