c# - serialdatareceivedeventhandler - Problema con SerialPort
serial port in c# (6)
Puede heredar de SerialPort y anular el método Dispose () para manejar tales excepciones. Solo puedes engullir la excepción (Dispose no debería lanzarse de todos modos).
Si desea registrar la excepción o manejarla de alguna otra forma, primero deberá verificar el indicador de eliminación . Si es falso significa que Dispose fue llamado por el destructor de SerialPort y el objeto ya está huérfano.
P.ej
public class MySerialPort:SerialPort
{
protected override void Dispose(bool disposing)
{
try
{
base.Dispose(disposing);
}
catch (Exception exc )
{
if (disposing)
{
//Log the error
}
}
}
}
Estoy trabajando con SerialPort para comunicarme (solo lectura) con un lector de código de barras.
He instalado el controlador para que funcione con el lector como si estuviera conectado a través de Com-port, aunque es un dispositivo usb. Cuando el dispositivo está enchufado, aparece otro Com-port en la lista.
El problema es el siguiente. Inicializo el objeto SerialPort para leer desde el lector de códigos de barras, pero si el lector está desenchufado, no tengo forma de finalizar o eliminar el objeto SerialPort correctamente, porque el puerto al que está "conectado" ya no existe.
El resultado es WinIOException cuando el programa está cerrado. No puedo capturarlo no solo en el código que trabaja con SerialPort sino también en el nivel de program.cs. De acuerdo con la pila WinIOException se lanza después de los intentos de finalizar y eliminar el objeto SerialPort.
¿Hay alguna idea de cómo puedo operar con esta situación de manera adecuada? ¿O al menos para atrapar la excepción?
Lo que sé con certeza es que el problema no está en este controlador en particular; Tenía otro lector de código de barras de otro fabricante (con el mismo controlador de propósito): la situación es la misma.
Suspiro, este es un problema antiguo con emuladores de puertos serie USB. Los puertos serie son dispositivos que datan de la edad de piedra. Solían atornillarse en el autobús, no hay manera de eliminarlos mientras un programa lo está utilizando sin provocar chispas ni producir humo. La edad de piedra también incluye la falta de cualquier tipo de compatibilidad plug-and-play para que un programa pueda detectar que el dispositivo se vuelve repentinamente gonzo.
Desafortunadamente, la mayoría de los controladores de dispositivo defectuosos que los emulan simplemente los hacen desaparecer, aunque un programa tenga el puerto abierto. Esto funciona tan bien como sacar una unidad flash del zócalo cuando Windows está escribiendo archivos en ella. Hay un hilo de trabajo en segundo plano que espera las notificaciones del controlador del dispositivo para que pueda generar los eventos DataReceived, ErrorReceived y PinChanged. Ese hilo sufre un ataque al corazón cuando el dispositivo desaparece de repente. No puedes atraparlo, es un hilo que fue iniciado por la clase SerialPort, no puedes envolverlo con try / catch.
Por demanda popular, Microsoft hizo algo al respecto en .NET 4.0. No estoy seguro de qué sucede en ese lanzamiento. Si está atascado en una versión anterior, la única cosa razonable que puede hacer es colocar un letrero junto a la ranura USB: "¡No lo extraiga mientras está en uso!" Lo que inevitablemente hace que alguien desenchufe el dispositivo al menos dos veces para ver qué pasa. Después de lo cual se aburren con eso y te dejan en paz.
La solución muy irracional es un archivo app.exe.config con este contenido:
<?xml version ="1.0"?>
<configuration>
<runtime>
<legacyUnhandledExceptionPolicy enabled="1"/>
</runtime>
</configuration>
No lo uses
Bueno, malas noticias.
La solución de Panagiotis Kanavos no ayuda. El problema sigue aquí.
.Net 4.0 tampoco ayuda. He instalado VS2010, nada ha cambiado. La excepción no retirada todavía se lanza. Desafortunadamente, "colocar una cinta adhesiva junto a la ranura USB:" ¡No extraer mientras está en uso! "Parece ser la única decisión ...
En mi código, esto sucede como parte del método Finalize()
en el BaseStream, que es llamado por el recolector de basura.
Como tal, si uno hereda la clase .NET SerialPort y anula el Abrir / Cerrar, puede hacer lo siguiente:
Durante el Open, simplemente llame a GC.SuppressFinalize(Me.BaseStream)
Durante el cierre, intente llamar a GC.ReRegisterForFinalize(Me.BaseStream)
Si el USB se ha extraído, se lanzará una excepción, quejándose sobre el acceso al BaseStream. Verifique la propiedad .IsOpen
antes de llamar al GC
, o envuélvalo en un Try
Catch
si no confía en .IsOpen
para devolver False cada vez ...
Eso resolverá, su aplicación manejará el hecho de que se ha extraído y no se bloqueará cuando cierre.
Actualmente no puedo hacerlo y luego volver a abrir el puerto si está conectado de nuevo, pero al menos hay un progreso más allá de una etiqueta que dice no tocar ...
He tenido la misma experiencia. Aunque no se recomienda, puede desenchufar y conectar un dispositivo serie a un puerto en serie real y la comunicación comenzará de nuevo. Un puerto serie USB no funciona de esta manera. También he tenido el problema de que el puerto serial USB no aparece como un puerto disponible mediante el método SerialPort.GetPortNames () hasta que el software crea una instancia del puerto serie virtual.
Resolví este problema creando un proceso separado que maneja el puerto serie. Cuando el puerto serie está desenchufado, reinicio el proceso. Ahora puedo volver a conectarme a un dispositivo de puerto serie desenchufado sin reiniciar la aplicación principal.
TLDR; Crea un proceso separado.
Código de ejemplo
Código de proceso del puerto serial
static void Main(string[] args)
{
using (var output = Console.OpenStandardOutput())
using (var serialPort = new SerialPort(args[0], int.Parse(args[1])))
{
serialPort.Open();
while (serialPort.IsOpen)
{
serialPort.BaseStream.CopyTo(output);
}
}
}
Aplicación principal
var options = new ProcessStartInfo()
{
FileName = "Serial Port Process name here",
UseShellExecute = false,
RedirectStandardOutput = true,
};
using(var process = Process.Start(options))
{
using (StreamReader reader = process.StandardOutput)
{
while (!process.HasExited)
{
string result = reader.ReadLine();
Console.WriteLine(result);
}
}
}