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.
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.