Getting Vendor ID and Product ID from Winusb

4.8k views Asked by At

I am trying to get the Vendor and Product IDs from a Winusb device and am getting accessviolationexception when trying to use the winusb_GetDesicriptor() and cannot figure out why I am getting that exception.

Here are my declarations:

    internal devInfo myDevInfo = new devInfo();
    USB_INTERFACE_DESCRIPTOR ifaceDescriptor;
    USB_DEVICE_DESCRIPTOR deviceDescriptor;


    internal struct USB_INTERFACE_DESCRIPTOR
    {
        internal Byte bLength;
        internal Byte bDescriptorType;
        internal Byte bInterfaceNumber;
        internal Byte bAlternateSetting;
        internal Byte bNumEndpoints;
        internal Byte bInterfaceClass;
        internal Byte bInterfaceSubClass;
        internal Byte bInterfaceProtocol;
        internal Byte iInterface;
    }


    [StructLayout(LayoutKind.Explicit, Size = 18, CharSet = CharSet.Auto)]
    internal struct USB_DEVICE_DESCRIPTOR
    {
        [FieldOffset(0)]internal byte bLength;
        [FieldOffset(1)]internal byte bDescriptorType;
        [FieldOffset(2)]internal ushort bcdUSB;
        [FieldOffset(4)]internal byte bDeviceClass;
        [FieldOffset(5)]internal byte bDeviceSubClass;
        [FieldOffset(6)]internal byte bDeviceProtocol;
        [FieldOffset(7)]internal byte bMaxPacketSize0;
        [FieldOffset(8)]internal ushort idVendor;
        [FieldOffset(10)]internal ushort idProduct;
        [FieldOffset(12)]internal ushort bcdDevice;
        [FieldOffset(14)]internal byte iManufacturer;
        [FieldOffset(15)]internal byte iProduct;
        [FieldOffset(16)]internal byte iSerialNumber;
        [FieldOffset(17)]internal byte bNumConfigurations;
    }

    [DllImport("winusb.dll", SetLastError = true)]
    internal static extern Boolean WinUsb_Initialize(SafeFileHandle DeviceHandle, ref IntPtr InterfaceHandle);

    [DllImport("winusb.dll", SetLastError = true)]
    internal static extern Boolean WinUsb_QueryInterfaceSettings(IntPtr InterfaceHandle, Byte AlternateInterfaceNumber, ref USB_INTERFACE_DESCRIPTOR UsbAltInterfaceDescriptor);

    [DllImport("winusb.dll", SetLastError = true)]
    internal static extern Boolean WinUsb_GetDescriptor(IntPtr InterfaceHandle, byte DescriptorType, byte Index, ushort LanguageID, ref USB_DEVICE_DESCRIPTOR UsbAltDeviceDescriptor, ulong BufferLength, ref long LengthTransferred);

And then here is the code I am trying to run:

deviceHandle = CreateFile
                   (devicePathName,
                   (GENERIC_WRITE | GENERIC_READ),
                   FILE_SHARE_READ | FILE_SHARE_WRITE,
                   IntPtr.Zero,
                   OPEN_EXISTING,
                   FILE_FLAG_OVERLAPPED,
                   0);

            success = WinUsb_Initialize(deviceHandle, ref myDevInfo.winUsbHandle);
            success = WinUsb_QueryInterfaceSettings(myDevInfo.winUsbHandle, 0, ref ifaceDescriptor);
            success = WinUsb_GetDescriptor(myDevInfo.winUsbHandle,
                           0x01,
                           (byte)deviceIndex,
                           0,
                           ref deviceDescriptor,
                           18,
                           ref lengthTransferred);

I am getting through the initialize and getting the values back from queryinterfacesettings, but getting the accessviolation on the GetDescriptor call

2

There are 2 answers

7
Preston On BEST ANSWER

Read the documentation for WinUsb_GetDescriptor.

It looks like your parameters are not correct. To obtain the VID/PID, which is in the Device Descriptor, you will want to specify the USB_DEVICE_DESCRIPTOR_TYPE type for the second parameter (0x01). You also only need to specify the language ID if you are requesting a String Descriptor. The length for your device descriptor is wrong too, it should be 18 (ushort is 2 bytes, this is probably the reason for your access violation). You also want to use byte instead of Byte in your DeviceDescriptor struct, you don't want the .NET class representation of the byte, just the type value itself.

Here is updated code that may work for you:

success = WinUsb_GetDescriptor(myDevInfo.winUsbHandle,
                               0x01, 
                               (byte)deviceIndex,
                               0,
                               ref deviceDescriptor,
                               18,
                               ref lengthTransferred);
0
Christian Findlay On

Here is a class for USB calls including helper code for getting other descriptor information.

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 byte 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(SafeFileHandle 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
} 

Usage

        var isSuccess2 = WinUsbApiCalls.WinUsb_GetDescriptor(defaultInterfaceHandle, WinUsbApiCalls.DEFAULT_DESCRIPTOR_TYPE, 0, WinUsbApiCalls.EnglishLanguageID, out var _UsbDeviceDescriptor, bufferLength, out var lengthTransferred);

The code comes from here and is part of the Usb.Net framework. To connect to enumerate through and get USB devices with it, you can see the wiki.