Introduction
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.
Background
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.
Using the code
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:
- Create an SDI application using MFC.
- Specify
CRichEditView
as the base class for your CView
class.
- Import the Word type library.
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).
- Add code to invoke methods exposed by the Automation objects. Relevant sections of code are given below.
- In order to have a pop-up menu that lists the synonyms/spelling suggestions, we need to handle the Right-Click event in the Rich Edit control.
Creating an Instance of Word Application
if (!oWordApp.CreateDispatch("Word.Application"))
{
AfxMessageBox("CreateDispatch failed.", MB_OK | MB_SETFOREGROUND);
exit(1);
return;
}
Check for Spelling:
First, we need to separate each word and then invoke the Spell checker.
void CSpellerView::OnSpellCheck()
{
CString str,strRes;
ClearUnderline();
m_rich.GetWindowText(str);
int iStart = 0,iEnd =0, iLen=0, iStrLen;
iEnd = str.Find(' ',0);
iStrLen = str.GetLength();
if(iEnd <0 && iStrLen >0)
{
iEnd = iStrLen;
}
for(int ndx = 0; iEnd > 0 && ndx < iStrLen; ndx ++ )
{
strRes = str.Mid(iStart,iEnd-iStart);
if(!CheckWord(strRes))
{
Underline(iStart,iEnd);
}
iStart = iEnd+1;
iEnd = str.Find(' ',iStart);
}
strRes = str.Mid(iStart,iStrLen-1);
if(!CheckWord(strRes))
{
Underline(iStart,iStrLen);
}
}
Now check if the spelling is correct for each word.
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);
if(oWordApp!=NULL)
{
if(oWordApp.CheckSpelling(LPCTSTR(str),vOpt,vOpt,vOpt,
vOpt,vOpt,vOpt,vOpt,vOpt,vOpt,vOpt,vOpt,vOpt))
return TRUE;
}
To get the Synonym list:
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);
SynonymInfo* oSin = new SynonymInfo();
oSin->AttachDispatch(oWordApp.GetSynonymInfo(LPCTSTR(argstr),vOpt));
COleVariant vMeaning(short(1));
COleVariant vSyno=oSin->GetSynonymList(vMeaning);
long index=0;
if(vSyno.vt==(VT_ARRAY|VT_BSTR))
{
CString str;
int syncount;
syncount=(vSyno.parray)->cbElements;
long* ptr;
HRESULT lResult;
if(syncount==0)
{
if(oSin != NULL)
{
delete oSin;
oSin = NULL;
}
return FALSE;
}
lResult=SafeArrayLock(vSyno.parray);
if(lResult)
{
if(oSin != NULL)
{
delete oSin;
oSin = NULL;
}
return FALSE;
}
for(int i=0;i<syncount;i++)
{
ptr=(long*) (vSyno.parray)->pvData;
str=(BSTR)ptr[i];
menu.AppendMenu(MF_ENABLED|MF_STRING,
i, LPCTSTR(str));
}
lResult=SafeArrayUnlock(vSyno.parray);
}
if(oSin != NULL)
{
delete oSin;
oSin = NULL;
}
return TRUE;
}
catch(...)
{
return FALSE;
}
}
Similarly, to get the spelling suggestions:
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{
COleVariant vTrue((short)TRUE), vFalse((short)FALSE),
vOpt((long)DISP_E_PARAMNOTFOUND, VT_ERROR);
SpellingSuggestions oSpells;
SpellingSuggestion oSpell;
Documents oDocs(oWordApp.GetDocuments());
_Document oDoc;
oDoc = oDocs.Add(vOpt, vOpt, vOpt, vTrue);
oSpells = oWordApp.GetSpellingSuggestions((LPCTSTR)argstr,
vOpt, vOpt, vOpt, vOpt, vOpt, vOpt, vOpt,
vOpt, vOpt, vOpt, vOpt, vOpt, vOpt);
long lCount = oSpells.GetCount();
if (lCount > 0)
{
for(long i=1; i<= lCount; i++)
{
oSpell = oSpells.Item(i);
menu.AppendMenu(MF_ENABLED|MF_STRING,i-1,
LPCTSTR(oSpell.GetName()));
}
}
oDoc.SetSaved(TRUE);
oDoc.Close(vFalse, vOpt, vOpt);
return TRUE;
}
catch(...)
{
return FALSE;
}
To handle the pop-up menu:
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)
OnSynonym();
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)
{
UINT iID = wParam;
CString str;
menu.GetMenuString(iID,str,MF_BYCOMMAND);
if(str.GetLength() > 0)
{
CString sel;
sel = m_rich.GetSelText();
if(sel.Find(' ') >0 )
str+=" ";
m_rich.ReplaceSel(LPCTSTR(str),TRUE);
OnSpellCheck();
}
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.