Qt中使用ActiveX(一)
阿新 • • 發佈:2019-01-22
由於最近需要使用ActiveX,一般來說可以使用微軟提供的MFC或者ATL框架來開發,由於我個人對這部分內容不是很熟悉,好在Qt也提供對於ActiveX的支援。本文主要記錄個人學習ActiveX的一些內容,方便日後查閱。本文以Qt5(5.3.1)提供的ActiveX為參考,但是由於ActiveX這部分比較穩定,因此Qt4應該也是一樣的。
- 概述
- 支援將已有的COM或者ActiveX空間引入到Qt的應用程式中
- 支援將Qt應用程式或者Qt的物件匯出成COM物件或者ActiveX控制元件供他人使用
- 使用QAxContainer模組,通過QAxObject和QAxWidget分別支援COM物件和ActiveX控制元件的開發,可以通過這兩個物件將外部的COM或者ActiveX元件接入到Qt應用程式
- 使用QAxServer模組,通過QAxAggregated、QAxBindable和QAxFactory類,通過了程序內和可執行程式exe兩種方式的COM Server模式,用來將Qt寫的內容匯出為COM或者ActiveX供他人使用。
- 使用QtActiveX建立COM或ActiveX Server
- Qt作為Server支援的模式
TEMPLATE = app
QT += axserver
RC_FILE = qaxserver.rc
當作為程序內dll的時候,需要這樣寫.pro檔案
TEMPLATE = lib
QT += axserver
CONFIG += dll
DEF_FILE = qaxserver.def
RC_FILE = qaxserver.rc
...
但是我們不用去操心這些內容,因為一般我們是用嚮導來生成Qt工程的,當你勾選ActiveX Server模式的時候,嚮導已經幫你寫好這些內容了。
當使用QAxServer開發dll時,實際工程編譯連結過程中會涉及到以下的過程: 1. 應用程式將會連結到qtserver.lib而不是qtmain.lib 2. idc工具會被呼叫,產生IDL檔案(介面描述語言的介面描述檔案) 3.呼叫MIDL工具編譯IDL檔案到型別庫 4.呼叫idc工具將型別庫附到server的二進位制程式碼中 5. 註冊dll 另外在.Pro檔案中可以新增一個版本資訊,這個版本資訊會作型別庫和server dll的版本號,新增方式使用VERSION變數即可:
TEMPLATE = lib
VERSION = 2.5
...
- COM程序外和程序內使用方式的比較
- 開發Server的過程
#include <QWidget>
class MyActiveX : public QWidget
{
Q_OBJECT
只裡面Q_OBJECT巨集不能少,它提供了關於類MyActiveX的一些元資料資訊, 接下來繼續新增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工具生成(微軟提供的一個小工具,可以生成全球唯一的識別符號,可以在系統資料夾或者visual Studio的工具選單中找到),工具提供了多種模式,可以選擇需要的模式複製新增到程式碼中:
除了上述基本必要的資訊之外(ClassID實際上被寫入登錄檔中,當控制元件被使用的時候會搜尋登錄檔找到裡面該COM控制元件dll的位置並載入,可以使用regedit.exe在HKEY_CLASSES_ROOT中找到很多已經註冊的COM元件資訊),Qt還提供了Q_CLASSINFO更多的內容,如下表所示:
名稱 | 值和含義 |
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”呼叫者不能使用該類 |
RegisterObject | 僅能用在程序外方式的COM中 |
MIME | 該COM控制元件支援的檔案格式描述 |
CoClassAlias | 類的名稱在IDL中被修改為CoClassAlias指定的名字 |
繼續上面的程式碼,接下來可以新增一些屬性到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類中的要素轉換為COM中的標準要素供其他呼叫者使用,具體來說:
1. Qt類中的屬性和公有的插槽函式(slots)會被轉換為COM中的屬性和方法
2. Qt類中的訊號(signals)會被轉換成為COM元件中的事件另外其他的資料型別轉換之間的對應關係如下圖所示: 1. Qt中屬性的資料型別與COM中資料型別的轉換關係如下:
Qt資料型別 | COM 屬性資料型別 |
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中訊號和插槽函式的形式引數資料型別
Qt資料型別 | 對應COM的資料型別 |
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<QVariant> | [in]SAFEARRAY(VARIANT) |
QList<QVariant>& | [in,out]SAFEARRAY(VARIANT)* |
QObject* | [in] IDispatch* |
- 釋出COM控制元件
QAXFACTORY_BEGIN("{ad90301a-849e-4e8b-9a91-0a6dc5f6461f}",
"{a8f21901-7ff7-4f6a-b939-789620c03d83}")
QAXCLASS(MyWidget)
QAXCLASS(MyWidget2)
QAXTYPE(MySubType)
QAXFACTORY_END()
上面這段程式碼把MyWidget和MyWidget2匯出為可供外部呼叫的COM物件,並註冊MySubType型別可供MyWidget和MyWidget2中的屬性和引數使用。
- 程序外COM控制元件的編寫
#include <QApplication>
#include <QAxFactory>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
if (!QAxFactory::isServer()) {
// create and show main window
}
return app.exec();
}