ref : http://zachsaw.blogspot.com/2010/07/serialport-ioexception-workaround-in-c.html

As promised, I've whipped up a quick workaround to fix the problem as described here.

Here's the code:

 

  1 using System;
  2 using System.IO;
  3 using System.IO.Ports;
  4 using System.Runtime.InteropServices;
  5 using System.Text;
  6 using Microsoft.Win32.SafeHandles;
  7 
  8 namespace SerialPortTester
  9 {
 10     public class SerialPortFixer : IDisposable
 11     {
 12         public static void Execute(string portName)
 13         {
 14             using (new SerialPortFixer(portName))
 15             {
 16             }
 17         }
 18         #region IDisposable Members
 19 
 20         public void Dispose()
 21         {
 22             if (m_Handle != null)
 23             {
 24                 m_Handle.Close();
 25                 m_Handle = null;
 26             }
 27         }
 28 
 29         #endregion
 30 
 31         #region Implementation
 32 
 33         private const int DcbFlagAbortOnError = 14;
 34         private const int CommStateRetries = 10;
 35         private SafeFileHandle m_Handle;
 36 
 37         private SerialPortFixer(string portName)
 38         {
 39             const int dwFlagsAndAttributes = 0x40000000;
 40             const int dwAccess = unchecked((int) 0xC0000000); 
 41  
 42             if ((portName == null) || !portName.StartsWith("COM", StringComparison.OrdinalIgnoreCase))
 43             {
 44                 throw new ArgumentException("Invalid Serial Port", "portName");
 45             }
 46             SafeFileHandle hFile = CreateFile(@"\\.\" + portName, dwAccess, 0, IntPtr.Zero, 3, dwFlagsAndAttributes,
 47                                               IntPtr.Zero);
 48             if (hFile.IsInvalid)
 49             {
 50                 WinIoError();
 51             }
 52             try
 53             {
 54                 int fileType = GetFileType(hFile);
 55                 if ((fileType != 2) && (fileType != 0))
 56                 {
 57                      throw new ArgumentException("Invalid Serial Port", "portName");
 58                 }
 59                 m_Handle = hFile;
 60                 InitializeDcb();
 61             }
 62             catch
 63             {
 64                 hFile.Close();
 65                 m_Handle = null;
 66                 throw;
 67             }
 68         }
 69 
 70         [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
 71         private static extern int FormatMessage(int dwFlags, HandleRef lpSource, int dwMessageId, int dwLanguageId,
 72                                                 StringBuilder lpBuffer, int nSize, IntPtr arguments);
 73 
 74         [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
 75         private static extern bool GetCommState(SafeFileHandle hFile, ref Dcb lpDcb);
 76 
 77         [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
 78         private static extern bool SetCommState(SafeFileHandle hFile, ref Dcb lpDcb);
 79 
 80         [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
 81         private static extern bool ClearCommError(SafeFileHandle hFile, ref int lpErrors, ref Comstat lpStat);
 82 
 83         [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
 84         private static extern SafeFileHandle CreateFile(string lpFileName, int dwDesiredAccess, int dwShareMode,
 85                                                         IntPtr securityAttrs, int dwCreationDisposition,
 86                                                         int dwFlagsAndAttributes, IntPtr hTemplateFile);
 87 
 88         [DllImport("kernel32.dll", SetLastError = true)]
 89         private static extern int GetFileType(SafeFileHandle hFile);
 90 
 91         private void InitializeDcb()
 92         {
 93             Dcb dcb = new Dcb();
 94             GetCommStateNative(ref dcb);
 95             dcb.Flags &= ~(1u << DcbFlagAbortOnError);
 96             SetCommStateNative(ref dcb);
 97         }
 98 
 99         private static string GetMessage(int errorCode)
100         {
101             StringBuilder lpBuffer = new StringBuilder(0x200);
102             if (
103                 FormatMessage(0x3200, new HandleRef(null, IntPtr.Zero), errorCode, 0, lpBuffer, lpBuffer.Capacity,
104                               IntPtr.Zero) != 0)
105             {
106                 return lpBuffer.ToString();
107             }
108             return "Unknown Error";
109         }
110 
111         private static int MakeHrFromErrorCode(int errorCode)
112         {
113             return (int) (0x80070000 | (uint) errorCode);
114         }
115 
116         private static void WinIoError()
117         {
118             int errorCode = Marshal.GetLastWin32Error();
119             throw new IOException(GetMessage(errorCode), MakeHrFromErrorCode(errorCode));
120         }
121 
122         private void GetCommStateNative(ref Dcb lpDcb)
123         {
124             int commErrors = 0;
125             Comstat comStat = new Comstat();
126 
127             for (int i = 0; i < CommStateRetries; i++)
128             {
129                 if (!ClearCommError(m_Handle, ref commErrors, ref comStat))
130                 {
131                      WinIoError();
132                 }
133                 if (GetCommState(m_Handle, ref lpDcb))
134                 {
135                      break;
136                 }
137                 if (i == CommStateRetries - 1)
138                 {
139                      WinIoError();
140                 }
141             }
142         } 
143  
144         private void SetCommStateNative(ref Dcb lpDcb)
145         {
146             int commErrors = 0;
147             Comstat comStat = new Comstat(); 
148  
149             for (int i = 0; i < CommStateRetries; i++)
150             {
151                  if (!ClearCommError(m_Handle, ref commErrors, ref comStat))
152                  {
153                      WinIoError();
154                  }
155                  if (SetCommState(m_Handle, ref lpDcb))
156                  {
157                      break;
158                  }
159                  if (i == CommStateRetries - 1)
160                  {
161                      WinIoError();
162                  }
163             }
164         }
165 
166         #region Nested type: COMSTAT
167 
168         [StructLayout(LayoutKind.Sequential)]
169         private struct Comstat
170         {
171             public readonly uint Flags;
172             public readonly uint cbInQue;
173             public readonly uint cbOutQue;
174         }
175 
176         #endregion
177 
178         #region Nested type: DCB
179 
180         [StructLayout(LayoutKind.Sequential)]
181         private struct Dcb
182         {
183             public readonly uint DCBlength;
184             public readonly uint BaudRate;
185             public uint Flags;
186             public readonly ushort wReserved;
187             public readonly ushort XonLim;
188             public readonly ushort XoffLim;
189             public readonly byte ByteSize;
190             public readonly byte Parity;
191             public readonly byte StopBits;
192             public readonly byte XonChar;
193             public readonly byte XoffChar;
194             public readonly byte ErrorChar;
195             public readonly byte EofChar;
196             public readonly byte EvtChar;
197             public readonly ushort wReserved1;
198         }
199 
200         #endregion
201 
202         #endregion
203     }
204 
205     internal class Program
206     {
207         private static void Main(string[] args)
208         {
209             SerialPortFixer.Execute("COM1");
210             using (SerialPort port = new SerialPort("COM1"))
211             {
212                 port.Write("test");
213             }
214         }
215     }
216 } 

 

 

 

分类:

技术点:

相关文章: