Click here to Skip to main content
Email Password   helpLost your password?

Screen shot

Introduction

The demo enhances a CRichEditCtrl that provides basic syntax highlighting for C/C++ or any other languages. The CRichEditCtrl also provides an interface that checks spelling using the CSAPI and gives a screen feedback by a coloring underline. This demo uses intensively the TOM interface. The check of spelling occurs only in the comments part of a source code or in strings. The control provides highlighting keywords not only in the source code but also for Doxygen in the comments.

Implementation

For a better implementation, the project has been organized into three classes. CSyntaxcolor manages comments, strings and keyword detection. CSpellingChecker manages the spelling of keywords and manages dictionaries. CSyntaxColorSpellChecker inherits from CSyntaxcolor and overloads the highlighting to provide a coloring underline feedback for the CRichEditCtrl.

Strategy

In order to avoid problems with the redraw of the control, I used Text Object Model (TOM) interface. This interface allows to manipulate runs of characters without sad effects on the screen, and gives more functions than the Win32 API. You can, for example, disable the undo during the modifications of colors. For the spelling, I used CSAPI. There is only some documentation about this API, but it eases considerably the implementation of a spell engine. It allows you to use many standardized dictionaries in your application. I am not sure if it is an official API from Microsoft.

Points of Interest

The main problem to handle syntax highlighting correctly is to manage the multi-line comments without re-computing each time colors of the complete file. The change of only one character could affect the entire file. Re-computing the complete file takes time and slows down the process of typing. To detect the modification of the multi-line comment structure, there is no clean solution. My solution has been to overload the notification EN_MSGFILTER of the CRichEditCtrl. When the user types a character able to change the state of the multi-line comments, I set a flag. And I do a fast analysis of the current line in order to know if the comment is opened or closed.

void CDemoEditorView::OnMsgfilterEdit(NMHDR* pNMHDR, LRESULT* pResult) 
{
  MSGFILTER *pMsgFilter = reinterpret_cast<MSGFILTER *>(pNMHDR);
  if(pMsgFilter->msg == WM_CHAR)
  {
    switch(pMsgFilter->wParam)
    {
      case '*':
      case '/':
        {
          m_bChangeAll = true;
          break;// '*' comment could affect all the file

        }
    }
    CHARRANGE cr;
    GetRichEditCtrl().GetSel(cr);
    if(cr.cpMax -cr.cpMin)// when we remove, it could remove '*/' or '/*'

    {
      m_bChangeAll = true;
    }
  }
  if(pMsgFilter->msg == WM_KEYDOWN)
  {
    switch(pMsgFilter->wParam)
    {
      case VK_BACK:
      case VK_DELETE:
      case VK_RETURN:
        m_bChangeAll = true;
        break;
    }
  }
  if(m_bChangeAll)
  {
    CHARRANGE cr;
    GetRichEditCtrl().GetSel(cr);
    m_nextedComments  = 
     m_colorizer.AnalyseMultiCommentLine(GetRichEditCtrl().LineFromChar(cr.cpMin));
  }
  *pResult = 0;
}

Using Colorizer

I consider the colorization of a text as a set of styles in a run of characters. A style includes all properties for a string (color, font, size, �). The ITextRange interface handles the concept of style through the functions GetSyle and SetStyle. Most of the time, this property is not used in a default implementation, but this LONG is stored in the run. I have stored in this value, the index of the highlight class. It is now very easy to quickly continue a multi line comment style when I evaluate only a part of the file. The style is stored directly in the run of characters. The main job of coloring is done in the function ColorizeRange(�). You can customize the keywords with the function AddKeyList(�). It will be easy to customize this class for HTML, XML, or other languages. You can customize the comments and string detection by changing CreateCommentsAndStringsTags(�). Also, you can change and add more highlight styles by changing CreateDefaultStyle().

void CSyntaxColor::CreateDefaultStyle()
{
    m_tStyle.SetSize(styleMax);
    // black for normal

    m_tStyle[normal]    = CKeyStyle(RGB(0,0,0));
    // blue for syntax

    m_tStyle[syntax]    = CKeyStyle(RGB(0,0,255));
    // Gray for directives

    m_tStyle[directive] = CKeyStyle(RGB(192,192,192));
    // blue for pragma

    m_tStyle[pragma]    = CKeyStyle(RGB(0,0,255));
    // green  multi comment green

    m_tStyle[mcomments] = CKeyStyle(RGB(0,200,0));
    // green  single comment green

    m_tStyle[scomments] = CKeyStyle(RGB(0,200,0));
    // blue string

    m_tStyle[sstring]   = CKeyStyle(RGB(0,0,255));
    // blue string

    m_tStyle[dstring]   = CKeyStyle(RGB(0,0,255));
    // red keyword comments and bold

    m_tStyle[highlightComments]= CKeyStyle(RGB(255,0,0),bold);
}

