www.pudn.com > RichDrawText_demo.zip > RichDrawText.cpp


#include "stdafx.h" 
#include "RichDrawText.h" 
 
// Link against riched20.lib 
#pragma comment(lib,"riched20.lib") 
 
// The IID in riched20.lib in the Plaform SDK appears to be incorrect. 
// This one is from the Microsoft Knowledge Base, article Q270161. 
const IID IID_ITextServices = { 
  // 8d33f740-cf58-11ce-a89d-00aa006cadc5 
  0x8d33f740, 0xcf58, 0x11ce, {0xa8, 0x9d, 0x00, 0xaa, 0x00, 0x6c, 0xad, 0xc5} 
}; 
 
CRichDrawText::CRichDrawText() 
{ 
  // Get the current font settings 
  NONCLIENTMETRICS ncm; 
  ::ZeroMemory(&ncm,sizeof ncm); 
  ncm.cbSize = sizeof ncm; 
  ::SystemParametersInfo(SPI_GETNONCLIENTMETRICS,sizeof ncm,&ncm,0); 
 
  // Work out the name and point size of the font 
  CStringW strFontName(ncm.lfMessageFont.lfFaceName); 
  HDC hDC = ::GetDC(NULL); 
  int iPointSize = -1 * ::MulDiv(ncm.lfMessageFont.lfHeight,72,::GetDeviceCaps(hDC,LOGPIXELSY)); 
  ::ReleaseDC(NULL,hDC); 
 
  // Create a default character format 
  ::ZeroMemory(&m_CharFormat,sizeof m_CharFormat); 
  m_CharFormat.cbSize = sizeof m_CharFormat; 
  m_CharFormat.dwMask = CFM_BOLD|CFM_CHARSET|CFM_COLOR|CFM_FACE|CFM_ITALIC|CFM_OFFSET| 
    CFM_PROTECTED|CFM_SIZE|CFM_STRIKEOUT|CFM_UNDERLINE; 
  m_CharFormat.yHeight = 20 * iPointSize; 
  m_CharFormat.crTextColor = ::GetSysColor(COLOR_BTNTEXT); 
  m_CharFormat.bPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE; 
  wcscpy(m_CharFormat.szFaceName,strFontName); 
 
  // Create a default paragraph format 
  ::ZeroMemory(&m_ParaFormat,sizeof m_ParaFormat); 
  m_ParaFormat.cbSize = sizeof m_ParaFormat; 
  m_ParaFormat.dwMask = PFM_ALIGNMENT|PFM_NUMBERING|PFM_OFFSET|PFM_OFFSETINDENT| 
    PFM_RIGHTINDENT|PFM_RTLPARA|PFM_STARTINDENT|PFM_TABSTOPS; 
  m_ParaFormat.wAlignment = PFA_LEFT; 
 
  // Get an interface to the windowless rich edit control 
  CComPtr unknown; 
  HRESULT hr = ::CreateTextServices(NULL,&m_xTextHost,&unknown); 
  ASSERT(SUCCEEDED(hr)); 
 
  // Convert the returned interface to ITextDocument and ITextServices 
  m_TextDoc = unknown; 
  m_TextServ = unknown; 
} 
 
void CRichDrawText::SetText(LPCWSTR text) 
{ 
  // Get a range for the whole of the text in the control 
  CComPtr range; 
  m_TextDoc->Range(0,0,&range); 
  range->MoveEnd(tomStory,1,NULL); 
 
  // Replace the whole text 
  range->SetText(CComBSTR(text)); 
} 
 
void CRichDrawText::Range(long cpFirst, long cpLim, ITextRange** ppRange) 
{ 
  // Get the given range of text in the control 
  m_TextDoc->Range(cpFirst,cpLim,ppRange); 
} 
 
void CRichDrawText::SizeText(CDC& dc, CRect& rect) 
{ 
  LONG w = rect.Width(); 
  LONG h = 0; 
 
  // Given a rectange of a particular width, work out how much vertical space 
  // is needed to display the text in the windowless control. 
  SIZEL extent = { -1, -1 }; 
  HRESULT hr = m_TextServ->TxGetNaturalSize(DVASPECT_CONTENT, 
    dc.GetSafeHdc(),0,NULL,TXTNS_FITTOCONTENT,&extent,&w,&h); 
  ASSERT(SUCCEEDED(hr)); 
  if (FAILED(hr)) 
    h = 0; 
 
  // Adjust the height of the rectangle 
  rect.bottom = rect.top+h; 
} 
 
