Date: | January 10, 2007 / year-entry #9 |
Tags: | code |
Orig Link: | https://blogs.msdn.microsoft.com/oldnewthing/20070110-13/?p=28463 |
Comments: | 5 |
Summary: | To load an entire file into a rich text control, you can use the EM_STREAMIN message, which accepts an IStream of data all at once. Once you find the message, it's pretty straightforward how to use it, but I'll write out the code anyway; DWORD CALLBACK EditStreamCallback(DWORD_PTR dwCookie, LPBYTE lpBuff, LONG cb, PLONG pcb) {... |
To load an entire file into a rich text control, you can use
the DWORD CALLBACK EditStreamCallback(DWORD_PTR dwCookie, LPBYTE lpBuff, LONG cb, PLONG pcb) { HANDLE hFile = (HANDLE)dwCookie; return !ReadFile(hFile, lpBuff, cb, (DWORD *)pcb, NULL); } BOOL FillRichEditFromFile(HWND hwnd, LPCTSTR pszFile) { BOOL fSuccess = FALSE; HANDLE hFile = CreateFile(pszFile, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); if (hFile != INVALID_HANDLE_VALUE) { EDITSTREAM es = { (DWORD_PTR)hFile, 0, EditStreamCallback }; if (SendMessage(hwnd, EM_STREAMIN, SF_RTF, (LPARAM)&es) && es.dwError == 0) { fSuccess = TRUE; } CloseHandle(hFile); } return fSuccess; }
You pretty much follow your nose.
The "But I tried this, and only the first line of the file gets read in. What am I doing wrong?" Ah, a classic rookie mistake.
You forgot to set the Don't worry, I made this mistake, too. "What if my data is in some other format than a file?"
As long as you can write a function that produces the next few bytes
of data,
you can stream it into a rich edit control.
For example, here's a version that loads an arbitrary DWORD CALLBACK EditStreamCallback(DWORD_PTR dwCookie, LPBYTE lpBuff, LONG cb, PLONG pcb) { IStream *pstm = (IStream *)dwCookie; return FAILED(pstm->Read(lpBuff, cb, (ULONG*)pcb)); } BOOL FillRichEditFromStream(HWND hwnd, IStream *pstm) { BOOL fSuccess = FALSE; EDITSTREAM es = { (DWORD_PTR)pstm, 0, EditStreamCallback }; if (SendMessage(hwnd, EM_STREAMIN, SF_RTF, (LPARAM)&es) && es.dwError == 0) { fSuccess = TRUE; } return fSuccess; } There's still a bug in this code, however, and it's not where you expect it. We'll take another look next time. |
Comments (5)
Comments are closed. |
First!
The only way I could get RICHEDIT50W to interpret RTF was to stream it in via callback as you show here. However, earlier versions seem happy to interpret RTF if you just throw it at them in one big message.
Completely buried with two projects and the main one is going to CTP #2 at a major back in Paris/London
If the rich edit control was created by a different thread, then SendMessage will pass the EM_STREAMIN to that thread, so the IStream could get called from the wrong apartment.
On second thought, even if the control was created by the thread that calls SendMessage, does anything guarantee that the control will call EditStreamCallback on that thread? I don’t see that specified in the documentation of EM_STREAMIN or EditStreamCallback; I may have missed a general rule somewhere.
> There’s still a bug in this code, however,
> and it’s not where you expect it.
That sounds like a challenge, and someone lent me a few spare minutes, so let’s see.
(1) MSDN says:
* The control continues to call the callback
* function until one of the following
* conditions occurs:
[…]
* or an invalid character in the read buffer
[…]
Suppose the control says to read 10 bytes, there are 65 bytes remaining readable in the file, and the next 10 bytes consist of 9 single-byte characters plus the first half of 1 double-byte character. The result will be an invalid character in the read buffer.
(2) This code has the CALLBACK macro on the definition of EditStreamCallback, but MSDN’s specification says not to.
(3) If the assumption that somethings never change might possibly be false in the future, if DWORD might no longer be close enough to the same as LONG or if a DWORD might change to a DWORD_PTR (as some did), then some of this code’s casts might break in the future. The effect might be silent successful compilation but danger at runtime.
You need to raise the ceiling.