For each word in the NormalSlot or the CommentSlot, ColorizeRange calls OnColorKeyWord(int istart ,int iend ,LPCSTR pword, HighLightStyle style) to colorize a keyword.

Using the Speller

To implement the spelling checker in syntax colorizing, I have created a new class derived from CSyntaxcolor. The class includes an object CSpellingChecker and overload OnColorKeyWord(�). The new class continues the job of OnColorKeyWord done in CSyntaxcolor, and checks where the colorization occurs, checks the spelling, and sets the underline to signal a misspelled word.

bool CSyntaxColorSpellChecker::OnColorKeyWord(int istart, int iend, 
                          LPCSTR pword, HightLightStyle style)
{
    if(CSyntaxColor::OnColorKeyWord(istart,iend,pword,style)) return true;
    long newunderline = 0;
    if(style == scomments || style == mcomments || 
                             style == sstring || style == dstring )
    {
        newunderline = m_cSpeller.CheckWord(pword) ? 0: SPELL_UNDERLINE;
    }
    m_pRange->SetRange(istart,iend);
    ITextFont *pFont;
    m_pRange->GetFont(&pFont);
    pFont->SetUnderline(newunderline);
    pFont->Release();
    return false;
}

You can change the language of the speller by passing another LID to the function Initialize(lidFrench, lidDutch,�). Just make sure before that the dictionary and the spell engine is rightly installed in the registry. CSpellingChecker also provides some tools to manage dictionaries and words suggestion through a set of functions. Suggestion word comes not only from the main dictionary (.LEX) but also from your user dictionary.

bool CheckWord(LPCSTR pWord);
bool SuggestWords(LPCSTR pWord,int max, CStringArray & tList );
bool IgnoreAlways(LPCSTR pWord);
bool AddToUserDic(LPCSTR pWord);

It is possible to add more user dictionaries (read only) in the function InitEngine, if you modify the SIB structure for each call of SuggestWords and CheckWord. These extra dictionaries can be constructed automatically from your source code, in order to check the spelling of function names, variables, etc�

The Demo

The demo just implements the three classes in a text editor. I have added syntax highlighting and spell checking in comments to a basic application created by Visual C++. The editor is configured for C++ keywords highlight and Doxygen keywords in the comments.

History

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
GeneralThis Colorizer works very well
rob_toutant
22:32 24 Nov '09  
I needed a quick and easy way to add code colorizing to a c++ program and your code did the trick. thank you for posting it. Big Grin

It is surprisingly fast and efficient..would be nice if some additional editing features where included - like highlighting text and being able to press tab for indenting.


