




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、最新 精品 Word 欢迎下载 可修改转:使用P/Invoke来开发用于与串行设备通讯的.NET基类2022/08/13/214338.html?Pending=true#Post本文相关代码下载:NetSerialComm.exe (89KB) 导引:在.NET环境下编写与RS252串口通信的应用程序的唯一方法,就是引用过时了的并且有点限制的MSComm ActiveX控件。这篇文章介绍了用C#安全代码编写一个多线程的,且时尚的与RS232通讯的基础类库。这个类库使用平台调用服务(即Platform Invocation Services)来与Win32 API直接交互。程序员可以通过继承在
2、任何.NET语言下使用这个类库;这个文章还探讨了一些用C#和Visual Basic .NET写的示例程序。 微软.NET框架类库(FCL)提供了相当全面广泛的功能来替代在Win32API编程下原有的功能,特别是C#与Visual Basic.NET语言的可互访性。尽管如此,RS232串口通讯是.NET框架类库是明显未被涉及的方面之一。从而很正常的,很多人就把这些接口当成了遗弃物。目前,你还是通过软件层与串行调制解调器进行通讯,比如TAPI与PPP。其它从前使用这些接口的设备现在正在向USB接口移植。不过,一些专业的RS232设备的驱动程序仍然有通讯的需要,比如GPS接收器,barcode a
3、nd swipe card readers,可编程控制器和一些可预见的程序员将来继续使用的设备。(关于RS232接口的规格信息,可以参看Hardware Specs.) 平台调用服务 (P/Invoke)是能够使用托管的CLR代码调用非托管DLLs的.NET技术,包括那些实现Win32 API的DLLs。在这篇文章里,我将用C#把与RS232通信的API封装到CLR托管的代码中去。生成的基类库将使用.NET语言开发特定设备的驱动变得相对容易。完整的代码和示例可以从这篇文章顶部的链接中下载到。 设计原理在把Win32串口通讯功能封装到托管类的时候,这里至少有四种实现方式让你选择:1.使用P/In
4、voke把API函数、常数、结构作为静态成员封装到托管类中。虽然我在里面使用了这种方法,但没有这个类暴露给程序员。2.写一个流的处理角色。这是.NET框架对文件、控制台、网络通讯的一般地、可扩充的提取。咋一看,这个很有吸引力,但近距离审视的时候,这个更适用于传统的调制解调器,而不适合于现在基于命令响应语法的设备。3.做一个直接替换MSComm OLE Control Extension(OCX)控件的替代品。换句话说,新建一个封装了API文件处理并提供许多基本的方法和事件(比如,Open,Close,Read,Write等等)。你可以在应用程序类里初始化这个类库里的一个对象来达到重用的目的那就
5、是说,通过COM-style的集合。4.写一个应用程序需要继承的基类。这是一个充分体现.NET优点运行时对不同语言继承的无关性的面向对象的方法。这些基础的方法被继承进应用程序对象中,虚方法将被使用,而不是使用事件。这个应用程序对象将巧妙地提供一个适用于真实RS232设备公共接口(比如,一个GPS接收器驱动可能拥有一些关于经度和纬度的公共属性)。 我将采用第四种方法。这个类库将会包含两个被生明为抽象类的基类(它们不能被示例化),但我将使用继承来把它们作为实现某些特定应用的基类。图1表明了这种继承的层次关系。 图1继承层次第一个库类,CommBase,对数据格式化、更容易开启与关闭通讯接口、发送与
6、接收字节数据、输入与输出交互的控制等都不提供任何实现。 第二个库类,CommLine,继承自CommBase,并且做了两个实现:接收与发送的字节是ASCII编码并使用一个保留的ASCII控制编码来标记数据行数的可变长度,能够接收与传输字符串。当然,这个模型是可扩展的;比如,你可以编写可选的Unicode版的CommLine。 使用基类 两个应用程序的例子,BaseTerm和LineTerm,可以下载的到。他们可以用于与任何串口设备进行一般用途的交流,包括调制解调器。我先从一个用户的观点来简单的看一下BaseTerm,然后再更细致地分析一个LineTerm的源代码。 图2 BaseTerm Ba
7、seTerm(参看图2)是一个完全基于WindowsForm的应用程序,它继承自CommBase并提供一个基于字节的可调节终端。点击Settings按纽可以打开了一个对话框来对通讯设置的全部参数进行设置(参看图3)。这个窗口上菜单可以帮助用户以结构化的XML文件来保存或加载这些设置参数,也保存大量用于普通流控制模式的设置。提示解释了各个设置项的用法。一旦保存为XML,当你再次启动这个程序的时候,你可以在命令行格式下设定这个文件。一旦连上线,打出的字符就可以立即被传送到远端设备中支。键盘上的按键发送合适的ASCII字节,如果你想发送键盘上没有的编码,你可以使用“escape facility”.
8、 图3 Comm设置 可以通过输入符号来结束这个“escape”,它可以把一个合适的ASCII码立即发送过去。当需要传输 0);62 63 64 6566 catch (Exception e)67 68 if (uMask != IntPtr.Zero)69 Marshal.FreeHGlobal(uMask);7071 if (unmanagedOv != IntPtr.Zero)72 Marshal.FreeHGlobal(unmanagedOv);7374 if (!(e is ThreadAbortException)75 76 rxException = e;77 OnRxExce
9、ption(e);78 79 8081图6接收线程的简单版 图6是一个简化版的ReceiveThread。SetCommMask表明当一个新字节到达的时候我希望被通知到。WaitCommEvent可能返回true,在这种情况下已经有一个或更多的字节处于队列中。如果返回附带错误码的ERROR_IO_PENDING,我会挂起这个线程直到有一个字节到达。被传递给WaitCommEvent的OVERLAPPED结构包含一个到AutoResetEvent的句柄,它被当作有字节到达的信号。当我执行AutoResetEvent的WaitOne方法时,执行被挂起直到这个事件被触发。不管WaitCommEven
10、t立即返回true还是信号不久完成,eventMask变量有一位用于标识SetCommMask正常被引发所需的条件(在实际代码中,我也描述了一些其它的家务管理的条件)。注意我同样为eventMask使用了手动排列技巧就像先前在OVERLAPPED中描述的一样。我猜测这也许是没必要的,也许自动排列也可以,但在文档中没有精确的描述,因为这样做更安全一些总比遗憾要好的多。用托管变量替换无序的指针作为引用参数好像有用,但那可能只是因为内存没有被重用而已。因为依赖于时间,不只是一个字符要排队,因此每次使用ReadFile来排出一个字节,重复使用,并每次使用一个字符来调用虚方法OnRxChar。当我接收到
11、ERROR_IO_PENDING错误编码时,我就调用CancelIo方法,从而避免等在这里;我想在WaitCommEvent循环等待。在使用工作线程,错误处理和异常需要好好地处理。任何发生在ReceiveThread里的未处理异常,及任何调用它的虚方法,以及由以上调用的方法或引发的事件将会级联下去并由catch子句捕获处理。如果产生的异常不是ThreadAbortException异常,那么它就存储在CommBase类作为一个私有成员,并且这个线程将被中止。下次在主线程里程序代码将调用一个方法然后再引发一个异常,端口就会关闭。这充分利用了内置异常结构的优点,当引发了一个一般性“接收线程错误”异
12、常时,它里面就包含了存储在里面的原线程。ThrowException是继承类里的提供的一个辅助方法;它通过它所调用的线程来调节它的行为。 配置和其它细节我从CommBaseSettings辅助类对象读取所有配置。Open方法通过调用虚方法CommSettings来获得这个对象,并把所有的置拷贝到API结构中去。CommBaseSettings类还提供了用于保存和覆盖配置到XML配置文件的方法,及大量地应用这些一般性配置。我利用窗口上的智能帮助提示为配置提供了帮助文档。因为继承类提供了自己的继承自CommBaseSettings类配置类,这种配置提供了一种可扩展性基础配置结构。通过这种方式我继承
13、了CommLineSettings类,为CommLine类提供了额外的配置。共有三个API方法用于配置通讯协议:SetupComm,SetCommState及SetCommTimeouts三个方法。SetupComm方法需要接收缓冲的大小及传输队列。正常情况下你可以把这些设置为0或根据操作系统决定,但对一些文件传输和简单应用程序,可调节的所需的大小是值得的。系统不一定能满足这种需要;在Windowns XP里,这就好像动态传输队列,并仅接收队列的长度是必须的。SetCommState方法在一个称为设备控制块(DCB)的结构里提供了波特传输率、字格式及握手设置等配置信息。SetCommTimeo
14、uts在COMMTIMEOUTS结构里提供了三个接收和两个传输超时值。接收超时值对我所选择的设计没有用处,因为单个字符是异步处理的。如果接收超时时间是必须的,那它必须在一个高的水平上实现(比如,CommLine为它的传输方法提供了一个超时时间)。传输超时时间很有用,特别对于多字节传输。Send方法里的字节的数量由sendTimeoutMultiplier方法啬,然后sendTimeoutConstant被附加到这并提供以微秒为单位的总时间。一旦端口被打开并被寝化里,Open方法调用了一个AfterOpen虚方法,它将被重写来检查到远程设置的连接状态且尽可能地配置它。如果这个返回false,端口
15、将再次被关闭且Open方法自己将返回false.如果需要的话,还有一个BeforeClose方法来关闭远程设备。CommB ase还提供了两个重载版本的Send方法,一个提供了一个字节数组为参数另一个提供了另一个单独的字节作为参数。CommLine提供了第三个版本的Send方法,用字符串作为参数。在进行合适的数据转化后,所有这些最终使用字节数组版本的方法。还提供了一个以单个字节为参数的SendImmediate方法。它将在传输队列里将比其它字节前面传输这个字节,并且对实现自定义流控制模式是非常有用的。它还提供了一些用于传输请求、数据终端准备输出插脚及把TX输出到暂停条件。输入插脚Clear-t
16、o-Send(CTS),Data Set Ready(DSR),Received Line Signal Detector(RLSD),以及Ring Detect-可以使用GetModemStatus来直接读,当任意输入或输出插脚改变状态时,虚方法OnStatusChange将被调用。GetQueuesStatus方法将返回一个QueueStatus对象,并给出传输的大小、内容、接收队列以及如果必要的话,流控制条件现在是块传输。结论我使用Platform Invocation Services来填补了FCL功能上的一个空白。但这表明确是一个不平凡但非常可行的锻炼。所存在的绝对多数困难在于还没有用于P/Invoke的完全的工具及文档支持。最后,我做一下总结。作为这个项目的一部分,并在我考虑ManualResetEvent和AutoResetEvent框架类已经封装了所有我需要的功能之前,我写了和测试了所有的对于Win32 Waitable Events API的完全封装。记住:当时候,你仅需要把你所有的时间都花在写全新的类而不是凑合使用已经存在的你所需的东西。在从新改造之前先检查一下你的硬盘。基于这个原理,我希望这些基类能帮助其它的程序员把RS232设备通讯带入.NET世界。
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 赊销额度协议书
- 楼栋长志愿服务协议书
- 背书转让协议书
- 变更孩子抚养权协议书
- 综合还款协议书
- 考研录取协议书
- 房屋代买卖合同协议书
- 酒场休战协议书
- 道路绿化协议书
- 米油回收协议书
- 细致解读wps考试内容的试题及答案
- 2025届高考语文写作押题范文8篇及分析
- 纸张印刷与印后加工考核试卷
- 2025年汽车维修工职业资格考试重点试题及答案
- 2024年四川西华师范大学招聘辅导员真题
- 2025年安全生产考试题库:安全生产隐患排查治理安全生产责任制试题
- 2025年高考英语语法填空热点语法填空热点话题06(学生版+解析)
- 湛江漓源农牧科技有限公司年产36万吨饲料项目环境影响报告表
- 随班就读试题及答案
- 1.1细胞是生命活动的基本单位课件高一上学期生物人教版(2019)必修1
- 2024年福建省长乐市事业单位公开招聘医疗卫生岗笔试题带答案
评论
0/150
提交评论