_portHandle = CreateFile(
@$"\\.\\{_portName}", // Serial port name (e.g., \\.\COM1)
GENERIC_READ | GENERIC_WRITE, // Access mode
0, // Share mode
IntPtr.Zero, // Security attributes
OPEN_EXISTING, // Open existing
FILE_FLAG_OVERLAPPED, // Overlapped mode for asynchronous I/O
IntPtr.Zero // Template file (must be NULL for serial ports)
);
Код обрабатывает операции ввода-вывода в потоке с использованием NativeOverlapped:
private void ReadThread(CancellationToken token)
{
IntPtr overlappedPtr = IntPtr.Zero;
try
{
IntPtr portHandle = _portHandle;
SetupComPort(portHandle);
var buffer = new byte[16 * 1024];
uint eventMask = 0;
using var waitEvent = new ManualResetEvent(false);
var overlapped = new NativeOverlapped
{
OffsetLow = 0,
OffsetHigh = 0,
EventHandle = waitEvent.SafeWaitHandle.DangerousGetHandle()
};
overlappedPtr = Marshal.AllocHGlobal(Marshal.SizeOf());
Marshal.StructureToPtr(overlapped, overlappedPtr, false);
while (!token.IsCancellationRequested)
{
if (WaitCommEvent(portHandle, ref eventMask, ref overlapped))
{
if ((eventMask & EVRXCHAR) != 0)
{
ReadFile(portHandle, buffer, (uint)buffer.Length, out uint bytesRead, overlappedPtr);
// Process incoming data
}
}
}
}
finally
{
if (overlappedPtr != IntPtr.Zero)
{
Marshal.FreeHGlobal(overlappedPtr); // Cleanup memory
}
}
}
Что я пробовал до сих пор:
- Ручное управление памятью:
Используется Marshal.AllocHGlobal и Marshal.FreeHGlobal для NativeOverlapped.
Гарантируется правильное выделение и освобождение NativeOverlapped.
Потокобезопасность: - Критические операции заключены в блокировки.
- Проверено наличие ошибок, таких как ERROR_IO_PENDING, и корректно обработано.
Подробнее здесь: https://stackoverflow.com/questions/793 ... lapped-i-o