Click here to Skip to main content
Click here to Skip to main content

A Very Simple Way to Use Richedit 5.0 in VC6 and other VS versions

, 24 Feb 2010 CPOL
Rate this:
Please Sign up or sign in to vote.
A good tip for using RichEdit 5.0.

Introduction

Microsoft VC++ 6.0 can only build a RichEdit 1.0 app with MFC 4.2. My friends always ask me how to use RichEdit 2.0 or another version of the RichEdit control in a VC6 project. So, this tiny article is just a little attempt of mine to share the info with all of you, and it may be helpful. Smile | :)

This article will show you how to use RichEdit v4.1 (RICHEDIT50W in msftedit.dll) directly.

An additional advantage of the method which is shown in the article is that we can get a fully functional CRichEditView based on the RichEdit v4.1 control, instead of just creating a RichEdit v4.1 control with only text functions. Because we still use MFC, we just only replace the base RichEdit control from 1.0 to 4.1. So, we can still Ctrl+V a bitmap from the clipboard to our CRichEditView, can still insert an object and add some hyperlink text with the in-place MFC member functions.

Background

Since Windows(R) has upgraded to Version 6.1, why should we only use RichEdit 1.0 or 2.0? Well... here is something that could let you use RichEdit 4.1 (msftedit.dll) directly.

Principle

Because our CMyAppView is derived from CRichEditView, we can see the statements below in VIEWRICH.CPP:

CRichEditView::CRichEditView():
  CCtrlView(_T("RICHEDIT"),      //MFC hard-coded the ClassName ....
                               //here is the Key.
                               //Our goal is to REPLACE "RICHEDIT"
                               //to "RichEdit50W". And we can do this in our
                               //View Class' Constructor. You can get those
                               //codes under this segment :)
    AFX_WS_DEFAULT_VIEW |
    WS_HSCROLL | WS_VSCROLL | ES_AUTOHSCROLL | ES_AUTOVSCROLL |
    ES_MULTILINE | ES_NOHIDESEL | ES_SAVESEL | ES_SELECTIONBAR)
    {
     m_bSyncCharFormat = m_bSyncParaFormat = TRUE;
     m_lpRichEditOle = NULL;
     ...
    }

Let's go deeper. The MFC source shows us that CRichEditView is derived from CCtrlView, and in VIEWCORE.CPP, in the constructor of CCtrlView, we can see CCtrlView save the class name "RICHEDIT" which gets from CRichEditView into m_strClass, then use this member var in the PreCreateWindow() and Create() functions. The code is shown below:

CCtrlView::CCtrlView(LPCTSTR lpszClass, DWORD dwStyle)
{
 m_strClass = lpszClass;
 //here, MFC save the ClassName given by
 //CRichEditView's Constructor

 m_dwDefaultStyle = dwStyle;
}
BOOL CCtrlView::PreCreateWindow(CREATESTRUCT& cs)
{
 ASSERT(cs.lpszClass == NULL);
 cs.lpszClass = m_strClass;//CCtrlView apply the ClassName to a
CREATESTRUCT here
 ...
 return CView::PreCreateWindow(cs);
}

As we know, every window is created by the CreateWindowEx() API eventually. 'CREATESTRUCT& cs' is just brought from CWnd::CreateEx(), which is used to tell the system how to create a window.

BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName,
       LPCTSTR lpszWindowName, DWORD dwStyle,
       int x, int y, int nWidth, int nHeight,
       HWND hWndParent, HMENU nIDorHMenu, LPVOID lpParam)
{
 // allow modification of several common create parameters
 CREATESTRUCT cs;
 cs.dwExStyle = dwExStyle;
 cs.lpszClass = lpszClassName;
 cs.lpszName = lpszWindowName;
 cs.style = dwStyle;
 cs.x = x;
 cs.y = y;
 cs.cx = nWidth;
 cs.cy = nHeight;
 cs.hwndParent = hWndParent;
 cs.hMenu = nIDorHMenu;
 cs.hInstance = AfxGetInstanceHandle();
 cs.lpCreateParams = lpParam;

 if (!PreCreateWindow(cs))//CCtrlView::PreCreateWindow() will be called here,
       //and our New ClassName "RichEdit50W" has been already in cs
 {
   PostNcDestroy();
   return FALSE;
 }

 AfxHookWindowCreate(this);
 HWND hWnd = ::CreateWindowEx(cs.dwExStyle, cs.lpszClass,
   cs.lpszName, cs.style, cs.x, cs.y, cs.cx, cs.cy,
   cs.hwndParent, cs.hMenu, cs.hInstance, cs.lpCreateParams);
   // Our RichEdit v4.1(RICHEDIT50W) Ctrl
   // has been created successfully!
 ...
}

How Do We Use the Code?

This is a very typical project produced by the MFC App Wiz. CMyAppView is the View Class derived from CRichEditView.

class CMyAppView : public CRichEditView
{
...
}

There are two steps. First, put 'm_strClass=TEXT("RichEdit50W");' into the the constructor of CMyAppView. It should look like this:

CMyAppView::CMyAppView()
{
  m_strClass=TEXT("RichEdit50W");
  //Must be m_strClass, it is a member of CCtrlView
  ...
}

Then , put 'LoadLibrary(TEXT("msftedit.dll"));' into the constructor of the CMyApp class. And, OLE must be initialized too. When it is done, it should look like this:

