目錄
第1章說明
1 為什么需要異步寫數據?
如下圖所示,以波特率300打開一個串口。

圖1
單擊"同步發送"按鈕,則數據未發送完之前寫數據的函數不會返回。波特率300,每秒大概能發送25個字符,發送500個字符就需要20秒。這20秒之內,整個程序將處於假死狀態。
單擊"異步發送"按鈕,就不會出現假死狀態。
2 異步寫數據的代碼
異步寫數據的代碼如下:
| private void btnWriteAsync_Click(object sender, EventArgs e) {//異步寫 byte[] byt = System.Text.Encoding.Default.GetBytes(txtSend.Text); if(byt!=null && byt.Length > 0) { IntPtr hComm = GetCommHandle(m_sp); UInt32 w = 0; m_ov.hEvent = IntPtr.Zero; m_ov.Internal = IntPtr.Zero; m_ov.InternalHigh = IntPtr.Zero; m_ov.Offset = 0; m_ov.OffsetHigh = 0; WriteFile(hComm, byt, (UInt32)byt.Length, ref w, ref m_ov); } } |
要點為:
1)GetCommHandle函數獲取.NET SerialPort對象的串口句柄hComm;
2)調用WriteFile函數,異步寫數據。
以下是結構OVERLAPPED的聲明、函數WriteFile的聲明、函數GetCommHandle的實現:
| [StructLayout(LayoutKind.Sequential,Pack=4)] public struct OVERLAPPED { public IntPtr Internal; public IntPtr InternalHigh; public UInt32 Offset; public UInt32 OffsetHigh; public IntPtr hEvent; } [DllImport("kernel32.dll", SetLastError = true , CallingConvention = CallingConvention.Winapi)] private static extern UInt32 WriteFile(IntPtr hFile, byte[] lpBuffer , UInt32 nNumberOfBytesToWrite , ref UInt32 lpNumberOfBytesWritten , ref OVERLAPPED lpOverlapped);
protected System.IO.Ports.SerialPort m_sp = new System.IO.Ports.SerialPort(); protected OVERLAPPED m_ov;
static IntPtr GetCommHandle(System.IO.Ports.SerialPort sp) {//獲得串口句柄,供 Win32 API 使用 IntPtr hComm = IntPtr.Zero; if (sp != null) { object stream = typeof(System.IO.Ports.SerialPort).GetField("internalSerialStream", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).GetValue(sp); var handle = (Microsoft.Win32.SafeHandles.SafeFileHandle)stream.GetType().GetField("_handle", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).GetValue(stream); hComm = handle.DangerousGetHandle(); } return hComm; } |
3 源代碼
本文的代碼已上傳至git服務器:
https://github.com/hanford77/Exercise
https://git.oschina.net/hanford/Exercise
在目錄 SerialPort\c# 目錄內。
