Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > .NET Frameworks (точка нет фреймворки) > C# (си шарп)
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 28.12.2019, 22:26   #1
Kuzya69
Пользователь
 
Регистрация: 20.07.2013
Сообщений: 42
По умолчанию Как избавиться от System.ObjectDisposedException при Close-закрытии зависшего порта

Есть приложение, работающее с устройством на микроконтроллере со встроенным ЮСБ.
Устройство подключено к компьютеру и ОС через виртуальный ком-порт.
В определенные моменты (например для перевода в бутлоадер) устройству нужно отправлять команду на перезагрузку "sendCommand(bReset)".
Так как ЮСБ внутри контроллера, то теряется соединение с устройством, оно как-бы зависает, и не слышит и не отвечает.
Есть вариант восстановить соединение с устройством.
Для этого надо поменять (освободить), занимаемый устройством, СОМ-порт (обязательно закрыв его).
А потом программно Отключить-Задействовать драйвер устройства. Я не стал полностью выкладывать код, слишком много.
Упростил перевключение драйвера, на "ручное", чтобы выбросить кучу ненужного. Состряпал коротенький код, в котором моя проблема явно проявляется.
Фраемворк нельзя использовать выше 4-го (нужно чтобы программа работала и на ВинХР). И сборку делаю под "Any CPU".
Знаю что в последней версии фраемворка, этот баг, с закрытием зависшего порта, Микрософт пофиксил, но не могу использовать этот фраемворк.
Еще информация, когда проверяю код в студии, под отладчиком, этот баг не проявляется, валится только когда работаю без студии.
Причем не влияет, какую я сделал сборку (дебагерную или релизную). То-есть все-таки как-то можно его избежать. Вопрос, КАК?

Как ловится этот баг.
Периодически нажимаю на кнопку "button3".
Не всегда, но в самый неожиданный момент, на произвольном нажатии кнопки, выскакивает окно с исключением.
Вот его данные из журнала событий винды.(оставил самое главное, из-за чего происходит):
Это стек:
System.ObjectDisposedException в ... в ... в.... System.IO.Ports.SerialStream+EventL oopRunner.WaitForCommEvent() ....
Это доп. сведения:
System.ObjectDisposedException не обработано
Message: Необработанное исключение типа "System.ObjectDisposedException " в mscorlib.dll
Дополнительные сведения: Дескриптор SafeHandle был закрыт


Перепробовал уже кучу вариантов, и их комбинаций:
1). Таймауты просто дикие задавал почти после каждой операции с портом.
2). GC.SuppressFinalize(serialPort1.Bas eStream) после открытия порта + GC.ReRegisterForFinalize(serialPort 1.BaseStream) перед закрытием порта.
3). при каждом открытии порта, создавать новый экземпляр его класса.
4). Создавал класс-наследник от SerialPort.
5). Выводил нажатие на кнопку в отдельный поток.
6). В файле "App.config", вставлял строку "<legacyUnhandledExceptionPolic y enabled="1"/>"
Это помогло, но только для ОС выше ВинХР, на ВинХР, валится. Да и это решение очень "скользкое".
Кстати оно натолкнуло на мысль, а можно временно отключить обработчик этого исключения, восстановить порт, а потом опять включить?

Код:
/* Form1.cs */
namespace AppMy
{
    public partial class Form1 : Form
	{
        public Form1()
        {
            InitializeComponent();
            getAvailablePorts_Simple("COM4");   // устанавливаем имя виртуального порта
        }

        private void button3_Click(object sender, EventArgs e)
        {
            try
            {
                string DeviceForRst = serialPort1.PortName; // запоминаем имя текущего порта, чтобы отдать его на перезагрузку драйвера
                if (serialPort1.IsOpen == false) 
				{
					serialPort1.Open();
					Thread.Sleep(1000);
				}
				if (serialPort1.IsOpen == false) {Log("Не смог открыть порт");}
				else
                {
                    getBoxInfo();                         // Получаем информацию об устройстве подключенном к порту
                    sendCommand(bReset);                  // Передаем устройству команду на перезагрузку (драйвер устройства зависает)
                    RestartComPort_Simple(DeviceForRst);  // меняем ком-порт, перезагружаем драйвер зависшего порта, возвращаем ком-порт
                    getBoxInfo();                         // Получаем информацию об устройстве подключенном к порту (проверяем работоспособность)
                }
            }
            catch (Exception ex)
            {
                Log(ex.Message);
            }
        }

        public void RestartComPort_Simple(string NamePort)
        {
            Thread.Sleep(2000);
            getAvailablePorts_Simple(); // сбрасываем имя порта на имя по умолчанию (самое первое из списка)
//================ Начало возможного падения =============================================================
            string sErr = "!!!!Обязательно перезагрузите драйвер ком-порта!!!!!\r\n В диспетчере устройств.\r\n  А потом нажмите 'ОК' в этом окне";
            MessageBox.Show(sErr, "Перезагрузите драйвер:", MessageBoxButtons.OK, MessageBoxIcon.Stop);
            getAvailablePorts_Simple(NamePort); // устанавливаем имя порта в NamePort
//================ Конец возможного падения =============================================================
            Thread.Sleep(2000);
        }

        private void getAvailablePorts_Simple(string sInPort = "ерунда всякая") // несуществующее имя порта
        {
            string[] ports = SerialPort.GetPortNames();
            if (ports.Any(x => x == sInPort) == true)
            {} // есть заданное имя в списке, оставляем заданное имя
            else{sInPort = ports[0];} // Нет заданного имени в списке, берем самый первый по умолчанию
            try
            {
                if (serialPort1.IsOpen == true)
                {
                    //serialPort1.Dispose(true);
                    serialPort1.Close();
                }
            }
            catch (Exception ex)
            {
                Log(ex.Message);
            }
            finally
            {
                serialPort1.PortName = sInPort;
            }
        }
    }
}
/* Form1.Designer.cs */
namespace AppMy
{
    partial class Form1
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used. Очистите все используемые ресурсы.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null)){components.Dispose();}
            base.Dispose(disposing);
        }
        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
		{
			//...........................
            this.serialPort1 = new System.IO.Ports.SerialPort(this.components);
			//...........................
            this.serialPort1.BaudRate = 115200;
            this.serialPort1.DtrEnable = true;
            this.serialPort1.Handshake = System.IO.Ports.Handshake.XOnXOff;
            this.serialPort1.RtsEnable = true;
			//...........................
		}
        #endregion
        private System.Windows.Forms.Button button3;
    }
}
/* Program.cs */
namespace AppMy
{
    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }
    }
}

Последний раз редактировалось Kuzya69; 28.12.2019 в 22:41.
Kuzya69 вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Зависает форма при закрытии порта Принтер C# (си шарп) 1 24.12.2015 15:15
Сниффер COM-порта или программное создание виртуального COM-порта Oleg_Ponomaryov Общие вопросы C/C++ 4 12.06.2015 09:28
Перезапуск зависшего приложения Val Rubis Общие вопросы Delphi 14 09.08.2012 07:27
Ошибка при запуске: This system does not support fullscreen mode. Choose 'Close' to terminate the application. afirat Паскаль, Turbo Pascal, PascalABC.NET 3 07.05.2012 05:45
Ошибка Ambiguity between '_fastcall System::operator +(int,const System::Variant &)' and '_fastcall System::opera Jawner C++ Builder 1 12.04.2012 09:58