VB 函数在串口操作模块的运用

人盡茶涼 提交于 2019-11-27 20:42:50

1.应用

      1.1RegOpenKeyEx函数涉及注册表的相关知识,先了解注册表的作用及数据结构

  •       注册表的作用

        注册表是windows操作系统中的一个核心数据库,其中存放着各种参数,直接控制着windows的启动、硬件驱动程序的装载以及一些windows应用程序的运行,从而在整个系统中起着核心作用。这些作用包括了软、硬件的相关配置和状态信息,比如注册表中保存有应用程序和资源管理器外壳的初始条件、首选项和卸载数据等,联网计算机的整个系统的设置和各种许可,文件扩展名与应用程序的关联,硬件部件的描述、状态和属性,性能记录和其他底层的系统状态信息,以及其他数据等。

       具体来说,在启动Windows时,Registry会对照已有硬件配置数据,检测新的硬件信息;系统内核从Registry中选取信息,包括要装入什么设备驱动程序,以及依什么次序装入,内核传送回它自身的信息,例如版权号等;同时设备驱动程序也向Registry传送数据,并从Registry接收装入和配置参数,一个好的设备驱动程序会告诉Registry它在使用什么系统资源,例如硬件中断或DMA通道等,另外,设备驱动程序还要报告所发现的配置数据;为应用程序或硬件的运行提供增加新的配置数据的服务。配合ini文件兼容16位Windows应用程序,当安装—个基于Windows 3.x的应用程序时,应用程序的安装程序Setup像在windows中—样创建它自己的INI文件或在win.ini和system.ini文件中创建入口;同时windows还提供了大量其他接口,允许用户修改系统配置数据,例如控制面板、设置程序等。

      如果注册表受到了破坏,轻则使windows的启动过程出现异常,重则可能会导致整个windows系统的完全瘫痪。因此正确地认识、使用,特别是及时备份以及有问题恢复注册表对windows用户来说就显得非常重要。

  •       注册表的数据结构 

       注册表由键(也叫主键或称“项”)、子键(子项)和值项构成。一个键就是分支中的一个文件夹,而子键就是这个文件夹当中的子文件夹,子键同样它也是一个键。一个值项则是一个键的当前定义,由名称、数据类型以及分配的值组成。一个键可以有一个或多个值,每个值的名称各不相同,如果一个值的名称为空,则该值为该键的默认值。 

        在注册表编辑器(regedit.exe)中,数据结构显示如下,其中,command键是open键的子键,(默认)表示该值是默认值,值名称为空,其数据类型为REG_SZ,数据值为%systemroot%/system32/notepad.exe"%1数据类型。

        注册表的数据类型主要有以下四种:显示类型(在编辑器中)数据类型说明

        REG_SZ:字符串:文本字符串

        REG_MULTI_SZ:多字符串值:含有多个文本值的字符串
        REG_BINARY:二进制数:二进制值,以十六进制显示,
        REG_DWORD:双字值;一个32位的二进制值,显示为8位的十六进制值。
        ‘以上取自百度百科.
  •      RegOpenKeyEx函数作用为打开一个指定的键.其函数原型如下:
