@@ -12,13 +12,58 @@ use winapi::um::winbase::*;
1212use winapi:: um:: winnt:: {
1313 DUPLICATE_SAME_ACCESS , FILE_ATTRIBUTE_NORMAL , GENERIC_READ , GENERIC_WRITE , HANDLE ,
1414} ;
15+ use winapi:: shared:: winerror:: { ERROR_IO_PENDING , ERROR_OPERATION_ABORTED } ;
16+ use winapi:: shared:: ntdef:: NULL ;
17+ use winapi:: um:: synchapi:: CreateEventW ;
18+ use winapi:: um:: minwinbase:: OVERLAPPED ;
19+ use winapi:: um:: ioapiset:: GetOverlappedResult ;
20+ use winapi:: um:: errhandlingapi:: GetLastError ;
1521
1622use crate :: windows:: dcb;
1723use crate :: {
1824 ClearBuffer , DataBits , Error , ErrorKind , FlowControl , Parity , Result , SerialPort ,
1925 SerialPortBuilder , StopBits ,
2026} ;
2127
28+ struct OverlappedHandle ( pub HANDLE ) ;
29+
30+ impl OverlappedHandle {
31+ #[ inline]
32+ fn new ( ) -> io:: Result < Self > {
33+ match unsafe { CreateEventW ( ptr:: null_mut ( ) , TRUE , FALSE , ptr:: null_mut ( ) ) } {
34+ NULL => Err ( io:: Error :: last_os_error ( ) ) ,
35+ handle => Ok ( Self ( handle) )
36+ }
37+ }
38+
39+ #[ inline]
40+ fn close ( self ) {
41+ //drop
42+ }
43+
44+ #[ inline]
45+ fn create_overlapped ( & self ) -> OVERLAPPED {
46+ OVERLAPPED {
47+ Internal : 0 ,
48+ InternalHigh : 0 ,
49+ u : unsafe {
50+ MaybeUninit :: zeroed ( ) . assume_init ( )
51+ } ,
52+ hEvent : self . 0 ,
53+ }
54+
55+ }
56+ }
57+
58+ impl Drop for OverlappedHandle {
59+ #[ inline( always) ]
60+ fn drop ( & mut self ) {
61+ unsafe {
62+ CloseHandle ( self . 0 ) ;
63+ }
64+ }
65+ }
66+
2267/// A serial port implementation for Windows COM ports
2368///
2469/// The port will be closed when the value is dropped. However, this struct
@@ -63,7 +108,7 @@ impl COMPort {
63108 0 ,
64109 ptr:: null_mut ( ) ,
65110 OPEN_EXISTING ,
66- FILE_ATTRIBUTE_NORMAL ,
111+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED ,
67112 0 as HANDLE ,
68113 )
69114 } ;
@@ -105,27 +150,20 @@ impl COMPort {
105150 ///
106151 /// This function returns an error if the serial port couldn't be cloned.
107152 pub fn try_clone_native ( & self ) -> Result < COMPort > {
108- let process_handle: HANDLE = unsafe { GetCurrentProcess ( ) } ;
109- let mut cloned_handle: HANDLE = INVALID_HANDLE_VALUE ;
110- unsafe {
111- DuplicateHandle (
112- process_handle,
113- self . handle ,
114- process_handle,
115- & mut cloned_handle,
116- 0 ,
117- TRUE ,
118- DUPLICATE_SAME_ACCESS ,
119- ) ;
120- if cloned_handle != INVALID_HANDLE_VALUE {
121- Ok ( COMPort {
122- handle : cloned_handle,
123- port_name : self . port_name . clone ( ) ,
124- timeout : self . timeout ,
125- } )
126- } else {
127- Err ( super :: error:: last_os_error ( ) )
128- }
153+ // duplicate communications device handle
154+ let mut duplicate_handle = INVALID_HANDLE_VALUE ;
155+ let process = unsafe { GetCurrentProcess ( ) } ;
156+ let res = unsafe {
157+ DuplicateHandle ( process, self . handle , process, & mut duplicate_handle, 0 , FALSE , DUPLICATE_SAME_ACCESS )
158+ } ;
159+
160+ match res {
161+ 0 => Err ( super :: error:: last_os_error ( ) ) ,
162+ _ => Ok ( COMPort {
163+ handle : duplicate_handle,
164+ port_name : self . port_name . clone ( ) ,
165+ timeout : self . timeout ,
166+ } )
129167 }
130168 }
131169
@@ -178,48 +216,76 @@ impl FromRawHandle for COMPort {
178216
179217impl io:: Read for COMPort {
180218 fn read ( & mut self , buf : & mut [ u8 ] ) -> io:: Result < usize > {
181- let mut len: DWORD = 0 ;
219+ let mut read_size = buf. len ( ) ;
220+
221+ let bytes_to_read = self . bytes_to_read ( ) ? as usize ;
222+
223+ if self . timeout . as_millis ( ) == 0 && bytes_to_read < read_size {
224+ read_size = bytes_to_read;
225+ }
226+ if read_size == 0 {
227+ return Ok ( 0 ) ;
228+ }
182229
183- match unsafe {
230+ let evt_handle = OverlappedHandle :: new ( ) ?;
231+ let mut overlapped = evt_handle. create_overlapped ( ) ;
232+ let mut len: DWORD = 0 ;
233+ let read_result = unsafe {
184234 ReadFile (
185235 self . handle ,
186236 buf. as_mut_ptr ( ) as LPVOID ,
187- buf . len ( ) as DWORD ,
237+ read_size as DWORD ,
188238 & mut len,
189- ptr :: null_mut ( ) ,
239+ & mut overlapped ,
190240 )
191- } {
192- 0 => Err ( io:: Error :: last_os_error ( ) ) ,
193- _ => {
194- if len != 0 {
195- Ok ( len as usize )
196- } else {
197- Err ( io:: Error :: new (
198- io:: ErrorKind :: TimedOut ,
199- "Operation timed out" ,
200- ) )
201- }
202- }
241+ } ;
242+ let last_error = unsafe { GetLastError ( ) } ;
243+ if read_result == 0 && last_error != ERROR_IO_PENDING && last_error != ERROR_OPERATION_ABORTED {
244+ return Err ( io:: Error :: last_os_error ( ) ) ;
245+ }
246+ let overlapped_result = unsafe { GetOverlappedResult ( self . handle , & mut overlapped, & mut len, TRUE ) } ;
247+ evt_handle. close ( ) ;
248+ let last_error = unsafe { GetLastError ( ) } ;
249+ if overlapped_result == 0 && last_error != ERROR_OPERATION_ABORTED {
250+ return Err ( io:: Error :: last_os_error ( ) ) ;
251+ }
252+ if len != 0 {
253+ Ok ( len as usize )
254+ } else {
255+ Err ( io:: Error :: new (
256+ io:: ErrorKind :: TimedOut ,
257+ "Operation timed out" ,
258+ ) )
203259 }
204260 }
205261}
206262
207263impl io:: Write for COMPort {
208264 fn write ( & mut self , buf : & [ u8 ] ) -> io:: Result < usize > {
265+ let evt_handle = OverlappedHandle :: new ( ) ?;
266+ let mut overlapped = evt_handle. create_overlapped ( ) ;
209267 let mut len: DWORD = 0 ;
210-
211- match unsafe {
268+ let write_result = unsafe {
212269 WriteFile (
213270 self . handle ,
214271 buf. as_ptr ( ) as LPVOID ,
215272 buf. len ( ) as DWORD ,
216273 & mut len,
217- ptr :: null_mut ( ) ,
274+ & mut overlapped ,
218275 )
219- } {
220- 0 => Err ( io:: Error :: last_os_error ( ) ) ,
221- _ => Ok ( len as usize ) ,
276+ } ;
277+ let last_error = unsafe { GetLastError ( ) } ;
278+ if write_result == 0 && last_error != ERROR_IO_PENDING && last_error != ERROR_OPERATION_ABORTED {
279+ return Err ( io:: Error :: last_os_error ( ) ) ;
280+ }
281+ let overlapped_result = unsafe { GetOverlappedResult ( self . handle , & mut overlapped, & mut len, TRUE ) } ;
282+ evt_handle. close ( ) ;
283+
284+ let last_error = unsafe { GetLastError ( ) } ;
285+ if overlapped_result == 0 && last_error != ERROR_OPERATION_ABORTED {
286+ return Err ( io:: Error :: last_os_error ( ) ) ;
222287 }
288+ Ok ( len as usize )
223289 }
224290
225291 fn flush ( & mut self ) -> io:: Result < ( ) > {
0 commit comments