以文本方式查看主题 - 计算机科学论坛 (http://bbs.xml.org.cn/index.asp) -- 『 C/C++编程思想 』 (http://bbs.xml.org.cn/list.asp?boardid=61) ---- VC实现串行通信的动态链接库(DLL) (http://bbs.xml.org.cn/dispbbs.asp?boardid=61&rootid=&id=27021) |
-- 作者:卷积内核 -- 发布时间:2/7/2006 10:44:00 AM -- VC实现串行通信的动态链接库(DLL) 本文是作者根据工程中的实践经验,以实例方式介绍了用VC++编写DLL实现串行通信的方法,并给出了用其它语言调用该DLL的范例。 一、引言 串行通讯口作为计算机与外部串行设备进行数据传输的重要端口,因其使用简单、方便,在业界的各种计算机系统中得到了广泛的应用。由于应用范围很广,软件人员在串行通信方面也积累了丰富的编程经验。关于串行通信的文章不时见于报端,并且还有一些专门讨论 虽然关于串口编程的资料很多,但由于工程上需求多种多样,需要根据不同的条件对串口进行灵活控制,在实际应用中,常用的方法有: (1)用汇编或标准通讯函数,往指定端口直接读写数据; (2)利用Visual Studio提供的MSComm控件; (3)使用Windows提供的API函数。 本文是作者在工程实践中根据实际需要,在Visual C++环境中,直接使用Windows提供的API函数实现一个串行通信动态链接库(DLL)的完整实例,实例既给出了DLL函数的编写方法,又包括一份用其它编程工具(VB)对此DLL进行声明及调用的范例。为了使读者一目了然,并减少代码量,本例作了简化,但完全可以运行。希望对需要进行串行通信编程的同行以及需要学习编写DLL的编程爱好者提供一点帮助。 二、准备知识 1、DLL基本概念 动态链接库(DLL) 是Windows操作系统的基础,Windows API中的所有函数就是包含在DLL中,它有众多优点,如:简化软件项目管理以便分工合作,有助于节省内存,便于资源共享并且可以用多种语言来编写。 用VC++ 编写动态链接有以下四种类型:Win32 DLL、MFC常规DLL(动态链接MFC)、MFC常规DLL(静态链接MFC)、MFC扩展DLL等,关于它们之间的区别,在此不一一介绍,可参阅相关文档。本程序的编写为Win32 DLL。 2、串行通信基础知识 在Windows系统,系统通过一个叫DCB(Device Control Block)的结构对串行口进行配置,通过Windows API GetCommState函数可以得到串行通讯口的状态信息,使用SetCommState函数可以对串行通讯口进行设置,实现串行通信一般需按以下四步进行: (1) 打开串口。由于串口是独占性资源,因此应用程序打开串口后,别的应用程序就不能再打开此串口了。 (2)配置串口。利用GetCommState函数获取串口当前配置,根据需要更改DCB 结构中的参数,然后用SetCommState函数设置串口通讯参数。 (3)数据传送。在串口上进行数据发送接收,并根据需要进行校验,触发一些事件等等。这个串口通讯DLL的目的就是收发数据。 (4)关闭串口。不需要此串口时,关闭串口,供其它的应用程序使用。 3、CALLBACK函数 在微软的官方手册中是这样定义CALLBACK函数的:“CALLBACK函数是由应用程序定义而由操作系统调用的函数”。在我们编写DLL时,就是由应用程序定义而由此DLL执行的函数,这一机制在被调用者(DLL)和调用者(应用程序)之间进行信息传递是非常有用的。这一特性,让初学者较难理解,但是它却是编写串行通信程序者的福音,正是由于使用这一特性,才可很方便地在动态链接库中实现MSComm控件中的OnComm 事件,并且可根据需要进行灵活控制。 三、串行通讯动态链接库的编写 以上将一些基础知识进行了适当的介绍,下面再着重讨论怎样编写一个动态链接库(DLL)。 1、从VC++ 6.0的File菜单中选择New命令,并在列表框中选择Win32 Dynamic-Link Library项,创建一个工程。 2、往工程中添加头文件 根据需要,我们在头文件中定义此DLL提供给外部调用的五个输出函数,其定义方法如下: //com.h DLL的源代码模块需要包含该头文件,若要编写调用该动态链接库函数的C/C++应用程序,也需要包含此头文件。另外,你会发现,MyComDll中包含了extern "C"链接指示符,这是因为在用C++编写动态链接库时,通常在经C++编译器编译后,其函数名称会改变,如 3、往工程中添加C/C++源代码模块 在C++源代码模块中,首先应包含如下头文件,及定义相关变量: #include <windows.h> 然后就定义本动态链接库的五个输出函数: (1)ComOpen(int port) 此函数用来打开指定的串行通讯口,其参数port即为通讯口号。打开端口后,通过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在特定的时刻(本程序是当串行端口接收到有效数据时)通过内部的指针函数,调用外部的应用 //com.cpp 4、往工程中添加模块定义文件 模块定义文件(module-definition)文件是以.def为扩展名的文本文件,为了能被其他开发工具如Visual Basic、Delphi等使用,创建的DLL文件必须要有模块定义文件,否则在应用程序调用ComOpen时会出现“Can’t find DLL entry point ComOpen in Comdll.dll”的 LIBRARY COMDLL 四、动态链接库函数的VB 调用示范 1、VB测试程序 以下程序示范了在VB中如何调用由VC++编写的动态链接库中的函数。因为动态链接库中使用了回调函数,在VB代码中必须将回调函数放到标准的.BAS模块中,不可放在窗体模块中,也不能将其附加到类模块中。CALLBACK函数只是触发同一工程中一个窗体上的定时器控件,对串口数据进行采集,其定义如下: Sub CallBackFunc(ByVal port As Long) Form1.Timer1.Interval = 1 在标准的.BAS模块中,还需定义该DLL函数的调用方式,具体如下: Option Explicit 在窗体程序中,当打开串口时,调用DLL的SetCallBack函数设置回调函数,调用方式如下: SetCallBack (comport, AddressOf CallBackFunc); 关键字AddressOf是将CallBackFunc的函数地址传递给DLL中的指针函数void (CALLBACK* infunc) (int port)。 2、调试方法 串行通讯的调试相对来说是比较麻烦,在实践中,可以在同一台具有两个串行通讯口的机器上进行调试,只需要将两个串口的RXD和TXD交叉连接,并将5脚对等连接,就可以进行调试了;当然,也可用一个串口进行调试,只需将同一串口的2、3连接。 在调试过程中,需提醒读者注意的一点是:动态链接库与执行文件应在同一目录下,否则出现找不到动态链接库的问题;由于Windows操作系统本身的原因,在对动态链接库的第一次使用时,须将其拷贝至系统安装目录的system32子目录中才能避免上述问题。 五、结束语 此DLL是本人在工作中的一点经验积累,去除工程实践中的繁琐枝叶,只涉及串行通讯的关键代码,目的是展示以DLL实现串行通信的方法,希望本文能对读者起到抛砖引玉的作用。 |
W 3 C h i n a ( since 2003 ) 旗 下 站 点 苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》 |
37.109ms |