4

I want to use QAxObject to create a new docx file. how can I create a new doc and docx file and write my text with QAxObject in qt for windows. I try this code but I could not find my answer because it opens existing file but I want to create new one and use 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()");
drescherjm
  • 10,365
  • 5
  • 44
  • 64
Niusha
  • 79
  • 1
  • 10
  • you need to clarify your question and show what you already had tried by yourself. Because there are a lot of possible answers and a lot of job should be done. Don't write that you are doing something, show what you already did and ask more detailed questions. – Dmitry Sazonov Jan 15 '20 at 10:34
  • I want to use QAxObjectin to create a new docx file. in link that I post it opens an existing file. – Niusha Jan 15 '20 at 10:37
  • Please, update your question to have all necessary information. It is not welcome if you are pushing everyone to visit external links. Second point, stackoverflow is not a free-coding-service, you need to to self investigation of your question and show summarized results to community. – Dmitry Sazonov Jan 15 '20 at 12:04
  • I update my question. – Niusha Jan 15 '20 at 12:19
  • 1
    @DmitrySazonov: I understand the question perfectly: How to use ActiveQt to create a word document from scratch?, as opposed to opening / reading an existing document.I can't find a single template / example / tutorial on SO or any other forum that answers that question, and upvotes here show that some other people wants this question to be answered. Please reopen! – Former contributor Jan 15 '20 at 13:48
  • @Pedro for me it's not clear, where problem is started? Question is about Qt or it is about ActiveX? I don't see any attempts of error handling, etc. – Dmitry Sazonov Jan 21 '20 at 12:13
  • @DmitrySazonov, I don't know the question origin or OP motivations, and to tell the truth I don't care. OP is asking about COM automation, specifically Word automation to create documents from scratch from a Qt application. This can be done with ActiveQt, which is part of the Qt Frameworks. Seems that OP prefers to do it the hard way. using `QAxObject` directly. Well, I prefer to do it in another way that is also supported by the Qt tooling/Framework, seems easier, and have not been mentioned in SO before. Maybe other readers in the future could find it helpful. – Former contributor Jan 21 '20 at 21:43

2 Answers2

3

There are already some answers to questions like this one in SO suggesting the usage of QAxObject with dynamicCall() for MS Office automation. This can be done, and it will work, but I think that there is a better and more fun way to do it.

My proposal is to import the COM Type Library that comes with each Office application, generating a C++ object model. This has two advantages: is similar to the interop approach that is popular in C# and VB.NET, and even samples for those languages may be used as models for our own Qt projects. And of course, you may enjoy autocompletion in Qt Creator for classes and member names. Did I mention fun already?

This is very similar to the 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 that may be found in the Qt bin directory. This is a simple command line program project importing the MS Word object model:

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
}

To discover the GUID of other type libraries, you may use the oleview.exe utility.

QMake creates a source file MSWORD.cpp and a header MSWORD.h that you may include in your own classes to access to the generated object model. This sample generates a Word document from scratch, and saves it in two formats:

#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;
}

As you can see, the code is quite readable, at the price of including a big chunk of code. You #include the generated header MSWORD.h, and the program creates a new document, populates its contents with two text lines, and saves this document twice: first in the modern DOCX format, and then in the DOC format compatible with Word 97/2003.

The complete project can be found in this GitHub repository.

Former contributor
  • 2,466
  • 2
  • 10
  • 15
0
#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
Niusha
  • 79
  • 1
  • 10