RTF streaming and the clipboard

I had a need to copy multiple views derived from CRichEditView to the clipboard. The sample code below contains an RTF StreamOut function with its associated callback function and a code snippet for copying multiple views into a single CF_RTF clipboard image.

The basic premise was to programmatically cycle through all the pertinent CRichEditViews in order to create a composite RTF report that could be placed on the clipboard with a single click of the mouse. If your application contains many Read-Only type views from database queries or numerical calculations this method will provide a nice snapshot of the resultant data set.

I created a user defined ID_STREAM_VIEWS message that is handled by the CUIMainWindow::OnEditBothPanes method. Menu and Toolbar button control associated with the ID_STREAM_VIEWS can be found in the CUIMainWindow::OnUpdateEditBothPanes UI handler. (Note: CUIMainWindow is derived from CFrameWnd)

The OnEditBothPanes copies both views from my static splitter window onto the clipboard. The idea is simple, walk through each view and stream out the data from the underlying CRichEditCtrl. The OnEditBothPanes function is only accessible if both panes are derived from a CRichEditView. (see OnUpdateEditBothPanes). This restriction allows me to cycle through each replaceable view and not have to worry if it can support a StreamRead method. The area which still needs work is the implied RTF reader. The function as it stands employs a quick hack on the RTF stream.
void CUIMainWindow::OnEditBothPanes() 
  // Get RTF streams from pane 0 and pane 1.
  COleDataSource* pDataSource = new COleDataSource; 

  CString strPane0;
  CString strPane1;

  CUIView* pView;

  SetActiveView((CView *)m_SplitterWnd.GetPane(0,0));
  pView = CUIView::GetView();

  SetActiveView((CView *)m_SplitterWnd.GetPane(0,1));
  pView = CUIView::GetView();

  // we are going to concatenate the two rtf streams together
  // therefore drop the ending paren on the first stream as well
  // as the starting header on the second stream

  CString strTemp; 

  // find ending parenthesis and position just before it
  strTemp = strPane0.Left (strPane0.ReverseFind('}'));
  file.Write (strTemp, strTemp.GetLength());

  // drop RTF header information through \fonttbl data because
  // you can not, rather, should not nest RTF with header information
  // notice I break the rules till I finish my RTF reader
  // RTF Version 1.5 Specification defines the following header syntax:
  //    \rtf<charset> \deff? <fonttbl><filetb>?<colortbl>?<stylesheet>?
  //    <listtables>?<revtbl>?
  strTemp = strPane1;
  char *pDest = strstr((LPCTSTR)strTemp, _T("{\\colortbl"));
  int  offset = 0;
  if (pDest != NULL)
    offset = pDest - (LPCTSTR)strTemp;

  // complete rtf stream with a closing parenthesis and write to shared file
  strTemp = strPane1.Mid (offset);
  strTemp += "}";
  file.Write (strTemp, strTemp.GetLength());

  UINT format = ::RegisterClipboardFormat (CF_RTF);
  HGLOBAL hMem = file.Detach();
#if _MFC_VER <= 0x0421
  pDataSource->CacheGlobalData (format, hMem);

void CUIMainWindow::OnUpdateEditBothPanes(CCmdUI* pCmdUI) 
  // if either pane isn't a CUIView class disable button
  // CUIView is a CRichEditView derived class

  CObject* objPane0;
  CObject* objPane1;

  objPane0 = m_SplitterWnd.GetPane(0,0);
  objPane1 = m_SplitterWnd.GetPane(0,1);

  if ( (objPane0->IsKindOf(RUNTIME_CLASS(CUIView))) &&
       (objPane1->IsKindOf(RUNTIME_CLASS(CUIView))) )

void CUIView::StreamRead (CString& rtfString)
  CSharedFile sf;

  es.dwCookie = (DWORD)&sf;
  es.dwError = 0;
  es.pfnCallback = StreamOutCtrl;
  GetRichEditCtrl().StreamOut(SF_RTF , es);
  DWORD dw = sf.GetLength();
  int nSize = INT_MAX;

  if (dw < INT_MAX)
    nSize = (int)dw;

  LPTSTR pStr = rtfString.GetBufferSetLength(nSize);
  sf.Read(pStr, nSize);


static DWORD CALLBACK StreamOutCtrl (DWORD dwCookie, LPBYTE pbBuff,
                                     LONG cb, LONG* pcb)
  CSharedFile *pstr = (CSharedFile*)dwCookie;

  pstr->Write(pbBuff, cb);
  *pcb = cb;

  return 0;

Updated 4 April 1998


  • thanks

    Posted by wxhisme on 12/05/2007 09:08am

    this is my need which i find all the way .thank you very much!

  • Thanks

    Posted by asahukar on 01/27/2006 11:59am

    Thank you for the time and effort you put in to post this info. Just what I needed :-)

  • How can put BYTE buffer data(Bitmap) into clipboard

    Posted by Legacy on 10/31/2002 12:00am

    Originally posted by: Aldemar Cuartas

    How can i put a BYTE buffer data got from an OBJECT field (ORACLE) into a RichEditCtrl. The data it's a bitmap that I need to insert into a text position. I want not have to save the bitmap first out into a file, I want to pass it directly from the variable BYTE to the RichEditCtrl and It shows the image.


  • how to read/write OLE OBJ in RichEdit control use stream or clipboard?

    Posted by Legacy on 09/11/2000 12:00am

    Originally posted by: sunbai

    where to find information for RichEdit control?
    sample for OLE obj? use streamin/streamout

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: December 11, 2014 @ 1:00 p.m. ET / 10:00 a.m. PT Market pressures to move more quickly and develop innovative applications are forcing organizations to rethink how they develop and release applications. The combination of public clouds and physical back-end infrastructures are a means to get applications out faster. However, these hybrid solutions complicate DevOps adoption, with application delivery pipelines that span across complex hybrid cloud and non-cloud environments. Check out this …

  • On-demand Event Event Date: October 29, 2014 It's well understood how critical version control is for code. However, its importance to DevOps isn't always recognized. The 2014 DevOps Survey of Practice shows that one of the key predictors of DevOps success is putting all production environment artifacts into version control. In this webcast, Gene Kim discusses these survey findings and shares woeful tales of artifact management gone wrong! Gene also shares examples of how high-performing DevOps …

Most Popular Programming Stories

More for Developers

RSS Feeds