CRichEditControl50W: A VC++ Rich Text Edit 4.1 MFC Control

Introduction

CRichEditControl50W is a CWnd-derived Rich Text Edit control. Version 4.1 uses the new, poorly documented msftedit.dll (MSFTEDIT_CLASS, or "RichEdit50W" classname) that ships with Windows XP. The CRichEditCtrl provided in VC++ .NET only uses the old v. 3.0 rich edit control (RICHEDIT_CLASS, or "RichEdit20W"). There are no examples of using the new control in MFC that I could find anywhere on the 'Net. So, I decided to create my own after looking at the CRichEditCtrl and CRichEditView classes in VS. This may be a trivial exercise, but the lack of documentation made me do a whole lot of research and digging through VS source code to realize that msftedit.dll was not supported by VS .NET, nor the CRichEditView class. I figured I'd save somebody else the headache of sorting this mess out.

Background

I tried to update my application's CRichEditCtrl with the new "RichEdit50W" window class. You can't simply substitute MSFTEDIT_CLASS for RICHEDIT_CLASS in richedit.h. Microsoft uses the 4.1 version in Wordpad XP, and has developed new, undocumented classes CRichEdit2View, CRichEdit2Ctrl, CRichEdit2Doc, CRichEdit2Cntr (which I found by looking at Wordpad.exe with a Hex Editor), but they don't appear in Visual Studio .NET 2003 or even in VS.NET 2005 BETA1, Whidbey. They left the old WORDPAD example using riched20.dll. The "RichEdit50W" (or "MSFTEDIT_CLASS") class does not work with the current CRichEditView in VS; CRichEditView is hard-coded to load riched20.dll.

I haven't created any new base document/view architecture classes like MS did, so you won't be able to use the document/view architecture to embed objects unless you develop your own and recompile VS .NET. But if you don't need to embed objects, the control works great, and provides the advanced text formatting capabilities of RichEdit v. 4.1.

Using the Code

Steps:

  1. Create a new MFC application in Visual Studio. In the "Application Type" tab, select "Single Document", and DESELECT the Document/View Architecture option; you don't need this. I named my application RE50W. Once complete, remove all references to the CChildView class, which is the default view constructed by CMainFrame; you don't need this, either.


  2. Add the files RichEditControl50W.cpp and RichEditControl50W.h to your project. This is the CRichEditControl50W control I created.


  3. In the application's re50w.cpp, add:
  4. #include "RichEditControl50W.h"    // before
    #include "MainFrm.h"
    
  5. In MainFrame.cpp, add:
  6. #include "RichEditControl50W.h"    // before
    #include "MainFrm.h"
    
  7. In MainFrame.h, declare CRichEditControl50W m_REControl50W as a protected member:
  8. etc..........................
    protected:    // control bar embedded members
    CStatusBar m_wndStatusBar;
    CToolBar m_wndToolBar;
    CRichEditControl50W m_REControl50W;
    etc..........................
    
  9. In MainFrame.cpp, under OnCreate, change the way the view is created:
  10. int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
    {
         if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
              return -1;
    
         //Set Options for the Rich Edit Control 
         DWORD w_RichEd = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS |
                          WS_VSCROLL | ES_AUTOVSCROLL | WS_HSCROLL |
                          ES_AUTOHSCROLL | ES_MULTILINE;
    
         // create a rich edit control to occupy the client area
         // of the frame
         if (!m_REControl50W.Create(w_RichEd, CRect(0, 0, 0, 0),
             this, AFX_IDW_PANE_FIRST))
         {
             TRACE0("Failed to create view window\n");
             return -1;
         }
    
         // Send Initialization messages to the window
         //Set the control to accept the maximum amount of text
         m_REControl50W.LimitText50W(-1); 
    
        //Other options for the control
         DWORD REOptions = (ECO_AUTOVSCROLL | ECO_AUTOHSCROLL |
                            ECO_NOHIDESEL | ECO_SAVESEL |
                            ECO_SELECTIONBAR);
    
         //Set other options
         m_REControl50W.SetOptions50W( 
              ECOOP_OR,        //The type of operation
              REOptions );     //Options
    
         //Set the event masks for the rich edit control
         m_REControl50W.SetEventMask50W(
              ENM_SELCHANGE | ENM_LINK     //New event mask for the
                                           //rich edit control
              );
    
         //Set the default character formatting...see
         //RichEditControl50W.cpp for function definition
         m_REControl50W.SetDefaultCharFormat50W( 
              CFM_COLOR | CFM_BOLD | CFM_SIZE |     //Mask options
              CFM_FACE | CFM_BACKCOLOR,
              RGB(0,0,0),              //Text Color
              !CFE_BOLD,               //Text Effects
              "Trebuchet MS",          //Font name
              200,                     //Font yHeight
              RGB(255,255,255));       //Font background color
    
         //Text for RE Control Example, has to be in RTF format
         m_csMessage = "{\\rtf1 {RE50W by Jim Dunne Copyright(C) 2005
                        \\line http://www.topjimmy.net/tjs
                        \\line\\b jim@dunnes.net}";
    
         //Set the caret selection to the end of any current text
         m_REControl50W.SetSel50W(-1, -1);
    
         //Write to the control
        //Write the text in m_csMessage to the RE Control
         m_REControl50W.SetTextTo50WControl(m_csMessage,
              ST_SELECTION,     // SETTEXT flags value
              1200);            // SETTEXT codepage value
    
         etc..........................
    
  11. Add the OnContextMenu function to CMainFrame to handle your custom popup menu for the rich edit control. Create a custom popup menu named IDR_REPOPUP (see source code for more details):
  12. void CMainFrame::OnContextMenu(CWnd* pWnd, CPoint point)
    {
       CMenu menu;
       if (menu.LoadMenu(IDR_REPOPUP))
       {
          CMenu* pPopup = menu.GetSubMenu(0);
          ASSERT(pPopup != NULL);
          pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON,
                                 point.x , point.y, AfxGetMainWnd());
       }
    }
    
  13. Add command and update handlers and functions for your popup menu. An example for the "Copy" function:
  14. BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
    ON_WM_CREATE()
    ON_WM_SETFOCUS()
    ON_WM_CONTEXTMENU()
    
    ON_COMMAND(ID_REPOPUP_COPY, OnPopupCopy)
    ON_UPDATE_COMMAND_UI(ID_REPOPUP_COPY, OnUpdatePopupCopy)
    
    etc.................
    
    void CMainFrame::OnPopupCopy()
    {
       m_pWnd.SendMessage(WM_COPY, 0, 0);
    }
    
    void CMainFrame::OnUpdatePopupCopy(CCmdUI* pCmdUI)
    {
       m_pWnd.SendMessage(EM_EXGETSEL, 0, (LPARAM)&m_crStatus);
        //  Activate the "Copy" menu item if anything is selected
        pCmdUI->Enable(m_crStatus.cpMin != m_crStatus.cpMax);
        //  CHARRANGE m_crStatus declared in MainFrame.h
    }
    
  15. Add #include <richedit.h> to the bottom of stdafx.h. (This isn't actually necessary, but just to be safe....).

