Click or drag to resize

WinUsbManager Class

The root class for the managed interface to WinUSB.sys.
Inheritance Hierarchy
SystemObject
  WinUsbNetWinUsbManager

Namespace:  WinUsbNet
Assembly:  WinUsbNet (in WinUsbNet.dll) Version: 1.0.0.0 (1.0.0.0)
Syntax
public class WinUsbManager : IDisposable

The WinUsbManager type exposes the following members.

Constructors
  NameDescription
Public methodWinUsbManager
Initializes a new instance of the WinUsbManager class.
Top
Properties
  NameDescription
Public propertyUsbDevices
Gets the collection of matching USB devices that are currently attached.
Top
Methods
  NameDescription
Public methodDispose
Releases all resources used by the WinUsbManager object.
Protected methodDispose(Boolean)
Releases the unmanaged resources used by the WinUsbManager, and optionally releases the managed resources.
Public methodEquals
Determines whether the specified Object is equal to the current Object.
(Inherited from Object.)
Protected methodFinalize
Allows a WinUsbManager object to free resources before it is reclaimed by garbage collection.
(Overrides ObjectFinalize.)
Public methodGetHashCode
Serves as a hash function for a particular type.
(Inherited from Object.)
Public methodGetType
Gets the Type of the current instance.
(Inherited from Object.)
Protected methodMemberwiseClone
Creates a shallow copy of the current Object.
(Inherited from Object.)
Public methodToString
Returns a string that represents the current object.
(Inherited from Object.)
Top
Events
  NameDescription
Public eventCode exampleDeviceChange
Occurs when a matching USB device is attached or detached.
Top
Remarks

The first step in communicating with a USB device is to use the WinUsbManager constructor to create an instance of WinUsbManager. The UsbDevices collection will be populated with any USB devices with a matching GUID that are already attached. You can subscribe to the DeviceChange event to be informed when this collection changes.

The next step is to select a UsbDevice from the UsbDevices collection and call its Open method. A very simple application could simply use UsbDevices[0], but this may fail when multiple instances of the application are running due to the exclusive lock on open USB devices. A better approach would be to enumerate the UsbDevices collection to determine which UsbDevice object(s) can be successfully opened.

I/O with the USB device is performed using a PipeStream from the PipeStreams collection of the UsbDevice. A PipeStream represents a communications pipe with a specific USB endpoint.

After I/O with the USB device is completed, call the Close method on the UsbDevice. Finally, call the Dispose method when done using WinUsbManager.

Examples
This example assumes a Form named Form1 with a TextBox named txtGuid and a ListBox named lstDevices. It creates a WinUsbManager using the GUID in the text box, and then maintains a list of currently attached matching USB devices in the list box. The devices are identified by their manufacturer, product name, and serial number as present in the USB device. Double-clicking on a USB device in the list box will trigger some I/O transfers.
using System;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Diagnostics;
using WinUsbNet;

namespace WinUsbExample
{
    public partial class Form1 : Form
    {
        const string StrGuidDefault = "5eca211f-8f8f-4848-9c44-ca291c8dbb6a";

        // private instance of our WinUsbManager
        WinUsbManager m_WinUsb;

        // Form constructor
        public Form1()
        {
            InitializeComponent();
        }

        // Create a new WinUsbManager, disposing of any previous instance.
        // Called whenever the GUID changes.
        void CreateWinUsbManager(Guid guid)
        {
            if (m_WinUsb != null)
                m_WinUsb.Dispose();
            m_WinUsb = new WinUsbManager(guid);

            // Subscribe to the DeviceChange event
            m_WinUsb.DeviceChange += new EventHandler<DeviceChangeEventArgs>(DeviceChange);

            // If any devices are already attached, put them in the list
            foreach (UsbDevice dev in m_WinUsb.UsbDevices)
                GetDeviceName(dev);
        }

        // Helper function to get a string descriptor from the USB device.
        string GetStringDescriptor(UsbDevice dev, int iString)
        {
            byte[] arbBuf;

            if (iString != 0)
            {
                // Get the string descriptor:
                // bmRequestType = 0 - standard device request
                // bRequest = 6 - Get_Descriptor
                // wValue: high byte = 3 - string; low byte = descriptor index
                // wIndex = 0x409 - language ID, US English
                // wLength = 255 - max length
                arbBuf = dev.ControlRead(0, 6, (ushort)(iString | 0x300), 0x409, 255);

                // arbBuf[0] = total length
                // arbBuf[1] = 3 (string)
                // arbBuf[2] = start of string (Unicode)
                if (arbBuf.Length >= 4)
                    return Encoding.Unicode.GetString(arbBuf, 2, arbBuf[0] - 2);
            }
            return string.Empty;
        }

