C# API方式串口读写

简介:

在调试ICU通信设备的时候,由于串口通信老出现故障,所以就怀疑CF实现的SerialPort类是否有问题,所以最后决定用纯API函数实现串口读写。
先从网上搜索相关代码(关键字:C# API 串口),发现网上相关的资料大约来源于一个版本,那就是所谓的msdn提供的样例代码(msdn的具体出处,我没有考证),其它的代码大都是它的变种。
其实这个示例代码是有问题的,也就是说DCB结构体声明的有问题,虽然该代码可以正常通信,不过如果你设置了奇偶校验的话,你会发现奇偶校验无效。
VC中的DCB结构声明如下:
 

 
  1. typedef struct _DCB {  
  2.     DWORD DCBlength;      /* sizeof(DCB)                     */  
  3.     DWORD BaudRate;       /* Baudrate at which running       */  
  4.     DWORD fBinary: 1;     /* Binary Mode (skip EOF check)    */  
  5.     DWORD fParity: 1;     /* Enable parity checking          */  
  6.     DWORD fOutxCtsFlow:1; /* CTS handshaking on output       */  
  7.     DWORD fOutxDsrFlow:1; /* DSR handshaking on output       */  
  8.     DWORD fDtrControl:2; /* DTR Flow control                */  
  9.     DWORD fDsrSensitivity:1; /* DSR Sensitivity              */  
  10.     DWORD fTXContinueOnXoff: 1; /* Continue TX when Xoff sent */  
  11.     DWORD fOutX: 1;       /* Enable output X-ON/X-OFF        */  
  12.     DWORD fInX: 1;        /* Enable input X-ON/X-OFF         */  
  13.     DWORD fErrorChar: 1; /* Enable Err Replacement          */  
  14.     DWORD fNull: 1;       /* Enable Null stripping           */  
  15.     DWORD fRtsControl:2; /* Rts Flow control                */  
  16.     DWORD fAbortOnError:1; /* Abort all reads and writes on Error */  
  17.     DWORD fDummy2:17;     /* Reserved                        */  
  18.     WORD wReserved;       /* Not currently used              */  
  19.     WORD XonLim;          /* Transmit X-ON threshold         */  
  20.     WORD XoffLim;         /* Transmit X-OFF threshold        */  
  21.     BYTE ByteSize;        /* Number of bits/byte, 4-8        */  
  22.     BYTE Parity;          /* 0-4=None,Odd,Even,Mark,Space    */  
  23.     BYTE StopBits;        /* 0,1,2 = 1, 1.5, 2               */  
  24.     char XonChar;         /* Tx and Rx X-ON character        */  
  25.     char XoffChar;        /* Tx and Rx X-OFF character       */  
  26.     char ErrorChar;       /* Error replacement char          */  
  27.     char EofChar;         /* End of Input character          */  
  28.     char EvtChar;         /* Received Event character        */  
  29.     WORD wReserved1;      /* Fill for now.                   */  
  30. } DCB, *LPDCB;  

 
有问题的代码DCB结构声明如下:
[StructLayout(LayoutKind.Sequential)]
       

 
  1. public struct DCB  
  2.         {  
  3.             public int DCBlength;  
  4.             public int BaudRate;  
  5.             public int fBinary;  
  6.             public int fParity;  
  7.             public int fOutxCtsFlow;  
  8.             public int fOutxDsrFlow;  
  9.             public int fDtrControl;  
  10.             public int fDsrSensitivity;  
  11.             public int fTXContinueOnXoff;  
  12.             public int fOutX;  
  13.             public int fInX;  
  14.             public int fErrorChar;  
  15.             public int fNull;  
  16.             public int fRtsControl;  
  17.             public int fAbortOnError;  
  18.             public int fDummy2;  
  19.             public uint flags;  
  20.             public ushort wReserved;  
  21.             public ushort XonLim;  
  22.             public ushort XoffLim;  
  23.             public byte ByteSize;  
  24.             public byte Parity;  
  25.             public byte StopBits;  
  26.             public byte XonChar;  
  27.             public byte XoffChar;  
  28.             public byte ErrorChar;  
  29.             public byte EofChar;  
  30.             public byte EvtChar;  
  31.             public ushort wReserved1;  
  32.         }  

对C++比较熟悉网友应该知道,结构体中这种格式的声明,如DWORD fBinary: 1;是以位为单位进行变量设置的,DCB中相关位一共占4个字节,也就是相当于C#中的一个int变量所占的空间。很明显上面的DCB结构会有问题,实际上后面你设置的串口参数,如奇偶校验由于偏移有问题,虽然你设置了,其实都没有设置成功。
其实也不是我说人家的DCB声明错了就错了,在SerialPort类中你就可以找到微软官方自己的DCB声明(需要反编译SerialPort类),声明如下:
[StructLayout(LayoutKind.Sequential)]
       

 
  1. public struct DCB  
  2.        {  
  3.            public int DCBlength;  
  4.            public int BaudRate;  
  5.            public uint Flags;  
  6.            public ushort wReserved;  
  7.            public ushort XonLim;  
  8.            public ushort XoffLim;  
  9.            public byte ByteSize;  
  10.            public byte Parity;  
  11.            public byte StopBits;  
  12.            public byte XonChar;  
  13.            public byte XoffChar;  
  14.            public byte ErrorChar;  
  15.            public byte EofChar;  
  16.            public byte EvtChar;  
  17.            public ushort wReserved1;  
  18.        }  

并且专门有一个设置位标志的函数,如下:
 

 
  1. internal void SetDcbFlag(int whichFlag, int setting)  
  2.         {  
  3.             uint num;  
  4.             setting = setting << whichFlag;  
  5.             if ((whichFlag == 4) || (whichFlag == 12))  
  6.             {  
  7.                 num = 3;  
  8.             }  
  9.             else if (whichFlag == 15)  
  10.             {  
  11.                 num = 0x1ffff;  
  12.             }  
  13.             else 
  14.             {  
  15.                 num = 1;  
  16.             }  
  17.             dcb.flags &= ~(num << whichFlag);  
  18.             dcb.flags |= (uint)setting;  
  19.         }  

经过修改能正确运行的API代码如下(注意,由于我是在WinCE平台上运行,所以DLL的路径为"\\windows\\coredll.dll",你修改为"kernel32"后即可在PC机使用):
 

 
  1. ///<summary>  
  2.     /// API串口类 叶帆修改 http://yfsoft.blog.51cto.com
  3.     ///</summary>  
  4.     public class CommPort  
  5.     {  
  6.         ///<summary>  
  7.         ///端口名称(COM1,COM2...COM4...)  
  8.         ///</summary>  
  9.         public string Port = "COM1:";  
  10.         ///<summary>  
  11.         ///波特率9600  
  12.         ///</summary>  
  13.         public int BaudRate = 9600;  
  14.         ///<summary>  
  15.         ///数据位4-8  
  16.         ///</summary>  
  17.         public byte ByteSize = 8; //4-8   
  18.         ///<summary>  
  19.         ///奇偶校验0-4=no,odd,even,mark,space   
  20.         ///</summary>  
  21.         public byte Parity = 0;   //0-4=no,odd,even,mark,space   
  22.         ///<summary>  
  23.         ///停止位  
  24.         ///</summary>  
  25.         public byte StopBits = 0;   //0,1,2 = 1, 1.5, 2   
  26.         ///<summary>  
  27.         ///超时长  
  28.         ///</summary>  
  29.         public int ReadTimeout = 200;  
  30.         ///<summary>  
  31.         ///串口是否已经打开  
  32.         ///</summary>  
  33.         public bool Opened = false;  
  34.         ///<summary>  
  35.         /// COM口句柄  
  36.         ///</summary>  
  37.         private int hComm = -1;  
  38.    
  39.         #region "API相关定义"  
  40.         private const string DLLPATH = "\\windows\\coredll.dll"// "kernel32";  
  41.    
  42.         ///<summary>  
  43.         /// WINAPI常量,写标志  
  44.         ///</summary>  
  45.         private const uint GENERIC_READ = 0x80000000;  
  46.         ///<summary>  
  47.         /// WINAPI常量,读标志  
  48.         ///</summary>  
  49.         private const uint GENERIC_WRITE = 0x40000000;  
  50.         ///<summary>  
  51.         /// WINAPI常量,打开已存在  
  52.         ///</summary>  
  53.         private const int OPEN_EXISTING = 3;  
  54.         ///<summary>  
  55.         /// WINAPI常量,无效句柄  
  56.         ///</summary>  
  57.         private const int INVALID_HANDLE_VALUE = -1;  
  58.    
  59.         private const int PURGE_RXABORT = 0x2;  
  60.         private const int PURGE_RXCLEAR = 0x8;  
  61.         private const int PURGE_TXABORT = 0x1;  
  62.         private const int PURGE_TXCLEAR = 0x4;  
  63.    
  64.         ///<summary>  
  65.         ///设备控制块结构体类型  
  66.         ///</summary>  
  67.         [StructLayout(LayoutKind.Sequential)]  
  68.         public struct DCB  
  69.         {  
  70.            ///<summary>  
  71.             /// DCB长度  
  72.             ///</summary>  
  73.             public int DCBlength;  
  74.             ///<summary>  
  75.             ///指定当前波特率  
  76.             ///</summary>  
  77.             public int BaudRate;  
  78.             ///<summary>  
  79.             ///标志位  
  80.             ///</summary>  
  81.             public uint flags;  
  82.             ///<summary>  
  83.             ///未使用,必须为0  
  84.             ///</summary>  
  85.             public ushort wReserved;  
  86.             ///<summary>  
  87.             ///指定在XON字符发送这前接收缓冲区中可允许的最小字节数  
  88.             ///</summary>  
  89.             public ushort XonLim;  
  90.             ///<summary>  
  91.             ///指定在XOFF字符发送这前接收缓冲区中可允许的最小字节数  
  92.             ///</summary>  
  93.             public ushort XoffLim;  
  94.             ///<summary>  
  95.             ///指定端口当前使用的数据位  
  96.             ///</summary>  
  97.             public byte ByteSize;  
  98.             ///<summary>  
  99.             ///指定端口当前使用的奇偶校验方法,可能为:EVENPARITY,MARKPARITY,NOPARITY,ODDPARITY 0-4=no,odd,even,mark,space   
  100.             ///</summary>  
  101.             public byte Parity;  
  102.             ///<summary>  
  103.             ///指定端口当前使用的停止位数,可能为:ONESTOPBIT,ONE5STOPBITS,TWOSTOPBITS 0,1,2 = 1, 1.5, 2   
  104.             ///</summary>  
  105.             public byte StopBits;  
  106.             ///<summary>  
  107.             ///指定用于发送和接收字符XON的值 Tx and Rx XON character   
  108.             ///</summary>  
  109.             public byte XonChar;  
  110.             ///<summary>  
  111.             ///指定用于发送和接收字符XOFF值 Tx and Rx XOFF character   
  112.             ///</summary>  
  113.             public byte XoffChar;  
  114.             ///<summary>  
  115.             ///本字符用来代替接收到的奇偶校验发生错误时的值  
  116.             ///</summary>  
  117.             public byte ErrorChar;  
  118.             ///<summary>  
  119.             ///当没有使用二进制模式时,本字符可用来指示数据的结束  
  120.             ///</summary>  
  121.             public byte EofChar;  
  122.             ///<summary>  
  123.             ///当接收到此字符时,会产生一个事件  
  124.             ///</summary>  
  125.             public byte EvtChar;  
  126.             ///<summary>  
  127.             ///未使用  
  128.             ///</summary>  
  129.             public ushort wReserved1;  
  130.         }  
  131.    
  132.         ///<summary>  
  133.         ///串口超时时间结构体类型  
  134.         ///</summary>  
  135.         [StructLayout(LayoutKind.Sequential)]  
  136.         private struct COMMTIMEOUTS  
  137.         {  
  138.             public int ReadIntervalTimeout;  
  139.             public int ReadTotalTimeoutMultiplier;  
  140.             public int ReadTotalTimeoutConstant;  
  141.             public int WriteTotalTimeoutMultiplier;  
  142.             public int WriteTotalTimeoutConstant;  
  143.         }  
  144.    
  145.         ///<summary>  
  146.         ///溢出缓冲区结构体类型  
  147.         ///</summary>  
  148.         [StructLayout(LayoutKind.Sequential)]  
  149.         private struct OVERLAPPED  
  150.         {  
  151.             public int Internal;  
  152.             public int InternalHigh;  
  153.             public int Offset;  
  154.             public int OffsetHigh;  
  155.             public int hEvent;  
  156.         }  
  157.    
  158.         ///<summary>  
  159.         ///打开串口  
  160.         ///</summary>  
  161.         ///<param name="lpFileName">要打开的串口名称</param>  
  162.         ///<param name="dwDesiredAccess">指定串口的访问方式,一般设置为可读可写方式</param>  
  163.         ///<param name="dwShareMode">指定串口的共享模式,串口不能共享,所以设置为0</param>  
  164.         ///<param name="lpSecurityAttributes">设置串口的安全属性,WIN9X下不支持,应设为NULL</param>  
  165.         ///<param name="dwCreationDisposition">对于串口通信,创建方式只能为OPEN_EXISTING</param>  
  166.         ///<param name="dwFlagsAndAttributes">指定串口属性与标志,设置为FILE_FLAG_OVERLAPPED(重叠I/O操作),指定串口以异步方式通信</param>  
  167.         ///<param name="hTemplateFile">对于串口通信必须设置为NULL</param>  
  168.         [DllImport(DLLPATH)]  
  169.         private static extern int CreateFile(string lpFileName, uint dwDesiredAccess, int dwShareMode,  
  170.         int lpSecurityAttributes, int dwCreationDisposition, int dwFlagsAndAttributes, int hTemplateFile);  
  171.    
  172.         ///<summary>  
  173.         ///得到串口状态  
  174.         ///</summary>  
  175.         ///<param name="hFile">通信设备句柄</param>  
  176.         ///<param name="lpDCB">设备控制块DCB</param>  
  177.         [DllImport(DLLPATH)]  
  178.         private static extern bool GetCommState(int hFile, ref DCB lpDCB);  
  179.    
  180.         ///<summary>  
  181.         ///建立串口设备控制块(嵌入版没有)  
  182.         ///</summary>  
  183.         ///<param name="lpDef">设备控制字符串</param>  
  184.         ///<param name="lpDCB">设备控制块</param>  
  185.         //[DllImport(DLLPATH)]  
  186.         //private static extern bool BuildCommDCB(string lpDef, ref DCB lpDCB);  
  187.    
  188.         ///<summary>  
  189.         ///设置串口状态  
  190.         ///</summary>  
  191.         ///<param name="hFile">通信设备句柄</param>  
  192.         ///<param name="lpDCB">设备控制块</param>  
  193.         [DllImport(DLLPATH)]  
  194.         private static extern bool SetCommState(int hFile, ref DCB lpDCB);  
  195.    
  196.         ///<summary>  
  197.         ///读取串口超时时间  
  198.         ///</summary>  
  199.         ///<param name="hFile">通信设备句柄</param>  
  200.         ///<param name="lpCommTimeouts">超时时间</param>  
  201.         [DllImport(DLLPATH)]  
  202.         private static extern bool GetCommTimeouts(int hFile, ref COMMTIMEOUTS lpCommTimeouts);  
  203.    
  204.         ///<summary>  
  205.         ///设置串口超时时间  
  206.         ///</summary>  
  207.         ///<param name="hFile">通信设备句柄</param>  
  208.         ///<param name="lpCommTimeouts">超时时间</param>  
  209.         [DllImport(DLLPATH)]  
  210.         private static extern bool SetCommTimeouts(int hFile, ref COMMTIMEOUTS lpCommTimeouts);  
  211.    
  212.         ///<summary>  
  213.         ///读取串口数据  
  214.         ///</summary>  
  215.         ///<param name="hFile">通信设备句柄</param>  
  216.         ///<param name="lpBuffer">数据缓冲区</param>  
  217.         ///<param name="nNumberOfBytesToRead">多少字节等待读取</param>  
  218.         ///<param name="lpNumberOfBytesRead">读取多少字节</param>  
  219.         ///<param name="lpOverlapped">溢出缓冲区</param>  
  220.         [DllImport(DLLPATH)]  
  221.         private static extern bool ReadFile(int hFile, byte[] lpBuffer, int nNumberOfBytesToRead,  
  222.         ref int lpNumberOfBytesRead, ref OVERLAPPED lpOverlapped);  
  223.    
  224.         ///<summary>  
  225.         ///写串口数据  
  226.         ///</summary>  
  227.         ///<param name="hFile">通信设备句柄</param>  
  228.         ///<param name="lpBuffer">数据缓冲区</param>  
  229.         ///<param name="nNumberOfBytesToWrite">多少字节等待写入</param>  
  230.         ///<param name="lpNumberOfBytesWritten">已经写入多少字节</param>  
  231.         ///<param name="lpOverlapped">溢出缓冲区</param>  
  232.         [DllImport(DLLPATH)]  
  233.         private static extern bool WriteFile(int hFile, byte[] lpBuffer, int nNumberOfBytesToWrite,  
  234.         ref int lpNumberOfBytesWritten, ref OVERLAPPED lpOverlapped);  
  235.    
  236.         [DllImport(DLLPATH, SetLastError = true)]  
  237.         private static extern bool FlushFileBuffers(int hFile);  
  238.    
  239.         [DllImport(DLLPATH, SetLastError = true)]  
  240.         private static extern bool PurgeComm(int hFile, uint dwFlags);  
  241.    
  242.         ///<summary>  
  243.         ///关闭串口  
  244.         ///</summary>  
  245.         ///<param name="hObject">通信设备句柄</param>  
  246.         [DllImport(DLLPATH)]  
  247.         private static extern bool CloseHandle(int hObject);  
  248.    
  249.         ///<summary>  
  250.         ///得到串口最后一次返回的错误  
  251.         ///</summary>  
  252.         [DllImport(DLLPATH)]  
  253.         private static extern uint GetLastError();  
  254.         #endregion  
  255.    
  256.         ///<summary>  
  257.         ///设置DCB标志位  
  258.         ///</summary>  
  259.         ///<param name="whichFlag"></param>  
  260.         ///<param name="setting"></param>  
  261.         ///<param name="dcb"></param>  
  262.         internal void SetDcbFlag(int whichFlag, int setting, DCB dcb)  
  263.         {  
  264.             uint num;  
  265.             setting = setting << whichFlag;  
  266.             if ((whichFlag == 4) || (whichFlag == 12))  
  267.             {  
  268.                 num = 3;  
  269.             }  
  270.             else if (whichFlag == 15)  
  271.             {  
  272.                 num = 0x1ffff;  
  273.             }  
  274.             else 
  275.             {  
  276.                 num = 1;  
  277.             }  
  278.             dcb.flags &= ~(num << whichFlag);  
  279.             dcb.flags |= (uint)setting;  
  280.         }  
  281.    
  282.         ///<summary>  
  283.         ///建立与串口的连接  
  284.         ///</summary>  
  285.         public int Open()  
  286.         {  
  287.             DCB dcb = new DCB();  
  288.             COMMTIMEOUTS ctoCommPort = new COMMTIMEOUTS();  
  289.    
  290.             // 打开串口   
  291.             hComm = CreateFile(Port, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);  
  292.             if (hComm == INVALID_HANDLE_VALUE)  
  293.             {  
  294.                 return -1;  
  295.             }  
  296.             // 设置通信超时时间  
  297.             GetCommTimeouts(hComm, ref ctoCommPort);  
  298.             ctoCommPort.ReadTotalTimeoutConstant = ReadTimeout;  
  299.             ctoCommPort.ReadTotalTimeoutMultiplier = 0;  
  300.             ctoCommPort.WriteTotalTimeoutMultiplier = 0;  
  301.             ctoCommPort.WriteTotalTimeoutConstant = 0;  
  302.             SetCommTimeouts(hComm, ref ctoCommPort);  
  303.    
  304.             //设置串口参数  
  305.             GetCommState(hComm, ref dcb);  
  306.             dcb.DCBlength = Marshal.SizeOf(dcb);  
  307.             dcb.BaudRate = BaudRate;  
  308.             dcb.flags = 0;  
  309.             dcb.ByteSize = (byte)ByteSize;  
  310.             dcb.StopBits = StopBits;  
  311.             dcb.Parity = (byte)Parity;  
  312.    
  313.             //------------------------------  
  314.             SetDcbFlag(0, 1, dcb);            //二进制方式   
  315.             SetDcbFlag(1, (Parity == 0) ? 0 : 1, dcb);  
  316.             SetDcbFlag(2, 0, dcb);            //不用CTS检测发送流控制  
  317.             SetDcbFlag(3, 0, dcb);            //不用DSR检测发送流控制  
  318.             SetDcbFlag(4, 0, dcb);            //禁止DTR流量控制  
  319.             SetDcbFlag(6, 0, dcb);            //对DTR信号线不敏感  
  320.             SetDcbFlag(9, 1, dcb);            //检测接收缓冲区  
  321.             SetDcbFlag(8, 0, dcb);            //不做发送字符控制  
  322.             SetDcbFlag(10, 0, dcb);           //是否用指定字符替换校验错的字符  
  323.             SetDcbFlag(11, 0, dcb);           //保留NULL字符  
  324.             SetDcbFlag(12, 0, dcb);           //允许RTS流量控制  
  325.             SetDcbFlag(14, 0, dcb);           //发送错误后,继续进行下面的读写操作  
  326.             //--------------------------------  
  327.             dcb.wReserved = 0;                       //没有使用,必须为0         
  328.             dcb.XonLim = 0;                          //指定在XOFF字符发送之前接收到缓冲区中可允许的最小字节数  
  329.             dcb.XoffLim = 0;                         //指定在XOFF字符发送之前缓冲区中可允许的最小可用字节数  
  330.             dcb.XonChar = 0;                         //发送和接收的XON字符   
  331.             dcb.XoffChar = 0;                        //发送和接收的XOFF字符  
  332.             dcb.ErrorChar = 0;                       //代替接收到奇偶校验错误的字符   
  333.             dcb.EofChar = 0;                         //用来表示数据的结束        
  334.             dcb.EvtChar = 0;                         //事件字符,接收到此字符时,会产生一个事件          
  335.             dcb.wReserved1 = 0;                      //没有使用   
  336.    
  337.             if (!SetCommState(hComm, ref dcb))  
  338.             {  
  339.                 return -2;  
  340.             }  
  341.             Opened = true;  
  342.             return 0;  
  343.         }  
  344.         ///<summary>  
  345.         ///关闭串口,结束通讯  
  346.         ///</summary>  
  347.         public void Close()  
  348.         {  
  349.             if (hComm != INVALID_HANDLE_VALUE)  
  350.             {  
  351.                 CloseHandle(hComm);  
  352.             }  
  353.         }  
  354.         ///<summary>  
  355.         ///读取串口返回的数据  
  356.         ///</summary>  
  357.         ///<param name="NumBytes">数据长度</param>  
  358.         public int Read(ref byte[] bytData, int NumBytes)  
  359.         {  
  360.             if (hComm != INVALID_HANDLE_VALUE)  
  361.             {  
  362.                 OVERLAPPED ovlCommPort = new OVERLAPPED();  
  363.                 int BytesRead = 0;  
  364.                 ReadFile(hComm, bytData, NumBytes, ref BytesRead, ref ovlCommPort);  
  365.                 return BytesRead;  
  366.             }  
  367.             else 
  368.             {  
  369.                 return -1;  
  370.             }  
  371.         }  
  372.    
  373.         ///<summary>  
  374.         ///向串口写数据  
  375.         ///</summary>  
  376.         ///<param name="WriteBytes">数据数组</param>  
  377.         public int Write(byte[] WriteBytes, int intSize)  
  378.         {  
  379.             if (hComm != INVALID_HANDLE_VALUE)  
  380.             {  
  381.                 OVERLAPPED ovlCommPort = new OVERLAPPED();  
  382.                 int BytesWritten = 0;  
  383.                 WriteFile(hComm, WriteBytes, intSize, ref BytesWritten, ref ovlCommPort);  
  384.                 return BytesWritten;  
  385.             }  
  386.             else 
  387.             {  
  388.                 return -1;  
  389.             }  
  390.         }  
  391.    
  392.         ///<summary>  
  393.         ///清除接收缓冲区  
  394.         ///</summary>  
  395.         ///<returns></returns>  
  396.         public void ClearReceiveBuf()  
  397.         {  
  398.             if (hComm != INVALID_HANDLE_VALUE)  
  399.             {  
  400.                 PurgeComm(hComm, PURGE_RXABORT | PURGE_RXCLEAR);  
  401.             }  
  402.         }  
  403.    
  404.         ///<summary>  
  405.         ///清除发送缓冲区  
  406.         ///</summary>  
  407.         public void ClearSendBuf()  
  408.         {  
  409.             if (hComm != INVALID_HANDLE_VALUE)  
  410.             {  
  411.                 PurgeComm(hComm, PURGE_TXABORT | PURGE_TXCLEAR);  
  412.             }  
  413.         }  
  414.  }  

后记:我的串口程序修改为API方式后,实际发现与SerialPort类遇到同样的问题,所以SerialPort类还是值得信任的。该API方式的代码在WinCE平台和PC平台都调试通过。


 















本文转自yefanqiu51CTO博客,原文链接:http://blog.51cto.com/yfsoft/323424,如需转载请自行联系原作者

相关文章
|
1月前
|
开发框架 .NET API
RESTful API 设计与实现:C# 开发者的一分钟入门
【10月更文挑战第5天】本文从零开始,介绍了如何使用 C# 和 ASP.NET Core 设计并实现一个简单的 RESTful API。首先解释了 RESTful API 的概念及其核心原则,然后详细说明了设计 RESTful API 的关键步骤,包括资源识别、URI 设计、HTTP 方法选择、状态码使用和错误处理。最后,通过一个用户管理 API 的示例,演示了如何创建项目、定义模型、实现控制器及运行测试,帮助读者掌握 RESTful API 的开发技巧。
63 7
|
1月前
|
API C#
异步轮询 Web API 的实现与 C# 示例
异步轮询 Web API 的实现与 C# 示例
82 0
|
3月前
|
开发框架 人工智能 自然语言处理
基于ChatGPT的API的C#接入研究
基于ChatGPT的API的C#接入研究
|
5月前
|
C#
【C#】C#读写Excel文件
【C#】C#读写Excel文件
131 1
|
6月前
|
JSON API C#
C# 通过阿里云 API 实现企业工商数据查询
C# 通过阿里云 API 实现企业工商数据查询
|
6月前
|
JSON 文字识别 算法
C# 通过阿里云 API 实现企业营业执照OCR识别
C# 通过阿里云 API 实现企业营业执照OCR识别
|
6月前
|
API C# 图形学
【Unity 3D】常见API的讲解以及在C#脚本中的执行(附源码)
【Unity 3D】常见API的讲解以及在C#脚本中的执行(附源码)
139 1
|
6月前
|
安全 API C#
C# | System.IO.Pipelines 很酷的读写数据流方式!
文本分享一种新的读写数据流方式 —— System.IO.Pipelines。这个东西在 .NET Core 2.1 中出现了,它能够帮助你更高效地处理数据流。 System.IO.Pipelines 是啥? System.IO.Pipelines 是一个用于读写数据流的高性能 API。它主要由三个部分组成:Pipe、PipelineReader 和 PipelineWriter。 Pipe 是一个异步、线程安全的缓冲区,它让数据在生产者和消费者之间流动。PipelineReader 和 PipelineWriter 则是 Pipe 的读取和写入端点。
326 0
C# | System.IO.Pipelines 很酷的读写数据流方式!
|
6月前
|
监控 安全 API
深入探讨API安全性与C#实例演示
在本篇文章中,我们将深入研究 API 的安全性,并通过使用 C# 的实际示例探索一些基本机制。
107 0
|
API C# Windows
C#实现操作Windows窗口句柄:常用窗口句柄相关API、Winform中句柄属性和Process的MainWindowHandle问题【窗口句柄总结之三】
本篇主要介绍一些与窗口句柄相关的一些API,比如设置窗口状态、当前激活的窗口、窗口客户区的大小、鼠标位置、禁用控件等,以及介绍Winform中的句柄属性,便于直接获取控件或窗体句柄,以及不推荐...
3176 0
C#实现操作Windows窗口句柄:常用窗口句柄相关API、Winform中句柄属性和Process的MainWindowHandle问题【窗口句柄总结之三】
下一篇
无影云桌面