2012-03-23 24 views
9

Tengo un pequeño problema con un escáner de código de barras USB. Estoy utilizando el escáner con la clase "SerialPort":Liberación de un puerto serie virtual desconectado

 this._barcodeScanner = new SerialPort(comPort, 9600, Parity.None, 8, StopBits.One) { Handshake = Handshake.None, ReadTimeout = 500, WriteTimeout = 500 }; 
     this._barcodeScanner.Open(); 
     this._barcodeScanner.DataReceived += BarcodeScannerCallback; 

Si desconecto el dispositivo USB mientras it abrieron a través de la clase "SerialPort", no puedo cerrar el software correctamente y el puerto virtual permanece abierto por toda la eternidad o hasta que reinicie toda la computadora.

Así que mi pregunta es, ¿hay alguna forma de cerrar el puerto virtual después de desconectar el dispositivo a través del código C#?

Saludos

[editar # 1]

Alrighty, algo más de código:

De esta manera estoy comprobando cada 10 segundos si el dispositivo está enchufado:

private bool CheckUsbDeviceAvailability() 
    { 
     ManagementObjectSearcher searcher = new ManagementObjectSearcher("root\\WMI", 
     "SELECT * FROM MSSerial_PortName WHERE PortName = '" + this.PortName + "'"); 

     if (searcher.Get().Count > 0) 
      return true; 
     return false; 
    } 

Ese es el evento de devolución de llamada del puerto serie:

void BarcodeScannerCallback(object sender, SerialDataReceivedEventArgs e) 
    { 
     Thread.Sleep(500); 
     string data = this._barcodeScanner.ReadExisting().Replace(Convert.ToChar(2), Convert.ToChar(32)).Trim(); 
     if (data.StartsWith("AX")) 
     { 
      string[] arrData = data.Split('\n'); 
      this._barcodeScanner.StopAvailabilityThread(); 
      Barcode code = new Barcode(arrData[0].Replace("\r", "")); 

      if (CheckIfBarcodeExists(code)) 
       this.UpdateBarcodeNode(code); 
      else 
       this.CreateBarcodeNode(code); 

      BarcodeScannerCallbackEvent(sender, e, code); 
      this._barcodeScanner.StartAvailabilityThread(); 
     } 

     this._barcodeScanner.ComDevicePluggedIn = ScannerDevice.ComAvailabilityState.Available; 
    } 

si es imposible responder más que se disparará el "DeviceNotAvailableEvent()":

void BarcodeScannerDeviceNotAvailableEvent() 
    { 
     this._barcodeScanner.Close(); 
     this._barcodeScanner.Dispose(); 
    } 

He imponerse a la dirección de eventos Disponer de la clase "SerialPort" para que se inunda va a abortar el hilo:

protected override void Dispose(bool isDisposing) 
    { 
     if (isDisposing) 
     { 
      this._deviceAvailableThread.Abort(); 

     } 

     base.Dispose(isDisposing); 
    } 
+0

¿Qué intenta cerrar el puerto serie cuando el dispositivo se ha desconectado? –

+0

Cuando el dispositivo está desenchufado, estoy abortando todos los hilos, que pertenecen de alguna manera al dispositivo; Cierro el SerialPort mismo (que no arroja un error) y estoy desechando el objeto –

+0

¿se puede mostrar más código? – Reniuz

Respuesta

22

Los puertos serie datan de la edad de piedra de la informática. Ahí es donde enchufaste tu teletipo ASR-33 para comenzar a escribir en tu programa Fortran. La interfaz eléctrica es muy simple. También lo es la API de Windows para usar un puerto serie desde su propio código. Prácticamente cualquier entorno de tiempo de ejecución los respalda.

El USB ha reemplazado por completo el hardware del puerto serie. Tiene una interfaz lógica mucho más avanzada para la máquina, compatible con muchos tipos diferentes de dispositivos. Y admite Plug and Play, lo que permite que el sistema operativo detecte cuándo se conecta o quita un dispositivo, así como la instalación automática del controlador del dispositivo, etcétera.

Esta flexibilidad tiene un precio, sin embargo, un dispositivo USB siempre necesita un controlador de dispositivo para ser utilizable. Los controladores del dispositivo son no creados iguales. Los diferentes controladores requieren diferentes formas de hablar con el dispositivo. Usualmente se hace a través de DeviceIoControl() o Read/WriteFile() pero esas son funciones de API muy opacas. En los primeros días del USB, los fabricantes de dispositivos proporcionaban una DLL que proporcionaba una API enriquecida para ocultar los detalles de la implementación.

Eso no funcionó tan bien, los fabricantes no son muy buenos escribiendo buenas API y seguro que no les gusta apoyarlos ellos. Entonces, una buena solución sería admitir una API estándar, una que esté disponible en cualquier máquina, compatible con cualquier tiempo de ejecución, documentada y mantenida por otra persona. Al igual que la API del puerto serie.

Eso no funcionó tan bien, los fabricantes no son muy buenos para escribir controladores de dispositivos que emulan puertos serie. El mayor problema con la API es que no tiene soporte para Plug and Play. Falta el núcleo de soporte, después de que todo el hardware del puerto serial no tiene la interfaz lógica para soportarlo.Hay compatibilidad con algunos para detectar que un dispositivo está conectado a través de la línea de handshake de hardware DTR, pero no admite para detectar que el puerto ya no está allí.

Separar el dispositivo USB es el problema. En un mundo ideal, el emulador incorporado en el controlador del dispositivo simplemente simularía que el puerto en serie aún está allí hasta que se cierre el último identificador del dispositivo. Esa sería la implementación lógica, dado que no hay forma de desencadenar un evento Plug and Play. Por alguna extraña razón que parece ser difícil de implementar. La mayoría de los controladores USB toman el atajo crummy, simplemente hacen que el dispositivo desaparezca incluso mientras está en uso.

Esto hace estragos en cualquier código de modo de usuario que use el dispositivo. Que normalmente está escrito para suponer que es un puerto serie real y los puertos serie reales no desaparecen de repente. Al menos no sin dibujar una brillante chispa azul. Lo que sale mal es bastante impredecible porque depende de cómo responde el conductor a las solicitudes en un dispositivo que ya no está allí. Una excepción no detectable en un hilo de trabajo iniciado por SerialPort fue un error común. Parece que su controlador realmente se equivoca, genera un código de retorno de error en la solicitud del controlador MJ_CLOSE. Lo cual es algo lógico que se debe hacer por un controlador, después de todo, el dispositivo ya no está allí, pero es bastante insoluble desde su final. Usted tiene un mango y no puede cerrarlo. Eso es un arroyo sin remo.

Cada versión principal de .NET tenía un pequeño parche para las clases de SerialPort para intentar minimizar un poco la miseria. Pero hay una cantidad limitada que Microsoft puede hacer, detectar todos los errores y fingir que no sucedieron finalmente lleva a una clase que ya no brinda un buen diagnóstico, incluso con un buen controlador.

enfoques prácticos Así son:

  • siempre utilice la opción Quitar hardware con seguridad icono de la bandeja de Windows
  • usar la versión más reciente de .NET
  • contacto con el vendedor y pida una actualización del controlador
  • vendedores de zanjas que suministran controladores pésimos
  • dicen a sus usuarios que, simplemente porque es el solamente cosa que puede hacer con un dispositivo USB, que desenchufar no resuelve ningún problema
  • maquillaje cerrar el puerto fácil y accesible en la interfaz de usuario
  • pegue el conector USB al puerto por lo que no se puede quitar

La quinta viñeta también es lo que hace que los programadores tengan problemas. Escribir código de puerto serie no es fácil, es muy asíncrono y el hilo de subprocesos que ejecuta el evento DataReceived es difícil de tratar. Cuando no puede diagnosticar el problema del software, tiende a culpar al hardware. Hay muy poco que pueda hacer con el hardware, pero desenchúfelo. Mala idea. Ahora tienes dos problemas.

+0

bien, así que ya no tengo que buscar el problema de mi lado. Entender los puertos serie es mucho más claro para mí ahora, gracias por eso;) –

+2

Esta es una respuesta muy completa. Esta debería ser la respuesta canónica para este tipo de pregunta. –

+1

-1 para "USB ha reemplazado completamente el hardware del puerto serie". como una declaración general. –

0

Este problema existe en .Net 2, 3, 3.5 puede utilizar marco 4 (problema no existe en .NET 4)

+1

Sé que esta es una respuesta de hace 2 años ... Si todavía está allí, ¿le importaría a usted (oa cualquier otra persona) dar detalles? –

Cuestiones relacionadas