Exemple d'application COM (ActiveQt)
L'exemple COM App montre comment utiliser ActiveQt pour développer une application Qt qui peut être automatisée via COM. Différentes classes basées sur QObject sont exposées en tant qu'objets COM qui communiquent avec l'interface graphique de l'application Qt en cours d'exécution. Les API de ces objets COM ont été conçues pour ressembler aux API des applications COM standard, c'est-à-dire celles de 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; };
La première classe Application représente l'objet application. Elle expose des propriétés en lecture seule documents et id pour accéder à la liste des documents et à un identifiant. Une propriété en lecture/écriture visible contrôle si l'interface utilisateur de l'application basée sur QTabWidget doit être visible, et un slot quit() met fin à l'application.
L'attribut RegisterObject est défini pour s'assurer que les instances de cette classe sont enregistrées dans la table des objets en cours d'exécution (ROT) de COM, ce qui permet aux clients COM de se connecter à un objet COM déjà instancié.
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; };
La classe DocumentList stocke une liste de documents. Elle fournit une API permettant de lire le nombre de documents, d'accéder à chaque document par son index et de créer un nouveau document. La propriété application renvoie l'objet racine.
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; };
La classe Document représente enfin un document dans l'application. Chaque document est représenté par une page dans le widget d'onglets de l'application et possède un titre qui peut être lu et écrit via l'API du document. La propriété application renvoie à nouveau l'objet racine.
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()); }
L'implémentation de la classe Document crée une nouvelle page pour le widget d'onglets et utilise le titre de cette page pour la propriété title. La page est supprimée lorsque le document est supprimé.
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; }
L'implémentation de la classe DocumentList est simple.
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"
La classe Application initialise l'interface utilisateur dans le constructeur, puis l'affiche et la cache dans l'implémentation de setVisible(). Le nom de l'objet (accessible via la propriété id ) est défini à "From QAxFactory " pour indiquer que cet objet COM a été créé par COM. Notez qu'il n'y a pas de destructeur qui supprimerait QTabWidget - cela est fait dans le slot quit(), avant d'appeler quit() à travers un single-shot-timer, qui est nécessaire pour s'assurer que l'appel COM au slot est complet.
QAXFACTORY_BEGIN("{edd3e836-f537-4c6f-be7d-6014c155cc7a}", "{b7da3de8-83bb-4bbe-9ab7-99a05819e201}") QAXCLASS(Application) QAXTYPE(Document) QAXTYPE(DocumentList) QAXFACTORY_END()
Les classes sont exportées du serveur à l'aide des macros QAxFactory. Seuls les objets Application peuvent être instanciés de l'extérieur - les autres API ne peuvent être utilisées qu'après avoir accédé aux objets respectifs par l'intermédiaire de l'API Application.
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(); }
La fonction de point d'entrée main() crée une application QApplication et n'entre dans la boucle d'événements que si l'application a été lancée par COM. Si l'application a été lancée par l'utilisateur, l'objet Application est créé et le nom de l'objet est "From Application". Le serveur COM est ensuite démarré et l'objet application est enregistré auprès de COM. Il est maintenant accessible aux clients COM par l'intermédiaire des API spécifiques au client.
La sortie de l'application est contrôlée explicitement - si COM a démarré l'application, le code client doit appeler quit() ; si l'utilisateur a démarré l'application, celle-ci se termine lorsque la dernière fenêtre a été fermée.
Enfin, l'interface utilisateur est rendue visible et la boucle d'événements est lancée.
Une simple application Visual Basic pourrait maintenant accéder à cette application Qt. Dans VB, démarrez un nouveau projet "Standard Exe" et ajoutez une référence de projet à la bibliothèque de type comappLib. Créez un formulaire avec une zone de liste "DocumentList", une étiquette statique "DocumentsCount" et un bouton de commande "NewDocument". Enfin, implémentez le code du formulaire comme suit :
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 Sub
Pour construire l'exemple, vous devez d'abord construire la bibliothèque QAxServer. Ensuite, exécutez qmake et votre outil make dans examples\activeqt\comapp.
© 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.