The task is to write an application that works with a pool of COM ports to which modems are connected. First, choose a free modem:
for (int i = 0; i < lstPorts.Count; i++) { if (lstPorts[i].Status == "Ожидает") { PortNum = lstPorts[i].Title; lstPorts[i].Status = "В работе"; break; } } Then, in the same procedure, the modem polling procedure is called.
await Task.Run(() => ModemPolling(PortNum)); This procedure first selects the modem number, then calls the procedure for working with the COM port and modem (located in another class)
async void ModemPolling(string PortN) { int Jp = lstModem.Items.Count; phModel phMod; string telN=string.Empty; string SNum=string.Empty; clsProcess proc; proc = new clsProcess(); proc.onStr += onProcStr; proc.onEnd += onEndProc; for (int j = 0; j < Jp; j++) { phMod = (phModel)lstModem.Items[j]; if (phMod.Status == 0) { Dispatcher.Invoke(new Action(() => ((phModel)lstModem.Items[j]).Status = 1)); telN = ((phModel)lstModem.Items[j]).PnoneN; SNum = ((phModel)lstModem.Items[j]).SerialN; break; } } await Task.Run(() => proc.ModemProc(PortN, telN, SNum)); } Auxiliary modem number class
public class phModel { string _serialN; string _pnoneN; int _hResult; int _status; int _pError; //серийный номер public string SerialN { get => _serialN; set=>_serialN = value; } //телефонный номер public string PnoneN { get => _pnoneN; set=>_pnoneN = value; } //результат выполнения операции public int HResult { get => _hResult; set=>_hResult = value; } //статус модема (свободен, занят, завершил работу, ошибка) public int Status { get => _status; set=>_status = value; } //код ошибки public int PError { get => _pError; set=>_pError = value; } public void SetStatus(int inSt) { _status = inSt; } } And actually, the very procedure of working with a modem
public void ModemProc(string portNum, string telNum, string serialN) { portNumber = portNum; TelNum = telNum; SNumber = serialN; try { _port = new SerialPort(portNum) { BaudRate = _speed, Parity = _stParity, WriteTimeout = _tsT, ReadTimeout = _rsT, StopBits = _stBits, DataBits = _dBits, Handshake = Handshake.XOnXOff, DtrEnable = true, RtsEnable = true, NewLine = Environment.NewLine, DiscardNull = true }; if (!_port.IsOpen) _port.Open(); _port.DataReceived += _port_DataReceived; var na = new NotifyArgs(1, 1, "Порт " + portNum + " открыт.", 0, portNumber, TelNum); onStr?.Invoke(na); Thread.Sleep(500); int pRes = ModemConnect(telNum); } catch { } } public void PortClose(string pNum) { if (_port.IsOpen) _port.Close(); var na = new NotifyArgs(1, 2, "Порт " + pNum + " закрыт.", 0, portNumber, TelNum); onStr?.Invoke(na); Thread.Sleep(500); } int ModemConnect(string modemNum) { _port.Write("+++\r\n"); _port.Write("ATE1\r\n"); Thread.Sleep(500); _port.Write("ATH0\r\n"); // установка режима ожидания Thread.Sleep(500); _port.Write("AT+IFC=0,2\r\n"); // устанавливается режим контроля над передачей Thread.Sleep(500); _port.Write("at+cbst=7,0,1\r\n"); // устанавливается прозрачный режим Thread.Sleep(500); if (!Regex.IsMatch(modemNum, @"(8|\+)9[0-9]{9}")) return 11; _port.Write("ATDT " + modemNum + "\r\n" + " "); return 0; } void modemDisconnect() { try { Thread.Sleep(1000); _port.Write("+++\r\n"); Thread.Sleep(500); _port.WriteLine("ATH0\r\n"); // установка режима ожидания Thread.Sleep(500); } catch { } } NotifyArgs is a helper class that passes information to the main form of the application.
Calls to the modemDisconnect () and PortClose () methods are located at the end of the methods that process the data received from the modem.
In synchronous mode (for one COM port) everything works fine. But I need to use all the free modems of the pool (which have the status of "Pending"). Actually, the program is written for asynchronous mode.
However, in practice, very often (but not every time) an application crashes with an error
System.ObjectDisposedException: 'Дескриптор SafeHandle был закрыт' Error log
System.ObjectDisposedException HResult=0x80131622 Message=Дескриптор SafeHandle был закрыт Source=mscorlib StackTrace: at System.Runtime.InteropServices.SafeHandle.DangerousAddRef(Boolean& success) at System.StubHelpers.StubHelpers.SafeHandleAddRef(SafeHandle pHandle, Boolean& success) at Microsoft.Win32.UnsafeNativeMethods.GetOverlappedResult(SafeFileHandle hFile, NativeOverlapped* lpOverlapped, Int32& lpNumberOfBytesTransferred, Boolean bWait) at System.IO.Ports.SerialStream.EventLoopRunner.WaitForCommEvent() at System.Threading.ThreadHelper.ThreadStart_Context(Object state) at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Threading.ThreadHelper.ThreadStart() Error occurs after trying to execute a line of code
_port.Write("ATDT " + modemNum + "\r\n" + " "); I have been struggling with the problem for the fourth day. On the Internet, adequate information about SafeHandle and how to fight it was never found .. Can someone tell me what to do ..