CMyApp::CMyApp()
{
 CoInitialize(NULL); //this must be called FIRST!

 //m_hinstRE41 is a HINSTANCE type member var of CMyApp
 m_hinstRE41=LoadLibrary(TEXT("msftedit.dll"));
 //this DLL must be loaded.
 ...
}

CMyApp::~CMyApp()
{
 if(m_hinstRE41)
 FreeLibrary(m_hinstRE41);
}
CMyApp::InitInstance()
{
 AfxOleInit();                     //you don't want to miss this ....
 AfxEnableControlContainer();      //and this ....
 ...
}

Another Important Tip

In CMyAppView::OnDestroy, you should see:

void CGreatTracerView::OnDestroy()
{
  //CRichEditView::OnDestroy(); <------the MFC App Wiz put the codes here,
  // but it shouldn't.
  // Deactivate the item on destruction; this is important
  // when a splitter view is being used.
  COleClientItem* pActiveItem = GetDocument()->
               GetInPlaceActiveItem(this); //If OnDestroy() were still up there,
                                       //the app would CRASH here!
  if (pActiveItem != NULL && pActiveItem->GetActiveView() == this)
  {
     pActiveItem->Deactivate();
     ASSERT(GetDocument()->GetInPlaceActiveItem(this) == NULL);
  }
  CRichEditView::OnDestroy();
  // this codes should be here, so, everything is fine!
}

By the way, I really recommend building the project in Unicode. Smile | :)

History

  • 2010.2.6: First version - 1.0.
  • 2010.2.7: Version 1.1 - Added more intro and the principle part.
  • 2010.2.23: Version 1.2 - Corrected the version error; msftedit.dll contains RichEdit v4.1 (the class name is RICHEDIT50W), not v5.0.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

GhostEx

China China
No Biography provided

Comments and Discussions

 
GeneralMy vote of 5 Pinmembercccfff77714-Jul-10 23:11 
General.NET Richedit Control PinmemberDmex8713-Mar-10 6:50 
Since this article mentions "other VS Versions", This MSDN doc should be included with the article as a reference for showing the differences between Richedit versions: http://msdn.microsoft.com/en-us/library/bb787873(VS.85).aspx
 

The .NET framework (2.0, 3.0, 3.5) RichTextBox control uses the 3.0 version of the Richedit control, This code will tweak the default RichTextBox to load the 4.1 version of Rich Edit. I know VS2008 uses the 3.0 control and I haven't checked VS2010 but I assume it also uses the 3.0 control.
 
Note, The new functions for the 4.1 control have not been added but should be easy to implement the required SendMessage's.
 
Drop this code into a new C# code file, rebuild the project then simply drop the control into your Form from the VS toolbox and enjoy. Thumbs Up | :thumbsup:
 
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
 
namespace RichEditor
{
    public class RichTextBoxEx : RichTextBox
    {
        IntPtr mHandle = IntPtr.Zero;
 
        protected override CreateParams CreateParams
        {
            get
            {
                //Prevent module being loaded multiple times.
                if (this.mHandle == IntPtr.Zero)
                {
                    //load the library to obtain an instance of the RichEdit50 class.
                    this.mHandle = LoadLibrary("msftedit.dll");
                }
   
                //If module loaded, reset ClassName.
                if (this.mHandle != IntPtr.Zero) 
                {
                    CreateParams cParams = base.CreateParams;
 
                    // Check Unicode or ANSI system and set appropriate ClassName.
                    if (Marshal.SystemDefaultCharSize == 1) 
                    {
                        cParams.ClassName = "RichEdit50A";
                    }
                    else
                    {
                        cParams.ClassName = "RichEdit50W";
                    }
 
                    return cParams;
                }
                else // Module wasnt loaded, return default .NET RichEdit20 CreateParams.
                {
                    return base.CreateParams;
                }
            }
        }
 
        
        ~RichTextBoxEx()
        {
            //Free loaded Library.
            if (mHandle != IntPtr.Zero)
            {
                FreeLibrary(mHandle);
            }
        }
 
        [DllImport("kernel32.dll", SetLastError = true)]
        private static extern IntPtr LoadLibrary(String lpFileName);
       
        [DllImport("kernel32.dll", SetLastError = true)]
        private static extern bool FreeLibrary(IntPtr hModule);
    }
}
 
Steven
QuestionRichEdit 7.0 PinmemberCarc2-Mar-10 7:49 
AnswerRe: RichEdit 7.0 PinmemberGhostEx2-Mar-10 23:30 
GeneralRe: RichEdit 7.0 PinmemberCarc3-Mar-10 0:53 
GeneralRe: RichEdit 7.0 PinmemberWarrick Procter5-Dec-10 21:09 
GeneralRich Edit v4.1 PinmemberS.H.Bouwhuis17-Feb-10 2:56 
GeneralRe: Rich Edit v4.1 PinmemberAxel Rietschin20-Feb-10 16:51 
GeneralRe: Rich Edit v4.1 PinmemberS.H.Bouwhuis21-Feb-10 2:10 
AnswerRe: Rich Edit v4.1 PinmemberGhostEx23-Feb-10 1:22 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.141015.1 | Last Updated 24 Feb 2010
Article Copyright 2010 by GhostEx
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid