Beispiel für eine COM-Anwendung (ActiveQt)
Das COM-App-Beispiel zeigt, wie man mit ActiveQt eine Qt-Anwendung entwickelt, die über COM automatisiert werden kann. Verschiedene auf „ QObject “ basierende Klassen werden als COM-Objekte bereitgestellt, die mit der Qt GUI der laufenden Qt-Anwendung kommunizieren. Die APIs dieser COM-Objekte wurden so gestaltet, dass sie den APIs von Standard-COM-Anwendungen ähneln, d. h. denen aus Microsoft Office.
class Application : public QObject
{
Q_OBJECT
Q_CLASSINFO("ClassID", "{b50a71db-c4a7-4551-8d14-49983566afee}")
Q_CLASSINFO("InterfaceID", "{4a427759-16ef-4ed8-be79-59ffe5789042}")
Q_CLASSINFO("RegisterObject", "yes")
Q_PROPERTY(DocumentList* documents READ documents)
Q_PROPERTY(QString id READ id)
Q_PROPERTY(bool visible READ isVisible WRITE setVisible)
public:
explicit Application(QObject *parent = nullptr);
DocumentList *documents() const;
QString id() const { return objectName(); }
void setVisible(bool on);
bool isVisible() const;
QTabWidget *window() const { return m_ui.data(); }
public slots:
void quit();
private:
QScopedPointer <DocumentList> m_docs;
QScopedPointer <QTabWidget> m_ui;
};Die erste Klasse „ Application “ repräsentiert das Anwendungsobjekt. Sie stellt die schreibgeschützten Eigenschaften „ documents “ und „ id “ bereit, um Zugriff auf die Liste der Dokumente sowie auf eine Kennung zu erhalten. Die Lese-/Schreib-Eigenschaft „ visible “ steuert, ob die auf „ QTabWidget “ basierende Benutzeroberfläche der Anwendung sichtbar sein soll, und der Slot „ quit() “ beendet die Anwendung.
Das Attribut „RegisterObject“ ist so gesetzt, dass Instanzen dieser Klasse in der Running Object Table (ROT) von COM registriert werden – dies ermöglicht es COM-Clients, eine Verbindung zu einem bereits instanziierten COM-Objekt herzustellen.
class DocumentList : public QObject
{
Q_OBJECT
Q_CLASSINFO("ClassID", "{496b761d-924b-4554-a18a-8f3704d2a9a6}")
Q_CLASSINFO("InterfaceID", "{6c9e30e8-3ff6-4e6a-9edc-d219d074a148}")
Q_PROPERTY(Application* application READ application)
Q_PROPERTY(int count READ count)
public:
explicit DocumentList(Application *application);
int count() const;
Application *application() const;
public slots:
Document *addDocument();
Document *item(int index) const;
private:
QList<Document *> m_list;
};Die Klasse „ DocumentList “ speichert eine Liste von Dokumenten. Sie stellt eine API bereit, um die Anzahl der Dokumente abzurufen, über den Index auf jedes Dokument zuzugreifen und ein neues Dokument zu erstellen. Die Eigenschaft „ application “ gibt das Stammobjekt zurück.
class Document : public QObject
{
Q_OBJECT
Q_CLASSINFO("ClassID", "{2b5775cd-72c2-43da-bc3b-b0e8d1e1c4f7}")
Q_CLASSINFO("InterfaceID", "{2ce1761e-07a3-415c-bd11-0eab2c7283de}")
Q_PROPERTY(Application *application READ application)
Q_PROPERTY(QString title READ title WRITE setTitle)
public:
explicit Document(DocumentList *list);
virtual ~Document();
Application *application() const;
QString title() const;
void setTitle(const QString &title);
private:
QScopedPointer <QWidget> m_page;
};Die Klasse ` Document ` repräsentiert schließlich ein Dokument in der Anwendung. Jedes Dokument wird durch eine Seite im Register-Widget der Anwendung dargestellt und verfügt über einen Titel, der über die API des Dokuments gelesen und geschrieben werden kann. Die Eigenschaft ` application ` gibt wiederum das Stammobjekt zurück.
Document::Document(DocumentList *list)
: QObject(list)
{
QTabWidget *tabs = list->application()->window();
m_page.reset(new QWidget(tabs));
m_page->setWindowTitle(tr("Unnamed"));
tabs->addTab(m_page.data(), m_page->windowTitle());
m_page->show();
}
Document::~Document() = default;
Application *Document::application() const
{
return qobject_cast<DocumentList *>(parent())->application();
}
QString Document::title() const
{
return m_page->windowTitle();
}
void Document::setTitle(const QString &t)
{
m_page->setWindowTitle(t);
QTabWidget *tabs = application()->window();
int index = tabs->indexOf(m_page.data());
tabs->setTabText(index, m_page->windowTitle());
}Die Implementierung der Klasse ` Document ` erstellt eine neue Seite für das Register-Widget und verwendet den Titel dieser Seite für die Eigenschaft `title`. Die Seite wird gelöscht, wenn das Dokument gelöscht wird.
DocumentList::DocumentList(Application *application)
: QObject(application)
{
}
Application *DocumentList::application() const
{
return qobject_cast<Application *>(parent());
}
int DocumentList::count() const
{
return m_list.size();
}
Document *DocumentList::item(int index) const
{
return m_list.value(index, nullptr);
}
Document *DocumentList::addDocument()
{
Document *document = new Document(this);
m_list.append(document);
return document;
}Die Implementierung von „ DocumentList “ ist unkompliziert.
Application::Application(QObject *parent)
: QObject(parent),
m_ui(new QTabWidget),
m_docs(new DocumentList(this))
{
setObjectName(QStringLiteral("From QAxFactory"));
}
DocumentList *Application::documents() const
{
return m_docs.data();
}
void Application::setVisible(bool on)
{
m_ui->setVisible(on);
}
bool Application::isVisible() const
{
return m_ui->isVisible();
}
void Application::quit()
{
m_docs.reset();
m_ui.reset();
QTimer::singleShot(0 /*ms*/, qApp, &QCoreApplication::quit);
}
#include "main.moc"Die Klasse „ Application “ initialisiert die Benutzeroberfläche im Konstruktor und blendet sie in der Implementierung von „ setVisible() “ ein bzw. aus. Der Objektname (zugänglich über die Eigenschaft „ id “) wird auf „ "From QAxFactory “ gesetzt, um anzuzeigen, dass dieses COM-Objekt von COM erstellt wurde. Beachten Sie, dass es keinen Destruktor gibt, der „ QTabWidget “ löschen würde – dies geschieht stattdessen im Slot „ quit() “, bevor „ quit()“ über einen Single-Shot-Timer aufgerufen wird, was erforderlich ist, um sicherzustellen, dass der COM-Aufruf des Slots abgeschlossen ist.
QAXFACTORY_BEGIN("{edd3e836-f537-4c6f-be7d-6014c155cc7a}", "{b7da3de8-83bb-4bbe-9ab7-99a05819e201}")
QAXCLASS(Application)
QAXTYPE(Document)
QAXTYPE(DocumentList)
QAXFACTORY_END()Die Klassen werden mithilfe der Makros „ QAxFactory “ vom Server exportiert. Nur „ Application “-Objekte können von außen instanziiert werden – die anderen APIs können erst genutzt werden, nachdem über die „ Application “-API auf die jeweiligen Objekte zugegriffen wurde.
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
app.setQuitOnLastWindowClosed(false);
// started by COM - don't do anything
if (QAxFactory::isServer())
return app.exec();
// started by user
Application appobject;
appobject.setObjectName(QStringLiteral("From Application"));
QAxFactory::startServer();
QAxFactory::registerActiveObject(&appobject);
appobject.window()->setMinimumSize(300, 100);
appobject.setVisible(true);
QObject::connect(&app, &QGuiApplication::lastWindowClosed, &appobject, &Application::quit);
return app.exec();
}Die Einstiegsfunktion `main()` erstellt ein ` QApplication` und tritt direkt in die Ereignisschleife ein, wenn die Anwendung von COM gestartet wurde. Wurde die Anwendung vom Benutzer gestartet, wird das ` Application `-Objekt erstellt und der Objektname auf „From Application“ gesetzt. Anschließend wird der COM-Server gestartet und das Anwendungsobjekt bei COM registriert. Es ist nun für COM-Clients über die klientspezifischen APIs zugänglich.
Das Beenden der Anwendung wird explizit gesteuert – wenn COM die Anwendung gestartet hat, muss der Client-Code `quit()` aufrufen; wenn der Benutzer die Anwendung gestartet hat, wird die Anwendung beendet, sobald das letzte Fenster geschlossen wurde.
Schließlich wird die Benutzeroberfläche eingeblendet und die Ereignisschleife gestartet.
Eine einfache Visual-Basic-Anwendung könnte nun auf diese Qt-Anwendung zugreifen. Starten Sie in VB ein neues „Standard-Exe“-Projekt und fügen Sie eine Projektreferenz zur Typbibliothek „comappLib“ hinzu. Erstellen Sie ein Formular mit einer Listbox „DocumentList“, einem statischen Label „DocumentsCount“ und einer Befehlsschaltfläche „NewDocument“. Implementieren Sie schließlich den Code für das Formular wie folgt:
Private Application As comappLib.Application
Private MyApp As Boolean
Private Sub UpdateList()
DocumentList.Clear
DocumentsCount.Caption = Application.documents.Count
For Index = 0 To Application.documents.Count - 1
DocumentList.AddItem (Application.documents.Item(Index).Title)
Next
End Sub
Private Sub Form_Load()
On Error GoTo CreateNew
Set Application = GetObject(, "comapp.Application")
MyApp = False
GoTo Initialized
CreateNew:
On Error GoTo InitializeFailed
Set Application = New Application
Application.Visible = True
MyApp = True
Initialized:
Caption = Application.id
UpdateList
InitializeFailed:
End Sub
Private Sub Form_Unload(Cancel As Integer)
If MyApp Then
Application.quit
End If
End Sub
Private Sub NewDocument_Click()
Application.documents.addDocument
UpdateList
End SubUm das Beispiel zu erstellen, müssen Sie zunächst die Bibliothek „ QAxServer “ erstellen. Führen Sie anschließend „ qmake “ und Ihr Make-Tool unter „ examples\activeqt\comapp “ aus.
© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.