ref : http://zachsaw.blogspot.com/2010/07/serialport-ioexception-workaround-in-c.html
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 }