1   LONG RegOpenKeyEx(
2   HKEY hkey,
3   LPCTSTR lpSubKey,
4   DWORD ulOption,
5   REGSAM samDesired,
6   PHKEY phkResult
7   );
  •       各参数的返回值的含义如下:

       hKey为主键值,可以取下面的一些数值:

       HKEY_CLASSES_ROOT(&H800000000)、HKEY_CURRENT_CONFIG(&H80000005)、HKEY_CURRENT_USER(&H80000001)、HKEY_LOCAL_MACHINE(&H80000002)、HKEY_USERS(&H80000003)、HKEY_PERORMANCE_DATA(WINNT操作系统)、HKEY_DYN_DATA(WIN9X操作系统)

        参数lpSubKey为一个指向以零结尾的字符串的指针,其中包括子健的名称,可以利用反斜线()分隔不同的子健名.如果字符串为空,则根据参数创建一个新的句柄.在这种情况下,并不关闭先前打开的句柄.

       ulOption保留,通常必须设置为0

       参数samDesired用来设置对键的访问的权限,可以取下面的一些值:

       KEY_CREATE_LINK 准许生成符号键
  KEY_CREATE_SUB_KEY 准许生成子键
  KEY_ENUMERATE_SUB_KEYS 准许生成枚举子键
  KEY_EXECUTE 准许进行读操作
  KEY_NOTIFY 准许更换通告
  KEY_QUERY_VALUE 准许查询子键
  KEY_ALL_ACCESS 提供完全访问,是上面数值的组合
  KEY_READ 是下面数值的组合:
  KEY_QUERY_VALUE、KEY_ENUMERATE_SUB_KEYS、KEY_NOTIFY
  KEY_SET_VALUE 准许设置子键的数值         

       参数phkResult为一个指针,用来指向打开的键的句柄。可以通过RegCloseKey函数来关闭这个句柄。

  •     RegEnumValue函数是用来枚举指定项的值

               返回值(Long)为0,表示成功。其他任何值都代表一个错误代码

               其各参数的返回值如下:

               hKey (Long),一个已打开项的句柄, 或者指定一个标准项名               

               dwlndex(Long),欲获取值的索引。注意第一个值得索引编号为零

               lpValueName(String),用于装载位于指定索引处值名的一个缓冲区

               lpcbValueName(Long),用于装载lpValueName缓冲区长度的一个变量。一旦返回,它会设为实际载入缓冲区的字符数量

               lpReserved (Long),未用;设为零

               lpType (Long),用于装载值的类型代码的变量

               lpData (Byte),用于装载值数据的一个缓冲区

               lpcbData (Long),用于装载lpData缓冲区长度的一个变量。一旦返回,它会设为实际载入缓冲区的字符数量 

  •      RegCloseKey函数关闭系统注册表中的一个项(键)   返回值:Long,零(ERROR_SUCCESS)表示成功。其他任何值都代表一个错误代码

                hKey(Long)       要关闭的项                

  •       Sleep函数做休眠功能

                 参数dwMilliseconds  为休眠时间

  •        CloseHandle函数关闭一个内核参数。       

                  其中包括文件、文件映射、进程、线程、安全和同步对象。涉及文件处理时,这个函数常与vb的close命令相似。应尽可能的使用close,因为它支持vb的差错控制。注意这个函数使用的文件句柄与vb的文件编号是完全不同的。Long类型,非零表示成功,零表示失败。会设置GetLastError

                  hObject(Long)  欲关闭的一个对象的句柄

  •        Createfile函数,这是一个全功能的例程,可打开和创建通信服务、设备及控制台

          返回值 Long,如执行成功,则返回文件句柄。INVALID_HANDLE_VALUE(-1)表示出错,会设置GetLastError。即使函数成功,但若文件存在,且指定了CREATE_ALWAYS(2) 或 OPEN_ALWAYS(4),GetLastError也会设为ERROR_ALREADY_EXISTS(183&)。

          lpFileName(String)          要打开的文件的名字

          dwDesiredAccess Long)  如果为 GENERIC_READ 表示允许对设备进行读访问;如果为 GENERIC_WRITE 表示允许对设备进行写访问(可组合使用);如果为零,表示只允许获取与一个设备有关的信息

          dwShareMode(Long)        零表示不共享; FILE_SHARE_READ 和/或 FILE_SHARE_WRITE 表示允许对文件进行共享访问

          lpSecurityAttributes         SECURITY_ATTRIBUTES,指向一个SECURITY_ATTRIBUTES结构的指针,定义了文件的安全特性(如果操作系统支持的话)    

          dwCreationDisposition(Long)      常数有CREATE_NEW、CREATE_ALWAYS、OPEN_EXISTING(本次运用到的常数,文件必须存在。由设备提出要求)等          

          dwFlagAndAttributes(Long)     一个或多个下述常数 常数有FILE_ATTRIBUTE_ARCHIVE、FILE_ATTRIBUTE_COMPRESSED、FILE_ATTRIBUTE_NORMAL等(本次的运用的常数为0)

          hTemplateFile(Long)         如果不为0,则指定一个文件句柄。新文件将从这个文件中复制扩展属性

          本次运用于打开一个通信端口时(如COM1),无论如何都要设置OPEN_EXISTING这个函数代替了lOpen和lCreate函数,应该是首选

  •           GetCommState函数,获取串口的当前配置。