void CRichDrawText::DrawText(CDC& dc, const CRect& rect) 
{ 
  // Draw the text in the windowless control onto the given device context, 
  // within the given bounding rectangle. 
  RECTL rc = { rect.left, rect.top, rect.right, rect.bottom }; 
  HRESULT hr = m_TextServ->TxDraw(DVASPECT_CONTENT,0,NULL,NULL,dc.GetSafeHdc(),0, 
    &rc,NULL,NULL,NULL,0,0); 
  ASSERT(SUCCEEDED(hr)); 
} 
 
BEGIN_INTERFACE_MAP(CRichDrawText, CCmdTarget) 
  INTERFACE_PART(CRichDrawText, IID_ITextHost, TextHost) 
END_INTERFACE_MAP() 
 
STDMETHODIMP_(ULONG) CRichDrawText::XTextHost::AddRef() 
{ 
  return 1; 
} 
 
STDMETHODIMP_(ULONG) CRichDrawText::XTextHost::Release() 
{ 
  return 1; 
} 
 
STDMETHODIMP CRichDrawText::XTextHost::QueryInterface(REFIID iid, LPVOID* ppvObj) 
{ 
  METHOD_PROLOGUE(CRichDrawText, TextHost) 
  return (HRESULT)pThis->InternalQueryInterface(&iid,ppvObj); 
} 
 
HDC CRichDrawText::XTextHost::TxGetDC() 
{ 
  return 0; 
} 
 
INT CRichDrawText::XTextHost::TxReleaseDC(HDC hdc) 
{ 
  return 0; 
} 
 
BOOL CRichDrawText::XTextHost::TxShowScrollBar(INT fnBar, BOOL fShow) 
{ 
  return FALSE; 
} 
 
BOOL CRichDrawText::XTextHost::TxEnableScrollBar(INT fuSBFlags, INT fuArrowflags) 
{ 
  return FALSE; 
} 
 
BOOL CRichDrawText::XTextHost::TxSetScrollRange(INT fnBar, LONG nMinPos, INT nMaxPos, BOOL fRedraw) 
{ 
  return FALSE; 
} 
 
BOOL CRichDrawText::XTextHost::TxSetScrollPos(INT fnBar, INT nPos, BOOL fRedraw) 
{ 
  return FALSE; 
} 
 
void CRichDrawText::XTextHost::TxInvalidateRect(LPCRECT prc, BOOL fMode) 
{ 
} 
 
void CRichDrawText::XTextHost::TxViewChange(BOOL fUpdate) 
{ 
} 
 
BOOL CRichDrawText::XTextHost::TxCreateCaret(HBITMAP hbmp, INT xWidth, INT yHeight) 
{ 
  return FALSE; 
} 
 
BOOL CRichDrawText::XTextHost::TxShowCaret(BOOL fShow) 
{ 
  return FALSE; 
} 
 
BOOL CRichDrawText::XTextHost::TxSetCaretPos(INT x, INT y) 
{ 
  return FALSE; 
} 
 
BOOL CRichDrawText::XTextHost::TxSetTimer(UINT idTimer, UINT uTimeout) 
{ 
  return FALSE; 
} 
 
void CRichDrawText::XTextHost::TxKillTimer(UINT idTimer) 
{ 
} 
 
void CRichDrawText::XTextHost::TxScrollWindowEx(INT dx, INT dy, LPCRECT lprcScroll, 
  LPCRECT lprcClip, HRGN hrgnUpdate, LPRECT lprcUpdate, UINT fuScroll) 
{ 
} 
 
void CRichDrawText::XTextHost::TxSetCapture(BOOL fCapture) 
{ 
} 
 
void CRichDrawText::XTextHost::TxSetFocus() 
{ 
} 
 
void CRichDrawText::XTextHost::TxSetCursor(HCURSOR hcur, BOOL fText) 
{ 
} 
 
BOOL CRichDrawText::XTextHost::TxScreenToClient(LPPOINT lppt) 
{ 
  return FALSE; 
} 
 
