如何在 windows 的 qt 中使用 QAxObject 创建 docx 和 doc 文件?

How to create docx and doc file with QAxObject in qt for windows?

我想使用 QAxObject 创建一个新的 docx 文件。我怎样才能创建一个新的 docdocx 文件,并在 qt 中为 windows 编写我的文本 QAxObject。我尝试了这段代码,但找不到答案,因为它打开了现有文件,但我想创建一个新文件并使用 QAxObject.

QString     outFile("C:/test.docx");
QString     inFile1("C:/test1.docx");
QString     inFile2("C:/test2.docx");
QAxObject   axObject("Word.Application");
QAxObject   *documents = axObject.querySubObject("Documents");
QAxObject   *document = documents->querySubObject("Open(const QString&, bool)", inFile1, true);
QAxObject   *selection = axObject.querySubObject("Selection");

selection->dynamicCall("EndKey(QVariant&)", 6); // WdUnits::wdStory=6
selection->dynamicCall("InsertBreak(QVariant&)", 7); // WdBreakType::wdPageBreak=7
selection->dynamicCall("InsertFile(QString&)", inFile2);

document->dynamicCall("SaveAs(const QString&)", outFile);
document->dynamicCall("Close()");
axObject.dynamicCall("Quit()");

SO 中已经有一些 answers 类似的问题,建议将 QAxObjectdynamicCall() 一起用于 MS Office 自动化。这可以做到,而且会奏效,但我认为有更好、更有趣的方法来做到这一点。

我的建议是导入每个 Office 应用程序自带的 COM 类型库,生成一个 C++ object 模型。这有两个优点:类似于 C# 和 VB.NET 中流行的互操作方法,甚至这些语言的示例也可以用作我们自己的 Qt 项目的模型。当然,您可以在 Qt Creator 中享受 类 和成员名称的自动完成功能。我已经提到乐趣了吗?

这与 Qt bin 目录中的 Qutlook Example for the Outlook application that is included among the ActiveQt samples. The documentation doesn't tell much more than adding the TYPELIBS variable in your application's .pro file. The translation is performed by the dumpcpp.exe utility 非常相似。这是一个导入MS Word object模型的简单命令行程序项目:

QT += widgets axcontainer
CONFIG += c++11 cmdline

DUMPCPP=$$absolute_path("dumpcpp.exe", $$dirname(QMAKE_QMAKE))
TYPELIBS = $$system($$DUMPCPP -getfile {00020905-0000-0000-C000-000000000046})

isEmpty(TYPELIBS) {
    message("Microsoft Word type library not found!")
    REQUIRES += MSWord
} else {
    SOURCES  = main.cpp
}

要发现其他类型库的 GUID,您可以使用 oleview.exe 实用程序。

QMake 创建一个源文件 MSWORD.cpp 和一个 header MSWORD.h,您可以将其包含在您自己的 类 中以访问生成的 object 模型.此示例从头开始生成 Word 文档,并以两种格式保存:

#include <QApplication>
#include <QStandardPaths>
#include <QDir>
#include "MSWORD.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    Word::Application word;
    if (!word.isNull()) {
        word.SetVisible(false);

        Word::Documents* docs = word.Documents();
        Word::Document* newDoc = docs->Add();
        Word::Paragraph* p = newDoc->Content()->Paragraphs()->Add();
        p->Range()->SetText("Hello Word Document from Qt!");
        p->Range()->InsertParagraphAfter();
        p->Range()->SetText("That's it!");

        QDir outDir(QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation));

        QVariant fileName = outDir.absoluteFilePath("wordaut.docx");
        QVariant format = Word::wdFormatXMLDocument;
        newDoc->SaveAs2(fileName, format);

        QVariant fileName2 = outDir.absoluteFilePath("wordaut2.doc");
        QVariant format2 = Word::wdFormatDocument;
        newDoc->SaveAs2(fileName2, format2);

        newDoc->Close();
        word.Quit();
    }

    return 0;
}

如您所见,代码可读性很强,代价是包含了大量代码。您 #include 生成了 header MSWORD.h,程序会创建一个新文档,用两行文本填充其内容,并将该文档保存两次:第一次以现代 DOCX 格式,然后与 Word 97/2003 兼容的 DOC 格式。

完整的项目可以在GitHub repository中找到。

#if defined(Q_OS_WIN)
    else if (mod == "DOCX" || mod == "DOC") {
        QTemporaryDir tempDir;
        QString text_filename;
        QString     outFile;
        QString     allMessage;
        else if (mod == "DOCX") {
            if(tempDir.isValid()){
                const QString tempFile = tempDir.path() + "/docxTemplate.docx";
                if(QFile::copy(":/docxTemplate.docx",tempFile)){
                    text_filename = tempFile;
                } else {
                    qDebug()<< "cannot locate docxTemplate.docx";
                }
            }
            else {
                qDebug()<< "cannot access filesystem";
            }
            QString     outFile(pathDirectory+"/"+filename+".docx");
        }
        else if (mod == "DOC") {
            if(tempDir.isValid()){
                const QString tempFile = tempDir.path() + "/docTemplate.doc";
                if(QFile::copy(":/docTemplate.doc",tempFile)){
                    text_filename = tempFile;
                } else {
                    qDebug()<< "cannot locate docTemplate.doc";
                }
            }
            else {
                qDebug()<< "cannot access filesystem";
            }
            QString     outFile(pathDirectory+"/"+filename+".doc");
        }
        QString     inFile(text_filename);
        QAxObject   axObject("Word.Application");
        QAxObject   *documents = axObject.querySubObject("Documents");
        QAxObject   *document = documents->querySubObject("Open(const QString&, bool)", inFile, true);
        document->dynamicCall("SaveAs(const QString&)", outFile);
        document->dynamicCall("Close()");
        axObject.dynamicCall("Quit()");

        QAxObject   axObjectNew("Word.Application");
        QAxObject   *documentsNew = axObjectNew.querySubObject("Documents");
        QAxObject   *documentNew = documentsNew->querySubObject("Open(const QString&, bool)", outFile, true);
        QAxObject   *selection = axObjectNew.querySubObject("Selection");
        selection->dynamicCall("TypeText(QString)",allMessage);
        documentNew->dynamicCall("Close()");
        axObjectNew.dynamicCall("Quit()");
    }
#endif