1 BOOL GetCommState( 
2 HANDLE hFile
3 LPDCB lpDCB
4 );GetCommState函数的第一个参数hFile是由CreateFile函数返回指向已打开串行口的句柄。第二个参数指向设备控制块DCB。如果函数调用成功,则返回值为非0;若函数调用失败,则返回值为0。当应用程序仅仅需要修改一部分串行口的配置值时,可以通过GetCommState函数获得当前的DCB结构,然后更改参数,在调用SetCommState函数设置修改的DCB来配置串行口
  •           PurgeComm函数作用为清空缓冲区

                    该函数原型为:

 

1   BOOL PurgeComm(HANDLE hFile,HANDLE dwFlags)
2   HANDLE hFile      '串口句柄
3   HANDLE dwFlags    '需要完成的操作
     本次运用到为PurgeComm的PURGE_RXABORT和PURGE_RXCLEAR值的组合,PURGE_RXABORT终止所有正在进行得字符串输入操作,完成一个正在进行中得重叠i/o,并带有已设置的适当事件。PURGE_RXCLEAR这个命令用于设备驱动程序清除缓冲区,经常与PURGE_RXABORT命令一起使用

 

  •          ReadFile函数,从文件中读出数据。与lread函数相比,这个函数要明显灵活的多。该函数能够操作通信设备、管道、套接字以及邮槽

                   Long,非零表示成功,零表示失败。会设置GetLastError。如启动的是一次异步读操作,则函数会返回零值,并将ERROR_IO_PENDING设置成GetLastError的结果。如结果不是零值,但读入的字节数小于nNumberOfByteToRead参数指定的值,表明早已抵达了文件的结尾

                   hFile(Long)   文件的句柄

                   lpBuffer(Any)   用于保存读入数据的一个缓冲区

                   nNumberOfBytesToRead(Long)    要读入的字符数

                   lpNumberOfBytesRead(Long)        从文件中实际读入的字符数

                   lpOverlapped      OVERLAPPED,如文件打开时指定了FILE_FLAG_OVERLAPPED,那么必须用这个参数引用一个特殊的结构。那个结构定义了一次异步读取操作。否则,应将这个参数设为NULL(将函数声明成ByVal As Long,并传递零值)

                   并非每种操作系统都支持对每种设备进行异步操作。

  •         SetCommState函数 根据设备控制块的规范,配置通信设备。这个函数重新初始化所有的硬件和控制设置。但是不会清空输出和输入队列。其函数原型为              

 

1 BOOL WINAPI SetCommState(
2   _In_ HANDLE hFile,
3   _In_ LPDCB  lpDCB
4 );hFile[in]:指向通信设备的句柄。CreateFile函数返回的句柄lpDCB[in]: DCB结构体指针,该结构体包含对通信设备的配置信息函数成功,返回非0函数失败,返回0

 

  •          SetCommTimeouts函数,对通信的所有读和写操作设置超时时间

                    函数原型如下:

1 BOOL WINAPI SetCommTimeouts(
2   _In_ HANDLE         hFile,
3   _In_ LPCOMMTIMEOUTS lpCommTimeouts
4 );
hFile[in]:指向通信设备的句柄。CreateFile函数返回的句柄lpCommTimeouts[in]:指向包含新超时值的COMMTIMEOUTS结构的指针返回值:函数成功,返回非0函数失败,返回0,进一步错误信息call GetLastError
  •         SetupComm函数,此函数初始化一个指定的通信设备的通信参数

                   函数原型如下:

