用VC开发串口通信dll控件
本文利用VC編程工具,對Windows提供的API函數進行封裝,實現了一個串行通信動態鏈接庫dll的完整實例,實例既給出了DLL函數的編寫方法,又包括一份用其它編程工具(VB)對此DLL進行聲明及調用的范例。為了使大家能看得懂,本例作了簡化。希望對需要進行串行通信編程的網友及需要學習編寫DLL的編程愛好者提供一點幫助。
一、有關dll的常識
1、什么是dll
DLL是動態鏈接庫Dynamic Link Library 的簡稱, DLL是一個包含可由多個程序同時使用的代碼和數據的庫,DLL不是可執行文件。動態鏈接提供了一種方法,使進程可以調用不屬于其可執行代碼的函數。函數的可執行代碼位于一個 DLL 中,該 DLL 包含一個或多個已被編譯、鏈接并與使用它們的進程分開存儲的函數。DLL 還有助于共享數據和資源。多個應用程序可同時訪問內存中單個DLL 副本的內容。DLL 是一個包含可由多個程序同時使用的代碼和數據的庫。Windows API中的所有函數就是包含在DLL中,它有眾多優點,如:簡化軟件項目管理以便分工合作,有助于節省內存,便于資源共享并且可以用多種語言來編寫。
用VC++ 編寫動態鏈接有以下四種類型:Win32 DLL、MFC常規DLL(動態鏈接MFC)、MFC常規DLL(靜態鏈接MFC)、MFC擴展DLL等,關于它們之間的區別,在此不一一介紹,可參閱相關文檔。本程序的編寫為Win32 DLL。
如何沒有dll編寫基礎,請查閱相關文檔,進一步學習dll開發。
2、串口通信一般步驟
在Windows系統,用CreateFile函數來打開串口設備,在打開之前,應該對串口相關參數進行配置,系統通過一個叫DCB(Device Control Block)的結構對串行口進行配置,通過Windows API GetCommState函數可以得到串行通訊口的狀態信息,使用SetCommState函數可以對串行通訊口進行設置,配置好后即可打工串口,打開串口后可以通過ReadFile和WriteFile讀寫串口。實現串行通信一般需按以下四步進行:
(1) 打開串口。由于串口是獨占性資源,因此應用程序打開串口后,別的應用程序就不能再打開此串口了,所以在使用CreateFile打開串口時相關參數要注意,應使用獨點方式。
(2)配置串口。利用GetCommState函數獲取串口當前配置,根據需要更改DCB 結構中的參數,然后用SetCommState函數設置串口通訊參數。
(3)數據傳送。在串口上進行數據發送接收,并根據需要進行校驗,觸發一些事件等等。這個串口通訊DLL的目的就是收發數據。
(4)關閉串口。不需要此串口時,關閉串口,供其它的應用程序使用。
3、有關CALLBACK函數
在編寫dll時,CALLBACK函數是必不可少的。在微軟的官方手冊中是這樣定義CALLBACK函數的:“CALLBACK函數是由應用程序定義而由操作系統調用的函數”。在我們編寫DLL時,就是由應用程序定義,而調用是由我們編寫的DLL來執行,這一機制在被調用者(DLL)和調用者(應用程序)之間進行信息傳遞是非常有用的。這一特性,讓初學者較難理解,但是它卻是編寫串行通信程序者的福音,正是由于使用這一特性,才可很方便地在動態鏈接庫中實現像MSComm控件中的OnComm 事件,并且可根據需要進行靈活控制。
二、串口通信動態鏈接庫dll的編寫
下面演示了如何用VC縮寫串口通信dll過程。
1、從VC++ 6.0的File菜單中選擇New命令,并在列表框中選擇Win32 Dynamic-Link Library項,創建一個工程,如下圖所示:
2、往工程中添加頭文件
在新建一個com.h文件,里加入對外提供的函數接口,如要有5個,如下所示:
DLL的源代碼模塊需要包含該頭文件,而且用戶應用程序在使用此串口dll時也要包含com.h。另外,你會發現,MyComDll中包含了extern "C"鏈接指示符,這是因為在用C++編寫動態鏈接庫時,通常在經C++編譯器編譯后,其函數名稱會改變,如ComOpen編譯后,展現給調用者的名字是:_ComOpen@8這種形式,這樣應用程序在調用時,鏈接程序就會提示找不到指定的函數。加上extern“C”后的作用就告訴編譯器不要改變變量名或函數名。__declspec(dllimport)是告訴編譯器,應用程序將從這個DLL 模塊引入這些函數,__declspec(dllexport) 是告訴編譯器這些函數是從產生的DLL模塊輸出給別的應用程序調用。
3、往工程中添加C/C++源代碼文件
在C++源代碼模塊中,首先應包含如下頭文件,及定義相關變量:
然后實現本動態鏈接庫的五個輸出函數:
(1)ComOpen(int port)
此函數接口功能是用來打開指定的串行通訊端口,參數port即為通訊口號(不用在前面加com了)。打開端口后,通過API函數GetCommState得到該端口的配置;根據需要更改其波特率、數據位、停止位等,以及設置觸發信號事件的字符(即設置BCB的EvtChar字段);然后通過調用SetCommState設置端口。
串口打開成功后,將創建一個ComThreader線程,在ComThreader中,循環監控串行口是否收到有效數據,若收到則觸發回調函數。
(2)GetComData (LPBYTE buf)
此函數是將串口接收緩沖區中的數據放到接收緩沖區buf中。
(3)SendDataToCom(LPBYTE Cmd,int CmdLen)
此函數是將指定長度的數據發送到串行口中。其長度由于變量CmdLen指定,發送的數據即為變量Cmd中的內容。發送數據時,需要將線程ComThreader暫時掛起,以避免與接收數據的線程沖突,產生紊亂。
(4)ComClose()
此函數用來關閉已打開的串口,無參數。通過事件觸發以及WaitForSingleObject 、WaitForMultipleObjects函數,中斷線程,關閉創建的各種事件、文件,釋放相應資源,因為采用了多線程技術,因此需要特別注意主線程和子線程的相互同步。
(5)SetCallBack(int controlport,void (CALLBACK *outfunc)(int controlport))
此函數的功能是設置回調函數,controlport為指定的端口,outfunc是外部應用程序傳過來的函數指針,其主要目的是將應用程序的函數指針傳給DLL中的一個指針函數,DLL在特定的時刻(本程序是當串行端口接收到有效數據時)通過內部的指針函數,調用外部的應用 程序,從而實現“回調”功能。
4、往工程中添加模塊定義文件
模塊定義文件(module-definition)文件是以.def為擴展名的文本文件,為了能被其他開發工具如Visual Basic、Delphi等使用,創建的DLL文件必須要有模塊定義文件,否則在應用程序調用ComOpen時會出現“Can’t find DLL entry point ComOpen in Comdll.dll”錯誤提示。Exports節和extern "C"的作用一樣,告訴編譯器不要改變輸出的函數名。
四、動態鏈接庫函數的VB 調用示范
1、VB測試程序
以下程序示范了在VB中如何調用由VC++編寫的動態鏈接庫中的函數。因為動態鏈接庫中使用了回調函數,在VB代碼中必須將回調函數放到標準的.BAS模塊中,不可放在窗體模塊中,也不能將其附加到類模塊中。CALLBACK函數只是觸發同一工程中一個窗體上的定時器控件,對串口數據進行采集,其定義如下:
在標準的.BAS模塊中,還需定義該DLL函數的調用方式,具體如下:
在窗體程序中,當打開串口時,調用DLL的SetCallBack函數設置回調函數,調用方式如下:
關鍵字AddressOf是將CallBackFunc的函數地址傳遞給DLL中的指針函數void (CALLBACK* infunc) (int port)。
2、調試方法
串行通訊的調試相對來說是比較麻煩,在實踐中,可以在同一臺具有兩個串行通訊口的機器上進行調試,只需要將兩個串口的RXD和TXD交叉連接,并將5腳對等連接,就可以進行調試了;當然,也可用一個串口進行調試,只需將同一串口的2、3連接。
在調試過程中,需提醒讀者注意的一點是:動態鏈接庫與執行文件應在同一目錄下,否則出現找不到動態鏈接庫的問題;由于Windows操作系統本身的原因,在對動態鏈接庫的第一次使用時,須將其拷貝至系統安裝目錄的system32子目錄中才能避免上述問題。
總結
以上是生活随笔為你收集整理的用VC开发串口通信dll控件的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: VC基于MSCOMM控件串口通讯
- 下一篇: 开源免费的C/C++网络库(c/c++