I compiled your code using visual studio 6 ( yes i am still using visual studio 6 ) and as well 2008 express addition - on Vista Home Premium - there was one thing that needed to be changed to make your code work...
changing all of the '\r' to '\n' and as well "\r" to "\n" otherwise everything came out as comment color (couldn't find the end of the line)

thanks again for posting your code
GeneraltomWave at Win98 problem
vblazheyev@gmail.com
6:36 29 Sep '05  
why this code does not working at win98???
HREsult is S_OK, but nothing at control......
What Im doing wrong????



void CpsRichEditCtrlWrapper::MakeUnderLine(const CHARRANGE& cr, BOOL bCheck)
{
CComPtr pRange = NULL;
HRESULT hr = GetRangeFromTom(cr.cpMin, cr.cpMax, pRange);
if (FAILED(hr))
{
return;
}
ITextFont* pFont=NULL;
pRange->GetFont(&pFont);
if (bCheck)
{
//// --->>>>>>> here
hr = pFont->SetUnderline(tomWave);
////// <----
}
else
{
pFont->SetUnderline(0);
}
pFont->Release();
}



vblazheyev@gmail.com

GeneralCan't find TOM.h
solikang
16:50 14 Jun '05  
Hi
I downloaded the source file in this page.

I tried to compile it with Visual studio 6.0. But I can't.

The reason is absence of "TOM.h".

Can I get it?? If anyone have it, please send me.

Thanks.

solikang@gmail.com
GeneralRe: Can't find TOM.h
William Hennebois
21:16 14 Jun '05  
you will find tom.h in the latest update of Platform SDK and the install of OfficeSpeller here http://home.tula.net/frazez/OfficeSpeller.exe[]
have fun

Game developer, Tools Application engineer
GeneralRe: Can't find TOM.h
solikang
1:55 15 Jun '05  
Thanks for replying me.

I can find "TOM.h" in platform SDK. So I can compile source.

I made "DemoEditor.exe" ,but it can't open file. I'll debug and trace. If you have any idea about it, please advise me. It may be very helpful to me.

And, I visit "http://home.tula.net/frazez/OfficeSpeller.exe" and download "OfficeSpeller.exe".
It produces "MSSP232.DLL". I have no reference about it, so I can't use it. Is there any header file which describes this 'dll' file? If you know, please let me know also.

I appreciate for your tip once again. And I expect you will reply this article also.
GeneralRe: Can't find TOM.h
William Hennebois
10:10 22 Jun '05  
The tool install a speller engine of office 97 and register it on the registry key
regKey.Format("HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Shared Tools/Proofing Tools/Spelling/%d/Normal",m_Language);
(Engine and Dictionary)

The Demoeditor is designed to use the spell engine of office 97, if you want to use the OfficeSpeller.exe.You have to modify the CSpellingChecker::Initialize by adding

CString engine = reg.ReadKey("Engine","C:/Program Files/Fichiers communs/Microsoft Shared/PROOF/MSSP232.DLL");
m_MdrNameLex = reg.ReadKey("Dictionary","C:/Program Files/Fichiers communs/Microsoft Shared/PROOF/MSSP2_EN.LEX");

engine.TrimRight('\"');
engine.TrimLeft('\"');
m_MdrNameLex.TrimRight('\"');
m_MdrNameLex.TrimLeft('\"');

this code remove the extra quote added by the install


Game developer, Tools Application engineer
GeneralRe: Can't find TOM.h
William Hennebois
10:11 22 Jun '05  
The tool install a speller engine of office 97 and register it on the registry key
regKey.Format("HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Shared Tools/Proofing Tools/Spelling/%d/Normal",m_Language);
Engine and Dictionary

The editor is designed to use the spell engine of office 97, if you want to use the OfficeSpeller.exe.You have to modify the CSpellingChecker::Initialize by adding

CString engine = reg.ReadKey("Engine","C:/Program Files/Fichiers communs/Microsoft Shared/PROOF/MSSP232.DLL");
m_MdrNameLex = reg.ReadKey("Dictionary","C:/Program Files/Fichiers communs/Microsoft Shared/PROOF/MSSP2_EN.LEX");

engine.TrimRight('\"');
engine.TrimLeft('\"');

m_MdrNameLex.TrimRight('\"');
m_MdrNameLex.TrimLeft('\"');
this code remove the extra quote added by the install


Game developer, Tools Application engineer
GeneralTOM interface is great but is incomplete?
Alexandru
3:12 27 Jan '05  

Does anybody know how can 'tomCharset' and 'tomLink' be accessed and modified ?

I would like to access these two text attributes (font charset and whether the text is a hotlink or not) using ITextDocument,ITextRange and ITextFont, but I can't see any member function??

If anyone has an idea, please let me know.
Searching the web with Google and searching MSDN revealed nothing.

Thank you.

Alexandru Matei, mateia@easynet.ro
GeneralHtml support?
are_all_nicks_taken_or_what
16:20 6 Dec '04  
EXCELLENT! This is one outstanding class! Thanks a lot!

I wonder one thing though. How do I use CSyntaxColor for html syntax highlighting? Html should only be highlighted inside '<' and '>', and I don't quite see how that could easily be managed in your class. Any suggestions?
GeneralUnhandled exception in DemoEditor.exe
MayaRafi
21:14 17 Nov '04  
The program failed by entering the first letter from keyboard in the function CSyntaxColor::AnalyseMultiCommentLine(..) => CNoChangeEdit::CNoChangeEdit(...) => CRichEditCtrl::GetEventMask() either in Debug and Release mode.

May
GeneralRe: Unhandled exception in DemoEditor.exe
Anonymous
21:56 21 Nov '04  
Strange, no reason to crash in this place, may be a troube with local configuration
GeneralRe: Unhandled exception in DemoEditor.exe
ak99372
23:51 27 Feb '05  
problem is that returned value from
CSyntaxColorSpellChecker::Initialize
is not handled when condition
if(!m_cSpeller.Initialize(lidAmerican))
return false;
returns false and does not initialize
CSyntaxColor::Initialize(pCtrl);


Joshua
GeneralA small problem: You're not allowed to use Microsoft's dictionaries!
Mike Eriksson
23:08 15 Nov '04  
Hello!

Thanks for the article and the code.

CSAPI *IS* an official api which makes it easier to create spellchecking software. There is one drawback, not with the api but with Microsofts licensing, You are not allowed to use Microsofts Dictionaries!!

Quote:
"NOTE: CSAPI may not be used to call into Microsoft's spell check engine and lexicon. For example, third-party developers who want to incorporate spell check capabilities into their own applications may not use CSAPI to access the spell check engine and lexicons that are installed by Microsoft Office. Microsoft does not currently provide spell check utilities for use in third-party products."

More info here:
http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q262605&

// Anders

Anders Eriksson
Sonork 100.21825
GeneralRe: A small problem: You're not allowed to use Microsoft's dictionaries!
danmorin
4:53 16 Nov '04  
This is a generic warning message: "Microsoft does not currently provide spell check utilities for use in third-party products."

It means that Microsoft is not supporting the development of third-party spell checking. If I paid for Microsoft Office, I am allowed to use every component, including the spell checker. So every user owning Microsoft Office can use the spell checker for personal use. If a user does not have Office installed on his/her computer, then he is not allowed to use the Office spell checker Wink

If you read the article at http://support.microsoft.com/kb/243844/EN-US/[^], you will see Microsoft is promoting the use of its own spell checking:

Quote:
"Software written to work with Microsoft Office can take advantage of the spell checking capabilities of Microsoft Word to add spell checking to their own application."

It is in the interest of Microsoft to have developers use Office components. The more users using your product, the more those users are "sticking to Office" rather than drifting away to competitors.
GeneralRe: A small problem: You're not allowed to use Microsoft's dictionaries!
Gerhold
6:33 16 Nov '04  
Hello,

you're right. You can use the spellchecking capabilities from Microsoft office.
But only via the automation model (OLE, COM).

If you develop any commercial software, it is not legal to access the spell checking engine via the CSAPI.

I know this, because I had to rewrite my application... Frown

Greetings
Gerhold


P.S. The Spell Checking engine for the languages Finnish, Swedish, Norwegian, Danish and German, for instance, is written from the finnish company Lingsoft.

GeneralRe: A small problem: You're not allowed to use Microsoft's dictionaries!
danmorin
5:17 9 Jun '05  
Gerhold wrote: You can use the spellchecking capabilities from Microsoft office.
But only via the automation model (OLE, COM).

This makes sense. The future is in COM; not in the traditional APIs. If I was Microsoft, I would not *officially* support the CSAPI. Instead, I would encourage developers to use the COM intrfaces.
GeneralC# Code
skjagini
14:58 13 Nov '04  
Hi,

It will be very useful if we can get C# copy for the people we dont know vc++.
GeneralSample binary crashes
YoSilver
11:48 13 Nov '04  
Haven't downloaded the source yet, but the DemoEditor.EXE crashed when I run it.Frown

One always gets the deserved.
http://www.silveragesoftware.com/hffr.html
Update your source code with my tool HandyFile Find And Replace!
GeneralRe: Sample binary crashes
William Hennebois
23:21 13 Nov '04  
the app runs correctly on my PC, may be troubles with a specific configuration I didn't check, if you can , compile the project, run it and send me the feedback about where the program crash



Game developer, Tools Application engineer
GeneralRe: Sample binary crashes
YoSilver
14:01 14 Nov '04  
Yes, the problem appears since american proofing is not installed on my system Smile
OK, here we go.

There are problems in your code.

You do not initialise member pointer with null. This causes access violations, for example, in case dictionary are not installed in the system.

bool CSpellingChecker::Terminate()
{
if(m_Handle)
{
/* crash on exit if uninitialised!!! -> */ m_lpfnSpellCloseUdr(m_Handle, m_udr,FALSE);
m_lpfnSpellCloseMdr(m_Handle, &m_Mdrs);
m_lpfnSpellTerminate(m_Handle, FALSE);
}
m_Handle = 0;
if(m_hinstSpell) FreeLibrary (m_hinstSpell);
m_hinstSpell = 0;
m_bEnable = false;
return true;
}
add checks here:
	if(m_Handle)
{
if (m_lpfnSpellCloseUdr)
m_lpfnSpellCloseUdr(m_Handle, m_udr,FALSE);
if (m_lpfnSpellCloseMdr)
m_lpfnSpellCloseMdr(m_Handle, &m_Mdrs);
if (m_lpfnSpellTerminate)
m_lpfnSpellTerminate(m_Handle, FALSE);
}
Add 3 lines to CSpellingChecker constructor:

	m_lpfnSpellCloseUdr = 0;
m_lpfnSpellCloseMdr = 0;
m_lpfnSpellTerminate = 0;
Modify CSyntaxColorSpellChecker::Initialize to make it call CSyntaxColor::Initialize in all cases:
bool CSyntaxColorSpellChecker::Initialize(CRichEditCtrl *pCtrl)
{
bool bResult = m_cSpeller.Initialize(lidAmerican);
bResult &= CSyntaxColor::Initialize(pCtrl);
return bResult;
}
BTW, it is best to determine the sytem language and load the corresponding library instead of simply calling m_cSpeller.Initialize(lidAmerican);. In my case this call failsFrown .

Anyway, a very good engine otherwise !

One always gets the deserved.
http://www.silveragesoftware.com/hffr.html
Update your source code with my tool HandyFile Find And Replace!


Last Updated 12 Nov 2004 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010