1 BOOL SetupComm(
2 HANDLE hFile,
3 DWORD dwInQueue,
4 DWORD dwOutQueue
5 );hFile[in]: 通讯设备句柄。CreateFile函数返回此句柄dwInQueue[in]:指定推荐的大小,以字节为单位,对设备的内部输入缓冲区。dwOutQueue[in]:指定推荐的大小,以字节为单位,对设备的内部输出缓冲区。返回值非零表示成功。零表示失败。获取更多错误信息,调用GetLastError函数
  •         WriteFile函数,将数据写入一个文件。该函数比lwrite函数要灵活的多。也可将这个函数应用于对通信设备、管道、套接字以及邮槽的处理

       返回值:Long,TRUE(非零)表示成功,否则返回零。会设置GetLastError

       hFile(Long)     一个文件的句柄

       lpBuffer          Any,要写入的一个数据缓冲区

       nNumberOfBytesToWrite(Long)  要写入的字节数量。如写入零字节,表示是吗都不写入,但会更新文件的“上一次修改时间”。针对位于远程系统的命名管道,限制在65535个字节以内

       lpNumberOfBytesWritten(Long)  实际写入文件的字节数量

       lpOverlapped   OVERLAPPED,倘若在指定FILE_FLAG_OVERLAPPED的前提下打开文件,这个参数就必须引用一个特殊的结构。那个结构定义了一次异步写操作。否则,该参数应置为空(将声明变为ByVal As Long,并传递零值)

  •        ClearCommError函数,如果在串口通信中发生错误,如发生中断,奇偶错误等,I/O操作将会终止。如果程序要进一步执行I/O操作,必须调用ClearCommError()函数。ClearCommError()函数有两个作用:第一个作用是清除错误条件;第二个作用是确定串口通信状态。

           ClearCommError的声明如下

            如果在串口通信中发生错误,如发生中断,奇偶错误等,I/O操作将会终止。如果程序要进一步执行I/O操作,必须调用ClearCommError()函数。ClearCommError()函数有两个作用:第一个作用是清除错误条件;第二个作用是确定串口通信状态。ClearCommError()函数的声明如下:

1 BOOL ClearCommError(
2 HANDLE hFile,
3 LPDWORD lpErrors,
4 LPCOMSTAT lpStat
5 );其中主要参数介绍如下:hFile:标识通信设备,CreateFile()函数返回该句柄。lpErrors:指向用一个指明错误类型的掩码填充的32位变量。该变量可以是CE_BREAK、CE_FRAME、CE_IOE、CE_MODE、CE_OVERRUN、CE_RXOVER、CE_RXPARITY、CE_TXFULL、CE_DNS、CE_OOP、CE_PTO的组合lpStat:指向一个COMSTAT结构,该结构接收设备的状态信息。如果lpStat参数不设置,则没有设备状态信息被返回。

2.API引用声明

 1 Private Declare Function RegOpenKeyEx Lib "advapi32.dll" Alias "RegOpenKeyExA" (ByVal hKey As Long, ByVal lpSubKey As String, ByVal ulOptions As Long, ByVal samDesired As Long, phkResult As Long) As Long
 2 Private Declare Function RegEnumValue Lib "advapi32.dll" Alias "RegEnumValueA" (ByVal hKey As Long, ByVal dwIndex As Long, ByVal lpValueName As String, lpcbValueName As Long, ByVal lpReserved As Long, lpType As Long, lpData As String, lpcbData As Long) As Long
 3 Private Declare Function RegCloseKey Lib "advapi32.dll" (ByVal hKey As Long) As Long
 4 Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
 5 Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
 6 Private Declare Function CreateFile Lib "kernel32" Alias "CreateFileA" (ByVal lpFileName As String, ByVal dwDesiredAccess As Long, ByVal dwShareMode As Long, lpSecurityAttributes As SECURITY_ATTRIBUTES, ByVal dwCreationDisposition As Long, ByVal dwFlagsAndAttributes As Long, ByVal hTemplateFile As Long) As Long
 7 Private Declare Function GetCommState Lib "kernel32" (ByVal nCid As Long, lpDCB As DCB) As Long
 8 Private Declare Function PurgeComm Lib "kernel32" (ByVal hFile As Long, ByVal dwFlags As Long) As Long
 9 Private Declare Function ReadFile Lib "kernel32" (ByVal hFile As Long, lpBuffer As Any, ByVal nNumberOfBytesToRead As Long, lpNumberOfBytesRead As Long, lpOverlapped As OVERLAPPED) As Long
