// Feel free to use this code in your own applications. // The Author does not guarantee anything about this code. // Author : Yves Maurer // FormattedTextDraw.cpp : Implementation of CFormattedTextDraw #include "stdafx.h" #include "FormattedTextDraw.h" ///////////////////////////////////////////////////////////////////////////// // CallBack functions DWORD CALLBACK EditStreamInCallback(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb) { PCOOKIE pCookie = (PCOOKIE) dwCookie; if(pCookie->dwSize - pCookie->dwCount < (DWORD) cb) *pcb = pCookie->dwSize - pCookie->dwCount; else *pcb = cb; CopyMemory(pbBuff, pCookie->bstrText, *pcb); pCookie->dwCount += *pcb; return 0; // callback succeeded - no errors } ///////////////////////////////////////////////////////////////////////////// // CFormattedTextDraw HRESULT CFormattedTextDraw::get_RTFText(BSTR *pVal) { *pVal = SysAllocStringLen(m_RTFText, SysStringLen(m_RTFText)); return S_OK; } HRESULT CFormattedTextDraw::put_RTFText(BSTR newVal) { HRESULT hr; long len; LRESULT lResult = 0; EDITSTREAM editStream; if (m_RTFText != NULL) SysFreeString(m_RTFText); len = SysStringLen(newVal); m_RTFText = SysAllocStringLen(newVal, len); if (!m_spTextServices) return S_FALSE; m_editCookie.bstrText = (BSTR) malloc(len + 1); WideCharToMultiByte(CP_ACP, 0, m_RTFText, len, (char *) m_editCookie.bstrText, len, NULL, NULL); m_editCookie.dwSize = lstrlenA((LPSTR) m_editCookie.bstrText); m_editCookie.dwCount = 0; editStream.dwCookie = (DWORD_PTR) &m_editCookie; editStream.dwError = 0; editStream.pfnCallback = EditStreamInCallback; hr = m_spTextServices->TxSendMessage(EM_STREAMIN, (WPARAM)(SF_RTF | SF_UNICODE), (LPARAM)&editStream, &lResult); free(m_editCookie.bstrText); return S_OK; } HRESULT CFormattedTextDraw::Draw(void *hdcDraw, RECT *prc) { if (!m_spTextServices) return S_FALSE; m_spTextServices->TxDraw( DVASPECT_CONTENT, // Draw Aspect 0, // Lindex NULL, // Info for drawing optimization NULL, // target device information (HDC) hdcDraw, // Draw device HDC NULL, // Target device HDC (RECTL *) prc, // Bounding client rectangle NULL, // Clipping rectangle for metafiles (RECT *) NULL, // Update rectangle NULL, // Call back function NULL, // Call back parameter TXTVIEW_INACTIVE); // What view of the object could be TXTVIEW_ACTIVE return S_OK; } HRESULT CFormattedTextDraw::Create() { return CreateTextServicesObject(); } HRESULT CFormattedTextDraw::get_NaturalWidth(long Height, long *pVal) { long lWidth; SIZEL szExtent; HDC hdcDraw; if (!m_spTextServices) return S_FALSE; hdcDraw = GetDC(NULL); szExtent.cy = Height; szExtent.cx = 10000; lWidth = 10000; m_spTextServices->TxGetNaturalSize(DVASPECT_CONTENT, hdcDraw, NULL, NULL, TXTNS_FITTOCONTENT, &szExtent, &lWidth, &Height); ReleaseDC(NULL, hdcDraw); *pVal = lWidth; return S_OK; } HRESULT CFormattedTextDraw::get_NaturalHeight(long Width, long *pVal) { long lHeight; SIZEL szExtent; HDC hdcDraw; if (!m_spTextServices) return S_FALSE; hdcDraw = GetDC(NULL); szExtent.cx = Width; szExtent.cy = 10000; lHeight = 10000; m_spTextServices->TxGetNaturalSize(DVASPECT_CONTENT, hdcDraw, NULL, NULL, TXTNS_FITTOCONTENT, &szExtent, &Width, &lHeight); ReleaseDC(NULL, hdcDraw); *pVal = lHeight; return S_OK; } ///////////////////////////////////////////////////////////////////////////// // ITextHost functions HDC CFormattedTextDraw::TxGetDC() { return NULL; } INT CFormattedTextDraw::TxReleaseDC(HDC hdc) { return 1; } BOOL CFormattedTextDraw::TxShowScrollBar(INT fnBar, BOOL fShow) { return FALSE; } BOOL CFormattedTextDraw::TxEnableScrollBar(INT fuSBFlags, INT fuArrowflags) { return FALSE; } BOOL CFormattedTextDraw::TxSetScrollRange(INT fnBar, LONG nMinPos, INT nMaxPos, BOOL fRedraw) { return FALSE; } BOOL CFormattedTextDraw::TxSetScrollPos(INT fnBar, INT nPos, BOOL fRedraw) { return FALSE; } void CFormattedTextDraw::TxInvalidateRect(LPCRECT prc, BOOL fMode) { } void CFormattedTextDraw::TxViewChange(BOOL fUpdate) { } BOOL CFormattedTextDraw::TxCreateCaret(HBITMAP hbmp, INT xWidth, INT yHeight) { return FALSE; } BOOL CFormattedTextDraw::TxShowCaret(BOOL fShow) { return FALSE; } BOOL CFormattedTextDraw::TxSetCaretPos(INT x, INT y) { return FALSE; } BOOL CFormattedTextDraw::TxSetTimer(UINT idTimer, UINT uTimeout) { return FALSE; } void CFormattedTextDraw::TxKillTimer(UINT idTimer) { } void CFormattedTextDraw::TxScrollWindowEx(INT dx, INT dy, LPCRECT lprcScroll, LPCRECT lprcClip, HRGN hrgnUpdate, LPRECT lprcUpdate, UINT fuScroll) { } void CFormattedTextDraw::TxSetCapture(BOOL fCapture) { } void CFormattedTextDraw::TxSetFocus() { } void CFormattedTextDraw::TxSetCursor(HCURSOR hcur, BOOL fText) { } BOOL CFormattedTextDraw::TxScreenToClient(LPPOINT lppt) { return FALSE; } BOOL CFormattedTextDraw::TxClientToScreen(LPPOINT lppt) { return FALSE; } HRESULT CFormattedTextDraw::TxActivate(LONG * plOldState) { return S_OK; } HRESULT CFormattedTextDraw::TxDeactivate(LONG lNewState) { return S_OK; } HRESULT CFormattedTextDraw::TxGetClientRect(LPRECT prc) { *prc = m_rcClient; return S_OK; } HRESULT CFormattedTextDraw::TxGetViewInset(LPRECT prc) { *prc = m_rcViewInset; return S_OK; } HRESULT CFormattedTextDraw::TxGetCharFormat(const CHARFORMATW **ppCF) { *ppCF = m_pCF; return S_OK; } HRESULT CFormattedTextDraw::TxGetParaFormat(const PARAFORMAT **ppPF) { *ppPF = &m_PF; return S_OK; } COLORREF CFormattedTextDraw::TxGetSysColor(int nIndex) { return GetSysColor(nIndex); } HRESULT CFormattedTextDraw::TxGetBackStyle(TXTBACKSTYLE *pstyle) { *pstyle = TXTBACK_TRANSPARENT; return S_OK; } HRESULT CFormattedTextDraw::TxGetMaxLength(DWORD *plength) { *plength = m_dwMaxLength; return S_OK; } HRESULT CFormattedTextDraw::TxGetScrollBars(DWORD *pdwScrollBar) { *pdwScrollBar = m_dwScrollbar; return S_OK; } HRESULT CFormattedTextDraw::TxGetPasswordChar(TCHAR *pch) { return S_FALSE; } HRESULT CFormattedTextDraw::TxGetAcceleratorPos(LONG *pcp) { *pcp = -1; return S_OK; } HRESULT CFormattedTextDraw::TxGetExtent(LPSIZEL lpExtent) { return E_NOTIMPL; } HRESULT CFormattedTextDraw::OnTxCharFormatChange(const CHARFORMATW * pcf) { memcpy(m_pCF, pcf, pcf->cbSize); return S_OK; } HRESULT CFormattedTextDraw::OnTxParaFormatChange(const PARAFORMAT * ppf) { memcpy(&m_PF, ppf, ppf->cbSize); return S_OK; } HRESULT CFormattedTextDraw::TxGetPropertyBits(DWORD dwMask, DWORD *pdwBits) { *pdwBits = m_dwPropertyBits; return S_OK; } HRESULT CFormattedTextDraw::TxNotify(DWORD iNotify, void *pv) { return S_OK; } HIMC CFormattedTextDraw::TxImmGetContext() { return NULL; } void CFormattedTextDraw::TxImmReleaseContext(HIMC himc) { } HRESULT CFormattedTextDraw::TxGetSelectionBarWidth(LONG *lSelBarWidth) { *lSelBarWidth = 100; return S_OK; } ///////////////////////////////////////////////////////////////////////////// // custom functions HRESULT CFormattedTextDraw::CharFormatFromHFONT(CHARFORMAT2W* pCF, HFONT hFont) // Takes an HFONT and fills in a CHARFORMAT2W structure with the corresponding info { HWND hWnd; LOGFONT lf; HDC hDC; LONG yPixPerInch; // Get LOGFONT for default font if (!hFont) hFont = (HFONT) GetStockObject(SYSTEM_FONT); // Get LOGFONT for passed hfont if (!GetObject(hFont, sizeof(LOGFONT), &lf)) return E_FAIL; // Set CHARFORMAT structure memset(pCF, 0, sizeof(CHARFORMAT2W)); pCF->cbSize = sizeof(CHARFORMAT2W); hWnd = GetDesktopWindow(); hDC = GetDC(hWnd); yPixPerInch = GetDeviceCaps(hDC, LOGPIXELSY); pCF->yHeight = -lf.lfHeight * LY_PER_INCH / yPixPerInch; ReleaseDC(hWnd, hDC); pCF->yOffset = 0; pCF->crTextColor = 0; pCF->dwEffects = CFM_EFFECTS | CFE_AUTOBACKCOLOR; pCF->dwEffects &= ~(CFE_PROTECTED | CFE_LINK | CFE_AUTOCOLOR); if(lf.lfWeight < FW_BOLD) pCF->dwEffects &= ~CFE_BOLD; if(!lf.lfItalic) pCF->dwEffects &= ~CFE_ITALIC; if(!lf.lfUnderline) pCF->dwEffects &= ~CFE_UNDERLINE; if(!lf.lfStrikeOut) pCF->dwEffects &= ~CFE_STRIKEOUT; pCF->dwMask = CFM_ALL | CFM_BACKCOLOR | CFM_STYLE; pCF->bCharSet = lf.lfCharSet; pCF->bPitchAndFamily = lf.lfPitchAndFamily; #ifdef UNICODE wcscpy(pCF->szFaceName, lf.lfFaceName); #else MultiByteToWideChar(CP_ACP, 0, lf.lfFaceName, LF_FACESIZE, pCF->szFaceName, LF_FACESIZE); #endif return S_OK; } HRESULT CFormattedTextDraw::InitDefaultCharFormat() { return CharFormatFromHFONT(m_pCF, NULL); } HRESULT CFormattedTextDraw::InitDefaultParaFormat() { memset(&m_PF, 0, sizeof(PARAFORMAT2)); m_PF.cbSize = sizeof(PARAFORMAT2); m_PF.dwMask = PFM_ALL; m_PF.wAlignment = PFA_LEFT; m_PF.cTabCount = 1; m_PF.rgxTabs[0] = lDefaultTab; return S_OK; } //https://connect.microsoft.com/VisualStudio/feedback/details/551071/the-6-0a-sdk-is-missing-riched20-lib-for-x64 HRESULT CreateRichEdit(ITextHost *pTextHost, IUnknown **ppUnk) { HRESULT hr = -1; PCreateTextServices TextServicesProc = NULL; HMODULE hmod = LoadLibrary(_T("msftedit.dll")); if (hmod) { TextServicesProc = (PCreateTextServices)GetProcAddress(hmod, "CreateTextServices"); if (TextServicesProc) { hr = TextServicesProc(NULL, pTextHost, ppUnk); } } return hr; } HRESULT CFormattedTextDraw::CreateTextServicesObject() { HRESULT hr = S_OK; IUnknown *spUnk; hr = CreateRichEdit(static_cast(this), &spUnk); if (hr == S_OK) { hr = spUnk->QueryInterface(IID_ITextServicesEx, (void**)&m_spTextServices); hr = spUnk->QueryInterface(IID_ITextDocument, (void**)&m_spTextDocument); spUnk->Release(); } return hr; }