Qt Active Server的注册

对于Qt开发Active Server需要使用MSVC版Qt。mingw版无法用于开发Active Sever,只能通过Qt Active调用COM组件。

idc工具:D:\Qt\Qt5.5.1\5.5\msvc2013\bin

1
2
3
4
5
6
7
#注册
idc.exe multipleax.dll /regserver
idc.exe multipleax.dll -regserver

#反注册
idc.exe multipleax.dll /unregserver
idc.exe multipleax.dll -unregserver

通过Qt Active Server,可以通过浏览器来显示应用,效果就像一个web应用。Active server可以编译成dll或exe的形式。

要为每个COM类提供属性,请使用Q_CLASSINFO宏,它是Qt的元对象系统的一部分。

Key Meaning of value
Version 类的版本号,默认值是1.0
Description 类的描述
ClassID 类的ID(COM中用来唯一确定一个类的方式)QAxFactory::classID
InterfaceID 接口ID(COM中用来唯一确定接口的方式) QAxFactory::interfaceID
EventsID 事件接口ID。 如果未指定,则没有信号作为COM事件公开
DefaultProperty 指定的属性表示此类的默认属性。IE浏览器。 按钮的默认属性是“text”
DefaultSignal 指定的信号表示此类的默认信号。IE浏览器。 按钮的默认信号将被“click”
LicenseKey 对象创建需要指定的许可证密钥。 密钥可以为空以要求许可机器。 默认情况下,类未获得许可。 另请参阅以下部分。
StockEvents 如果值为“yes”,则对象公开Stock事件。参阅QAxFactory::hasStockEvents()
ToSuperClass 对象公开所有基类的接口,包括类名的值。参阅QAxFactory::exposeToSuperClass()
Insertable 如果值为“yes”,则该类被注册为“Insertable”,并将列在OLE 2容器(例如:Microsoft Office)中。 默认情况下不设置此属性。
Aggregatable 如果值为“no”,则该类不支持聚合。 默认情况下,支持聚合
Creatable 如果值为“no”,则客户端无法创建类,并且只能通过另一个类的API获得(即,类是子类型)。
RegisterObject 如果值为“yes”,则此类的对象将使用OLE注册并可从运行对象表中访问(即,客户端可以连接到此类的已运行实例)。 仅在进程外服务器中支持此属性
MIME 该对象可以处理值中指定格式的数据和文件。 该值的格式为mime:extension:description。 多个格式由分号分隔
CoClassAlias 生成的IDL和注册表中使用的类名。对于存在于命名空间中的C ++类很有用 - 默认情况下,只删除“::”以使IDL编译。
Implemented Categories 逗号分隔的类别ID(CATID)UUID列表。 除了“control”,“insertable”等之外,用于指定其他容器功能的通用机制。典型的CATID包括CATID_InternetAware(“{0DE86A58-2BAA-11CF-A229-00AA003D7352}”),CATID_SafeForScripting(“{7DD95801-9882-11CF-” 9FA9-00AA006C42C4}“)以及用户定义的CATID值。

这里有两种方法,一种是进程内,另一种是进程外。进程内是把com组件编译成动态库的形式,进程外是指把com组件编译成可执行文件。

进程内COM组件

.pro

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
TEMPLATE = lib
TARGET = multipleax

CONFIG += warn_off dll
QT += widgets axserver

SOURCES = main.cpp
HEADERS = ax1.h ax2.h
RC_FILE = multipleax.rc
DEF_FILE = multipleax.def

# This .pri file suppresses the registration of the examples in the
# Qt Continuous Integration infrastructure.
QT_CI_JENKINS_HOME=$$(JENKINS_HOME)
!isEmpty(QT_CI_JENKINS_HOME) {
message("Qt CI environment detected, suppressing example registration")
CONFIG += qaxserver_no_postlink
}

QAxWidget1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#ifndef AX1_H
#define AX1_H

#include <QWidget>
#include <QPainter>

class QAxWidget1 : public QWidget
{
Q_OBJECT
Q_CLASSINFO("ClassID", "{1D9928BD-4453-4bdd-903D-E525ED17FDE5}")
Q_CLASSINFO("InterfaceID", "{99F6860E-2C5A-42ec-87F2-43396F4BE389}")
Q_CLASSINFO("EventsID", "{0A3E9F27-E4F1-45bb-9E47-63099BCCD0E3}")

Q_PROPERTY(QColor fillColor READ fillColor WRITE setFillColor)
public:
explicit QAxWidget1(QWidget *parent = nullptr)
: QWidget(parent), m_fillColor(Qt::red)
{
}

QColor fillColor() const
{
return m_fillColor;
}

void setFillColor(const QColor &fc)
{
m_fillColor = fc;
repaint();
}

protected:
void paintEvent(QPaintEvent *e)
{
QPainter paint(this);
QRect r = rect();
r.adjust(10, 10, -10, -10);
paint.fillRect(r, m_fillColor);
}

private:
QColor m_fillColor;
};

#endif // AX1_H

QAxWidget2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#ifndef AX2_H
#define AX2_H

#include <QWidget>
#include <QPainter>