        // Build up device name from manufacturer, product name, and
        // serial number strings. The index of each of these strings
        // is in a fixed location in the device descriptor. Then add
        // the device to the list box.
        void GetDeviceName(UsbDevice dev)
        {
            byte[] arbBuf;
            string strTag;

            try
            {
                dev.Open();

                // Get device descriptor
                // bmRequestType = 0 - standard device request
                // bRequest = 6 - Get_Descriptor
                // wValue: high byte = 1 - device; low byte = 0 - descriptor index
                // wIndex = 0 - not used
                // wLength = 18 - length of descriptor
                arbBuf = dev.ControlRead(0, 6, 0x100, 0, 18);

                // Entries 14, 15, and 16 have the index of the manufacturer,
                // product name, and serial number string descriptors, respectively.
                strTag = GetStringDescriptor(dev, arbBuf[14]);
                strTag += '/';
                strTag += GetStringDescriptor(dev, arbBuf[15]);
                strTag += '/';
                strTag += GetStringDescriptor(dev, arbBuf[16]);

                // Assign the combined ID string to the Tag.
                dev.Tag = strTag;
            }
            catch (Exception exc)
            {
                dev.Tag = "Can't open: " + exc.Message;
            }

            dev.Close();    // done for now

            // Use the Tag as the value to be returned by ToString().
            // This makes it easy to add the UsbDevice to a list box.
            dev.GetMyString = delegate(UsbDevice device) { return (string)device.Tag; };

            // The list box will display ToString(), which is now the Tag.
            lstDevices.Items.Add(dev);
        }

        //*****************************************************************
        // Events

        // Matching USB device has been attached or detached.
        void DeviceChange(object sender, DeviceChangeEventArgs e)
        {
            if (e.IsAttach)
                GetDeviceName(e.UsbDevice);    // Add name to list box
            else
                lstDevices.Items.Remove(e.UsbDevice); // Remove name from list box
        }

        // Form is displayed, set the GUID text box to the default value.
        // This will cause the TextChanged event to fire.
        private void Form1_Shown(object sender, EventArgs e)
        {
            txtGuid.Text = StrGuidDefault;
        }

        // GUID has changed. If valid, use it to create a new
        // WinUsbManager.
        private void txtGuid_TextChanged(object sender, EventArgs e)
        {
            Guid guid;

            lstDevices.Items.Clear();    // Empty the list box

            try
            {
                guid = new Guid(txtGuid.Text);
                CreateWinUsbManager(guid);
            }
            catch (Exception exc)
            {
                lstDevices.Items.Add("Invalid GUID: " + exc.Message);
            }
        }

        //*****************************************************************
        // I/O

        // Just for demo purposes, use the DoubleClick event on the list box
        // to trigger some I/O on the selected device.
        private void lstDevices_DoubleClick(object sender, EventArgs e)
        {
            UsbDevice dev = null;
            BinaryReader reader;
            BinaryWriter writer;

            try
            {
                // Open the USB device selected in the list box
                dev = (UsbDevice)lstDevices.SelectedItem;
                dev.Open();

                // Search for IN and OUT endpoints. Typically this is not 
                // necessary because you would know the characteristics of
                // your USB device (i.e., what endpoint to use).
                reader = null;
                writer = null;
                foreach (PipeStream pipe in dev.PipeStreams)
                {
                    if (pipe == null)
                        continue;

                    // When we find a PipeStream that can read, wrap it in a
                    // BinaryReader. Note that it is still OK to bypass it
                    // and perform reads directly with the PipeStream.
                    if (pipe.CanRead && reader == null)
                        reader = new BinaryReader(pipe);

                    // To use BinaryWriter, we need to wrap the PipeStream
                    // in a BufferedStream. Otherwise each Write() call would
                    // send its own little USB packet. If WriteUseShortPacket
                    // is false, then the buffer size should just equal the
                    // packet size. Otherwise, the buffer must be big enough
                    // for the largest block we'll send through the 
                    // BinaryWriter. Note that you can still bypass the 
                    // BinaryWriter and go directly to the PipeStream; this
                    // would be useful for large blocks.
                    if (pipe.CanWrite && writer == null)
                        writer = new BinaryWriter(
                            new BufferedStream(pipe, pipe.WriteMaxPacketSize));
                }

                // Create some data
                byte b = 0;
                ushort us = 0;
                byte bCnt = 7;
                int i;

                // Write command data. By using BufferedStream, nothing is
                // sent until the Flush() call.
                writer.Write(b);
                writer.Write(us);
                writer.Write(bCnt);
                writer.Flush();

                // Read some data back
                us = reader.ReadUInt16();
                i = reader.ReadInt32();

                // Demonstrate bypassing the BinaryReader. Most likely you
                // would do this for larger blocks that you want as an
                // array of bytes.
                //b = reader.ReadByte();
                b = (byte)reader.BaseStream.ReadByte();

                // Just show data in debugger output window.
                Debug.WriteLine("Data: " + us + ", " + i + ", " + b);
            }
            catch (Exception exc)
            {
                MessageBox.Show("Transfer error: " + exc.Message, 
                    "WinUSB Example", 
                    MessageBoxButtons.OK, 
                    MessageBoxIcon.Error);
            }
            finally
            {
                if (dev != null)
                    dev.Close();
            }
        }
    }
}
See Also