CRichEditControl50W: A VC++ Rich Text Edit 4.1 MFC Control

A Look at CRichEditControl50W

  1. On "Create," it loads msftedit.dll and creates the control as a CWnd:
  2. BOOL CRichEditControl50W::Create(DWORD dwStyle, const RECT&
                                     rect, CWnd* pParentWnd, UINT nID)
    {
        //Load the MSFTEDIT.DLL library. HINSTANCE
        //m_hInstRichEdit50W declared in RichEditControl50W.h
        m_hInstRichEdit50W = LoadLibrary("msftedit.dll");
        if (!m_hInstRichEdit50W)
        {
            AfxMessageBox("MSFTEDIT.DLL Didn't Load");
            return(0);
        }
    
        CWnd* pWnd = this;
        return pWnd->Create("RichEdit50W", NULL, dwStyle, rect,
                            pParentWnd, nID);
    }
    
  3. It implements some of the functions of CRichEditCtrl, which I've modified to make easier to use. For example, my SetTextTo50WControl() function:
  4. void CRichEditControl50W::SetTextTo50WControl(CString csText,
                                                  int nSTFlags,
                                                  int nSTCodepage)
    {   //Set the options. SETTEXTEX m_st50W declared in
        //RichEditControl50W.h
        m_st50W.codepage = nSTCodepage;
        m_st50W.flags = nSTFlags;
        SendMessage(EM_SETTEXTEX, (WPARAM)&m_st50W, (LPARAM)
                   (LPCTSTR)csText);
    }
    

    specifies both the text to be written to the control and the flags for the SETTEXT structure m_st50W, which is a member variable declared in RichEditControl50W.h.

  5. The destructor releases msftedit.dll:
  6. CRichEditControl50W::~CRichEditControl50W()
    {
        //Free the MSFTEDIT.DLL library
        if(m_hInstRichEdit50W)
        FreeLibrary(m_hInstRichEdit50W);
    
  7. You can write your own functions to emulate and/or improve upon the CRichEditCtrl functions. Just have a look at WINCTRL4.CPP, AFXCMN.H, AFXCMN.INL, and VIEWRICH.CPP in Visual Studio and you can get an idea of how to implement them. Msftedit.dll and Riched20.dll are very similar; all of the CRichEditCtrl messages should work for CRichEditControl50W. The only big differences I could find by looking at both DLLs with the OLE/COM Object Viewer in Visual Studio is that Msftedit.dll implements the ITextDocument2 and ITextMsgFilter interfaces, which I can find no documentation on.


  8. As you can see from the following screenshot of my updated app, you can create nice tables and do all kinds of cool text formatting with the new rich edit control, which you can't do with RichEdit 3.0 (try creating a table with no interior borders with riched20.dll, and you'll see what I mean):

[tj30beta.jpg]

Check the MSDN documentation for many more things you can do with rich edit controls. For information on RTF codes, see the Microsoft Office Word 2003 Rich Text Format (RTF) Specification White Paper.



About the Author

Jim Dunne

My name is Jim Dunne. I'm retired from the US Air Force. In some of my spare time, I develop some ping/traceroute applications that I first wrote as a Master's in Computer Engineering thesis. My resume is at http://www.dunnes.net/resume.

Downloads

Comments

  • There are no comments yet. Be the first to comment!

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

Top White Papers and Webcasts

  • Hybrid cloud platforms need to think in terms of sweet spots when it comes to application platform interface (API) integration. Cloud Velocity has taken a unique approach to tight integration with the API sweet spot; enough to support the agility of physical and virtual apps, including multi-tier environments and databases, while reducing capital and operating costs. Read this case study to learn how a global-level Fortune 1000 company was able to deploy an entire 6+ TB Oracle eCommerce stack in Amazon Web …

  • Corporate e-Learning technology has a long and diverse pedigree. As far back as the 1980s, companies were adopting computer-based training to supplement traditional classroom activities. More recently, rich web-based applications have added streaming audio and video, real-time collaboration and other new tools to the e-Learning mix. At the same time, the growing availability of informal learning tools--a category that includes everything from web searches to social media posts--are having a major impact on …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds