來新公司學習接手新項目,拿到代碼打開解決方案看到里面竟然有40幾個工程,有點吃驚。具體看代碼也有很多之前沒見過的寫法,上了幾天火。
有件事就沒太搞明白,按照文檔的說法上層很多軟件都要調用IO服務器,但看程序安裝目錄,IO服務器其實是一個exe程序,按照我之前的印象,能被別的程序調用的也得是動態庫、靜態庫或者服務。實在想不通exe程序怎么作為接口被別的程序調用的。
結果昨天研究了一天,想通了,這個IO服務器其實就是COM組件。
按照網上的說法:COM component(COM組件)是微軟公司為了計算機工業的軟件生產更加符合人類的行為方式開發的一種新的軟件開發技術。在COM構架下,人們可以開發出各種各樣的功能專一的組件,然后將它們按照需要組合起來,構成復雜的應用系統。由此帶來的好處是多方面的:可以將系統中的組件用新的替換掉,以便隨時進行系統的升級和定制;可以在多個應用系統中重復利用同一個組件;可以方便的將應用系統擴展到網絡環境下;COM與語言,平台無關的特性使所有的程序員均可充分發揮自己的才智與專長編寫組件模塊。
COM組件可以是dll或者exe或者服務的形式。
按照這個思路,代碼就看懂了不少,之所以解決方案里有那么多工程,也不過是因為划分了很多動態庫和COM組件。
又花了些時間,寫了個小程序來實現最簡單的exe形式COM組件的生成與調用,如下:
首先建立一個ALT工程:
在類視圖里,為工程添加ALT的類,和接口:
這里定義了類,和對應的接口(Interface),注意ProgID要寫,待會程序調用com接口時,要通過ProgID找com組件
之后項目目錄如下,在.idl文件里有com接口(interface),里面還定義了com組件的id等等不贅述了,實現類在ATLTest.cpp里,其對應關系都是vs自動搭建的。
接下來還是在類視圖里具體添加方法(接口和實現):
方法內部寫程序,邏輯是兩數求和:
STDMETHODIMP CCATLTest::ATLTestFunc0(SHORT num1, SHORT num2, SCODE* pRetNum) { *pRetNum = num1 + num2; return S_OK; }
然后編譯會出錯,那是因為執行com組件注冊命令時候,缺乏管理員權限,
重新啟動vs,以管理員權限運行即可。
接下來建一個mfc項目,這不是今天主題就不贅述了,
在界面上簡單填個按鈕和輸入框,寫個兩數求和的圖形界面demo,
具體的求和的方法要調用com組件。
mfc項目里添加com接口,在類向導里選擇添加類,選atl,選TypeLib中的MFC類:
之后可以選取前面定義的Lib:
加入COM接口文件后,就可以調用了,注意我下面的寫法:
void CATLMfcClientDlg::OnBnClickedGetRetButton() { CoInitialize(NULL); CATLTest myCom; if (!myCom.CreateDispatch(_T("ATLTest.math.1"))) { MessageBox(L"組件注冊失敗"); return; } CString strNum1,strNum2; // 獲取用戶輸入的數字 this->numInput1.GetWindowTextW(strNum1); this->numInput2.GetWindowTextW(strNum2); // 調用COM接口,兩數求和 short ret = myCom.ATLTestFunc0(_wtoi(strNum1),_wtoi(strNum2)); WCHAR buf[50]; _itow(ret,buf,10); // 顯示結果 this->numRet.SetWindowTextW(buf); CoUninitialize(); return; }
運行效果:
上面有說的簡略的地方,具體可以看我上傳git的源碼:
https://github.com/SonnAdolf/MyAtlExeComDemo
額外內容:
動態鏈接庫和COM組件的區別
1動態鏈接庫的表現形式只能是dll[變態該名的除外], COM組件的表現形式可以是dll也可以是exe。
注:其實字體、驅動等也算是動態鏈接庫的一種,這里略去...
2 動態鏈接庫的生成和編譯器及系統相關,在Windows/Linux下系統,需要分別編譯才能使用。
COM組件是二進制編碼,在Windows和Linux下可以直接使用,不需要重新編譯。
3 COM組件是按照COM規范實現的dll或者exe;動態鏈接庫是一個可以導出函數的函數集合。
4 動態鏈接庫只能在本機被調用,COM組件支持分布式使用。