![]() |
Platforms, Frameworks & Libraries »
COM / COM+ »
Automation
Intermediate
Adding Spell Check and Synonym Info to a Text Editor, using Word AutomationBy pratheeshAn article on adding spell check and synonym info functionality to an editor using MS Word Automation. |
VC6, Windows, COM, Dev
|
|
Advanced Search |
|
|
|
||||||||||||||||

This article explains how the automation objects exposed by the Word Application can be customized to achieve similar functionality. The Spell check, Spelling suggestions and Synonyms suggestions are implemented in this project. The word suggestions are shown in a popup menu when a word is selected and right-clicked. For a correct word, it gives the synonyms list, and for a wrong word, it will give the spelling suggestions. There is a lot of scope for improvement in this application including better handling of errors and additional functionalities, but this is just to illustrate the power and extensibility of automation.
This article is an extension to the article "Creating a Dictionary using Word Automation and Text-to-Speech Control". But the code is made a lot more simpler.
The article referred above gives an explanation on how to start with Word Automation. The steps involved in creating an application like this would be:
CRichEditView as the base class for your CView class.

Open Class Wizard. In the 'Automation' tab, click 'Add Class' --> 'From Type-Library'. The open file dialog asks for '*.olb' files. You can find it in the 'Microsoft Office directory'. For Office 2000, it is msword9.olb. For older versions, it is msword8.olb. Once you find the Type-Lib, open it and a new window pops up. It asks us to choose the automation objects that Word exposes. If you are not sure which classes to choose then select all and press OK. You can see that two files are being added to the project - Msword9.cpp and Msword9.h (in older versions, it is Msword8.cpp and Msword8.h). Don't forget to include Msword9.h in the file where you declare the Word objects (as in CSpellerView.h for this project).
if (!oWordApp.CreateDispatch("Word.Application")) { AfxMessageBox("CreateDispatch failed.", MB_OK | MB_SETFOREGROUND); exit(1); return; }
First, we need to separate each word and then invoke the Spell checker.
void CSpellerView::OnSpellCheck() { CString str,strRes; ClearUnderline(); //Clear all underlines as this is a fresh search m_rich.GetWindowText(str); //Get all the text from the editor int iStart = 0,iEnd =0, iLen=0, iStrLen; iEnd = str.Find(' ',0); //find the first space iStrLen = str.GetLength(); if(iEnd <0 && iStrLen >0) { iEnd = iStrLen; //This is for the special case when there is only one word } for(int ndx = 0; iEnd > 0 && ndx < iStrLen; ndx ++ ) { strRes = str.Mid(iStart,iEnd-iStart); //Extract the word if(!CheckWord(strRes)) //check for spelling { Underline(iStart,iEnd); //Underline on error } iStart = iEnd+1; iEnd = str.Find(' ',iStart); //get the next word separated by ' ' } strRes = str.Mid(iStart,iStrLen-1); // get the last word if(!CheckWord(strRes)) //Check word checks the spelling for each word that is separated. { Underline(iStart,iStrLen); } }
Invoke the CheckSpelling() method of the Word Application object passing the string containing the word. All other parameters can be kept optional.
COleVariant vOpt((long)DISP_E_PARAMNOTFOUND, VT_ERROR); // parameters for OLE calls... if(oWordApp!=NULL) { if(oWordApp.CheckSpelling(LPCTSTR(str),vOpt,vOpt,vOpt, vOpt,vOpt,vOpt,vOpt,vOpt,vOpt,vOpt,vOpt,vOpt)) return TRUE; }
Invoke the GetSynonymInfo() method. Each word in the list is added to the popup menu also.
BOOL CSpellerView::GetSuggestions(CString argstr)
{
try{
COleVariant vOpt((long)DISP_E_PARAMNOTFOUND,
VT_ERROR);// parameters for OLE calls...
SynonymInfo* oSin = new SynonymInfo();
oSin->AttachDispatch(oWordApp.GetSynonymInfo(LPCTSTR(argstr),vOpt));
// let's find the synonym list for the first meaning only
COleVariant vMeaning(short(1));
COleVariant vSyno=oSin->GetSynonymList(vMeaning);
//get it...
long index=0;
if(vSyno.vt==(VT_ARRAY|VT_BSTR))
{
CString str;
int syncount;
// get the size of the list
syncount=(vSyno.parray)->cbElements;
long* ptr;
HRESULT lResult;
if(syncount==0)
// no synonyms... but the server is the first
// to know this!!! and it will react
{
if(oSin != NULL)
{
delete oSin; //Delete the synonym object
oSin = NULL;
}
return FALSE;
}
// lock the safe-array before extraction
lResult=SafeArrayLock(vSyno.parray);
if(lResult)
{
if(oSin != NULL)
{
delete oSin; //Delete the synonym object
oSin = NULL;
}
return FALSE;
}
for(int i=0;i<syncount;i++)
{
ptr=(long*) (vSyno.parray)->pvData;
// get the pointer to the array data
str=(BSTR)ptr[i];
// get each meaning
menu.AppendMenu(MF_ENABLED|MF_STRING,
i, LPCTSTR(str)); //Add each to the pop-up menu
}
lResult=SafeArrayUnlock(vSyno.parray);
// done... so unlock
}
if(oSin != NULL)
{
delete oSin;
//Delete the synonym object
oSin = NULL;
}
return TRUE;
}
catch(...)
{
return FALSE;
}
}
Invoke the GetSpellingSuggestions() method. Please note that it is required to open a document to check for spelling suggestions. Again, each word in the list is added to the popup menu for spelling suggestions.
BOOL CSpellerView::GetCorrections(CString argstr)
{
try{
// Parameters
COleVariant vTrue((short)TRUE), vFalse((short)FALSE),
vOpt((long)DISP_E_PARAMNOTFOUND, VT_ERROR);
SpellingSuggestions oSpells;// The spelling suggestions collection
SpellingSuggestion oSpell; // For each spelling
// A document has to be opened
Documents oDocs(oWordApp.GetDocuments());
_Document oDoc; // To check the Spelling suggestions
oDoc = oDocs.Add(vOpt, vOpt, vOpt, vTrue);
// Add the doc to the documents collection
oSpells = oWordApp.GetSpellingSuggestions((LPCTSTR)argstr,
vOpt, vOpt, vOpt, vOpt, vOpt, vOpt, vOpt,
vOpt, vOpt, vOpt, vOpt, vOpt, vOpt);
// Get the Spelling Suggestions
long lCount = oSpells.GetCount();
// Get the number of suggestions
if (lCount > 0)
{
for(long i=1; i<= lCount; i++)
{
oSpell = oSpells.Item(i); // Get each suggestion
menu.AppendMenu(MF_ENABLED|MF_STRING,i-1,
LPCTSTR(oSpell.GetName()));
//Add each word to the pop-up menu
}
}
oDoc.SetSaved(TRUE); // Set the doc to be saved
oDoc.Close(vFalse, vOpt, vOpt); // Close the document
return TRUE;
}
catch(...)
{
return FALSE;
}
We need to handle the PreTranslateMessage as it is difficult to track the WM_RBUTTONDOWN method for the Rich Edit control otherwise. Here's the code:
BOOL CSpellerView::PreTranslateMessage(MSG* pMsg)
{
if (pMsg->message == WM_RBUTTONDOWN)
//Handle the right click event in rich edit
OnSynonym();
//Get the synonyms for the selected word
return CView::PreTranslateMessage(pMsg);
}
Also, it is required to process the OnCommand() handler to know when the user selects an item in the popup menu.
BOOL CSpellerView::OnCommand(WPARAM wParam, LPARAM lParam)
{
// TODO: Add your specialized code here and/or call the base class
UINT iID = wParam;
CString str;
menu.GetMenuString(iID,str,MF_BYCOMMAND);//Find selection by ID
if(str.GetLength() > 0)
{
CString sel;
sel = m_rich.GetSelText(); //Get the selected word from the pop-up
if(sel.Find(' ') >0 )
str+=" ";
m_rich.ReplaceSel(LPCTSTR(str),TRUE);
//Replace the selection in editor
OnSpellCheck(); //Re-Check the Spelling.
}
return CView::OnCommand(wParam, lParam);
}
Rest of the code deals mostly with the pop-up menu, underlining the miss-spelt word, copying the clipboard data etc. I hope this can be easily understood from the code. By the way, I haven't spell checked this article with this application. ;-) !!!
Poetry courtesy: Rabindranath Tagore.
| You must Sign In to use this message board. | ||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
General
News
Question
Answer
Joke
Rant
Admin
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 3 Feb 2005 Editor: Smitha Vijayan |
Copyright 2005 by pratheesh Everything else Copyright © CodeProject, 1999-2009 Web13 | Advertise on the Code Project |