使用 Word 自动化为文本编辑器添加拼写检查和同义词信息






4.72/5 (11投票s)
2005年2月4日
3分钟阅读

82279

2761
一篇关于使用 MS Word 自动化向编辑器添加拼写检查和同义词信息功能 的文章。
引言
本文解释了如何自定义 Word 应用程序公开的自动化对象以实现类似的功能。此项目实现了拼写检查、拼写建议和同义词建议。当选择一个单词并右键单击时,会在弹出菜单中显示单词建议。对于正确的单词,它会给出同义词列表,对于错误的单词,它将给出拼写建议。这个应用程序有很多改进的空间,包括更好地处理错误和附加功能,但这只是为了说明自动化的强大功能和可扩展性。
背景
本文是文章“使用 Word 自动化和文本到语音控件创建词典”的扩展。但代码被简化了很多。
使用代码
上面提到的文章解释了如何开始使用 Word 自动化。创建这样的应用程序所涉及的步骤是
- 使用 MFC 创建一个 SDI 应用程序。
- 将
CRichEditView
指定为CView
类的基类。 - 导入 Word 类型库。
打开类向导。在“自动化”选项卡中,单击“添加类” -->“从类型库”。打开文件对话框会询问“*.olb”文件。您可以在“Microsoft Office 目录”中找到它。对于 Office 2000,它是 msword9.olb。对于旧版本,它是 msword8.olb。找到类型库后,打开它,会弹出一个新窗口。它要求我们选择 Word 公开的自动化对象。如果您不确定要选择哪些类,请全部选择并按确定。您可以看到有两个文件被添加到项目中 - Msword9.cpp 和 Msword9.h (在旧版本中,它是 Msword8.cpp 和 Msword8.h)。不要忘记在声明 Word 对象的文件中包含 Msword9.h(如在此项目的 CSpellerView.h 中)。
- 添加代码以调用自动化对象公开的方法。下面给出了相关的代码部分。
- 为了拥有一个列出同义词/拼写建议的弹出菜单,我们需要处理 Rich Edit 控件中的右键单击事件。
创建 Word 应用程序的实例
if (!oWordApp.CreateDispatch("Word.Application")) { AfxMessageBox("CreateDispatch failed.", MB_OK | MB_SETFOREGROUND); exit(1); return; }
检查拼写
首先,我们需要分离每个单词,然后调用拼写检查器。
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); } }
现在检查每个单词的拼写是否正确。
调用 Word 应用程序对象的 CheckSpelling()
方法,传入包含单词的字符串。所有其他参数都可以保持可选。
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; }
获取同义词列表
调用 GetSynonymInfo()
方法。列表中的每个单词也会被添加到弹出菜单中。
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; } }
类似地,获取拼写建议
调用 GetSpellingSuggestions()
方法。请注意,需要打开一个文档来检查拼写建议。同样,列表中的每个单词都会被添加到用于拼写建议的弹出菜单中。
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; }
处理弹出菜单
我们需要处理 PreTranslateMessage
,因为否则很难跟踪 Rich Edit 控件的 WM_RBUTTONDOWN
方法。这是代码
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); }
此外,需要处理 OnCommand()
处理程序以了解用户何时在弹出菜单中选择一个项目。
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); }
其余代码主要处理弹出菜单、给拼写错误的单词加下划线、复制剪贴板数据等。我希望这可以从代码中轻松理解。顺便说一句,我没有用这个应用程序来拼写检查这篇文章。 ;-) !!!
诗歌由拉宾德拉纳特·泰戈尔提供。