Доступ к программе проверки правописания MS-Word из (неуправляемого) C ++ - PullRequest
1 голос
/ 28 января 2010

Я нашел несколько статей о взаимодействии с программой проверки орфографии MS-Word из C # и об управлении C ++ с использованием .NET. (Для всех, кто заинтересован: это и это )

Но я не смог найти ничего похожего на то, чтобы сделать это через стандартный неуправляемый C ++ в приложении MFC, используя COM. Я предполагаю, что .NET-примеры на самом деле используют COM, что означает, что это возможно, но может ли это быть ужасно и уродливо?

1 Ответ

4 голосов
/ 28 января 2010

Я сделал это. Это не , что сложно. Я упаковал все это в DLL и сделал диалог предложений сам.

По сути, это просто открытие слова и запрос его проверки орфографии для конкретного слова. Если проверка не удалась, вы запрашиваете предложения.

Есть только две точки, где вы можете потерпеть неудачу: 1. документ должен быть открытым, то есть вы всегда должны создавать его в коде 2. для разных версий слов словарь иногда сохраняется как юникод, а иногда (более старые версии) нет. Конечно, это важно, только если вы хотите сохранить новые слова в пользовательском словаре.

Хорошо, вот код:

заголовочный файл:

#pragma once
#include "msword.h"

class CWord  
{
public:
    CWord();
    bool Initialize();
    void Terminate();
    bool CheckSpelling(CString text);
    bool CorrectSpelling(CString text,CString& corrected,CWnd* pParent,CPoint point);

private:
    _Application m_word;
    COleVariant m_vTrue;
    COleVariant m_vFalse;
    COleVariant m_vOpt;
    bool m_bInit;

    void AddToDictionary(CString text);
    CString OleErrorMsg(COleDispatchException* e);
};

И реализация (только самые важные части, извините за немецкие комментарии -> Я переведу их при необходимости)

CWord::CWord()
{
    // häufig gebrauchte Variants
    m_vFalse = COleVariant((short) FALSE);
    m_vTrue  = COleVariant((short) TRUE);
    m_vOpt   = COleVariant((long)DISP_E_PARAMNOTFOUND,VT_ERROR);

    m_bInit = false;
}

// sinnvolle Fehlermeldung erstellen
CString CWord::OleErrorMsg(COleDispatchException* e)
{
    CString msg;

    if(!e->m_strSource.IsEmpty())
        msg = e->m_strSource + " - ";

    if(!e->m_strDescription.IsEmpty())
        msg += e->m_strDescription;
    else
        msg += "Unbekannter Fehler.";

    return msg;
}

// Word starten
bool CWord::Initialize()
{
    try
    {
        if(!m_bInit)
        {
            m_word.CreateDispatch("Word.Application");
            m_bInit = true;
        }
    }
    catch(COleDispatchException* e) 
    {   
        AfxMessageBox(OleErrorMsg(e),MB_ICONEXCLAMATION);
        e->Delete();
        return false;
    }

    return true;
}

// Aufräumen
void CWord::Terminate()
{   
    try
    {   
        if(m_word != NULL)  
        {
            m_word.Quit(m_vFalse,m_vOpt,m_vOpt);
            m_word.DetachDispatch();
            m_word = NULL;
            m_bInit = false;
        }
    }
    catch(COleDispatchException* e)
    {
        AfxMessageBox(OleErrorMsg(e),MB_ICONEXCLAMATION);
        e->Delete();
    }
}

// ein Wort auf Rechtschreibung überprüfen
bool CWord::CheckSpelling(CString text)
{
    try
    {
        if(m_word == NULL)
        {
            AfxMessageBox("Word nicht initialisiert!",MB_ICONINFORMATION);
            return false;
        }

        int res = m_word.CheckSpelling((LPCTSTR) text,m_vOpt,m_vFalse,m_vOpt,
            m_vOpt,m_vOpt,m_vOpt,m_vOpt,m_vOpt,m_vOpt,m_vOpt,m_vOpt,m_vOpt);
        return res != 0;
    }
    catch(COleDispatchException* e)
    {
        AfxMessageBox(OleErrorMsg(e),MB_ICONEXCLAMATION);
        e->Delete();
    }

    return false;
}

