windowxp做網(wǎng)站服務(wù)器寧波技術(shù)好的企業(yè)網(wǎng)站制作
一、COM簡介
1.1 COM是什么?
COM,Component Object Model,即組件對象模型,是一種以組件為發(fā)布單元的對象模型,這種模型使各軟件組件可以用一種統(tǒng)一的方式進(jìn)行交互。COM 既提供了組件之間進(jìn)行交互的規(guī)范,也提供了實現(xiàn)交互的環(huán)境,因為組件對象之間交互的規(guī)范不依賴于任何特定的語言,所以,COM也可以是不同語言協(xié)作開發(fā)的一種標(biāo)準(zhǔn)。
COM實際上是一種組件標(biāo)準(zhǔn),COM不僅僅提供了組件之間的接口標(biāo)準(zhǔn),它還引入了面向?qū)ο蟮乃季S。在COM標(biāo)準(zhǔn)中,對象是一個非常活躍的元素,常常被稱為COM對象。組件模塊為COM對象提供了活動的空間,COM對象以接口的方式提供服務(wù),這種接口就被稱為COM接口。COM組件、COM對象、COM接口三者的關(guān)系如下圖所示:
在Windows系統(tǒng)平臺上,一個COM組件可以是一個DLL(Dynamic?Linking?Library,動態(tài)鏈接庫)文件,也可以是一個EXE(可執(zhí)行程序)文件。一個組件程序可以包含多個COM對象,并且每個COM對象可以實現(xiàn)多個接口。
當(dāng)另外的組件或者普通程序(即組件的客戶程序)調(diào)用組件的功能時,它首先創(chuàng)建一個COM對象或者通過其他途徑獲得COM對象,然后通過該對象所實現(xiàn)的COM接口調(diào)用它所提供的服務(wù)。當(dāng)所有的服務(wù)結(jié)束之后,如果客戶程序不再需要該COM對象,那么它就應(yīng)該釋放掉對象所占用的資源,包括對象自身。
1.2?COM接口與API之間的區(qū)別
COM接口和經(jīng)常說的API有點相似。通過API接口層,可以很好地把兩個程序連接起來,但存在一些問題:1)、當(dāng)API非常多時,使用會非常不方便,需要對函數(shù)進(jìn)行組織。2)、API函數(shù)需要標(biāo)準(zhǔn)化,按照統(tǒng)一的調(diào)用方式進(jìn)行處理,以適應(yīng)不同編程語言的實現(xiàn),包括參數(shù)傳遞順序、參數(shù)類型、函數(shù)返回處理都需要標(biāo)準(zhǔn)化。而COM定義了一套完整的接口規(guī)范,不僅可以彌補以上API作為組件接口的補足,還充分發(fā)揮了組件對象的優(yōu)勢,并實現(xiàn)了組件對象的多態(tài)性。
1.3?.NET組件和COM組件的區(qū)別
.NET組件和COM組件之間的主要區(qū)別在于它們的設(shè)計目標(biāo)、實現(xiàn)方式和運行環(huán)境。.NET組件是微軟推出的新一代編程模型,用于構(gòu)建Web應(yīng)用、桌面應(yīng)用和移動應(yīng)用;而COM組件是Windows操作系統(tǒng)中基于二進(jìn)制代碼通信的機制,主要用于實現(xiàn)Windows系統(tǒng)中的各種組件之間的互操作。.NET組件和COM組件在實現(xiàn)方式、編程語言和運行環(huán)境上有所不同。
實現(xiàn)方式:
.NET組件:通過C#、VB.NET等.NET編程語言編寫,以.NET框架為基礎(chǔ),運行在.NET運行時(CLR)上。
COM組件:通過C++、VB6等編程語言編寫,以COM為基礎(chǔ),運行在COM運行時上。
編程語言:
.NET組件:使用C#、VB.NET等.NET編程語言編寫,可以跨平臺運行。
COM組件:使用C++、VB6等編程語言編寫,只能在Windows操作系統(tǒng)中運行。
運行環(huán)境:
.NET組件:運行在.NET運行時(CLR)上,支持多語言、跨平臺、面向?qū)ο蠛皖愋桶踩裙δ堋?/span>
COM組件:運行在COM運行時上,支持多語言、跨平臺、面向?qū)ο蠛皖愋桶踩裙δ堋?/span>
生命周期:
.NET組件:具有短暫的生命周期,一旦被加載到內(nèi)存中,就可以立即運行。
COM組件:具有較長的生命周期,需要經(jīng)過加載、注冊、卸載等步驟,需要更多的手動管理。
安全性:
.NET組件:提供了內(nèi)存管理和類型安全等功能,可以避免緩沖區(qū)溢出等安全問題。
COM組件:由于手動管理,容易出現(xiàn)緩沖區(qū)溢出等安全問題。
總的來說,.NET組件和COM組件在設(shè)計目標(biāo)、實現(xiàn)方式和運行環(huán)境上有所不同,但它們都是用于構(gòu)建Windows應(yīng)用程序的組件化編程模型。
因此COM組件并不依賴于.NET?Framework的運行環(huán)境。
但兩者之間是可以相互調(diào)用,見如下文章:
COM 互操作示例:.NET 客戶端和 COM 服務(wù)器 - .NET Framework | Microsoft Learn
1.4?類廠
在創(chuàng)建組件對象時,客戶程序調(diào)用COM庫中的函數(shù)進(jìn)行組件對象的創(chuàng)建工作,COM庫的創(chuàng)建函數(shù)根據(jù)注冊表的信息并調(diào)用組件程序的入口函數(shù)來創(chuàng)建組件對象。所以組件程序需要提供一個標(biāo)準(zhǔn)的入口函數(shù)?DllGetObjectClass?函數(shù),用于提供本組件的組件信息。而在?DllGetObjectClass?中,是以類廠的方式獲取組件對象的。
類廠,顧名思義,就是COM類的工廠。如果對C++比較熟悉的話,應(yīng)該會知道設(shè)計模式中的工廠設(shè)計模式,其實這個類廠的概念就和工廠設(shè)計模式很相似。確切的說,類廠應(yīng)該成為“對象廠”,因為類廠是COM對象的生產(chǎn)基地,COM庫通過類廠創(chuàng)建COM對象;COM規(guī)定,每一個COM類,對應(yīng)的都要有一個類廠專門用于該COM類的對象的創(chuàng)建工作。
如果一個組件程序?qū)崿F(xiàn)了多個COM對象類,則相應(yīng)的有多個類廠。所以,上述關(guān)于字典組件的結(jié)構(gòu)、和多個類廠的結(jié)構(gòu)就如下所示:
1.5?COM庫
COM除了定義了組件程序和客戶程序交互的規(guī)范以外,它也提供了COM的實現(xiàn)部分即COM庫,使得這些規(guī)范能夠真正地應(yīng)用起來。并且COM庫也充當(dāng)了組件程序和客戶程序之間的橋梁,尤其是在組件對象的創(chuàng)建過程中,以及在對象管理、內(nèi)存管理和一些標(biāo)準(zhǔn)化操作方面起著重要的作用。
COM庫的一些常用函數(shù):
客戶程序調(diào)用COM庫創(chuàng)建組件對象的順序圖:
1.6?COM實現(xiàn)過程
COM客戶程序、COM庫、COM組件程序三者之間的協(xié)作過程
1.7?QTActiveX介紹
Qt提供了QtActiveX模塊來支持微軟ActiveX的開發(fā),Qt的ActiveX和COM的開發(fā)支持兩種方式:
支持將已有的COM或者ActiveX空間引入到Qt的應(yīng)用程序中
支持將Qt應(yīng)用程序或者Qt的對象導(dǎo)出成COM對象或者ActiveX控件供他人使用
具體來說,Qt是通過ActiveXQt框架中的兩個模塊來支持上述所說的兩種方式的:
使用QAxContainer模塊,通過QAxObject和QAxWidget分別支持COM對象和ActiveX控件的開發(fā),可以通過這兩個對象將外部的COM或者ActiveX組件接入到Qt應(yīng)用程序
使用QAxServer模塊,通過QAxAggregated、QAxBindable和QAxFactory類,通過了進(jìn)程內(nèi)和可執(zhí)行程序exe兩種方式的COM?Server模式,用來將Qt寫的內(nèi)容導(dǎo)出為COM或者ActiveX供他人使用。
二、基于VS+QT開發(fā)Com組件
Qt的windows商業(yè)版本提供了ActiveQt這個framework,使用這個組件我們可以在Qt中使用ActiveX控件,并且也開發(fā)基于Qt的ActiveX控件。
開源版本是沒有的,需要依賴于VS的QT插件來做開發(fā)。
2.1 環(huán)境配置
2.1.1?VS+QT+vsaddin插件安裝
操作參考:
QT - QT中配置MSVC編譯環(huán)境 以及 VS中配置QT開發(fā)環(huán)境_qt msvc-CSDN博客
本次最終采用QT6.7?+?VS2022版本。
2.1.2?安裝相關(guān)問題
1.QT安裝速度提升,避免各種網(wǎng)絡(luò)超時報錯:
安裝QT時,更換鏡像源,以帶參數(shù)的方式啟動:
.\qt-unified-windows-x64-4.4.2-online --mirror https://mirrors.tuna.tsinghua.edu.cn/qt
2.VS、QT、MSVC、qtaddin版本對應(yīng)問題
下載qtaddin插件,與對應(yīng)VS20xx版本對應(yīng)即可。
QT5.12.12不支持MSVC2019,最高支持到MSVC2017
QT5.15.2可支持到MSVC2019,但是當(dāng)前沒有離線包的版本,在線安裝也不支持;
QT6.x可支持到MSVC2022
MSVC20xx?一般要與對應(yīng)的VS20xx相對應(yīng)(參考的兩篇文章分別都是對應(yīng)的)
因此QT所支持的MSVC版本,一般需要跟VS20xx對應(yīng)起來。
網(wǎng)上成功的:
QT5.15.2?+?MSVC?2019?+?VS2019
QT5.14.2?+?MSVC?2017?+?VS2017?
自測:
QT6.7?+?MSVC2019?+?VS2019??,新建activex項目,點擊生成各種報錯,未找到有效解決方案;
QT5.14.2?+?MSVC2017?+?VS2017,但VS?2017的winform項目,看不到生成的com組件……
QT5.14.2?+?MSVC2017?+?VS2017(負(fù)責(zé)生成COM)?+?VS2022(C#負(fù)責(zé)調(diào)用com),預(yù)覽界面可以看到組件UI,實際運行顯示不了;并且VS2017生成com有不穩(wěn)定的情況,后續(xù)編譯不了了……
最終測試版本成功:
QT6.7?+?MSVC2019?+?VS2022?+?QTaddin3.2
注意點:先用IE模式,用html測試生成的Activex控件可用,隨后再用winform項目做測試,會好一些。
??需要使用管理員權(quán)限打開VS202軟件。
安裝QT時,ActiveQT組件一定要安裝,不然會出現(xiàn)項目找不到active相關(guān)頭文件的問題:
要修改已有的qt組件,運行QT安裝目錄下的工具即可:
MaintenanceTool.exe
VS2019 + Qt5.12 配置完成后,無法打開 Qt 源文件解決方案(非常實用)_無法打開qbuttongroup源文件-CSDN博客
2.2?COM(ActiveX)組件開發(fā)
QT - QT中的COM編程(dll進(jìn)程內(nèi)組件形式)_qt com組件-CSDN博客
2.2.1?實際代碼
ActiveQtServer1.h
#pragma once#include <QtWidgets/QWidget>
#include <ActiveQt/QAxBindable>#include "ui_ActiveQtServer1.h"class ActiveQtServer1 : public QWidget, public QAxBindable
{Q_OBJECTpublic:ActiveQtServer1(QWidget *parent = nullptr);public slots://定義兩個槽函數(shù),便于外部調(diào)用QString getVersion();QString getCurrentTime();private:Ui::ActiveQtServer1Class ui;
};
ActiveQtServer1.cpp
#include "ActiveQtServer1.h"
#include <ActiveQt/QAxFactory>ActiveQtServer1::ActiveQtServer1(QWidget *parent): QWidget(parent)
{ui.setupUi(this);
}
QAXFACTORY_DEFAULT(ActiveQtServer1,"{c5e4017e-73a4-47c2-ad5d-aba20c13a6ba}","{4c7d8024-69c9-4377-8a73-f163a00ad8d8}","{c46481e5-2702-476c-9cb2-e8dca9a23a47}","{484c7403-d8fa-4d7d-ac12-b75f20d6e60b}","{a3dd71cf-f57e-49ef-a6c3-939b4d2e7339}"
)
QString ActiveQtServer1::getVersion() {return "0.0.1";
}
QString ActiveQtServer1::getCurrentTime() {return ui.calendarWidget->selectedDate().toString();
}
2.2.2?生成dll
需要以管理員模式運行VS,才能夠正常生成和注冊:
2.2.3?發(fā)布(需要通過windeploy發(fā)布依賴的文件)
D:\Qt\Qt5.12.12\5.12.12\winrt_armv7_msvc2017\bin\windeployqt.exe .\ActiveQtServer1.dll
2.2.3?IE模式?Html測試
從注冊表查詢classid
編寫html文件,替換classid,保存到本地(可以任一目錄)
<html>
<head>
<title>activeQtDemo</title>
</head>
<body><object id="233432" width="80%" height="80%"classid="CLSID:869BDCDE-E935-432D-AC52-F66C8F1D27DD"> <PARAM NAME="_Version" VALUE="65536"><!-- 以下為入坑了 --><!-- classid="2F12BFB8-137D-4DC2-9A93-634EFE5A6DFC"> 1D991CF8-6F9D-4574-9507-B526D699F4321D991CF8-6F9D-4574-9507-B526D699F432--> [Object not available! Did you forget to build and register the server?]</object>
</body>
</html>
edge瀏覽器配置白名單,支持IE模式(需要支持Activex的瀏覽器)
通過IE瀏覽器打開:
點擊允許加載插件
2.2.4?更新Com組件:重新生成,*.dll無法打開的問題
查看占用的進(jìn)程:
把dllhost.exe對應(yīng)的進(jìn)程kill掉:
devenv.exe 對應(yīng)的是VS winform調(diào)用方,關(guān)掉該工程即可。
三、QT?QtWidgetApp調(diào)用COM
3.1 操作參考文章? ? ? ??
Qt調(diào)用Com組件--QT調(diào)用COM組件DLL(dumpCPP工具)_qt dumpcpp dll-CSDN博客
3.2?實際代碼
main.cpp
#include <QApplication>
#include <QAxObject>
#include <QDebug>
#include <QFile>int main(int argc, char *argv[])
{QApplication a(argc, argv);QAxObject *mpAxObj;mpAxObj = new QAxObject();//指定調(diào)用的COM組件類ID(clsid\ClassID),這個ID要填正確,就是前面宏定義的 ClassID.mpAxObj->setControl("{c5e4017e-73a4-47c2-ad5d-aba20c13a6ba}");//導(dǎo)出支持調(diào)用的函數(shù)接口QString DOC = mpAxObj->generateDocumentation();QFile outFile("com_function.html");outFile.open(QIODevice ::ReadWrite|QIODevice ::Text);QTextStream TS(&outFile);TS<<DOC<<endl;//調(diào)用COM組件函數(shù)接口: 顯示界面mpAxObj->dynamicCall("show()");//調(diào)用COM組件函數(shù)接口:獲取版本QString result=mpAxObj->dynamicCall("getVersion()").toString();qDebug()<<"插件的版本號:"<<result;//調(diào)用COM組件函數(shù)接口:獲取當(dāng)前時間QString result2=mpAxObj->dynamicCall("getCurrentTime()").toString();qDebug()<<"當(dāng)前時間:"<<result2;return a.exec();
}
四、VS?winform調(diào)用COM
4.1?winform工程引用com組件
操作參考:
C#-winform調(diào)用COM組件(COM組件由Qt開發(fā))-云社區(qū)-華為云
Qt開發(fā)Activex筆記(三):C#調(diào)用Qt開發(fā)的Activex控件_qt開發(fā)ocx給c#-CSDN博客
4.2?修改生成的目標(biāo)平臺為x64
4.3?運行最終效果
4.4?遇到的問題:
4.4.1?點擊運行后,報錯沒有注冊類
System.Runtime.InteropServices.COMException
??HResult=0x80040154
??Message=沒有注冊類?(異常來自?HRESULT:0x80040154?(REGDB_E_CLASSNOTREG))
??Source=System.Windows.Forms
??StackTrace:
???at?System.Windows.Forms.UnsafeNativeMethods.CoCreateInstance(Guid&?clsid,?Object?punkOuter,?Int32?context,?Guid&?iid)
???at?System.Windows.Forms.AxHost.CreateWithLicense(String?license,?Guid?clsid)
???at?System.Windows.Forms.AxHost.CreateInstanceCore(Guid?clsid)
???at?System.Windows.Forms.AxHost.CreateInstance()
???at?System.Windows.Forms.AxHost.GetOcxCreate()
???at?System.Windows.Forms.AxHost.TransitionUpTo(Int32?state)
???at?System.Windows.Forms.AxHost.CreateHandle()
???at?System.Windows.Forms.Control.CreateControl(Boolean?fIgnoreVisible)
???at?System.Windows.Forms.Control.CreateControl(Boolean?fIgnoreVisible)
???at?System.Windows.Forms.AxHost.EndInit()
???at?WindowsFormsApp4.Form1.InitializeComponent()?in?D:\VisionProject\VSWorkSpace\WinformWS\WindowsFormsApp4\WindowsFormsApp4\Form1.Designer.cs:line?64
???at?WindowsFormsApp4.Form1..ctor()?in?D:\VisionProject\VSWorkSpace\WinformWS\WindowsFormsApp4\WindowsFormsApp4\Form1.cs:line?17
???at?WindowsFormsApp4.Program.Main()?in?D:\VisionProject\VSWorkSpace\WinformWS\WindowsFormsApp4\WindowsFormsApp4\Program.cs:line?19
項目屬性,生成的目標(biāo)平臺修改為x64。
4.4.2?控件已經(jīng)成功添加到工具箱中,但未在活動設(shè)計器中啟用
問題描述:Visual?studio?2022?添加com組件到工具箱錯誤提示:
下列控件已經(jīng)成功添加到工具箱中,但未在活動設(shè)計器中啟用?,請確認(rèn)要添加的控件能夠兼容當(dāng)前設(shè)計器和.net?framework?版本。
修改方法:
要選擇上面這個Windows窗體應(yīng)用(.NET?Framework)
【W(wǎng)indows?窗體應(yīng)用】的窗體屬性中還有其他信息,目標(biāo)框架:.NET?Core?3.1
而【W(wǎng)indows?窗體應(yīng)用(.NET?Framework)】,其框架則是.NET?Framework
這個.NET?Core與?.NET?Framework是完全不一樣的東西:
- .NET?framework框架開發(fā)出來的應(yīng)用只能在windows上運行。
- .netcore?是開源的,開發(fā)出來的應(yīng)用可以跨平臺運行,比如運行在MAC,Linux上?。
而我們添加的COM組件,實際上是只應(yīng)用于windows環(huán)境的技術(shù),在一個非windows?的底層技術(shù)以及上層環(huán)境肯定就是不行的了。
4.4.3?引入控件報錯
1.在工具箱中,拖入控件到UI中,會彈窗報錯:
直接重新生成項目,也會報錯:
生成的dll確實是64位的:
2.修改為x64平臺(上述第二章的qt?com?dll也是基于x64編譯的)后,編譯正常,且AxActiveQTServer2Lib不再報錯
五、最終代碼demo
https://download.csdn.net/download/u011490813/89246081https://download.csdn.net/download/u011490813/89246081
參考資料
COM簡介
COM - COM的簡單介紹_com組件結(jié)構(gòu)-CSDN博客
windeployqt打包Qt應(yīng)用程序(Com只注冊了,還不夠,需要通過windeploy發(fā)布依賴的文件):
windeployqt打包Qt應(yīng)用程序_qt windeployqt 打包-CSDN博客
Qt的進(jìn)程間通信,以Active服務(wù)器的形式,手把手教你VS上進(jìn)行Qt的COM、ActivedQt?Server的開發(fā),比保姆還保姆
https://www.cnblogs.com/Leventure/p/16971934.html
VS+QT插件創(chuàng)建qt 的ActiveQT Server工程踩過的坑_qt activeqt server-CSDN博客