CRichEditCtrlEx : Replacing "RICHEDIT" control with "RichEdit20A"

While writing a dev notes Visual Studio plug in, I wanted the rich edit control in a dialog to understand URL's so developers could add links to sites and email addresses.   After talking to "Long John", he led me to the easy way of doing it, and now I am posting the work for others.  Basically this requires CRichEditCtrlEx to use the new rich edit DLL RICHED20.DLL.  The first thing to do it change the window class name of the rich edit controls from "RICHEDIT" to "RichEdit20A" in the *.rc file.  Next, we create a class derived from CRichEditCtrl called CRichEditCtrlEx and override the Create() method:

class CRichEditCtrlEx : public CRichEditCtrl
{
public:
    CRichEditCtrlEx();
    virtual ~CRichEditCtrlEx();
    
    // ClassWizard generated virtual function overrides
    //{{AFX_VIRTUAL( CRichEditCtrlEx )
    public:
    virtual BOOL Create( DWORD in_dwStyle, const RECT& in_rcRect, 
                         CWnd* in_pParentWnd, UINT in_nID );
    //}}AFX_VIRTUAL
    
    // Generated message map functions
protected:
    //{{AFX_MSG( CRichEditCtrlEx )
    //}}AFX_MSG
    DECLARE_MESSAGE_MAP()
};

Now implement the Create() method like this:

BOOL CRichEditCtrlEx::Create(DWORD in_dwStyle,  const RECT& in_rcRect,
                             CWnd* in_pParentWnd, UINT in_nID)
{
    if( ! ::AfxInitRichEditEx() )
    {
        return FALSE ;
    }
    
    CWnd* l_pWnd = this ;
    return l_pWnd->Create( _T( "RichEdit20A" ), NULL, in_dwStyle, 
                           in_rcRect, in_pParentWnd, in_nID );
}

This is almost exactly what is in CRichEditCtrl::Create(), except the different window class name, and the call to AfxInitRichEdit() has been changed to AfxInitRichEditEx() which first calls AfxInitRichEdit (we do not want to break the normal CRichEditCtrl).   In the RichEditCtrlEx.h file, you need to add the DLL holder class and function prototype:

class _AFX_RICHEDITEX_STATE
{
public:
    _AFX_RICHEDITEX_STATE();
    virtual ~_AFX_RICHEDITEX_STATE();

    HINSTANCE m_hInstRichEdit20 ;
};

BOOL PASCAL AfxInitRichEditEx();

Now, in the source code, add the implementation:

_AFX_RICHEDITEX_STATE::_AFX_RICHEDITEX_STATE()
{
    m_hInstRichEdit20 = NULL ;
}

_AFX_RICHEDITEX_STATE::~_AFX_RICHEDITEX_STATE()
{
    if( m_hInstRichEdit20 != NULL )
    {
        ::FreeLibrary( m_hInstRichEdit20 ) ;
    }
}

_AFX_RICHEDITEX_STATE _afxRichEditStateEx ;

BOOL PASCAL AfxInitRichEditEx()
{
    if( ! ::AfxInitRichEdit() )
    {
        return FALSE ;
    }
    
    _AFX_RICHEDITEX_STATE* l_pState = &_afxRichEditStateEx ;
    
    if( l_pState->m_hInstRichEdit20 == NULL )
    {
        l_pState->m_hInstRichEdit20 = LoadLibraryA("RICHED20.DLL") ;
    }
    
    return l_pState->m_hInstRichEdit20 != NULL ;
}

Last thing to help out it we add a method to set the auto URL detection in the Rich Edit to on/off:

inline BOOL CRichEditCtrlEx::AutoURLDetect( BOOL in_fEnable )
{
    ASSERT(::IsWindow( m_hWnd ) );
    return ( BOOL )::SendMessage( m_hWnd, EM_AUTOURLDETECT, in_fEnable, 0 );
}

See the attached sample for the full source code.

Now to use this in your code, you need to use CRichEditCtrlEx for the rich edits you want to include URL detection, and you must call AfxInitRichEditEx() in your CMyApp::InitInstance() if you have dialogs using the rich edit controls.

To then use the URL, you must set the event mask on the rich edit control to include ENM_LINK and then the control will send EN_LINK notifications.  The EN_LINK notification uses the ENLINK structure which includes a message ID.  This message will be:

  • WM_LBUTTONDBLCLK
  • WM_LBUTTONDOWN
  • WM_LBUTTONUP
  • WM_MOUSEMOVE
  • WM_RBUTTONDBLCLK
  • WM_RBUTTONDOWN
  • WM_RBUTTONUP
  • WM_SETCURSOR