10 Private Declare Function SetCommState Lib "kernel32" (ByVal hCommDev As Long, lpDCB As DCB) As Long
11 Private Declare Function SetCommTimeouts Lib "kernel32" (ByVal hFile As Long, lpCommTimeouts As COMMTIMEOUTS) As Long
12 Private Declare Function SetupComm Lib "kernel32" (ByVal hFile As Long, ByVal dwInQueue As Long, ByVal dwOutQueue As Long) As Long
13 Private Declare Function WriteFile Lib "kernel32" (ByVal hFile As Long, ByRef lpBuffer As Any, ByVal nNumberOfBytesToWrite As Long, lpNumberOfBytesWritten As Long, lpOverlapped As OVERLAPPED) As Long   14 Private Declare Function ClearCommError Lib "kernel32" (ByVal hFile As Long, lpErrors As Long, lpStat As COMSTAT) As Long

3.实例代码段

 1 Public Function EnumSerialPorts() As String  '枚举已存在的串口
 2     Dim hKey As Long, ID As Long, Result As String
 3     Dim Value As String, ValueLength As Long, Data As String, DataLength As Long
 4     Result = ""
 5     If RegOpenKeyEx(HKEY_LOCAL_MACHINE, "HARDWARE\DEVICEMAP\SERIALCOMM", 0&, KEY_READ, hKey) = ERROR_SUCCESS Then '打开注册表,HKEY_LOCAL_MACHINE(机器主键)主键,子键"HARDWARE\DEVICEMAP\SERIALCOMM",ulOptions通常默认为0,即0&,参数samDesired传递实参KEY_READ(准许设置子键的数值),参数phkResult传递实参hkey用来打开键的句柄
 6         Do
 7             ValueLength = 2000
 8             DataLength = 2000
 9             Value = String(ValueLength, Chr(32))  '注册项             'String(,)返回[个数]各[字符],Value = 2000*Chr(32)  Chr()返回[Ascii]编码所代表的字符 Chr(32)为空格
10             Data = String(DataLength, Chr(32)) '值 Com 名称
11             If RegEnumValue(hKey, ID, ByVal Value, ValueLength, 0&, REG_DWORD, ByVal Data, DataLength) = ERROR_SUCCESS Then
12                 Result = Result & IIf(Len(Result) = 0, "", ",") & Trim(Replace(Left(Data, DataLength), Chr(0), Chr(32))) 'IIf函数类似于C语言中的三目运算符,Trim(,)返回去掉了前、后的之后的字符串,Replace(,,,)在第一个参数中查找第二个参数,并用第三个参数替换全部的在第一个参数的中第二个参数。Left(字符串,长度)从[字符串]的左边开始返回[长度]个字符
13             Else
14                 Exit Do
15             End If
16             ID = ID + 1
17         Loop
18         RegCloseKey hKey
19     End If
20     EnumSerialPorts = Result
21 End Function

 

 1 Public Sub ComClose(ByRef Handle As Long)                  '通讯关闭
 2     If Handle = -1 Then Exit Sub
 3     CloseHandle Handle            '需关闭的设备句柄
 4     Handle = -1
 5 End Sub
 6  
 7 Public Function ComOpen(ByVal Port As String, Optional ByVal Settings As String = "9600,n,8,1", Optional ByVal dwInQueue As Long = DEFAULT_QUEUE, Optional ByVal dwOutQueue As Long = DEFAULT_QUEUE) As Long                  '打开串口通讯
 8     Dim Result As Long, lpDCB As DCB, lpCommTimeouts As COMMTIMEOUTS, lpSA As SECURITY_ATTRIBUTES
 9     ComOpen = -1