// Dialog mit Möglichkeiten anzeigen und Auswahl zurückgeben
bool CWord::CorrectSpelling(CString text,CString& corrected,CWnd* pParent,CPoint /*point*/)
{
    AFX_MANAGE_STATE(AfxGetStaticModuleState());
    ASSERT(pParent != NULL);
    bool ret = false;

    CVorschlagDlg dlg(pParent);
    dlg.m_strWort = text;

    try
    {
        // ein Dokument muss geöffnet sein, sonst verweigert GetSpellingSuggestions!
        Documents docs = m_word.GetDocuments();
        _Document doc = docs.Add(m_vOpt,m_vOpt,m_vOpt,m_vTrue);

        // jetzt die Vorschläge holen
        SpellingSuggestions spells = m_word.GetSpellingSuggestions((LPCTSTR) text,m_vOpt,m_vOpt,m_vOpt,
            m_vOpt,m_vOpt,m_vOpt,m_vOpt,m_vOpt,m_vOpt,m_vOpt,m_vOpt,m_vOpt,m_vOpt);

        // in die Stringlist des Dialogs einfüllen
        for(int i = 1;i <= spells.GetCount();i++)
        {
            SpellingSuggestion ss = spells.Item(i);
            dlg.m_slVorschlaege.AddTail((LPCTSTR) ss.GetName());
        }

        // das Dokument wieder schliessen
        doc.SetSaved(TRUE);
        doc.Close(m_vFalse,m_vOpt,m_vOpt);
    }
    catch(COleDispatchException* e)
    {
        AfxMessageBox(OleErrorMsg(e),MB_ICONEXCLAMATION);
        e->Delete();
        return false;
    } 

    // Dialog öffnen und Ergebnis auswerten
    // ACHTUNG: im Switch fällt das Ergebnis durch bis zu 3 Cases durch!
    switch(dlg.DoModal())
    {
    case IDOK:
        // noch zum Word-Wörterbuch hinzufügen
        AddToDictionary(dlg.m_strWort);

    case IDYES:
    case IDIGNORE:
        corrected = dlg.m_strWort;
        ret = true;
        break;

    default: 
        break;
    } // switch

    return ret;
} 

void CWord::AddToDictionary(CString text)
{
    CString strFilename;
    CStdioFile datei;

    try
    {
        // den Dateinamen herausfinden
        Dictionaries dics = m_word.GetCustomDictionaries();
        Dictionary dic = dics.GetActiveCustomDictionary();
        strFilename = dic.GetPath() + "\\" + dic.GetName();
    }
    catch(COleDispatchException* e)
    {
        AfxMessageBox(OleErrorMsg(e),MB_ICONEXCLAMATION);
        e->Delete();
        return;
    }

    try
    {
        if(!datei.Open(strFilename, CFile::modeReadWrite))
        {
            AfxMessageBox("Fehler beim Öffnen des Wörterbuches!",MB_ICONEXCLAMATION);
            return;
        }

        // herausfinden ob Datei UNICODE - kodiert - für Office 2007
        bool bUnicode = false;
        unsigned char cBOM[2];
        const unsigned char UNICODE_BOM[2] = {unsigned char(0xFF),unsigned char(0xFE)};

        if(datei.GetLength() > 2)
        {
            datei.Read((LPVOID) cBOM,2);
            bUnicode = cBOM[0] == UNICODE_BOM[0] &&  cBOM[1] == UNICODE_BOM[1];
        }

        datei.SeekToEnd();

        if(bUnicode)
        {
            USES_CONVERSION;
            LPCWSTR lpsz = T2W(text);
            datei.Write(lpsz,wcslen(lpsz) * sizeof(WCHAR)); 
        }
        else
        {
            datei.WriteString(text + "\n");
        }

        datei.Close();


        // jetzt noch das CRLF im Unicode nachschreiben
        if(bUnicode)
        {
            using namespace std;
            char crlf[4] = {13,0,10,0};
            //ofstream of(strFilename,ios_base::binary | ios_base::_Openmode::app);
            ofstream of(strFilename,ios_base::binary | ios_base::app);
            of.write(crlf,4);
            of.close();         
        }
    }
    catch(CException* e)
    {
        e->ReportError();
        e->Delete();
    }
}
...