BOOL CRichDrawText::XTextHost::TxClientToScreen(LPPOINT lppt) 
{ 
  return FALSE; 
} 
 
HRESULT CRichDrawText::XTextHost::TxActivate(LONG* plOldState) 
{ 
  return E_FAIL; 
} 
 
HRESULT CRichDrawText::XTextHost::TxDeactivate(LONG lNewState) 
{ 
  return E_FAIL; 
} 
 
HRESULT CRichDrawText::XTextHost::TxGetClientRect(LPRECT prc) 
{ 
  return E_FAIL; 
} 
 
HRESULT CRichDrawText::XTextHost::TxGetViewInset(LPRECT prc) 
{ 
  // Set zero sized margins 
  *prc = CRect(0,0,0,0); 
  return S_OK; 
} 
 
HRESULT CRichDrawText::XTextHost::TxGetCharFormat(const CHARFORMATW **ppCF) 
{ 
  METHOD_PROLOGUE(CRichDrawText, TextHost) 
 
  // Return the default character format set up in the constructor 
  *ppCF = &(pThis->m_CharFormat); 
  return S_OK; 
} 
 
HRESULT CRichDrawText::XTextHost::TxGetParaFormat(const PARAFORMAT **ppPF) 
{ 
  METHOD_PROLOGUE(CRichDrawText, TextHost) 
 
  // Return the default paragraph format set up in the constructor 
  *ppPF = &(pThis->m_ParaFormat); 
  return S_OK; 
} 
 
COLORREF CRichDrawText::XTextHost::TxGetSysColor(int nIndex) 
{ 
  // Pass requests for colours on to Windows 
  return ::GetSysColor(nIndex); 
} 
 
HRESULT CRichDrawText::XTextHost::TxGetBackStyle(TXTBACKSTYLE *pstyle) 
{ 
  // Do not erase what is underneath the drawing area 
  *pstyle = TXTBACK_TRANSPARENT; 
  return S_OK; 
} 
 
HRESULT CRichDrawText::XTextHost::TxGetMaxLength(DWORD *plength) 
{ 
  // Set the maximum size of text to be arbitrarily large 
  *plength = 1024*1024*16; 
  return S_OK; 
} 
 
HRESULT CRichDrawText::XTextHost::TxGetScrollBars(DWORD *pdwScrollBar) 
{ 
  // Do not allow scrollbars 
  *pdwScrollBar = 0; 
  return S_OK; 
} 
 
HRESULT CRichDrawText::XTextHost::TxGetPasswordChar(TCHAR *pch) 
{ 
  return S_FALSE; 
} 
 
HRESULT CRichDrawText::XTextHost::TxGetAcceleratorPos(LONG *pcp) 
{ 
  *pcp = -1; 
  return S_OK; 
} 
 
HRESULT CRichDrawText::XTextHost::TxGetExtent(LPSIZEL lpExtent) 
{ 
  return E_NOTIMPL; 
} 
 
HRESULT CRichDrawText::XTextHost::OnTxCharFormatChange(const CHARFORMATW * pcf) 
{ 
  return E_FAIL; 
} 
 
HRESULT CRichDrawText::XTextHost::OnTxParaFormatChange(const PARAFORMAT * ppf) 
{ 
  return E_FAIL; 
} 
 
HRESULT CRichDrawText::XTextHost::TxGetPropertyBits(DWORD dwMask, DWORD *pdwBits) 
{ 
  // Set the windowless control as being multiple lines of wrapping rich text 
  DWORD bits = TXTBIT_MULTILINE|TXTBIT_RICHTEXT|TXTBIT_WORDWRAP; 
  *pdwBits = bits & dwMask; 
  return S_OK; 
} 
 
HRESULT CRichDrawText::XTextHost::TxNotify(DWORD iNotify, void *pv) 
{ 
  // Claim to have handled the notifcation, even though we always ignore it 
  return S_OK; 
} 
 
HIMC CRichDrawText::XTextHost::TxImmGetContext() 
{ 
  return 0; 
} 
 
void CRichDrawText::XTextHost::TxImmReleaseContext(HIMC himc) 
{ 
} 
 
HRESULT CRichDrawText::XTextHost::TxGetSelectionBarWidth(LONG *lSelBarWidth) 
{ 
  // No selection bar 
  *lSelBarWidth = 0; 
  return S_OK; 
}