10     If IsNumeric(Port) Then
11         Port = "\\.\Com" & Port
12     Else
13         Port = "\\.\" & Port
14     End If
15     Result = CreateFile(Port, GENERIC_READ Or GENERIC_WRITE, 0&, lpSA, OPEN_EXISTING, 0, 0&)   '创建句柄
16     If Result = -1 Then Exit Function                       '创建句柄失败,Result = -1(即返回INVALID_HANDLE_VALUE)表示执行失败
17     If GetCommState(Result, lpDCB) = 0 Then                 '返回值等于零,未能获取当前的DCB结构
18         CloseHandle Result                                  '关闭指向串行口的句柄
19         Exit Function
20     End If
21     BuildCommDCB Settings, lpDCB                            '
22     If SetCommState(Result, lpDCB) = 0 Then                 '返回值为0,SetCommState函数修改DCB配置串行口失败
23         CloseHandle Result
24         Exit Function
25     End If
26     SetupComm Result, dwInQueue, dwOutQueue  '分配串口缓冲区
27     '设定通讯超时参数
28     lpCommTimeouts.ReadIntervalTimeout = 2
29     lpCommTimeouts.ReadTotalTimeoutConstant = 4
30     lpCommTimeouts.ReadTotalTimeoutMultiplier = 3
31     lpCommTimeouts.WriteTotalTimeoutConstant = 5000 '一次写入串口数据的固定超时。
32     lpCommTimeouts.WriteTotalTimeoutMultiplier = 50 '写入每字符间的超时。
33     SetCommTimeouts Result, lpCommTimeouts          '设置指向的通信设备的句柄为Result和指向包含新超时值得COMMTIMEOUTS结构的指针
34     ComOpen = Result
35 End Function
36   
37 Public Function ComReadByte(ByVal Handle As Long, ByRef Result() As Byte, Optional ByVal WaitTime As Long = DEFAULT_WAIT_TIME) As Long     '读取串口数据
38     Dim lpOverlapped As OVERLAPPED, lpStat As COMSTAT, lpErrors As Long
39     If Handle = -1 Then Exit Function                '上个ComOpen函数句柄返回值为-1,Handle就会等于-1
40     ComReadByte = 0
41     If WaitTime > 0 Then Sleep WaitTime
42     ClearCommError Handle, lpErrors, lpStat    '标识通信设备Handle,lpErrors指明错误类型的掩码的32位变量,lpStat指向一个COMSTAT结构,该结构接收设备的状态信息
43     If lpStat.cbInQue > 0 Then
44         ReDim Result(DEFAULT_QUEUE - 1) '设置缓冲区大小1K
45         ReadFile Handle, Result(0), lpStat.cbInQue, ComReadByte, lpOverlapped
46         If ComReadByte > 0 Then
47             ReDim Preserve Result(ComReadByte - 1)             '重新定义数组Result
48         Else
49             Erase Result
50         End If
51     End If
52 End Function
53  
54 Public Function ComWriteByte(ByVal Handle As Long, ByRef Data() As Byte) As Long                                    '写入串口数据
55     Dim lpOverlapped As OVERLAPPED, lpErrors As Long, lpStat As COMSTAT
56     If (Handle = -1) Or (Len(StrConv(Data, vbUnicode)) = 0) Then Exit Function
57     PurgeComm Handle, PURGE_RXABORT Or PURGE_RXCLEAR  '清空输入缓冲区
58 
59     
60     WriteFile Handle, Data(0), UBound(Data) + 1, ComWriteByte, lpOverlapped
61     Do
62         ClearCommError Handle, lpErrors, lpStat
63     Loop Until lpStat.cbOutQue = 0  '等待输出结束
64 End Function
65 '---------------------
66 '作者: 笨狗先飞
67 '来源: CSDN
68 '原文:https://blog.csdn.net/bakw/article/details/50487609
69 '版权声明:本文为博主原创文章,转载请附上博文链接

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!