一、建立ActiveQt项目
自动生成的demo代码如下:
#include "ActiveQtServerHourse.h"
#include <ActiveQt/QAxFactory>
ActiveQtServerHourse::ActiveQtServerHourse(QWidget *parent)
: QWidget(parent)
{
ui.setupUi(this);
}
QAXFACTORY_DEFAULT(ActiveQtServerHourse, //暴露给外部的类的名称,我们这里暴露的类名称为ActiveQtServerHourse,先就这么写
"{82a36901-0766-498b-beaf-8b3e62e0b530}", //类ID,如果是一个DLL需要暴露多个类的话,调用的时候是通过这个ID连接到指定的类
"{b8de8377-4185-4c9d-a803-77b1939b1360}", //接口ID,不用管
"{70744dbb-3062-4ade-9a0c-fc42dafa5b8f}", //事件ID,不用管,如果当前的类需要发送事件的话需要定义
"{f763f5b7-cc63-4a05-9757-9debc4a7078d}", //当前lib 的ID,这个是这个lib的唯一标识,如果只有一个类导出,我们可能会需要用到这个东西
"{cd0da224-8eec-4739-a342-ecf88f6d3259}" //当前进程ID,这个如果是你将这个COM组件设定为EXE,那么我们可能就需要通过这个来建立连接
二、定义需要导出的类
QAXFACTORY_DEFAULT()宏的作用是导出一个AxtiveX控件,可以用于仅导出一个控件的ActiveX server。
当server要导出多个控件时,也就是一个DLL需要暴露多个类,需要重新修改代码格式:
ActiveQtServerHourse.h
#pragma once
#include <QtWidgets/QWidget>
#include <ActiveQt/QAxBindable>
#include "ui_ActiveQtServerHourse.h"
class ActiveQtServerHourse : public QWidget, public QAxBindable
{
Q_OBJECT
Q_CLASSINFO("ClassID", "{4f09dbb6-672f-46fa-89c6-06acc997209d}")
Q_CLASSINFO("InterfaceID", "{54e54ad8-17db-4fd1-8156-a6a9f10ac8dd}")
public:
ActiveQtServerHourse(QWidget *parent = nullptr);
private:
Ui::ActiveQtServerHourseClass ui;
};
上面定义了有关这个类的属性,也就是ClassID,InterfaceID,EventsID。
类需要继承QObject和QAxBindable,前者可以保证signals和slots的使用,后者可以保证signals和slots和COM函数和事件对接上。
将Qt官方demo,一起集成到里面来:
COM App Example (ActiveQt) | Active Qt 6.7.1
Document.h
#pragma once
#include <QObject>
#include <QApplication>
#include <QAxFactory>
#include <QTabWidget>
#include <QScopedPointer>
#include <QTimer>
#include <QList>
class Application;
class DocumentList;
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;
};
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:
void addDocument(Document*);
Document* addDocument();
Document* item(int index) const;
private:
QList<Document*> m_list;
};
//! [1]
//! [2]
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;
};
Document.cpp
#include "Document.h"
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());
}
//! [3] //! [4]
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);
}
void DocumentList::addDocument(Document* document) {
m_list.append(document);
}
Document* DocumentList::addDocument()
{
Document* document = new Document(this);
m_list.append(document);
return document;
}
//! [4] //! [5]
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);
}
三、声明所有导出的多个类,并生成dll
然后我们还需要在总的宏编译,在CPP文件中定义需要导出的类:
#include "ActiveQtServerHourse.h"
#include <ActiveQt/QAxFactory>
#include "Document.h"
ActiveQtServerHourse::ActiveQtServerHourse(QWidget *parent)
: QWidget(parent)
{
ui.setupUi(this);
}
QAXFACTORY_BEGIN("{edd3e836-f537-4c6f-be7d-6014c155cc7a}", "{b7da3de8-83bb-4bbe-9ab7-99a05819e201}")
QAXTYPE(Document)
QAXCLASS(DocumentList)
QAXCLASS(Application)
QAXCLASS(ActiveQtServerHourse)
QAXFACTORY_END()
随后点击生成dll,并用windeploy做发布。
D:\Qt\6.7\6.7.0\msvc2019_64\bin\windeployqt.exe .\ActiveQtServerHourse.dll
四、C#调用Com C++类
4.1 添加类引用
4.2 查看可以访问的函数
4.3 C#代码使用Com类
using System;
using System.Windows.Forms;
namespace WindowsFormsApp4
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
ActiveQtServerHourseLib.Application appobj = new ActiveQtServerHourseLib.Application();
appobj.visible = true;
ActiveQtServerHourseLib.DocumentList docList = appobj.documents;
docList.addDocument_1();
docList.addDocument_1();
docList.addDocument_1();
docList.addDocument_1();
int count = docList.count;
axActiveQtServerSnake1.set_text("Hello, I'm From C# text,docs count:" + count + ",doc title:" + docList.item(0).title);
}
}
}
参考文章
Qt的进程间通信,以Active服务器的形式,手把手教你VS上进行Qt的COM、ActivedQt Server的开发,比保姆还保姆
https://www.cnblogs.com/Leventure/p/16971934.html
如何用ActiveQt写导出类