COM App 範例 (ActiveQt)

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

第 1 個類 應用程序 錶示應用程序對象。它暴露隻讀特性 documents and id 以訪問文檔列錶和標識符。讀/寫特性 visible 控製是否 QTabWidget 基應用程序的用戶界麵應該可見,和槽 quit() 終止應用程序。

The RegisterObject 屬性的設置是為確保在 COM ROT (運行對象錶) 中注冊此類的實例 - 這允許 COM 客戶端連接到已實例化的 COM 對象。

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

The DocumentList 類存儲文檔的列錶。它提供讀取文檔數、按索引訪問各文檔及創建新文檔的 API。 application 特性返迴根對象。

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

The Document 類錶示最終應用程序文檔。各文檔由應用程序選項卡 Widget 中的頁麵錶示,且擁有的標題透過文檔 API 可讀寫。 application 特性再次返迴根對象。

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()
{
}
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());
}
					

實現為 Document 類為選項卡 Widget 創建新頁麵,並將該頁麵標題用於 title 特性。會刪除頁麵當刪除文檔時。

DocumentList::DocumentList(Application *application)
: QObject(application)
{
}
Application *DocumentList::application() const
{
    return qobject_cast<Application *>(parent());
}
int DocumentList::count() const
{
    return m_list.count();
}
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;
}
					

The DocumentList 實現很簡單。

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"
					

The 應用程序 類在構造函數中初始化用戶界麵,並展示和隱藏它在實現 setVisible() 。對象名稱 (可訪問透過 id 特性) 被設為 "From QAxFactory " 以指示此 COM 對象已由 COM 所創建。注意,沒有析構函數會刪除 QTabWidget - 代替履行這的是在 quit() 槽,先於調用 quit() 透過單發計時器,確保完成 COM 槽的調用是必要的。

QAXFACTORY_BEGIN("{edd3e836-f537-4c6f-be7d-6014c155cc7a}", "{b7da3de8-83bb-4bbe-9ab7-99a05819e201}")
   QAXCLASS(Application)
   QAXTYPE(Document)
   QAXTYPE(DocumentList)
QAXFACTORY_END()
					

類的導齣是從服務器使用 QAxFactory 宏。僅 應用程序 對象可以從外部實例化 - 纔可以使用其它 API 後於訪問各個對象縱觀 應用程序 API.

int main(int argc, char *argv[])
{
    QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    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();
}
					

main() 入口點函數創建 QApplication ,且僅僅進入事件循環若應用程序已由 COM 所啓動。若應用程序已由用戶所啓動,則 應用程序 對象被創建且對象名稱被設為 From Application。然後啓動 COM 服務器,並采用 COM 注冊應用程序對象。現在,透過特定客戶端 API 可訪問 COM 客戶端。

應用程序的退齣是明確控製的 - 若 COM 啓動瞭應用程序,則客戶端代碼必須調用 quit();若用戶啓動瞭應用程序,則終止應用程序當關閉最後窗口時。

最後,使用戶界麵可見,並啓動事件循環。

簡單的 Visual Basic 應用程序現在可以訪問此 Qt 應用程序。以 VB,啓動新 Standard Exe 工程並嚮 comappLib 類型庫添加工程引用。創建具有 DocumentList 列錶框、DocumentsCount 靜態標簽及 NewDocument 命令按鈕的錶單。最後,為錶單實現像這樣的代碼:

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)
    下一
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
					

要構建範例必須先構建 QAxServer 庫。然後運行 qmake 和 make 工具在 examples\activeqt\comapp .

文件: