private void WriteMain(byte[] buf, int offset, int length) { byte[] bufToWrite; while (length > 0) { if (offset != 0) { bufToWrite = new byte[length]; Buffer.BlockCopy(buf, offset, bufToWrite, 0, length); } else { bufToWrite = buf; } int wroteLength = 0; GCHandle wroteLengthPinned = GCHandle.Alloc(wroteLength, GCHandleType.Pinned); int transferredLength = 0; GCHandle transferredLengthPinned = GCHandle.Alloc(transferredLength, GCHandleType.Pinned); NativeOverlapped writeOverlapped = new NativeOverlapped(); writeOverlapped.EventHandle = _writeOverlappedEvent.SafeWaitHandle.DangerousGetHandle(); GCHandle writeOverlappedPinned = GCHandle.Alloc(writeOverlapped, GCHandleType.Pinned); GCHandle bufToWritePinned = GCHandle.Alloc(bufToWrite, GCHandleType.Pinned); // Note: // GCHandle.Alloc(<struct>, GCHandleType.Pinned) makes a GCHandle for `Boxed' struct object. // So if you want to read a value of the struct, you have to read it from `Boxed' struct object // which is returned by GCHandle.Target. try { bool success = Win32Serial.WriteFile( _fileHandle, bufToWritePinned.AddrOfPinnedObject(), length, wroteLengthPinned.AddrOfPinnedObject(), writeOverlappedPinned.AddrOfPinnedObject()); if (!success) { int lastErr = Marshal.GetLastWin32Error(); if (lastErr != Win32.ERROR_IO_PENDING) { throw new IOException("WriteFile failed for " + lastErr); } success = Win32Serial.GetOverlappedResult( _fileHandle, writeOverlappedPinned.AddrOfPinnedObject(), transferredLengthPinned.AddrOfPinnedObject(), true); if (!success) { lastErr = Marshal.GetLastWin32Error(); throw new Exception("GetOverlappedResult failed " + lastErr); } wroteLength = (int)transferredLengthPinned.Target; // copy from pinned `boxed' Int32 } else { wroteLength = (int)wroteLengthPinned.Target; // copy from pinned `boxed' Int32 } } finally { wroteLengthPinned.Free(); transferredLengthPinned.Free(); writeOverlappedPinned.Free(); bufToWritePinned.Free(); } offset += wroteLength; length -= wroteLength; } }
private void AsyncEntry() { const int EV_RXCHAR = 1; ManualResetEvent commEventOverlappedEvent = null; ManualResetEvent readOverlappedEvent = null; try { commEventOverlappedEvent = new ManualResetEvent(false); readOverlappedEvent = new ManualResetEvent(false); NativeOverlapped commEventOverlapped = new NativeOverlapped(); commEventOverlapped.EventHandle = commEventOverlappedEvent.SafeWaitHandle.DangerousGetHandle(); NativeOverlapped readOverlapped = new NativeOverlapped(); readOverlapped.EventHandle = readOverlappedEvent.SafeWaitHandle.DangerousGetHandle(); GCHandle commEventOverlappedPinned = GCHandle.Alloc(commEventOverlapped, GCHandleType.Pinned); // Pin a boxed NativeOverlapped GCHandle readOverlappedPinned = GCHandle.Alloc(readOverlapped, GCHandleType.Pinned); // Pin a boxed NativeOverlapped int commFlags = 0; GCHandle commFlagsPinned = GCHandle.Alloc(commFlags, GCHandleType.Pinned); // Pin a boxed Int32 int readLength = 0; GCHandle readLengthPinned = GCHandle.Alloc(readLength, GCHandleType.Pinned); // Pin a boxed Int32 int transferredLength = 0; GCHandle transferredLengthPinned = GCHandle.Alloc(transferredLength, GCHandleType.Pinned); // Pin a boxed Int32 byte[] buf = new byte[128]; GCHandle bufPinned = GCHandle.Alloc(buf, GCHandleType.Pinned); // Note: // GCHandle.Alloc(<struct>, GCHandleType.Pinned) makes a GCHandle for `Boxed' struct object. // So if you want to read a value of the struct, you have to read it from `Boxed' struct object // which is returned by GCHandle.Target. try { bool success = false; success = Win32Serial.ClearCommError(_fileHandle, IntPtr.Zero, IntPtr.Zero); if (!success) { throw new Exception("ClearCommError failed " + Marshal.GetLastWin32Error()); } //このSetCommMaskを実行しないとWaitCommEventが失敗してしまう success = Win32Serial.SetCommMask(_fileHandle, 0); if (!success) { throw new Exception("SetCommMask failed " + Marshal.GetLastWin32Error()); } success = Win32Serial.SetCommMask(_fileHandle, EV_RXCHAR); if (!success) { throw new Exception("SetCommMask failed " + Marshal.GetLastWin32Error()); } while (true) { commFlags = 0; commFlagsPinned.Target = commFlags; // Pin a new boxed Int32 transferredLength = 0; transferredLengthPinned.Target = transferredLength; // Pin a new boxed Int32 commEventOverlappedPinned.Target = commEventOverlapped; // Pin a new boxed NativeOverlapped success = Win32Serial.WaitCommEvent( _fileHandle, commFlagsPinned.AddrOfPinnedObject(), commEventOverlappedPinned.AddrOfPinnedObject()); if (!success) { int lastErr = Marshal.GetLastWin32Error(); if (lastErr == Win32.ERROR_INVALID_HANDLE) { goto CLOSED; // closed in another thread ? } if (lastErr != Win32.ERROR_IO_PENDING) { throw new Exception("WaitCommEvent failed " + lastErr); } success = Win32Serial.GetOverlappedResult( _fileHandle, commEventOverlappedPinned.AddrOfPinnedObject(), transferredLengthPinned.AddrOfPinnedObject(), true); if (!success) { lastErr = Marshal.GetLastWin32Error(); if (lastErr == Win32.ERROR_INVALID_HANDLE || lastErr == Win32.ERROR_OPERATION_ABORTED) { goto CLOSED; // closed in another thread ? } throw new Exception("GetOverlappedResult failed " + lastErr); } } if ((int)commFlagsPinned.Target != EV_RXCHAR) { goto CLOSED; } while (true) { readLength = 0; readLengthPinned.Target = readLength; // Pin a new boxed Int32 transferredLength = 0; transferredLengthPinned.Target = transferredLength; // Pin a new boxed Int32 readOverlappedPinned.Target = readOverlapped; // Pin a new boxed NativeOverlapped success = Win32Serial.ReadFile( _fileHandle, bufPinned.AddrOfPinnedObject(), buf.Length, readLengthPinned.AddrOfPinnedObject(), readOverlappedPinned.AddrOfPinnedObject()); if (!success) { int lastErr = Marshal.GetLastWin32Error(); if (lastErr == Win32.ERROR_INVALID_HANDLE) { goto CLOSED; // closed in another thread ? } if (lastErr != Win32.ERROR_IO_PENDING) { throw new Exception("ReadFile failed " + lastErr); } success = Win32Serial.GetOverlappedResult( _fileHandle, readOverlappedPinned.AddrOfPinnedObject(), transferredLengthPinned.AddrOfPinnedObject(), true); if (!success) { lastErr = Marshal.GetLastWin32Error(); if (lastErr == Win32.ERROR_INVALID_HANDLE || lastErr == Win32.ERROR_OPERATION_ABORTED) { goto CLOSED; // closed in another thread ? } throw new Exception("GetOverlappedResult failed " + lastErr); } readLength = (int)transferredLengthPinned.Target; // copy from pinned `boxed' Int32 } else { readLength = (int)readLengthPinned.Target; // copy from pinned `boxed' Int32 } if (readLength <= 0) { break; } _dataFragment.Set(buf, 0, readLength); _callback.OnReception(_dataFragment); } } } finally { commEventOverlappedPinned.Free(); readOverlappedPinned.Free(); commFlagsPinned.Free(); readLengthPinned.Free(); transferredLengthPinned.Free(); bufPinned.Free(); } CLOSED: ; } catch (Exception ex) { if (!_parent.IsClosed) { _callback.OnAbnormalTermination(ex.Message); } } finally { if (commEventOverlappedEvent != null) { commEventOverlappedEvent.Close(); } if (readOverlappedEvent != null) { readOverlappedEvent.Close(); } } }