65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.72/5 (11投票s)

2005年2月4日

3分钟阅读

viewsIcon

82279

downloadIcon

2761

一篇关于使用 MS Word 自动化向编辑器添加拼写检查和同义词信息功能 的文章。

Sample Image - AutoSpellCheck.gif

引言

本文解释了如何自定义 Word 应用程序公开的自动化对象以实现类似的功能。此项目实现了拼写检查、拼写建议和同义词建议。当选择一个单词并右键单击时,会在弹出菜单中显示单词建议。对于正确的单词,它会给出同义词列表,对于错误的单词,它将给出拼写建议。这个应用程序有很多改进的空间,包括更好地处理错误和附加功能,但这只是为了说明自动化的强大功能和可扩展性。

背景

本文是文章“使用 Word 自动化和文本到语音控件创建词典”的扩展。但代码被简化了很多。

使用代码

上面提到的文章解释了如何开始使用 Word 自动化。创建这样的应用程序所涉及的步骤是

  1. 使用 MFC 创建一个 SDI 应用程序。
  2. CRichEditView 指定为 CView 类的基类。

  3. 导入 Word 类型库。

    打开类向导。在“自动化”选项卡中,单击“添加类” -->“从类型库”。打开文件对话框会询问“*.olb”文件。您可以在“Microsoft Office 目录”中找到它。对于 Office 2000,它是 msword9.olb。对于旧版本,它是 msword8.olb。找到类型库后,打开它,会弹出一个新窗口。它要求我们选择 Word 公开的自动化对象。如果您不确定要选择哪些类,请全部选择并按确定。您可以看到有两个文件被添加到项目中 - Msword9.cppMsword9.h (在旧版本中,它是 Msword8.cppMsword8.h)。不要忘记在声明 Word 对象的文件中包含 Msword9.h(如在此项目的 CSpellerView.h 中)。

  4. 添加代码以调用自动化对象公开的方法。下面给出了相关的代码部分。
  5. 为了拥有一个列出同义词/拼写建议的弹出菜单,我们需要处理 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);
}

其余代码主要处理弹出菜单、给拼写错误的单词加下划线、复制剪贴板数据等。我希望这可以从代码中轻松理解。顺便说一句,我没有用这个应用程序来拼写检查这篇文章。 ;-) !!!

诗歌由拉宾德拉纳特·泰戈尔提供。

© . All rights reserved.