If you want to override the default action, set the pResult to 1, otherwise set it to zero.  See the example code to see how to handle this notification.

Download demo project - 16KB (this sample was compiled and tested using VC 6.0 sp1 on NT 4.0 sp4)



Comments

  • RichEdit and XP themed style

    Posted by Legacy on 11/25/2003 12:00am

    Originally posted by: Peter Sander

    I was hoping that the newer RichEdit version support a RichEdit control being drawn in WindowsXP style, e.g. like an edit control. However, they always end up in the old sunken style.
    I also figured out, that the Themes do not natively support a control name RICHEDIT.
    Has anybody figured out this?

    Reply
  • Find and Replace Problem in RichEdit20W

    Posted by Legacy on 07/14/2003 12:00am

    Originally posted by: Kathy

    I develop an MDI application using RichEdit20W DLL to support Unicode RichEdit View. I found that the Find and Replace functions doesn't work.

    I use the default menu items (ID_EDIT_FIND and ID_EDIT_REPLACE) to provide these 2 functions. I just use the system default function handlers to find and replace the text in RichEdit view.

    But, when I use the older DLL (the default one), both functions works correctly.

    I develop my application using VC++ 6.0 with SP5 under Windows 2000.

    Please help me to solve this problem!

    Thanks

    Kathy

    Reply
  • Rich Edit View2.0

    Posted by Legacy on 08/16/2002 12:00am

    Originally posted by: Leon Forsen

    The following is an example of rich edit2.0 based on the default SD rich edit project. 
    
    Please email me for source code.
    1.revise PreCreateWindows
    BOOL CRich20DocViewView::PreCreateWindow(CREATESTRUCT& cs)
    {
    // TODO: Modify the Window class or styles here by modifying
    // the CREATESTRUCT cs
    // return CRichEditView::PreCreateWindow(cs);
    m_strClass="RichEdit20A";
    BOOL nR=CRichEditView::PreCreateWindow(cs);
    LoadLibraryA("RICHED20.DLL");
    return nR;
    }
    2. revise OnDestory
    void CRich20DocViewView::OnDestroy()
    {
    // Deactivate the item on destruction; this is important
    // when a splitter view is being used.
    // CRichEditView::OnDestroy();
    COleClientItem* pActiveItem = GetDocument()->GetInPlaceActiveItem(this);
    if (pActiveItem != NULL && pActiveItem->GetActiveView() == this)
    {
    pActiveItem->Deactivate();
    ASSERT(GetDocument()->GetInPlaceActiveItem(this) == NULL);
    }
    CRichEditView::OnDestroy();
    }
    3. Enable auto URL detect in OnInitialUpdate()
    long lENM=GetRichEditCtrl().GetEventMask();
    lENM|=ENM_LINK;
    GetRichEditCtrl().SetEventMask(lENM);
    BOOL bEnable=1;
    ::SendMessage(m_hWnd,EM_AUTOURLDETECT,bEnable,0);
    4. URL left-button_dwon open with notify message
    ON_NOTIFY_REFLECT_EX(EN_LINK, OnLink )
    afx_msg void OnLink( NMHDR* in_pNotifyHeader, LRESULT* out_pResult );
    void CRich20DocViewView::OnLink( NMHDR* in_pNotifyHeader, LRESULT* out_pResult )
    {
    ENLINK * pLink=(ENLINK*) in_pNotifyHeader;
    if(pLink->msg==WM_LBUTTONDOWN)
    {
    GetRichEditCtrl().SetSel(pLink->chrg);
    CString str=GetRichEditCtrl().GetSelText();
    ShellExecute( this->GetSafeHwnd(), _T( "open" ), str, NULL, NULL, SW_SHOWNORMAL ) ;
    }
    }

    5. To print correctly, revise OnPrint. Without the following, there might be a non-stop print with blank pages)
    void CRich20DocViewView::OnPrint(CDC* pDC, CPrintInfo* pInfo)
    {
    // TODO: Add your specialized code here and/or call the base class
    ASSERT_VALID(this);
    ASSERT_VALID(pDC);
    ASSERT(pInfo != NULL);
    ASSERT(pInfo->m_bContinuePrinting);

    UINT nPage = pInfo->m_nCurPage;
    ASSERT(nPage <= (UINT)m_aPageStart.GetSize());
    long nIndex = (long) m_aPageStart[nPage-1];

    // print as much as possible in the current page.
    nIndex = PrintPage(pDC, nIndex, 0xFFFFFFFF);
    //nIndex got above hasn't take "return" into account
    //The following codes add nIndex when there are any new lines
    int nLength=GetTextLength();
    CString strRich;
    GetRichEditCtrl().GetWindowText(strRich);
    int nS=0;
    while(nS!=-1)
    {
    nS=strRich.Find("\r\n",nS);
    if(nS!=-1)
    {
    nLength--;
    nS++;
    }

    }
    //END adding nIndex

    //other error that might cause non-stop print
    if(m_nIndex==nIndex)
    nLength-=10000;
    m_nIndex=nIndex;
    //end other erro

    if (nIndex >= nLength)//GetTextLength()
    {
    TRACE0("End of Document\n");
    pInfo->SetMaxPage(nPage);
    }

    // update pagination information for page just printed
    if (nPage == (UINT)m_aPageStart.GetSize())
    {
    if (nIndex < nLength)//GetTextLength()
    m_aPageStart.Add(nIndex);
    }
    else
    {
    ASSERT(nPage+1 <= (UINT)m_aPageStart.GetSize());
    ASSERT(nIndex == (long)m_aPageStart[nPage+1-1]);
    }
    // CRichEditView::OnPrint(pDC, pInfo);
    }


    Reply
  • Keep Linkfont when changing RichEditCtrlFont, possible??

    Posted by Legacy on 06/20/2002 12:00am

    Originally posted by: christos

    This is great article which spared me a lot of time. Thanks!

    But there is one question left:
    How to keep the LinkFont when changing the Font of the Control?

    Thanks for your help,

    Christos

    Reply
  • Some Fonts Not Displaying with RichEdit20.dll

    Posted by Legacy on 06/06/2002 12:00am

    Originally posted by: Ranjini

    Some fonts (BookShelf,Webdings) is not taking into effect with RichEdit20.I could modify the font with RichEdit10.dll.
    It would be of great help if this problem could be resolved

    Reply
  • geting character under mouse cursor in a window

    Posted by Legacy on 05/26/2002 12:00am

    Originally posted by: habib

    Dear All,
    I am trying to write a screan reader program, and I should read each character or world under mouse cursor. for example when mouse go on a text in a text box (or even a button or ..) I read just character under the mouse pointer.

    pls note that I should read character by character note whole text of window.

    I really appriciate if some one help me.

    Thanks,
    Habib Rostami

    Reply
  • Upgrade to Riched20.dll problem.

    Posted by Legacy on 04/15/2002 12:00am

    Originally posted by: Zarin Thomas

    In my application, I use the Dundas library which helps me to use the VB Script editor.
    This editor provided by Dundas inturn uses the Riched32.dll
    Now when upgrading to the Riched20.dll, there are some problems observed. Since Dundas no longer provides any support we need to tackle the problem ourselves.

    The VB script editor looks likes this
    '(Declarations)
    Dim StDoc
    Set Stdoc = Appobject.Opendocument ("Prog1.ST")
    'End of (Declarations)


    The '(Declarations)" and "'End of (Declarations)" lines in the script editor file are protected.
    When I press enter after "'(Declarations)" and try to edit the next line I am not being permitted to do so.
    Also another problem observed is that "'End of (Declarations)" line which is protected is also editable.

    The same application works perfectly well with the Richedt32.dll.

    The changes that I did to try and make it work for Riched20.dll are as follows
    1. In the InitInstance of my main application I do a - LoadLibrary("RICHED20.DLL"); now instead of the earlier LoadLibrary("RICHED32.DLL");
    2. In the the constructor of the CRichEditCtrl {Part of the Dundas library} I again do a - LoadLibrary("RICHED20.DLL"); just to be on the safe side.
    3. In the ViewClass {Part of the Dundas library} where the rich edit control is created I have the following statement

    m_pWndEditCtrl->CWnd::CreateEx(WS_EX_STATICEDGE,
    _T("RichEdit20A"), NULL, WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_HSCROLL |ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN, CRect(11, 11 + (m_bShowCombos?28:0),247,55), this, IDC_SED_TEXT)

    Earlier instead of _T("RichEdit20A") it was _T("RICHEDIT"). Note: This change in the class name has been made in the ViewClass.cpp file and not in the resource file as this control has been created dynamically and not via the resource editor.

    Does anybody have any idea why it happens like this. The library getting loaded is Riched20.dll itself, checked thru "Process Explorer" tool and not Riched32.dll.

    Pls. help

    Thanks in advance
    Zarin.


    Reply
  • How can I set the color of the url text?

    Posted by Legacy on 04/08/2002 12:00am

    Originally posted by: Silviu Marele

    Ok, it's very nice that my RichEdit control finds the url's . But when finding one, it sets for it a specific color and I don't know where this color is taken from. How can I set the color I want for the url's?

    Thank you.

    Reply
  • How to create hyperlinks like MSWord Table of contents ??

    Posted by Legacy on 03/12/2002 12:00am

    Originally posted by: venky

    This is an excellent article. Thanks.


    BTW, do you have any idea if we can create our own custom tags that the RichEdit can interpret. Say I want to make a hyper link on some text. On clicking that hyper link I want to do some other action (Not opening a browser, because that link is not for any web page). ie. Somewhat similar to what MS Word has for its Table Of Contents. How do I do that

    Please let me know

    Venky

    Reply
  • URL detection in CRichEditView derived class

    Posted by Legacy on 03/03/2002 12:00am

    Originally posted by: Suraj Gogoi

    To auto detect URL in your CRichEditView derive class
    
    ////////////myview.h//////////////////
    //add this fuctions..
    class CMyView : public CRichEditView
    {
    // Attributes
    public:
    //////////code taken fron Andrew Forget//////////
    virtual BOOL AutoURLDetect( BOOL in_fEnable ) ;
    afx_msg void OnRichEditExLink( NMHDR*
    in_pNotifyHeader, LRESULT* out_pResult ) ;
    protected:
    virtual void OnInitialUpdate(); // called first protected:
    DECLARE_MESSAGE_MAP()
    };
    ///////////myview.cpp//////////////////
    //this message map is important to get the EN_LINK notification from CRichEditCtrl

    ON_NOTIFY_REFLECT_EX(EN_LINK, OnRichEditExLink )


    //////////code taken fron Andrew Forget//////////

    inline BOOL CMyView ::AutoURLDetect( BOOL in_fEnable )
    { ASSERT(::IsWindow( m_hWnd ) ) ; return ( BOOL )::SendMessage( m_hWnd, EM_AUTOURLDETECT, in_fEnable, 0 ) ; }

    void CMyView ::OnRichEditExLink(
    NMHDR* in_pNotifyHeader,
    LRESULT* out_pResult )
    {
    CRichEditCtrl & rRichEditCtrl = GetRichEditCtrl( );//add by me to get the control specific info
    ENLINK* l_pENLink = ( ENLINK* )in_pNotifyHeader ;

    *out_pResult = 0 ;
    switch( l_pENLink->msg )
    {
    default:
    {
    }
    break ;

    case WM_SETCURSOR:
    {
    if( m_crLink != NULL )
    {
    ::SetCursor( m_crLink ) ;
    *out_pResult = 1 ;
    }
    }
    break ;
    case WM_LBUTTONDOWN:
    {
    CString l_URL ;
    CHARRANGE l_CharRange ;
    rRichEditCtrl.GetSel( l_CharRange ) ;
    rRichEditCtrl.SetSel( l_pENLink->chrg ) ;
    l_URL = rRichEditCtrl.GetSelText() ;
    rRichEditCtrl.SetSel( l_CharRange ) ;

    CWaitCursor l_WaitCursor ;

    ShellExecute( this->GetSafeHwnd(), _T( "open" ), l_URL, NULL, NULL, SW_SHOWNORMAL ) ;

    *out_pResult = 1 ;
    }
    break ;
    case WM_LBUTTONUP:
    {
    *out_pResult = 1 ;
    }
    break ;
    }
    }

    Reply
  • Loading, Please Wait ...

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

Top White Papers and Webcasts

  • The latest release of SugarCRM's flagship product gives users new tools to build extraordinary customer relationships. Read an in-depth analysis of SugarCRM's enhanced ability to help companies execute their customer-facing initiatives from Ovum, a leading technology research firm.

  • The impact of a data loss event can be significant. Real-time data is essential to remaining competitive. Many companies can no longer afford to rely on a truck arriving each day to take backup tapes offsite. For most companies, a cloud backup and recovery solution will eliminate, or significantly reduce, IT resources related to the mundane task of backup and allow your resources to be redeployed to more strategic projects. The cloud - can now be comfortable for you – with 100% recovery from anywhere all …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds