qt编写activex_Qt中使用ActiveX(一)
由于最近需要使用ActiveX,一般來說可以使用微軟提供的MFC或者ATL框架來開發(fā),由于我個人對這部分內(nèi)容不是很熟悉,好在Qt也提供對于ActiveX的支持。本文主要記錄個人學習ActiveX的一些內(nèi)容,方便日后查閱。本文以Qt5(5.3.1)提供的ActiveX為參考,但是由于ActiveX這部分比較穩(wěn)定,因此Qt4應該也是一樣的。
概述
Qt提供了QtActiveX模塊來支持微軟ActiveX的開發(fā),Qt的ActiveX和COM的開發(fā)支持兩種方式:
支持將已有的COM或者ActiveX空間引入到Qt的應用程序中
支持將Qt應用程序或者Qt的對象導出成COM對象或者ActiveX控件供他人使用
具體來說,Qt是通過ActiveXQt框架中的兩個模塊來支持上述所說的兩種方式的:
使用QAxContainer模塊,通過QAxObject和QAxWidget分別支持COM對象和ActiveX控件的開發(fā),可以通過這兩個對象將外部的COM或者ActiveX組件接入到Qt應用程序
使用QAxServer模塊,通過QAxAggregated、QAxBindable和QAxFactory類,通過了進程內(nèi)和可執(zhí)行程序exe兩種方式的COM Server模式,用來將Qt寫的內(nèi)容導出為COM或者ActiveX供他人使用。
下圖簡要的說明了QtActiveX的作用
使用QtActiveX創(chuàng)建COM或ActiveX Server
在正式開始之前先對COM和ActiveX做一個簡要的對比。COM(Component Object Model)是微軟提出的一種技術,它定義了一種規(guī)范,通過COM可以輕松實現(xiàn)一種語言(如C#)調(diào)用另一種語言(如C++、VB等)開發(fā)的功能模塊。ActiveX是微軟主要針對互聯(lián)網(wǎng)客戶端設計的以COM為技術基礎的一種實現(xiàn),一般來說二者并沒有本質(zhì)的區(qū)別,僅有一些概念上的差異,一般來說:
1. ActiveX一般包含一個窗體界面,COM對象一般并沒有界面
2. COM對象一般作為一個可調(diào)用的模塊來使用,ActiveX一般嵌入在網(wǎng)頁中使用
上述僅僅是一種使用上的慣例,但是并未強制一定這樣
使用Qt作COM和ActiveX的開發(fā)需要使用QAxServer模塊,這里面包含三個類:
1. QAxFactory定義了創(chuàng)建COM對象的工廠類
2. QAxBindable定義了COM對象與Qt對象之間的轉(zhuǎn)換關系,也就是說Qt中的對象通過QAxBindable轉(zhuǎn)換為COM中的要素
3. QAxAggregated定義了COM組件接口
Qt作為Server支持的模式
COM組件在開發(fā)出來之后有多種形式,可以是一個dll,也可以是一個exe可執(zhí)行程序。可以在進程中被加載(一般最常用的模式),可以作為外部進程為其他進程提供服務,甚至可以是遠程服務器上的進程為本地集成提供服務。Qt ActiveX 提供了In-Process和out-of-process executable兩種方式的支持。簡單來說就是提供了一種 Dll供應用程序調(diào)用也提供了一種可以作為運行的exe,為其他應用提供一些調(diào)用服務。
當作為獨立exe時候,我們需要這樣編寫.pro文件:
TEMPLATE = app
QT += axserver
RC_FILE = qaxserver.rc當作為進程內(nèi)dll的時候,需要這樣寫.pro文件
TEMPLATE = lib
QT += axserver
CONFIG += dll
DEF_FILE = qaxserver.def
RC_FILE = qaxserver.rc
...但是我們不用去操心這些內(nèi)容,因為一般我們是用向?qū)砩蒕t工程的,當你勾選ActiveX Server模式的時候,向?qū)б呀?jīng)幫你寫好這些內(nèi)容了。
當使用QAxServer開發(fā)dll時,實際工程編譯鏈接過程中會涉及到以下的過程:
1. 應用程序?qū)溄拥絨tserver.lib而不是qtmain.lib
2. idc工具會被調(diào)用,產(chǎn)生IDL文件(接口描述語言的接口描述文件)
3.調(diào)用MIDL工具編譯IDL文件到類型庫
4.調(diào)用idc工具將類型庫附到server的二進制代碼中
5. 注冊dll
另外在.Pro文件中可以添加一個版本信息,這個版本信息會作類型庫和server dll的版本號,添加方式使用VERSION變量即可:
TEMPLATE = lib
VERSION = 2.5
...
COM進程外和進程內(nèi)使用方式的比較
進程外的使用方式是將COM寫成一個exe可執(zhí)行文件,當它運行的時候其他程序可以調(diào)用它提供的接口來開發(fā),這樣做如果某個調(diào)用它的程序出了bug,那么只有該程序會崩潰,其他調(diào)用不收影響,提供了更好的隔離性。缺點是需要更長的啟動時間與跨進程通信的一些額外負擔。
進程內(nèi)的使用方式就很簡單了,調(diào)用過程僅僅是通過類似虛函數(shù)這樣的調(diào)用,需要加載的時間短、效率比較高。
開發(fā)Server的過程
為了使用Qt實現(xiàn)COM對象,我們必須使用一個QObject的子類,如果該子類是QWidget的子類,那么這個COM對象就是一個ActiveX控件。代碼如下:
#include
class MyActiveX : public QWidget
{
Q_OBJECT只里面Q_OBJECT宏不能少,它提供了關于類MyActiveX的一些元數(shù)據(jù)信息, 接下來繼續(xù)添加ActiveX的一些信息
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_CLASSINFO定義了COM組件的一些信息,這里面ClassID和InterfaceID是必須的,當你需要使用COM中的事件時,EventsID就需要添加進來。里面的128位的字符串使用GUID.exe工具生成(微軟提供的一個小工具,可以生成全球唯一的標識符,可以在系統(tǒng)文件夾或者visual Studio的工具菜單中找到),工具提供了多種模式,可以選擇需要的模式復制添加到代碼中:
除了上述基本必要的信息之外(ClassID實際上被寫入注冊表中,當控件被使用的時候會搜索注冊表找到里面該COM控件dll的位置并加載,可以使用regedit.exe在HKEY_CLASSES_ROOT中找到很多已經(jīng)注冊的COM組件信息),Qt還提供了Q_CLASSINFO更多的內(nèi)容,如下表所示:
名稱
值和含義
Version
類的版本號,默認值是1.0
Description
類的描述
ClassID
類的ID(COM中用來唯一確定一個類的方式)
InterfaceID
接口ID(COM中用來唯一確定接口的方式)
EventsID
事件ID
DefaultProperty
默認屬性
DefaultSignal
默認的時間
LicenseKey
類的許可號,默認未開啟,如果開啟使用類需要許可號
StockEvents
TODO:???
ToSuperClass
暴露父類的接口
Insertable
設置"yes"后可以被列到OLE2容器中,默認未設置
Aggregatable
默認是"yes",COM支持聚合
Creatable
設置為“no”調(diào)用者不能使用該類
RegisterObject
僅能用在進程外方式的COM中
MIME
該COM控件支持的文件格式描述
CoClassAlias
類的名稱在IDL中被修改為CoClassAlias指定的名字
繼續(xù)上面的代碼,接下來可以添加一些屬性到COM組件中,可以使用另一個宏Q_PROPERTY
Q_PROPERTY(int value READ value WRITE setValue)之后可以像寫Qt程序那樣來完成。
public:
MyActiveX(QWidget *parent = 0)
...
int value() const;
public slots:
void setValue(int v);
...
signals:
void valueChange(int v);
...
};Qt的ActiveX框架會將Qt類中的要素轉(zhuǎn)換為COM中的標準要素供其他調(diào)用者使用,具體來說:
1. ?Qt類中的屬性和公有的插槽函數(shù)(slots)會被轉(zhuǎn)換為COM中的屬性和方法
2. ?Qt類中的信號(signals)會被轉(zhuǎn)換成為COM組件中的事件
另外其他的數(shù)據(jù)類型轉(zhuǎn)換之間的對應關系如下圖所示:
1. Qt中屬性的數(shù)據(jù)類型與COM中數(shù)據(jù)類型的轉(zhuǎn)換關系如下:
Qt數(shù)據(jù)類型
COM 屬性數(shù)據(jù)類型
bool
VARIANT_BOOL
QString
BSTR
int
int
uint
unsigned int
double
double
qlonglong
CY
qulonglong
CY
QColor
OLE_COLOR
QDate
DATE
QDateTime
DATE
QTime
DATE
QFont
IFontDisp*
QPixmap
IPixtureDisp*
QVariant
VARIANT
QVariantList
SAFEARRAY(VARIANT)
QStringList
SAFEARRAY(BSTR)
QByteArray
SAFEARRAY(BYTE)
QRect
User defined type
QSize
User defined type
QPoint
User defined type
2. Qt中信號和插槽函數(shù)的形式參數(shù)數(shù)據(jù)類型
Qt數(shù)據(jù)類型
對應COM的數(shù)據(jù)類型
bool
[in] VARIANT_BOOL
bool&
[in,out] VARIANT_BOOL*
QString, const Qtring&
[in] BSTR
QString&
[in, out] BSTR*
QStinrg&
[in, out] BSTR*
int
[in] int
int&
[in, out]int
uint
[in,out]unsigned int
uint&
[int, out] unsigned int*
double
[in] double
QColor, const QColor&
[in] OLE_COLOR
QColor&
[in,out] OLE_COLOR*
QDate, const QDate&
[in] DATE
QDate&
[in,out]DATE*
QDateTime, const QDateTime&
[in] DATE
QDateTime&
[in,out]DATE*
QFont, const QFont&
[in] IFontDisp*
QFont&
[in,out]IFontDisp**
QPixmap, const QPixmap&
[in]IPictureDisp*
QPixmap&
[in,out]IPictureDisp**
QList
[in]SAFEARRAY(VARIANT)
QList&
[in,out]SAFEARRAY(VARIANT)*
QObject*
[in] IDispatch*
此外QActiveX也可以通過Q_ENUMS和Q_FLAGS將枚舉變量導出,如果使用了非上表中的類型來作為信號和插槽函數(shù)的參數(shù)類型,那么Qt ActiveX框架不會轉(zhuǎn)換這些參數(shù)。
發(fā)布COM控件
為了讓Qt編寫的代碼可以作為一個COM組件被使用,必須提供獲取COM對象的方法,在Qt中使用QAxFactory來完成,最簡單的方法是使用下面的宏:
QAXFACTORY_BEGIN("{ad90301a-849e-4e8b-9a91-0a6dc5f6461f}",
"{a8f21901-7ff7-4f6a-b939-789620c03d83}")
QAXCLASS(MyWidget)
QAXCLASS(MyWidget2)
QAXTYPE(MySubType)
QAXFACTORY_END()上面這段代碼把MyWidget和MyWidget2導出為可供外部調(diào)用的COM對象,并注冊MySubType類型可供MyWidget和MyWidget2中的屬性和參數(shù)使用。
進程外COM控件的編寫
對于進程外可執(zhí)行的COM組件,我們需要執(zhí)行一個main函數(shù)來實例化一個QApplication,和一般的Qt程序類似。
#include
#include
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
if (!QAxFactory::isServer()) {
// create and show main window
}
return app.exec();
}
總結(jié)
以上是生活随笔為你收集整理的qt编写activex_Qt中使用ActiveX(一)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mysql my.ini utf8_修改
- 下一篇: cookie获取java_java中如何