class QAxWidget2 : public QWidget
{
Q_OBJECT
Q_CLASSINFO("ClassID", "{58139D56-6BE9-4b17-937D-1B1EDEDD5B71}")
Q_CLASSINFO("InterfaceID", "{B66280AB-08CC-4dcc-924F-58E6D7975B7D}")
Q_CLASSINFO("EventsID", "{D72BACBA-03C4-4480-B4BB-DE4FE3AA14A0}")
Q_CLASSINFO("ToSuperClass", "QAxWidget2")
Q_CLASSINFO("StockEvents", "yes")
Q_CLASSINFO("Insertable", "yes")

Q_PROPERTY(int lineWidth READ lineWidth WRITE setLineWidth)
public:
explicit QAxWidget2(QWidget *parent = nullptr)
: QWidget(parent), m_lineWidth(1)
{
}

int lineWidth() const
{
return m_lineWidth;
}

void setLineWidth(int lw)
{
m_lineWidth = lw;
repaint();
}

protected:
void paintEvent(QPaintEvent *e)
{
QPainter paint(this);
QPen pen = paint.pen();
pen.setWidth(m_lineWidth);
paint.setPen(pen);

QRect r = rect();
r.adjust(10, 10, -10, -10);
paint.drawEllipse(r);
}

private:
int m_lineWidth;
};

#endif // AX2_H

main.cpp

1
2
3
4
5
6
7
8
9
10
#include "ax1.h"
#include "ax2.h"
#include <QAxFactory>

QT_USE_NAMESPACE

QAXFACTORY_BEGIN("{98DE28B6-6CD3-4e08-B9FA-3D1DB43F1D2F}", "{05828915-AD1C-47ab-AB96-D6AD1E25F0E2}")
QAXCLASS(QAxWidget1)
QAXCLASS(QAxWidget2)
QAXFACTORY_END()

multipleax.def

1
2
3
4
5
6
7
EXPORTS
DllCanUnloadNow PRIVATE
DllGetClassObject PRIVATE
DllRegisterServer PRIVATE
DllUnregisterServer PRIVATE
DumpIDL PRIVATE

multipleax.rc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include "winver.h"

1 TYPELIB "multipleax.rc"
1 ICON DISCARDABLE "multipleax.ico"

VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,0,0
PRODUCTVERSION 1,0,0,0
FILEFLAGSMASK 0x3fL
FILEOS 0x00040000L
FILETYPE 0x2L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904e4"
BEGIN
VALUE "CompanyName", "The Qt Company Ltd."
VALUE "FileDescription", "Multiple Example (ActiveQt)"
VALUE "FileVersion", "1.0.0.0"
VALUE "LegalCopyright", "Copyright (C) 2015 The Qt Company Ltd."
VALUE "InternalName", "multipleax.dll"
VALUE "OriginalFilename", "multipleax.dll"
VALUE "ProductName", "Multiple Example (ActiveQt)"
VALUE "ProductVersion", "1.0.0.0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1252
END
END

test.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<script language="javascript">
function setColor( form )
{
Ax1.fillColor = form.colorEdit.value;
}

function setWidth( form )
{
Ax2.lineWidth = form.widthEdit.value;
}
</script>

<p />
This is one QWidget subclass:<br />
<object ID="Ax1" CLASSID="CLSID:1D9928BD-4453-4bdd-903D-E525ED17FDE5"
CODEBASE="http://qt.nokia.com/demos/multipleax.cab">
[Object not available! Did you forget to build and register the server?]
</object><br />
<form>
Fill Color: <input type="edit" ID="colorEdit" value = "red" />
<input type="button" value = "Set" onClick="setColor(this.form)" />
<input type="button" value = "Hide" onClick="Ax1.hide()" />
<input type="button" value = "Show" onClick="Ax1.show()" />
</form>

<p />
This is another QWidget subclass:<br />
<object ID="Ax2" CLASSID="CLSID:58139D56-6BE9-4b17-937D-1B1EDEDD5B71"
CODEBASE="http://qt.nokia.com/demos/multipleax.cab">
[Object not available! Did you forget to build and register the server?]
</object><br />
<form>
Line width: <input type="edit" ID="widthEdit" value = "1" />
<input type="button" value = "Set" onClick="setWidth(this.form)" />
</form>

注册使用

1
idc.exe multipleax.dll /regserver

注册成功后使用IE浏览器打开test.html

进程外COM组件

.pro

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
include(../shared.pri)

TEMPLATE = app
QT += axserver

QT += widgets

# Input
SOURCES += main.cpp

RC_FILE = comapp.rc
DEF_FILE = comapp.def

# This .pri file suppresses the registration of the examples in the
# Qt Continuous Integration infrastructure.
QT_CI_JENKINS_HOME=$$(JENKINS_HOME)
!isEmpty(QT_CI_JENKINS_HOME) {
message("Qt CI environment detected, suppressing example registration")
CONFIG += qaxserver_no_postlink
}


main.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213

#include <QApplication>
#include <QAxFactory>
#include <QTabWidget>
#include <QScopedPointer>
#include <QTimer>

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:
Document *addDocument();
Document *item(int index) const;

private:
QList<Document *> m_list;
};

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

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

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"

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

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

comapp.def

1
2
3
4
5
6
7
8

EXPORTS
DllCanUnloadNow PRIVATE
DllGetClassObject PRIVATE
DllRegisterServer PRIVATE
DllUnregisterServer PRIVATE
DumpIDL PRIVATE

comapp.rc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

#include "winver.h"

1 TYPELIB "multipleax.rc"
1 ICON DISCARDABLE "comapp.ico"

VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,0,0
PRODUCTVERSION 1,0,0,0
FILEFLAGSMASK 0x3fL
FILEOS 0x00040000L
FILETYPE 0x2L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904e4"
BEGIN
VALUE "CompanyName", "The Qt Company Ltd."
VALUE "FileDescription", "comapp (ActiveQt)"
VALUE "FileVersion", "1.0.0.0"
VALUE "LegalCopyright", "Copyright (C) 2015 The Qt Company Ltd."
VALUE "InternalName", "comapp"
VALUE "OriginalFilename", "comapp"
VALUE "ProductName", "comapp (ActiveQt)"
VALUE "ProductVersion", "1.0.0.0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1252
END
END

注册使用

1
idc.exe comapp.exe /regserver