1

I'm trying to get the text of a Richedit Control from another program.

So I found EM_STREAMOUT for SendMessage.

This is my code so far (also from another Stackoverflow topic):

    DWORD CALLBACK EditStreamOutCallback(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
{
    std::stringstream *rtf = (std::stringstream*) dwCookie;
    rtf->write((char*)pbBuff, cb);
    *pcb = cb;
    return 0;
}

int main() {
    std::stringstream rtf;

    EDITSTREAM es = {0};
    es.dwCookie = (DWORD_PTR) &rtf;
    es.pfnCallback = &EditStreamOutCallback;
    SendMessage((HWND) 0x00000000000A06E8, EM_STREAMOUT, SF_RTF, (LPARAM)&es);

}

The only thing that happens is that SendMessage returns 0 - so obviously no bytes were read - and the program of which I'm trying to get the information out of goes up to 100% CPU usage.

  • 2
    EM_STREAMOUT won't work across a process boundary. You would need to inject your code into the other process for this to work. – Jonathan Potter Feb 22 '14 at 23:23
  • But reading text from normal edit controls with WM_GETTEXT works fine and I don't find anything in the MSDN which says that it doesn't work across process boundaries. – user3342002 Feb 22 '14 at 23:25
  • 2
    You found it in an SO comment. It is correct. – Hans Passant Feb 22 '14 at 23:34
  • Assuming that it is correct - how do i get the text out of a Richedit from another program? It must be possible because I'm able to do it in AutoIt which wraps around the WinAPI. – user3342002 Feb 22 '14 at 23:39
  • WM_GETTEXT will work, but if you want formatted text you'll have to inject your code. – Jonathan Potter Feb 22 '14 at 23:52
  • got it...somehow I tested WM_GETTEXT but after many many hours of programming I kinda did it wrong the first time...thanks ^^ – user3342002 Feb 22 '14 at 23:56

1 Answers1

2

Some messages, like WM_GETTEXT, are marshaled by Windows for you. That is why you can retrieve a window's text across process boundaries. EM_STREAMIN/OUT are not auto-marshaled. That is why your code is crashing. The EDITSTREAM struct and the callback code must exist in the address space of the same process that owns the RichEdit.

For many non-marshaled messages that need to cross process boundaries, you can allocate input/output buffers using VirtualAllocEx(), fill them using WriteProcessMemory(), and read from them using ReadProcessMemory(). But because the EDITSTREAM callback code needs to be in the same process as well, you are best off moving your entire EM_STREAMOUT logic into a DLL and then inject it into the target process using CreateRemoteThread() or other injection technique. You can use GetWindowThreadProcessId() to get the process/thread IDs that own the RichEdit. Your DLL can then retrieve the RichEdit data and send it back to your main app using any IPC (Inter-Process Communication) mechanism of your choosing, such as a named pipe, a mailslot, the WM_COPYDATA message, etc.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • Or simply take advantage of the [UI Automation Support for Standard Controls](http://msdn.microsoft.com/en-us/library/windows/desktop/ee671196.aspx). – IInspectable Feb 23 '14 at 17:35
  • Does UIA support retrieving a RichEdit's RTF instead of its plain text? – Remy Lebeau Feb 23 '14 at 18:44
  • The question asks for *"the text of a RichEdit Control"*. While UI Automation does not directly allow access to the RTF, it offers interfaces to query text properties such as font face or color. – IInspectable Feb 23 '14 at 19:26
  • The *question* may say text, but the *code* says RTF. And having to scan the text querying for properties and ranges to gather formatting information is very inefficient. – Remy Lebeau Feb 23 '14 at 20:25