SHARE
Facebook X Pinterest WhatsApp

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 […]

Written By
thumbnail
CodeGuru Staff
CodeGuru Staff
Aug 6, 1998
CodeGuru content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More

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();
  pView->StreamRead(strPane0);

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

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

  CSharedFile file (GMEM_MOVEABLE | GMEM_DDESHARE | GMEM_ZEROINIT);
  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
  ::GlobalUnlock(hMem);
#endif
  pDataSource->CacheGlobalData (format, hMem);
  pDataSource->SetClipboard();
}


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))) )
    pCmdUI->Enable(1);
  else
    pCmdUI->Enable(0);
}


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

  EDITSTREAM es;
  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.SeekToBegin();
  sf.Read(pStr, nSize);
  rtfString.ReleaseBuffer();

}

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

Recommended for you...

How To Make Windows 11 Faster
Enrique Stone
Nov 30, 2022
Working with the Windows Registry in C#
Joydip Kanjilal
Jun 17, 2022
Using Multiple Programming Languages to Create an ASP.NET Website
Tariq Siddiqui
Jun 11, 2022
Finding a Microsoft Office version with .NET
Hannes DuPreez
May 20, 2022
CodeGuru Logo

CodeGuru covers topics related to Microsoft-related software development, mobile development, database management, and web application programming. In addition to tutorials and how-tos that teach programmers how to code in Microsoft-related languages and frameworks like C# and .Net, we also publish articles on software development tools, the latest in developer news, and advice for project managers. Cloud services such as Microsoft Azure and database options including SQL Server and MSSQL are also frequently covered.

Property of TechnologyAdvice. © 2025 TechnologyAdvice. All Rights Reserved

Advertiser Disclosure: Some of the products that appear on this site are from companies from which TechnologyAdvice receives compensation. This compensation may impact how and where products appear on this site including, for example, the order in which they appear. TechnologyAdvice does not include all companies or all types of products available in the marketplace.