Trabajar con dispositivos USB en .NET

Utilizando .Net (C#), ¿cómo se puede trabajar con dispositivos USB?

Cómo se puede detectar eventos USB (conexiones/desconexiones) y cómo comunicarse con los dispositivos (lectura/escritura).

Hay un nativo .Net solución para ello?

12 Kommentare

  1. 21

    No hay nativo (por ejemplo, las bibliotecas del Sistema) solución para esto. Esa es la razón por la que SharpUSBLib existe, como es mencionado por moobaa.

    Si desea deshacer su propio controlador para dispositivos USB, usted puede comprobar fuera de la Clase SerialPort de Sistema.IO.Puertos.

    • ¿Cómo se puede utilizar el puerto USB a través de la clase SerialPort?
    • Así, en el ’08 USB 1.0 fue corriendo de un puerto serial de la tecnología. 😀 No está seguro de cómo hacer esto con USB 2.0 y USB 3.0
    • Yo sólo uso CreateFile winapi para acceder a usb 🙂
  2. 26

    He intentado usar SharpUSBLib y la pata de mi equipo (se necesita una restauración del sistema). Le pasó a un compañero de trabajo en el mismo proyecto.

    He encontrado una alternativa en LibUSBDotNet: http://sourceforge.net/projects/libusbdotnet
    Aun no lo usaba mucho, pero parece bueno y actualizado recientemente (a diferencia de Sharp).

    EDIT: a partir de mediados de febrero de 2017, LibUSBDotNet fue actualizada sobre 2 semanas. Mientras tanto SharpUSBLib no ha sido actualizado desde el año 2004.

  3. 12

    He utilizado el siguiente código para detectar cuando los dispositivos USB se conecta y se desconecta de mi equipo:

    class USBControl : IDisposable
        {
            //used for monitoring plugging and unplugging of USB devices.
            private ManagementEventWatcher watcherAttach;
            private ManagementEventWatcher watcherRemove;
    
            public USBControl()
            {
                //Add USB plugged event watching
                watcherAttach = new ManagementEventWatcher();
                //var queryAttach = new WqlEventQuery("SELECT * FROM Win32_DeviceChangeEvent WHERE EventType = 2");
                watcherAttach.EventArrived += new EventArrivedEventHandler(watcher_EventArrived);
                watcherAttach.Query = new WqlEventQuery("SELECT * FROM Win32_DeviceChangeEvent WHERE EventType = 2");
                watcherAttach.Start();
    
                //Add USB unplugged event watching
                watcherRemove = new ManagementEventWatcher();
                //var queryRemove = new WqlEventQuery("SELECT * FROM Win32_DeviceChangeEvent WHERE EventType = 3");
                watcherRemove.EventArrived += new EventArrivedEventHandler(watcher_EventRemoved);
                watcherRemove.Query = new WqlEventQuery("SELECT * FROM Win32_DeviceChangeEvent WHERE EventType = 3");
                watcherRemove.Start();
            }
    
            ///<summary>
            ///Used to dispose of the USB device watchers when the USBControl class is disposed of.
            ///</summary>
            public void Dispose()
            {
                watcherAttach.Stop();
                watcherRemove.Stop();
                //Thread.Sleep(1000);
                watcherAttach.Dispose();
                watcherRemove.Dispose();
                //Thread.Sleep(1000);
            }
    
            void watcher_EventArrived(object sender, EventArrivedEventArgs e)
            {
                Debug.WriteLine("watcher_EventArrived");
            }
    
            void watcher_EventRemoved(object sender, EventArrivedEventArgs e)
            {
                Debug.WriteLine("watcher_EventRemoved");
            }
    
            ~USBControl()
            {
                this.Dispose();
            }
    
    
        }

    Asegúrese de llamar al método Dispose() cuando se cierra la aplicación. De lo contrario, recibirá un objeto COM de error en tiempo de ejecución cuando se cierra.

  4. 4

    Me gustaría recomendar LibUSBDotNet, la biblioteca que he estado usando durante 2 años.
    Si usted tiene que trabajar con un dispositivo USB (enviar solicitudes, respuestas de proceso), esta biblioteca es la mejor solución que he podido encontrar.

    Pros:

    • Tiene todos los métodos que usted necesita para trabajar en sintonía o asincrónico modo.
    • Código fuente proporcionado
    • De muestras suficientes para empezar a usarlo de inmediato.

    Contras:

    • La pobre documentación (es problema común para los proyectos de código abierto). Básicamente, usted puede encontrar apenas común descripción de los métodos en el archivo de ayuda CHM y eso es todo.
      Pero me sigue pareciendo siempre que las muestras y el código fuente es suficiente para la codificación.
      A veces sólo veo un comportamiento extraño y quieren saber por qué fue puesto en marcha en este camino y no se puede obtener incluso una pista…
    • Parece incompatible más. La última versión se publicó en Octubre de 2010. Y es difícil obtener respuestas a veces.
  5. 2

    Dispositivos USB por lo general se dividen en dos categorías: Hid, y USB. Un dispositivo USB puede o no puede ser un dispositivo Hid y viceversa. Hid es generalmente un poco más fácil trabajar con más directa de USB. Diferentes plataformas tienen diferentes APIs para tratar tanto USB y se Escondió.

    Aquí está la documentación para UWP:

    USB:
    https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/how-to-connect-to-a-usb-device–uwp-app-

    Hid:
    https://docs.microsoft.com/en-us/uwp/api/windows.devices.humaninterfacedevice

    Aquí está la documentación para Android:
    https://developer.xamarin.com/api/namespace/Android.Hardware.Usb/

    Aquí son de dos clases para tratar con USB/Escondió en el raw de la API de Windows a nivel de:

    https://github.com/MelbourneDeveloper/Device.Net/blob/master/src/Hid.Net/Windows/HidAPICalls.cs

    public static class HidAPICalls 
    {
        #region Constants
        private const int DigcfDeviceinterface = 16;
        private const int DigcfPresent = 2;
        private const uint FileShareRead = 1;
        private const uint FileShareWrite = 2;
        private const uint GenericRead = 2147483648;
        private const uint GenericWrite = 1073741824;
        private const uint OpenExisting = 3;
        private const int HIDP_STATUS_SUCCESS = 0x110000;
        private const int HIDP_STATUS_INVALID_PREPARSED_DATA = -0x3FEF0000;
        #endregion
    
        #region API Calls
    
        [DllImport("hid.dll", SetLastError = true)]
        private static extern bool HidD_GetPreparsedData(SafeFileHandle hidDeviceObject, out IntPtr pointerToPreparsedData);
    
        [DllImport("hid.dll", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
        private static extern bool HidD_GetManufacturerString(SafeFileHandle hidDeviceObject, IntPtr pointerToBuffer, uint bufferLength);
    
        [DllImport("hid.dll", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
        private static extern bool HidD_GetProductString(SafeFileHandle hidDeviceObject, IntPtr pointerToBuffer, uint bufferLength);
    
        [DllImport("hid.dll", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
        private static extern bool HidD_GetSerialNumberString(SafeFileHandle hidDeviceObject, IntPtr pointerToBuffer, uint bufferLength);
    
        [DllImport("hid.dll", SetLastError = true)]
        private static extern int HidP_GetCaps(IntPtr pointerToPreparsedData, out HidCollectionCapabilities hidCollectionCapabilities);
    
        [DllImport("hid.dll", SetLastError = true)]
        private static extern bool HidD_GetAttributes(SafeFileHandle hidDeviceObject, out HidAttributes attributes);
    
        [DllImport("hid.dll", SetLastError = true)]
        private static extern bool HidD_FreePreparsedData(ref IntPtr pointerToPreparsedData);
    
        [DllImport("hid.dll", SetLastError = true)]
        private static extern void HidD_GetHidGuid(ref Guid hidGuid);
    
        private delegate bool GetString(SafeFileHandle hidDeviceObject, IntPtr pointerToBuffer, uint bufferLength);
    
        #endregion
    
        #region Helper Methods
    
        #region Public Methods
        public static HidAttributes GetHidAttributes(SafeFileHandle safeFileHandle)
        {
            var isSuccess = HidD_GetAttributes(safeFileHandle, out var hidAttributes);
            WindowsDeviceBase.HandleError(isSuccess, "Could not get Hid Attributes");
            return hidAttributes;
        }
    
        public static HidCollectionCapabilities GetHidCapabilities(SafeFileHandle readSafeFileHandle)
        {
            var isSuccess = HidD_GetPreparsedData(readSafeFileHandle, out var pointerToPreParsedData);
            WindowsDeviceBase.HandleError(isSuccess, "Could not get pre parsed data");
    
            var result = HidP_GetCaps(pointerToPreParsedData, out var hidCollectionCapabilities);
            if (result != HIDP_STATUS_SUCCESS)
            {
                throw new Exception($"Could not get Hid capabilities. Return code: {result}");
            }
    
            isSuccess = HidD_FreePreparsedData(ref pointerToPreParsedData);
            WindowsDeviceBase.HandleError(isSuccess, "Could not release handle for getting Hid capabilities");
    
            return hidCollectionCapabilities;
        }
    
        public static string GetManufacturer(SafeFileHandle safeFileHandle)
        {
            return GetHidString(safeFileHandle, HidD_GetManufacturerString);
        }
    
        public static string GetProduct(SafeFileHandle safeFileHandle)
        {
            return GetHidString(safeFileHandle, HidD_GetProductString);
        }
    
        public static string GetSerialNumber(SafeFileHandle safeFileHandle)
        {
            return GetHidString(safeFileHandle, HidD_GetSerialNumberString);
        }
        #endregion
    
        #region Private Static Methods
        private static string GetHidString(SafeFileHandle safeFileHandle, GetString getString)
        {
            var pointerToBuffer = Marshal.AllocHGlobal(126);
            var isSuccess = getString(safeFileHandle, pointerToBuffer, 126);
            Marshal.FreeHGlobal(pointerToBuffer);
            WindowsDeviceBase.HandleError(isSuccess, "Could not get Hid string");
            return Marshal.PtrToStringUni(pointerToBuffer);     
        }
        #endregion
    
        #endregion

    }

    https://github.com/MelbourneDeveloper/Device.Net/blob/master/src/Usb.Net/Windows/WinUsbApiCalls.cs

    public static partial class WinUsbApiCalls
    {
        #region Constants
        public const int EnglishLanguageID = 1033;
        public const uint DEVICE_SPEED = 1;
        public const byte USB_ENDPOINT_DIRECTION_MASK = 0X80;
        public const int WritePipeId = 0x80;
    
        ///<summary>
        ///Not sure where this constant is defined...
        ///</summary>
        public const int DEFAULT_DESCRIPTOR_TYPE = 0x01;
        public const int USB_STRING_DESCRIPTOR_TYPE = 0x03;
        #endregion
    
        #region API Calls
        [DllImport("winusb.dll", SetLastError = true)]
        public static extern bool WinUsb_ControlTransfer(IntPtr InterfaceHandle, WINUSB_SETUP_PACKET SetupPacket, byte[] Buffer, uint BufferLength, ref uint LengthTransferred, IntPtr Overlapped);
    
        [DllImport("winusb.dll", SetLastError = true, CharSet = CharSet.Auto)]
        public static extern bool WinUsb_GetAssociatedInterface(SafeFileHandle InterfaceHandle, byte AssociatedInterfaceIndex, out SafeFileHandle AssociatedInterfaceHandle);
    
        [DllImport("winusb.dll", SetLastError = true)]
        public static extern bool WinUsb_GetDescriptor(SafeFileHandle InterfaceHandle, byte DescriptorType, byte Index, ushort LanguageID, out USB_DEVICE_DESCRIPTOR deviceDesc, uint BufferLength, out uint LengthTransfered);
    
        [DllImport("winusb.dll", SetLastError = true)]
        public static extern bool WinUsb_GetDescriptor(SafeFileHandle InterfaceHandle, byte DescriptorType, byte Index, UInt16 LanguageID, byte[] Buffer, UInt32 BufferLength, out UInt32 LengthTransfered);
    
        [DllImport("winusb.dll", SetLastError = true)]
        public static extern bool WinUsb_Free(SafeFileHandle InterfaceHandle);
    
        [DllImport("winusb.dll", SetLastError = true)]
        public static extern bool WinUsb_Initialize(SafeFileHandle DeviceHandle, out SafeFileHandle InterfaceHandle);
    
        [DllImport("winusb.dll", SetLastError = true)]
        public static extern bool WinUsb_QueryDeviceInformation(IntPtr InterfaceHandle, uint InformationType, ref uint BufferLength, ref byte Buffer);
    
        [DllImport("winusb.dll", SetLastError = true)]
        public static extern bool WinUsb_QueryInterfaceSettings(SafeFileHandle InterfaceHandle, byte AlternateInterfaceNumber, out USB_INTERFACE_DESCRIPTOR UsbAltInterfaceDescriptor);
    
        [DllImport("winusb.dll", SetLastError = true)]
        public static extern bool WinUsb_QueryPipe(SafeFileHandle InterfaceHandle, byte AlternateInterfaceNumber, byte PipeIndex, out WINUSB_PIPE_INFORMATION PipeInformation);
    
        [DllImport("winusb.dll", SetLastError = true)]
        public static extern bool WinUsb_ReadPipe(SafeFileHandle InterfaceHandle, byte PipeID, byte[] Buffer, uint BufferLength, out uint LengthTransferred, IntPtr Overlapped);
    
        [DllImport("winusb.dll", SetLastError = true)]
        public static extern bool WinUsb_SetPipePolicy(IntPtr InterfaceHandle, byte PipeID, uint PolicyType, uint ValueLength, ref uint Value);
    
        [DllImport("winusb.dll", SetLastError = true)]
        public static extern bool WinUsb_WritePipe(SafeFileHandle InterfaceHandle, byte PipeID, byte[] Buffer, uint BufferLength, out uint LengthTransferred, IntPtr Overlapped);
        #endregion
    
        #region Public Methods
        public static string GetDescriptor(SafeFileHandle defaultInterfaceHandle, byte index, string errorMessage)
        {
            var buffer = new byte[256];
            var isSuccess = WinUsb_GetDescriptor(defaultInterfaceHandle, USB_STRING_DESCRIPTOR_TYPE, index, EnglishLanguageID, buffer, (uint)buffer.Length, out var transfered);
            WindowsDeviceBase.HandleError(isSuccess, errorMessage);
            var descriptor = new string(Encoding.Unicode.GetChars(buffer, 2, (int)transfered));
            return descriptor.Substring(0, descriptor.Length - 1);
        }
        #endregion
    }

    Con cualquiera de estas soluciones será necesario sondear para el dispositivo en un intervalo, o utilizar una de las API nativa del dispositivo de escucha de las clases. Sin embargo, esta biblioteca pone una capa a través de Hid, y USB en todas las plataformas, de modo que se puedan detectar las conexiones y desconexiones fácilmente: https://github.com/MelbourneDeveloper/Device.Net/wiki/Device-Listener . Esta es la manera de usarlo:

    internal class TrezorExample : IDisposable
    {
        #region Fields
        //Define the types of devices to search for. This particular device can be connected to via USB, or Hid
        private readonly List<FilterDeviceDefinition> _DeviceDefinitions = new List<FilterDeviceDefinition>
        {
            new FilterDeviceDefinition{ DeviceType= DeviceType.Hid, VendorId= 0x534C, ProductId=0x0001, Label="Trezor One Firmware 1.6.x", UsagePage=65280 },
            new FilterDeviceDefinition{ DeviceType= DeviceType.Usb, VendorId= 0x534C, ProductId=0x0001, Label="Trezor One Firmware 1.6.x (Android Only)" },
            new FilterDeviceDefinition{ DeviceType= DeviceType.Usb, VendorId= 0x1209, ProductId=0x53C1, Label="Trezor One Firmware 1.7.x" },
            new FilterDeviceDefinition{ DeviceType= DeviceType.Usb, VendorId= 0x1209, ProductId=0x53C0, Label="Model T" }
        };
        #endregion
    
        #region Events
        public event EventHandler TrezorInitialized;
        public event EventHandler TrezorDisconnected;
        #endregion
    
        #region Public Properties
        public IDevice TrezorDevice { get; private set; }
        public DeviceListener DeviceListener { get; private set; }
        #endregion
    
        #region Event Handlers
        private void DevicePoller_DeviceInitialized(object sender, DeviceEventArgs e)
        {
            TrezorDevice = e.Device;
            TrezorInitialized?.Invoke(this, new EventArgs());
        }
    
        private void DevicePoller_DeviceDisconnected(object sender, DeviceEventArgs e)
        {
            TrezorDevice = null;
            TrezorDisconnected?.Invoke(this, new EventArgs());
        }
        #endregion
    
        #region Public Methods
        public void StartListening()
        {
            TrezorDevice?.Dispose();
            DeviceListener = new DeviceListener(_DeviceDefinitions, 3000);
            DeviceListener.DeviceDisconnected += DevicePoller_DeviceDisconnected;
            DeviceListener.DeviceInitialized += DevicePoller_DeviceInitialized;
        }
    
        public async Task InitializeTrezorAsync()
        {
            //Get the first available device and connect to it
            var devices = await DeviceManager.Current.GetDevices(_DeviceDefinitions);
            TrezorDevice = devices.FirstOrDefault();
            await TrezorDevice.InitializeAsync();
        }
    
        public async Task<byte[]> WriteAndReadFromDeviceAsync()
        {
            //Create a buffer with 3 bytes (initialize)
            var writeBuffer = new byte[64];
            writeBuffer[0] = 0x3f;
            writeBuffer[1] = 0x23;
            writeBuffer[2] = 0x23;
    
            //Write the data to the device
            return await TrezorDevice.WriteAndReadAsync(writeBuffer);
        }
    
        public void Dispose()
        {
            TrezorDevice?.Dispose();
        }
        #endregion
    }
  6. 1

    Si usted tiene de National Instruments software en el PC, puede crear un Controlador USB utilizando sus «NI-VISA Asistente de Controlador».

    Pasos para crear el Controlador USB: http://www.ni.com/tutorial/4478/en/

    Una vez creado el controlador será capaz de Leer y Escribir bytes a cualquier Dispositivo USB.

    Asegúrese de que el controlador es visto por windows en el Administrador de Dispositivos:

    Trabajar con dispositivos USB en .NET

    De Código De C#:

        using NationalInstruments.VisaNS;
    
        #region UsbRaw
        ///<summary>
        ///Class to communicate with USB Devices using the UsbRaw Class of National Instruments
        ///</summary>
        public class UsbRaw
        {
            private NationalInstruments.VisaNS.UsbRaw usbRaw;
            private List<byte> DataReceived = new List<byte>();
    
            ///<summary>
            ///Initialize the USB Device to interact with
            ///</summary>
            ///<param name="ResourseName">In this format: "USB0::0x1448::0x8CA0::NI-VISA-30004::RAW".  Use the NI-VISA Driver Wizard from Start»All Programs»National Instruments»VISA»Driver Wizard to create the USB Driver for the device you need to talk to.</param>
            public UsbRaw(string ResourseName)
            {
                usbRaw = new NationalInstruments.VisaNS.UsbRaw(ResourseName, AccessModes.NoLock, 10000, false);
                usbRaw.UsbInterrupt += new UsbRawInterruptEventHandler(OnUSBInterrupt);
                usbRaw.EnableEvent(UsbRawEventType.UsbInterrupt, EventMechanism.Handler);
            }
    
            ///<summary>
            ///Clears a USB Device from any previous commands
            ///</summary>
            public void Clear()
            {
                usbRaw.Clear();
            }
    
            ///<summary>
            ///Writes Bytes to the USB Device
            ///</summary>
            ///<param name="EndPoint">USB Bulk Out Pipe attribute to send the data to.  For example: If you see on the Bus Hound sniffer tool that data is coming out from something like 28.4 (Device column), this means that the USB is using Endpoint 4 (Number after the dot)</param>
            ///<param name="BytesToSend">Data to send to the USB device</param>
            public void Write(short EndPoint, byte[] BytesToSend)
            {
                usbRaw.BulkOutPipe = EndPoint;
                usbRaw.Write(BytesToSend);       //Write to USB
            }
    
            ///<summary>
            ///Reads bytes from a USB Device
            ///</summary>
            ///<returns>Bytes Read</returns>
            public byte[] Read()
            {
                usbRaw.ReadByteArray();     //This fires the UsbRawInterruptEventHandler                
    
                byte[] rxBytes = DataReceived.ToArray();      //Collects the data received
    
                return rxBytes;
            }
    
            ///<summary>
            ///This is used to get the data received by the USB device
            ///</summary>
            ///<param name="sender"></param>
            ///<param name="e"></param>
            private void OnUSBInterrupt(object sender, UsbRawInterruptEventArgs e)
            {
                try
                {
                    DataReceived.Clear();     //Clear previous data received
                    DataReceived.AddRange(e.DataBuffer);                    
                }
                catch (Exception exp)
                {
                    string errorMsg = "Error: " + exp.Message;
                    DataReceived.AddRange(ASCIIEncoding.ASCII.GetBytes(errorMsg));
                }
            }
    
            ///<summary>
            ///Use this function to clean up the UsbRaw class
            ///</summary>
            public void Dispose()
            {
                usbRaw.DisableEvent(UsbRawEventType.UsbInterrupt, EventMechanism.Handler);
    
                if (usbRaw != null)
                {
                    usbRaw.Dispose();
                }              
            }
    
        }
        #endregion UsbRaw

    Uso:

    UsbRaw usbRaw = new UsbRaw("USB0::0x1448::0x8CA0::NI-VISA-30004::RAW");
    
    byte[] sendData = new byte[] { 0x53, 0x4c, 0x56 };
    usbRaw.Write(4, sendData);      //Write bytes to the USB Device
    byte[] readData = usbRaw.Read();   //Read bytes from the USB Device
    
    usbRaw.Dispose();

    Espero que esto ayude a alguien.

  7. 0

    La mayoría de los USB chipsets vienen con los controladores. Silicon Labs tiene uno.

    • De esta manera tengo una dependencia en el controlador de sí mismo? ¿Hay un genérico solución que funcione en todos los equipos?
    • Usted tendrá una dependencia en el archivo dll y un hardware de dependencia en el chipset utilizado. Sin embargo, esta es la forma más rápida de ponerse en marcha con la comunicación USB si usted tiene el control sobre el software y el hardware.
  8. 0

    He intentado de varias de estas sugerencias no hubo suerte. Terminé de escribir una solución de trabajo con Java y el hid4java de la biblioteca. Como una aplicación de consola, puedo shell a lo de C# utilizando Process.Start(), paso de parámetros, así como la lectura de las respuestas. Esto proporciona básica HID I/O, pero sin conectar/desconectar eventos. Para que yo había necesidad de volver a escribir para que se ejecute como un demonio/servicio y el uso de canalizaciones con nombre o algún otro servidor/cliente de transporte. Por ahora, es suficiente para conseguir el trabajo hecho desde el hi4java biblioteca «simplemente funciona».

Kommentieren Sie den Artikel

Bitte geben Sie Ihren Kommentar ein!
Bitte geben Sie hier Ihren Namen ein

Recent Articles

Python «set» con duplicados/elementos repetidos

Hay una forma estándar de representar un "conjunto" que puede contener elementos duplicados. Como yo lo entiendo, un conjunto tiene exactamente un cero o...

Python: generador de expresión vs rendimiento

En Python, ¿hay alguna diferencia entre la creación de un generador de objetos a través de un generador de expresión versus el uso de...

Cómo exportar/importar la Masilla lista de sesiones?

Hay una manera de hacer esto? O tengo que tomar manualmente cada archivo de Registro? InformationsquelleAutor s.webbandit | 2012-10-23

no distingue mayúsculas de minúsculas coincidentes en xpath?

Por ejemplo, para el xml a continuación <CATALOG> <CD title="Empire Burlesque"/> <CD title="empire burlesque"/> <CD...