January 10th, 2007

How do I load an entire file into a rich text control?

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)
{
 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 EM_STREAMIN message wants you to tell it the format of the stream (SF_RTF) and provide a pointer to an EDITSTREAM structure that controls the input. Since we want to read from a file, we open a file for reading and use it as the dwCookie for our EditStreamCallback. The only tricky part is getting the return value correct for the callback. For some reason, the rich edit control wants zero on success and nonzero on failure, so we need to flip the sense of the ReadFile return value accordingly. Aside from that, there’s nothing particularly interesting going on.

“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 ES_MULTILINE style when you created the rich edit control.

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 IStream into a rich edit control:

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.

Topics
Code

Author

Raymond has been involved in the evolution of Windows for more than 30 years. In 2003, he began a Web site known as The Old New Thing which has grown in popularity far beyond his wildest imagination, a development which still gives him the heebie-jeebies. The Web site spawned a book, coincidentally also titled The Old New Thing (Addison Wesley 2007). He occasionally appears on the Windows Dev Docs Twitter account to tell stories which convey no useful information.

0 comments

Discussion are closed.